Prctl是linux的一个函数,可以对进程、线程做一些设置,prctl内部通过虚表来调用对应的功能,如果我们劫持prctl的虚表,使它指向其他对我们有帮助的内核函数,比如call_usermodehelper函数,该函数执行一个用户传入的二进制文件,且以root权限执行,由此可以利用起来提权。
我们分析一下prctl源码,在linux/kernel/sys.c里,我们看到这
Prctl是linux的一个函数,可以对进程、线程做一些设置,prctl内部通过虚表来调用对应的功能,如果我们劫持prctl的虚表,使它指向其他对我们有帮助的内核函数,比如call_usermodehelper函数,该函数执行一个用户传入的二进制文件,且以root权限执行,由此可以利用起来提权。
我们分析一下prctl源码,在linux/kernel/sys.c里,我们看到这
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 | qemu-system-x86_64 \ |
查看一下内核版本,为4.4.x
Linux内核使用的是slab/slub分配器,与glibc下的ptmalloc有许多类似的地方。比如kfree后,[原来的用户数据区的前8字节会有指向下一个空闲块的指针]{.mark}。如果用户请求的大小在空闲的堆块里有满足要求的,则直接取出。
通过调试,可以发现,被释放的堆的**[数据域前8字节]{.mark}正好指向下一个空闲堆的[数据域]{.mark}**
当用户打开ptmx驱动时,会分配一个tty_struct结构,它的结构如下
1 | struct tty_struct { |
其中有一个**[const struct tty_operations *ops]{.mark}**指针,它是一个tty_operations指针,而tty_operations结构体里是一些列对驱动操作的函数指针。
Linux kernel rop根glibc下的ROP思路是差不多的,当我们学习掌握了glibc下的ROP,再来看kernel的ROP攻击,就很容易理解了。
与用户态同样的是,内核有也类似于PIE的机制,加kaslr,在启动系统时的脚本里可以指定开启或关闭kaslr。
1 | qemu-system-x86_64 \ |
首先,我们用IDA分析一下驱动文件zerofs.ko,发现该驱动注册了一个文件系统,实现了一个自己的文件系统。
题目改编自simplefs,https://github.com/psankar/simplefs,一个简易的文件系统,可以实现文件的存储。而本题,在上面的基础上做了精简修改。并且留有几个漏洞。一个文件系统的镜像,需要mount到目录上,才能使用。而mount是如何来识别这些文件系统的呢,这就靠驱动,register_filesystem将用户定义的文件系统注册,链接到系统维护的一个文件系统表上,mount遍历这张表,丛中取出对应的文件系统,并使用驱动里提供的一系列文件操作。