0%

VDSO就是Virtual Dynamic Shared Object,是内核提供的虚拟的.so,这个.so文件不在磁盘上,而是在内核里头。内核把包含某.so的内存页在程序启动的时候映射入其内存空间,对应的程序就可以当普通的.so来使用里面的函数。Vdso里面封装了这几个函数,其作用主要是加快对于某些对速度要求很高的系统调用,更多详细信息可以查看https://blog.csdn.net/juana1/article/details/6904932

由于vdso是在内核里,每个程序使用的时候,从内核里映射给程序,如果我们事先在内核里把vdso给劫持了,并把相应的函数覆盖成我们的shellcode,然后,当其他程序要用的时候,从内核把我们篡改过的vdso映射过去,如果它正好调用了对应的函数,就会执行我们对应位置布下的shellcode。当然普通权限的程序,调用我们的shellcode,也只是普通权限;如果有root权限的程序,调用我们的shellcode,那么我们的shellcode也是以root权限执行。在linux中,crontab是带有root权限的,并且它会不断的调用vdso里的gettimeofday函数,因此,我们如果把gettimeofday函数劫持为shellcode,等待被调用即可。至于为什么可以劫持vdso,因为vdso对于用户程序,只读、执行,而对于内核,它是RWX的,可以修改。因此只要利用漏洞,将对于函数修改为shellcode,布置在vdso的shellcode可以为反弹shell的shellcode,也可以是再运行一个其他程序,其他程序将继承权限。以CSAW-2015-StringIPC为例。

阅读全文 »

首先,查看一下启动脚本,发现没有开smap、smep、kaslr

1
2
3
4
5
6
7
8
qemu-system-x86_64 \  
-m 512 \
-kernel ./bzImage \
-initrd ./rootfs.cpio \
-append "console=ttyS0 root=/dev/ram rdinit=/sbin/init" \
-nographic \
-s \
-netdev user,id=t0, -device e1000,netdev=t0,id=nic0 \

查看一下内核版本,为4.4.x

阅读全文 »

userfaultfd是linux下的一直缺页处理机制,用户可以自定义函数来处理这种事件。所谓的缺页,就是所访问的页面还没有装入RAM中。比如mmap创建的堆,它实际上还没有装载到内存中,系统有自己默认的机制来处理,用户也可以自定义处理函数,在处理函数没有结束之前,缺页发生的位置将处于暂停状态。这将非常有助于条件竞争的利用

举个栗子

假如在内核里有这样一段代码

阅读全文 »

条件竞争发生在多线程多进程中,往往是因为没有对全局数据、函数进行加锁,导致多进程同时访问修改,使得数据与理想的不一致而引发漏洞。本节,我们从wctf2018-klist这题来分析一下条件竞争制造UAF的利用。

wctf2018-klist

首先,查看一下启动脚本,发现开启了smep机制,说明内核不能直接执行用户空间的代码

阅读全文 »

Linux内核使用的是slab/slub分配器,与glibc下的ptmalloc有许多类似的地方。比如kfree后,[原来的用户数据区的前8字节会有指向下一个空闲块的指针]{.mark}。如果用户请求的大小在空闲的堆块里有满足要求的,则直接取出。

通过调试,可以发现,被释放的堆的**[数据域前8字节]{.mark}正好指向下一个空闲堆的[数据域]{.mark}**

阅读全文 »

