1.实验前准备
1)重点文档解释
获取实验文档后,将其解压,会获得几个文件,阅读readme文档,大致了解各文件作用,文件包括(ctarget,rtarget,farm.c,hex2raw,README,cookie.txt)
- ctarget Linux二进制文件存在代码注入漏洞。用于任务的1-3阶段。
- rtarget Linux二进制文件存在面向返回的编程漏洞。用于任务的第4-5阶段。
- cookie.txt 包含此实验室实例所需的4字节签名的文本文件。
- hex2raw 生成字节序列的实用程序。
2) hex2raw工具的使用
重点了解下hex2raw这个小程序,帮助我们将文本形式的字符串转换生成十六进制字节序列,其主要用法如红框标注说明,我们实验中通过控制台或者文件输入的是文本数据,如果想构造形如0x1234这样的十六进制序列,需要做下转换
3)实验环境兼容性问题
关于测试环境的问题,也许是不同虚拟机环境不同,导致实验程序的兼容性出现了问题,如下图,我按照实验手册中说明的控制台进行输入的方法测试,没有办法进行输入,直接会报错
利用手册中管道输入的方法也会报错(原因也一直没找到,也许还是实验环境兼容性的问题-_-||)
所以,我们可以按照如下图中我的方法
首先将输入数据存放到一本地文件,然后通过hex2raw工具转换后存到另一个本地文件,最后通过./ctarget -qi input.txt 这种方式测试
./hex2raw < your_sol_file > input.txt
./ctarget -qi input.txt
验证过,是可行的,如下图
2.实验开始
对于Level1,我们不需要注入新的代码。相反,利用字符串将重定向程序以执行现有的过程,就可以实现。如下是初始的test程序,第4行通过getbuf()调用,会读取控制台中我们的输入数据,然后进行printf输出。
大家可以利用上面我介绍的方法,随便输入一段文字,然后运行看下输出情况
如下是touch1的代码
我们的任务是在getbuf()执行其返回语句时让ctarget执行touch1的代码,而不是返回到test()中。请注意,我们的利用漏洞字符串也可能破坏与此阶段不直接相关的堆栈部分,但这不会导致问题,因为touch1会导致程序直接退出(有exit(0)语句)。
本题就是利用一个基本的缓冲区溢出把getbuf
的返回地址设置成touch1
的地址。
思路是将touch1
的开始地址,放在某个位置(test进行call getbuf()指令前,要将该指令的下一指令地址压栈,此时的压入栈帧中的位置,就是我们要修改的位置),以实现当ret
指令被getbuf
执行后会将控制权转移给touch1
1)分析test汇编代码
0000000000401968 <test>:
401968: 48 83 ec 08 sub $0x8,%rsp
40196c: b8 00 00 00 00 mov $0x0,%eax
401971: e8 32 fe ff ff call 4017a8 <getbuf>
401976: 89 c2 mov %eax,%edx
401978: be 88 31 40 00 mov $0x403188,%esi
40197d: bf 01 00 00 00 mov $0x1,%edi
401982: b8 00 00 00 00 mov $0x0,%eax
401987: e8 64 f4 ff ff call 400df0 <__printf_chk@plt>
40198c: 48 83 c4 08 add $0x8,%rsp
401990: c3 ret
这里首先$rsp-8分配栈帧,然后调用getbuf(),
随后把返回值赋给了edx(读取成功后返回值为1),将
0x403188
赋给esi
,传参完成后,调用printf()进行输出,可以想到$esi指向的应该是printf
的格式化字符,check
一下,和预期一致
2)分析getbuf汇编代码
00000000004017a8 <getbuf>:
4017a8: 48 83 ec 28 sub $0x28,%rsp
4017ac: 48 89 e7 mov %rsp,%rdi
4017af: e8 8c 02 00 00 call 401a40 <Gets>
4017b4: b8 01 00 00 00 mov $0x1,%eax
4017b9: 48 83 c4 28 add $0x28,%rsp
4017bd: c3 ret
4017be: 90 nop
4017bf: 90 nop
代码开始通过$rsp-40创建了40个字节的栈帧空间,然后将栈顶地址赋给rdi,调用Gets()进行输入,输入字符放到此40字节的缓冲区中。
00000000004017c0 <touch1>:
4017c0: 48 83 ec 08 sub $0x8,%rsp
4017c4: c7 05 0e 2d 20 00 01 movl $0x1,0x202d0e(%rip) # 6044dc <vlevel>
4017cb: 00 00 00
4017ce: bf c5 30 40 00 mov $0x4030c5,%edi
4017d3: e8 e8 f4 ff ff call 400cc0 <puts@plt>
4017d8: bf 01 00 00 00 mov $0x1,%edi
4017dd: e8 ab 04 00 00 call 401c8d <validate>
4017e2: bf 00 00 00 00 mov $0x0,%edi
4017e7: e8 54 f6 ff ff call 400e40 <exit@plt>
所以我们只要把getbuf的返回地址设置成touch1的地址=0x4017c0即
可。这里getbuf的缓冲区为40字节。我们可以前40个字节随便输入。只需要接下来的八个字节构造为地址0x00000000004017c0
即可。我们构造一个txt文件用来输入touch1.txt
3) 测试
接下来,运行我们的实例,如下图,level1通过了。
./hex2raw < touch1.txt >ctarget_1.txt
./ctarget -qi ctarget_1.txt