Xdebug 是 PHP 的调试工具,为 PHP 脚本与调试器客户端提供了一个接口,使用 DBGp 协议进行交互,使用的是 XML 格式的数据。在调试的时候,可以通过调试器在服务器上执行任意代码。通过 phpinfo()
可以查看 WebServer 上是否有开启 Xdebug,由于 Xdebug 支持远程调试,如果服务器上配置不当,可能引起远程任意命令执行。
Xdebug 在 php.ini
中进行配置,比较关键参数有几项:
1 | ; 启用远程调试 |
PHP 允许动态识别是否启动调试,当访问任意 PHP 页面时,如果浏览器的 GET,POST,COOKIE 中包含 XDEBUG_SESSION_START 参数,且 php 开启了 xdebug 模块,则会与 remote_host 的调试端口通过 TCP 协议建立会话进行 debug 信息的交互。
数据流程
固定 IP 地址
xdebug.remote_connect_back=0 的情况,这也是 Xdebug 的默认方式。
动态 IP 地址
xdebug.remote_connect_back=1 的情况
实例分析
Chrome 中有一个 Xdebug 插件,可以进行远程调试,Github 地址。在Xdebug 插件中开启监听,访问服务端的任意 PHP 页面,带上 XDEBUG_SESSION_START 参数
1 | http://192.168.1.10:8080/test.php?XDEBUG_SESSION_START=1 |
Xdebug 插件可以接收到调试会话,然后可以在上面执行任意命令。通过抓包分析可以发现,调试会话的消息是通过 XML 进行交互,会话建立的时候,服务端会发送:
1 | 490.<?xml version="1.0" encoding="iso-8859-1"?> |
当在 xdebug 中执行 PHP 代码时,例如
1 | print_r(file_get_contents('D:/1.txt'), true) |
会发送这种格式的数据给 WebServer,-i 63
是会话编号,可以取任意的数字,后面是 php 代码的 base64,最后的 . 是 \x00
。而且发送的数据包内容必须是 304 的倍数,多余的部分以 \x00
填充。
1 | eval -i 63 -- cHJpbnRfcihmaWxlX2dldF9jb250ZW50cygnRDovMS50eHQnKSwgdHJ1ZSk=............................................................................ |
当服务端接收到调试器发送的命令后,会执行其中的 PHP 代码,并返回执行结果,这个过程会返回很多个 response,其中第一个 response 就是 PHP 代码的执行结果,同样是以 base64 编码。
1 | 260.<?xml version="1.0" encoding="iso-8859-1"?> |
分析了 Xdebug 调试的交互过程,可以写出一个脚本来执行任意命令。如果是在公网上的 PHP 网站,需要有一个公网 IP 才能实现远程调试,如果只有 Linux 的公网服务器可用,可以使用这个脚本来模拟这个过程。
1 | # encoding: utf-8 |