Skip to content

Commit 6d6d5a7

Browse files
committed
Land @0x41414141's bugfixing
2 parents d6dc8be + b1e6de2 commit 6d6d5a7

File tree

6 files changed

+157
-67
lines changed

6 files changed

+157
-67
lines changed

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ def smb_cmd_create(c, buff)
1414
pkt = CONST::SMB_CREATE_PKT.make_struct
1515
pkt.from_s(buff)
1616

17-
payload = (pkt['Payload'].v['Payload'])
17+
payload = (pkt['Payload'].v['Payload']).downcase
1818
payload.gsub!(/^[\x00]*/, '') # delete padding
19-
payload = Rex::Text.to_ascii(payload)
20-
payload.gsub!(/[\x00]*$/, '') # delete padding
19+
payload = Rex::Text.ascii_safe_hex(payload)
20+
payload.gsub!(/\\x([0-9a-f]{2})/i, '') # delete hex chars
2121

2222
if payload.nil? || payload.empty?
2323
payload = file_name
@@ -28,7 +28,7 @@ def smb_cmd_create(c, buff)
2828
attribs = 0x80 # File Attributes
2929
eof = exe_contents.length
3030
is_dir = 0
31-
elsif payload == path_name
31+
elsif payload.eql?(path_name)
3232
fid = smb[:dir_id].to_i
3333
attribs = 0x10 # Ordinary Dir
3434
eof = 0
@@ -52,9 +52,9 @@ def smb_cmd_create(c, buff)
5252
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
5353
pkt['Payload']['SMB'].v['WordCount'] = 42
5454
pkt['Payload'].v['AndX'] = 0xff # no further commands
55-
pkt['Payload'].v['OpLock'] = 0x3 # Grant Oplock on File
55+
pkt['Payload'].v['OpLock'] = CONST::LEVEL_II_OPLOCK # Grant Oplock on File
5656
pkt['Payload'].v['FileID'] = fid
57-
pkt['Payload'].v['Action'] = 0x1 # The file existed and was opened
57+
pkt['Payload'].v['Action'] = CONST::FILE_OPEN # The file existed and was opened
5858
pkt['Payload'].v['CreateTimeLow'] = lo
5959
pkt['Payload'].v['CreateTimeHigh'] = hi
6060
pkt['Payload'].v['AccessTimeLow'] = lo

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

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,32 @@ module Command
77
module Trans2
88
# This mixin provides methods to handle TRAN2_FIND_FIRST2 subcommands
99
module FindFirst2
10+
1011
def smb_cmd_trans2_find_first2(c, buff)
12+
1113
params = CONST::SMB_TRANS2_FIND_FIRST2_PARAMETERS.make_struct
1214
params.from_s(buff)
1315

1416
loi = params.v['InformationLevel']
15-
file_name = Rex::Text.to_ascii(params.v['FileName'])
16-
file_name.gsub!(/[\x00]*$/, '') #delete padding
17+
search_path = Rex::Text.to_ascii(params.v['FileName']).downcase
18+
search_path.gsub!(/[\x00]*/, '') #delete padding
19+
search_path.gsub!(/\\x([0-9a-f]{2})/i, '') # delete hex chars
20+
21+
# Do some dummy managing for wildcards
22+
# TODO: improve
23+
search_path.gsub!(/<\./, '*.') # manage wildcards
24+
extension = File.extname(file_name)
25+
if search_path == "#{path_name}*#{extension}"
26+
search_path = "#{path_name}#{file_name}"
27+
end
1728

1829
case loi
1930
when CONST::SMB_FIND_FILE_NAMES_INFO
20-
smb_cmd_find_file_names_info(c, file_name)
31+
smb_cmd_find_file_names_info(c, search_path)
2132
when CONST::SMB_FIND_FILE_BOTH_DIRECTORY_INFO
22-
smb_cmd_find_file_both_directory_info(c, file_name)
33+
smb_cmd_find_file_both_directory_info(c, search_path)
2334
when CONST::SMB_FIND_FILE_FULL_DIRECTORY_INFO
24-
smb_cmd_find_file_full_directory_info(c, file_name)
35+
smb_cmd_find_file_full_directory_info(c, search_path)
2536
else
2637
dprint("\t\tUnknown LOI [smb_cmd_trans2_find_first2] - #{loi}")
2738
# SEND success with the hope of going ahead...

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,10 @@ def smb_cmd_trans2_query_file_information(c, buff)
1717
fid = params.v['FID']
1818

