From 42bc7496cf337cfc3fe09939b710c5cbf4c6baaf Mon Sep 17 00:00:00 2001 From: HD Moore Date: Wed, 26 Apr 2006 16:59:44 +0000 Subject: [PATCH] All sorts of fun changes to smb/dcerpc, the basics are: 1) Clean up SMB constants, add new ones, define which ones are supported by dialect 2) DCERPC over SMB uses a 'OpenPipe' class, not an 'OpenFile' 3) A new DCERPC option called 'smb_pipeio' allows the user to switch between Read/Write and TransactNamedPipe() git-svn-id: file:///home/svn/incoming/trunk@3622 4d416f70-5f16-0410-b530-b9f4589650da --- lib/rex/proto/dcerpc/client.rb | 24 ++- lib/rex/proto/dcerpc/client.rb.ut.rb | 2 +- lib/rex/proto/smb/client.rb | 9 +- lib/rex/proto/smb/constants.rb | 190 +++++++++++++++--- lib/rex/proto/smb/simpleclient.rb | 48 ++++- .../exploits/windows/smb/ms04_011_lsass.rb | 2 +- 6 files changed, 227 insertions(+), 48 deletions(-) diff --git a/lib/rex/proto/dcerpc/client.rb b/lib/rex/proto/dcerpc/client.rb index 4a8d7e0e4a..999a8ccc67 100644 --- a/lib/rex/proto/dcerpc/client.rb +++ b/lib/rex/proto/dcerpc/client.rb @@ -15,7 +15,7 @@ require 'rex/proto/smb/exceptions' def initialize(handle, socket, useroptions = Hash.new) self.handle = handle self.socket = socket - self.options = { 'smb_user' => '', 'smb_pass' => '' } # put default options here... + self.options = { 'smb_user' => '', 'smb_pass' => '', 'smb_pipeio' => 'rw' } # put default options here... self.options.merge!(useroptions) # we must have a valid handle, regardless of everything else @@ -45,7 +45,7 @@ require 'rex/proto/smb/exceptions' raise "ack, #{self.handle.protocol} requires socket type tcp, not #{self.socket.type?}!" end when 'ncacn_np' - if self.socket.class == Rex::Proto::SMB::SimpleClient::OpenFile + if self.socket.class == Rex::Proto::SMB::SimpleClient::OpenPipe self.ispipe = 1 elsif self.socket.type? == 'tcp' self.smb_connect() @@ -87,17 +87,20 @@ require 'rex/proto/smb/exceptions' def smb_connect() require 'rex/proto/smb/simpleclient' - if self.socket.peerport == 445 - smb = Rex::Proto::SMB::SimpleClient.new(self.socket, true) - elsif self.socket.peerport == 139 + + if self.socket.peerport == 139 smb = Rex::Proto::SMB::SimpleClient.new(self.socket) else - raise "ACK, how did we get a peerport other than 139 or 445? #{self.socket.peerport}" + smb = Rex::Proto::SMB::SimpleClient.new(self.socket, true) end + smb.client.evasion_level = 0 smb.login('*SMBSERVER', self.options['smb_user'], self.options['smb_pass']) smb.connect('IPC$') + f = smb.create_pipe(self.handle.options[0]) + f.mode = self.options['smb_pipeio'] + self.socket = f self.smb = smb end @@ -105,7 +108,7 @@ require 'rex/proto/smb/exceptions' def read() raw_response = '' - if self.socket.class == Rex::Proto::SMB::SimpleClient::OpenFile + if self.socket.class == Rex::Proto::SMB::SimpleClient::OpenPipe begin if self.options['segment_read'] while(true) @@ -144,12 +147,13 @@ require 'rex/proto/smb/exceptions' end def write(data) - if self.options['segment_write'] + + if (! self.options['segment_write'] or (self.handle.protocol == 'ncacn_np' and self.options['smb_pipeio'] != 'rw')) + self.socket.write(data) + else while (data.length > 0) len = self.socket.write( data.slice!(0, (rand(20)+5)) ) end - else - self.socket.write(data) end data.length diff --git a/lib/rex/proto/dcerpc/client.rb.ut.rb b/lib/rex/proto/dcerpc/client.rb.ut.rb index b34159d4aa..610d0ddfd2 100755 --- a/lib/rex/proto/dcerpc/client.rb.ut.rb +++ b/lib/rex/proto/dcerpc/client.rb.ut.rb @@ -259,7 +259,7 @@ class Rex::Proto::DCERPC::Client::UnitTest < Test::Unit::TestCase smb.login('*SMBSERVER', user, pass) smb.connect('IPC$') f = smb.create_pipe('\BROWSER') - assert_instance_of(Rex::Proto::SMB::SimpleClient::OpenFile, f, 'pipe') + assert_instance_of(Rex::Proto::SMB::SimpleClient::OpenPipe, f, 'pipe') handle = Rex::Proto::DCERPC::Handle.new(['4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0'], 'ncacn_np', $_REX_TEST_SMB_HOST, ['\BROWSER']) assert_instance_of(Rex::Proto::DCERPC::Handle, handle, 'handle') diff --git a/lib/rex/proto/smb/client.rb b/lib/rex/proto/smb/client.rb index f3d2ec8e81..b775c19c6b 100644 --- a/lib/rex/proto/smb/client.rb +++ b/lib/rex/proto/smb/client.rb @@ -131,7 +131,7 @@ EVADE = Rex::Proto::SMB::Evasions when CONST::SMB_COM_TREE_DISCONNECT res = smb_parse_tree_disconnect(pkt, data) - when CONST::SMB_COM_CREATE_ANDX + when CONST::SMB_COM_NT_CREATE_ANDX res = smb_parse_create(pkt, data) when CONST::SMB_COM_TRANSACTION, CONST::SMB_COM_TRANSACTION2 @@ -262,7 +262,7 @@ EVADE = Rex::Proto::SMB::Evasions raise XCEPT::InvalidWordCount end - # Process incoming SMB_COM_CREATE_ANDX packets + # Process incoming SMB_COM_NT_CREATE_ANDX packets def smb_parse_create(pkt, data) # Windows says 42, but Samba says 34, same structure :-/ @@ -805,7 +805,7 @@ EVADE = Rex::Proto::SMB::Evasions pkt = CONST::SMB_CREATE_PKT.make_struct self.smb_defaults(pkt['Payload']['SMB']) - pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_CREATE_ANDX + pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NT_CREATE_ANDX pkt['Payload']['SMB'].v['Flags1'] = 0x18 pkt['Payload']['SMB'].v['Flags2'] = 0x2001 pkt['Payload']['SMB'].v['WordCount'] = 24 @@ -822,7 +822,7 @@ EVADE = Rex::Proto::SMB::Evasions self.smb_send(pkt.to_s) - ack = self.smb_recv_parse(CONST::SMB_COM_CREATE_ANDX) + ack = self.smb_recv_parse(CONST::SMB_COM_NT_CREATE_ANDX) # Save off the FileID if (ack['Payload'].v['FileID'] > 0) @@ -1116,7 +1116,6 @@ EVADE = Rex::Proto::SMB::Evasions return ack end - # Perform a transaction2 request using the specified subcommand, parameters, and data def trans2 (subcommand, param = '', body = '', setup_count = 0, setup_data = '') diff --git a/lib/rex/proto/smb/constants.rb b/lib/rex/proto/smb/constants.rb index adbef5d7d2..60cdac1bd8 100644 --- a/lib/rex/proto/smb/constants.rb +++ b/lib/rex/proto/smb/constants.rb @@ -7,26 +7,78 @@ require 'rex/text' require 'rex/struct2' # SMB Commands -SMB_COM_CREATE_DIR = 0x00 -SMB_COM_DELETE_DIR = 0x01 -SMB_COM_CLOSE = 0x04 -SMB_COM_DELETE = 0x06 -SMB_COM_RENAME = 0x07 -SMB_COM_CHECK_DIR = 0x10 -SMB_COM_READ_RAW = 0x1a -SMB_COM_WRITE_RAW = 0x1d -SMB_COM_TRANSACTION = 0x25 -SMB_COM_TRANSACTION2 = 0x32 -SMB_COM_OPEN_ANDX = 0x2d -SMB_COM_READ_ANDX = 0x2e -SMB_COM_WRITE_ANDX = 0x2f -SMB_COM_TREE_DISCONNECT = 0x71 -SMB_COM_NEGOTIATE = 0x72 -SMB_COM_SESSION_SETUP_ANDX = 0x73 -SMB_COM_LOGOFF = 0x74 -SMB_COM_TREE_CONNECT_ANDX = 0x75 -SMB_COM_NT_TRANSACT = 0xa0 -SMB_COM_CREATE_ANDX = 0xa2 +SMB_COM_CREATE_DIRECTORY = 0x00 +SMB_COM_DELETE_DIRECTORY = 0x01 +SMB_COM_OPEN = 0x02 +SMB_COM_CREATE = 0x03 +SMB_COM_CLOSE = 0x04 +SMB_COM_FLUSH = 0x05 +SMB_COM_DELETE = 0x06 +SMB_COM_RENAME = 0x07 +SMB_COM_QUERY_INFORMATION = 0x08 +SMB_COM_SET_INFORMATION = 0x09 +SMB_COM_READ = 0x0a +SMB_COM_WRITE = 0x0b +SMB_COM_LOCK_BYTE_RANGE = 0x0c +SMB_COM_UNLOCK_BYTE_RANGE = 0x0d +SMB_COM_CREATE_TEMPORARY = 0x0e +SMB_COM_CREATE_NEW = 0x0f +SMB_COM_CHECK_DIRECTORY = 0x10 +SMB_COM_PROCESS_EXIT = 0x11 +SMB_COM_SEEK = 0x12 +SMB_COM_LOCK_AND_READ = 0x13 +SMB_COM_WRITE_AND_UNLOCK = 0x14 +SMB_COM_READ_RAW = 0x1a +SMB_COM_READ_MPX = 0x1b +SMB_COM_READ_MPX_SECONDARY = 0x1c +SMB_COM_WRITE_RAW = 0x1d +SMB_COM_WRITE_MPX = 0x1e +SMB_COM_WRITE_MPX_SECONDARY = 0x1f +SMB_COM_WRITE_COMPLETE = 0x20 +SMB_COM_QUERY_SERVER = 0x21 +SMB_COM_SET_INFORMATION2 = 0x22 +SMB_COM_QUERY_INFORMATION2 = 0x23 +SMB_COM_LOCKING_ANDX = 0x24 +SMB_COM_TRANSACTION = 0x25 +SMB_COM_TRANSACTION_SECONDARY = 0x26 +SMB_COM_IOCTL = 0x27 +SMB_COM_IOCTL_SECONDARY = 0x28 +SMB_COM_COPY = 0x29 +SMB_COM_MOVE = 0x2a +SMB_COM_ECHO = 0x2b +SMB_COM_WRITE_AND_CLOSE = 0x2c +SMB_COM_OPEN_ANDX = 0x2d +SMB_COM_READ_ANDX = 0x2e +SMB_COM_WRITE_ANDX = 0x2f +SMB_COM_NEW_FILE_SIZE = 0x30 +SMB_COM_CLOSE_AND_TREE_DISC = 0x31 +SMB_COM_TRANSACTION2 = 0x32 +SMB_COM_TRANSACTION2_SECONDARY = 0x33 +SMB_COM_FIND_CLOSE2 = 0x34 +SMB_COM_FIND_NOTIFY_CLOSE = 0x35 +SMB_COM_TREE_CONNECT = 0x70 +SMB_COM_TREE_DISCONNECT = 0x71 +SMB_COM_NEGOTIATE = 0x72 +SMB_COM_SESSION_SETUP_ANDX = 0x73 +SMB_COM_LOGOFF_ANDX = 0x74 +SMB_COM_TREE_CONNECT_ANDX = 0x75 +SMB_COM_QUERY_INFORMATION_DISK = 0x80 +SMB_COM_SEARCH = 0x81 +SMB_COM_FIND = 0x82 +SMB_COM_FIND_UNIQUE = 0x83 +SMB_COM_FIND_CLOSE = 0x84 +SMB_COM_NT_TRANSACT = 0xa0 +SMB_COM_NT_TRANSACT_SECONDARY = 0xa1 +SMB_COM_NT_CREATE_ANDX = 0xa2 +SMB_COM_NT_CANCEL = 0xa4 +SMB_COM_NT_RENAME = 0xa5 +SMB_COM_OPEN_PRINT_FILE = 0xc0 +SMB_COM_WRITE_PRINT_FILE = 0xc1 +SMB_COM_CLOSE_PRINT_FILE = 0xc2 +SMB_COM_GET_PRINT_QUEUE = 0xc3 +SMB_COM_READ_BULK = 0xd8 +SMB_COM_WRITE_BULK = 0xd9 +SMB_COM_NO_ANDX_COMMAND = 0xff # SMB_COM_NT_TRANSACT Subcommands NT_TRANSACT_CREATE = 1 # File open/create @@ -43,17 +95,19 @@ OPEN_MODE_OPEN = 0x01 # Open the file if the file exists OPEN_MODE_TRUNC = 0x02 # Truncate the file if the file exists # Shared Access -OPEN_SHARE_COMPAT = 0x00 -OPEN_SHARE_DENY_EXCL = 0x10 -OPEN_SHARE_DENY_WRITE = 0x20 -OPEN_SHARE_DENY_READEXEC = 0x30 -OPEN_SHARE_DENY_NONE = 0x40 +OPEN_SHARE_COMPAT = 0x00 +OPEN_SHARE_DENY_EXCL = 0x10 +OPEN_SHARE_DENY_WRITE = 0x20 +OPEN_SHARE_DENY_READEXEC = 0x30 +OPEN_SHARE_DENY_NONE = 0x40 + # File Access -OPEN_ACCESS_READ = 0x00 -OPEN_ACCESS_WRITE = 0x01 -OPEN_ACCESS_READWRITE = 0x02 -OPEN_ACCESS_EXEC = 0x03 +OPEN_ACCESS_READ = 0x00 +OPEN_ACCESS_WRITE = 0x01 +OPEN_ACCESS_READWRITE = 0x02 +OPEN_ACCESS_EXEC = 0x03 + # Create Disposition CREATE_ACCESS_SUPERSEDE = 0x00 # Replace any previously existing file @@ -72,6 +126,84 @@ NETBIOS_REDIR = 'CACACACACACACACACACACACACACACAAA' # SMB Error Codes SMB_ERROR_BUFFER_OVERFLOW = 0x80000005 +# SMB Dialect Compatibility +DIALECT = {} + +DIALECT['PC NETWORK PROGRAM 1.0'] = [ + SMB_COM_CHECK_DIRECTORY, + SMB_COM_CLOSE, + SMB_COM_CLOSE_PRINT_FILE, + SMB_COM_CREATE, + SMB_COM_CREATE_DIRECTORY, + SMB_COM_CREATE_NEW, + SMB_COM_CREATE_TEMPORARY, + SMB_COM_DELETE, + SMB_COM_DELETE_DIRECTORY, + SMB_COM_FLUSH, + SMB_COM_GET_PRINT_QUEUE, + SMB_COM_LOCK_BYTE_RANGE, + SMB_COM_NEGOTIATE, + SMB_COM_OPEN, + SMB_COM_OPEN_PRINT_FILE, + SMB_COM_PROCESS_EXIT, + SMB_COM_QUERY_INFORMATION, + SMB_COM_QUERY_INFORMATION_DISK, + SMB_COM_READ, + SMB_COM_RENAME, + SMB_COM_SEARCH, + SMB_COM_SEEK, + SMB_COM_SET_INFORMATION, + SMB_COM_TREE_CONNECT, + SMB_COM_TREE_DISCONNECT, + SMB_COM_UNLOCK_BYTE_RANGE, + SMB_COM_WRITE, + SMB_COM_WRITE_PRINT_FILE +] + +DIALECT['LANMAN 1.0'] = DIALECT['PC NETWORK PROGRAM 1.0'] + [ + SMB_COM_COPY, + SMB_COM_ECHO, + SMB_COM_FIND, + SMB_COM_FIND_CLOSE, + SMB_COM_FIND_UNIQUE, + SMB_COM_IOCTL, + SMB_COM_IOCTL_SECONDARY, + SMB_COM_LOCK_AND_READ, + SMB_COM_LOCKING_ANDX, + SMB_COM_MOVE, + SMB_COM_OPEN_ANDX, + SMB_COM_QUERY_INFORMATION2, + SMB_COM_READ_ANDX, + SMB_COM_READ_MPX, + SMB_COM_READ_RAW, + SMB_COM_SESSION_SETUP_ANDX, + SMB_COM_SET_INFORMATION2, + SMB_COM_TRANSACTION, + SMB_COM_TRANSACTION_SECONDARY, + SMB_COM_TREE_CONNECT_ANDX, + SMB_COM_WRITE_AND_CLOSE, + SMB_COM_WRITE_AND_UNLOCK, + SMB_COM_WRITE_ANDX, + SMB_COM_WRITE_COMPLETE, + SMB_COM_WRITE_MPX, + SMB_COM_WRITE_MPX_SECONDARY, + SMB_COM_WRITE_RAW +] + +DIALECT['LM1.2X002'] = DIALECT['LANMAN 1.0'] + [ + SMB_COM_FIND_CLOSE2, + SMB_COM_LOGOFF_ANDX, + SMB_COM_TRANSACTION2, + SMB_COM_TRANSACTION2_SECONDARY +] + +DIALECT['NTLM 0.12'] = DIALECT['LM1.2X002'] + [ + SMB_COM_NT_CANCEL, + SMB_COM_NT_CREATE_ANDX, + SMB_COM_NT_RENAME, + SMB_COM_NT_TRANSACT, + SMB_COM_NT_TRANSACT_SECONDARY +] # Create a NetBIOS session packet template def self.make_nbs (template) diff --git a/lib/rex/proto/smb/simpleclient.rb b/lib/rex/proto/smb/simpleclient.rb index 1ae6675c9c..36cfc9f7b0 100644 --- a/lib/rex/proto/smb/simpleclient.rb +++ b/lib/rex/proto/smb/simpleclient.rb @@ -45,7 +45,7 @@ EVADE = Rex::Proto::SMB::Evasions end # Read data from the file - def read (length = nil, offset = 0) + def read(length = nil, offset = 0) if (length == nil) data = '' fptr = offset @@ -105,6 +105,50 @@ EVADE = Rex::Proto::SMB::Evasions end end + class OpenPipe < OpenFile + + # Valid modes are: 'trans' and 'rw' + attr_accessor :mode + + def initalize(*args) + super(*args) + mode = 'rw' + @buff = '' + end + + def read_buffer(length, offset=0) + @buff.slice!(0, length) + end + + def read(length = nil, offset = 0) + case self.mode + when 'trans' + read_buffer(length, offset) + when 'rw' + super(length, offset) + else + raise ArgumentError + end + end + + def write(data, offset = 0) + case self.mode + + when 'trans' + write_trans(data, offset) + when 'rw' + super(data, offset) + else + raise ArgumentError + end + end + + def write_trans(data, offset=0) + ack = self.client.trans_named_pipe(self.file_id, data) + @buff << ack['Payload'].v['Payload'] + end + end + # Public accessors attr_accessor :last_error @@ -168,7 +212,7 @@ attr_accessor :socket, :client, :direct, :shares, :last_share disposition = UTILS.create_mode_to_disposition(perm) ok = self.client.create(path, disposition) file_id = ok['Payload'].v['FileID'] - fh = OpenFile.new(self.client, path, self.client.last_tree_id, file_id) + fh = OpenPipe.new(self.client, path, self.client.last_tree_id, file_id) end def trans_pipe(fid, data) diff --git a/modules/exploits/windows/smb/ms04_011_lsass.rb b/modules/exploits/windows/smb/ms04_011_lsass.rb index 537f7d5eb5..36bc2589a7 100644 --- a/modules/exploits/windows/smb/ms04_011_lsass.rb +++ b/modules/exploits/windows/smb/ms04_011_lsass.rb @@ -125,7 +125,7 @@ class Exploits::Windows::Smb::MS04_011_LSASS < Msf::Exploit::Remote Rex::Text.rand_text(528) + NDR.long(rand(0xFFFFFF)) - print_status('sending exploit ...') + print_status('Calling the vulnerable function...') begin response = dcerpc_call(9, stub) rescue Rex::Proto::DCERPC::Exceptions::NoResponse