Attack-lab 总结
csapp 的第三个 lab。考察局限在内存安全,主要依靠缓冲区溢出为基础并浅尝面向返回编程 ROP。
谁都只得那双手靠拥抱亦难任你拥有
要拥有必先懂失去怎接受
第一部分
这部分主要 attack ctarget 文件。因为使用 gets(类似)函数没有判断长度导致字符串可以一路插穿栈帧,藉此可以改掉函数的返回地址,也就是栈帧最高处储存的地址来导向我们想让他去的地方。
这个 lab 不改栈地址,所以可以用绝对地址。
问题函数:
1 | unsigned getbuf() |
鉴于 bomb lab 的摧残我已经熟练掌握 gdb 的基本用法,然后装了 gef 插件直接看栈,当然也可以使用 x /(foo) xw $rsp 看到栈内容,而且不装插件在这个 lab 里用 layout asm 似乎会卡退(wsl 2.0)就看不了反汇编。
需要用 hex2raw 将载荷转成字符串,在 gdb 里用 - i 运行,参见文档。
b getbuf 下断点,run -q 第一次运行(离线一定 - q),看到栈顶距离 getbuf 的返回地址有 40 字节的缓冲,然后直接填充掉,把地址换成 touch1 的绝对地址。载荷如下:
1 | 31 32 33 34 35 36 37 38 39 30 |
第二关需要把一个特定值给到检查函数里面。这样要求前面 padding 的内容就得包含机器码(这个 lab 的栈中内容可以运行)。函数的第一个参数储存在 % rdi 寄存器,可以直接 movq。我第一次写的是把 % rsp 改掉指向 touch2 函数的地址,但后来想想实在是憨只要 pushq 就好了口阿。缓冲区要填满,全部 nop。
1 | movq $0x59b997fa %rdi |
第三关更困难一点。需要传一个字符串,检查函数传参指针
1 | int hexmatch(unsigned val, char *sval) |
比较的时候会随机地址,不过其实没什么影响。还是把字符串藏到栈里,但是一开始我往低处藏似乎总是被 hexmatch 申请的空间给抹了,索性直接越过 touch3 的栈帧把字符串藏到 test 函数栈帧里,有风险但不多因为 test 函数不会再被返回了,以防万一我保留了原来的 touch3 返回地址。注意字符串一定以 \0 结尾,而且和小端序没关系。对了这个小端序真的烦,0xdeadbeef 需要写成 ef be ad de。和第二题类似。
1 | movq $0x5561dcb8, %rdi #string addr |