2005-10-03 13:51:05 +00:00
require 'rex/proto/smb'
require 'rex/proto/dcerpc'
2006-06-13 21:27:01 +00:00
require 'rex/encoder/ndr'
2011-03-07 19:57:53 +00:00
require 'rex/proto/ntlm/constants'
require 'rex/proto/ntlm/crypt'
require 'rex/proto/ntlm/base'
require 'rex/proto/ntlm/message'
2005-10-03 13:51:05 +00:00
module Msf
###
#
# This mixin provides utility methods for interacting with a SMB/CIFS service on
# a remote machine. These methods may generally be useful in the context of
# exploitation. This mixin extends the Tcp exploit mixin. Only one SMB
# service can be accessed at a time using this class.
#
###
module Exploit::Remote::SMB
include Exploit :: Remote :: Tcp
SIMPLE = Rex :: Proto :: SMB :: SimpleClient
XCEPT = Rex :: Proto :: SMB :: Exceptions
2006-09-14 05:51:24 +00:00
CONST = Rex :: Proto :: SMB :: Constants
2009-11-03 18:09:05 +00:00
2011-01-30 19:26:35 +00:00
2005-11-15 23:02:17 +00:00
# Alias over the Rex DCERPC protocol modules
DCERPCPacket = Rex :: Proto :: DCERPC :: Packet
DCERPCClient = Rex :: Proto :: DCERPC :: Client
DCERPCResponse = Rex :: Proto :: DCERPC :: Response
DCERPCUUID = Rex :: Proto :: DCERPC :: UUID
2006-06-13 21:27:01 +00:00
NDR = Rex :: Encoder :: NDR
2005-12-13 06:08:40 +00:00
2010-08-12 15:00:58 +00:00
# Mini-mixin for making SMBUser/SMBPass/SMBDomain regular options vs advanced
# Included when the module needs credentials to function
module Authenticated
def initialize ( info = { } )
super
register_options (
[
OptString . new ( 'SMBUser' , [ false , 'The username to authenticate as' , '' ] ) ,
OptString . new ( 'SMBPass' , [ false , 'The password for the specified username' , '' ] ) ,
OptString . new ( 'SMBDomain' , [ false , 'The Windows domain to use for authentication' , 'WORKGROUP' ] ) ,
] , Msf :: Exploit :: Remote :: SMB :: Authenticated )
end
end
2005-10-03 13:51:05 +00:00
def initialize ( info = { } )
super
2009-11-03 18:09:05 +00:00
2006-04-30 19:49:27 +00:00
register_evasion_options (
2005-11-15 23:02:17 +00:00
[
2010-08-12 15:00:58 +00:00
OptBool . new ( 'SMB::pipe_evasion' , [ true , 'Enable segmented read/writes for SMB Pipes' , false ] ) ,
2006-04-30 19:49:27 +00:00
OptInt . new ( 'SMB::pipe_write_min_size' , [ true , 'Minimum buffer size for pipe writes' , 1 ] ) ,
OptInt . new ( 'SMB::pipe_write_max_size' , [ true , 'Maximum buffer size for pipe writes' , 1024 ] ) ,
OptInt . new ( 'SMB::pipe_read_min_size' , [ true , 'Minimum buffer size for pipe reads' , 1 ] ) ,
OptInt . new ( 'SMB::pipe_read_max_size' , [ true , 'Maximum buffer size for pipe reads' , 1024 ] ) ,
OptInt . new ( 'SMB::pad_data_level' , [ true , 'Place extra padding between headers and data (level 0-3)' , 0 ] ) ,
OptInt . new ( 'SMB::pad_file_level' , [ true , 'Obscure path names used in open/create (level 0-3)' , 0 ] ) ,
OptInt . new ( 'SMB::obscure_trans_pipe_level' , [ true , 'Obscure PIPE string in TransNamedPipe (level 0-3)' , 0 ] ) ,
2009-11-03 18:09:05 +00:00
2005-11-15 23:02:17 +00:00
] , Msf :: Exploit :: Remote :: SMB )
2007-02-18 07:02:47 +00:00
register_advanced_options (
[
2010-08-12 15:00:58 +00:00
OptBool . new ( 'SMBDirect' , [ true , 'The target port is a raw SMB service (not NetBIOS)' , true ] ) ,
2007-02-18 07:02:47 +00:00
OptString . new ( 'SMBUser' , [ false , 'The username to authenticate as' , '' ] ) ,
OptString . new ( 'SMBPass' , [ false , 'The password for the specified username' , '' ] ) ,
2010-11-08 20:07:17 +00:00
OptString . new ( 'SMBDomain' , [ false , 'The Windows domain to use for authentication' , '.' ] ) ,
2011-03-07 19:57:53 +00:00
OptString . new ( 'SMBName' , [ true , 'The NetBIOS hostname (required for port 139 connections)' , '*SMBSERVER' ] ) ,
2011-03-08 23:29:34 +00:00
OptBool . new ( 'SMB::VerifySignature' , [ true , " Enforces client-side verification of server response signatures " , false ] ) ,
OptInt . new ( 'SMB::ChunkSize' , [ true , 'The chunk size for SMB segments, bigger values will increase speed but break NT 4.0 and SMB signing' , 500 ] ) ,
#
# Control the identified operating system of the client
#
OptString . new ( 'SMB::Native_OS' , [ true , 'The Native OS to send during authentication' , 'Windows 2000 2195' ] ) ,
2011-03-09 00:42:12 +00:00
OptString . new ( 'SMB::Native_LM' , [ true , 'The Native LM to send during authentication' , 'Windows 2000 5.0' ] ) ,
2011-03-08 23:46:44 +00:00
#
2011-03-08 23:29:34 +00:00
# UseNTLMv2 forces NTLMv2 instead of NTLM2_session behavior when the 'Negotiate NTLM2' flag is set
#
OptBool . new ( 'NTLM::UseNTLMv2' , [ true , " Use NTLMv2 instead of NTLM2_session when \' Negotiate NTLM2 \' key is true " , false ] ) ,
#
# UseNTLM2_session forces the use of NTLMV2 session keys instead of NTLMv1, emulating the default of Windows 2000+
#
OptBool . new ( 'NTLM::UseNTLM2_session' , [ true , 'Activate the \'Negotiate NTLM2 key\' flag, forcing the use of a NTLMv2_session' , true ] ) ,
#
# SendLM has no effect when NTLM_UseNTLM2_session = true, NTLM_UseNTLMv2 = false or NTLM_SendNTLM = false
#
OptBool . new ( 'NTLM::SendLM' , [ true , " Always send the LANMAN response (except when NTLMv2_session is specified) " , true ] ) ,
#
# UseLMKey is valid when NTLM_SendLM = true, NTLM_SendNTLM = true, or NTLM_UseNTLM2_session = false
#
OptBool . new ( 'NTLM::UseLMKey' , [ true , " Activate the \' Negotiate Lan Manager Key \' flag, using the LM key when the LM response is sent " , false ] ) ,
#
# SendNTLM allows the NTLM response to be excluded, emulating Win9x behavior (don't change unless you are testing)
#
OptBool . new ( 'NTLM::SendNTLM' , [ true , 'Activate the \'Negotiate NTLM key\' flag, indicating the use of NTLM responses' , true ] ) ,
2011-03-16 00:12:07 +00:00
#
# SendSPN will send an avp of type 9/SPN in the ntlmv2 client blob, this is mandatory on windows seven / 2008 r2 if
# Microsoft network server : Server SPN target name validation level is set to <Required from client> or we get an STATUS_ACCESS_DENIED
#
2011-03-16 20:01:28 +00:00
OptBool . new ( 'NTLM::SendSPN' , [ true , 'Send an avp of type SPN in the ntlmv2 client Blob, this allow authentification on windows Seven/2008r2 when SPN is required' , true ] ) ,
2011-03-07 19:57:53 +00:00
2007-02-18 07:02:47 +00:00
] , Msf :: Exploit :: Remote :: SMB )
2005-10-03 13:51:05 +00:00
register_options (
2009-03-17 19:11:26 +00:00
[
Opt :: RHOST ,
2009-11-03 18:09:05 +00:00
OptInt . new ( 'RPORT' , [ true , 'Set the SMB service port' , 445 ] )
2009-03-17 19:11:26 +00:00
] , Msf :: Exploit :: Remote :: SMB )
2009-11-03 18:09:05 +00:00
2009-10-28 18:04:50 +00:00
register_autofilter_ports ( [ 139 , 445 ] )
2009-11-03 18:09:05 +00:00
register_autofilter_services ( %W{ netbios-ssn microsoft-ds } )
2005-10-03 13:51:05 +00:00
end
2009-11-03 18:09:05 +00:00
2009-09-22 21:26:20 +00:00
def connect ( global = true )
2009-11-03 18:09:05 +00:00
2009-09-22 21:26:20 +00:00
disconnect ( ) if global
2009-11-03 18:09:05 +00:00
2009-09-22 21:26:20 +00:00
s = super ( global )
self . sock = s if global
2009-11-03 18:09:05 +00:00
# Disable direct SMB when SMBDirect has not been set
# and the destination port is configured as 139
2009-03-28 05:49:33 +00:00
direct = smb_direct
2009-11-03 18:09:05 +00:00
if ( datastore . default? ( 'SMBDirect' ) and rport . to_i == 139 )
2009-12-21 19:04:28 +00:00
direct = false
2009-11-03 18:09:05 +00:00
end
2009-09-22 21:26:20 +00:00
c = SIMPLE . new ( s , direct )
2009-11-03 18:09:05 +00:00
2006-01-27 05:33:08 +00:00
# setup pipe evasion foo
2006-04-30 19:49:27 +00:00
if datastore [ 'SMB::pipe_evasion' ]
2006-01-27 05:33:08 +00:00
# XXX - insert code to change the instance of the read/write functions to do segmentation
end
2009-11-03 18:09:05 +00:00
2006-04-30 19:49:27 +00:00
if ( datastore [ 'SMB::pad_data_level' ] )
2009-09-22 21:26:20 +00:00
c . client . evasion_opts [ 'pad_data' ] = datastore [ 'SMB::pad_data_level' ]
2006-04-30 19:49:27 +00:00
end
if ( datastore [ 'SMB::pad_file_level' ] )
2009-09-22 21:26:20 +00:00
c . client . evasion_opts [ 'pad_file' ] = datastore [ 'SMB::pad_file_level' ]
2006-04-30 19:49:27 +00:00
end
if ( datastore [ 'SMB::obscure_trans_pipe_level' ] )
2009-09-22 21:26:20 +00:00
c . client . evasion_opts [ 'obscure_trans_pipe' ] = datastore [ 'SMB::obscure_trans_pipe_level' ]
2005-12-13 06:08:40 +00:00
end
2009-11-03 18:09:05 +00:00
2009-09-22 21:26:20 +00:00
self . simple = c if global
c
2006-01-27 05:33:08 +00:00
end
2005-12-13 06:08:40 +00:00
2005-11-16 17:56:07 +00:00
# Convert a standard ASCII string to 16-bit Unicode
2006-04-30 19:49:27 +00:00
def unicode ( str )
2005-11-26 02:34:39 +00:00
Rex :: Text . to_unicode ( str )
2005-11-16 17:56:07 +00:00
end
2009-11-03 18:09:05 +00:00
2005-11-17 04:25:30 +00:00
# This method establishes a SMB session over the default socket
2005-10-03 13:51:05 +00:00
def smb_login
simple . login (
2009-11-03 18:09:05 +00:00
datastore [ 'SMBName' ] ,
2007-02-18 07:06:30 +00:00
datastore [ 'SMBUser' ] ,
datastore [ 'SMBPass' ] ,
2011-03-07 19:57:53 +00:00
datastore [ 'SMBDomain' ] ,
2011-03-08 23:29:34 +00:00
datastore [ 'SMB::VerifySignature' ] ,
datastore [ 'NTLM::UseNTLMv2' ] ,
datastore [ 'NTLM::UseNTLM2_session' ] ,
datastore [ 'NTLM::SendLM' ] ,
datastore [ 'NTLM::UseLMKey' ] ,
datastore [ 'NTLM::SendNTLM' ] ,
datastore [ 'SMB::Native_OS' ] ,
2011-03-16 00:12:07 +00:00
datastore [ 'SMB::Native_LM' ] ,
2011-03-16 00:34:07 +00:00
{ :use_spn = > datastore [ 'NTLM::SendSPN' ] , :name = > self . rhost }
2005-10-03 13:51:05 +00:00
)
2008-03-13 15:46:33 +00:00
simple . connect ( " \\ \\ #{ datastore [ 'RHOST' ] } \\ IPC$ " )
2005-10-03 13:51:05 +00:00
end
2005-11-17 04:25:30 +00:00
2011-03-07 19:57:53 +00:00
2009-11-03 18:09:05 +00:00
# This method returns the native operating system of the peer
2005-10-03 13:51:05 +00:00
def smb_peer_os
self . simple . client . peer_native_os
end
2009-11-03 18:09:05 +00:00
2005-11-17 04:25:30 +00:00
# This method returns the native lanman version of the peer
2005-10-03 13:51:05 +00:00
def smb_peer_lm
self . simple . client . peer_native_lm
end
2009-11-03 18:09:05 +00:00
2005-11-17 04:25:30 +00:00
# This method opens a handle to an IPC pipe
2005-10-03 13:51:05 +00:00
def smb_create ( pipe )
self . simple . create_pipe ( pipe )
end
2009-11-03 18:09:05 +00:00
2011-03-07 19:57:53 +00:00
#the default chunk size of 48000 for OpenFile is not compatible when signing is enabled (and with some nt4 implementations)
#cause it looks like MS windows refuse to sign big packet and send STATUS_ACCESS_DENIED
#fd.chunk_size = 500 is better
def smb_open ( path , perm )
2011-03-08 23:29:34 +00:00
self . simple . open ( path , perm , datastore [ 'SMB::ChunkSize' ] )
2011-03-07 19:57:53 +00:00
end
2005-11-29 02:57:04 +00:00
def smb_hostname
2007-02-18 07:06:30 +00:00
datastore [ 'SMBName' ] || '*SMBSERVER'
2005-11-29 02:57:04 +00:00
end
2009-11-03 18:09:05 +00:00
2008-11-03 09:17:08 +00:00
def smb_direct
datastore [ 'SMBDirect' ]
end
2009-11-03 18:09:05 +00:00
2010-12-02 17:29:26 +00:00
def domain
datastore [ 'SMBDomain' ]
end
def smbhost
if domain == " . "
" #{ rhost } : #{ rport } "
else
" #{ rhost } : #{ rport } | #{ domain } "
end
end
# If the username contains a / slash, then
# split it as a domain/username. NOTE: this
# is predicated on forward slashes, and not
# Microsoft's backwards slash convention.
def domain_username_split ( user )
return user if ( user . nil? || user . empty? )
if ! user [ / \/ / ] # Only /, not \!
return [ nil , user ]
else
return user . split ( " / " , 2 )
end
end
def splitname ( uname )
if datastore [ " PRESERVE_DOMAINS " ]
d , u = domain_username_split ( uname )
return u
else
return uname
end
end
2009-11-03 18:09:05 +00:00
2008-11-03 20:37:51 +00:00
#
# Fingerprinting methods
#
2009-11-03 18:09:05 +00:00
2008-11-03 20:37:51 +00:00
# This method the EnumPrinters() function of the spooler service
def smb_enumprinters ( flags , name , level , blen )
stub =
NDR . long ( flags ) +
( name ? NDR . uwstring ( name ) : NDR . long ( 0 ) ) +
NDR . long ( level ) +
NDR . long ( rand ( 0xffffffff ) + 1 ) +
NDR . long ( blen ) +
" \x00 " * blen +
NDR . long ( blen )
2009-11-03 18:09:05 +00:00
2008-11-03 20:37:51 +00:00
handle = dcerpc_handle (
2009-11-03 18:09:05 +00:00
'12345678-1234-abcd-ef00-0123456789ab' , '1.0' ,
2008-11-03 20:37:51 +00:00
'ncacn_np' , [ " \\ SPOOLSS " ]
)
begin
dcerpc_bind ( handle )
dcerpc . call ( 0x00 , stub )
return dcerpc . last_response . stub_data
rescue :: Interrupt
raise $!
rescue :: Exception = > e
return nil
2009-11-03 18:09:05 +00:00
end
2008-11-03 20:37:51 +00:00
end
2009-11-03 18:09:05 +00:00
2008-11-03 20:37:51 +00:00
# This method dumps the print provider strings from the spooler
def smb_enumprintproviders
resp = smb_enumprinters ( 8 , nil , 1 , 0 )
2009-11-03 18:09:05 +00:00
return nil if not resp
2008-11-03 20:37:51 +00:00
rptr , tmp , blen = resp . unpack ( " V* " )
resp = smb_enumprinters ( 8 , nil , 1 , blen )
return nil if not resp
2009-11-03 18:09:05 +00:00
2008-11-03 20:37:51 +00:00
bcnt , pcnt , stat = resp [ - 12 , 12 ] . unpack ( " VVV " )
return nil if stat != 0
return nil if pcnt == 0
return nil if bcnt > blen
return nil if pcnt < 3
#
# The correct way, which leads to invalid offsets :-(
#
2009-11-13 20:28:36 +00:00
#providers = []
#
#0.upto(pcnt-1) do |i|
# flags,desc_o,name_o,comm_o = resp[8 + (i*16), 16].unpack("VVVV")
#
# #desc = read_unicode(resp,8+desc_o).gsub("\x00", '')
# #name = read_unicode(resp,8+name_o).gsub("\x00", '')
# #comm = read_unicode(resp,8+comm_o).gsub("\x00", '')
# #providers << [flags,desc,name,comm]
#end
#
#providers
2009-11-16 18:28:45 +00:00
return resp
2008-11-03 20:37:51 +00:00
end
2009-11-03 18:09:05 +00:00
2008-11-03 20:37:51 +00:00
# This method performs an extensive set of fingerprinting operations
def smb_fingerprint
fprint = { }
2009-11-03 18:09:05 +00:00
2008-11-03 20:37:51 +00:00
# Connect to the server if needed
if ( not self . simple )
connect ( )
smb_login ( )
end
2010-08-12 15:00:58 +00:00
2008-11-03 20:37:51 +00:00
os = 'Unknown'
sp = ''
case smb_peer_os ( )
when 'Windows NT 4.0'
os = 'Windows NT 4.0'
when 'Windows 5.0'
os = 'Windows 2000'
when 'Windows 5.1'
os = 'Windows XP'
when / Windows XP ( \ d+) Service Pack ( \ d+) /
os = 'Windows XP'
sp = 'Service Pack ' + $2
when / Windows Server 2003 ( \ d+)$ /
os = 'Windows 2003'
sp = 'No Service Pack'
when / Windows Server 2003 ( \ d+) Service Pack ( \ d+) /
os = 'Windows 2003'
sp = 'Service Pack ' + $2
when / Windows Server 2003 R2 ( \ d+) Service Pack ( \ d+) /
os = 'Windows 2003 R2'
sp = 'Service Pack ' + $2
when / Windows Vista \ (TM \ ) ( \ w+| \ w+ \ w+) ( \ d+) Service Pack ( \ d+) /
os = 'Windows Vista ' + $1
sp = 'Service Pack ' + $3
when / Windows Vista \ (TM \ ) ( \ w+| \ w+ \ w+) ( \ d+) /
os = 'Windows Vista ' + $1
sp = '(Build ' + $2 + ')'
2009-12-26 18:26:24 +00:00
when / Windows Server \ (R \ ) 2008 (([ \ - \ w]+ ){1,4})( \ d+) Service Pack ( \ d+) /
2009-12-26 18:29:24 +00:00
os = 'Windows 2008 ' + $1 . strip
2009-12-26 18:17:35 +00:00
sp = 'Service Pack ' + $4
2008-11-03 20:37:51 +00:00
2009-12-26 18:26:24 +00:00
when / Windows Server \ (R \ ) 2008 (([ \ - \ w]+ ){1,4})( \ d+) /
2009-12-26 18:29:24 +00:00
os = 'Windows 2008 ' + $1 . strip
2009-12-26 18:17:35 +00:00
sp = '(Build ' + $3 + ')'
2009-06-28 20:23:31 +00:00
2009-12-26 18:26:24 +00:00
when / Windows \ (R \ ) Storage Server 2008 (([ \ - \ w]+ ){1,4})( \ d+) Service Pack ( \ d+) /
2009-12-26 18:29:24 +00:00
os = 'Windows 2008 Storage Server ' + $1 . strip
2009-12-26 18:17:35 +00:00
sp = 'Service Pack ' + $4
2009-06-28 20:23:31 +00:00
2009-12-26 18:26:24 +00:00
when / Windows \ (R \ ) Storage Server 2008 (([ \ - \ w]+ ){1,4})( \ d+) /
2009-12-26 18:29:24 +00:00
os = 'Windows 2008 Storage Server ' + $1 . strip
2009-12-26 18:17:35 +00:00
sp = '(Build ' + $3 + ')'
2009-11-03 18:09:05 +00:00
2009-12-26 18:26:24 +00:00
when / Windows 7 (([ \ - \ w]+ ){1,4})( \ d+) /
2009-12-26 18:29:24 +00:00
os = 'Windows 7 ' + $1 . strip
2009-12-26 18:17:35 +00:00
sp = '(Build ' + $3 + ')'
2008-11-03 20:37:51 +00:00
2009-12-26 18:26:24 +00:00
when / ^(Windows.*) Service Pack ( \ d+) /
2009-12-26 18:29:24 +00:00
os = $1 . strip
2009-12-26 18:26:24 +00:00
sp = 'Service Pack ' + $2
when / ^(Windows.*) ( \ d+) /
2009-12-26 18:29:24 +00:00
os = $1 . strip
2009-12-26 18:26:24 +00:00
sp = '(Build ' + $2 + ')'
2010-02-11 22:37:00 +00:00
when 'VxWorks'
os = 'VxWorks'
sp = smb_peer_lm ( )
2008-11-03 20:37:51 +00:00
when 'Unix'
os = 'Unix'
sv = smb_peer_lm ( )
case sv
when / Samba \ s+(.*) /i
sp = 'Samba ' + $1
end
end
if ( os == 'Windows XP' and sp . length == 0 )
# SRVSVC was blocked in SP2
begin
smb_create ( " \\ SRVSVC " )
sp = 'Service Pack 0 / 1'
rescue :: Rex :: Proto :: SMB :: Exceptions :: ErrorCode = > e
if ( e . error_code == 0xc0000022 )
sp = 'Service Pack 2+'
end
end
end
if ( os == 'Windows 2000' and sp . length == 0 )
# LLSRPC was blocked in a post-SP4 update
begin
smb_create ( " \\ LLSRPC " )
sp = 'Service Pack 0 - 4'
rescue :: Rex :: Proto :: SMB :: Exceptions :: ErrorCode = > e
if ( e . error_code == 0xc0000022 )
sp = 'Service Pack 4 with MS05-010+'
end
end
end
#
# Perform granular XP SP checks if LSARPC is exposed
#
if ( os == 'Windows XP' )
#
# Service Pack 2 added a range(0,64000) to opnum 0x22 in SRVSVC
# Credit to spoonm for first use of unbounded [out] buffers
#
handle = dcerpc_handle (
2009-11-03 18:09:05 +00:00
'4b324fc8-1670-01d3-1278-5a47bf6ee188' , '3.0' ,
2008-11-03 20:37:51 +00:00
'ncacn_np' , [ " \\ BROWSER " ]
)
begin
dcerpc_bind ( handle )
2009-11-03 18:09:05 +00:00
stub =
2008-11-03 20:37:51 +00:00
NDR . uwstring ( Rex :: Text . rand_text_alpha ( rand ( 10 ) + 1 ) ) +
NDR . wstring ( Rex :: Text . rand_text_alpha ( rand ( 10 ) + 1 ) ) +
NDR . long ( 64001 ) +
NDR . long ( 0 ) +
NDR . long ( 0 )
dcerpc . call ( 0x22 , stub )
sp = " Service Pack 0 / 1 "
rescue :: Interrupt
raise $!
rescue :: Rex :: Proto :: SMB :: Exceptions :: ErrorCode
rescue :: Rex :: Proto :: SMB :: Exceptions :: ReadPacket
rescue :: Rex :: Proto :: DCERPC :: Exceptions :: Fault
sp = " Service Pack 2+ "
rescue :: Exception
end
#
# Service Pack 3 fixed information leaks via [unique][out] pointers
# Call SRVSVC::NetRemoteTOD() to return [out] [ref] [unique]
# Credit:
# Pointer leak is well known, but Immunity also covered in a paper
# Silent fix of pointer leak in SP3 and detection method by Rhys Kidd
#
handle = dcerpc_handle (
2009-11-03 18:09:05 +00:00
'4b324fc8-1670-01d3-1278-5a47bf6ee188' , '3.0' ,
2008-11-03 20:37:51 +00:00
'ncacn_np' , [ " \\ BROWSER " ]
)
begin
dcerpc_bind ( handle )
stub = NDR . uwstring ( Rex :: Text . rand_text_alpha ( rand ( 8 ) + 1 ) )
resp = dcerpc . call ( 0x1c , stub )
if ( resp and resp [ 0 , 4 ] == " \x00 \x00 \x02 \x00 " )
sp = " Service Pack 3 "
else
if ( resp and sp =~ / Service Pack 2 \ + / )
sp = " Service Pack 2 "
end
end
rescue :: Interrupt
raise $!
rescue :: Rex :: Proto :: SMB :: Exceptions :: ErrorCode
rescue :: Rex :: Proto :: SMB :: Exceptions :: ReadPacket
rescue :: Exception
end
end
#
# Remote language detection via Print Providers
# Credit: http://immunityinc.com/downloads/Remote_Language_Detection_in_Immunity_CANVAS.odt
#
lang = 'Unknown'
2009-11-03 18:09:05 +00:00
sigs =
2008-11-03 20:37:51 +00:00
{
'English' = >
[
Rex :: Text . to_unicode ( 'Windows NT Remote Printers' ) ,
Rex :: Text . to_unicode ( 'LanMan Print Services' )
] ,
'Spanish' = >
[
Rex :: Text . to_unicode ( 'Impresoras remotas Windows NT' ) ,
Rex :: Text . to_unicode ( 'Impresoras remotas de Windows NT' )
] ,
'Italian' = >
[
Rex :: Text . to_unicode ( 'Stampanti remote di Windows NT' ) ,
Rex :: Text . to_unicode ( 'Servizi di stampa LanMan' )
] ,
'French' = >
[
Rex :: Text . to_unicode ( 'Imprimantes distantes NT' ) ,
Rex :: Text . to_unicode ( 'Imprimantes distantes pour Windows NT' ) ,
Rex :: Text . to_unicode ( " Services d'impression LanMan " )
] ,
'German' = >
[
Rex :: Text . to_unicode ( 'Remotedrucker' )
] ,
2008-11-04 22:27:59 +00:00
'Portuguese - Brazilian' = >
2008-11-03 20:37:51 +00:00
[
Rex :: Text . to_unicode ( 'Impr. remotas Windows NT' ) ,
Rex :: Text . to_unicode ( 'Impressoras remotas do Windows NT' )
] ,
2008-11-04 22:27:59 +00:00
'Portuguese' = >
2008-11-03 20:37:51 +00:00
[
Rex :: Text . to_unicode ( 'Imp. remotas do Windows NT' )
] ,
'Hungarian' = >
[
2009-03-07 18:17:08 +00:00
Rex :: Text . to_unicode ( " \x54 \xe1 \x76 \x6f \x6c \x69 \x20 \x6e \x79 \x6f \x6d \x74 \x61 \x74 \xf3 \x6b " )
2008-11-03 20:37:51 +00:00
] ,
'Finnish' = >
[
2009-03-07 18:17:08 +00:00
Rex :: Text . to_unicode ( " \x45 \x74 \xe4 \x74 \x75 \x6c \x6f \x73 \x74 \x69 \x6d \x65 \x74 " )
2008-11-03 20:37:51 +00:00
] ,
'Dutch' = >
[
Rex :: Text . to_unicode ( 'Externe printers voor NT' )
] ,
'Danish' = >
[
Rex :: Text . to_unicode ( 'Fjernprintere' )
] ,
'Swedish' = >
[
2009-03-07 18:17:08 +00:00
Rex :: Text . to_unicode ( " \x46 \x6a \xe4 \x72 \x72 \x73 \x6b \x72 \x69 \x76 \x61 \x72 \x65 " )
2008-11-03 20:37:51 +00:00
] ,
'Polish' = >
[
Rex :: Text . to_unicode ( 'Zdalne drukarki' )
] ,
2008-11-04 07:13:48 +00:00
'Czech' = >
[
2009-03-07 18:17:08 +00:00
Rex :: Text . to_unicode ( " \x56 \x7a \x64 \xe1 \x6c \x65 \x6e \xe9 \x20 \x74 \x69 \x73 \x6b \xe1 \x72 \x6e \x79 " )
2008-11-04 07:13:48 +00:00
] ,
2008-11-03 20:37:51 +00:00
'Turkish' = >
[
" \x59 \x00 \x61 \x00 \x7a \x00 \x31 \x01 \x63 \x00 \x31 \x01 \x6c \x00 \x61 \x00 \x72 \x00 "
] ,
'Japanese' = >
[
" \xea \x30 \xe2 \x30 \xfc \x30 \xc8 \x30 \x20 \x00 \xd7 \x30 \xea \x30 \xf3 \x30 \xbf \x30 "
] ,
'Chinese - Traditional' = >
[
" \xdc \x8f \x0b \x7a \x53 \x62 \x70 \x53 \x3a \x67 "
] ,
2009-11-03 18:09:05 +00:00
'Chinese - Traditional / Taiwan' = >
2008-11-03 20:37:51 +00:00
[
" \x60 \x90 \xef \x7a \x70 \x53 \x68 \x88 \x5f \x6a " ,
] ,
'Korean' = >
[
" \xd0 \xc6 \xa9 \xac \x20 \x00 \x04 \xd5 \xb0 \xb9 \x30 \xd1 " ,
] ,
'Russian' = >
[
" \x1f \x04 \x40 \x04 \x38 \x04 \x3d \x04 \x42 \x04 \x35 \x04 \x40 \x04 \x4b \x04 \x20 \x00 \x43 \x04 \x34 \x04 \x30 \x04 \x3b \x04 \x35 \x04 \x3d \x04 \x3d \x04 \x3e \x04 \x33 \x04 \x3e \x04 \x20 \x00 \x34 \x04 \x3e \x04 \x41 \x04 \x42 \x04 \x43 \x04 \x3f \x04 \x30 \x04 " ,
] ,
}
begin
prov = smb_enumprintproviders ( )
if ( prov )
sigs . each_key do | k |
sigs [ k ] . each do | s |
if ( prov . index ( s ) )
lang = k
break
end
break if lang != 'Unknown'
end
break if lang != 'Unknown'
end
if ( lang == 'Unknown' )
@fpcache || = { }
mhash = :: Digest :: MD5 . hexdigest ( prov [ 4 , prov . length - 4 ] )
if ( not @fpcache [ mhash ] )
buff = " \n "
buff << " *** NEW FINGERPRINT: PLEASE SEND TO [ msfdev[at]metasploit.com ] \n "
2008-11-04 04:24:11 +00:00
buff << " VERS: $Revision$ \n "
2008-11-03 20:37:51 +00:00
buff << " HOST: #{ rhost } \n "
buff << " OS: #{ os } \n "
buff << " SP: #{ sp } \n "
prov . unpack ( " H* " ) [ 0 ] . scan ( / .{64}|.* / ) . each do | line |
next if line . length == 0
buff << " FP: #{ line } \n "
end
prov . split ( / \ x00 \ x00+ / ) . each do | line |
line . gsub! ( " \x00 " , '' )
line . strip!
next if line . length < 6
buff << " TXT: #{ line } \n "
end
buff << " *** END FINGERPRINT \n "
print_line ( buff )
@fpcache [ mhash ] = true
end
end
end
rescue :: Interrupt
raise $!
rescue :: Rex :: Proto :: SMB :: Exceptions :: ErrorCode
end
fprint [ 'os' ] = os
fprint [ 'sp' ] = sp
fprint [ 'lang' ] = lang
fprint
end
2009-11-03 18:09:05 +00:00
2008-11-03 20:37:51 +00:00
#
# Accessors
#
2009-11-03 18:09:05 +00:00
2005-11-15 23:02:17 +00:00
attr_accessor :simple
2005-10-03 13:51:05 +00:00
end
2007-07-03 04:20:50 +00:00
###
#
# This mixin provides a minimal SMB server
#
###
module Exploit::Remote::SMBServer
include Exploit :: Remote :: TcpServer
CONST = :: Rex :: Proto :: SMB :: Constants
CRYPT = :: Rex :: Proto :: SMB :: Crypt
UTILS = :: Rex :: Proto :: SMB :: Utils
XCEPT = :: Rex :: Proto :: SMB :: Exceptions
EVADE = :: Rex :: Proto :: SMB :: Evasions
2011-03-08 23:31:06 +00:00
NTLM_CONST = :: Rex :: Proto :: NTLM :: Constants
NTLM_CRYPT = :: Rex :: Proto :: NTLM :: Crypt
NTLM_UTILS = :: Rex :: Proto :: NTLM :: Utils
NTLM_BASE = :: Rex :: Proto :: NTLM :: Base
NTLM_MESSAGE = :: Rex :: Proto :: NTLM :: Message
2007-07-03 04:20:50 +00:00
def initialize ( info = { } )
super
register_options (
[
2010-03-27 21:00:28 +00:00
OptPort . new ( 'SRVPORT' , [ true , " The local port to listen on. " , 445 ] )
2007-07-03 04:20:50 +00:00
] , self . class )
end
def setup
super
@state = { }
end
def on_client_connect ( client )
# print_status("New SMB connection from #{client.peerhost}:#{client.peerport}")
smb_conn ( client )
end
2009-11-03 18:09:05 +00:00
2007-07-03 04:20:50 +00:00
def on_client_data ( client )
# print_status("New data from #{client.peerhost}:#{client.peerport}")
smb_recv ( client )
true
end
2009-11-03 18:09:05 +00:00
2007-07-03 04:20:50 +00:00
def on_client_close ( client )
smb_stop ( client )
end
2009-11-03 18:09:05 +00:00
2007-07-03 04:20:50 +00:00
def smb_conn ( c )
@state [ c ] = { :name = > " #{ c . peerhost } : #{ c . peerport } " , :ip = > c . peerhost , :port = > c . peerport }
end
2009-11-03 18:09:05 +00:00
2007-07-03 04:20:50 +00:00
def smb_stop ( c )
@state . delete ( c )
end
2009-11-03 18:09:05 +00:00
2007-07-03 04:20:50 +00:00
def smb_recv ( c )
smb = @state [ c ]
smb [ :data ] || = ''
smb [ :data ] << c . get_once
2009-11-03 18:09:05 +00:00
2007-07-03 04:20:50 +00:00
while ( smb [ :data ] . length > 0 )
2009-11-03 18:09:05 +00:00
2007-07-03 04:20:50 +00:00
return if smb [ :data ] . length < 4
plen = smb [ :data ] [ 2 , 2 ] . unpack ( 'n' ) [ 0 ]
return if smb [ :data ] . length < plen + 4
buff = smb [ :data ] . slice! ( 0 , plen + 4 )
pkt_nbs = CONST :: NBRAW_PKT . make_struct
pkt_nbs . from_s ( buff )
# print_status("NetBIOS request from #{smb[:name]} #{pkt_nbs.v['Type']} #{pkt_nbs.v['Flags']} #{buff.inspect}")
# Check for a NetBIOS name request
if ( pkt_nbs . v [ 'Type' ] == 0x81 )
# Accept any name they happen to send
2009-11-03 18:09:05 +00:00
2007-07-03 04:20:50 +00:00
host_dst = UTILS . nbname_decode ( pkt_nbs . v [ 'Payload' ] [ 1 , 32 ] ) . gsub ( / [ \ x00 \ x20]+$ / , '' )
host_src = UTILS . nbname_decode ( pkt_nbs . v [ 'Payload' ] [ 35 , 32 ] ) . gsub ( / [ \ x00 \ x20]+$ / , '' )
2009-11-03 18:09:05 +00:00
2007-07-03 04:20:50 +00:00
smb [ :nbdst ] = host_dst
smb [ :nbsrc ] = host_src
2009-11-03 18:09:05 +00:00
2007-07-03 04:20:50 +00:00
# print_status("NetBIOS session request from #{smb[:name]} (asking for #{host_dst} from #{host_src})")
c . write ( " \x82 \x00 \x00 \x00 " )
next
end
2009-11-03 18:09:05 +00:00
#
2007-07-03 04:20:50 +00:00
# TODO: Support AndX parameters
2009-11-03 18:09:05 +00:00
#
2007-07-03 04:20:50 +00:00
# Cast this to a generic SMB structure
pkt = CONST :: SMB_BASE_PKT . make_struct
pkt . from_s ( buff )
# Only response to requests, ignore server replies
if ( pkt [ 'Payload' ] [ 'SMB' ] . v [ 'Flags1' ] & 128 != 0 )
2009-11-03 18:09:05 +00:00
print_status ( " Ignoring server response from #{ smb [ :name ] } " )
2007-07-03 04:20:50 +00:00
next
end
2009-11-03 18:09:05 +00:00
2007-07-03 04:20:50 +00:00
cmd = pkt [ 'Payload' ] [ 'SMB' ] . v [ 'Command' ]
begin
smb_cmd_dispatch ( cmd , c , buff )
rescue :: Interrupt
raise $!
rescue :: Exception = > e
2008-12-19 07:11:08 +00:00
print_status ( " Error processing request from #{ smb [ :name ] } ( #{ cmd } ): #{ e . class } #{ e } #{ e . backtrace } " )
2009-11-03 18:09:05 +00:00
next
end
end
2007-07-03 04:20:50 +00:00
end
2009-11-03 18:09:05 +00:00
2007-07-03 04:20:50 +00:00
def smb_cmd_dispatch ( cmd , c , buff )
2009-11-03 18:09:05 +00:00
smb = @state [ c ]
print_status ( " Received command #{ cmd } from #{ smb [ :name ] } " )
2007-07-03 04:20:50 +00:00
end
2009-11-03 18:09:05 +00:00
2007-07-03 04:20:50 +00:00
def smb_set_defaults ( c , pkt )
2011-01-30 19:26:35 +00:00
smb = @state [ c ]
2007-07-03 04:20:50 +00:00
pkt [ 'Payload' ] [ 'SMB' ] . v [ 'ProcessID' ] = smb [ :process_id ] . to_i
pkt [ 'Payload' ] [ 'SMB' ] . v [ 'UserID' ] = smb [ :user_id ] . to_i
pkt [ 'Payload' ] [ 'SMB' ] . v [ 'TreeID' ] = smb [ :tree_id ] . to_i
pkt [ 'Payload' ] [ 'SMB' ] . v [ 'MultiplexID' ] = smb [ :multiplex_id ] . to_i
end
2009-11-03 18:09:05 +00:00
2011-01-30 19:26:35 +00:00
def smb_error ( cmd , c , errorclass , esn = false )
# 0xc0000022 = Deny
# 0xc000006D = Logon_Failure
# 0x00000000 = Ignore
pkt = CONST :: SMB_BASE_PKT . make_struct
smb_set_defaults ( c , pkt )
pkt [ 'Payload' ] [ 'SMB' ] . v [ 'Command' ] = cmd
pkt [ 'Payload' ] [ 'SMB' ] . v [ 'Flags1' ] = 0x88
if esn
pkt [ 'Payload' ] [ 'SMB' ] . v [ 'Flags2' ] = 0xc801
else
pkt [ 'Payload' ] [ 'SMB' ] . v [ 'Flags2' ] = 0xc001
end
pkt [ 'Payload' ] [ 'SMB' ] . v [ 'ErrorClass' ] = errorclass
c . put ( pkt . to_s )
end
2007-07-03 04:20:50 +00:00
end
2008-11-03 09:17:08 +00:00
end
2009-11-03 18:09:05 +00:00