最近做 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. 但是懒惰的我强行使用各种办法把代码给压进去了. 比如 subl
比 subq
少一个字节, 于是可以只减 rsp
的低32位 esp
. 同理还有 movq
和 movl
. 再有就是清零可以直接 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, %rax
和 movq %rax, %rdi
. 因为栈地址前面一段都是 f
, 所以必需得用 64 位操作. 正好这一条链式传递可以把 %rsp
放到 %rdi
.
另外还需要弄一个偏移量. 把常数压进栈里然后放到 %rsi
. 但是由于 farm 里找不到 很好用的片段, 这里需要一个非常长的传递, 依次经过 rax rdx rcx rsi
. 这里需要好好使用 vim 的正则匹配功能才能迅速地找到对应的代码.
最后就是把 %rax
再放到 %rdi
, 然后调 touch3
.
最后一个问要大力感谢室友 seventhheavan 给我的提示.