【计算机系统基础】AttackLab实验

实验目的与要求

1. 强化机器级表示、汇编语言、调试器和逆向工程等方面基础知识,并结合栈帧工作原理实现简单的栈溢出攻击,掌握其基本攻击基本方式和原理,进一步为编程过程中应对栈溢出攻击打下一定的基础。

2. 理解缓冲区的工作原理和字符填充过程及其特点。对于无边界检测的语言及其工作方式所造成的缓冲区漏洞加深理解。

3. 通过字符串填充的方式,完成5各阶段的缓冲区攻击。分别基于基本返回地址填充、攻击代码填充、ROP等实现这5个难度递增的阶段的缓冲区溢出攻击。

实验原理与内容

“AttackLab”是一个Linux下的可执行C程序,包含了5个阶段(phase1~phase5)的不同内容。程序运行过程中,要求学生能够根据缓冲区的工作方式和程序的反汇编代码来确定攻击字符串长度和字符串中的关键内容。每次成功实现缓冲区溢出攻击时都会有提示相应内容,如果攻击失败则单纯的提示segmentation fault相关信息。

要求攻击字符串的执行不许绕开代码中的validate函数,缓冲区溢出之后对应ret的返回地址可以是以下类型:

1.函数touch1、touch2、touch3的首地址;

2.自行注入的攻击的首地址;

3.在后两个阶段中(ROP攻击),与farm.c的对应的可利用的gadget的起始地址,farm.c对应的机器码已经包含在可执行文件中。可以使用的gadget首地址需处于start_farm和end_farm之间的部分。

注意:前三个阶段使用ctarget作为攻击目标文件,后两个阶段中使用rtarget作为攻击目标文件。

每个阶段考察一个缓冲区溢出方式,难度逐级递增:

阶段1:使用非ROP方式对ctarget进行攻击,调用touch1,且成功输出Touch1!: You called touch1。若不完全满足题目要求,则会提示“Misfire”和FAIL相关字段。

阶段2:使用非ROP方式对ctarget进行攻击,调用touch2,且成功输出Touch2!: You called touch2。攻击过程中需要改写cookie变量的值。若不完全满足题目要求,则会提示“Misfire” 和FAIL相关字段。

阶段3:使用非ROP方式对ctarget进行攻击,调用touch3,且成功输出Touch3!: You called touch3。攻击过程中需要使hexmatch的返回值能够正确引导validate函数。若不完全满足题目要求,则会提示“Misfire” 和FAIL相关字段。

阶段4:使用ROP方式对rtarget进行攻击,调用touch2,且成功输出Touch2!: You called touch2。若不完全满足题目要求,则会提示“Misfire” 和FAIL相关字段。

阶段5:使用ROP方式对rtarget进行攻击,调用touch3,且成功输出Touch3!: You called touch3。若不完全满足题目要求,则会提示“Misfire” 和FAIL相关字段。

ctarget和rtarget都从standard input读入数据,可以以重定向文件的形式进行输入。实验利用getbuf函数中的缓冲区。getbuf函数的结构如下:

unsigned getbuf()

{

char buf[BUFFER_SIZE];

Gets(buf);

return 1;

}

函数中的Gets函数与标准库中的gets函数类似,它从standard input中读取字符(以\n或者EOF结尾)并将它们添加字符串结尾符\0后存入缓冲区中。学生需要根据ctarget和rtarget文件及其反汇编代码来确定缓冲区位置及大小,并想办法构建出攻击字符串。

实验设备与软件环境

1.Linux操作系统—64位Ubuntu 18.04

2. gdb调试器和objdump反汇编指令

3. 笔记本

实验过程与结果(可贴图)

阶段一

解题思路:先利用objdump -d  ctarget > ctarget.s得到汇编代码。将touch1的开始地址,放在某个位置,以实现当ret指令被getbuf执行后会将控制权转移给touch1。也就是返回getbuf()函数的时候,执行touch1()而不是返回test()。

先确定getbuf创建的缓冲区的大小,查看代码可知,缓冲区大小为0x38,十六进制的0x38转化成十进制是56。

