|
55 | 55 | from nxc.helpers.logger import highlight |
56 | 56 | from nxc.helpers.bloodhound import add_user_bh |
57 | 57 | from nxc.helpers.powershell import create_ps_command |
| 58 | +from nxc.helpers.misc import detect_if_ip |
| 59 | +from nxc.protocols.ldap.resolution import LDAPResolution |
58 | 60 |
|
59 | 61 | from dploot.triage.vaults import VaultsTriage |
60 | 62 | from dploot.triage.browser import BrowserTriage, LoginData, GoogleRefreshToken, Cookie |
@@ -125,6 +127,7 @@ def __init__(self, args, db, host): |
125 | 127 | self.no_ntlm = False |
126 | 128 | self.protocol = "SMB" |
127 | 129 | self.is_guest = None |
| 130 | + self.isdc = False |
128 | 131 |
|
129 | 132 | connection.__init__(self, args, db, host) |
130 | 133 |
|
@@ -185,20 +188,30 @@ def enum_host_info(self): |
185 | 188 | if not self.targetDomain: # Not sure if that can even happen but now we are safe |
186 | 189 | self.targetDomain = self.hostname |
187 | 190 | else: |
188 | | - # If we can't authenticate with NTLM and the target is supplied as a FQDN we must parse it |
189 | 191 | try: |
190 | | - import socket |
191 | | - socket.inet_aton(self.host) |
192 | | - self.logger.debug("NTLM authentication not available! Authentication will fail without a valid hostname and domain name") |
193 | | - self.hostname = self.host |
194 | | - self.targetDomain = self.host |
| 192 | + # If we know the host is a DC we can still get the hostname over LDAP if NTLM is not available |
| 193 | + if self.is_host_dc() and detect_if_ip(self.host): |
| 194 | + self.hostname, self.domain = LDAPResolution(self.host).get_resolution() |
| 195 | + self.targetDomain = self.domain |
| 196 | + # If we can't authenticate with NTLM and the target is supplied as a FQDN we must parse it |
| 197 | + else: |
| 198 | + # Check if the host is a valid IP address, if not we parse the FQDN in the Exception |
| 199 | + import socket |
| 200 | + socket.inet_aton(self.host) |
| 201 | + self.logger.debug("NTLM authentication not available! Authentication will fail without a valid hostname and domain name") |
| 202 | + self.hostname = self.host |
| 203 | + self.targetDomain = self.host |
195 | 204 | except OSError: |
196 | 205 | if self.host.count(".") >= 1: |
197 | 206 | self.hostname = self.host.split(".")[0] |
198 | 207 | self.targetDomain = ".".join(self.host.split(".")[1:]) |
199 | 208 | else: |
200 | 209 | self.hostname = self.host |
201 | 210 | self.targetDomain = self.host |
| 211 | + except Exception as e: |
| 212 | + self.logger.debug(f"Error getting hostname from LDAP: {e}") |
| 213 | + self.hostname = self.host |
| 214 | + self.targetDomain = self.host |
202 | 215 |
|
203 | 216 | if self.args.domain: |
204 | 217 | self.domain = self.args.domain |
@@ -283,21 +296,12 @@ def print_host_info(self): |
283 | 296 | self.logger.display(f"{self.server_os}{f' x{self.os_arch}' if self.os_arch else ''} (name:{self.hostname}) (domain:{self.targetDomain}) ({signing}) ({smbv1}) {ntlm}") |
284 | 297 |
|
285 | 298 | if self.args.generate_hosts_file or self.args.generate_krb5_file: |
286 | | - from impacket.dcerpc.v5 import nrpc, epm |
287 | | - self.logger.debug("Performing authentication attempts...") |
288 | | - isdc = False |
289 | | - try: |
290 | | - epm.hept_map(self.host, nrpc.MSRPC_UUID_NRPC, protocol="ncacn_ip_tcp") |
291 | | - isdc = True |
292 | | - except DCERPCException: |
293 | | - self.logger.debug("Error while connecting to host: DCERPCException, which means this is probably not a DC!") |
294 | | - |
295 | 299 | if self.args.generate_hosts_file: |
296 | 300 | with open(self.args.generate_hosts_file, "a+") as host_file: |
297 | | - dc_part = f" {self.targetDomain}" if isdc else "" |
| 301 | + dc_part = f" {self.targetDomain}" if self.isdc else "" |
298 | 302 | host_file.write(f"{self.host} {self.hostname}.{self.targetDomain}{dc_part} {self.hostname}\n") |
299 | | - self.logger.debug(f"{self.host} {self.hostname}.{self.targetDomain}{dc_part} {self.hostname}") |
300 | | - elif self.args.generate_krb5_file and isdc: |
| 303 | + self.logger.debug(f"Line added to {self.args.generate_hosts_file} {self.host} {self.hostname}.{self.targetDomain}{dc_part} {self.hostname}") |
| 304 | + elif self.args.generate_krb5_file and self.isdc: |
301 | 305 | with open(self.args.generate_krb5_file, "w+") as host_file: |
302 | 306 | data = f""" |
303 | 307 | [libdefaults] |
@@ -658,6 +662,18 @@ def generate_tgt(self): |
658 | 662 | except Exception as e: |
659 | 663 | self.logger.fail(f"Failed to get TGT: {e}") |
660 | 664 |
|
| 665 | + def is_host_dc(self): |
| 666 | + from impacket.dcerpc.v5 import nrpc, epm |
| 667 | + self.logger.debug("Performing authentication attempts...") |
| 668 | + try: |
| 669 | + epm.hept_map(self.host, nrpc.MSRPC_UUID_NRPC, protocol="ncacn_ip_tcp") |
| 670 | + self.isdc = True |
| 671 | + return True |
| 672 | + except DCERPCException: |
| 673 | + self.logger.debug("Error while connecting to host: DCERPCException, which means this is probably not a DC!") |
| 674 | + self.isdc = False |
| 675 | + return False |
| 676 | + |
661 | 677 | @requires_admin |
662 | 678 | def execute(self, payload=None, get_output=False, methods=None) -> str: |
663 | 679 | """ |
|
0 commit comments