1919
case loi
20-
when CONST::SMB_QUERY_FILE_STANDARD_INFO, CONST::SMB_QUERY_FILE_STANDARD_INFO_ALIAS
20+
when CONST::SMB_QUERY_FILE_STANDARD_INFO, CONST::SMB_QUERY_FILE_STANDARD_INFO_ALIAS, CONST::SMB_QUERY_FILE_INTERNAL_INFO_ALIAS
2121
smb_cmd_trans_query_file_info_standard(c, fid)
2222
when CONST::SMB_QUERY_FILE_BASIC_INFO, CONST::SMB_QUERY_FILE_BASIC_INFO_ALIAS, CONST::SMB_SET_FILE_BASIC_INFO_ALIAS
2323
smb_cmd_trans_query_file_info_basic(c, fid)
24-
#when CONST::SMB_QUERY_FILE_NETWORK_OPEN_INFO
25-
#smb_cmd_trans_query_file_info_network(c, fid)
2624
else
2725
dprint("\t\tUnknown LOI [smb_cmd_trans2_query_file_information] - #{loi.to_s}")
2826
# SEND success with the hope of going ahead...

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,22 @@ module Trans2
99
module QueryPathInformation
1010

1111
def smb_cmd_trans2_query_path_information(c, buff)
12+
1213
params = CONST::SMB_TRANS2_QUERY_PATH_PARAMETERS.make_struct
1314
params.from_s(buff)
1415

1516
loi = params.v['InformationLevel']
16-
file_name = params.v['FileName']
17-
file_name.gsub!(/[\x00]*$/, '') #delete padding
17+
file_name = Rex::Text.to_ascii(params.v['FileName']).downcase
18+
file_name.gsub!(/[\x00]*/, '') #delete padding
19+
file_name.gsub!(/\\x([0-9a-f]{2})/i, '') # delete hex chars
1820

1921
case loi
22+
when CONST::SMB_QUERY_FILE_STANDARD_INFO, CONST::SMB_QUERY_FILE_STANDARD_INFO_ALIAS, CONST::SMB_QUERY_FILE_INTERNAL_INFO_ALIAS
23+
smb_cmd_trans_query_path_info_standard(c, file_name)
2024
when CONST::SMB_QUERY_FILE_BASIC_INFO, CONST::SMB_QUERY_FILE_BASIC_INFO_ALIAS, CONST::SMB_SET_FILE_BASIC_INFO_ALIAS
2125
smb_cmd_trans_query_path_info_basic(c, file_name)
22-
when CONST::SMB_QUERY_FILE_STANDARD_INFO, CONST::SMB_QUERY_FILE_STANDARD_INFO_ALIAS
23-
smb_cmd_trans_query_path_info_standard(c, file_name)
24-
#when CONST::SMB_QUERY_FILE_NETWORK_OPEN_INFO
25-
#smb_cmd_trans_query_file_info_network(c, buff)
26+
when CONST::SMB_QUERY_FILE_NETWORK_OPEN_INFO
27+
smb_cmd_trans_query_path_info_network(c, file_name)
2628
else
2729
dprint("\t\tUnknown LOI [smb_cmd_trans2_query_path_information] - #{loi.to_s}")
2830
# SEND success with the hope of going ahead...

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

Lines changed: 93 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,59 @@ module InformationLevel
77
# This mixin provides methods to handle TRAN2_QUERY_PATH_INFORMATION subcommands
88
module Query
99

