Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions nxc/helpers/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,18 @@ def __call__(self, parser, namespace, values, option_string=None):
# Set an attribute to track whether the value was explicitly set
setattr(namespace, self.dest, values)
setattr(namespace, f"{self.dest}_explicitly_set", True)


def get_conditional_action(baseAction):
class ConditionalAction(baseAction):
def __init__(self, option_strings, dest, **kwargs):
x = kwargs.pop("make_required", [])
super().__init__(option_strings, dest, **kwargs)
self.make_required = x

def __call__(self, parser, namespace, values, option_string=None):
for x in self.make_required:
x.required = True
super().__call__(parser, namespace, values, option_string)

return ConditionalAction
23 changes: 21 additions & 2 deletions nxc/protocols/ldap.py
Original file line number Diff line number Diff line change
Expand Up @@ -1037,8 +1037,27 @@ def kerberoasting(self):
f.write(line + "\n")
return

# Building the search filter
searchFilter = "(&(servicePrincipalName=*)(!(objectCategory=computer)))"
if self.args.kerberoast_users:
target_usernames = []
for item in self.args.kerberoast_users:
if os.path.isfile(item):
try:
with open(item, encoding="utf-8") as f:
target_usernames.extend(line.strip() for line in f if line.strip())
except Exception as e:
self.logger.fail(f"Failed to read file '{item}': {e}")
else:
target_usernames.append(item.strip())

self.logger.info(f"Targeting specific users for kerberoasting: {', '.join(target_usernames)}")

# build search filter for specific users
user_filter = "".join([f"(sAMAccountName={username})" for username in target_usernames])
searchFilter = f"(&(servicePrincipalName=*)(!(objectCategory=computer))(|{user_filter}))"
else:
# default to all
searchFilter = "(&(servicePrincipalName=*)(!(objectCategory=computer)))"

