注:本实验所用文件不是csapp官网给出的,是学校下发的。可以参考我的思路。
本阶段目标是使getbuf调用结束后,控制权交给touch1函数。
则我们要知道两件事:一是缓冲区大小,二是touch1在虚拟内存中的位置。
用objdump -d ctarget > ctarget.s命令,反汇编ctarget代码。用本机安装的vs打开,方便阅读。
如下图,缓冲区大小为0x38字节,即56字节。
如下图,touch1的位置在0x4018a3.
那么,就可以先输入56字节的任意数据,将getbuf的缓冲区填满,然后溢出8个字节,这8个字节原本的内容是test调用getbuf后的返回地址。将这个返回地址用touch1的地址(0x4018a3)覆盖,这样在getbuf函数执行retq指令后,程序就会返回到touch1函数,执行touch1函数。
新建一个名为e1.txt文件,输入以下内容。
这个e1.txt文件中的内容就是在getbuf中,用户要输入的内容。但是不能直接定向输入到ctarget中,而是要将数据通过hex2raw程序转化后,再输入ctarget程序。
hex2raw的使用方法如下图。
所以,如下图,用hex2raw小工具得到真正的二进制代码,带参数运行。本阶段完成。(个人信息部分已隐藏)
本阶段目标是调用touch2,并且传递一个正确的参数。
其中cookie是0x2486651c
我们注入的代码的要做的事情:
将cookie的值(0x2486651c) mov到第一个参数(寄存器rdx) 把touch2位置压入栈中 返回 |
如下图,其中touch2的位置为4018d7。
movl $0x2486651c, %rdi push $0x4018d7 ret |
将以上汇编代码用gcc编译为机器代码,再反汇编得到:
至此得到了应注入的机器代码。不要忘记,溢出区的地方写栈顶地址,以便在buf函数调用结束后rip跳到我们注入的代码的地址。栈顶地址可以通过gdb调试时的rsp值得到,为0x55631238。新建一个名为e2.txt文件,输入以下内容:
用hex2raw小工具得到真正的二进制代码,带参数运行。本阶段完成。
本阶段的目标是调用touch3,调用时向touch3传递一个参数,是字符串,字符串的内容是cookie,即sval=“2486651c\0”.并且要特别注意字符串的存放位置,不能存在buf的栈帧(即大小为0x38字节的缓冲区)中,不然调用其他函数时马上会被覆盖,按地址读出的就不是我们写入的sval字符串了。所以将其存在溢出后的位置,即text函数的栈帧中。
将存放字符串的地址mov到rdx touch3函数首地址压栈 返回 |
如下图,touch3的地址为0x4019f0
movq $0x55631278, %rdi push $0x4019f0 ret |
将以上汇编代码用gcc编译为机器代码,再反汇编得到:
至此得到了应注入的机器代码。不要忘记,溢出区的地方写栈顶地址(与阶段二的地址一样,是0x55631238,无需再次用gdb调试),以便在buf函数调用结束后rip跳到我们注入的代码的地址。接下来还要写入“2486651c\0”字符串。这个字符串转为ascii码为:32 34 38 36 36 35 31 63 00.
新建一个名为e2.txt文件,输入以下内容:
用hex2raw小工具得到真正的二进制代码,带参数运行。本阶段完成。
接下来的两个阶段用到rtarget和farm.c
objdump -d rtarget > rtarget.s
用vs打开rtarget.s
本阶段的目标是用面向返回攻击的办法,使得touch2被成功调用。但是由于采用了栈随机化,即段程序分配的栈的位置在每次运行时都是随机的,这就使我们无法确定在哪里插入代码限制可执行代码区域,而且它限制栈上存放的代码是不可执行的。且还有一个限制:最多用2段farm.c中的小工具。
所有可能会用到的机器指令如下图
不能注入自己写的代码,则缓冲区的0x38字节都不用,以56个00填充缓冲区。我们要用到的是溢出的部分。如同phase2的解决方法类似,把0x2486651c放到rdi寄存器中,返回。
所以溢出区的内容是
使用能从栈中pop的小工具 0x2486651c touch2的地址 |
想把0x2486651c直接pop到%rdi中对应的机器指令为5f。
但小工具中没有5f,而有58。
于是想到movl %eax, %edi。恰好,小工具中有movl %eax, %edi对应的机器代码(89 c7)。
新建一个名为e4.txt文件,输入以下内容。
用hex2raw小工具得到真正的二进制代码,带参数运行。本阶段完成。
本阶段的目标是用面向返回注入的办法调用touch3,并且最多用8段farm.c中的小工具。
用到的小工具如下面所示
根据在farm.c中找到的所有小工具,对应的指令顺序应该是下面这样的(顺序为从上到下)
movq %rsp, %rax |
movl %eax, %edi |
popq %ax |
movl %ax, %cx |
movl %cx, %dx |
movl %dx, %si |
R[ax] = R[si] + R[di] |
movl %eax, %edi |
对应的机器代码:
401ad9 |
89 c7 |
58 |
89 c1 |
89 ca |
89 c6 |
48 8d 04 37 |
89 c7 |
各个小工具对应的地址为:
401ad9 |
401a9e |
401a97 |
401b6f |
401b32 |
401b97 |
401ad3 |
401a9e |
栈中完整的内容如下(为了清晰的看出每句话的功能,写代码地址的地方替换为了汇编代码):
movq %rsp, %rax |
movl %eax, %edi |
popq %ax |
0x48(偏移值) |
movl %ax, %cx |
movl %cx, %dx |
movl %dx, %si |
R[ax] = R[si] + R[di] |
movl %eax, %edi |
touch3的地址 |
cookie字符串 |
综上分析,新建一个名为e5.txt文件,输入以下内容。
用hex2raw小工具得到真正的二进制代码,带参数运行。本阶段完成。