Skip to content

Commit

Permalink
Merge pull request #63 from XiaoliChan/connection-miss-port
Browse files Browse the repository at this point in the history
[connection.py] Improvement
  • Loading branch information
Marshall-Hallenbeck authored Nov 3, 2023
2 parents 5e247be + b4bd5d6 commit 9fc67da
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 47 deletions.
34 changes: 20 additions & 14 deletions nxc/connection.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import random
import socket
from socket import AF_INET, AF_INET6, SOCK_DGRAM, IPPROTO_IP, AI_CANONNAME
from socket import getaddrinfo
from os.path import isfile
from threading import BoundedSemaphore
from functools import wraps
from time import sleep
from ipaddress import ip_address
from socket import AF_UNSPEC, SOCK_DGRAM, IPPROTO_IP, AI_CANONNAME, getaddrinfo

from nxc.config import pwned_label
from nxc.helpers.logger import highlight
Expand All @@ -22,15 +20,22 @@


def gethost_addrinfo(hostname):
try:
for res in getaddrinfo(hostname, None, AF_INET6, SOCK_DGRAM, IPPROTO_IP, AI_CANONNAME):
af, socktype, proto, canonname, sa = res
host = canonname if ip_address(sa[0]).is_link_local else sa[0]
except socket.gaierror:
for res in getaddrinfo(hostname, None, AF_INET, SOCK_DGRAM, IPPROTO_IP, AI_CANONNAME):
af, socktype, proto, canonname, sa = res
host = sa[0] if sa[0] else canonname
return host
is_ipv6 = False
is_link_local_ipv6 = False
address_info = {"AF_INET6": "", "AF_INET": ""}

for res in getaddrinfo(hostname, None, AF_UNSPEC, SOCK_DGRAM, IPPROTO_IP, AI_CANONNAME):
af, _, _, canonname, sa = res
address_info[af.name] = sa[0]

# IPv4 preferred
if address_info["AF_INET"]:
host = address_info["AF_INET"]
else:
is_ipv6 = True
host, is_link_local_ipv6 = (canonname, True) if ip_address(address_info["AF_INET6"]).is_link_local else (address_info["AF_INET6"], False)

return host, is_ipv6, is_link_local_ipv6


def requires_admin(func):
Expand Down Expand Up @@ -78,6 +83,7 @@ def __init__(self, args, db, host):
self.args = args
self.db = db
self.hostname = host
self.port = self.args.port
self.conn = None
self.admin_privs = False
self.password = ""
Expand All @@ -91,10 +97,10 @@ def __init__(self, args, db, host):
self.logger = nxc_logger

try:
self.host = gethost_addrinfo(self.hostname)
self.host, self.is_ipv6, self.is_link_local_ipv6 = gethost_addrinfo(self.hostname)
if self.args.kerberos:
self.host = self.hostname
self.logger.info(f"Socket info: host={self.host}, hostname={self.hostname}, kerberos={ 'True' if self.args.kerberos else 'False' }")
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}")
except Exception as e:
self.logger.info(f"Error resolving hostname {self.hostname}: {e}")
return
Expand Down
8 changes: 4 additions & 4 deletions nxc/protocols/ftp.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def proto_logger(self):
extra={
"protocol": "FTP",
"host": self.host,
"port": self.args.port,
"port": self.port,
"hostname": self.hostname,
}
)
Expand All @@ -41,7 +41,7 @@ def print_host_info(self):
def create_conn_obj(self):
self.conn = FTP()
try:
self.conn.connect(host=self.host, port=self.args.port)
self.conn.connect(host=self.host, port=self.port)
except Exception as e:
self.logger.debug(f"Error connecting to FTP host: {e}")
return False
Expand All @@ -61,8 +61,8 @@ def plaintext_login(self, username, password):

# 230 is "User logged in, proceed" response, ftplib raises an exception on failed login
if "230" in resp:
self.logger.debug(f"Host: {self.host} Port: {self.args.port}")
self.db.add_host(self.host, self.args.port, self.remote_version)
self.logger.debug(f"Host: {self.host} Port: {self.port}")
self.db.add_host(self.host, self.port, self.remote_version)

cred_id = self.db.add_credential(username, password)

Expand Down
18 changes: 9 additions & 9 deletions nxc/protocols/ldap.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,14 @@ def proto_logger(self):
extra={
"protocol": "LDAP",
"host": self.host,
"port": self.args.port,
"port": self.port,
"hostname": self.hostname,
}
)

def get_ldap_info(self, host):
try:
proto = "ldaps" if (self.args.gmsa or self.args.port == 636) else "ldap"
proto = "ldaps" if (self.args.gmsa or self.port == 636) else "ldap"
ldap_url = f"{proto}://{host}"
self.logger.info(f"Connecting to {ldap_url} with no baseDN")
try:
Expand Down Expand Up @@ -349,7 +349,7 @@ def kerberos_login(

try:
# Connect to LDAP
proto = "ldaps" if (self.args.gmsa or self.args.port == 636) else "ldap"
proto = "ldaps" if (self.args.gmsa or self.port == 636) else "ldap"
ldap_url = f"{proto}://{self.target}"
self.logger.info(f"Connecting to {ldap_url} - {self.baseDN} [1]")
self.ldapConnection = ldap_impacket.LDAPConnection(ldap_url, self.baseDN)
Expand All @@ -374,7 +374,7 @@ def kerberos_login(


self.logger.extra["protocol"] = "LDAP"
self.logger.extra["port"] = "636" if (self.args.gmsa or self.args.port == 636) else "389"
self.logger.extra["port"] = "636" if (self.args.gmsa or self.port == 636) else "389"
self.logger.success(out)

if not self.args.local_auth:
Expand Down Expand Up @@ -472,7 +472,7 @@ def plaintext_login(self, domain, username, password):

try:
# Connect to LDAP
proto = "ldaps" if (self.args.gmsa or self.args.port == 636) else "ldap"
proto = "ldaps" if (self.args.gmsa or self.port == 636) else "ldap"
ldap_url = f"{proto}://{self.target}"
self.logger.debug(f"Connecting to {ldap_url} - {self.baseDN} [3]")
self.ldapConnection = ldap_impacket.LDAPConnection(ldap_url, self.baseDN)
Expand All @@ -483,7 +483,7 @@ def plaintext_login(self, domain, username, password):
out = f"{domain}\\{self.username}:{process_secret(self.password)} {self.mark_pwned()}"

self.logger.extra["protocol"] = "LDAP"
self.logger.extra["port"] = "636" if (self.args.gmsa or self.args.port == 636) else "389"
self.logger.extra["port"] = "636" if (self.args.gmsa or self.port == 636) else "389"
self.logger.success(out)

if not self.args.local_auth:
Expand Down Expand Up @@ -563,7 +563,7 @@ def hash_login(self, domain, username, ntlm_hash):

try:
# Connect to LDAP
proto = "ldaps" if (self.args.gmsa or self.args.port == 636) else "ldap"
proto = "ldaps" if (self.args.gmsa or self.port == 636) else "ldap"
ldaps_url = f"{proto}://{self.target}"
self.logger.info(f"Connecting to {ldaps_url} - {self.baseDN}")
self.ldapConnection = ldap_impacket.LDAPConnection(ldaps_url, self.baseDN)
Expand All @@ -573,7 +573,7 @@ def hash_login(self, domain, username, ntlm_hash):
# Prepare success credential text
out = f"{domain}\\{self.username}:{process_secret(self.nthash)} {self.mark_pwned()}"
self.logger.extra["protocol"] = "LDAP"
self.logger.extra["port"] = "636" if (self.args.gmsa or self.args.port == 636) else "389"
self.logger.extra["port"] = "636" if (self.args.gmsa or self.port == 636) else "389"
self.logger.success(out)

if not self.args.local_auth:
Expand Down Expand Up @@ -1319,7 +1319,7 @@ def bloodhound(self):
self.logger.highlight("Using kerberos auth from ccache")

timestamp = datetime.now().strftime("%Y-%m-%d_%H%M%S") + "_"
bloodhound = BloodHound(ad, self.hostname, self.host, self.args.port)
bloodhound = BloodHound(ad, self.hostname, self.host, self.port)
bloodhound.connect()

bloodhound.run(
Expand Down
4 changes: 2 additions & 2 deletions nxc/protocols/mssql.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def proto_logger(self):
extra={
"protocol": "MSSQL",
"host": self.host,
"port": self.args.port,
"port": self.port,
"hostname": "None",
}
)
Expand Down Expand Up @@ -112,7 +112,7 @@ def print_host_info(self):

def create_conn_obj(self):
try:
self.conn = tds.MSSQL(self.host, self.args.port)
self.conn = tds.MSSQL(self.host, self.port)
self.conn.connect()
except OSError as e:
self.logger.debug(f"Error connecting to MSSQL: {e}")
Expand Down
6 changes: 3 additions & 3 deletions nxc/protocols/rdp.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def proto_logger(self):
extra={
"protocol": "RDP",
"host": self.host,
"port": self.args.port,
"port": self.port,
"hostname": self.hostname,
}
)
Expand All @@ -105,7 +105,7 @@ def print_host_info(self):
return True

def create_conn_obj(self):
self.target = RDPTarget(ip=self.host, domain="FAKE", port=self.args.port, timeout=self.args.rdp_timeout)
self.target = RDPTarget(ip=self.host, domain="FAKE", port=self.port, timeout=self.args.rdp_timeout)
self.auth = NTLMCredential(secret="pass", username="user", domain="FAKE", stype=asyauthSecret.PASS)

self.check_nla()
Expand Down Expand Up @@ -147,7 +147,7 @@ def create_conn_obj(self):
self.target = RDPTarget(
ip=self.host,
hostname=self.hostname,
port=self.args.port,
port=self.port,
domain=self.domain,
dc_ip=self.domain,
timeout=self.args.rdp_timeout,
Expand Down
16 changes: 8 additions & 8 deletions nxc/protocols/smb.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ def proto_logger(self):
extra={
"protocol": "SMB",
"host": self.host,
"port": self.args.port,
"port": self.port,
"hostname": self.hostname,
}
)
Expand Down Expand Up @@ -582,7 +582,7 @@ def create_smbv1_conn(self, kdc=""):
kdc if kdc else self.host,
kdc if kdc else self.host,
None,
self.args.port,
self.port,
preferredDialect=SMB_DIALECT,
timeout=self.args.smb_timeout,
)
Expand All @@ -603,7 +603,7 @@ def create_smbv3_conn(self, kdc=""):
kdc if kdc else self.host,
kdc if kdc else self.host,
None,
self.args.port,
self.port,
timeout=self.args.smb_timeout,
)
self.smbv1 = False
Expand Down Expand Up @@ -735,7 +735,7 @@ def execute(self, payload=None, get_output=False, methods=None):
self.host if not self.kerberos else self.hostname + "." + self.domain,
self.smb_share_name,
self.conn,
self.args.port,
self.port,
self.username,
self.password,
self.domain,
Expand All @@ -744,7 +744,7 @@ def execute(self, payload=None, get_output=False, methods=None):
self.kdcHost,
self.hash,
self.args.share,
self.args.port,
self.port,
self.logger,
self.args.get_output_tries
)
Expand Down Expand Up @@ -1256,12 +1256,12 @@ def rid_brute(self, max_rid=None):

