51

Linux Kernel Pwn ABC(Ⅰ)(draft)

 5 years ago
source link: http://m4x.fun/post/linux-kernel-pwn-abc-1/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

记录一下最近学到的 linux kernel pwn 知识,比较基础。

Basic Knowledge

主要参考了 Linux Kernel Exploitation

Kernel

kernel 也是一个程序,用来管理软件发出的数据 I/O 要求,讲这些要求转义为指令,交给 CPU 和计算机中的其他组件处理,是现代操作系统最基本的部分。

YVFnEfu.png!web

kernel 最主要的功能有两点:

  1. 控制并与硬件进行交互
  2. 提供 application 能运行的环境

包括 I/O,权限控制,系统调用,进程管理,内存管理等多项功能都可以归结到上边两点中。

需要注意的是, kernel 的 crash 通常会引起重启

Ring Model

intel CPU 将 CPU 的特权级别分为 4 个级别:Ring 0, Ring 1, Ring 2, Ring 3。

Ring0 只给 OS 使用,Ring 3 所有程序都可以使用,内层 Ring 可以随便使用外层 Ring 的资源。

使用 Ring Model 是为了提升系统安全性,例如某个间谍软件作为一个在 Ring 3 运行的用户程序,在不通知用户的时候打开摄像头会被阻止,因为访问硬件需要使用being驱动程序保留的 Ring 1 的方法。

大多数的现代操作系统只使用了 Ring 0 和 Ring 3。 aI3qayZ.jpg!web

Loadable Kernel Modules(LKMs)

可加载核心模块 (或直接称为内核模块) 就像运行在内核空间的可执行程序,包括:

  • 驱动程序(Device drivers)
  • 文件系统驱动

LKMs 的文件格式和用户态的可执行程序相同,Linux 下为 ELF,Windows 下为 exe/dll,mac 下为 MACH-O,因此我们可以用 IDA 等工具来分析内核模块。

常用指令

  • insmod: 讲指定模块加载到内核中
  • rmmod: 从内核中卸载指定模块
  • lsmod: 列出已经加载的模块

大多数kernel vulnerability 也出在 LVM 中。

syscall

系统调用,指的是用户空间的程序向操作系统内核请求需要更高权限的服务,比如 IO 操作或者进程间通信。系统调用提供用户程序与操作系统间的接口,部分库函数(如 scanf,puts 等 IO 相关的函数实际上是对系统调用的封装 (read 和 write))。

/usr/include/x86_64-linux-gnu/asm/unistd_64.h/usr/include/x86_64-linux-gnu/asm/unistd_32.h 分别可以查看 64 位和 32 位的系统调用号。

同时推荐一个很好用的网站 Linux Syscall Reference ,可以查阅 32 位系统调用对应的寄存器含义以及源码。欢迎师傅们推荐 64 位类似功能的网站。

状态切换

user space to kernel space

当发生 系统调用产生异常外设产生中断 等事件时,会发生用户态到内核态的切换,具体的过程为:

  1. 通过 swapgs 切换 GS 段寄存器,将 GS 寄存器值和一个特定位置的值进行交换,目的是保存 GS 值,同时将该位置的值作为内核执行时的 GS 值使用。
  2. 将当前栈顶(用户空间栈顶)记录在 CPU 独占变量区域里,将 CPU 独占区域里记录的内核栈顶放入 rsp/esp。
  3. 通过 push 保存各寄存器值,具体的 代码 如下:

    ENTRY(entry_SYSCALL_64)
     /* SWAPGS_UNSAFE_STACK是一个宏,x86直接定义为swapgs指令 */
     SWAPGS_UNSAFE_STACK
        
     /* 保存栈值,并设置内核栈 */
     movq %rsp, PER_CPU_VAR(rsp_scratch)
     movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
        
        
    /* 通过push保存寄存器值,形成一个pt_regs结构 */
    /* Construct struct pt_regs on stack */
    pushq  $__USER_DS      /* pt_regs->ss */
    pushq  PER_CPU_VAR(rsp_scratch)  /* pt_regs->sp */
    pushq  %r11             /* pt_regs->flags */
    pushq  $__USER_CS      /* pt_regs->cs */
    pushq  %rcx             /* pt_regs->ip */
    pushq  %rax             /* pt_regs->orig_ax */
    pushq  %rdi             /* pt_regs->di */
    pushq  %rsi             /* pt_regs->si */
    pushq  %rdx             /* pt_regs->dx */
    pushq  %rcx tuichu    /* pt_regs->cx */
    pushq  $-ENOSYS        /* pt_regs->ax */
    pushq  %r8              /* pt_regs->r8 */
    pushq  %r9              /* pt_regs->r9 */
    pushq  %r10             /* pt_regs->r10 */
    pushq  %r11             /* pt_regs->r11 */
    sub $(6*8), %rsp      /* pt_regs->bp, bx, r12-15 not saved */
  4. 通过汇编指令判断是否为 x32_abi。

  5. 通过系统调用号,跳到全局变量 sys_call_table 相应位置继续执行系统调用。

