Files
rpcscope/docs/ARCHITECTURE.md
T
2026-10-15 12:34:26 -04:00

6.2 KiB
Raw Blame History

Architecture

RPCScope separates collection from interpretation so that external tool changes do not silently change the meaning of a finding.

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.