Fix anonymous share enumeration + JSON Lines output (shares, files, content matches) + Py3.14 console fix#96
Open
ocervell wants to merge 7 commits into
Conversation
When no credentials are supplied, login() switched to the "Guest" account and only fell back to a true null session if Guest *failed*. On Samba with `map to guest = Bad User`, the Guest login succeeds but the SRVSVC NetrShareEnumAll RPC (listShares) is denied (STATUS_ACCESS_DENIED), so share enumeration silently returned nothing even though `smbclient -L -N` works. Prefer a true anonymous null session first, matching smbclient -N behaviour. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- feat(output): add `--json [FILE]` to emit results as JSON Lines (share, file, content_match records). With no FILE the JSONL goes to stdout and human-readable logs are redirected to stderr; with a FILE it is appended. - feat(cli): when no content/filename/extension filter is given, enumerate and print shares for each remote target (like `smbclient -L`) instead of erroring. - fix(logging): force the "fork" multiprocessing start method. Python 3.14 changed the Linux default to "forkserver", which re-imports modules in the worker and creates a new, unlistened log queue, so no console output appeared (only the log file). Forcing fork restores the shared queue; guarded so it is a no-op on older Pythons and degrades safely where fork is unavailable. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
All contributors have signed the CLA ✍️ ✅ |
Author
|
I have read the CLA Document and I hereby sign the CLA |
bls-cla-bot Bot
added a commit
to blacklanternsecurity/CLA
that referenced
this pull request
Jun 16, 2026
Author
|
recheck |
Previously the share list was only printed in no-filter mode. When a filter was supplied, shares were enumerated but only logged at debug level. Now the enumerated shares are reported once per target at INFO and emitted as JSON share records regardless of whether filters are active. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make all JSON Lines records consistent: share, file, and content_match now each carry explicit "target" and "port" fields (plus share/path). The content_match record is emitted from the spiderling instead of the parser so the target/port/share context is available; the file record now uses the host/port directly rather than str(Target). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
content_match records now carry a "matches" array with the exact substrings that matched each pattern (deduped, capped at 20 distinct samples per pattern per file, each truncated to 256 chars). The matched substrings are recovered from the regex span against the extracted text, so no extra scanning is needed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Author
|
Here is an example of the manspider output with JSON lines are emitted to |
Each entry in a content_match record's "matches" array is now an object with
the matched string plus its 1-based location in the extracted text:
{"match": ..., "line": N, "column": N, "end_column": N}. Locations are
derived from the regex span, so no extra scanning is required.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`--extensions "ini cfg"` (a single quoted argument) now behaves the same as `--extensions ini cfg` (two arguments). Previously the quoted form became the single extension ".ini cfg", causing the search to match nothing. Each value is now split on whitespace before normalization. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A set of related fixes and features discovered while running
manspideragainst a Samba host wheresmbclient -L //host -Nlisted shares fine but manspider returned nothing.1.
fix(smb): use anonymous null session before Guest for share enumerationWhen no credentials are supplied,
login()switched to theGuestaccount and only fell back to a true null session if Guest failed. On Samba withmap to guest = Bad User, the Guest login succeeds, but the SRVSVCNetrShareEnumAllRPC (listShares) is denied withSTATUS_ACCESS_DENIED— so share enumeration silently returned nothing even thoughsmbclient -L -Nworks. Now a true anonymous null session is attempted first, matchingsmbclient -N.Verified directly with impacket against the same host:
2.
fix(logging): force theforkmultiprocessing start methodPython 3.14 changed the default start method on Linux to
forkserver, which re-imports modules in the worker process and creates a new, unlistened log queue — so no console output appeared at all (only the file log). Forcingforkrestores the shared queue between the parent'sQueueListenerand the worker'sQueueHandler. Guarded with try/except so it's a no-op on older Pythons and degrades safely whereforkis unavailable.3.
feat(cli): list shares when no filter is givenWhen none of
--filenames/--content/--extensions/--exclude-extensionsare specified, manspider now enumerates and prints the shares for each remote target (likesmbclient -L) instead of erroring out.4.
feat: always report enumerated shares while spideringPreviously the share list was only shown in no-filter mode. The enumerated shares are now reported once per target at INFO level (and emitted to JSON) regardless of whether filters are active.
5.
feat(output):--json [FILE]JSON Lines outputAdds machine-readable output.
--json FILEappends JSON Lines to a file;--jsonwith no argument writes JSONL to stdout and redirects human-readable logs to stderr (so stdout stays clean for piping).Three record types, each carrying a consistent
target+port:{"type": "share", "target": "localhost", "port": 445, "share": "myshare"} {"type": "file", "target": "localhost", "port": 445, "share": "myshare", "path": "sample.cfg", "size": 10, "downloaded": false} {"type": "content_match", "target": "localhost", "port": 445, "share": "myshare", "path": "creds.cfg", "pattern": "password=\\S+", "count": 1, "matches": [{"match": "password=Sup3rS3cret!", "line": 2, "column": 1, "end_column": 22}]}content_matchrecords include amatchesarray with the actual matched substrings and where they were found — each entry is{"match": ..., "line": N, "column": N, "end_column": N}(1-based). Samples are deduped and capped at 20 distinct matches per pattern per file (each truncated to 256 chars). The substrings and locations are recovered from the regex span against the already-extracted text, so no extra scanning is performed.Testing
All behaviours verified end-to-end against a local Samba container (
myshare, anonymous read-write): null-session enumeration, console output on Python 3.14.4, no-filter share listing, share reporting while spidering, and--jsonin both stdout and file modes including captured match strings with line/column locations.🤖 Generated with Claude Code