10-
# shortcut.. always send OBJECT_NAME_NOT_FOUND
11-
def smb_cmd_trans_query_file_info_basic(c, buff)
10+
#
11+
# Responds to QUERY_PATH_INFO (Basic) requests
12+
#
13+
def smb_cmd_trans_query_file_info_basic(c, fid)
14+
smb = @state[c]
1215
pkt = CONST::SMB_TRANS_RES_PKT.make_struct
1316
smb_set_defaults(c, pkt)
17+
18+
if fid.eql?smb[:file_id].to_i
19+
attrib = CONST::SMB_EXT_FILE_ATTR_NORMAL # File attributes => file
20+
elsif fid.nil? || fid.empty? || fid == "\x00" # empty path
21+
# QUERY_PATH_INFO_PARAMETERS doesn't include a file name, return a Directory answer
22+
attrib = CONST::SMB_EXT_FILE_ATTR_DIRECTORY # File attributes => directory
23+
else
24+
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TRANSACTION2
25+
pkt['Payload']['SMB'].v['ErrorClass'] = CONST::SMB_STATUS_OBJECT_NAME_NOT_FOUND # OBJECT_NAME_NOT_FOUND
26+
pkt['Payload']['SMB'].v['Flags1'] = FLAGS
27+
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
28+
c.put(pkt.to_s)
29+
return
30+
end
31+
32+
trans2_params = CONST::SMB_TRANS2_QUERY_PATH_INFORMATION_RES_PARAMETERS.make_struct
33+
trans2_params.v['EaErrorOffset'] = 0
34+
35+
query_path_info = CONST::SMB_QUERY_FILE_BASIC_INFO_HDR.make_struct
36+
query_path_info.v['loCreationTime'] = lo
37+
query_path_info.v['hiCreationTime'] = hi
38+
query_path_info.v['loLastAccessTime'] = lo
39+
query_path_info.v['hiLastAccessTime'] = hi
40+
query_path_info.v['loLastWriteTime'] = lo
41+
query_path_info.v['hiLastWriteTime'] = hi
42+
query_path_info.v['loLastChangeTime'] = lo
43+
query_path_info.v['hiLastChangeTime'] = hi
44+
query_path_info.v['ExtFileAttributes'] = attrib
45+
1446
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TRANSACTION2
15-
pkt['Payload']['SMB'].v['ErrorClass'] = CONST::SMB_STATUS_OBJECT_NAME_NOT_FOUND
1647
pkt['Payload']['SMB'].v['Flags1'] = FLAGS
1748
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
49+
pkt['Payload']['SMB'].v['WordCount'] = 10
50+
pkt['Payload'].v['ParamCountTotal'] = trans2_params.to_s.length
51+
pkt['Payload'].v['DataCountTotal'] = query_path_info.to_s.length
52+
pkt['Payload'].v['ParamCount'] = trans2_params.to_s.length
53+
pkt['Payload'].v['ParamOffset'] = CONST::SMB_TRANS_RES_PKT_LENGTH
54+
pkt['Payload'].v['DataCount'] = query_path_info.to_s.length
55+
pkt['Payload'].v['DataOffset'] = CONST::SMB_TRANS_RES_PKT_LENGTH + trans2_params.to_s.length + UNICODE_NULL_LENGTH
56+
pkt['Payload'].v['Payload'] =
57+
"\x00" + # Padding
58+
trans2_params.to_s +
59+
"\x00\x00" + # Padding
60+
query_path_info.to_s
61+
1862
c.put(pkt.to_s)
19-
return
2063
end
2164

2265
# shortcut, we only have one file....
@@ -113,7 +156,6 @@ def smb_cmd_trans_query_path_info_basic(c, path)
113156
c.put(pkt.to_s)
114157
end
115158

116-
117159
#
118160
# Responds to QUERY_PATH_INFO (Standard) requests
119161
#
@@ -123,10 +165,8 @@ def smb_cmd_trans_query_path_info_standard(c, path)
123165
pkt = CONST::SMB_TRANS_RES_PKT.make_struct
124166
smb_set_defaults(c, pkt)
125167

126-
if path && path.ends_with?(file_name) #TODO: do it better
168+
if path && path.include?(file_name) #TODO: do it better
127169
attrib = 0 # File attributes => file
128-
elsif path && path.ends_with?(file_name + '.Local')
129-
attrib = 1 # File attributes => file
130170
elsif path && path == path_name
131171
# QUERY_PATH_INFO_PARAMETERS doesn't include a file name, return a Directory answer
132172
attrib = 1 # File attributes => directory
@@ -174,61 +214,68 @@ def smb_cmd_trans_query_path_info_standard(c, path)
174214
c.put(pkt.to_s)
175215
end
176216

177-
=begin
178217
#
179-
# Responds to QUERY_FILE_INFO (Network) requests
180-
# Is it needed?
181-
def smb_cmd_trans_query_file_info_network(c, buff)
182-
pkt = CONST::SMB_TRANS2_PKT.make_struct
183-
pkt.from_s(buff)
184-
185-
payload = pkt['Payload'].v['SetupData'].gsub(/\x00/, '').gsub(/.*\\/, '').chomp.strip
218+
# Responds to QUERY_PATH_INFO (Network Open) requests
219+
#
220+
# At the moment we just support '\\' path always send a SUCCESS...
221+
def smb_cmd_trans_query_path_info_network(c, path)
186222

