脏牛(DirtyCow)[CVE-2016-5195]复现
脏牛(DirtyCow)[CVE-2016-5195]复现
前言
本章主要是为了解决掉前面很疑惑的脏牛提权漏洞的原理,故复现了该漏洞,主要还是为了填坑吧,这篇文章只能说是对其他文章的转载加总结,大部分内容都源于参考链接,只是添加了我的部分思考
漏洞背景
Linux内核的内存子系统的get_user_page内核函数在处理Copy-on-Write(写时拷贝,以下使用COW表示)的过程中,存在条件竞争漏洞,导致可以破坏私有只读内存映射。一个低权限的本地用户能够利用此漏洞获取其他只读内存映射的写权限,有可能进一步导致提权漏洞(修改su或者passwd程序就可以达到root的目的)
- 漏洞名称:脏牛漏洞(DirtyCow)
- 漏洞编号:CVE-2016-5195
- 影响范围:Linux kernel >= 2.6.22(2007年发行,直到2016年10月18日才修复)
- 漏洞危害: 低权限用户利用该漏洞技术可以在全版本Linux系统上实现本地提权
主流发行版修复之后的内核版本,如果你的内核版本低于列表里的版本,表示还存在脏牛漏洞。
Centos7 /RHEL7 | 3.10.0-327.36.3.el7 |
---|---|
Cetnos6/RHEL6 | 2.6.32-642.6.2.el6 |
Ubuntu 16.10 | 4.8.0-26.28 |
Ubuntu 16.04 | 4.4.0-45.66 |
Ubuntu 14.04 | 3.13.0-100.147 |
Debian 8 | 3.16.36-1+deb8u2 |
Debian 7 | 3.2.82-1 |
前置知识
docker与宿主机共享内核,如果要触发这个漏洞,需要宿主机存在dirtyCow漏洞的宿主机。
也就是说,就算你搭建一个unbuntu14.04版本的docker环境,如果你的宿主机没有这个漏洞还是无法复现,于是我们需要搭建一个unbuntu低版本的虚拟机环境去复现
我们使用ubuntu-14.04.5服务器版本来复现,建议还是用桌面版复现,后面可以方便调试和理清楚原理
Ubuntu系统镜像下载:old-releases.ubuntu.com/releases/14…
漏洞原理分析
脏牛漏洞的主要原理便是 Linux内核的内存子系统在处理写时拷贝(Copy-on-Write)时存在条件竞争漏洞,导致可以破坏私有只读内存映射。
一个低权限的本地用户能够利用此漏洞获取其他只读内存映射的写权限,所以有可能进一步导致提权漏洞。
写时拷贝
COW(copy on write)
技术即写时拷贝技术是linux程序中用的一个技术,在程序fork
进程时,内核只为子进程创建虚拟空间结构,虚拟空间拷贝父进程的对应段内容,也就是说子进程对应段和父进程指向同一块物理内存,直到父进程/子进程中有改变段内容的操作再为子进程相应段分配物理空间(如exec)。
具体地,如果父/子进程改变了段,但没有exec,则只为子进程的堆栈段分配物理内存,子进程的代码段和父进程对应同一个物理空间;若有exec,则子进程的代码段也分配物理内存,和父进程独立开来。(注:这里的exec并不是一个函数,而是一组函数的统称,包含了execl()、execlp()、execv()、execvp()
)
写时复制的好处是延迟甚至免除了内存复制,推迟到父进程或子进程向某内存页写入数据之前。传统的fork在子进程创建的时候就把进程数据拷贝给子进程,然而很多时候子进程都会实现自己的功能,调用exec替换原进程,这种情况下刚刚拷贝的数据又会被替换掉,效率低下。有了COW之后再创建新的进程只是复制了父进程的页表给子进程,并无对物理内存的操作,调用exec之后则为子进程的.text/.data/heap/stack
段分配物理内存。而如果没有exec,也没有改变段内容,相当于只读的方式共享内存。没exec但改变了段内容则子进程和父进程共享代码段,为数据段和堆栈段分配物理内存。
其实现方式可以参见Copy On Write机制了解一下,基本原理是将内存页标为只读,一旦父子进程要改变内存页内容,就会触发页异常中断,将触发的异常的内存页复制一份(其余页还是同父进程共享)。
在CTF比赛中,这里出过的考点是通过fork出的子进程爆破canary
,由于父进程和子进程共享内存空间,所以parent和child的canary一样。
缺页中断处理
缺页中断异常处理的总流程如下图。主要关注COW的条件。引起缺页异常首先要区分出是由于编程错误引起的还是由于缺页引发的错误。如果是缺页引起的错误,再去看引起错误的线性地址是否是合法地址,因为有请求调页和写时复制的机制,我们请求的页最开始是假定不会使用的,因此给的都是零页
,即全部填充为0的页,并且这个零页不需要我们分配并填充,可以直接给一个现成的并且设置为不可写。当第一次访问这个页的时候会触发缺页中断,进而激活写时复制。
[CVE-2016-5195]复现/image-20231226145318581.png)
漏洞利用
检查内核版本
[CVE-2016-5195]复现/image-20231222113435268.png)
内核版本是比较低的,存在漏洞
下载EXP脚本
1 | git clone https://github.com/FireFart/dirtycow |
下载下来后编译一下即可,命令如下
1 | gcc -pthread dirty.c -o dirty -lcrypt |
脚本使用方法
1 | ./dirty #泄露出密码 |
[CVE-2016-5195]复现/image-20231222113854151.png)
可以看到成功泄露了密码,也可以改写密码