Code Injection
Phase_1
任务
执行完 getbuf 函数之后不跳转到 test 函数,而是执行 touch1 函数。
分析流程
-
首先得到getbuf的汇编代码
得知getbuf的缓冲区大小为0x28(即40)。为了使它跳转到touch1,通过缓冲区溢出把栈帧上面的返回地址改掉;填充40字节内容+touch1地址即可。 -
查看touch1的汇编代码
得到touch1地址为0x4017c0。 -
小端排列逆向填充,制作相应的字符文件attack1.txt
-
执行,得
成功
Phase_2
任务
插入一段代码,使得getbuf()函数返回时,执行touch2(),而不是返回test()
分析流程
-
分析touch2可知,我们需要把cookie作为参数传入touch2中。
-
要做的事情有
- 注入代码,修改%rdi使它等于cookie(0x59b997fa)。
- 改变getbuf的返回地址,使其跳转到我们输入的代码块。
- 使注入的代码执行结束后跳转到touch2。
-
首先观察touch2的汇编代码
得到其地址为0x4017ec。 -
接下来编写注入代码,制作相应文件injection2.s
-
由于retq函数是从栈顶弹出一个值进行跳转,所以除了要改变%rdi的值,还要我们要压入touch2的首地址。具体代码如下
将其编译得到
-
我们的代码从栈顶注入,所以还需要得到栈顶指针
-
在栈的开始位置为注入代码的指令序列,然后填充满至40个字节,在接下来的8个字节,也就是原来的返回地址,填充成注入代码的起始地址,也就是%rsp的地址。为了方便理解,画一下注入后的栈图
-
制作相应的字符文件attack2.txt
-
执行,得
成功
Phase_3
任务
在getbuf()函数返回的时候,执行touch3()而不是返回test()。从touch3()可以看出我们需要注入新的代码,让touch3()以为它接收到的参数是自己的cookie的字符串表示。
分析流程
- 首先分析hexmatch得源代码
查阅资料得
sprintf指的是字符串格式化命令,函数声明为 int sprintf(char *string, char *format [,argument,…]);,主要功能是把格式化的数据写入某个字符串中,即发送格式化输出到 string 所指向的字符串。sprintf 是个变参函数。使用sprintf 对于写入buffer的字符数是没有限制的,这就存在了buffer溢出的可能性。
-
所以我们需要传入的字符串为“
59b997fa
”,通过查阅ASCII表,将其转为16进制序列“35 39 62 39 39 37 66 61 00”。我们要将这个序列赋值给%rdi作为参数传入函数,但是字符串类型无法直接传递,我们要把它存进内存 -
在hexmatch中,由于有
考虑到getbuf栈帧大小,所以把字符串放进getbuf栈帧并不安全。所以考虑将字符串放在test栈帧。剩下的工作就和任务二类似 -
利用gdb得到test的栈顶地址
可知是0x5561dca8 -
再查看touch3的开始地址
可知是0x4018fa -
编写注入代码,制作相应文件injection3.s
-
将其编译得到
-
画出栈图
-
制作相应的字符文件attack3.txt
-
执行,得
成功
R O P
首先将farm.c编译,得到一个gadget farm
Phase_4
- 任务和Phase_2相同,但是要使用rop方式进行攻击
- 考虑的攻击方式为:通过缓冲区溢出漏洞将cookie写入栈,然后把它pop到某寄存器,再把它move到%rdi中
- 为方便理解,画出栈图
- 由此我们需要的汇编代码为
popq %rax
movq %rax, %rdi
-
查表可知指令字节分别为:58,48 89 c7
-
回到farm中查找,得到
得到两条指令的地址:0x17,0x0e。 -
制作相应的字符文件attack4.txt
-
执行,得
失败 -
应该是farm里的指令地址出了问题。查询资料得知是没有把farm编译为可执行代码。
-
重新利用gdb查找指令地址
得到指令地址分别为:0x4019ab,0x4019a2 -
编写字符文件
-
重新执行
成功
Phase_5
-
任务和Phase_3相同,但是要使用rop方式进行攻击。
-
但是由于每一次栈的位置是随机的,不能再像之前直接通过地址来索引字符串的起始地址,考虑先动态获取每次栈顶指针再加上偏移量来索引字符串的地址,再把地址传送到%rdi,调用touch3。
-
需要做的事情有
- 获取%rsp的地址。
- 获取字符偏移量。
- 计算得到字符串首地址再传送到%rdi。
- 调用touch3。
-
查找farm,得到
- movq %rsp,%rax 的指令字节为48 89 e0,地址为0x401a06
- movq %rax, %rdi的指令字节为48 89 c7,地址为0x4019a2
- popq %rax的指令字节为58,地址为0x4019cc
- movl %eax, %edx的指令字节为89 c2,地址为0x4019dd
- movl %edx, %ecx的指令字节为89 d1,地址为0x401a70
- movl %ecx, %esi的指令字节为89 ce,地址为0x401a13
- lea (%rdi,%rsi,1),%rax的地址为0x4019d6
- movq %rax, %rdi的指令字节为48 89 c7,地址为0x4019a2
- movq %rsp,%rax 的指令字节为48 89 e0,地址为0x401a06
-
至此,字符串的地址已经被放进了%rdi中,画个栈图理清一下思路
可知偏移量为8*9=72,即为0x48 -
制作相应的字符文件attack5.txt
-
执行,得
成功
小结
在实验过程中对于栈有了更加深刻的理解,同时认识到了缓冲区溢出的危害。对于gcc和objdump的使用更加熟练