Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
RPC-Triage — A zero-symbol static analysis engine that extracts and mathematically ranks the Windows RPC attack surface using an AHP-based risk model. | Kitploit
Tools/GitHubGitHub/talha-nazeef-ahmed/rpc-triage
ReconnaissanceStatic AnalysisVulnerability AnalysisReverse EngineeringBinary AnalysisRed Teaming
GitHubtalha-nazeef-ahmed/rpc-triage

RPC-Triage

A zero-symbol static analysis engine that extracts and mathematically ranks the Windows RPC attack surface using an AHP-based risk model.

View Repository
144151 month agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

RPC-Triage

Static vs dynamic, read this first. It is worth being clear about the line between dynamic and static analysis up front: this tool does its ranking purely through static analysis. It reads the compiled MIDL / NDR structures straight out of the binary and never executes anything.

Static triage for the Windows RPC attack surface. Point it at a folder of PE binaries; it finds every one that registers an RPC server, recovers each interface's NDR method signatures, transport bindings and registration flags straight out of the compiled MIDL structures, and then ranks every interface by reachability x danger with a full arithmetic receipt attached to every score so you can check the math by hand.

Existing RPC tooling will happily recover an interface's method signatures and its registration flags. What none of it does is take both and answer the one question that actually decides where you spend your time: given that I can reach this interface, and given what its methods accept as input, how urgently should I look at it compared to everything else on the machine? That gap is what this fills.

What it does

  • Filters the target folder so Ghidra only ever auto-analyzes binaries that actually register an RPC server (they import rpcrt4.dll and call one of the RpcServerRegisterIf\* APIs). On System32 that is the difference between an afternoon and a week.

  • Extracts, per interface: UUID, the RPC_SERVER_INTERFACE / MIDL_SERVER_INFO chain, the authoritative DispatchTableCount, every method's opnum + parameter directions + decoded NDR opcodes, the registration flags (R9), the security-callback ("bouncer") presence, the security descriptor (best-effort), and the endpoint / transport bindings.

  • Ranks every clean interface on two independent axes and multiplies them into one 0-100 composite, bucketed Critical / High / Moderate / Low.

  • Explains itself: every score ships with a receipt string listing each component and the arithmetic that produced the final number.

How it works

target dir --(pefile filter) --> only RPC-registering PEs
          --(Ghidra headless auto-analysis) --> analyzed program DB
          --(extract_rpc_interfaces.py script) --> interfaces + NDR + flags + endpoints
          --(two-axis AHP ranking engine) --> ranked interfaces + receipts
           --> single JSON report

Zero-Symbol Dependency: A critical technical differentiator of this engine is that it operates entirely without debug symbols. By programmatically walking the dispatch tables and parsing the raw NDR (Network Data Representation) bytecodes and compiled MIDL structures directly from memory, the tool bypasses the need for Microsoft's .pdb files or live endpoint mapper queries. This guarantees the engine works out-of-the-box on stripped, production System32 binaries exactly as they ship.

Requirements

  • Ghidra 11.x (uses the bundled support/analyzeHeadless). Needs a JDK 17+ on PATH.

  • Python 3.8+ on the driver side, with pefile.

  • The extraction script runs under Ghidra's bundled Jython 2.7 - no third-party imports, nothing to install there.

  • Targets: Windows x64 PE files. Analysis itself is OS-independent (Ghidra is cross-platform), so you do not have to run this on Windows.

Install

git clone https://github.com/talha-nazeef-ahmed/RPC-Triage
cd RPC-Triage/
python -m pip install -r requirements.txt   # just pefile

requirements.txt: pefile>=2023.2.7

Usage

Everything is driven by orchestrator.py: it filters, imports, analyzes and runs the extractor for you.

python orchestrator.py \
  -t \"C:\Windows\System32\" \
  -g \"C:\ghidra_12.1.2_PUBLIC\" \
  -s \".\extract_rpc_interfaces.py\" \
  -o \".\out\report.json\" \
  --stagedir \".\out\staged\" \
  --projdir  \".\out\ghidra_proj\" \
  --projname RPC_Atlas

flagmeaning
-t / --targetfolder of binaries to scan
-g / --ghidraGhidra install folder (the one containing support/analyzeHeadless)
-s / --scriptpath to extract_rpc_interfaces.py
-o / --outputpath of the JSON report to write
--stagedirfolder the filtered RPC binaries are copied into (kept)
--projdirfolder for the persistent Ghidra project
--projnameGhidra project name (e.g. RPC_Atlas)

First run vs re-run (important). The first run does the slow part: it filters, imports the matching binaries, runs full auto-analysis, then drops a .analysisComplete marker in --projdir. Every later run against the same project skips import/analysis (-process -noanalysis) and just re-runs the script over the already-analyzed programs. So analyzing System32 is a one-time cost and iterating on output is cheap. If analysis is interrupted the marker is not written and deletes the partial project (.rep / .gpr) and starts fresh.

Output

One JSON file: a list of binaries, each with an Interfaces array. A complete run over System32 is included in this repo at output/FullBatchRun.json it is the raw, uncurated output so you can see exactly what the tool produces at scale. Per interface:

fieldmeaning
CallSiteaddress of the RpcServerRegisterIf\* call
Tag / TagDescdata-quality bucket (see below)
Rank\"{Tier}/{Composite}\", e.g. Critical/91
RankDetailthe full scoring receipt (see below)
UUIDinterface UUID
InterfaceAddress / DispatchAddressrecovered structure addresses
FunctionsCountauthoritative stored method count; may carry (FLAG: Walked X != Stored Y)
Endpointstransport / endpoint bindings
SecurityHasBouncer, SecurityDescriptor, SecureOnly, LocalCallOnly
Methodsper-opnum parameter list with decoded NDR opcodes

Tags; the data-hygiene gate:

  • Clean: recovered cleanly; ranked normally.

  • Needs-Review: ranked, but the dispatch table walk overshot the stored count (usually a trailing thunk block). The score is real but carries [Provisional]; verify the method count before you quote it.

  • Diagnostics / Diagnostics (2): the row is an extraction artifact (an ASCII string mislatched as a UUID and/or a corrupt MIDL pointer). Not scored (Rank: N/A). These are kept on purpose: they report tool health, they are not attack surface.

The FLAG: Walked X != Stored Y note. The stored DispatchTableCount is authoritative and is what every score uses. The walked count is an independent executability cross-check; when the two disagree (commonly a clean 2x) the interface is tagged Needs-Review so you know to eyeball it. It never silently changes a score.

How to read a Rank receipt

This is the part that makes a score arguable:

Moderate/35 | Gate:35 [ncacn_np:41, MultiEndpointBonus:15, HasBouncer:-46, BouncerIsNotCaching:25] | Surface:100 [HasBogusStruct:1x(opnums 5):[in]:61, HasCallerSizedBuffer:5x(opnums 0,6,11):[in]:49, InPtrs:6:18, Count:12:6 -> raw:134 [capped to 100] * 1.0 -> 100] | (35 * 100) / 100 = 35 [Provisional]

Read it left to right:

Download Tool