内容简介:记录一下最近学到的 linux kernel pwn 知识,比较基础。主要参考了kernel 也是一个程序,用来管理软件发出的数据 I/O 要求,讲这些要求转义为指令,交给 CPU 和计算机中的其他组件处理,是现代操作系统最基本的部分。
记录一下最近学到的 linux kernel pwn 知识,比较基础。
Basic Knowledge
主要参考了 Linux Kernel Exploitation 。
Kernel
kernel 也是一个程序,用来管理软件发出的数据 I/O 要求,讲这些要求转义为指令,交给 CPU 和计算机中的其他组件处理,是现代操作系统最基本的部分。
kernel 最主要的功能有两点:
- 控制并与硬件进行交互
- 提供 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。
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
当发生 系统调用
, 产生异常
, 外设产生中断
等事件时,会发生用户态到内核态的切换,具体的过程为:
- 通过
swapgs
切换 GS 段寄存器,将 GS 寄存器值和一个特定位置的值进行交换,目的是保存 GS 值,同时将该位置的值作为内核执行时的 GS 值使用。 - 将当前栈顶(用户空间栈顶)记录在 CPU 独占变量区域里,将 CPU 独占区域里记录的内核栈顶放入 rsp/esp。
-
通过 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 */
-
通过汇编指令判断是否为 x32_abi。
-
通过系统调用号,跳到全局变量
sys_call_table
相应位置继续执行系统调用。
kernel space to user space
退出时,流程如下:
- 通过
swapgs
恢复 GS 值 - 通过
sysretq
或者iretq
恢复到用户控件继续执行。如果使用iretq
还需要给出用户空间的一些信息(CS, eflags/rflags, esp/rsp 等)
Mitigation
canary, dep, PIE, RELRO 等保护与用户态原理和作用相同
- smep:
CTF kernel pwn 相关
一般会给以下三种文件
- boot.sh: 一个用于启动 kernel 的 shell 的脚本,多用 qemu,保护措施与 qemu 不同的启动参数有关
- bzImage: kernel binary
- 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
先解压 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/内核
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
随机密码生成器
多种字符组合密码
HEX CMYK 转换工具
HEX CMYK 互转工具