内核
内核的漏洞类型
init.sh中的一些命令
cpio命令:用于备份Linux文件
1 | # cpio - copy files to and from archives |
mount
1 | # mount - mount a filesystem |
chrown
1 | # chown - change file owner and group |
setsid, setuidgid
1 | # setsid [options] program [arguments] |
kernel编译
内核源码下载
gitlab地址:https://gitlab.freedesktop.org/seanpaul/kernel/-/tags
官网地址:https://mirrors.edge.kernel.org/pub/linux/kernel/
安装需要的库
1 | apt-get install libncurses5-dev build-essential kernel-package bison flex libelf-dev |
编译
下载内核后解压,进入其目录执行make menuconfig
进入 kernel hacking,勾选
- KGDB:Kernel debugging
- Compile-time checks and compiler options—>Compile the kernel with debug info
开始编译,指定架构
1 | make ARCH=x86_64 -j4 bzImage |
然后在arch/x86_64/boot
下面就会生成对应的bzImage文件
调试的链接过程
bzImage是
1 | ../linux-4.9/scripts/extract-vmlinux bzImage > vmlinux |
1 | # docker容器中貌似不支持虚拟化不能用kvm,将-enable-kvm选项去掉 |
-m
是指定RAM大小(默认384)
-kernel
是指定的内核镜像,这里是我们编译的镜像路径,也可以是下载好的镜像,如./vmlinuz-4.15.0-22-generic
-initrd
设置刚刚利用busybox
创建的rootfs.img
,作为内核启动的文件系统
-append
附加选项,指定no kaslr可以关闭随机偏移
--nographic
和console=ttyS0
一起使用,启动的界面就变成当前终端
-s
相当于-gdb tcp::1234
的简写,可以直接通过主机的gdb远程连接
-monitor
配置用户模式的网络#将监视器重定向到主机设备/dev/null
-smp
用于声明所有可能用到的cpus, i.e. sockets cores threads = maxcpus.
-cpu
设置CPU的安全选项
1 | gdb |
1 | cat /sys/module/babydriver/sections/.text |
也可以通过以下命令输出所有的字符以及对应的地址
1 | cat /proc/kallsyms |
在调试的过程中直接修改uid可能会造成环境出现差别,所以要在文件系统的启动脚本中/etc/init.d/rsC
或者/init
中添加cat /proc/kallsyms > /tmp/kallsyms
将符号信息保存下来,供之后 调试使用。
kernel pwn 的目标
Kernel Pwn 就是找出内核模块中的漏洞,然后写一个 C 语言程序,放入文件系统中打包,重新运行取来,此时用户一般都是普通用户,运行程序调用此模块的功能利用漏洞,从而提升权限到 root 用户,读取 flag。
LKM
动态可加载模块Loadable Kernel Module
可以往 Kernel 中接入各种 LKM,也可以卸载,常见的外设驱动就是一个 LKM
LKM 文件与用户态的可执行文件一样,在 Linux 中就是 ELF 文件,可以利用 IDA 进行分析
LKM 是单独编译的,但是不能单独运行,他只能作为 OS Kernel 的一部分
1 | insmod # 接入指定模块 |
ioctl
ioctl 是设备驱动程序中对设备的 I/O 通道进行管理的函数
1 | /* |
如果一个 LKM 中提供了 iotcl 功能,并且实现了对应指令的操作,那么在用户态中,通过这个驱动程序,我们可以调用 ioctl 来直接调用模块中的操作。
内核态的保护模式
常见的保护机制
KPTI
:Kernel PageTable Isolation,内核页表隔离KASLR
:Kernel Address space layout randomization,内核地址空间布局随机化SMEP
:Supervisor Mode Execution Prevention,管理模式执行保护SMAP
:Supervisor Mode Access Prevention,管理模式访问保护Stack Protector
:Stack Protector又名canary,stack cookiekptr_restrict
:允许查看内核函数地址dmesg_restrict
:允许查看printk
函数输出,用dmesg
命令来查看MMAP_MIN_ADDR
:不允许申请NULL
地址mmap(0,....)
KASLR
、Stack Protector
与用户态下的ASLR
、canary
保护机制相似。
KASLR
相当于alsr开启后地址空间进行随机化布局。
内核地址空间布局随机化,并不默认开启,需要在内核命令行中添加指定指令。
qemu 增加启动参数 -append “kaslr” 即可开启
Stack Protector
相当于开启了canary,对栈上的地址进行保护。
MMAP_MIN_ADDR
保护机制不允许程序分配低内存地址
SMEP
管理模式执行保护,保护内核是其不允许执行用户空间代码。
操作系统是通过 CR4 寄存器的第 20 位的值来判断 SMEP 是否开启,1 开启,0 关闭,检查 SMEP 是否开启,可通过 mov 指令给 CR4 寄存器赋值从而达到关闭 SMEP 的目的,相关的 mov 指令可以通过 ropper,ROPgadget 等工具查找。
SMAP
管理模式访问保护,禁止内核访问用户空间的数据
提权
内核态调用commit_creds(prepare_kernel_cred(0)),返回用户态执行shell
1
commit_creds(prepare_kernel_cred(0)
修改cred结构体
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39struct cred {
atomic_t usage;
atomic_t subscribers; /* number of processes subscribed */
void *put_addr;
unsigned magic;
kuid_t uid; /* real UID of the task */
kgid_t gid; /* real GID of the task */
kuid_t suid; /* saved UID of the task */
kgid_t sgid; /* saved GID of the task */
kuid_t euid; /* effective UID of the task */
kgid_t egid; /* effective GID of the task */
kuid_t fsuid; /* UID for VFS ops */
kgid_t fsgid; /* GID for VFS ops */
unsigned securebits; /* SUID-less security management */
kernel_cap_t cap_inheritable; /* caps our children can inherit */
kernel_cap_t cap_permitted; /* caps we're permitted */
kernel_cap_t cap_effective; /* caps we can actually use */
kernel_cap_t cap_bset; /* capability bounding set */
kernel_cap_t cap_ambient; /* Ambient capability set */
unsigned char jit_keyring; /* default keyring to attach requested
* keys to */
struct key __rcu *session_keyring; /* keyring inherited over fork */
struct key *process_keyring; /* keyring private to this process */
struct key *thread_keyring; /* keyring private to this thread */
struct key *request_key_auth; /* assumed request_key authority */
void *security; /* subjective LSM security */
struct user_struct *user; /* real user ID subscription */
struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */
struct group_info *group_info; /* supplementary groups for euid/fsgid */
struct rcu_head rcu; /* RCU deletion hook */
};