Skip to content

Commit 2af8786

Browse files
committed
Updated
1 parent 0ebd5ce commit 2af8786

15 files changed

+2504
-0
lines changed

pivot_suite/ntlm_auth/U32.py

+156
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
# This file is part of 'NTLM Authorization Proxy Server' http://sourceforge.net/projects/ntlmaps/
2+
# Copyright 2001 Dmitry A. Rozmanov <dima@xenon.spb.ru>
3+
#
4+
# This library is free software: you can redistribute it and/or
5+
# modify it under the terms of the GNU Lesser General Public
6+
# License as published by the Free Software Foundation, either
7+
# version 3 of the License, or (at your option) any later version.
8+
9+
# This library is distributed in the hope that it will be useful,
10+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
# Lesser General Public License for more details.
13+
14+
# You should have received a copy of the GNU Lesser General Public
15+
# License along with this library. If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.
16+
17+
from __future__ import division
18+
import six
19+
20+
C = 0x1000000000
21+
22+
23+
def norm(n):
24+
return n & 0xFFFFFFFF
25+
26+
27+
class U32:
28+
v = 0
29+
30+
def __init__(self, value=0):
31+
if not isinstance(value, six.integer_types):
32+
value = six.byte2int(value)
33+
34+
self.v = C + norm(abs(int(value)))
35+
36+
def set(self, value=0):
37+
self.v = C + norm(abs(int(value)))
38+
39+
def __repr__(self):
40+
return hex(norm(self.v))
41+
42+
def __long__(self):
43+
return int(norm(self.v))
44+
45+
def __int__(self):
46+
return int(norm(self.v))
47+
48+
def __chr__(self):
49+
return chr(norm(self.v))
50+
51+
def __add__(self, b):
52+
r = U32()
53+
r.v = C + norm(self.v + b.v)
54+
return r
55+
56+
def __sub__(self, b):
57+
r = U32()
58+
if self.v < b.v:
59+
r.v = C + norm(0x100000000 - (b.v - self.v))
60+
else:
61+
r.v = C + norm(self.v - b.v)
62+
return r
63+
64+
def __mul__(self, b):
65+
r = U32()
66+
r.v = C + norm(self.v * b.v)
67+
return r
68+
69+
def __div__(self, b):
70+
r = U32()
71+
r.v = C + (norm(self.v) // norm(b.v))
72+
return r
73+
74+
def __truediv__(self, b):
75+
r = U32()
76+
r.v = C + (norm(self.v) / norm(b.v))
77+
return r
78+
79+
def __mod__(self, b):
80+
r = U32()
81+
r.v = C + (norm(self.v) % norm(b.v))
82+
return r
83+
84+
def __neg__(self):
85+
return U32(self.v)
86+
87+
def __pos__(self):
88+
return U32(self.v)
89+
90+
def __abs__(self):
91+
return U32(self.v)
92+
93+
def __invert__(self):
94+
r = U32()
95+
r.v = C + norm(~self.v)
96+
return r
97+
98+
def __lshift__(self, b):
99+
r = U32()
100+
r.v = C + norm(self.v << b)
101+
return r
102+
103+
def __rshift__(self, b):
104+
r = U32()
105+
r.v = C + (norm(self.v) >> b)
106+
return r
107+
108+
def __and__(self, b):
109+
r = U32()
110+
r.v = C + norm(self.v & b.v)
111+
return r
112+
113+
def __or__(self, b):
114+
r = U32()
115+
r.v = C + norm(self.v | b.v)
116+
return r
117+
118+
def __xor__(self, b):
119+
r = U32()
120+
r.v = C + norm(self.v ^ b.v)
121+
return r
122+
123+
def __not__(self):
124+
return U32(not norm(self.v))
125+
126+
def truth(self):
127+
return norm(self.v)
128+
129+
def __cmp__(self, b):
130+
if norm(self.v) > norm(b.v):
131+
return 1
132+
elif norm(self.v) < norm(b.v):
133+
return -1
134+
else:
135+
return 0
136+
137+
def __lt__(self, other):
138+
return self.v < other.v
139+
140+
def __gt__(self, other):
141+
return self.v > other.v
142+
143+
def __eq__(self, other):
144+
return self.v == other.v
145+
146+
def __le__(self, other):
147+
return self.v <= other.v
148+
149+
def __ge__(self, other):
150+
return self.v >= other.v
151+
152+
def __ne__(self, other):
153+
return self.v != other.v
154+
155+
def __nonzero__(self):
156+
return norm(self.v)

pivot_suite/ntlm_auth/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from . import ntlm, session_security
2+
3+
__all__ = ('ntlm', 'session_security')

pivot_suite/ntlm_auth/compute_hash.py

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# This library is free software: you can redistribute it and/or
2+
# modify it under the terms of the GNU Lesser General Public
3+
# License as published by the Free Software Foundation, either
4+
# version 3 of the License, or (at your option) any later version.
5+
6+
# This library is distributed in the hope that it will be useful,
7+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
8+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9+
# Lesser General Public License for more details.
10+
11+
# You should have received a copy of the GNU Lesser General Public
12+
# License along with this library. If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.
13+
14+
import binascii
15+
import hashlib
16+
import hmac
17+
import re
18+
from ntlm_auth import des
19+
20+
21+
def _lmowfv1(password, lmhash):
22+
"""
23+
[MS-NLMP] v28.0 2016-07-14
24+
25+
3.3.1 NTLM v1 Authentication
26+
Same function as LMOWFv1 in document to create a one way hash of the password. Only
27+
used in NTLMv1 auth without session security
28+
29+
:param password: The password of the user we are trying to authenticate with
30+
:return res: A Lan Manager hash of the password supplied
31+
"""
32+
33+
# fix the password length to 14 bytes
34+
if lmhash is not None:
35+
return lmhash.decode('hex')
36+
37+
password = password.upper()
38+
lm_pw = password[0:14]
39+
40+
# do hash
41+
magic_str = b"KGS!@#$%" # page 56 in [MS-NLMP v28.0]
42+
43+
res = b''
44+
dobj = des.DES(lm_pw[0:7])
45+
res = res + dobj.encrypt(magic_str)
46+
47+
dobj = des.DES(lm_pw[7:14])
48+
res = res + dobj.encrypt(magic_str)
49+
return res
50+
51+
def _ntowfv1(password, nthash):
52+
"""
53+
[MS-NLMP] v28.0 2016-07-14
54+
55+
3.3.1 NTLM v1 Authentication
56+
Same function as NTOWFv1 in document to create a one way hash of the password. Only
57+
used in NTLMv1 auth without session security
58+
59+
:param password: The password of the user we are trying to authenticate with
60+
:return digest: An NT hash of the password supplied
61+
"""
62+
if nthash is not None:
63+
return nthash.decode('hex')
64+
65+
digest = hashlib.new('md4', password.encode('utf-16le')).digest()
66+
return digest
67+
68+
def _ntowfv2(user_name, password, nthash, domain_name):
69+
"""
70+
[MS-NLMP] v28.0 2016-07-14
71+
72+
3.3.2 NTLM v2 Authentication
73+
Same function as NTOWFv2 (and LMOWFv2) in document to create a one way hash of the password.
74+
This combines some extra security features over the v1 calculations used in NTLMv2 auth.
75+
76+
:param user_name: The user name of the user we are trying to authenticate with
77+
:param password: The password of the user we are trying to authenticate with
78+
:param domain_name: The domain name of the user account we are authenticated with
79+
:return digest: An NT hash of the parameters supplied
80+
"""
81+
digest = _ntowfv1(password, nthash)
82+
digest = hmac.new(digest, (user_name.upper() + domain_name).encode('utf-16le')).digest()
83+
84+
85+
return digest

pivot_suite/ntlm_auth/compute_keys.py

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# This library is free software: you can redistribute it and/or
2+
# modify it under the terms of the GNU Lesser General Public
3+
# License as published by the Free Software Foundation, either
4+
# version 3 of the License, or (at your option) any later version.
5+
6+
# This library is distributed in the hope that it will be useful,
7+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
8+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9+
# Lesser General Public License for more details.
10+
11+
# You should have received a copy of the GNU Lesser General Public
12+
# License along with this library. If not, see <http://www.gnu.org/licenses/> or <http://www.gnu.org/licenses/lgpl.txt>.
13+
14+
import binascii
15+
import hashlib
16+
import hmac
17+
from ntlm_auth import des
18+
from ntlm_auth.constants import NegotiateFlags
19+
20+
def _get_exchange_key_ntlm_v1(negotiate_flags, session_base_key, server_challenge, lm_challenge_response, lm_hash):
21+
"""
22+
[MS-NLMP] v28.0 2016-07-14
23+
24+
4.3.5.1 KXKEY
25+
Calculates the Key Exchange Key for NTLMv1 authentication. Used for signing and sealing messages
26+
27+
@param negotiate_flags:
28+
@param session_base_key: A session key calculated from the user password challenge
29+
@param server_challenge: A random 8-byte response generated by the server in the CHALLENGE_MESSAGE
30+
@param lm_challenge_response: The LmChallengeResponse value computed in ComputeResponse
31+
@param lm_hash: The LMOWF computed in Compute Response
32+
@return key_exchange_key: The Key Exchange Key (KXKEY) used to sign and seal messages and compute the ExportedSessionKey
33+
"""
34+
if negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
35+
key_exchange_key = hmac.new(session_base_key, server_challenge + lm_challenge_response[:8]).digest()
36+
elif negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_LM_KEY:
37+
des_handler = des.DES(lm_hash[:7])
38+
first_des = des_handler.encrypt(lm_challenge_response[:8])
39+
des_handler = des.DES(lm_hash[7:8] + binascii.unhexlify('bdbdbdbdbdbdbd'))
40+
second_des = des_handler.encrypt(lm_challenge_response[:8])
41+
42+
key_exchange_key = first_des + second_des
43+
elif negotiate_flags & NegotiateFlags.NTLMSSP_REQUEST_NON_NT_SESSION_KEY:
44+
key_exchange_key = lm_hash[:8] + b'\0' * 8
45+
else:
46+
key_exchange_key = session_base_key
47+
48+
return key_exchange_key
49+
50+
def _get_exchange_key_ntlm_v2(session_base_key):
51+
"""
52+
[MS-NLMP] v28.0 2016-07-14
53+
54+
4.3.5.1 KXKEY
55+
Calculates the Key Exchange Key for NTLMv2 authentication. Used for signing and sealing messages.
56+
According to docs, 'If NTLM v2 is used, KeyExchangeKey MUST be set to the given 128-bit SessionBaseKey
57+
58+
@param session_base_key: A session key calculated from the user password challenge
59+
@return key_exchange_key: The Key Exchange Key (KXKEY) used to sign and seal messages
60+
"""
61+
return session_base_key
62+
63+
def get_sign_key(exported_session_key, magic_constant):
64+
"""
65+
3.4.5.2 SIGNKEY
66+
67+
@param exported_session_key: A 128-bit session key used to derive signing and sealing keys
68+
@param magic_constant: A constant value set in the MS-NLMP documentation (constants.SignSealConstants)
69+
@return sign_key: Key used to sign messages
70+
"""
71+
72+
sign_key = hashlib.md5(exported_session_key + magic_constant).digest()
73+
74+
return sign_key
75+
76+
def get_seal_key(negotiate_flags, exported_session_key, magic_constant):
77+
"""
78+
3.4.5.3. SEALKEY
79+
Main method to use to calculate the seal_key used to seal (encrypt) messages. This will determine
80+
the correct method below to use based on the compatibility flags set and should be called instead
81+
of the others
82+
83+
@param exported_session_key: A 128-bit session key used to derive signing and sealing keys
84+
@param negotiate_flags: The negotiate_flags structure sent by the server
85+
@param magic_constant: A constant value set in the MS-NLMP documentation (constants.SignSealConstants)
86+
@return seal_key: Key used to seal messages
87+
"""
88+
89+
if negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
90+
seal_key = _get_seal_key_ntlm2(negotiate_flags, exported_session_key, magic_constant)
91+
elif negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_LM_KEY:
92+
seal_key = _get_seal_key_ntlm1(negotiate_flags, exported_session_key)
93+
else:
94+
seal_key = exported_session_key
95+
96+
return seal_key
97+
98+
def _get_seal_key_ntlm1(negotiate_flags, exported_session_key):
99+
"""
100+
3.4.5.3 SEALKEY
101+
Calculates the seal_key used to seal (encrypt) messages. This for authentication where
102+
NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY has not been negotiated. Will weaken the keys
103+
if NTLMSSP_NEGOTIATE_56 is not negotiated it will default to the 40-bit key
104+
105+
@param negotiate_flags: The negotiate_flags structure sent by the server
106+
@param exported_session_key: A 128-bit session key used to derive signing and sealing keys
107+
@return seal_key: Key used to seal messages
108+
"""
109+
if negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_56:
110+
seal_key = exported_session_key[:7] + binascii.unhexlify('a0')
111+
else:
112+
seal_key = exported_session_key[:5] + binascii.unhexlify('e538b0')
113+
114+
return seal_key
115+
116+
def _get_seal_key_ntlm2(negotiate_flags, exported_session_key, magic_constant):
117+
"""
118+
3.4.5.3 SEALKEY
119+
Calculates the seal_key used to seal (encrypt) messages. This for authentication where
120+
NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY has been negotiated. Will weaken the keys
121+
if NTLMSSP_NEGOTIATE_128 is not negotiated, will try NEGOTIATE_56 and then will default
122+
to the 40-bit key
123+
124+
@param negotiate_flags: The negotiate_flags structure sent by the server
125+
@param exported_session_key: A 128-bit session key used to derive signing and sealing keys
126+
@param magic_constant: A constant value set in the MS-NLMP documentation (constants.SignSealConstants)
127+
@return seal_key: Key used to seal messages
128+
"""
129+
if negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_128:
130+
seal_key = exported_session_key
131+
elif negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_56:
132+
seal_key = exported_session_key[:7]
133+
else:
134+
seal_key = exported_session_key[:5]
135+
136+
seal_key = hashlib.md5(seal_key + magic_constant).digest()
137+
138+
return seal_key

0 commit comments

Comments
 (0)