本文是作者的作业备份,仅作参考,不可照搬抄袭!
实验背景:
本实验分为五个阶段,ctarget的三个使用的是CI(code-injection),rtarget的两个阶段使用的是ROP(return-oriented-programming),如表1所示
ctarget和rtarget都是用getbuf函数从标准输入读入字符串,getbuf函数定义如下:
函数
Gets
类似于标准库函数
gets
,从标准输入读入一个字符串(以
’\n’
或者
end-of-file
结束),将字符串(带
null
结束符)存储在指定的目的地址。从这段代码可以看出,目标地址是数组
buf
,声明为
BUFFER_SIZE
个字节。
BUFFER_SIZE
是一个编译时常量,在你的
target
程序生成时就具体确定了(每位学生的
target
的
BUFFER_SIZE
不同)。
函数
Gets()
和
gets()
都无法确定目标缓冲区是否够大,能够存储下读入的字符串。它们都只会简单地拷贝字节序列,可能会超出目标地址处分配的存储空间的边界。
如果用户输入的字符串足够短,
getbuf
会返回
1
如果用户输入的字符串很长,就会出错, 如图3所示:
实验步骤:
第一关:
首先调用了test函数,test中调用了getbuf函数,经过getbuf函数后返回test函数。
而第一关要求调用test函数后,不是正常返回test,而是执行touch1
从touch1函数可以看出,只有一个输出函数,不需要写入新代码。所以只要在栈中将程序getbuf的返回指令ret中的地址换成touch1的地址就可以了。
从sub $0x18,$rsp 可以看出getbuf创建的缓冲区大小为0x18,即24个字节。
而touch1的起始地址为0x401911,所以只需要利用缓冲区溢出去更改返回地址就可以了。
所以我们的攻击字符串attack1为
第二关:
与第一关类似,需要调用test在getbuf函数返回时,执行的是touch2而不是test
而观察touch2发现,除此以外,还需要利用缓冲区溢出注入数据,使得val中的数据等于我的cookie=0x66c417e7
而touch2的起始地址为0x40193f,而“cmp %edi,0
x203baf
(%rip)”说明touch2中的val则存在$edi中。也就是我们需要先将edi中的值设置为cookie,然后再跳转到touch2执行。
通过汇编与反汇编代码得:
第一串攻击字符串为48 c7 c7 e7 17 c4 66 68 3f 19 40 00 c3
而通过gdb,在0x401907处设置断点去查看getbuf下rsp所在地址
得到地址0x55666448,
所以最后得到攻击字符串:
第三关:
Getbuf调用后执行touch3,而touch3中调用了hexmatch的函数,而在hexmatch代码中我们可以看出需要让touch3参数val等于我的cookie字符的字符串表示。
我的cookie=0x66c417e7
而字符串表示 0x66c417e7=36 36 63 34 31 37 65 37
Touch3的起始地址为0x401a56,确认函数位置后我们需要确认将cookie的字符串表示放在合适的地方,而当调用hexmatch函数后,缓冲区中的数据会发生改变,所以我们需要看一下调用前后缓冲区的情况。
先写一个attack3.txt的攻击字符串,通过./hex2raw < attack3.txt > bufraw3.txt 转换成攻击代码,gdb进入touch3去看缓冲区.
缓冲区地址由第二关可知是0x55666448
在调用hexmatch(0x401a6d)前后设置断点。
比较调用前后的缓冲区,可以发现除了前面16个字节存放注入代码以外,还有0x55666450开始的40个字节也没有合适的空间可以存放调用后数据。
然后我们发现从0x55666468处开始的8个字节是前后不变,都没有存放其他数据,可以用来放我们的cookie,所以将这个地址注入rdi中
汇编与反汇编得:
所以第一串攻击代码为48 c7 c7 68 64 66 55 68 56 1a 40 00 c3
最后得攻击字符串为:
第四关:
使用gadget farm里的gadget来攻击rtarget函数,根据指令的字节编码,得出指令如下:
mov %rsp,%rax
ret
mov %rax,%rdi
ret
popq %rax
ret
movl %eax,%edx
ret
movl %edx,%ecx
ret
movl %ecx,%esi
ret
lea (%rdi,%rsi,1),%rax
ret
而本题要求:
- 只能使用movq 、popq、 ret、 nop的gadget。
- 只能使用前八个x86-64寄存器。
- 只能用两个gadget实现此次攻击。
- 如果一个gadget使用了popq指令,那么它会从栈中弹出数据。这样一来,攻击代码能既包含gadget的地址也包含数据。
与第二关相同,需要让val等于我的cookie值,而使得存放val的rdi寄存器注入cookie,可以用到以下的指令:
需要用到两个gadget,分别是
mov %rax,%rdi
ret
popq %rax
ret
所以攻击代码如下:
第五关:
本题要求为:
- 允许使用函数start_farm和end_farm之间的所有gadget。
- 可以使用movq、 popq、 ret、 nop、 movl指令,以及2字节指令。
- 只能使用前八个x86-64寄存器。
- 至少需要8个gadget实现此次攻击。
与第三关相同,需要将rdi的值设置为cookie的字符串表示的值,也就是存储cookie字符的地址。
与第三关相同,需要将rdi的值设置为cookie的字符串表示的值,也就是存储cookie字符的地址。需要先将buffer填充溢出,然后再加上cookie的偏移量。
结合上面的代码,可以进行这样的操作:
mov %rsp,%rax
ret
mov %rax,%rdi
ret
popq %rax
ret
movl %eax,%edx
ret
movl %edx,%ecx
ret
movl %ecx,%esi
ret
lea (%rdi,%rsi,1),%rax
ret
mov %rax,%rdi
ret
而从第一条指令结束一直到cookie之前还有9条指令,所以偏移量为0x48
所以攻击字符串为: