Skip to content

Commit cce5c32

Browse files
authored
Merge pull request Pennyw0rth#293 from Sant0rryu/main
2 parents b0b4641 + c09304e commit cce5c32

2 files changed

Lines changed: 81 additions & 14 deletions

File tree

nxc/protocols/smb.py

Lines changed: 80 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
NTDSHashes,
1515
)
1616
from impacket.nmb import NetBIOSError, NetBIOSTimeout
17-
from impacket.dcerpc.v5 import transport, lsat, lsad, scmr
17+
from impacket.dcerpc.v5 import transport, lsat, lsad, scmr, rrp
1818
from impacket.dcerpc.v5.rpcrt import DCERPCException
1919
from impacket.dcerpc.v5.transport import DCERPCTransportFactory, SMBTransport
2020
from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_GSS_NEGOTIATE
@@ -273,7 +273,7 @@ def enum_host_info(self):
273273
self.conn.logoff()
274274
except Exception as e:
275275
self.logger.debug(f"Error logging off system: {e}")
276-
276+
277277
# DCOM connection with kerberos needed
278278
self.remoteName = self.host if not self.kerberos else f"{self.hostname}.{self.domain}"
279279

@@ -707,11 +707,11 @@ def execute(self, payload=None, get_output=False, methods=None):
707707
except UnicodeDecodeError:
708708
self.logger.debug("Decoding error detected, consider running chcp.com at the target, map the result with https://docs.python.org/3/library/codecs.html#standard-encodings")
709709
output = output.decode("cp437")
710-
710+
711711
self.logger.debug(f"Raw Output: {output}")
712712
output = "\n".join([ll.rstrip() for ll in output.splitlines() if ll.strip()])
713713
self.logger.debug(f"Cleaned Output: {output}")
714-
714+
715715
if "This script contains malicious content" in output:
716716
self.logger.fail("Command execution blocked by AMSI")
717717
return None
@@ -732,24 +732,24 @@ def ps_execute(self, payload=None, get_output=False, methods=None, force_ps32=Fa
732732
if not payload:
733733
self.logger.error("No command to execute specified!")
734734
return None
735-
735+
736736
response = []
737737
obfs = obfs if obfs else self.args.obfs
738738
encode = encode if encode else not self.args.no_encode
739739
force_ps32 = force_ps32 if force_ps32 else self.args.force_ps32
740740
get_output = True if not self.args.no_output else get_output
741-
741+
742742
self.logger.debug(f"Starting ps_execute(): {payload=} {get_output=} {methods=} {force_ps32=} {obfs=} {encode=}")
743743
amsi_bypass = self.args.amsi_bypass[0] if self.args.amsi_bypass else None
744744
self.logger.debug(f"AMSI Bypass: {amsi_bypass}")
745-
745+
746746
if os.path.isfile(payload):
747747
self.logger.debug(f"File payload set: {payload}")
748748
with open(payload) as commands:
749749
response = [self.execute(create_ps_command(c.strip(), force_ps32=force_ps32, obfs=obfs, custom_amsi=amsi_bypass, encode=encode), get_output, methods) for c in commands]
750750
else:
751751
response = [self.execute(create_ps_command(payload, force_ps32=force_ps32, obfs=obfs, custom_amsi=amsi_bypass, encode=encode), get_output, methods)]
752-
752+
753753
self.logger.debug(f"ps_execute response: {response}")
754754
return response
755755

@@ -834,6 +834,74 @@ def shares(self):
834834
self.logger.highlight(f"{name:<15} {','.join(perms):<15} {remark}")
835835
return permissions
836836

837+
def interfaces(self):
838+
"""
839+
Retrieve the list of network interfaces info (Name, IP Address, Subnet Mask, Default Gateway) from remote Windows registry'
840+
Made by: @Sant0rryu, @NeffIsBack
841+
"""
842+
try:
843+
remoteOps = RemoteOperations(self.conn, False)
844+
remoteOps.enableRegistry()
845+
846+
if remoteOps._RemoteOperations__rrp:
847+
reg_handle = rrp.hOpenLocalMachine(remoteOps._RemoteOperations__rrp)["phKey"]
848+
key_handle = rrp.hBaseRegOpenKey(remoteOps._RemoteOperations__rrp, reg_handle, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces")["phkResult"]
849+
sub_key_list = rrp.hBaseRegQueryInfoKey(remoteOps._RemoteOperations__rrp, key_handle)["lpcSubKeys"]
850+
sub_keys = [rrp.hBaseRegEnumKey(remoteOps._RemoteOperations__rrp, key_handle, i)["lpNameOut"][:-1] for i in range(sub_key_list)]
851+
852+
self.logger.highlight(f"{'-Name-':<11} | {'-IP Address-':<15} | {'-SubnetMask-':<15} | {'-Gateway-':<15} | -DHCP-")
853+
for sub_key in sub_keys:
854+
interface = {}
855+
try:
856+
interface_key = f"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\{sub_key}"
857+
interface_handle = rrp.hBaseRegOpenKey(remoteOps._RemoteOperations__rrp, reg_handle, interface_key)["phkResult"]
858+
859+
# Retrieve Interace Name
860+
interface_name_key = f"SYSTEM\\ControlSet001\\Control\\Network\\{{4D36E972-E325-11CE-BFC1-08002BE10318}}\\{sub_key}\\Connection"
861+
interface_name_handle = rrp.hBaseRegOpenKey(remoteOps._RemoteOperations__rrp, reg_handle, interface_name_key)["phkResult"]
862+
interface_name = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, interface_name_handle, "Name")[1].rstrip("\x00")
863+
interface["Name"] = str(interface_name)
864+
if "Kernel" in interface_name:
865+
continue
866+
867+
# Retrieve DHCP
868+
try:
869+
dhcp_enabled = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, interface_handle, "EnableDHCP")[1]
870+
except DCERPCException:
871+
dhcp_enabled = False
872+
interface["DHCP"] = bool(dhcp_enabled)
873+
874+
# Retrieve IPAddress
875+
try:
876+
ip_address = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, interface_handle, "DhcpIPAddress" if dhcp_enabled else "IPAddress")[1].rstrip("\x00").replace("\x00", ", ")
877+
except DCERPCException:
878+
ip_address = None
879+
interface["IPAddress"] = ip_address if ip_address else None
880+
881+
# Retrieve SubnetMask
882+
try:
883+
subnetmask = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, interface_handle, "SubnetMask")[1].rstrip("\x00").replace("\x00", ", ")
884+
except DCERPCException:
885+
subnetmask = None
886+
interface["SubnetMask"] = subnetmask if subnetmask else None
887+
888+
# Retrieve DefaultGateway
889+
try:
890+
default_gateway = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, interface_handle, "DhcpDefaultGateway")[1].rstrip("\x00").replace("\x00", ", ")
891+
except DCERPCException:
892+
default_gateway = None
893+
interface["DefaultGateway"] = default_gateway if default_gateway else None
894+
895+
self.logger.highlight(f"{interface['Name']:<11} | {interface['IPAddress']!s:<15} | {interface['SubnetMask']!s:<15} | {interface['DefaultGateway']!s:<15} | {interface['DHCP']}")
896+
897+
except DCERPCException as e:
898+
self.logger.info(f"Failed to retrieve the network interface info for {sub_key}: {e!s}")
899+
900+
with contextlib.suppress(Exception):
901+
remoteOps.finish()
902+
except DCERPCException as e:
903+
self.logger.error(f"Failed to connect to the target: {e!s}")
904+
837905
def get_dc_ips(self):
838906
dc_ips = [dc[1] for dc in self.db.get_domain_controllers(domain=self.domain)]
839907
if not dc_ips:
@@ -1302,7 +1370,7 @@ def put_file_single(self, src, dst):
13021370
self.logger.success(f"Created file {src} on \\\\{self.args.share}\\{dst}")
13031371
except Exception as e:
13041372
self.logger.fail(f"Error writing file to share {self.args.share}: {e}")
1305-
1373+
13061374
def put_file(self):
13071375
for src, dest in self.args.put_file:
13081376
self.put_file_single(src, dest)
@@ -1325,7 +1393,6 @@ def get_file(self):
13251393
for src, dest in self.args.get_file:
13261394
self.get_file_single(src, dest)
13271395

1328-
13291396
def enable_remoteops(self):
13301397
try:
13311398
self.remote_ops = RemoteOperations(self.conn, self.kerberos, self.kdcHost)
@@ -1408,7 +1475,7 @@ def sccm(self):
14081475
except Exception as e:
14091476
self.logger.debug(f"Could not upgrade connection: {e}")
14101477
return
1411-
1478+
14121479
try:
14131480
self.logger.display("Collecting Machine masterkeys, grab a coffee and be patient...")
14141481
masterkeys_triage = MasterkeysTriage(
@@ -1423,7 +1490,7 @@ def sccm(self):
14231490
if len(masterkeys) == 0:
14241491
self.logger.fail("No masterkeys looted")
14251492
return
1426-
1493+
14271494
self.logger.success(f"Got {highlight(len(masterkeys))} decrypted masterkeys. Looting SCCM Credentials through {self.args.sccm}")
14281495
try:
14291496
# Collect Chrome Based Browser stored secrets
@@ -1613,7 +1680,6 @@ def dpapi(self):
16131680
"Google Refresh Token",
16141681
)
16151682

1616-
16171683
if dump_cookies and cookies:
16181684
self.logger.display("Start Dumping Cookies")
16191685
for cookie in cookies:
@@ -1801,4 +1867,4 @@ def add_ntds_hash(ntds_hash, host_id):
18011867
NTDS.finish()
18021868

18031869
def mark_guest(self):
1804-
return highlight(f"{highlight('(Guest)')}" if self.is_guest else "")
1870+
return highlight(f"{highlight('(Guest)')}" if self.is_guest else "")

nxc/protocols/smb/proto_args.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def proto_args(parser, parents):
3434

3535
mapping_enum_group = smb_parser.add_argument_group("Mapping/Enumeration", "Options for Mapping/Enumerating")
3636
mapping_enum_group.add_argument("--shares", action="store_true", help="enumerate shares and access")
37+
mapping_enum_group.add_argument("--interfaces", action="store_true", help="enumerate network interfaces")
3738
mapping_enum_group.add_argument("--no-write-check", action="store_true", help="Skip write check on shares (avoid leaving traces when missing delete permissions)")
3839
mapping_enum_group.add_argument("--filter-shares", nargs="+", help="Filter share by access, option 'read' 'write' or 'read,write'")
3940
mapping_enum_group.add_argument("--sessions", action="store_true", help="enumerate active sessions")

0 commit comments

Comments
 (0)