187-
dprint("[smb_cmd_trans_query_file_info_network] Payload length: #{payload.length.to_s}")
188-
dprint("[smb_cmd_trans_query_file_info_network] Payload is : #{payload.to_s}")
223+
pkt = CONST::SMB_TRANS_RES_PKT.make_struct
224+
smb_set_defaults(c, pkt)
189225

190-
if payload.length.to_s.eql?('4')
191-
attrib = "\x10\x00\x00\x00" # File attributes => directory
226+
if path && path.include?(file_name) #TODO: do it better
227+
attrib = 0 # File attributes => file
228+
elsif path && path == path_name
229+
# QUERY_PATH_INFO_PARAMETERS doesn't include a file name, return a Directory answer
230+
attrib = CONST::SMB_EXT_FILE_ATTR_DIRECTORY # File attributes => directory
231+
elsif path.nil? || path.empty? || path == "\x00" # empty path
232+
# QUERY_PATH_INFO_PARAMETERS doesn't include a file name, return a Directory answer
233+
attrib = CONST::SMB_EXT_FILE_ATTR_DIRECTORY # File attributes => directory
192234
else
193-
attrib = "\x80\x00\x00\x00" # File attributes => normal file
235+
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TRANSACTION2
236+
pkt['Payload']['SMB'].v['ErrorClass'] = CONST::SMB_STATUS_OBJECT_NAME_NOT_FOUND # OBJECT_NAME_NOT_FOUND
237+
pkt['Payload']['SMB'].v['Flags1'] = 0x88
238+
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
239+
c.put(pkt.to_s)
240+
return
194241
end
195242

243+
trans2_params = CONST::SMB_TRANS2_QUERY_PATH_INFORMATION_RES_PARAMETERS.make_struct
244+
trans2_params.v['EaErrorOffset'] = 0
245+
246+
query_path_info = CONST::SMB_QUERY_FILE_NETWORK_INFO_HDR.make_struct
247+
query_path_info.v['loCreationTime'] = lo
248+
query_path_info.v['hiCreationTime'] = hi
249+
query_path_info.v['loLastAccessTime'] = lo
250+
query_path_info.v['hiLastAccessTime'] = hi
251+
query_path_info.v['loLastWriteTime'] = lo
252+
query_path_info.v['hiLastWriteTime'] = hi
253+
query_path_info.v['loLastChangeTime'] = lo
254+
query_path_info.v['hiLastChangeTime'] = hi
255+
query_path_info.v['AllocationSize'] = 1048576
256+
query_path_info.v['EndOfFile'] = exe_contents.length
257+
query_path_info.v['ExtFileAttributes'] = attrib
258+
196259
pkt = CONST::SMB_TRANS_RES_PKT.make_struct
197260
smb_set_defaults(c, pkt)
198261

199262
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TRANSACTION2
200-
pkt['Payload']['SMB'].v['Flags1'] = 0x88
263+
pkt['Payload']['SMB'].v['Flags1'] = FLAGS
201264
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
202265
pkt['Payload']['SMB'].v['WordCount'] = 10
203-
pkt['Payload'].v['ParamCountTotal'] = 2
204-
pkt['Payload'].v['DataCountTotal'] = 56
205-
pkt['Payload'].v['ParamCount'] = 2
206-
pkt['Payload'].v['ParamOffset'] = 56
207-
pkt['Payload'].v['DataCount'] = 56
208-
pkt['Payload'].v['DataOffset'] = 60
266+
pkt['Payload'].v['ParamCountTotal'] = trans2_params.to_s.length
267+
pkt['Payload'].v['DataCountTotal'] = query_path_info.to_s.length + UNICODE_NULL_LENGTH
268+
pkt['Payload'].v['ParamCount'] = trans2_params.to_s.length
269+
pkt['Payload'].v['ParamOffset'] = CONST::SMB_TRANS_RES_PKT_LENGTH
270+
pkt['Payload'].v['DataCount'] = query_path_info.to_s.length + UNICODE_NULL_LENGTH
271+
pkt['Payload'].v['DataOffset'] = CONST::SMB_TRANS_RES_PKT_LENGTH + trans2_params.to_s.length + UNICODE_NULL_LENGTH
209272
pkt['Payload'].v['Payload'] =
210273
"\x00" + # Padding
211-
# QUERY_PATH_INFO Parameters
212-
"\x00\x00" + # EA Error Offset
274+
trans2_params.to_s +
213275
"\x00\x00" + # Padding
214-
# QUERY_PATH_INFO Data
215-
[lo, hi].pack("VV") + # Created
216-
[lo, hi].pack("VV") + # Last Access
217-
[lo, hi].pack("VV") + # Last Write
218-
[lo, hi].pack("VV") + # Change
219-
"\x00\x00\x10\x00\x00\x00\x00\x00" + # Allocation Size = 1048576 || 1Mb
220-
[exe_contents.length].pack("V") + "\x00\x00\x00\x00" + # End Of File
221-
attrib +
222-
"\x00\x00\x00\x00" # Unknown
223-
224-
my_pkt = pkt.to_s
225-
original_length = my_pkt[2, 2].unpack("n").first
226-
original_length = original_length + 24
227-
my_pkt[2, 2] = [original_length].pack("n")
228-
new_length = my_pkt[2, 2].unpack("n").first
276+
query_path_info.to_s
229277
c.put(pkt.to_s)
230278
end
231-
=end
232279
end
233280
end
234281
end

lib/rex/proto/smb/constants.rb

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,19 @@ class Constants
184184
OPEN_SHARE_DENY_READEXEC = 0x30
185185
OPEN_SHARE_DENY_NONE = 0x40
186186

187+
# OpLock Levels
188+
NO_OPLOCK = 0x00
189+
EXCLUSIVE_OPLOCK = 0x01
190+
BATCH_OPLOCK = 0x02
191+
LEVEL_II_OPLOCK = 0x03
192+
193+
# Dispositions, action to take if the file already exists or if the file is a new file and does not already exist
194+
FILE_SUPERSEDE = 0x00000000
195+
FILE_OPEN = 0x00000001
196+
FILE_CREATE = 0x00000002
197+
FILE_OPEN_IF = 0x00000003
198+
FILE_OVERWRITE = 0x00000004
199+
FILE_OVERWRITE_IF = 0x00000005
187200

188201
# File Access
189202
OPEN_ACCESS_READ = 0x00
@@ -282,9 +295,10 @@ class Constants
282295
SMB_QUERY_FILE_BASIC_INFO_ALIAS = 0x3EC # alias for 0x101
283296
SMB_SET_FILE_BASIC_INFO_ALIAS = 0x3EC # alias for 0x101
284297
SMB_QUERY_FILE_STANDARD_INFO_ALIAS = 0x3ED # alias for 0x102
298+
SMB_QUERY_FILE_INTERNAL_INFO_ALIAS = 0x3EE # alias for 0x103
285299
SMB_QUERY_FILE_EA_INFO_ALIAS = 0x3EF # alias for 0x103
286300
SMB_QUERY_FILE_NAME_INFO_ALIAS = 0x3F1 # alias for 0x104
287-
SMB_QUERY_FILE_NETWORK_OPEN_INFO = 0x040a
301+
SMB_QUERY_FILE_NETWORK_OPEN_INFO = 0x40A
288302
SMB_INFO_PASSTHROUGH = 0x1000
289303

290304
# SMB_COM_TRANSACTION2 MAX DATA COUNT information levels
@@ -1282,6 +1296,24 @@ def self.make_nbs (template)
12821296
['uint16v', 'EaErrorOffset', 0]
12831297
)
12841298

1299+
# A template for SMB_QUERY_FILE_NETWORK_INFO query path information level
1300+
SMB_QUERY_FILE_NETWORK_INFO_HDR = Rex::Struct2::CStructTemplate.new(
1301+
['uint32v', 'loCreationTime', 0],
1302+
['uint32v', 'hiCreationTime', 0],
1303+
['uint32v', 'loLastAccessTime', 0],
1304+
['uint32v', 'hiLastAccessTime', 0],
1305+
['uint32v', 'loLastWriteTime', 0],
1306+
['uint32v', 'hiLastWriteTime', 0],
1307+
['uint32v', 'loLastChangeTime', 0],
1308+
['uint32v', 'hiLastChangeTime', 0],
1309+
['uint64v', 'AllocationSize', 0],
1310+
['uint64v', 'EndOfFile', 0],
1311+
['uint32v', 'ExtFileAttributes', 0],
1312+
['uint32v', 'Reserved', 0]
1313+
)
1314+
1315+
SMB_QUERY_FILE_NETWORK_INFO_HDR_LENGTH = 56
1316+
12851317
# A template for SMB_QUERY_FILE_BASIC_INFO query path information level
12861318
SMB_QUERY_FILE_BASIC_INFO_HDR = Rex::Struct2::CStructTemplate.new(
12871319
['uint32v', 'loCreationTime', 0],

0 commit comments

Comments
 (0)