lib/rex/proto/ntlm/utils.rb in librex-0.0.65 vs lib/rex/proto/ntlm/utils.rb in librex-0.0.66
- old
+ new
@@ -1,5 +1,6 @@
+# -*- coding: binary -*-
require 'rex/proto/ntlm/constants'
require 'rex/proto/ntlm/crypt'
require 'rex/proto/ntlm/exceptions'
module Rex
@@ -55,48 +56,48 @@
# GSS BLOB usefull for SMB_NEGOCIATE_RESPONSE message
# mechTypes: 2 items :
# -MechType: 1.3.6.1.4.1.311.2.2.30 (SNMPv2-SMI::enterprises.311.2.2.30)
# -MechType: 1.3.6.1.4.1.311.2.2.10 (NTLMSSP - Microsoft NTLM Security Support Provider)
- #
+ #
# this is the default on Win7
def self.make_simple_negotiate_secblob_resp
- blob =
- "\x60" + self.asn1encode(
+ blob =
+ "\x60" + self.asn1encode(
"\x06" + self.asn1encode(
"\x2b\x06\x01\x05\x05\x02"
- ) +
+ ) +
"\xa0" + self.asn1encode(
"\x30" + self.asn1encode(
"\xa0" + self.asn1encode(
- "\x30" + self.asn1encode(
+ "\x30" + self.asn1encode(
"\x06" + self.asn1encode(
"\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"
- )
+ )
)
- )
+ )
)
)
)
- return blob
- end
+ return blob
+ end
# GSS BLOB usefull for SMB_NEGOCIATE_RESPONSE message
# mechTypes: 4 items :
# MechType: 1.2.840.48018.1.2.2 (MS KRB5 - Microsoft Kerberos 5)
# MechType: 1.2.840.113554.1.2.2 (KRB5 - Kerberos 5)
# MechType: 1.2.840.113554.1.2.2.3 (KRB5 - Kerberos 5 - User to User)
# MechType: 1.3.6.1.4.1.311.2.2.10 (NTLMSSP - Microsoft NTLM Security Support Provider)
- # mechListMIC:
+ # mechListMIC:
# principal: account@domain
def self.make_negotiate_secblob_resp(account, domain)
- blob =
- "\x60" + self.asn1encode(
+ blob =
+ "\x60" + self.asn1encode(
"\x06" + self.asn1encode(
"\x2b\x06\x01\x05\x05\x02"
- ) +
+ ) +
"\xa0" + self.asn1encode(
"\x30" + self.asn1encode(
"\xa0" + self.asn1encode(
"\x30" + self.asn1encode(
"\x06" + self.asn1encode(
@@ -105,14 +106,14 @@
"\x06" + self.asn1encode(
"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"
) +
"\x06" + self.asn1encode(
"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x03"
- ) +
+ ) +
"\x06" + self.asn1encode(
"\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"
- )
+ )
)
) +
"\xa3" + self.asn1encode(
"\x30" + self.asn1encode(
"\xa0" + self.asn1encode(
@@ -124,12 +125,12 @@
)
)
)
)
- return blob
- end
+ return blob
+ end
# BLOB without GSS usefull for ntlmssp type 1 message
def self.make_ntlmssp_blob_init(domain = 'WORKGROUP', name = 'WORKSTATION', flags=0x80201)
blob = "NTLMSSP\x00" +
[1, flags].pack('VV') +
@@ -142,23 +143,23 @@
[
name.length, #length
name.length, #max length
domain.length + 32
- ].pack('vvV') +
+ ].pack('vvV') +
domain + name
return blob
end
# GSS BLOB usefull for ntlmssp type 1 message
def self.make_ntlmssp_secblob_init(domain = 'WORKGROUP', name = 'WORKSTATION', flags=0x80201)
- blob =
- "\x60" + self.asn1encode(
+ blob =
+ "\x60" + self.asn1encode(
"\x06" + self.asn1encode(
"\x2b\x06\x01\x05\x05\x02"
- ) +
+ ) +
"\xa0" + self.asn1encode(
"\x30" + self.asn1encode(
"\xa0" + self.asn1encode(
"\x30" + self.asn1encode(
"\x06" + self.asn1encode(
@@ -173,48 +174,48 @@
)
)
)
)
- return blob
+ return blob
end
- # BLOB without GSS usefull for ntlm type 2 message
+ # BLOB without GSS usefull for ntlm type 2 message
def self.make_ntlmssp_blob_chall(win_domain, win_name, dns_domain, dns_name, chall, flags)
addr_list = ''
addr_list << [2, win_domain.length].pack('vv') + win_domain
addr_list << [1, win_name.length].pack('vv') + win_name
addr_list << [4, dns_domain.length].pack('vv') + dns_domain
addr_list << [3, dns_name.length].pack('vv') + dns_name
addr_list << [0, 0].pack('vv')
- ptr = 0
+ ptr = 0
blob = "NTLMSSP\x00" +
[2].pack('V') +
[
win_domain.length, # length
win_domain.length, # max length
(ptr += 48) # offset
].pack('vvV') +
[ flags ].pack('V') +
- chall +
+ chall +
"\x00\x00\x00\x00\x00\x00\x00\x00" +
[
addr_list.length, # length
addr_list.length, # max length
- (ptr += win_domain.length)
+ (ptr += win_domain.length)
].pack('vvV') +
- win_domain +
+ win_domain +
addr_list
return blob
end
# GSS BLOB usefull for ntlmssp type 2 message
def self.make_ntlmssp_secblob_chall(win_domain, win_name, dns_domain, dns_name, chall, flags)
-
+
blob =
"\xa1" + self.asn1encode(
"\x30" + self.asn1encode(
"\xa0" + self.asn1encode(
"\x0a" + self.asn1encode(
@@ -229,75 +230,75 @@
"\xa2" + self.asn1encode(
"\x04" + self.asn1encode(
make_ntlmssp_blob_chall(win_domain, win_name, dns_domain, dns_name, chall, flags)
)
)
- )
+ )
)
return blob
end
# BLOB without GSS Usefull for ntlmssp type 3 message
def self.make_ntlmssp_blob_auth(domain, name, user, lm, ntlm, enc_session_key, flags = 0x080201)
lm ||= "\x00" * 24
- ntlm ||= "\x00" * 24
-
+ ntlm ||= "\x00" * 24
+
domain_uni = Rex::Text.to_unicode(domain)
user_uni = Rex::Text.to_unicode(user)
name_uni = Rex::Text.to_unicode(name)
session = enc_session_key
- ptr = 64
+ ptr = 64
blob = "NTLMSSP\x00" +
[ 3 ].pack('V') +
-
+
[ # Lan Manager Response
lm.length,
lm.length,
(ptr)
].pack('vvV') +
-
+
[ # NTLM Manager Response
ntlm.length,
ntlm.length,
(ptr += lm.length)
- ].pack('vvV') +
-
+ ].pack('vvV') +
+
[ # Domain Name
domain_uni.length,
domain_uni.length,
(ptr += ntlm.length)
- ].pack('vvV') +
+ ].pack('vvV') +
[ # Username
user_uni.length,
user_uni.length,
(ptr += domain_uni.length)
- ].pack('vvV') +
+ ].pack('vvV') +
[ # Hostname
name_uni.length,
name_uni.length,
(ptr += user_uni.length)
- ].pack('vvV') +
-
+ ].pack('vvV') +
+
[ # Session Key (none)
session.length,
session.length,
(ptr += name_uni.length)
- ].pack('vvV') +
+ ].pack('vvV') +
[ flags ].pack('V') +
lm +
ntlm +
domain_uni +
user_uni +
- name_uni +
- session + "\x00"
+ name_uni +
+ session + "\x00"
return blob
end
# GSS BLOB Usefull for ntlmssp type 3 message
@@ -325,11 +326,11 @@
"\xa0" + self.asn1encode(
"\x0a" + self.asn1encode(
"\x00"
)
)
- )
+ )
)
return blob
end
# Return the correct ntlmflags upon the configuration
@@ -340,32 +341,32 @@
use_ntlmv2 = opt[:use_ntlmv2] != nil ? opt[:use_ntlmv2] : false
send_lm = opt[:send_lm] != nil ? opt[:send_lm] : true
send_ntlm = opt[:send_ntlm] != nil ? opt[:send_ntlm] : true
use_lanman_key = opt[:use_lanman_key] != nil ? opt[:use_lanman_key] : false
- if signing
+ if signing
ntlmssp_flags = 0xe2088215
else
ntlmssp_flags = 0xa2080205
end
if usentlm2_session
if use_ntlmv2
#set Negotiate Target Info
- ntlmssp_flags |= CONST::NEGOTIATE_TARGET_INFO
+ ntlmssp_flags |= CONST::NEGOTIATE_TARGET_INFO
end
else
#remove the ntlm2_session flag
ntlmssp_flags &= 0xfff7ffff
#set lanmanflag only when lm and ntlm are sent
if send_lm
ntlmssp_flags |= CONST::NEGOTIATE_LMKEY if use_lanman_key
end
end
-
+
#we can also downgrade ntlm2_session when we send only lmv1
ntlmssp_flags &= 0xfff7ffff if usentlm2_session && (not use_ntlmv2) && (not send_ntlm)
return ntlmssp_flags
end
@@ -412,25 +413,25 @@
#A 32-bit value indicating server or client configuration
when 7
#Client time
data[:chall_MsvAvTimestamp] = addr
when 8
- #A Restriction_Encoding structure
+ #A Restriction_Encoding structure
when 9
- #The SPN of the target server.
+ #The SPN of the target server.
when 10
#A channel bindings hash.
end
end
return data
end
# This function return an ntlmv2 client challenge
# This is a partial implementation, full description is in [MS-NLMP].pdf around 3.1.5.2.1 :-/
- def self.make_ntlmv2_clientchallenge(win_domain, win_name, dns_domain, dns_name,
+ def self.make_ntlmv2_clientchallenge(win_domain, win_name, dns_domain, dns_name,
client_challenge = nil, chall_MsvAvTimestamp = nil, spnopt = {})
-
+
client_challenge ||= Rex::Text.rand_text(8)
# We have to set the timestamps here to the one in the challenge message from server if present
# If we don't do that, recent server like Seven/2008 will send a STATUS_INVALID_PARAMETER error packet
timestamp = chall_MsvAvTimestamp != '' ? chall_MsvAvTimestamp : self.time_unix_to_smb(Time.now.to_i).reverse.pack("VV")
# Make those values unicode as requested
@@ -446,32 +447,32 @@
addr_list << [3, dns_name.length].pack('vv') + dns_name
addr_list << [7, 8].pack('vv') + timestamp
# Windows Seven / 2008r2 Request this type if in local security policies,
# Microsoft network server : Server SPN target name validation level is set to <Required from client>
- # otherwise it send an STATUS_ACCESS_DENIED packet
+ # otherwise it send an STATUS_ACCESS_DENIED packet
if spnopt[:use_spn]
spn= Rex::Text.to_unicode("cifs/#{spnopt[:name] || 'unknow'}")
addr_list << [9, spn.length].pack('vv') + spn
end
-
+
# MAY BE USEFUL FOR FUTURE
- # Seven (client) add at least one more av that is of type MsAvRestrictions (8)
- # maybe this will be usefull with future windows OSs but has no use at all for the moment afaik
+ # Seven (client) add at least one more av that is of type MsAvRestrictions (8)
+ # maybe this will be usefull with future windows OSs but has no use at all for the moment afaik
# restriction_encoding = [48,0,0,0].pack("VVV") + # Size, Z4, IntegrityLevel, SubjectIntegrityLevel
# Rex::Text.rand_text(32) # MachineId generated on startup on win7 and above
# addr_list << [8, restriction_encoding.length].pack('vv') + restriction_encoding
-
+
# Seven (client) and maybe others versions also add an av of type MsvChannelBindings (10) but the hash is "\x00" * 16
# addr_list << [10, 16].pack('vv') + "\x00" * 16
-
+
addr_list << [0, 0].pack('vv')
ntlm_clientchallenge = [1,1,0,0].pack("CCvV") + #RespType, HiRespType, Reserved1, Reserved2
timestamp + #Timestamp
client_challenge + #clientchallenge
- [0].pack("V") + #Reserved3
+ [0].pack("V") + #Reserved3
addr_list + "\x00" * 4
end
# create lm/ntlm responses
@@ -490,139 +491,139 @@
client_challenge = Rex::Text.rand_text(8)
ntlm_cli_challenge = ''
if send_ntlm #should be default
if usentlm2_session
if use_ntlmv2
- ntlm_cli_challenge = self.make_ntlmv2_clientchallenge(default_domain, default_name, dns_domain_name,
- dns_host_name,client_challenge ,
+ ntlm_cli_challenge = self.make_ntlmv2_clientchallenge(default_domain, default_name, dns_domain_name,
+ dns_host_name,client_challenge ,
chall_MsvAvTimestamp, spnopt)
if self.is_pass_ntlm_hash?(pass)
- argntlm = {
+ argntlm = {
:ntlmv2_hash => CRYPT::ntlmv2_hash(
- user,
- [ pass.upcase()[33,65] ].pack('H32'),
+ user,
+ [ pass.upcase()[33,65] ].pack('H32'),
domain,{:pass_is_hash => true}
),
- :challenge => challenge_key
+ :challenge => challenge_key
}
else
argntlm = {
:ntlmv2_hash => CRYPT::ntlmv2_hash(user, pass, domain),
- :challenge => challenge_key
+ :challenge => challenge_key
}
end
optntlm = { :nt_client_challenge => ntlm_cli_challenge}
ntlmv2_response = CRYPT::ntlmv2_response(argntlm,optntlm)
- resp_ntlm = ntlmv2_response
-
+ resp_ntlm = ntlmv2_response
+
if send_lm
if self.is_pass_ntlm_hash?(pass)
arglm = {
:ntlmv2_hash => CRYPT::ntlmv2_hash(
- user,
- [ pass.upcase()[33,65] ].pack('H32'),
+ user,
+ [ pass.upcase()[33,65] ].pack('H32'),
domain,{:pass_is_hash => true}
),
- :challenge => challenge_key
+ :challenge => challenge_key
}
else
arglm = {
:ntlmv2_hash => CRYPT::ntlmv2_hash(user,pass, domain),
- :challenge => challenge_key
+ :challenge => challenge_key
}
end
-
+
optlm = { :client_challenge => client_challenge }
resp_lm = CRYPT::lmv2_response(arglm, optlm)
else
resp_lm = "\x00" * 24
end
else # ntlm2_session
if self.is_pass_ntlm_hash?(pass)
- argntlm = {
- :ntlm_hash => [ pass.upcase()[33,65] ].pack('H32'),
- :challenge => challenge_key
+ argntlm = {
+ :ntlm_hash => [ pass.upcase()[33,65] ].pack('H32'),
+ :challenge => challenge_key
}
else
argntlm = {
- :ntlm_hash => CRYPT::ntlm_hash(pass),
- :challenge => challenge_key
+ :ntlm_hash => CRYPT::ntlm_hash(pass),
+ :challenge => challenge_key
}
end
-
+
optntlm = { :client_challenge => client_challenge}
resp_ntlm = CRYPT::ntlm2_session(argntlm,optntlm).join[24,24]
-
+
# Generate the fake LANMAN hash
resp_lm = client_challenge + ("\x00" * 16)
end
else # we use lmv1/ntlmv1
if self.is_pass_ntlm_hash?(pass)
argntlm = {
- :ntlm_hash => [ pass.upcase()[33,65] ].pack('H32'),
- :challenge => challenge_key
+ :ntlm_hash => [ pass.upcase()[33,65] ].pack('H32'),
+ :challenge => challenge_key
}
else
argntlm = {
- :ntlm_hash => CRYPT::ntlm_hash(pass),
- :challenge => challenge_key
+ :ntlm_hash => CRYPT::ntlm_hash(pass),
+ :challenge => challenge_key
}
end
-
+
resp_ntlm = CRYPT::ntlm_response(argntlm)
if send_lm
if self.is_pass_ntlm_hash?(pass)
arglm = {
:lm_hash => [ pass.upcase()[0,32] ].pack('H32'),
- :challenge => challenge_key
+ :challenge => challenge_key
}
else
arglm = {
:lm_hash => CRYPT::lm_hash(pass),
- :challenge => challenge_key
+ :challenge => challenge_key
}
end
resp_lm = CRYPT::lm_response(arglm)
else
#when windows does not send lm in ntlmv1 type response,
# it gives lm response the same value as ntlm response
resp_lm = resp_ntlm
end
end
- else #send_ntlm = false
+ else #send_ntlm = false
#lmv2
if usentlm2_session && use_ntlmv2
if self.is_pass_ntlm_hash?(pass)
arglm = {
:ntlmv2_hash => CRYPT::ntlmv2_hash(
- user,
- [ pass.upcase()[33,65] ].pack('H32'),
+ user,
+ [ pass.upcase()[33,65] ].pack('H32'),
domain,{:pass_is_hash => true}
),
- :challenge => challenge_key
+ :challenge => challenge_key
}
else
arglm = {
:ntlmv2_hash => CRYPT::ntlmv2_hash(user,pass, domain),
- :challenge => challenge_key
+ :challenge => challenge_key
}
end
optlm = { :client_challenge => client_challenge }
resp_lm = CRYPT::lmv2_response(arglm, optlm)
else
if self.is_pass_ntlm_hash?(pass)
arglm = {
:lm_hash => [ pass.upcase()[0,32] ].pack('H32'),
- :challenge => challenge_key
+ :challenge => challenge_key
}
else
arglm = {
:lm_hash => CRYPT::lm_hash(pass),
- :challenge => challenge_key
+ :challenge => challenge_key
}
end
resp_lm = CRYPT::lm_response(arglm)
end
resp_ntlm = ""
@@ -675,44 +676,44 @@
lanman_weak = false
if send_ntlm # Should be default
if usentlm2_session
if use_ntlmv2
if self.is_pass_ntlm_hash?(pass)
- user_session_key = CRYPT::ntlmv2_user_session_key(user,
+ user_session_key = CRYPT::ntlmv2_user_session_key(user,
[ pass.upcase()[33,65] ].pack('H32'),
- domain,
- challenge_key, ntlm_cli_challenge,
+ domain,
+ challenge_key, ntlm_cli_challenge,
{:pass_is_hash => true})
else
- user_session_key = CRYPT::ntlmv2_user_session_key(user, pass, domain,
+ user_session_key = CRYPT::ntlmv2_user_session_key(user, pass, domain,
challenge_key, ntlm_cli_challenge)
end
else
if self.is_pass_ntlm_hash?(pass)
- user_session_key = CRYPT::ntlm2_session_user_session_key([ pass.upcase()[33,65] ].pack('H32'),
- challenge_key,
- client_challenge,
+ user_session_key = CRYPT::ntlm2_session_user_session_key([ pass.upcase()[33,65] ].pack('H32'),
+ challenge_key,
+ client_challenge,
{:pass_is_hash => true})
else
- user_session_key = CRYPT::ntlm2_session_user_session_key(pass, challenge_key,
+ user_session_key = CRYPT::ntlm2_session_user_session_key(pass, challenge_key,
client_challenge)
end
end
else # lmv1/ntlmv1
# lanman_key may also be used without ntlm response but it is not so much used
- # so we don't care about this feature
+ # so we don't care about this feature
if send_lm && use_lanman_key
if self.is_pass_ntlm_hash?(pass)
- user_session_key = CRYPT::lanman_session_key([ pass.upcase()[0,32] ].pack('H32'),
- challenge_key,
+ user_session_key = CRYPT::lanman_session_key([ pass.upcase()[0,32] ].pack('H32'),
+ challenge_key,
{:pass_is_hash => true})
else
user_session_key = CRYPT::lanman_session_key(pass, challenge_key)
end
lanman_weak = true
-
+
else
if self.is_pass_ntlm_hash?(pass)
user_session_key = CRYPT::ntlmv1_user_session_key([ pass.upcase()[33,65] ].pack('H32'),
{:pass_is_hash => true})
else
@@ -721,42 +722,42 @@
end
end
else
if usentlm2_session && use_ntlmv2
if self.is_pass_ntlm_hash?(pass)
- user_session_key = CRYPT::lmv2_user_session_key(user, [ pass.upcase()[33,65] ].pack('H32'),
- domain,
- challenge_key, client_challenge,
+ user_session_key = CRYPT::lmv2_user_session_key(user, [ pass.upcase()[33,65] ].pack('H32'),
+ domain,
+ challenge_key, client_challenge,
{:pass_is_hash => true})
else
- user_session_key = CRYPT::lmv2_user_session_key(user, pass, domain,
+ user_session_key = CRYPT::lmv2_user_session_key(user, pass, domain,
challenge_key, client_challenge)
end
else
if self.is_pass_ntlm_hash?(pass)
- user_session_key = CRYPT::lmv1_user_session_key([ pass.upcase()[0,32] ].pack('H32'),
+ user_session_key = CRYPT::lmv1_user_session_key([ pass.upcase()[0,32] ].pack('H32'),
{:pass_is_hash => true})
else
user_session_key = CRYPT::lmv1_user_session_key(pass)
end
end
end
- user_session_key = CRYPT::make_weak_sessionkey(user_session_key,key_size, lanman_weak)
+ user_session_key = CRYPT::make_weak_sessionkey(user_session_key,key_size, lanman_weak)
# Sessionkey and encrypted session key
if key_exchange
signing_key = Rex::Text.rand_text(16)
enc_session_key = CRYPT::encrypt_sessionkey(signing_key, user_session_key)
else
signing_key = user_session_key
end
-
+
return signing_key, enc_session_key, ntlmssp_flags
-
-
+
+
end
-
+
end
end
end