Skip to content

Add safe_shares SMB module: share permission enumeration module that does not write files to disk#1138

Open
e-nzym3 wants to merge 3 commits intoPennyw0rth:mainfrom
e-nzym3:add-safe-shares-module
Open

Add safe_shares SMB module: share permission enumeration module that does not write files to disk#1138
e-nzym3 wants to merge 3 commits intoPennyw0rth:mainfrom
e-nzym3:add-safe-shares-module

Conversation

@e-nzym3
Copy link

@e-nzym3 e-nzym3 commented Mar 9, 2026

Preface

On a recent engagement, I stumbled upon a situation where Netexec's --shares flag
generated a bunch of artifacts on shares where my user did not possess DELETE permissions.

Artifact:
Screenshot_2026-03-08_19-49-03

Perms on share folder:
Screenshot_2026-03-08_19-48-30

First time I ran into this, but nonetheless, it sent me down a path of identifying
a better (safer) way of gathering share permissions, even with some slight downsides.

This proposed module comes with a slight downside, since share ACL and NTFS ACL may
differ, some WRITE permissions may be missed. Here's what output looks like when ran
against a share where my authenticating user has a DENY on DELETE permissions:

enzym3@pop-os:~/$ nxc smb 10.0.0.190 -u jsmith -p 'Passw0rd!' -M safe_shares
SMB         10.0.0.190      445    MORDOR-DC        [*] Windows 11 / Server 2025 Build 26100 x64 (name:MORDOR-DC) (domain:mordor.local) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         10.0.0.190      445    MORDOR-DC        [+] mordor.local\jsmith:Passw0rd!
SAFE_SHARES 10.0.0.190      445    MORDOR-DC        [*] Enumerated shares (no disk writes)
SAFE_SHARES 10.0.0.190      445    MORDOR-DC        Share                Access          Remark
SAFE_SHARES 10.0.0.190      445    MORDOR-DC        -----                ------          ------
SAFE_SHARES 10.0.0.190      445    MORDOR-DC        ADMIN$               NO ACCESS       Remote Admin
SAFE_SHARES 10.0.0.190      445    MORDOR-DC        C$                   NO ACCESS       Default share
SAFE_SHARES 10.0.0.190      445    MORDOR-DC        NETLOGON             READ            Logon server share
SAFE_SHARES 10.0.0.190      445    MORDOR-DC        SYSVOL               READ            Logon server share
SAFE_SHARES 10.0.0.190      445    MORDOR-DC        test_share           READ

And here's the output from --shares, correctly reporting WRITE permissions, but
at the same time leaving an artifact behind on disk (pictured in the first screenshot above).

enzym3@pop-os:~/$ nxc smb 10.0.0.190 -u jsmith -p 'Passw0rd!' --shares
SMB         10.0.0.190      445    MORDOR-DC        [*] Windows 11 / Server 2025 Build 26100 x64 (name:MORDOR-DC) (domain:mordor.local) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         10.0.0.190      445    MORDOR-DC        [+] mordor.local\jsmith:Passw0rd!
SMB         10.0.0.190      445    MORDOR-DC        [*] Enumerated shares
SMB         10.0.0.190      445    MORDOR-DC        Share           Permissions     Remark
SMB         10.0.0.190      445    MORDOR-DC        -----           -----------     ------
SMB         10.0.0.190      445    MORDOR-DC        ADMIN$                          Remote Admin
SMB         10.0.0.190      445    MORDOR-DC        C$                              Default share
SMB         10.0.0.190      445    MORDOR-DC        IPC$            READ            Remote IPC
SMB         10.0.0.190      445    MORDOR-DC        NETLOGON        READ            Logon server share
SMB         10.0.0.190      445    MORDOR-DC        SYSVOL          READ            Logon server share
SMB         10.0.0.190      445    MORDOR-DC        test_share      READ,WRITE

My thought: I'd rather have the option of running a safer check for WRITE permissions
and miss some, rather than potentially risk leaving a bunch of artifacts behind for clean-up.

In normal cases, it will report WRITE access as expected:

enzym3@pop-os:~/$ nxc smb 10.0.0.190 -u administrator -p 'Passw0rd!' -M safe_shares
SMB         10.0.0.190      445    MORDOR-DC        [*] Windows 11 / Server 2025 Build 26100 x64 (name:MORDOR-DC) (domain:mordor.local) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         10.0.0.190      445    MORDOR-DC        [+] mordor.local\administrator:Passw0rd! (Pwn3d!)
SAFE_SHARES 10.0.0.190      445    MORDOR-DC        [*] Enumerated shares (no disk writes)
SAFE_SHARES 10.0.0.190      445    MORDOR-DC        Share                Access          Remark
SAFE_SHARES 10.0.0.190      445    MORDOR-DC        -----                ------          ------
SAFE_SHARES 10.0.0.190      445    MORDOR-DC        ADMIN$               READ,WRITE      Remote Admin
SAFE_SHARES 10.0.0.190      445    MORDOR-DC        C$                   READ,WRITE      Default share
SAFE_SHARES 10.0.0.190      445    MORDOR-DC        NETLOGON             READ,WRITE      Logon server share
SAFE_SHARES 10.0.0.190      445    MORDOR-DC        SYSVOL               READ,WRITE      Logon server share
SAFE_SHARES 10.0.0.190      445    MORDOR-DC        test_share           READ,WRITE

Description

