最近做 attack lab 感到虽然很头大但是很好玩.

主要分为两个 target: code injection 和 return hack

两个实验的原理都是栈向上溢出之后抹掉了一些 return address, 从而可以改写, 做任何你想做的事.

ctarget

比较简单粗暴, 可以直接跳到用户上传的字符串里面, 把用户数据直接当代码执行.

第一个子任务

可以直接跳转.

第二个子任务

需要把 cookie 找出来并写进 %rdi. 我最开始以为cookie是随机的, 于是去gdb里把 cookie 的内存地址给弄出来强行读了. 后来才发现可以直接 hardcode.

第三个子任务

同上, 没有发现这个 trick, 于是就从内存里读之后, 调用它提供的 sprintf 函数. 这个函数有很多的陷阱, 比如一定要把 %rax 设成 0, 不然会跳错. 然后打印的地址也得自己在栈里找. 更坑的是栈空间会被 sprintf 函数给抹掉, 所以必需得先把 %rsp 放低到很远的位置去, 不然就算打对了字符串, 注入的代码段也没有了, 还是会 segmentation fault.

好了现在问题又来了, 注入的栈只有 56 个字节. 如何把上面一长串代码塞进去. 其实有个简单的方法是继续向上溢出, 中间加一条 jmp. 但是懒惰的我强行使用各种办法把代码给压进去了. 比如 sublsubq 少一个字节, 于是可以只减 rsp 的低32位 esp. 同理还有 movqmovl. 再有就是清零可以直接 xor %eax, %eax, 直接省下了四五个字节, 岂不美哉.

rtarget

这个就没那么粗暴了. 注入到栈空间里的东西只能是数据或者 ra, 不可以是代码. 如果 %pc 指进栈空间会直接报错.

但是引入了一个叫 farm 的东西. farm 里全是一些小函数, 有很多 c3, 即 ret. 于是只要在 c3 的前面找到一些有用的子串作为我需要的代码, 岂不就能解决问题了.

第四个子任务

这个任务要调 touch2, 即把 cookie 放进 %rdi. 前面说了其实 cookie 是固定的. 所以可以写进栈里.

观察发现有 popq %rax, 和 mov %eax, %edi 这俩非常有用的代码片段, 所以就直接 从栈里弹出来然后扔进 %edi 就完事了.

####第五个子任务 这个玩意挺有难度也挺有意思, 虽然做完之后觉得也就那样了.

任务是写字符串. 其实那个字符串的长度刚好就是一个 64 位整数, 放进栈里的某个位置就好. 然后有一个非常非常关键的函数叫 add_xy. (我因为没看到这个函数懵了一个小时也是很醉.) 这函数的意思是把 %rdi%rsi 加起来放进 %rax.

观察发现有 movq %rsp, %raxmovq %rax, %rdi. 因为栈地址前面一段都是 f, 所以必需得用 64 位操作. 正好这一条链式传递可以把 %rsp 放到 %rdi.

另外还需要弄一个偏移量. 把常数压进栈里然后放到 %rsi. 但是由于 farm 里找不到 很好用的片段, 这里需要一个非常长的传递, 依次经过 rax rdx rcx rsi. 这里需要好好使用 vim 的正则匹配功能才能迅速地找到对应的代码.

最后就是把 %rax 再放到 %rdi, 然后调 touch3.

最后一个问要大力感谢室友 seventhheavan 给我的提示.