首页
社区
课程
招聘
[原创]安天移动安全发布“大脏牛”漏洞分析报告(CVE-2017-1000405)
发表于: 2017-12-18 10:50 2899

[原创]安天移动安全发布“大脏牛”漏洞分析报告(CVE-2017-1000405)

2017-12-18 10:50
2899


一、背景简介

  脏牛漏洞(CVE-2016–5195)是公开后影响范围最广和最深的漏洞之一,这十年来的每一个Linux版本,包括Android、桌面版和服务器版都受到其影响。恶意攻击者通过该漏洞可以轻易地绕过常用的漏洞防御方法,对几百万的用户进行攻击。尽管已针对该漏洞进行了补丁修复,但国外安全公司Bindecy对该补丁和内容做出深入研究后发现,脏牛漏洞的修复补丁仍存在缺陷,由此产生了“大脏牛”漏洞。基于多年以来针对移动端漏洞的技术积累和安全对抗,安天移动安全对“大脏牛”漏洞进行了详细的技术分析,并提供了验证方案,全文如下。

二、漏洞原理分析

2.1 脏牛漏洞回顾

  在分析大脏牛漏洞前,我们需要对原始的脏牛漏洞利用方式进行完整的分析理解: 之前的漏洞是在get_user_pages函数中,这个函数能够获取用户进程调用的虚拟地址之后的物理地址,调用者需要声明它想要执行的具体操作(例如写/锁等操作),所以内存管理可以准备相对应的内存页。具体来说,也就是当进行写入私有映射的内存页时,会经过一个COW(写时拷贝)的过程,即复制只读页生成一个带有写权限的新页,原始页可能是私有保护不可写的,但它可以被其他进程映射使用。用户也可以在COW后的新页中修改内容之后重新写入到磁盘中。         

  现在我们来具体看下get_user_pages函数的相关代码:


  整个while循环的目的是获取请求页队列中的每个页,反复操作直到满足构建所有内存映射的需求,这也是retry标签的作用。 

  follow_page_mask读取页表来获取指定地址的物理页(同时通过PTE允许)或获取不满足需求的请求内容。在follow_page_mask操作中会获取PTE的spinlock,用来保护试图获取内容的物理页不会被释放掉。

  faultin_page函数申请内存管理的权限(同样有PTE的spinlock保护)来处理目标地址中的错误信息。在成功调用faultin_page后,锁会自动释放,从而保证follow_page_mask能够成功进行下一次尝试,以下是涉及到的代码。         

  原始的漏洞代码在faultin_page底部:


  上面这个判断语句想要表示的是,如果当前VMA中的标志显示当前页不可写,但是用户又执行了页的写操作,那么内核会执行COW操作,并且在处理中会有VM_FAULT_WRITE标志。换句话说在执行了COW操作后,上面的if判断为真,这时就移除了FOLL_WRITE标志。         

  一般情况下在COW操作后移除FOLL_WRITE标志是没有问题的,因为这时VMA指向的页是刚经过写时拷贝复制的新页,我们是有写权限的,后续不进行写权限检查并不会有问题。 但是,考虑这样一种情况,如果在这个时候用户通过madvise(MADV_DONTNEED)将刚刚申请的新页丢弃掉,那这时本来在faultin_page后应该成功的follow_page_mask会再次失败,又会进入faultin_page的逻辑,但是这个时候已经没有FOLL_WRITE的权限检查了,只会检查可读性。这时内核就会将只读页面直接映射到我们的进程空间里,这时VMA指向的页不再是通过COW获得的页,而是文件的原始页,这就获得了任意写文件的能力。   

  基本来看,上述的过程流也就是脏牛漏洞的利用过程。   

  在faultin_page中有对应的修复补丁:

  同时也加入了另一个新的follow_page_mask函数:

  与减少权限请求数不同,get_user_pages现在记住了经过COW循环的过程。之后只需要有FOLL_FORCE和FOLL_COW标志声明过且PTE标记为污染,就可以获取只读页的写入操作。