Adds a new SMB module safe_shares that enumerates share READ/WRITE permissions
without writing any files to disk — an OPSEC-safe alternative to the built-in
--shares flag. Effectively, an NXC implementation of SharpShares (https://github.com/djhohnstein/SharpShares).

Problem with existing --shares: Write access is tested by creating a
temporary file/directory, then deleting it. This leaves artifacts during
the creation-deletion window.

This module's approach (inspired by SharpShares):

  • READ check: listPath() — same non-destructive approach NXC already uses
  • WRITE check: Opens the share root directory (\) with GENERIC_WRITE desired
    access and FILE_OPEN (0x1) create disposition — opens the existing directory
    handle, never creates any object on disk. If the server grants the handle,
    write access is confirmed.

No third-party dependencies beyond impacket (already bundled with NXC).

AI Assistance: This module was developed with the assistance of Claude Code
(Anthropic). The technique research, impacket API usage, and module architecture
were AI-assisted; the code has been manually reviewed and tested.

Type of change

  • New feature (non-breaking change which adds functionality)
  • This PR was created with the assistance of AI (Claude Code by Anthropic —
    used for implementation and impacket API research)

Setup guide for the review

Any authenticated SMB session against a Windows target with shares is sufficient.
No special configuration required. Tested against:

  • Windows Server 2025 domain member
  • Python 3.12, Debian Linux
# Basic enumeration
nxc smb <target> -u <user> -p <pass> -M safe_shares

# Show only shares with WRITE access
nxc smb <target> -u <user> -p <pass> -M safe_shares -o FILTER=WRITE

# Exclude additional shares
nxc smb <target> -u <user> -p <pass> -M safe_shares -o EXCLUDE=IPC$,ADMIN$,C$

Screenshots

See Preface above for inline screenshots. Terminal output:

enzym3@pop-os:~/claude$ nxc smb 10.0.0.190 -u jsmith -p 'Passw0rd!' -M safe_shares
SMB         10.0.0.190      445    MORDOR-DC        [*] Windows 11 / Server 2025 Build 26100 x64 (name:MORDOR-DC) (domain:mordor.local) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         10.0.0.190      445    MORDOR-DC        [+] mordor.local\jsmith:Passw0rd!
SAFE_SHARES 10.0.0.190      445    MORDOR-DC        [*] Enumerated shares (no disk writes)
SAFE_SHARES 10.0.0.190      445    MORDOR-DC        Share                Access          Remark
SAFE_SHARES 10.0.0.190      445    MORDOR-DC        -----                ------          ------
SAFE_SHARES 10.0.0.190      445    MORDOR-DC        ADMIN$               NO ACCESS       Remote Admin
SAFE_SHARES 10.0.0.190      445    MORDOR-DC        C$                   NO ACCESS       Default share
SAFE_SHARES 10.0.0.190      445    MORDOR-DC        NETLOGON             READ            Logon server share
SAFE_SHARES 10.0.0.190      445    MORDOR-DC        SYSVOL               READ            Logon server share
SAFE_SHARES 10.0.0.190      445    MORDOR-DC        test_share           READ

Checklist

  • I have ran Ruff against my changes
  • I have added or updated the tests/e2e_commands.txt file
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
    (will open NetExec-Wiki PR after this is merged)

@mpgn
Copy link
Collaborator

mpgn commented Mar 9, 2026

@e-nzym3
Copy link
Author

e-nzym3 commented Mar 9, 2026

--no-write-check will omit checking write permissions altogether:

enzym3@pop-os:~/$ nxc smb 10.0.0.190 -u jsmith -p 'Passw0rd!' --shares --no-write-check
SMB         10.0.0.190      445    MORDOR-DC        [*] Windows 11 / Server 2025 Build 26100 x64 (name:MORDOR-DC) (domain:mordor.local) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         10.0.0.190      445    MORDOR-DC        [+] mordor.local\jsmith:Passw0rd!
SMB         10.0.0.190      445    MORDOR-DC        [*] Enumerated shares
SMB         10.0.0.190      445    MORDOR-DC        Share           Permissions     Remark
SMB         10.0.0.190      445    MORDOR-DC        -----           -----------     ------
SMB         10.0.0.190      445    MORDOR-DC        ADMIN$                          Remote Admin
SMB         10.0.0.190      445    MORDOR-DC        C$                              Default share
SMB         10.0.0.190      445    MORDOR-DC        IPC$            READ            Remote IPC
SMB         10.0.0.190      445    MORDOR-DC        NETLOGON        READ            Logon server share
SMB         10.0.0.190      445    MORDOR-DC        SYSVOL          READ            Logon server share

enzym3@pop-os:~/$ nxc smb 10.0.0.190 -u administrator -p 'Passw0rd!' --shares --no-write-check
SMB         10.0.0.190      445    MORDOR-DC        [*] Windows 11 / Server 2025 Build 26100 x64 (name:MORDOR-DC) (domain:mordor.local) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         10.0.0.190      445    MORDOR-DC        [+] mordor.local\administrator:Passw0rd! (Pwn3d!)
SMB         10.0.0.190      445    MORDOR-DC        [*] Enumerated shares
SMB         10.0.0.190      445    MORDOR-DC        Share           Permissions     Remark
SMB         10.0.0.190      445    MORDOR-DC        -----           -----------     ------
SMB         10.0.0.190      445    MORDOR-DC        ADMIN$          READ            Remote Admin
SMB         10.0.0.190      445    MORDOR-DC        C$              READ            Default share
SMB         10.0.0.190      445    MORDOR-DC        IPC$            READ            Remote IPC
SMB         10.0.0.190      445    MORDOR-DC        NETLOGON        READ            Logon server share
SMB         10.0.0.190      445    MORDOR-DC        SYSVOL          READ            Logon server share
SMB         10.0.0.190      445    MORDOR-DC        test_share      READ

whereas this module will check for WRITE permissions safely, and still report them where possible

Signed-off-by: e-nzym3 <jack@enzym3.io>
@NeffIsBack
Copy link
Member

NeffIsBack commented Mar 10, 2026

Thanks for the PR!

I think we should either integrate it into the default --share command or not integrate it at all, a module just for share enumeration is kinda the wrong place imo. This change would only result in false positives because we would show write privs although the NTFS privs might not allow the write, correct? Or am i missing something?

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.
@e-nzym3
Copy link
Author

e-nzym3 commented Mar 11, 2026

Actually, as I was digging more into the SharpShares logic, I realized it had some gaps that could be tightened down to make this proposed module less prone to false positives by adding checks for some other permissions as well, such as FILE_ADD_FILE or FILE_ADD_SUBDIRECTORY. It only checked for GENERIC_WRITE prior. Not sure how useful writing subdirectories may be, so that one is up for debate, currently it is reported as WRITE (subdir) to distinguish.

Another bonus I added was WRITE_DAC and WRITE_OWNER checks, which would check if the authenticating user can modify the permissions to grant themselves WRITE if it isn't already present (WRITE reporting takes precedence). I can provide a PoC script for this if interested.

To clarify on the false positive concern: the module is not reading the DACL directly, it's calling openFile() with FILE_OPEN which goes through the full Windows access check (share perms + NTFS + MIC). If NTFS denies it, the open fails and we report nothing. There are edge cases where it won't be accurate (disk quotas, Dynamic Access Control) but those are pretty niche.

Worth flagging if you're considering merging the logic:

  • False positives: quota exhaustion and conditional ACEs can fool an ACL probe but not an actual write attempt, --shares wins here
  • False negatives in --shares: WRITE_DAC and WRITE_OWNER don't allow immediate file creation so --shares won't flag them, but both are reliable escalation paths to full write. The module flags these as WRITE (ACL)

I created a test share setup to display when this module would trigger WRITE. Each individual share was only granted a subset of permissions for demonstration purposes. Here is the output of the share check script:
check_shares-output

  • In green, you will see permissions that would trigger the module's WRITE reporting, and the last column shows what the module would actually report.
  • The file/folder write was only implemented in this test script for validation purposes (it is not part of the module)

Here is what the module ran through nxc would report:
safe_shares-output

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants