Initial RPCScope release

This commit is contained in:
0x000 committed 2026-10-15 12:34:26 -04:00
commit 9dc7289652
40 files changed
+6688

No files matched your search

+77
View File
@@ -0,0 +1,77 @@
# Architecture
RPCScope separates collection from interpretation so that external tool changes do not silently change the meaning of a finding.
```text
targets (expanded, resolved, deduplicated, capped)
|
+-- independent TCP/135 + TCP/445 discovery
| +-- RPC-only hosts remain in scope
| +-- unreachable: stop here, retain discovery in JSON only
| +-- reachable: queue host pipelines only
+-- NetExec SMB inventory -------+
+-- enum4linux-ng JSON ----------+--> normalized HostEvidence
+-- Impacket rpcdump ------------+ |
+-- optional MSF scanner --------+ v
+-- opt-in CLDAP precondition ---+ (not a patch detector)
deterministic rules
|
+---------------+---------------+
| |
report.json report.md
```
## Trust boundaries
- Collector output is untrusted input. Parsers extract only labelled facts and never execute data from results.
- Credentials are passed to external tools only when the operator supplies them. Recorded command metadata redacts passwords.
- Live collection is gated by `--i-am-authorized`; offline analysis does not require the flag.
- A UUID match establishes interface exposure. It does not establish vulnerable code, reachable opnums, authorization, patch state, or exploitability.
- A CVE-level finding requires a purpose-built scanner result or a separately implemented, testable evidence predicate.
## Data model
`HostEvidence` is the stable seam of the project. Collectors contribute:
- identity: address, hostname, domain, OS fingerprint;
- SMB posture: SMBv1, signing, null/guest session state;
- shares: name, read/write access, comment;
- RPC surface: UUID, version, protocol label, provider, binding/endpoint;
- checks: explicit scanner name and outcome;
- check details: the actual attributed result marker and any evidence conflicts;
- collection: pending, success, failure, or skipped state for each collector;
- sources: raw artifact paths.
Rules consume only this model. They do not parse terminal output and do not invoke tools.
Dedicated checks are registered in `rpcscope/catalog.py`. CLI NetExec checks run in single-module, bounded live-host batches; unrelated modules remain separate processes. The five bind-only exposure methods share `METHOD=All` only when the complete unchanged set was selected. Each check keeps a separate normalized result. `longlogon` is native Python and estimates a naming precondition over CLDAP, not vulnerability or patch status.
The registry also distinguishes interface exposure and information gathering. Accepted RPC binds are `exposed`; spooler registrations and OXID interface results are `observed`. They become informational findings rather than CVE verdicts. `CheckAttempt` preserves backend-specific evidence, and conflicting positive/negative results are highlighted directly in minimal reports.
`advisories.py` contains a separate review-only metadata registry for 2020–2026 issues. `sync-cves` refreshes fixed Microsoft CNA records without changing `catalog.CHECKS`, importing code, or generating host vulnerability verdicts.
Discovery uses `--discovery-workers` (256 by default) for lightweight TCP probing and NetExec inventory. A check batch has at most `--jobs` live targets (8 by default, capped at 128 per command) and the same NetExec thread limit. Batches run sequentially; afterward the Python host pool has at most `--jobs` active futures. This avoids nested concurrency multiplication. Host pipelines run native/optional MSF checks, RPC dump, then optional full enum4linux. Full enum is enabled by `--deep` in the CLI; the library retains the old defaults. Dead targets never receive pending checks or host futures. TCP timeout/closed are completed reachability outcomes; an unprobed target indicates a real discovery interruption/deadline, while local resource exhaustion is explicitly a scan failure.
A thread-safe progress callback emits task start/finish events to stderr for reachable hosts and silently advances counts for unreachable ones. A separate callback publishes atomic report snapshots as host jobs finish. Parsing uses original in-memory output, while saved artifacts and check details redact supplied credentials; redaction cannot alter target addresses or detection markers before classification.
Execution completion is independent of evidence certainty. `inconclusive` and `suspected` are completed results; ordinary skipped checks are counted outside the eligible denominator. Failed processes, pending work and cancellation remain partial. Text and Markdown show reachable hosts; JSON retains the full expanded scope and all discovery states.
`netexec.py` plans batches and inspects installed CLI capabilities without importing scanner code. Help inspection is cached; read-only share semantics must be known. Output is indexed once by IP/module/port, and known zero-exit host exceptions do not masquerade as successful collection. See `NETEXEC_REVIEW.md` for pinned upstream references and verification limits.
## Rule quality bar
Every rule should include a stable ID, severity, confidence, exact evidence, impact, remediation, and a primary reference when one exists. New rules need positive and negative fixtures. Avoid CVE claims based only on banners, UUIDs, OS names, or open ports.
## NDRaider boundary
NDRaider can statically recover interface UUIDs and typed NDR method grammars from Windows binaries, then generate structure-aware fuzz inputs. That complements RPCScope in a lab workflow:
1. RPCScope observes a vendor UUID on an authorized target.
2. The assessor obtains the matching server binary through an approved process.
3. NDRaider analyzes the binary offline and exports grammar JSON.
4. A future importer correlates UUID/version/method counts with the remote observation.
5. Any live fuzzing remains a separate, explicit active-testing profile.
Keeping that boundary prevents a fast inventory scan from unexpectedly becoming a fuzzer.
See `CHECKER_POLICY.md` for the CVE synchronization and future proof-of-execution requirements.
+55
View File
@@ -0,0 +1,55 @@
# Checker and CVE policy
## Result states
Every implemented check must return an explicit state:
- `vulnerable`: the dedicated checker returned its documented positive marker;
- `not-vulnerable`: the checker completed and returned its documented negative marker;
- `suspected`: the checker found a capability or permission indicator requiring independent validation;
- `exposed`: the selected RPC interface accepted a bind; no coercion or exploitation was demonstrated;
- `observed`: inventory information was returned, such as registered spooler endpoints or advertised network interface addresses;
- `inconclusive`: the probe completed without enough evidence, including silence, access denial or an unsupported response;
- `precondition-met`, `precondition-not-met`, `precondition-borderline`: an empirical prerequisite estimate, not a vulnerability or patch verdict;
- `skipped-*`: the check could not run, for example because credentials were required.
- `pending`: the selected checker has not finished; used by live report checkpoints.
An exposed RPC UUID, OS banner, open port, or legacy protocol is an `EXPOSURE`, not a confirmed vulnerability.
`NOT VULNERABLE (SELECTED CHECKS)` is permitted only when selected vulnerability checks produced explicit negatives, no selected checks were skipped or unknown, and collection completed without evidence conflicts. Inventory and precondition results cannot independently produce that verdict. Result markers must match the expected module and host. Nonzero exits, contradictory messages, and silence cannot produce definitive results.
Execution completion and evidence certainty are separate: `suspected` and `inconclusive` count as completed checks, with uncertainty printed explicitly. Ordinary `skipped-*` results are excluded from the execution denominator and counted as `SKIPPED`; they never imply a negative. Failed processes, pending stages and cancellation still mark the scan partial. Closed/timed-out discovery services are completed reachability outcomes, not failed vulnerability checks; no host pipeline is queued without a reachable TCP/135 or TCP/445 service.
SMBGhost's dialect/compression indicator, PrintNightmare's driver-permission probe, and noPac's PAC-size heuristic produce `suspected` results. The removed NetExec NTLM reflection module is disabled pending an adapter for its replacement.
## Catalog synchronization
Metadata and executable checks have different lifecycles:
1. CVE metadata should be refreshed from the NVD CVE API.
2. Exploitation-in-the-wild priority should be overlaid from CISA's Known Exploited Vulnerabilities JSON feed.
3. Microsoft Windows applicability and remediation should link to the MSRC Update Guide.
4. RPC interface identity should link to the relevant Microsoft Open Specifications document.
5. A new CVE remains `metadata-only` until a deterministic positive and negative probe, fixtures, and target-version notes exist.
Keyword searches for “RPC,” “Netlogon,” or “spooler” are discovery aids only. They cannot safely create executable rules because CVE descriptions do not consistently identify a wire protocol, endpoint UUID, remotely observable patch signal, or non-destructive probe.
The implemented `sync-cves` command refreshes curated Microsoft CNA records only. The downloaded dataset is explicitly review-only with `scanner_coverage=false`. It never expands executable CVE/patch detection coverage or labels an individual host vulnerable. LongLogon has a precondition-only adapter included in `recommended`; its existence does not turn this metadata into a patch detector.
## LongLogon boundary
`--checks recommended` includes LongLogon's minimal CLDAP DC-locator queries on UDP/389; `--checks longlogon` selects just that adapter. It first validates an EX identity response, then conditionally measures a fixed one-character-user legacy response after a conservative baseline-size guard. It never sends a maximum-length user field or an overflow trigger. The upstream response-size extrapolation is an empirical heuristic, retained as `PRECONDITION` only. Invalid, mismatched, unsupported, timed-out or EX-only responses are `UNKNOWN`, not negative. No remote patch-state claim is made. Default TCP discovery does not cover UDP-only domain controllers whose TCP/135 and TCP/445 are both unavailable.
## Validation and exploitation
Future proof-of-execution adapters should live behind a separate command, not the scan command. The intended guardrails are:
- exactly one host and one check per invocation;
- a second explicit authorization flag;
- no CIDRs, target files, arbitrary shell commands, persistence, payload listeners, or credential dumping;
- a fixed proof that returns identity and OS/build only;
- no proof text in the report unless the target returned it;
- a target-change and cleanup declaration for every adapter;
- disabled adapters for checks whose only reliable proof risks corruption, password changes, denial of service, or persistent artifacts.
This keeps the resume project useful for validation while preventing a routine audit from silently becoming an exploitation campaign.
+73
View File
@@ -0,0 +1,73 @@
# NetExec execution review
Reviewed upstream revision: `89a698d93dfc101e7104d42523aac4765372cd7d`.
This is an interface/architecture review, not copied NetExec implementation code.
RPCScope continues to invoke the operator's installed executable.
## Findings and implementation
| Finding | RPCScope change |
| --- | --- |
| NetExec starts a protocol object per target in a thread pool, default 256 workers. | 256 lightweight discovery workers; bounded live-host batches for heavier checks. |
| Our old runner launched one NetExec process for every host/check pair. | One process per module/live-host batch, amortizing imports and initialization. |
| Full enum4linux `-A` preceded the dedicated probes. | Dedicated probes first; normal CLI leaves full enumeration to `--deep`. RPC dump remains enabled. |
| NetExec supports multiple modules per SMB session, but its module loop does not isolate arbitrary callback exceptions. | Keep unrelated modules in separate processes; no automatic retry of failed probes. |
| All five selected `coerce_plus` bind methods can use `METHOD=All` without a listener. | Combine only the complete, unchanged five-method selection. Subsets stay separate. Each method still has its own result record. |
| Current NetExec uses ACL-based share checks and opts into file writes with `--file-write-check`. Older versions offered `--no-write-check`. | Inspect installed help, select a known read-only mode, otherwise skip with an explicit error. Never enable file-write testing. |
| Admin checking adds an SCM RPC exchange; our adapters use `on_login`, not `on_admin_login`. | Use `--no-admin-check` only when the installed CLI advertises support. |
| NetExec may catch individual host exceptions and still exit zero. | Attribute known host exceptions and mark that host's check failed/unknown without invalidating other hosts. |
| Console output can contain credential echoes, truncated module labels and unrecognized messages. | Index by canonical IP/module/port once per batch; allow known label truncation; require documented full negative markers. |
| Reviewed MS17-010 and SMBGhost modules create IPv4 sockets. | Skip these adapters explicitly on IPv6 rather than pretending a checker executed successfully. |
| Local socket limits and noisy subprocesses could produce misleading outcomes or excessive temporary output. | Report local resource exhaustion as an execution failure, and actively stop over-limit output. |
## Execution and budgets
```text
scope -> TCP discovery -> NetExec inventory (open SMB listeners only)
-> same-module NetExec check batches (live, eligible hosts only)
-> bounded host pipelines: native / optional MSF / RPC / optional deep enum
-> evidence-backed reports
```
`--jobs` bounds each check batch and the later host pool; these phases do not
multiply their concurrency. Batches contain no more than 128 targets, even with
a larger jobs limit, and no more hosts than can execute in one NetExec thread
wave. A single-check process receives one check timeout. The combined five-bind
process receives five check timeouts in total; individual methods are not
independently timed inside that external process. Global batch failures remain
unknown/partial. Positive evidence is not inferred from process exit alone.
The core library keeps legacy isolated execution and full enum defaults for
compatibility. CLI defaults select batching and leave full enum to `--deep`.
`--isolated-checks` is a diagnostic fallback, not an automatic retry policy.
## Verification and limits
The mocked 32-live-host recommended scan executes 28 NetExec check invocations
instead of the old 352 (seven module groups, four eight-host batches). All twelve
selected results per host remain represented; inventory and capability-help
invocations are separate from this count. This is not a wall-clock benchmark.
Tests cover batching, selection boundaries, per-host result isolation, zero-exit
errors, cancellation, read-only share compatibility, output caps, and resource
failures. External tools are absent on the development host. Real version
interoperability, network throughput, and detection sensitivity/specificity are
not established by mocks and need an authorized, patched/unpatched lab matrix.
No live target scan was performed for this review.
A bare `nxc smb` connection/banner scan does less work than twelve selected
checks plus RPC/deep enumeration. The optimization removes avoidable overhead;
it does not remove the protocol work or turn heuristic findings into patch
proof. No scanner can promise flawless results across every network/tool build.
## Primary sources
- [Threaded target runner](https://github.com/Pennyw0rth/NetExec/blob/89a698d93dfc101e7104d42523aac4765372cd7d/nxc/netexec.py)
- [CLI worker default](https://github.com/Pennyw0rth/NetExec/blob/89a698d93dfc101e7104d42523aac4765372cd7d/nxc/cli.py)
- [Connection/module callback flow](https://github.com/Pennyw0rth/NetExec/blob/89a698d93dfc101e7104d42523aac4765372cd7d/nxc/connection.py)
- [SMB CLI and share options](https://github.com/Pennyw0rth/NetExec/blob/89a698d93dfc101e7104d42523aac4765372cd7d/nxc/protocols/smb/proto_args.py)
- [Share and admin checks](https://github.com/Pennyw0rth/NetExec/blob/89a698d93dfc101e7104d42523aac4765372cd7d/nxc/protocols/smb.py)
- [Combined bind-method interface](https://github.com/Pennyw0rth/NetExec/blob/89a698d93dfc101e7104d42523aac4765372cd7d/nxc/modules/coerce_plus.py)
- [Logger format](https://github.com/Pennyw0rth/NetExec/blob/89a698d93dfc101e7104d42523aac4765372cd7d/nxc/logger.py)
- [MS17-010 IPv4 implementation](https://github.com/Pennyw0rth/NetExec/blob/89a698d93dfc101e7104d42523aac4765372cd7d/nxc/modules/ms17-010.py)
- [SMBGhost IPv4 implementation](https://github.com/Pennyw0rth/NetExec/blob/89a698d93dfc101e7104d42523aac4765372cd7d/nxc/modules/smbghost.py)