所以需要构造攻击字符串将这56个字节填满,然后再填入touch1的起始地址,也就是小端法,即可完成攻击。构造字符串时,需要用到hex2raw来生成攻击字节码,然后将生成的攻击文件输入到ctarget中。

可以发现我们只要把getbuf的返回地址设置成touch1的地址 = 0x1d1940就可。这里getbuf的缓冲区为56字节。我们可以前56个字节乱输。只需要后面的值为 0x1d1940即可。输入文件内容如下:

输入文件为touch1.txt,则输入命令:

./hex2raw < touch1.txt | ./ctarget -q

即可通过第一个问题。ctarget默认会连接CMU的服务器,加 -q 参数可以取消连接服务器。

显示通关成功!

阶段二:

解题思路:通常我们调用一个函数会直接使用jmp,但writeup中给了建议说:不要用jmp,因为目标地址通常难以制定,而用ret。所以我们就仍然需要修改返回地址,然后通过ret指令来跳转到touch2。通常传参的第一个参数存在了寄存器%rdi当中,所以跳转之前需要把%rdi赋值为0x55fd3f95。也就说我们要写额外的语句去完成这个事情。也就是需要代码注入了。touch2的逻辑就是比较我们传入的参数val是否等于cookie的值0x55fd3f95。如果等于就可以通过。           

具体操作:打开ctarget.s文件查询touch2的首地址为40194b,打开cookie.txt查看cookie值为0x55fd3f95。   

只不过这次要从getbuf函数跳转到touch2函数,touch2函数有一个参数val,val的值要与cookie相等,才可以成功攻击。cookie的值为0x55fd3f95。

所以本题的关键就是在改变返回地址前也设置rdi寄存器的值。可以查看要插入的汇编代码:

新建一个l2.s的文本,把cookie值和touch2的地址写进去:

movq $0x55fd3f95,%rdi  //cookie值

pushq $0x40194b //touch2的地址

ret

用gcc –c l2.s 编译汇编文件,再用objdump -d l2.o > l2.d进行反汇编,得出汇编指令的机器语言,其指令序列为48 c7 c7 95 3f fd 55。

命令获得这三条指令的字节表示:

把rsp赋给了rdi然后调用了gets ,我们需要看一下rsp,在这里打一个断点。   Break getbuf 在getbuf函数处打断点。Run –q 用-q参数运行程序,直到遇到断点。Disas 反汇编当前函数。step 继续执行程序直到另一行代码,再中断,把控制器交给gdb。stepi 跳过没有调试信息的函数。p /x $rsp 用16进制打印rsp寄存器的值,这个地址就是我们注入的起始位置。

rsp的地址为0x00 00 00 00 55 67 85 78 ,我们可以让执行完getbuf之后回到rsp的这里,然后执行我们的三行汇编代码,就可以成功执行touch2了。

假设输入文件为touch2.txt,则输入命令:

./hex2raw < touch2.txt | ./ctarget -q

即可通过第二个问题。

阶段三:

解题思路:此阶段依然是代码注入攻击,但不同于之前的阶段,它需要传递字符串作为参数。如下图9所示,打开ctarget.s文件查询“touch3”,查看touch3的首地址为401a62,并发现攻击字符串中需要包含cookie字符串的表示,考虑转为ASCII十六进制数字并衔接“0”字节,使得语法成立。而hexmatch的调用会将数据压入栈中,覆盖getbuf使用的内存,因此考虑将cookie字符串放置在缓冲区外的位置,需要准确找到地址。

需要在利用缓冲区溢出的字符串中包含cookie的字符串表示形式。该字符串应该有8个十六进制数组成。注意没有前导0x。注意在c语言中的字符串表示会在末尾处加一个\0;注入的代码应将寄存器%rdi设置为此字符串的地址。调用函数hexmatch和strncmp时,它们会将数据压入堆栈,从而覆盖存放getbuf使用的缓冲区的内存部分。 因此,需要注意在哪里放置您的Cookie字符串。

其中0x556785b8是cookie值在栈中的地址,0x401a62是touch3函数的地址,接着分析栈帧里面是如何存放的。

如图所示可以看到getbuf函数,存进去的栈帧随着rsp指针一直移动,经过一系列的计算,得到getbuf栈顶地址0x401a62,然后在执行touch3函数。