2.2 大脏牛漏洞分析

  THP通过PMD(Pages Medium目录,PTE文件下一级)的_PAGE_PSE设置来打开,PMD指向一个2MB的内存页而非PTEs目录。PMDs在每一次扫描到页表时都会通过pmd_trans_huge函数进行检查,所以我们可以通过观察PMD指向pfn还是PTEs目录来判断是否可以聚合。在一些结构中,大PUDs(上一级目录)同样存在,这会导致产生1GB的页。 仔细查看脏牛补丁中关于THP的部分,我们可以发现大PMDs中用了和can_follow_write_pte同样的逻辑,其添加的对应函数can_follow_write_pmd:

  然而在大PMD中,一个页可以通过touch_pmd函数,无需COW循环就标记为dirty:

  这个函数在每次get_user_pages调用follow_page_mask试图访问大页面时被调用,很明显这个注释有问题,而现在dirty bit并非无意义的,尤其是在使用get_user_pages来读取大页时,这个页会无需经过COW循环而标记为dirty,使得can_follow_write_pmd的逻辑发生错误。

  在此时, 如何利用该漏洞就很明显了,我们可以使用类似脏牛的方法。这次在我们丢弃复制的内存页后,必须触发两次page fault,第一次创建它,第二次写入dirty bit。

  调用链:

  经过这个过程可以获得一个标记为脏的页面,并且是未COW的,剩下的就是要获取FOLL_FORCE和FOLL_COW标志了。这个过程可以采取类似dirtyCOW的利用方式。   

  总结这个漏洞利用的思路如下:   

1.首先经过COW循环,获取到FOLL_COW标志
2.用madvise干掉脏页
3.再次获取页将直接标记为脏
4.写入

三、影响范围

3.1 漏洞影响范围

  由于从2.6.38内核后才开始支持THP,所以漏洞影响所有内核在2.6.38以上并且开启THP的Linux系统。万幸的是在大多数Android系统的内核中没有开启THP,所以对于Android系统几乎没有影响。

3.2 如何在系统上查看是否受到影响

  如果是开发者,有内核源码可以查看编译的config文件,看CONFIG_TRANSPARENT_HUGEPAGE是否打开

  如果没有源码,在shell中可以查看/sys/kernel/mm/transparent_hugepage/enabled,如果输出结果为[always]表示透明大页被启用、[never]表示透明大页被禁用、[madvise]表示只在MADV_HUGEPAGE标志的VMA中启用THP,例如:

  如果以上两者都没有,可以查看/proc/meminfo,如果连HugePage*都没有,那就说明没有开启大页面,也不会受到漏洞影响。

四、验证代码

  验证POC请参照:cc5K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6T1K9h3&6V1k6h3y4&6i4K6u0r3d9s2g2Y4k6f1c8A6M7Y4c8&6b7$3!0%4f1p5!0o6

五、修复建议

  截止到文章发布时间,Linux各发行版本还未公布针对该漏洞的补丁信息,软件开发人员可通过:c2aK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Q4x3X3g2C8k6i4u0F1k6h3I4Q4x3X3g2G2M7X3N6Q4x3V1k6H3N6h3u0Q4x3V1k6K6j5$3#2Q4x3V1k6D9K9h3&6#2P5q4)9J5c8X3E0W2M7X3&6W2L8q4)9J5c8X3N6A6N6q4)9J5c8Y4y4@1j5h3u0D9k6g2)9J5c8X3I4A6L8Y4g2^5i4K6u0V1M7%4c8S2j5X3I4W2i4K6u0W2k6$3W2@1i4K6u0r3j5$3!0E0L8h3W2@1i4K6u0r3i4K6y4r3K9q4)9K6c8r3I4A6L8Y4g2^5i4K6u0V1y4q4)9J5k6e0W2Q4x3X3g2&6i4K6t1$3j5h3#2H3i4K6y4n7K9h3c8Q4x3@1b7%4x3o6x3I4j5h3f1J5j5h3t1K6y4$3b7K6k6r3j5#2x3$3x3@1j5e0c8W2z5e0V1H3x3K6x3J5z5h3p5#2k6o6x3^5j5K6M7@1y4h3g2U0i4@1f1&6i4K6R3%4i4K6S2p5i4@1f1$3i4K6V1$3i4@1t1H3i4@1f1%4i4@1u0o6i4K6V1$3i4@1f1^5i4@1q4r3i4K6V1I4e0r3W2F1N6i4S2Q4c8e0c8Q4b7V1k6Q4b7f1g2Q4c8e0g2Q4b7e0c8Q4z5p5c8Q4c8e0S2Q4b7f1k6Q4b7e0g2Q4c8e0k6Q4b7V1y4Q4z5p5k6Q4c8e0k6Q4b7U0c8Q4z5f1g2Q4c8e0y4Q4z5o6m8Q4z5o6u0Q4c8e0g2Q4b7e0k6Q4z5o6u0Q4c8e0k6Q4z5f1g2Q4z5f1y4Q4c8e0g2Q4b7V1y4Q4z5o6m8Q4c8e0g2Q4z5p5k6Q4z5e0q4Q4c8e0c8Q4b7V1q4Q4b7V1q4Q4c8e0g2Q4z5e0q4Q4z5e0S2Q4c8e0k6Q4z5f1q4Q4z5o6u0Q4c8e0k6Q4z5e0N6Q4b7U0k6Q4c8e0k6Q4z5e0N6Q4b7e0m8Q4c8e0k6Q4b7U0y4Q4z5e0g2Q4c8e0N6Q4b7V1y4Q4z5e0k6Q4c8e0S2Q4b7f1k6Q4z5e0q4Q4c8e0g2Q4z5e0u0Q4z5p5y4Q4c8e0k6Q4z5f1u0Q4b7V1k6Q4c8e0k6Q4z5p5c8Q4b7e0u0Q4c8e0g2Q4z5o6k6Q4z5o6g2Q4c8e0k6Q4b7e0m8Q4b7U0S2Q4c8f1k6Q4b7V1y4Q4z5p5y4Q4c8e0g2Q4z5p5k6Q4b7f1k6Q4c8e0c8Q4b7V1u0Q4b7e0g2Q4c8e0W2Q4z5o6m8Q4z5f1q4Q4c8e0S2Q4b7V1k6Q4z5o6N6Q4c8e0g2Q4z5o6g2Q4b7U0y4Q4c8e0W2Q4z5e0N6Q4b7f1c8Q4c8e0W2Q4z5o6m8Q4z5p5k6Q4c8e0k6Q4z5e0S2Q4z5p5g2Q4c8e0g2Q4b7e0c8Q4b7e0N6Q4c8e0W2Q4b7e0q4Q4b7U0g2Q4c8f1k6Q4b7V1y4Q4z5o6S2f1d9q4m8Q4c8f1k6Q4b7V1y4Q4z5o6W2Q4c8e0k6Q4z5f1c8Q4b7e0g2Q4c8e0N6Q4b7V1y4Q4z5e0y4Q4c8e0S2Q4b7e0N6Q4b7e0y4Q4c8e0y4Q4z5o6m8Q4z5o6t1`.

