Skip to content

Commit

Permalink
Merge pull request #438 from snowpeacock/fix_module_execution_method
Browse files Browse the repository at this point in the history
Bugfix : exec-method specified in module file is not used
  • Loading branch information
NeffIsBack authored Nov 15, 2024
2 parents 0da04dd + dca1d08 commit b387260
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 11 deletions.
17 changes: 16 additions & 1 deletion nxc/helpers/args.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from argparse import ArgumentDefaultsHelpFormatter, SUPPRESS, OPTIONAL, ZERO_OR_MORE
from argparse import Action

class DisplayDefaultsNotNone(ArgumentDefaultsHelpFormatter):
def _get_help_string(self, action):
Expand All @@ -7,4 +8,18 @@ def _get_help_string(self, action):
defaulting_nargs = [OPTIONAL, ZERO_OR_MORE]
if (action.option_strings or action.nargs in defaulting_nargs) and action.default: # Only add default info if it's not None
help_string += " (default: %(default)s)" # NORUFF
return help_string
return help_string


class DefaultTrackingAction(Action):
def __init__(self, option_strings, dest, default=None, required=False, **kwargs):
# Store the default value to check later
self.default_value = default
super().__init__(
option_strings, dest, default=default, required=required, **kwargs
)

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)
2 changes: 1 addition & 1 deletion nxc/protocols/smb.py
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,7 @@ def execute(self, payload=None, get_output=False, methods=None) -> str:
-------
str: The output of the command
"""
if self.args.exec_method:
if getattr(self.args, "exec_method_explicitly_set", False):
methods = [self.args.exec_method]
if not methods:
methods = ["wmiexec", "atexec", "smbexec", "mmcexec"]
Expand Down
17 changes: 8 additions & 9 deletions nxc/protocols/smb/proto_args.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
from argparse import _StoreTrueAction
from nxc.helpers.args import DisplayDefaultsNotNone
from nxc.helpers.args import DisplayDefaultsNotNone, DefaultTrackingAction


def proto_args(parser, parents):
smb_parser = parser.add_parser("smb", help="own stuff using SMB", parents=parents, formatter_class=DisplayDefaultsNotNone)
smb_parser.add_argument("-H", "--hash", metavar="HASH", dest="hash", nargs="+", default=[], help="NTLM hash(es) or file(s) containing NTLM hashes")

delegate_arg = smb_parser.add_argument("--delegate", action="store", help="Impersonate user with S4U2Self + S4U2Proxy")
self_delegate_arg = smb_parser.add_argument("--self", dest="no_s4u2proxy", action=get_conditional_action(_StoreTrueAction), make_required=[], help="Only do S4U2Self, no S4U2Proxy (use with delegate)")

dgroup = smb_parser.add_mutually_exclusive_group()
dgroup.add_argument("-d", "--domain", metavar="DOMAIN", dest="domain", type=str, help="domain to authenticate to")
dgroup.add_argument("--local-auth", action="store_true", help="authenticate locally to each target")

smb_parser.add_argument("--port", type=int, default=445, help="SMB port")
smb_parser.add_argument("--share", metavar="SHARE", default="C$", help="specify a share")
smb_parser.add_argument("--smb-server-port", default="445", help="specify a server port for SMB", type=int)
Expand Down Expand Up @@ -49,7 +49,7 @@ def proto_args(parser, parents):
mapping_enum_group.add_argument("--local-groups", nargs="?", const="", metavar="GROUP", help="enumerate local groups, if a group is specified then its members are enumerated")
mapping_enum_group.add_argument("--pass-pol", action="store_true", help="dump password policy")
mapping_enum_group.add_argument("--rid-brute", nargs="?", type=int, const=4000, metavar="MAX_RID", help="enumerate users by bruteforcing RIDs")

wmi_group = smb_parser.add_argument_group("WMI", "Options for WMI Queries")
wmi_group.add_argument("--wmi", metavar="QUERY", type=str, help="issues the specified WMI query")
wmi_group.add_argument("--wmi-namespace", metavar="NAMESPACE", default="root\\cimv2", help="WMI Namespace")
Expand All @@ -71,7 +71,7 @@ def proto_args(parser, parents):
files_group.add_argument("--append-host", action="store_true", help="append the host to the get-file filename")

cmd_exec_group = smb_parser.add_argument_group("Command Execution", "Options for executing commands")
cmd_exec_group.add_argument("--exec-method", choices={"wmiexec", "mmcexec", "smbexec", "atexec"}, default="wmiexec", help="method to execute the command. Ignored if in MSSQL mode")
cmd_exec_group.add_argument("--exec-method", choices={"wmiexec", "mmcexec", "smbexec", "atexec"}, default="wmiexec", help="method to execute the command. Ignored if in MSSQL mode", action=DefaultTrackingAction)
cmd_exec_group.add_argument("--dcom-timeout", help="DCOM connection timeout", type=int, default=5)
cmd_exec_group.add_argument("--get-output-tries", help="Number of times atexec/smbexec/mmcexec tries to get results", type=int, default=10)
cmd_exec_group.add_argument("--codec", default="utf-8", help="Set encoding used (codec) from the target's output. 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")
Expand All @@ -80,15 +80,14 @@ def proto_args(parser, parents):
cmd_exec_method_group = cmd_exec_group.add_mutually_exclusive_group()
cmd_exec_method_group.add_argument("-x", metavar="COMMAND", dest="execute", help="execute the specified CMD command")
cmd_exec_method_group.add_argument("-X", metavar="PS_COMMAND", dest="ps_execute", help="execute the specified PowerShell command")

posh_group = smb_parser.add_argument_group("Powershell Obfuscation", "Options for PowerShell script obfuscation")
posh_group.add_argument("--obfs", action="store_true", help="Obfuscate PowerShell scripts")
posh_group.add_argument("--amsi-bypass", nargs=1, metavar="FILE", help="File with a custom AMSI bypass")
posh_group.add_argument("--clear-obfscripts", action="store_true", help="Clear all cached obfuscated PowerShell scripts")
posh_group.add_argument("--force-ps32", action="store_true", help="force PowerShell commands to run in a 32-bit process (may not apply to modules)")
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):
Expand All @@ -103,4 +102,4 @@ def __call__(self, parser, namespace, values, option_string=None):
x.required = True
super().__call__(parser, namespace, values, option_string)

return ConditionalAction
return ConditionalAction

0 comments on commit b387260

Please sign in to comment.