关联漏洞
描述
Snipe-IT PoC exploit for CVE-2025-59712 and CVE-2025-59713
介绍
# PoC for CVE-2025-59712 and CVE-2025-59713
This PoC provides an automated script to exploit CVE-2025-59712 (XSS in `User-Agent` header) and CVE-2025-59713 (unsafe deserialization).
## Context
These two vulnerabilities were discovered by Synacktiv during vulnerability research on the Snipe-IT software. Snipe-IT is an open-source asset management system based on Laravel and designed to help organizations track and manage their physical and digital assets.
A technical writeup can be found in the dedicated security advisory on [Synacktiv's website](https://synacktiv.com/advisories/security-vulnerabilities-in-snipe-it).
## Modes
This script provides three subcommands, corresponding to exploitation modes: `xss`, `rce` and `fullchain`.
### XSS
This subcommand exploits CVE-2025-59712, which allows a low-privileged user to inject arbitrary JavaScript in the HTML page rendered when calling the `/reports/activity` route. This can only be done by an admin user, or a user that has explicit view permissions for reports. The injection is possible due to unproper sanitization of the `User-Agent` field when a user updates their profile information.
To do so, it will first log in as the low-privileged user, and then inject the JavaScript code defined in the file supplied via the `--javascript` flag.
```bash
$ python3 exploit.py xss --help
Usage: exploit.py xss [OPTIONS]
Execute XSS attack only with custom JavaScript payload
╭─ Options ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ * --url -u TEXT Target Snipe-IT URL [required] │
│ * --login -l TEXT Low-privileged username [required] │
│ * --password -p TEXT Low-privileged password [required] │
│ * --new-name -n TEXT New name for low-privileged user [required] │
│ * --javascript -js TEXT Path to custom JavaScript file [required] │
│ --proxy -x TEXT HTTP proxy (http://ip:port) │
│ --verbose -v [quiet|normal|verbose] Logging verbosity [default: normal] │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
> [!IMPORTANT]
> During the security research, tests were carried out on a version of Snipe-IT that, by default, displayed the `User-Agent` field in which the malicious JavaScript is injected. Since commit [10e5d88](https://github.com/grokability/snipe-it/commit/10e5d88fb6d129fbb0afe774a5988d260eaa56c9), the `User-Agent` property is not displayed by default when the action log table is rendered. The admin that will trigger the XSS needs therefore to have ticked the `User-Agent` box in the view options for Snipe-IT versions ulterior to this commit.
### RCE
This subcommand exploits CVE-2025-59713, which allows for remote code execution when credentials for an admin or superadmin user are known. To do so, the following steps are performed:
1. A backup of the Snipe-IT instance is triggered.
2. The generated backup is downloaded, edited in memory and uploaded back to Snipe-IT. The edition of the backup includes additional SQL statements in the `db-dumps/mysql-snipeit.sql` file, which creates a new custom field and edits the last action log with a JSON object containing the Laravel pop chain upon restore.
> [!TIP]
> By default, Snipe-IT includes the `.env` file in the backup. If the script detects it, the `APP_KEY` value is displayed and the `.env` file is saved in the `./output` directory (a custom location for that file can be specified with `--output-dir`).
3. A restore from the edited backup is triggered, which will execute the added SQL statements.
> [!CAUTION]
> Restoring a backup disconnects all the users connected to the instance.
4. Once the restore is completed, the `/api/v1/reports/activity` route is called, which triggers the deserialization and executes the Laravel pop chain.
```bash
$ python3 exploit.py rce --help
Usage: exploit.py rce [OPTIONS]
Execute RCE attack only (requires existing admin account)
╭─ Options ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ * --url -u TEXT Target Snipe-IT URL [required] │
│ * --admin-user -au TEXT Admin username [required] │
│ * --admin-pass -ap TEXT Admin password [required] │
│ --output-dir -od PATH Output dir for .env file [default: /home/ninja/Téléchargements/snipe-it-advisory/exploit/output] │
│ --shell-ip -si TEXT Reverse shell IP address │
│ --shell-port -sp INTEGER Reverse shell port │
│ --command -c TEXT Custom command (overrides reverse shell) │
│ --proxy -x TEXT HTTP proxy (http://ip:port) │
│ --verbose -v [quiet|normal|verbose] Logging verbosity [default: normal] │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
### Fullchain
The `fullchain` subcommand aims at chaining both the XSS and RCE vulnerabilities together. It corresponds to a scenario in which you only have access to a low-privileged user and want to achieve remote code execution. This will only works if the user who visits the `/reports/activity` page is an admin or superadmin. Indeed, only these roles have the rights to create and restore a backup, which is necessary to poison the database and trigger later the Laravel pop chain.
To do so, the script will:
1. Format a JavaScript template with a Lavaravel pop chain that will execute, by default, a bash reverse shell (you can personalize this option with
the `--command` flag, same as for the RCE mode).
2. Log in as the low-privileged user and inject the `User-Agent` field with a `<scr>` tag to force the victim's browser to source the malicious JavaScript template.
3. Boot a rogue HTTP server to distribute the above-mentioned template, as well as its dependencies.
4. When an admin or superadmin visits the `/reports/activity` route, the XSS is triggered and the malicious JavaScript is loaded and executed by the victim's browser. From then on, the same steps as the ones executed in the RCE module are performed, but in JavaScript.
5. When the backup is restored, the victim's browser issues a GET request (callback) to the Python HTTP server to notify that the backup is restored, and that the API route to trigger the RCE can be called.
This mode leverages several additional JavaScript libraries, all credits go to their respective authors:
- **crypto-js.js**: Used to perform cryptographic operations, original code can be found [here](https://gist.github.com/cynecx/b02210c255a3b18566e45a38371dbc70).
- **jszip.js** and **jszip-utils.js**: Used to perform in-memory editing of ZIP files. The official repos can be found respectively [here](https://github.com/Stuk/jszip) and [here](https://github.com/Stuk/jszip-utils).
```bash
$ python3 exploit.py fullchain --help
Usage: exploit.py fullchain [OPTIONS]
Execute full attack chain: XSS -> Backup manipulation -> RCE
╭─ Options ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ * --url -u TEXT Target Snipe-IT URL [required] │
│ * --login -l TEXT Low-privileged user's username [required] │
│ * --password -p TEXT Low-privileged user's password [required] │
│ * --new-name -n TEXT New name for low-privileged user [required] │
│ --ip -i TEXT HTTP server IP address (default: auto-detect) │
│ * --port -P INTEGER HTTP server port [required] │
│ --admin-user -au TEXT Admin username to create [default: admin_rce] │
│ --admin-pass -ap TEXT Admin password to create [default: password123] │
│ --shell-ip -si TEXT Reverse shell IP address │
│ --shell-port -sp INTEGER Reverse shell port │
│ --command -c TEXT Custom command (overrides reverse shell) │
│ --proxy -x TEXT HTTP proxy (http://ip:port) │
│ --verbose -v [quiet|normal|verbose] Logging verbosity [default: normal] │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
## Installation
To run this script, run the following commands:
```bash
$ git clone https://github.com/synacktiv/CVE-2025-59712_CVE-2025-59713
$ cd CVE-2025-59712_CVE-2025-59713
$ python3 -m venv .venv && source .venv/bin/activate
$ python3 -m pip install -r requirements.txt
```
## Dockerfile for testing environment
A Dockerfile is also provided in order to try out the script and reproduce the vulnerability exploitation. It pulls a vulnerable version of Snipe-IT, configures the database with `php artisan`, and sets up two users:
1. User `admin` with a default password of `AdminPassword123!`
2. User `lowpriv` with a default password of `LowPrivUser123!`
Before running the container, the `.env` and `snipe-it.conf` files need to be updated with the URL of the Snipe-IT instance:
```bash
$ sed -i 's|^APP_URL=.*|APP_URL=http://<IP>:<PORT>|' .env
$ sed -i 's|\(ServerName\s*\).*|\1http://<IP>:<PORT>|' snipe-it.conf
```
The container can then be run:
```bash
$ docker build . -t "snipe-it-cve"
$ docker run -p 80:80 --name "snipe-it-debian" snipe-it-cve:latest
```
文件快照
[4.0K] /data/pocs/13777e1b0ce191857b9d1cc23314643363a5d881
├── [4.0K] docker
│ ├── [3.2K] conf_users.sql
│ ├── [ 180] db_staging.sql
│ ├── [1.4K] Dockerfile
│ └── [ 228] snipe-it.conf
├── [ 42K] exploit.py
├── [9.3K] exploit_template.js
├── [ 16K] README.md
├── [ 65] requirements.txt
└── [4.0K] xss
├── [ 62K] crypto-js.min.js
├── [ 95K] jszip.min.js
└── [5.7K] jszip-utils.js
2 directories, 11 files
备注
1. 建议优先通过来源进行访问。
2. 如果因为来源失效或无法访问,请发送邮箱到 f.jinxu#gmail.com 索取本地快照(把 # 换成 @)。
3. 神龙已为您对POC代码进行快照,为了长期维护,请考虑为本地POC付费,感谢您的支持。