Linux Kernel Pwn ABC(Ⅰ)(draft)

栏目: 服务器 · Linux · 发布时间: 6年前

内容简介:记录一下最近学到的 linux kernel pwn 知识,比较基础。主要参考了kernel 也是一个程序,用来管理软件发出的数据 I/O 要求,讲这些要求转义为指令,交给 CPU 和计算机中的其他组件处理,是现代操作系统最基本的部分。

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

Basic Knowledge

主要参考了 Linux Kernel Exploitation

Kernel

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

Linux Kernel Pwn ABC(Ⅰ)(draft)

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。 Linux Kernel Pwn ABC(Ⅰ)(draft)

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


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

嵌入式Linux应用程序开发详解

嵌入式Linux应用程序开发详解

孙琼 / 人民邮电出版社 / 2006-7 / 46.00元

《嵌入式Linux应用程序开发详解》主要分为3个部分,包括Linux基础、搭建嵌入式Linux环境和嵌入式Linux的应用开发。Linux基础部分从Linux的安装过程、基本操作命令讲起,为Linux初学者能快速入门提供了保证。接着系统地讲解了嵌入式Linux的环境搭建,以及嵌入式Linux的I/O与文件系统的开发、进程控制开发、进程间通信开发、网络应用开发、基于中断的开发、设备驱动程序的开发以及......一起来看看 《嵌入式Linux应用程序开发详解》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换