六、总结

  “脏牛”漏洞是Linux内核之父Linus亲自修复的,他提交的补丁单独针对“脏牛”而言并没有问题。从我们的分析过程中发现,内核的开发者希望将“脏牛”的修复方法引用到PMD的逻辑中,但是由于PMD的逻辑和PTE并不完全一致才最终导致了“大脏牛”漏洞。连内核的开发者都会犯错,更何况普通的开发者。   

  “大脏牛”漏洞再一次提示我们,即便是官方修复过的漏洞仍有可能由修复补丁引入新的严重漏洞,漏洞在修复后需要我们像对待原始漏洞一样继续跟踪其修复补丁。

七、参考资料

1.fefK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6E0k6h3c8A6N6h3#2Q4x3X3g2U0L8$3#2Q4x3V1k6T1K9h3&6V1k6h3y4&6i4K6u0r3K9s2g2Y4k6g2)9J5k6r3c8A6M7Y4c8&6i4K6u0V1j5$3!0%4i4K6u0V1j5%4k6W2i4K6u0V1x3U0l9I4y4#2)9J5k6o6p5H3x3o6l9@1x3o6g2Q4x3X3b7I4x3e0m8W2j5$3p5I4x3K6u0V1k6e0m8Q4x3U0k6F1j5Y4y4H3i4K6y4n7

2.https://bbs.pediy.com/thread-223056.htm 

3.01dK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0N6X3g2Q4x3X3g2E0K9i4c8J5k6g2)9J5k6h3!0J5k6#2)9J5c8X3y4Y4K9g2)9J5k6r3u0A6L8W2)9J5c8X3y4$3k6h3&6S2L8h3g2Q4x3X3g2U0k6$3W2Q4x3@1k6F1j5h3#2W2i4K6y4p5b7#2k6q4i4K6u0V1x3U0l9I4y4#2)9J5k6o6p5H3x3o6l9@1x3o6f1`.


更多信息详见公司官网:fdeK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3q4$3L8s2y4W2j5#2)9J5k6h3y4G2L8g2!0q4x3#2)9^5x3q4)9^5x3q4!0q4x3#2)9^5x3q4)9^5x3l9`.`.

转载请注明来源:7b9K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3u0D9L8$3N6Q4x3X3g2S2N6X3I4K6k6h3y4Q4x3X3g2U0L8$3#2Q4x3V1k6Q4x3@1k6H3i4K6y4p5y4o6V1$3x3b7`.`.



[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回