attributes = [
"sAMAccountName",
"userAccountControl",
Expand Down
9 changes: 7 additions & 2 deletions nxc/protocols/ldap/proto_args.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from nxc.helpers.args import DefaultTrackingAction, DisplayDefaultsNotNone
from nxc.helpers.args import DefaultTrackingAction, DisplayDefaultsNotNone, get_conditional_action
from argparse import _StoreAction


def proto_args(parser, parents):
Expand All @@ -12,9 +13,13 @@ def proto_args(parser, parents):

egroup = ldap_parser.add_argument_group("Retrieve hash on the remote DC", "Options to get hashes from Kerberos")
egroup.add_argument("--asreproast", help="Output AS_REP response to crack with hashcat to file")
egroup.add_argument("--kerberoasting", help="Output TGS ticket to crack with hashcat to file")
kerberoasting_arg = egroup.add_argument("--kerberoasting", "--kerberoast", help="Output TGS ticket to crack with hashcat to file")
kerberoast_users_arg = egroup.add_argument("--kerberoast-users", nargs="+", dest="kerberoast_users", action=get_conditional_action(_StoreAction), make_required=[], help="Target specific users for kerberoasting (usernames or file containing usernames)")
egroup.add_argument("--no-preauth-targets", nargs=1, dest="no_preauth_targets", help="Targeted kerberoastable users")

# Make kerberoast-users require kerberoasting
kerberoast_users_arg.make_required = [kerberoasting_arg]

vgroup = ldap_parser.add_argument_group("Retrieve useful information on the domain")
vgroup.add_argument("--base-dn", metavar="BASE_DN", dest="base_dn", type=str, default=None, help="base DN for search queries")
vgroup.add_argument("--query", nargs=2, help="Query LDAP with a custom filter and attributes")
Expand Down
17 changes: 1 addition & 16 deletions nxc/protocols/smb/proto_args.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from argparse import _StoreTrueAction
from nxc.helpers.args import DisplayDefaultsNotNone, DefaultTrackingAction
from nxc.helpers.args import DisplayDefaultsNotNone, DefaultTrackingAction, get_conditional_action


def proto_args(parser, parents):
Expand Down Expand Up @@ -98,18 +98,3 @@ def proto_args(parser, parents):
posh_group.add_argument("--no-encode", action="store_true", default=False, help="Do not encode the PowerShell command ran on target")

return parser


def get_conditional_action(baseAction):
class ConditionalAction(baseAction):
def __init__(self, option_strings, dest, **kwargs):
x = kwargs.pop("make_required", [])
super().__init__(option_strings, dest, **kwargs)
self.make_required = x

def __call__(self, parser, namespace, values, option_string=None):
for x in self.make_required:
x.required = True
super().__call__(parser, namespace, values, option_string)

return ConditionalAction
17 changes: 1 addition & 16 deletions nxc/protocols/ssh/proto_args.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from argparse import _StoreAction
from nxc.helpers.args import DisplayDefaultsNotNone
from nxc.helpers.args import DisplayDefaultsNotNone, get_conditional_action


def proto_args(parser, parents):
Expand All @@ -22,18 +22,3 @@ def proto_args(parser, parents):
cgroup.add_argument("-x", metavar="COMMAND", dest="execute", help="execute the specified command")

return parser


def get_conditional_action(baseAction):
class ConditionalAction(baseAction):
def __init__(self, option_strings, dest, **kwargs):
x = kwargs.pop("make_required", [])
super().__init__(option_strings, dest, **kwargs)
self.make_required = x

def __call__(self, parser, namespace, values, option_string=None):
for x in self.make_required:
x.required = True
super().__call__(parser, namespace, values, option_string)

return ConditionalAction
16 changes: 1 addition & 15 deletions nxc/protocols/wmi/proto_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,5 @@ def proto_args(parser, parents):
cgroup.add_argument("--exec-method", choices={"wmiexec", "wmiexec-event"}, default="wmiexec", help="method to execute the command. (default: wmiexec). [wmiexec (win32_process + StdRegProv)]: get command results over registry instead of using smb connection. [wmiexec-event (T1546.003)]: this method is not very stable, highly recommend use this method in single host, using on multiple hosts may crash (just try again if it crashed).")
cgroup.add_argument("--exec-timeout", default=2, metavar="exec_timeout", dest="exec_timeout", type=int, help="Set timeout (in seconds) when executing a command, minimum 5 seconds is recommended. Default: %(default)s")
cgroup.add_argument("--codec", default="utf-8", help="Set encoding used (codec) from the target's output (default: utf-8). If errors are detected, run chcp.com at the target & map the result with https://docs.python.org/3/library/codecs.html#standard-encodings and then execute again with --codec and the corresponding codec")
return parser


def get_conditional_action(base_action):
class ConditionalAction(base_action):
def __init__(self, option_strings, dest, **kwargs):
x = kwargs.pop("make_required", [])
super().__init__(option_strings, dest, **kwargs)
self.make_required = x

def __call__(self, parser, namespace, values, option_string=None):
for x in self.make_required:
x.required = True
super().__call__(parser, namespace, values, option_string)

return ConditionalAction
return parser
4 changes: 3 additions & 1 deletion tests/e2e_commands.txt
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,9 @@ netexec ldap TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --users-ex
netexec ldap TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --groups
netexec ldap TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --get-sid
netexec ldap TARGET_HOST -u LOGIN_USERNAME -p '' --asreproast /tmp/output.txt
netexec ldap TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --kerberoasting /tmp/output2.txt
netexec ldap TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --kerberoasting /tmp/kerberoasting1.txt
netexec ldap TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --kerberoast /tmp/kerberoasting2.txt
netexec ldap TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --kerberoasting /tmp/kerberoasting3.txt --kerberoast-users test_user
netexec ldap TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --trusted-for-delegation
netexec ldap TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --admin-count
netexec ldap TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --gmsa
Expand Down