计算机系统基础实验 AttackLab

  • Post author:
  • Post category:其他


本文是作者的作业备份,仅作参考,不可照搬抄袭!

实验背景:

本实验分为五个阶段,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

而本题要求:

  1. 只能使用movq 、popq、 ret、 nop的gadget。
  2. 只能使用前八个x86-64寄存器。
  3. 只能用两个gadget实现此次攻击。
  4. 如果一个gadget使用了popq指令,那么它会从栈中弹出数据。这样一来,攻击代码能既包含gadget的地址也包含数据。

与第二关相同,需要让val等于我的cookie值,而使得存放val的rdi寄存器注入cookie,可以用到以下的指令:

需要用到两个gadget,分别是

mov   %rax,%rdi

ret

popq  %rax

ret

所以攻击代码如下:

第五关:

本题要求为:

  1. 允许使用函数start_farm和end_farm之间的所有gadget。
  2. 可以使用movq、 popq、 ret、 nop、 movl指令,以及2字节指令。
  3. 只能使用前八个x86-64寄存器。
  4. 至少需要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

所以攻击字符串为:



版权声明:本文为caoyitong原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。