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:
parent
86500aad47
commit
452cead1e9
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue