44from functools import wraps
55from time import sleep
66from ipaddress import ip_address
7+ from dns import resolver , rdatatype
78from socket import AF_UNSPEC , SOCK_DGRAM , IPPROTO_IP , AI_CANONNAME , getaddrinfo
89
910from nxc .config import pwned_label
2223user_failed_logins = {}
2324
2425
25- def gethost_addrinfo (hostname ):
26- is_ipv6 = False
27- is_link_local_ipv6 = False
26+ def get_host_addr_info (target , force_ipv6 , dns_server , dns_tcp , dns_timeout ):
27+ result = {
28+ "host" : "" ,
29+ "is_ipv6" : False ,
30+ "is_link_local_ipv6" : False
31+ }
2832 address_info = {"AF_INET6" : "" , "AF_INET" : "" }
2933
30- for res in getaddrinfo (hostname , None , AF_UNSPEC , SOCK_DGRAM , IPPROTO_IP , AI_CANONNAME ):
31- af , _ , _ , canonname , sa = res
32- address_info [af .name ] = sa [0 ]
34+ try :
35+ if ip_address (target ).version == 4 :
36+ address_info ["AF_INET" ] = target
37+ else :
38+ address_info ["AF_INET6" ] = target
39+ except Exception :
40+ # If the target is not an IP address, we need to resolve it
41+ if not (dns_server or dns_tcp ):
42+ for res in getaddrinfo (target , None , AF_UNSPEC , SOCK_DGRAM , IPPROTO_IP , AI_CANONNAME ):
43+ af , _ , _ , canonname , sa = res
44+ address_info [af .name ] = sa [0 ]
45+
46+ if address_info ["AF_INET6" ] and ip_address (address_info ["AF_INET6" ]).is_link_local :
47+ address_info ["AF_INET6" ] = canonname
48+ result ["is_link_local_ipv6" ] = True
49+ else :
50+ dnsresolver = resolver .Resolver ()
51+ dnsresolver .timeout = dns_timeout
52+ dnsresolver .lifetime = dns_timeout
53+
54+ if dns_server :
55+ dnsresolver .nameservers = [dns_server ]
56+
57+ try :
58+ answers_ipv4 = dnsresolver .resolve (target , rdatatype .A , raise_on_no_answer = False , tcp = dns_tcp )
59+ address_info ["AF_INET" ] = answers_ipv4 [0 ].address
60+ except Exception :
61+ pass
62+
63+ try :
64+ answers_ipv6 = dnsresolver .resolve (target , rdatatype .AAAA , raise_on_no_answer = False , tcp = dns_tcp )
65+ address_info ["AF_INET6" ] = answers_ipv6 [0 ].address
66+
67+ if address_info ["AF_INET6" ] and ip_address (address_info ["AF_INET6" ]).is_link_local :
68+ result ["is_link_local_ipv6" ] = True
69+ except Exception :
70+ pass
71+
72+ if not (address_info ["AF_INET" ] or address_info ["AF_INET6" ]):
73+ raise Exception (f"The DNS query name does not exist: { target } " )
3374
3475 # IPv4 preferred
35- if address_info ["AF_INET" ]:
36- host = address_info ["AF_INET" ]
76+ if address_info ["AF_INET" ] and not force_ipv6 :
77+ result [ " host" ] = address_info ["AF_INET" ]
3778 else :
38- is_ipv6 = True
39- host , is_link_local_ipv6 = ( canonname , True ) if ip_address ( address_info [ "AF_INET6" ]). is_link_local else ( address_info ["AF_INET6" ], False )
79+ result [ " is_ipv6" ] = True
80+ result [ "host" ] = address_info ["AF_INET6" ]
4081
41- return host , is_ipv6 , is_link_local_ipv6
82+ return result
4283
4384
4485def requires_admin (func ):
@@ -50,7 +91,7 @@ def _decorator(self, *args, **kwargs):
5091 return wraps (func )(_decorator )
5192
5293
53- def dcom_FirewallChecker (iInterface , timeout ):
94+ def dcom_FirewallChecker (iInterface , remoteHost , timeout ):
5495 stringBindings = iInterface .get_cinstance ().get_string_bindings ()
5596 for strBinding in stringBindings :
5697 if strBinding ["wTowerId" ] == 7 :
@@ -70,6 +111,7 @@ def dcom_FirewallChecker(iInterface, timeout):
70111 return True , None
71112 try :
72113 rpctransport = transport .DCERPCTransportFactory (stringBinding )
114+ rpctransport .setRemoteHost (remoteHost )
73115 rpctransport .set_connect_timeout (timeout )
74116 rpctransport .connect ()
75117 rpctransport .disconnect ()
@@ -81,45 +123,67 @@ def dcom_FirewallChecker(iInterface, timeout):
81123
82124
83125class connection :
84- def __init__ (self , args , db , host ):
85- self .domain = None
126+ def __init__ (self , args , db , target ):
86127 self .args = args
87128 self .db = db
88- self .hostname = host
89- self .port = self .args .port
129+ self .logger = nxc_logger
90130 self .conn = None
91- self .admin_privs = False
131+
132+ # Authentication info
92133 self .password = ""
93134 self .username = ""
94135 self .kerberos = bool (self .args .kerberos or self .args .use_kcache or self .args .aesKey )
95136 self .aesKey = None if not self .args .aesKey else self .args .aesKey [0 ]
96- self .kdcHost = None if not self .args .kdcHost else self .args .kdcHost
97137 self .use_kcache = None if not self .args .use_kcache else self .args .use_kcache
138+ self .admin_privs = False
98139 self .failed_logins = 0
140+
141+ # Network info
142+ self .domain = None
143+ self .host = None # IP address of the target. If kerberos this is the hostname
144+ self .hostname = target # Target info supplied by the user, may be an IP address or a hostname
145+ self .remoteName = target # hostname + domain, defaults to target if domain could not be resolved/not specified
146+ self .kdcHost = self .args .kdcHost
147+ self .port = self .args .port
99148 self .local_ip = None
100- self .logger = nxc_logger
101149
102- try :
103- self .host , self .is_ipv6 , self .is_link_local_ipv6 = gethost_addrinfo (self .hostname )
104- if self .args .kerberos :
105- self .host = self .hostname
106- self .logger .info (f"Socket info: host={ self .host } , hostname={ self .hostname } , kerberos={ self .kerberos } , ipv6={ self .is_ipv6 } , link-local ipv6={ self .is_link_local_ipv6 } " )
107- except Exception as e :
108- self .logger .info (f"Error resolving hostname { self .hostname } : { e } " )
150+ # DNS resolution
151+ dns_result = self .resolver (target )
152+ if dns_result :
153+ self .host , self .is_ipv6 , self .is_link_local_ipv6 = dns_result ["host" ], dns_result ["is_ipv6" ], dns_result ["is_link_local_ipv6" ]
154+ else :
109155 return
110156
157+ if self .args .kerberos :
158+ self .host = self .hostname
159+
160+ self .logger .info (f"Socket info: host={ self .host } , hostname={ self .hostname } , kerberos={ self .kerberos } , ipv6={ self .is_ipv6 } , link-local ipv6={ self .is_link_local_ipv6 } " )
161+
111162 try :
112163 self .proto_flow ()
113164 except Exception as e :
114165 if "ERROR_DEPENDENT_SERVICES_RUNNING" in str (e ):
115- self .logger .error (f"Exception while calling proto_flow() on target { self . host } : { e } " )
166+ self .logger .error (f"Exception while calling proto_flow() on target { target } : { e } " )
116167 else :
117- self .logger .exception (f"Exception while calling proto_flow() on target { self . host } : { e } " )
168+ self .logger .exception (f"Exception while calling proto_flow() on target { target } : { e } " )
118169 finally :
119- self .logger .debug (f"Closing connection to: { host } " )
170+ self .logger .debug (f"Closing connection to: { target } " )
120171 with contextlib .suppress (Exception ):
121172 self .conn .close ()
122173
174+ def resolver (self , target ):
175+ try :
176+ return get_host_addr_info (
177+ target = target ,
178+ force_ipv6 = self .args .force_ipv6 ,
179+ dns_server = self .args .dns_server ,
180+ dns_tcp = self .args .dns_tcp ,
181+ dns_timeout = self .args .dns_timeout
182+ )
183+ except Exception as e :
184+ self .logger .info (f"Error resolving hostname { target } : { e } " )
185+ return None
186+
123187 @staticmethod
124188 def proto_args (std_parser , module_parser ):
125189 return
0 commit comments