kernel space to user space

退出时,流程如下:

  1. 通过 swapgs 恢复 GS 值
  2. 通过 sysretq 或者 iretq 恢复到用户控件继续执行。如果使用 iretq 还需要给出用户空间的一些信息(CS, eflags/rflags, esp/rsp 等)

Mitigation

canary, dep, PIE, RELRO 等保护与用户态原理和作用相同

  • smep:

CTF kernel pwn 相关

一般会给以下三种文件

  1. boot.sh: 一个用于启动 kernel 的 shell 的脚本,多用 qemu,保护措施与 qemu 不同的启动参数有关
  2. bzImage: kernel binary
  3. rootfs.cpio: 文件系统映像

比如:

CISCN2017_babydriver [master●] ls
babydriver.tar
CISCN2017_babydriver [master●] x babydriver.tar
boot.sh
bzImage
rootfs.cpio
CISCN2017_babydriver [master●] ls
babydriver.tar  boot.sh  bzImage  rootfs.cpio
CISCN2017_babydriver [master●] file bzImage
bzImage: Linux kernel x86 boot executable bzImage, version 4.4.72 (atum@ubuntu) #1 SMP Thu Jun 15 19:52:50 PDT 2017, RO-rootFS, swap_dev 0x6, Normal VGA
CISCN2017_babydriver [master●] file rootfs.cpio
rootfs.cpio: gzip compressed data, last modified: Tue Jul  4 08:39:15 2017, max compression, from Unix, original size 2844672
CISCN2017_babydriver [master●] file boot.sh
boot.sh: Bourne-Again shell script, ASCII text executable
CISCN2017_babydriver [master●] bat boot.sh 
───────┬─────────────────────────────────────────────────────────────────────────────────
       │ File: boot.sh
───────┼─────────────────────────────────────────────────────────────────────────────────
   1   │ #!/bin/bash
   2   │ 
   3   │ qemu-system-x86_64 -initrd rootfs.cpio -kernel bzImage -append 'console=ttyS0 ro
       │ ot=/dev/ram oops=panic panic=1' -enable-kvm -monitor /dev/null -m 64M --nographi
       │ c  -smp cores=1,threads=1 -cpu kvm64,+smep
───────┴─────────────────────────────────────────────────────────────────────────────────

解释一下 qemu 启动的参数:

  • -initrd rootfs.cpio,使用 rootfs.cpio 作为内核启动的文件系统
  • -kernel bzImage,使用 bzImage 作为 kernel 映像
  • -cpu kvm64,+smep,设置 CPU 的安全选项,这里开启了 smep
  • -m 64M,设置虚拟 RAM 为 64M,默认为 128M

其他的选项可以通过 –help 查看。

Example

背景知识还有很多,会在分析例题的过程中逐步介绍。

kernel UAF

attachment here

先解压 rootfs.cpio 看一下有什么文件

CISCN2017_babydriver [master●] mkdir core
CISCN2017_babydriver [master●] cd core 
core [master●] mv ../rootfs.cpio rootfs.cpio.gz
core [master●●] gunzip ./rootfs.cpio.gz 
core [master●] ls
rootfs.cpio
core [master●] cpio -idmv < rootfs.cpio 
.
etc
etc/init.d
etc/passwd
etc/group
...
...
usr/sbin/rdev
usr/sbin/ether-wake
tmp
linuxrc
home
home/ctf
5556 块
core [master●] ls
bin  etc  home  init  lib  linuxrc  proc  rootfs.cpio  sbin  sys  tmp  usr
core [master●] bat init
───────┬─────────────────────────────────────────────────────────────────────────────────
       │ File: init
───────┼─────────────────────────────────────────────────────────────────────────────────
   1   │ #!/bin/sh
   2   │
   3   │ mount -t proc none /proc
   4   │ mount -t sysfs none /sys
   5   │ mount -t devtmpfs devtmpfs /dev
   6   │ chown root:root flag
   7   │ chmod 400 flag
   8   │ exec 0</dev/console
   9   │ exec 1>/dev/console
  10   │ exec 2>/dev/console
  11   │
  12   │ insmod /lib/modules/4.4.72/babydriver.ko
  13   │ chmod 777 /dev/babydev
  14   │ echo -e "\nBoot took $(cut -d' ' -f1 /proc/uptime) seconds\n"
  15   │ setsid cttyhack setuidgid 1000 sh
  16   │
  17   │ umount /proc
  18   │ umount /sys
  19   │ poweroff -d 0  -f
  20   │
───────┴────────────────────────────────────────────────────────────

Reference and Thanks to

https://zh.wikipedia.org/wiki/内核

https://zh.wikipedia.org/wiki/分级保护域

https://www.anquanke.com/post/id/86490


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK