Skip to content

Commit 7b7f4b2

Browse files
authored
Merge branch 'main' into timeroast_module
2 parents b1238fc + e19868e commit 7b7f4b2

101 files changed

Lines changed: 6074 additions & 2919 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/PULL_REQUEST_TEMPLATE/pull_request_template.md renamed to .github/PULL_REQUEST_TEMPLATE.md

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
1-
---
2-
name: Pull request
3-
about: Update code to fix a bug or add an enhancement/feature
4-
title: ''
5-
labels: ''
6-
assignees: ''
7-
8-
---
91
## Description
102

113
Please include a summary of the change and which issue is fixed, or what the enhancement does.

.github/workflows/build-binaries.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ jobs:
1010
strategy:
1111
matrix:
1212
os: [ubuntu-latest, macOS-latest, windows-latest]
13-
python-version: ["3.11"]
13+
python-version: ["3.12"]
1414
#python-version: ["3.8", "3.9", "3.10", "3.11"] # for binary builds we only need one version
1515
steps:
16-
- uses: actions/checkout@v3
16+
- uses: actions/checkout@v4
1717
- name: NetExec set up python on ${{ matrix.os }}
18-
uses: actions/setup-python@v4
18+
uses: actions/setup-python@v5
1919
with:
2020
python-version: ${{ matrix.python-version }}
2121
- name: Build Native Binary
@@ -25,13 +25,13 @@ jobs:
2525
pyinstaller netexec.spec
2626
- name: Upload Windows Binary
2727
if: runner.os == 'windows'
28-
uses: actions/upload-artifact@v3
28+
uses: actions/upload-artifact@v4
2929
with:
3030
name: nxc.exe
3131
path: dist/nxc.exe
3232
- name: Upload Nix/OSx Binary
3333
if: runner.os != 'windows'
34-
uses: actions/upload-artifact@v3
34+
uses: actions/upload-artifact@v4
3535
with:
3636
name: nxc-${{ matrix.os }}
3737
path: dist/nxc

.github/workflows/build-zipapps.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,24 @@ jobs:
1010
strategy:
1111
matrix:
1212
os: [ubuntu-latest, macOS-latest, windows-latest]
13-
python-version: ["3.8", "3.9", "3.10", "3.11"]
13+
python-version: ["3.10", "3.11", "3.12"]
1414
steps:
15-
- uses: actions/checkout@v3
15+
- uses: actions/checkout@v4
1616
- name: NetExec set up python on ${{ matrix.os }}
17-
uses: actions/setup-python@v4
17+
uses: actions/setup-python@v5
1818
with:
1919
python-version: ${{ matrix.python-version }}
2020
- name: Build Python ZipApp with Shiv
2121
run: |
2222
pip install shiv
2323
python build_collector.py
2424
- name: Upload nxc ZipApp
25-
uses: actions/upload-artifact@v3
25+
uses: actions/upload-artifact@v4
2626
with:
2727
name: nxc-zipapp-${{ matrix.os }}-${{ matrix.python-version }}
2828
path: bin/nxc
2929
- name: Upload nxcdb ZipApp
30-
uses: actions/upload-artifact@v3
30+
uses: actions/upload-artifact@v4
3131
with:
3232
name: nxcdb-zipapp-${{ matrix.os }}-${{ matrix.python-version }}
3333
path: bin/nxcdb

.github/workflows/lint.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ name: Lint Python code with ruff
33

44
on:
55
push:
6+
workflow_dispatch:
67

78
jobs:
89
lint:
@@ -11,14 +12,14 @@ jobs:
1112
github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository
1213

1314
steps:
14-
- uses: actions/checkout@v3
15+
- uses: actions/checkout@v4
1516
- name: Install poetry
1617
run: |
1718
pipx install poetry
1819
- name: Set up Python
19-
uses: actions/setup-python@v4
20+
uses: actions/setup-python@v5
2021
with:
21-
python-version: 3.11
22+
python-version: 3.12
2223
cache: poetry
2324
cache-dependency-path: poetry.lock
2425
- name: Install dependencies with dev group

.github/workflows/test.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ jobs:
1414
max-parallel: 5
1515
matrix:
1616
os: [ubuntu-latest]
17-
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
17+
python-version: ["3.10", "3.11", "3.12"]
1818
steps:
19-
- uses: actions/checkout@v3
19+
- uses: actions/checkout@v4
2020
- name: Install poetry
2121
run: |
2222
pipx install poetry
2323
- name: NetExec set up python ${{ matrix.python-version }} on ${{ matrix.os }}
24-
uses: actions/setup-python@v4
24+
uses: actions/setup-python@v5
2525
with:
2626
python-version: ${{ matrix.python-version }}
2727
cache: poetry

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
![Supported Python versions](https://img.shields.io/badge/python-3.8+-blue.svg)
1+
![Supported Python versions](https://img.shields.io/badge/python-3.10+-blue.svg)
22
[![Twitter](https://img.shields.io/twitter/follow/al3xn3ff?label=al3x_n3ff&style=social)](https://twitter.com/intent/follow?screen_name=al3x_n3ff)
33
[![Twitter](https://img.shields.io/twitter/follow/_zblurx?label=_zblurx&style=social)](https://twitter.com/intent/follow?screen_name=_zblurx)
44
[![Twitter](https://img.shields.io/twitter/follow/MJHallenbeck?label=MJHallenbeck&style=social)](https://twitter.com/intent/follow?screen_name=MJHallenbeck)
@@ -43,6 +43,11 @@ sudo apt install pipx git
4343
pipx ensurepath
4444
pipx install git+https://github.com/Pennyw0rth/NetExec
4545
```
46+
47+
## Availability on Unix distributions
48+
49+
[![Packaging status](https://repology.org/badge/vertical-allrepos/netexec.svg)](https://repology.org/project/netexec/versions)
50+
4651
# Development
4752
Development guidelines and recommendations in development
4853

netexec.spec

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ a = Analysis(
2525
'impacket.dcerpc.v5.lsad',
2626
'impacket.dcerpc.v5.gkdi',
2727
'impacket.dcerpc.v5.rprn',
28+
'impacket.dcerpc.v5.even',
2829
'impacket.dpapi_ng',
2930
'impacket.tds',
3031
'impacket.version',
@@ -48,6 +49,7 @@ a = Analysis(
4849
'pywerview.cli.helpers',
4950
'pylnk3',
5051
'pypykatz',
52+
'pyNfsClient',
5153
'masky',
5254
'msldap',
5355
'msldap.connection',
@@ -67,8 +69,10 @@ a = Analysis(
6769
'dploot.triage.browser',
6870
'dploot.triage.credentials',
6971
'dploot.triage.masterkeys',
72+
'dploot.triage.mobaxterm',
7073
'dploot.triage.backupkey',
7174
'dploot.triage.wifi',
75+
'dploot.triage.sccm',
7276
'dploot.lib.target',
7377
'dploot.lib.smb',
7478
'pyasn1_modules.rfc5652',

nxc/cli.py

Lines changed: 67 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from nxc.paths import NXC_PATH
1010
from nxc.loaders.protocolloader import ProtocolLoader
1111
from nxc.helpers.logger import highlight
12+
from nxc.helpers.args import DisplayDefaultsNotNone
1213
from nxc.logger import nxc_logger, setup_debug_logging
1314
import importlib.metadata
1415

@@ -21,10 +22,32 @@ def gen_cli_args():
2122
except ValueError:
2223
VERSION = importlib.metadata.version("netexec")
2324
COMMIT = ""
24-
CODENAME = "nxc4u"
25+
CODENAME = "NeedForSpeed"
2526
nxc_logger.debug(f"NXC VERSION: {VERSION} - {CODENAME} - {COMMIT}")
26-
27-
parser = argparse.ArgumentParser(description=rf"""
27+
28+
generic_parser = argparse.ArgumentParser(add_help=False, formatter_class=DisplayDefaultsNotNone)
29+
generic_group = generic_parser.add_argument_group("Generic", "Generic options for nxc across protocols")
30+
generic_group.add_argument("--version", action="store_true", help="Display nxc version")
31+
generic_group.add_argument("-t", "--threads", type=int, dest="threads", default=256, help="set how many concurrent threads to use")
32+
generic_group.add_argument("--timeout", default=None, type=int, help="max timeout in seconds of each thread")
33+
generic_group.add_argument("--jitter", metavar="INTERVAL", type=str, help="sets a random delay between each authentication")
34+
35+
output_parser = argparse.ArgumentParser(add_help=False, formatter_class=DisplayDefaultsNotNone)
36+
output_group = output_parser.add_argument_group("Output", "Options to set verbosity levels and control output")
37+
output_group.add_argument("--verbose", action="store_true", help="enable verbose output")
38+
output_group.add_argument("--debug", action="store_true", help="enable debug level information")
39+
output_group.add_argument("--no-progress", action="store_true", help="do not displaying progress bar during scan")
40+
output_group.add_argument("--log", metavar="LOG", help="export result into a custom file")
41+
42+
dns_parser = argparse.ArgumentParser(add_help=False, formatter_class=DisplayDefaultsNotNone)
43+
dns_group = dns_parser.add_argument_group("DNS")
44+
dns_group.add_argument("-6", dest="force_ipv6", action="store_true", help="Enable force IPv6")
45+
dns_group.add_argument("--dns-server", action="store", help="Specify DNS server (default: Use hosts file & System DNS)")
46+
dns_group.add_argument("--dns-tcp", action="store_true", help="Use TCP instead of UDP for DNS queries")
47+
dns_group.add_argument("--dns-timeout", action="store", type=int, default=3, help="DNS query timeout in seconds")
48+
49+
parser = argparse.ArgumentParser(
50+
description=rf"""
2851
. .
2952
.| |. _ _ _ _____
3053
|| || | \ | | ___ | |_ | ____| __ __ ___ ___
@@ -42,62 +65,53 @@ def gen_cli_args():
4265
{highlight('Version', 'red')} : {highlight(VERSION)}
4366
{highlight('Codename', 'red')}: {highlight(CODENAME)}
4467
{highlight('Commit', 'red')} : {highlight(COMMIT)}
45-
""", formatter_class=RawTextHelpFormatter)
46-
47-
parser.add_argument("-t", type=int, dest="threads", default=256, help="set how many concurrent threads to use (default: 256)")
48-
parser.add_argument("--timeout", default=None, type=int, help="max timeout in seconds of each thread (default: None)")
49-
parser.add_argument("--jitter", metavar="INTERVAL", type=str, help="sets a random delay between each authentication (default: None)")
50-
parser.add_argument("--no-progress", action="store_true", help="Not displaying progress bar during scan")
51-
parser.add_argument("--verbose", action="store_true", help="enable verbose output")
52-
parser.add_argument("--debug", action="store_true", help="enable debug level information")
53-
parser.add_argument("--version", action="store_true", help="Display nxc version")
54-
55-
dns_parser = parser.add_argument_group("DNS")
56-
dns_parser.add_argument("-6", dest="force_ipv6", action="store_true", help="Enable force IPv6")
57-
dns_parser.add_argument("--dns-server", action="store", help="Specify DNS server (default: Use hosts file & System DNS)")
58-
dns_parser.add_argument("--dns-tcp", action="store_true", help="Use TCP instead of UDP for DNS queries")
59-
dns_parser.add_argument("--dns-timeout", action="store", type=int, default=3, help="DNS query timeout in seconds (default: %(default)s)")
68+
""",
69+
formatter_class=RawTextHelpFormatter,
70+
parents=[generic_parser, output_parser, dns_parser]
71+
)
6072

6173
# we do module arg parsing here so we can reference the module_list attribute below
62-
module_parser = argparse.ArgumentParser(add_help=False)
63-
mgroup = module_parser.add_mutually_exclusive_group()
74+
module_parser = argparse.ArgumentParser(add_help=False, formatter_class=DisplayDefaultsNotNone)
75+
mgroup = module_parser.add_argument_group("Modules", "Options for nxc modules")
6476
mgroup.add_argument("-M", "--module", choices=get_module_names(), action="append", metavar="MODULE", help="module to use")
65-
module_parser.add_argument("-o", metavar="MODULE_OPTION", nargs="+", default=[], dest="module_options", help="module options")
66-
module_parser.add_argument("-L", "--list-modules", action="store_true", help="list available modules")
67-
module_parser.add_argument("--options", dest="show_module_options", action="store_true", help="display module options")
68-
module_parser.add_argument("--server", choices={"http", "https"}, default="https", help="use the selected server (default: https)")
69-
module_parser.add_argument("--server-host", type=str, default="0.0.0.0", metavar="HOST", help="IP to bind the server to (default: 0.0.0.0)")
70-
module_parser.add_argument("--server-port", metavar="PORT", type=int, help="start the server on the specified port")
71-
module_parser.add_argument("--connectback-host", type=str, metavar="CHOST", help="IP for the remote system to connect back to (default: same as server-host)")
72-
73-
subparsers = parser.add_subparsers(title="protocols", dest="protocol", description="available protocols")
74-
75-
std_parser = argparse.ArgumentParser(add_help=False)
76-
std_parser.add_argument("target", nargs="+" if not (module_parser.parse_known_args()[0].list_modules or module_parser.parse_known_args()[0].show_module_options) else "*", type=str, help="the target IP(s), range(s), CIDR(s), hostname(s), FQDN(s), file(s) containing a list of targets, NMap XML or .Nessus file(s)")
77-
std_parser.add_argument("-id", metavar="CRED_ID", nargs="+", default=[], type=str, dest="cred_id", help="database credential ID(s) to use for authentication")
78-
std_parser.add_argument("-u", metavar="USERNAME", dest="username", nargs="+", default=[], help="username(s) or file(s) containing usernames")
79-
std_parser.add_argument("-p", metavar="PASSWORD", dest="password", nargs="+", default=[], help="password(s) or file(s) containing passwords")
80-
std_parser.add_argument("--ignore-pw-decoding", action="store_true", help="Ignore non UTF-8 characters when decoding the password file")
81-
std_parser.add_argument("-k", "--kerberos", action="store_true", help="Use Kerberos authentication")
82-
std_parser.add_argument("--no-bruteforce", action="store_true", help="No spray when using file for username and password (user1 => password1, user2 => password2")
83-
std_parser.add_argument("--continue-on-success", action="store_true", help="continues authentication attempts even after successes")
84-
std_parser.add_argument("--use-kcache", action="store_true", help="Use Kerberos authentication from ccache file (KRB5CCNAME)")
85-
std_parser.add_argument("--log", metavar="LOG", help="Export result into a custom file")
86-
std_parser.add_argument("--aesKey", metavar="AESKEY", nargs="+", help="AES key to use for Kerberos Authentication (128 or 256 bits)")
87-
std_parser.add_argument("--kdcHost", metavar="KDCHOST", help="IP Address of the domain controller. If omitted it will use the domain part (FQDN) specified in the target parameter")
88-
89-
fail_group = std_parser.add_mutually_exclusive_group()
90-
fail_group.add_argument("--gfail-limit", metavar="LIMIT", type=int, help="max number of global failed login attempts")
91-
fail_group.add_argument("--ufail-limit", metavar="LIMIT", type=int, help="max number of failed login attempts per username")
92-
fail_group.add_argument("--fail-limit", metavar="LIMIT", type=int, help="max number of failed login attempts per host")
77+
mgroup.add_argument("-o", metavar="MODULE_OPTION", nargs="+", default=[], dest="module_options", help="module options")
78+
mgroup.add_argument("-L", "--list-modules", action="store_true", help="list available modules")
79+
mgroup.add_argument("--options", dest="show_module_options", action="store_true", help="display module options")
80+
81+
subparsers = parser.add_subparsers(title="Available Protocols", dest="protocol")
82+
83+
std_parser = argparse.ArgumentParser(add_help=False, parents=[generic_parser, output_parser, dns_parser], formatter_class=DisplayDefaultsNotNone)
84+
std_parser.add_argument("target", nargs="+" if not (module_parser.parse_known_args()[0].list_modules or module_parser.parse_known_args()[0].show_module_options or generic_parser.parse_known_args()[0].version) else "*", type=str, help="the target IP(s), range(s), CIDR(s), hostname(s), FQDN(s), file(s) containing a list of targets, NMap XML or .Nessus file(s)")
85+
credential_group = std_parser.add_argument_group("Authentication", "Options for authenticating")
86+
credential_group.add_argument("-u", "--username", metavar="USERNAME", dest="username", nargs="+", default=[], help="username(s) or file(s) containing usernames")
87+
credential_group.add_argument("-p", "--password", metavar="PASSWORD", dest="password", nargs="+", default=[], help="password(s) or file(s) containing passwords")
88+
credential_group.add_argument("-id", metavar="CRED_ID", nargs="+", default=[], type=str, dest="cred_id", help="database credential ID(s) to use for authentication")
89+
credential_group.add_argument("--ignore-pw-decoding", action="store_true", help="Ignore non UTF-8 characters when decoding the password file")
90+
credential_group.add_argument("--no-bruteforce", action="store_true", help="No spray when using file for username and password (user1 => password1, user2 => password2)")
91+
credential_group.add_argument("--continue-on-success", action="store_true", help="continues authentication attempts even after successes")
92+
credential_group.add_argument("--gfail-limit", metavar="LIMIT", type=int, help="max number of global failed login attempts")
93+
credential_group.add_argument("--ufail-limit", metavar="LIMIT", type=int, help="max number of failed login attempts per username")
94+
credential_group.add_argument("--fail-limit", metavar="LIMIT", type=int, help="max number of failed login attempts per host")
95+
96+
kerberos_group = std_parser.add_argument_group("Kerberos", "Options for Kerberos authentication")
97+
kerberos_group.add_argument("-k", "--kerberos", action="store_true", help="Use Kerberos authentication")
98+
kerberos_group.add_argument("--use-kcache", action="store_true", help="Use Kerberos authentication from ccache file (KRB5CCNAME)")
99+
kerberos_group.add_argument("--aesKey", metavar="AESKEY", nargs="+", help="AES key to use for Kerberos Authentication (128 or 256 bits)")
100+
kerberos_group.add_argument("--kdcHost", metavar="KDCHOST", help="FQDN of the domain controller. If omitted it will use the domain part (FQDN) specified in the target parameter")
101+
102+
server_group = std_parser.add_argument_group("Servers", "Options for nxc servers")
103+
server_group.add_argument("--server", choices={"http", "https"}, default="https", help="use the selected server")
104+
server_group.add_argument("--server-host", type=str, default="0.0.0.0", metavar="HOST", help="IP to bind the server to")
105+
server_group.add_argument("--server-port", metavar="PORT", type=int, help="start the server on the specified port")
106+
server_group.add_argument("--connectback-host", type=str, metavar="CHOST", help="IP for the remote system to connect back to")
93107

94108
p_loader = ProtocolLoader()
95109
protocols = p_loader.get_protocols()
96110

97111
try:
98112
for protocol in protocols:
99113
protocol_object = p_loader.load_protocol(protocols[protocol]["argspath"])
100-
subparsers = protocol_object.proto_args(subparsers, std_parser, module_parser)
114+
subparsers = protocol_object.proto_args(subparsers, [std_parser, module_parser])
101115
except Exception as e:
102116
nxc_logger.exception(f"Error loading proto_args from proto_args.py file in protocol folder: {protocol} - {e}")
103117

@@ -112,6 +126,10 @@ def gen_cli_args():
112126
print(f"{VERSION} - {CODENAME} - {COMMIT}")
113127
sys.exit(1)
114128

129+
# Multiply output_tries by 10 to enable more fine granural control, see exec methods
130+
if hasattr(args, "get_output_tries"):
131+
args.get_output_tries = args.get_output_tries * 10
132+
115133
return args
116134

117135

0 commit comments

Comments
 (0)