cve-2022-32250
学习了一段时间的 kernel pwn 之后,想去看看真实场景的 cve 是怎样的。看了一部分,有点太久了先咕咕咕,之后有时间再说…
nftables 介绍
分析这个 cve 的过程中遇到的比较大的阻碍是看分析源码比较晕,因为 nftables 不太熟悉。于是本文就从详细记录了一下利用命令行和 library 和 nftables 交互的方式,了解一个大致的结构和逻辑之后,看源码就轻松多了。
基本概念
nft
是命令行工具,用于在用户空间与 nftables 交互,它的基本使用可以查看: How to Use nftables | Linode Docs。这是一个 Linux 数据包分类框架,有表、链、规则几个概念。
table chain rule
PAWNYABLE kernel userfaultfd 笔记
感觉这个是比较古老(2020 左右的)用法了,看看即可?
概念
userfaultfd 可以类比成一个缺页异常的 handler,如果 handler 可以处理很久,那可能更好达到竞争的效果
工作流程
参考 Kernel Pwn Syscall userfaultfd and Syscall setxattr - Wings 的博客
户通过userfaultfd
系统调用接收文件描述符,并使用ioctl
将处理程序和地址等设置应用于它。当设置了 userfaultfd 的页面(第一次访问)发生页面错误时,将调用设置的处理程序,用户可以指定返回哪种数据(映射)。
在 CTF 题中通常用来卡条件竞争. 当内核模块中有 copy from/to user 的时候, 内核模块会访问用户的空间. 如果我们传入的是一个被 uffd 监视的地址, 那么这个线程将会被挂起直到处理结束. 这样就能够控制内核中线程的执行顺序, 从而更好的达到想要的竞争效果.
可能涉及了保护措施
大概是 linux-5.11 之后默认开启
对于没有
CAP_SYS_PTRACE
的用户以完全权限使用userfaultfd
,必须将unprivileged_userfaultfd
标志设置为 1。这个标志是/proc/sys/vm/unprivileged_userfaultfd
可以通过 进行设置和查看,默认设置为0,但可以确认在LK04机器上设置为1。
使用实例 ,参考 userfaultfd 的使用 - CTF Wiki:
先用 userfaultfd 系统调用获得一个 fd
Synology BC500 摄像头 rce | rwctf Lets-party-in-the-house
题目给了的附件有 player.cpio run.sh zImage
。原始固件可以从 Synology Archive Download Site - Index of /download/Firmware/Camera/BC500下载。
概况的分析
如何获取终端 ?
如果直接模拟固件,终端会被报错信息填满,可以在 /etc/init.d/rcS
使用 telnetd -p 23 -l /bin/sh
开启 telnet 服务,然后在脚本上加一个 hostfw 参数映射 telnet 到主机上进行操作。
PAWNYABLE kernel double fetch 笔记
感觉就像是 toctou?先检查后使用?
static long module_ioctl(struct file *filp,
unsigned int cmd,
unsigned long arg) {
if (verify_request((void*)arg))
return -EINVAL;
switch (cmd) {
case CMD_GET: return copy_data_to_user(filp, (void*)arg);
case CMD_SET: return copy_data_from_user(filp, (void*)arg);
default: return -EINVAL;
}
}
如果没开 smap
堆块的范围是 kmalloc-32,可以用 seq structure 获得 kernel base。
PAWNYABLE NULL Pointer Dereference 笔记
现在把基础的和 user mode 类似的部分看完了,该看内核独有的攻击咯。
概念
攻击的前提条件
-
为了完成 null ptr dereference,需要先禁用 SMAP(内核从用户态读写数据)
-
以及
cat /proc/sys/vm/mmap_min_addr
需要是 0。mmap 需要可以拿到地址为 0 的区域。
所以这么看起来,利用的条件还是比较原始的….
模块源码分析
看 mondule_ioctl 的功能的话,这个模块可以基于 ctx->key 和 ctx->data 对数据进行亦或的加解密。
虽然 CMD_SETKEY
有检查 private_data
是否已经初始化。但是, CMD_GETDATA
、 CMD_ENCRYPT
、 CMD_DECRYPT
没有此检查。就是说,如果 ctx 为 0 的话,也是可以进行 CMD_GETDATA
、 CMD_ENCRYPT
、 CMD_DECRYPT
的,只不过是用了用户空间的数据。
用户态控制 0x0 的地址
mmap 的参数设置中:
-
MAP_FIXED
强制将映射的内存区域放置在指定的地址。 -
MAP_POPULATE
: 在mmap
调用中使用MAP_POPULATE
标志主要是为了提前将映射的内存区域加载到物理内存中,而不是等到访问这些内存时才触发页面的加载。这对于一些需要确保快速访问内存的情况特别有用,尤其是当内存区域被映射为匿名内存 (MAP_ANONYMOUS
) 时。
PAWNYABLE kernel race condition 笔记
漏洞点在于,open 的时候 mutex 的检查和设置不是原子操作。
PAWNYABLE kernel heap overflow 笔记
kernel heap 结构
slab 的结构虽然之前看过了好多,但是现在再看还是感觉有点迷糊。大概是 slab 上的块是没有 metadata 的,但是释放的时候和使用的时候状态不同,释放的时候会存指针。不过既然 kernel 修改链表指针的操作不像 ptmalloc 这么多,那就不太细看了(
tty structure 用于泄露地址
本题的堆块申请大小是 0x400,和 tty structure 这个结构体申请的大小一样。大小一样的块物理地址可能相邻,所以溢出的时候可能可以复写到。
2024 网鼎杯半决赛 pwn 题 cardmaster
2024 网鼎杯半决赛 pwn 题 cardmaster。
结构体可以恢复成这个样子:
PAWNYABLE kernel stack overflow 笔记
PAWNYABLE 中的第一节 stack overflow 的学习笔记。( 觉得这个教程好细致,而且封面好可爱… 这一节讨论内核的栈溢出,分成了不同防护程度的情况来讨论不同的情况下面,攻击应该如何进行。
基本的思路
在 module_write 里面,copy_from_user 的大小是用户控制,大小没有检查的。可以在这里发生溢出。read 也有这个漏洞,可以读取更多的数据(
网鼎杯 2024 玄武 pwn2 (kernel)
setup 准备工作
void unshare_setup() {
char edit[0x100];
int tmp_fd;
// from lib pthread
unshare(CLONE_NEWNS | CLONE_NEWUSER | CLONE_NEWNET);
// from lib fcntl
tmp_fd = open("/proc/self/setgroups", O_WRONLY);
write(tmp_fd, "deny", strlen("deny"));
close(tmp_fd);
tmp_fd = open("/proc/self/uid_map", O_WRONLY);
sprintf(edit, "0 %d 1", getuid());
write(tmp_fd, edit, strlen(edit));
tmp_fd = open("/proc/self/gid_map", O_WRONLY);
snprintf(edit, sizeof(edit), "0 %d 1", getgid());
write(tmp_fd, edit, strlen(edit));
close(tmp_fd);
}
这个函数的目的是为当前进程配置新的名字空间,尤其是
mount
、user
和network
名字空间,确保进程在新的名字空间中有隔离的环境。此外,它通过设置 UID 和 GID 映射来确保进程在新的用户名字空间中以 root 用户身份 (UID 0) 运行,但在主机系统中仍保持原有的 UID 和 GID。这种做法通常用于容器技术或者其他需要进程隔离的场景。