当用户打开ptmx驱动时,会分配一个tty_struct结构,它的结构如下

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
struct tty_struct {  
int magic;
struct kref kref;
struct device *dev;
struct tty_driver *driver;
const struct tty_operations *ops;
int index;
/* Protects ldisc changes: Lock tty not pty */
struct ld_semaphore ldisc_sem;
struct tty_ldisc *ldisc;
struct mutex atomic_write_lock;
struct mutex legacy_mutex;
struct mutex throttle_mutex;
struct rw_semaphore termios_rwsem;
struct mutex winsize_mutex;
spinlock_t ctrl_lock;
spinlock_t flow_lock;
/* Termios values are protected by the termios rwsem */
struct ktermios termios, termios_locked;
struct termiox *termiox; /* May be NULL for unsupported */
char name[64];
struct pid *pgrp; /* Protected by ctrl lock */
struct pid *session;
unsigned long flags;
int count;
struct winsize winsize; /* winsize_mutex */
unsigned long stopped:1, /* flow_lock */
flow_stopped:1,
unused:BITS_PER_LONG - 2;
int hw_stopped;
unsigned long ctrl_status:8, /* ctrl_lock */
packet:1,
unused_ctrl:BITS_PER_LONG - 9;
unsigned int receive_room; /* Bytes free for queue */
int flow_change;
struct tty_struct *link;
struct fasync_struct *fasync;
wait_queue_head_t write_wait;
wait_queue_head_t read_wait;
struct work_struct hangup_work;
void *disc_data;
void *driver_data;
spinlock_t files_lock; /* protects tty_files list */
struct list_head tty_files;
#define N_TTY_BUF_SIZE 4096
int closing;
unsigned char *write_buf;
int write_cnt;
/* If the tty has a pending do_SAK, queue it here - akpm */
struct work_struct SAK_work;
struct tty_port *port;
} __randomize_layout;

其中有一个**[const struct tty_operations *ops]{.mark}**指针,它是一个tty_operations指针,而tty_operations结构体里是一些列对驱动操作的函数指针。

阅读全文 »

与用户态下的glibc差不多,都是对已经释放的空间未申请就直接使用,[内核的UAF往往是出现在多线程多进程多文件的情况下。]{.mark}即,假如某个用户程序对用一个内核驱动文件打开了两次,有两个文件描述符,它们都指向了该驱动,又因为是在同一个程序里,所以[当我们释放掉其中一个文件描述符后,还可以使用另一个文件描述符来操控驱动。]{.mark}

为了加深理解,我们就以一题为例

ciscn2017_babydriver

阅读全文 »

Linux kernel rop根glibc下的ROP思路是差不多的,当我们学习掌握了glibc下的ROP,再来看kernel的ROP攻击,就很容易理解了。

与用户态同样的是,内核有也类似于PIE的机制,加kaslr,在启动系统时的脚本里可以指定开启或关闭kaslr。

1
2
3
4
5
6
7
8
qemu-system-x86_64 \  
-m 256M \
-kernel ./bzImage \
-initrd ./core.cpio \
-append "root=/dev/ram rw console=ttyS0 oops=panic panic=1 quiet kaslr" \
-s \
-netdev user,id=t0, -device e1000,netdev=t0,id=nic0 \
-nographic \
阅读全文 »

首先,我们用IDA分析一下驱动文件zerofs.ko,发现该驱动注册了一个文件系统,实现了一个自己的文件系统。

题目改编自simplefs,https://github.com/psankar/simplefs,一个简易的文件系统,可以实现文件的存储。而本题,在上面的基础上做了精简修改。并且留有几个漏洞。一个文件系统的镜像,需要mount到目录上,才能使用。而mount是如何来识别这些文件系统的呢,这就靠驱动,register_filesystem将用户定义的文件系统注册,链接到系统维护的一个文件系统表上,mount遍历这张表,丛中取出对应的文件系统,并使用驱动里提供的一系列文件操作。

阅读全文 »

Double fetch漏洞是一种条件竞争漏洞,由于多线程的原因,使得内核里多次访问到用户的数据不一致而引发的漏洞。我们用户态传数据给内核,如果是简单的数据,则按传值传递,如果数据量很大很复杂,我们则传指针给内核。内核里首先会对数据的合理性进行校验,校验成功后,待会内核又重新在某处来访问我们的数据,而如果有另外一个线程在这之前篡改了数据,就使得数据不一致,从而可能形成漏洞。

我们以0ctf2018-final-baby这题为例

首先,我们用IDA分析一下ko驱动文件

阅读全文 »