Hey! and welcome to another THEY BURNED MY BUG episode. This time, we introduce CVE-2025-25257. An SQLi that I spotted back in Feb.
in case someone burn them before i get my bragging rights
— faulty *ptrrr (@0x_shaq) February 9, 2025
8157d42995395ba0c0cfccce37b934ebb63d3d5740ba43eda7fa853f389bca2a
8fc4ca6426ae50c7673326eacb6644a8b361ad1051138d04cbd9da8b807a0973
This is a pre-auth SQLi bug that can be leveraged to an RCE in FortiWeb.
Description
in httpd.conf
, there’s a native Apache handler:
<Location "/api/fabric/device/status">
SetHandler fabric_device_status-handler
</Location>
Looking at its code reveals that it is responsible for parsing user-supplied headers such as Authorization
.
The Authorization
header goes into the char token[]
variable, as is, without validation or sanitation.
In get_fabric_user_by_token()
, the token is concatenated to a SQL query:
ah, classic.
PoC
GET /api/fabric/device/status HTTP/1.1
Host: 192.168.10.144
Authorization: Bearer 123' or 'x'='x
Getting RCE
So, how can we escalate from SQLi to a pre-auth RCE?
To do this, we will use MySQL’s INTO OUTFILE
statement, which allows you to write files to the filesystem(SELECT 'hello' INTO OUTFILE '/tmp/foo.txt'
).
NOTE
Note: The
INTO OUTFILE
is available to high-privileged MySQL user, such asroot
, but, guess what? they are running the mysql queries asroot
haha)
How can we execute code? well, there’s a file called ml-draw.py
, it’s a cgi script contains the following imports and accessible without auth:
import os
import sys
import cgi
import cgitb; cgitb.enable()
import time
from datetime import datetime
import matplotlib
import pylab
import numpy as np
from numpy import array
I found that it is possible to override the 3rd party module by making a file in the core modules directory:
/var/log/lib/python3.10/matplotlib.py
Then, we send an HTTP request to the ml-draw.py
file it import the library triggers our code :D
There were a few obstacles to exploiting this such as length of payload, encoding issues, and more. I’d elaborate about it but it turns out WatchTowr wrote an analysis SO FAST and it literally includes every step of the same methods I dealt with the constraints lmao. So make sure to read their writeup :^) SynSynology is a legend.
Full Exploit
- The full exploit can be found here: https://github.com/0xbigshaq/CVE-2025-25257
- The signed version I tweeted about(
8fc4ca6426ae50c7673326eacb6644a8b361ad1051138d04cbd9da8b807a0973
) can also be found in the repo undersigned.py
(At this point of the research I only leveraged it to file read/write primitive, and after a day or two I found the RCE gadget.)
ptr@nix:~/repos/CVE-2025-25257 (main) $ sha256sum signed.py
8fc4ca6426ae50c7673326eacb6644a8b361ad1051138d04cbd9da8b807a0973 signed.py
I hope you enjoyed reading this! :D stay tuned because in the next few weeks I’m dropping another bug(it took them a long time to fix it so apologies for postponing it every time. It’s worth it tho).