@@ -1180,8 +1180,8 @@ class NTLMSSP(SSP):
11801180
11811181 Server-only arguments:
11821182
1183- :param DOMAIN_NB_NAME : the domain Netbios name (default: DOMAIN )
1184- :param DOMAIN_FQDN : the domain FQDN (default: <domain_nb_name>.local )
1183+ :param DOMAIN_FQDN : the domain FQDN (default: domain.local )
1184+ :param DOMAIN_NB_NAME : the domain Netbios name (default: strip DOMAIN_FQDN )
11851185 :param COMPUTER_NB_NAME: the server Netbios name (default: SRV)
11861186 :param COMPUTER_FQDN: the server FQDN
11871187 (default: <computer_nb_name>.<domain_fqdn>)
@@ -1248,9 +1248,9 @@ def __init__(
12481248 PASSWORD = None ,
12491249 USE_MIC = True ,
12501250 NTLM_VALUES = {},
1251- DOMAIN_NB_NAME = "DOMAIN" ,
12521251 DOMAIN_FQDN = None ,
1253- COMPUTER_NB_NAME = "SRV" ,
1252+ DOMAIN_NB_NAME = None ,
1253+ COMPUTER_NB_NAME = None ,
12541254 COMPUTER_FQDN = None ,
12551255 IDENTITIES = None ,
12561256 DO_NOT_CHECK_LOGIN = False ,
@@ -1263,9 +1263,21 @@ def __init__(
12631263 self .HASHNT = HASHNT
12641264 self .USE_MIC = USE_MIC
12651265 self .NTLM_VALUES = NTLM_VALUES
1266- self .DOMAIN_NB_NAME = DOMAIN_NB_NAME
1267- self .DOMAIN_FQDN = DOMAIN_FQDN or (self .DOMAIN_NB_NAME .lower () + ".local" )
1268- self .COMPUTER_NB_NAME = COMPUTER_NB_NAME
1266+ if DOMAIN_FQDN is None and UPN is not None :
1267+ from scapy .layers .kerberos import _parse_upn
1268+
1269+ self .DOMAIN_FQDN = _parse_upn (UPN )[1 ]
1270+ else :
1271+ self .DOMAIN_FQDN = DOMAIN_FQDN or "domain.local"
1272+ self .DOMAIN_NB_NAME = (
1273+ DOMAIN_NB_NAME or self .DOMAIN_FQDN .split ("." )[0 ].upper ()[:15 ]
1274+ )
1275+ if COMPUTER_NB_NAME is None and UPN is not None :
1276+ from scapy .layers .kerberos import _parse_upn
1277+
1278+ self .COMPUTER_NB_NAME = _parse_upn (UPN )[0 ]
1279+ else :
1280+ self .COMPUTER_NB_NAME = COMPUTER_NB_NAME or "SRV"
12691281 self .COMPUTER_FQDN = COMPUTER_FQDN or (
12701282 self .COMPUTER_NB_NAME .lower () + "." + self .DOMAIN_FQDN
12711283 )
@@ -1843,7 +1855,8 @@ def _getSessionBaseKey(self, Context, auth_tok):
18431855 return NTLMv2_ComputeSessionBaseKey (
18441856 ResponseKeyNT , auth_tok .NtChallengeResponse .NTProofStr
18451857 )
1846- log_runtime .debug ("NTLMSSP: Bad credentials for %s" % username )
1858+ elif self .IDENTITIES :
1859+ log_runtime .debug ("NTLMSSP: Bad credentials for %s" % username )
18471860 return None
18481861
18491862 def _checkLogin (self , Context , auth_tok ):
@@ -1872,3 +1885,173 @@ def _checkLogin(self, Context, auth_tok):
18721885 if NTProofStr == auth_tok .NtChallengeResponse .NTProofStr :
18731886 return True
18741887 return False
1888+
1889+
1890+ class NTLMSSP_DOMAIN (NTLMSSP ):
1891+ """
1892+ A variant of the NTLMSSP to be used in server mode that gets the session
1893+ keys from the domain using a Netlogon channel.
1894+
1895+ This has the same arguments as NTLMSSP, but supports the following in server
1896+ mode:
1897+
1898+ :param UPN: the UPN of the machine account to login for Netlogon.
1899+ :param HASHNT: the HASHNT of the machine account to use for Netlogon.
1900+ :param PASSWORD: the PASSWORD of the machine acconut to use for Netlogon.
1901+ :param DC_IP: (optional) specify the IP of the DC.
1902+
1903+ Examples::
1904+
1905+ >>> mySSP = NTLMSSP_DOMAIN(
1906+ ... UPN="Server1@domain.local",
1907+ ... HASHNT=bytes.fromhex("8846f7eaee8fb117ad06bdd830b7586c"),
1908+ ... )
1909+ """
1910+
1911+ def __init__ (self , UPN , * args , timeout = 3 , ssp = None , ** kwargs ):
1912+ from scapy .layers .kerberos import KerberosSSP
1913+
1914+ # UPN is mandatory
1915+ kwargs ["UPN" ] = UPN
1916+
1917+ # Either PASSWORD or HASHNT or ssp
1918+ if "HASHNT" not in kwargs and "PASSWORD" not in kwargs and ssp is None :
1919+ raise ValueError (
1920+ "Must specify either 'HASHNT', 'PASSWORD' or "
1921+ "provide a ssp=KerberosSSP()"
1922+ )
1923+ elif ssp is not None and not isinstance (ssp , KerberosSSP ):
1924+ raise ValueError ("'ssp' can only be None or a KerberosSSP !" )
1925+
1926+ # Call parent
1927+ super (NTLMSSP_DOMAIN , self ).__init__ (
1928+ * args ,
1929+ ** kwargs ,
1930+ )
1931+
1932+ # Treat specific parameters
1933+ self .DC_IP = kwargs .pop ("DC_IP" , None )
1934+ if self .DC_IP is None :
1935+ # Get DC_IP from dclocator
1936+ from scapy .layers .ldap import dclocator
1937+
1938+ self .DC_IP = dclocator (
1939+ self .DOMAIN_FQDN ,
1940+ timeout = timeout ,
1941+ debug = kwargs .get ("debug" , 0 ),
1942+ ).ip
1943+
1944+ # If logging in via Kerberos
1945+ self .ssp = ssp
1946+
1947+ def _getSessionBaseKey (self , Context , ntlm ):
1948+ """
1949+ Return the Session Key by asking the DC.
1950+ """
1951+ # No user / no domain: skip.
1952+ if not ntlm .UserNameLen or not ntlm .DomainNameLen :
1953+ return super (NTLMSSP_DOMAIN , self )._getSessionBaseKey (Context , ntlm )
1954+
1955+ # Import RPC stuff
1956+ from scapy .layers .dcerpc import NDRUnion
1957+ from scapy .layers .msrpce .msnrpc import (
1958+ NetlogonClient ,
1959+ NETLOGON_SECURE_CHANNEL_METHOD ,
1960+ )
1961+ from scapy .layers .msrpce .raw .ms_nrpc import (
1962+ NetrLogonSamLogonWithFlags_Request ,
1963+ PNETLOGON_NETWORK_INFO ,
1964+ PNETLOGON_AUTHENTICATOR ,
1965+ NETLOGON_LOGON_IDENTITY_INFO ,
1966+ RPC_UNICODE_STRING ,
1967+ STRING ,
1968+ )
1969+
1970+ # Create NetlogonClient with PRIVACY
1971+ client = NetlogonClient ()
1972+ client .connect_and_bind (self .DC_IP )
1973+
1974+ # Establish the Netlogon secure channel (this will bind)
1975+ try :
1976+ if self .ssp is None :
1977+ # Login via classic NetlogonSSP
1978+ client .establish_secure_channel (
1979+ mode = NETLOGON_SECURE_CHANNEL_METHOD .NetrServerAuthenticate3 ,
1980+ computername = self .COMPUTER_NB_NAME ,
1981+ domainname = self .DOMAIN_NB_NAME ,
1982+ HashNt = self .HASHNT ,
1983+ )
1984+ else :
1985+ # Login via KerberosSSP (Windows 2025)
1986+ # TODO
1987+ client .establish_secure_channel (
1988+ mode = NETLOGON_SECURE_CHANNEL_METHOD .NetrServerAuthenticateKerberos ,
1989+ )
1990+ except ValueError :
1991+ log_runtime .warning (
1992+ "Couldn't establish the Netlogon secure channel. "
1993+ "Check the credentials for '%s' !" % self .COMPUTER_NB_NAME
1994+ )
1995+ return super (NTLMSSP_DOMAIN , self )._getSessionBaseKey (Context , ntlm )
1996+
1997+ # Request validation of the NTLM request
1998+ req = NetrLogonSamLogonWithFlags_Request (
1999+ LogonServer = "" ,
2000+ ComputerName = self .COMPUTER_NB_NAME ,
2001+ Authenticator = client .create_authenticator (),
2002+ ReturnAuthenticator = PNETLOGON_AUTHENTICATOR (),
2003+ LogonLevel = 6 , # NetlogonNetworkTransitiveInformation
2004+ LogonInformation = NDRUnion (
2005+ tag = 6 ,
2006+ value = PNETLOGON_NETWORK_INFO (
2007+ Identity = NETLOGON_LOGON_IDENTITY_INFO (
2008+ LogonDomainName = RPC_UNICODE_STRING (
2009+ Buffer = ntlm .DomainName ,
2010+ ),
2011+ ParameterControl = 0x00002AE0 ,
2012+ UserName = RPC_UNICODE_STRING (
2013+ Buffer = ntlm .UserName ,
2014+ ),
2015+ Workstation = RPC_UNICODE_STRING (
2016+ Buffer = ntlm .Workstation ,
2017+ ),
2018+ ),
2019+ LmChallenge = Context .chall_tok .ServerChallenge ,
2020+ NtChallengeResponse = STRING (
2021+ Buffer = bytes (ntlm .NtChallengeResponse ),
2022+ ),
2023+ LmChallengeResponse = STRING (
2024+ Buffer = bytes (ntlm .LmChallengeResponse ),
2025+ ),
2026+ ),
2027+ ),
2028+ ValidationLevel = 6 ,
2029+ ExtraFlags = 0 ,
2030+ ndr64 = client .ndr64 ,
2031+ )
2032+
2033+ # Get response
2034+ resp = client .sr1_req (req )
2035+ if resp and resp .status == 0 :
2036+ # Success
2037+
2038+ # Validate DC authenticator
2039+ client .validate_authenticator (resp .ReturnAuthenticator .value )
2040+
2041+ # Get and return the SessionKey
2042+ UserSessionKey = resp .ValidationInformation .value .value .UserSessionKey
2043+ return bytes (UserSessionKey )
2044+ else :
2045+ # Failed
2046+ print (
2047+ conf .color_theme .fail (
2048+ "! %s" % STATUS_ERREF .get (resp .status , "Failure !" )
2049+ )
2050+ )
2051+ if resp .status not in STATUS_ERREF :
2052+ resp .show ()
2053+ return super (NTLMSSP_DOMAIN , self )._getSessionBaseKey (Context , ntlm )
2054+
2055+ def _checkLogin (self , Context , auth_tok ):
2056+ # Always OK if we got the session key
2057+ return True
0 commit comments