try:
full_hostname = self.host if not self.kerberos else self.hostname + "." + self.domain
string_binding = KNOWN_PROTOCOLS[self.args.port]["bindstr"]
string_binding = KNOWN_PROTOCOLS[self.port]["bindstr"]
logging.debug(f"StringBinding {string_binding}")
rpc_transport = transport.DCERPCTransportFactory(string_binding)
rpc_transport.set_dport(self.args.port)
rpc_transport.set_dport(self.port)

if KNOWN_PROTOCOLS[self.args.port]["set_host"]:
if KNOWN_PROTOCOLS[self.port]["set_host"]:
rpc_transport.setRemoteHost(full_hostname)

if hasattr(rpc_transport, "set_credentials"):
Expand Down
6 changes: 3 additions & 3 deletions nxc/protocols/ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def proto_logger(self):
extra={
"protocol": "SSH",
"host": self.host,
"port": self.args.port,
"port": self.port,
"hostname": self.hostname,
}
)
Expand All @@ -59,13 +59,13 @@ def enum_host_info(self):
if self.conn._transport.remote_version:
self.remote_version = self.conn._transport.remote_version
self.logger.debug(f"Remote version: {self.remote_version}")
self.db.add_host(self.host, self.args.port, self.remote_version)
self.db.add_host(self.host, self.port, self.remote_version)

def create_conn_obj(self):
self.conn = paramiko.SSHClient()
self.conn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
self.conn.connect(self.host, port=self.args.port, timeout=self.args.ssh_timeout, look_for_keys=False)
self.conn.connect(self.host, port=self.port, timeout=self.args.ssh_timeout, look_for_keys=False)
except AuthenticationException:
return True
except SSHException:
Expand Down
4 changes: 2 additions & 2 deletions nxc/protocols/vnc.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def proto_logger(self):
extra={
"protocol": "VNC",
"host": self.host,
"port": self.args.port,
"port": self.port,
"hostname": self.hostname,
}
)
Expand All @@ -50,7 +50,7 @@ def print_host_info(self):

def create_conn_obj(self):
try:
self.target = RDPTarget(ip=self.host, port=self.args.port)
self.target = RDPTarget(ip=self.host, port=self.port)
credential = UniCredential(protocol=asyauthProtocol.PLAIN, stype=asyauthSecret.NONE)
self.conn = VNCConnection(target=self.target, credentials=credential, iosettings=self.iosettings)
asyncio.run(self.connect_vnc(True))
Expand Down
4 changes: 2 additions & 2 deletions nxc/protocols/wmi.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def proto_logger(self):
extra={
"protocol": "WMI",
"host": self.host,
"port": self.args.port,
"port": self.port,
"hostname": self.hostname
}
)
Expand All @@ -67,7 +67,7 @@ def create_conn_obj(self):
if self.remoteName == "":
self.remoteName = self.host
try:
rpctansport = transport.DCERPCTransportFactory(fr"ncacn_ip_tcp:{self.remoteName}[{self.args.port!s}]")
rpctansport = transport.DCERPCTransportFactory(fr"ncacn_ip_tcp:{self.remoteName}[{self.port!s}]")
rpctansport.set_credentials(username="", password="", domain="", lmhash="", nthash="", aesKey="")
rpctansport.setRemoteHost(self.host)
rpctansport.set_connect_timeout(self.args.rpc_timeout)
Expand Down

0 comments on commit 9fc67da

Please sign in to comment.