getbuf之后执行touch3而不是继续执行test。必须要传递cookie字符串作为参数。在touch3函数中调用了hexmatch函数,这个函数的功能是匹配cookie和传进来的字符是否匹配。在本文中cookie的值是0x55fd3f95,所以我们传进去的参数应该是“55fd3f95”相关的。

基于ASCII对照表查找cookie值0x55fd3f95的十六进制数,具体是“35 35 66 64 33 66 39 35”,基于阶段二rsp的地址分析,考虑将cookie放入缓冲区后首地址递推0x10的位置,即cookie的text地址为0x556785b8。由此即可编写注入文件l3.s,与阶段二原理相似,改变rdi的值为cookie,如下图10所示。从而在终端中执行指令“gcc -c l3.s”,将汇编语言编译为二进制文件,然后再通过objdump指令“objdump -d l3.o > l3.d”进行反汇编,得出汇编指令的机器语言,并写入phase3.txt文件,成功完成攻击文件编写。

最后使用hex2raw工具,输入文件为touch3.txt,则输入命令:

./hex2raw < touch3.txt | ./ctarget -q

即可通过第三个问题,可以看到成功输出Touch3!: You called touch3,实现攻击。

阶段四:

解题思路:需要重复代码注入攻击中第二阶段的任务,劫持程序流,返回到touch2函数。只不过这个我们要做的是ROP攻击,这一阶段我们无法再像上一阶段中将指令序列放入到栈中,所以我们需要到现有的程序中,找到我们需要的指令序列。调用touch2的效果,但是搜索rtarget发现没有现成的代码片段组成gadget2的跳转。所以我们借助一个寄存器坐中间跳板。这里使用的是%rax寄存器做中间跳转。

操作过程:我们需要的代码序列如下:

popq %rax

movq %rax, %rdi

popq %rax的指令字节为:33。

8d表示33字节,87表示34字节,58表示35字节,所以我们找到了如下函数:

从中可以得出popq %rax指令的地址为:0x401b35。

movq %rax, %rdi的指令字节为:48 89 c7,所以我们找到了如下函数:

C7表示2c字节,07表示2d字节,48表示2e字节,可以得出movq %rax, %rdi指令的地址为:0x401b2e。

查看touch'2函数的地址,可以看出地址是0x40194b:

查看cookie的值,可以看出是0x55fd3f95:

输入文档内容:

/*getbuf的56字节*/
/*gadget1 的地址是 0x401b35 */
/*cookie 的地址是 0x55fd3d95*/
/*gadget2 的地址是 0x401b2e*/ 
/*touch2 的地址是 0x40194b*/

输入文件为touch4.txt,则输入命令:

./hex2raw < touch4.txt | ./rtarget -q

即可通过第四个问题。

阶段五:

解题思路:这一关的目标和Phase3一样,使用cookie构造字符串传递到touch3,使用rop的攻击手段。要求只能使用前八个x86-64寄存器 %rax-%rdi ;可以使用 movq, movl, popq, ret, nop的 gadget;可以使用在 rtarget代码中在 start_farm和 end_farm区域内的任意 gadget完成攻击;至少需要8个 gadget实现此次攻击。

根据第四关可知,我们所需的所有gadger在start_farm的汇编代码区域中寻找。需要将寄存器%rdi的值设置为cookie字符串的指针,即存储cookie字符串的地址。

去rtarget.s找出我们所需的代码,找到满足要求的gadget拼凑出攻击指令,根据一下指令寻找地址:

/*58*/ 地址 0x401b35

/*89 c2*/  地址 0x401b20

/*89 d1*/  地址 0x401b8b

/*89 ce*/   地址 0x401ba1

/*48 89 e0*/ 地址 0x401be5

/*48 89 c7*/  地址 0x401b2e

/*48 8d 04 37*/ 0x401b40

Touch3  地址  0x401b62

创建新的文件为touch5.txt,按照顺序依次填入输入:

输入命令:

./hex2raw < touch5.txt | ./rtarget -q 

即可通过第五个问题。

有问题可以私聊小编,小编看到后会第一时间回复大家,请耐心等待~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值