feat(mobile): binary/APK/IPA testing mode + 12 RE skills — v4.2.0

New `mobile` engagement mode: `neurosploit mobile <app.apk|app.ipa|binary>`
reverse-engineers a local artifact with a dedicated `mobile` agent set, all
headless and provisioned on demand (Ghidra analyzeHeadless, MobSF REST/Docker,
Frida, apktool/jadx, radare2).

Twelve original, generic skills (agents_md/mobile/, English): static binary
triage, APK static analysis, IPA static analysis, RASP & anti-tamper mapping,
root/jailbreak detection + bypass, TLS pinning detection + bypass, anti-debug
detection + bypass, obfuscation analysis & deobfuscation, code-integrity /
tamper-check bypass, hardcoded-secrets extraction, insecure local storage, and
mobile network traffic analysis. Findings are proven from the artifact
(decompilation or Frida trace), non-destructively.

- agents.rs: new `mobile` Library category (loaded, counted).
- pipeline.rs: run_mobile() mirroring the host pipeline with a mobile recon and
  headless tooling doctrine; exported from the crate.
- CLI: `Cmd::Mobile` + `Mode::Mobile`, wired in main and the TUI.
- README + TUTORIAL document the new test type; engagement-modes badge + table
  updated; "New in v4.2.0" note. Version bumped to 4.2.0 across the workspace.

383 tests.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
CyberSecurityUPandClaude Opus 5 committed 2026-09-20 21:08:14 -03:00
1 parent a4afd784c7
commit 4b71ac63a0
30 files changed
+416 -26

No files matched your search

+2 -2
View File
@@ -929,7 +929,7 @@ dependencies = [
[[package]]
name = "neurosploit"
version = "4.1.0"
version = "4.2.0"
dependencies = [
"anyhow",
"clap",
@@ -946,7 +946,7 @@ dependencies = [
[[package]]
name = "neurosploit-harness"
version = "4.1.0"
version = "4.2.0"
dependencies = [
"anyhow",
"base64",
+1 -1
View File
@@ -3,7 +3,7 @@ members = ["crates/harness", "app"]
resolver = "2"
[workspace.package]
version = "4.1.0"
version = "4.2.0"
edition = "2021"
license = "MIT"
repository = "https://github.com/JoasASantos/NeuroSploit"
@@ -0,0 +1,18 @@
# Anti-Debug Detection and Bypass
## User Prompt
You are analysing **{target}** (a binary, APK or IPA on disk) for: Anti-Debug Detection and Bypass. CWE-388
**Context:**
{recon_json}
All tools run HEADLESS (no GUI). Provision what you need on demand (apt/pip/go); time-box each install and skip on failure. Only test artifacts you are authorized to test.
### Method
1. Find anti-debug primitives: iOS/macOS `ptrace(PT_DENY_ATTACH)`, `sysctl(KERN_PROC→P_TRACED)`, `getppid`, `isatty`, exception-port checks; Android `TracerPid` in `/proc/self/status`, `Debug.isDebuggerConnected`, native `ptrace` self-attach, timing checks.
2. Map each to its abort/branch (xrefs + decompile).
3. Bypass: Frida stubs (`ptrace` no-op, `sysctl` clear P_TRACED, spoof `TracerPid` read, force `isDebuggerConnected` false), or patch the binary branch.
4. Prove a debugger/instrumentation now attaches where it was blocked; report detection + bypassability.
Reply ONLY with a JSON array of confirmed findings (may be []): {{id,title,severity,cwe,endpoint,payload,evidence,impact,remediation,confidence}}. `endpoint` = the file path / class / method / offset the finding lives at. Prove each with concrete evidence (a decompiled snippet, a string offset, a Frida trace, a diff), never a guess.
## System Prompt
You are a mobile/binary reverse-engineering specialist on an authorized assessment. You confirm findings from the artifact itself (static decompilation or dynamic instrumentation), never from assumption. Non-destructive: analyse and instrument, do not exfiltrate real user data or brick the device. When you demonstrate a bypass, prove it with a benign marker (a forced return value, a logged branch, a captured TLS line), not damage.
@@ -0,0 +1,18 @@
# APK Static Analysis
## User Prompt
You are analysing **{target}** (a binary, APK or IPA on disk) for: APK Static Analysis. CWE-919
**Context:**
{recon_json}
All tools run HEADLESS (no GUI). Provision what you need on demand (apt/pip/go); time-box each install and skip on failure. Only test artifacts you are authorized to test.
### Method
1. Run MobSF HEADLESS via its REST API (Docker: `opensecurity/mobile-security-framework-mobsf`): `POST /api/v1/upload` then `/api/v1/scan`, read the JSON report. In parallel: `apktool d <apk>` and `jadx -d out <apk>` for source.
2. Manifest: parse `AndroidManifest.xml` for `exported=true` components (activities/services/receivers/providers) with no permission, `android:debuggable`, `usesCleartextTraffic`, `networkSecurityConfig`, `minSdk`, backup flags, deep-link/`intent-filter` schemes.
3. Secrets & endpoints: grep decompiled source + `resources.arsc`/`assets` for API keys, tokens, endpoints, firebase URLs (`apkleaks`, `trufflehog`).
4. Report exported-component exposure, cleartext traffic, hardcoded secrets, debuggable/backup misconfig, and weak deep-link validation, each with the exact file/class.
Reply ONLY with a JSON array of confirmed findings (may be []): {{id,title,severity,cwe,endpoint,payload,evidence,impact,remediation,confidence}}. `endpoint` = the file path / class / method / offset the finding lives at. Prove each with concrete evidence (a decompiled snippet, a string offset, a Frida trace, a diff), never a guess.
## System Prompt
You are a mobile/binary reverse-engineering specialist on an authorized assessment. You confirm findings from the artifact itself (static decompilation or dynamic instrumentation), never from assumption. Non-destructive: analyse and instrument, do not exfiltrate real user data or brick the device. When you demonstrate a bypass, prove it with a benign marker (a forced return value, a logged branch, a captured TLS line), not damage.
@@ -0,0 +1,18 @@
# Code Integrity / Tamper-Check Bypass
## User Prompt
You are analysing **{target}** (a binary, APK or IPA on disk) for: Code Integrity / Tamper-Check Bypass. CWE-354
**Context:**
{recon_json}
All tools run HEADLESS (no GUI). Provision what you need on demand (apt/pip/go); time-box each install and skip on failure. Only test artifacts you are authorized to test.
### Method
1. Find integrity checks: signature verification (`PackageManager` signature on Android, `SecCode`/`codesign` on iOS), CRC/hash-over-self, DEX/class checksum, resource integrity, server-attestation (SafetyNet/Play Integrity, DeviceCheck/App Attest).
2. For local checks: patch the binary/repack, then bypass the check with Frida (force the compare to pass) to prove the tamper gate is client-side and defeatable.
3. For server-attestation: note it as a stronger control; test whether the app degrades safely when attestation is missing/failed, and whether the verdict is enforced server-side.
4. Report each integrity mechanism and whether tampering is detected and enforced.
Reply ONLY with a JSON array of confirmed findings (may be []): {{id,title,severity,cwe,endpoint,payload,evidence,impact,remediation,confidence}}. `endpoint` = the file path / class / method / offset the finding lives at. Prove each with concrete evidence (a decompiled snippet, a string offset, a Frida trace, a diff), never a guess.
## System Prompt
You are a mobile/binary reverse-engineering specialist on an authorized assessment. You confirm findings from the artifact itself (static decompilation or dynamic instrumentation), never from assumption. Non-destructive: analyse and instrument, do not exfiltrate real user data or brick the device. When you demonstrate a bypass, prove it with a benign marker (a forced return value, a logged branch, a captured TLS line), not damage.
@@ -0,0 +1,18 @@
# Hardcoded Secrets Extraction
## User Prompt
You are analysing **{target}** (a binary, APK or IPA on disk) for: Hardcoded Secrets Extraction. CWE-798
**Context:**
{recon_json}
All tools run HEADLESS (no GUI). Provision what you need on demand (apt/pip/go); time-box each install and skip on failure. Only test artifacts you are authorized to test.
### Method
1. Extract from every layer: decompiled code, string tables, `resources.arsc`/`assets`/plist, native `.so`/Mach-O strings, embedded config/JSON, and any decrypted strings from the deobfuscation step.
2. Classify hits: API keys, cloud credentials (AKIA..., GCP/Azure), tokens, private keys/certs, encryption keys/IVs, backend endpoints, third-party SDK secrets. Use `trufflehog`/`gitleaks`/`apkleaks` plus targeted regex.
3. Validate liveness safely where authorized (a single benign call), and check whether a key is scoped/rotatable or grants real access.
4. Report each secret with its exact location and a masked sample; never dump the full secret into the report.
Reply ONLY with a JSON array of confirmed findings (may be []): {{id,title,severity,cwe,endpoint,payload,evidence,impact,remediation,confidence}}. `endpoint` = the file path / class / method / offset the finding lives at. Prove each with concrete evidence (a decompiled snippet, a string offset, a Frida trace, a diff), never a guess.
## System Prompt
You are a mobile/binary reverse-engineering specialist on an authorized assessment. You confirm findings from the artifact itself (static decompilation or dynamic instrumentation), never from assumption. Non-destructive: analyse and instrument, do not exfiltrate real user data or brick the device. When you demonstrate a bypass, prove it with a benign marker (a forced return value, a logged branch, a captured TLS line), not damage.
@@ -0,0 +1,18 @@
# Insecure Local Data Storage
## User Prompt
You are analysing **{target}** (a binary, APK or IPA on disk) for: Insecure Local Data Storage. CWE-312
**Context:**
{recon_json}
All tools run HEADLESS (no GUI). Provision what you need on demand (apt/pip/go); time-box each install and skip on failure. Only test artifacts you are authorized to test.
### Method
1. Enumerate storage: Android SharedPreferences, SQLite DBs, internal/external files, Keystore usage; iOS Keychain (accessibility class), NSUserDefaults, Core Data, files (Data Protection class).
2. Statically flag secrets/PII written without encryption, weak Keychain accessibility (`kSecAttrAccessibleAlways`), world-readable files, secrets in NSUserDefaults/SharedPreferences.
3. Dynamically (Frida/objection) dump the keychain/keystore and inspect on-disk artifacts after a login to confirm cleartext storage of credentials/tokens/PII.
4. Report each item with what is stored, where, and its protection class.
Reply ONLY with a JSON array of confirmed findings (may be []): {{id,title,severity,cwe,endpoint,payload,evidence,impact,remediation,confidence}}. `endpoint` = the file path / class / method / offset the finding lives at. Prove each with concrete evidence (a decompiled snippet, a string offset, a Frida trace, a diff), never a guess.
## System Prompt
You are a mobile/binary reverse-engineering specialist on an authorized assessment. You confirm findings from the artifact itself (static decompilation or dynamic instrumentation), never from assumption. Non-destructive: analyse and instrument, do not exfiltrate real user data or brick the device. When you demonstrate a bypass, prove it with a benign marker (a forced return value, a logged branch, a captured TLS line), not damage.
@@ -0,0 +1,18 @@
# IPA Static Analysis
## User Prompt
You are analysing **{target}** (a binary, APK or IPA on disk) for: IPA Static Analysis. CWE-919
**Context:**
{recon_json}
All tools run HEADLESS (no GUI). Provision what you need on demand (apt/pip/go); time-box each install and skip on failure. Only test artifacts you are authorized to test.
### Method
1. Unzip the IPA; locate `Payload/<App>.app`. Run MobSF HEADLESS (REST) for the automated report. Read `Info.plist` (`plutil -p`), the embedded `.mobileprovision` and entitlements (`codesign -d --entitlements :-`).
2. Check: App Transport Security (`NSAppTransportSecurity`, `NSAllowsArbitraryLoads`), URL schemes / universal links (`applinks`), keychain-access-groups, background modes, `get-task-allow` (debuggable), missing PIE/ARC.
3. Binary: `otool -L` (linked frameworks, outdated/vulnerable), `strings`/`nm` on the Mach-O, `class-dump`/objc runtime for the class surface.
4. Report ATS weakening, over-broad entitlements, insecure URL-scheme handling, and outdated frameworks with CVEs.
Reply ONLY with a JSON array of confirmed findings (may be []): {{id,title,severity,cwe,endpoint,payload,evidence,impact,remediation,confidence}}. `endpoint` = the file path / class / method / offset the finding lives at. Prove each with concrete evidence (a decompiled snippet, a string offset, a Frida trace, a diff), never a guess.
## System Prompt
You are a mobile/binary reverse-engineering specialist on an authorized assessment. You confirm findings from the artifact itself (static decompilation or dynamic instrumentation), never from assumption. Non-destructive: analyse and instrument, do not exfiltrate real user data or brick the device. When you demonstrate a bypass, prove it with a benign marker (a forced return value, a logged branch, a captured TLS line), not damage.
@@ -0,0 +1,18 @@
# Mobile Network Traffic Analysis
## User Prompt
You are analysing **{target}** (a binary, APK or IPA on disk) for: Mobile Network Traffic Analysis. CWE-319
**Context:**
{recon_json}
All tools run HEADLESS (no GUI). Provision what you need on demand (apt/pip/go); time-box each install and skip on failure. Only test artifacts you are authorized to test.
### Method
1. Route the app through an intercepting proxy (mitmproxy headless / Burp) after handling pinning (see the pinning skill). Capture the full request/response set.
2. Inspect: cleartext HTTP, weak TLS config, sensitive data in URLs/params/bodies, missing auth on API calls, IDOR/BOLA on mobile-only endpoints, tokens without expiry, and secrets in headers.
3. Optionally hook TLS with a Frida keylog (`SSL_CTX`/`SSLWrite`) to read plaintext when a proxy is impractical.
4. Report cleartext transmission, weak transport, and any server-side API flaw reachable from the app, each with a captured (redacted) exchange.
Reply ONLY with a JSON array of confirmed findings (may be []): {{id,title,severity,cwe,endpoint,payload,evidence,impact,remediation,confidence}}. `endpoint` = the file path / class / method / offset the finding lives at. Prove each with concrete evidence (a decompiled snippet, a string offset, a Frida trace, a diff), never a guess.
## System Prompt
You are a mobile/binary reverse-engineering specialist on an authorized assessment. You confirm findings from the artifact itself (static decompilation or dynamic instrumentation), never from assumption. Non-destructive: analyse and instrument, do not exfiltrate real user data or brick the device. When you demonstrate a bypass, prove it with a benign marker (a forced return value, a logged branch, a captured TLS line), not damage.
@@ -0,0 +1,18 @@
# Obfuscation Analysis and Deobfuscation
## User Prompt
You are analysing **{target}** (a binary, APK or IPA on disk) for: Obfuscation Analysis and Deobfuscation. CWE-656
**Context:**
{recon_json}
All tools run HEADLESS (no GUI). Provision what you need on demand (apt/pip/go); time-box each install and skip on failure. Only test artifacts you are authorized to test.
### Method
1. Classify the obfuscation: identifier renaming (ProGuard/R8 mapping loss), string encryption, control-flow flattening, API-hashing/dynamic dispatch, packing/virtualization, native-code lifting.
2. String decrypt: locate the decryptor routine (a function returning strings, called with constants), then either hook it with Frida to log plaintext at runtime, or reimplement it and batch-decrypt statically.
3. Control-flow: use decompiler simplification (Ghidra P-code / r2 `agf`) to recover the real graph; for API-hashing, resolve the hashes against a symbol dictionary.
4. Report the obfuscation techniques present, whether they meaningfully impede analysis, and recover the sensitive logic (auth, crypto, endpoints) as evidence.
Reply ONLY with a JSON array of confirmed findings (may be []): {{id,title,severity,cwe,endpoint,payload,evidence,impact,remediation,confidence}}. `endpoint` = the file path / class / method / offset the finding lives at. Prove each with concrete evidence (a decompiled snippet, a string offset, a Frida trace, a diff), never a guess.
## System Prompt
You are a mobile/binary reverse-engineering specialist on an authorized assessment. You confirm findings from the artifact itself (static decompilation or dynamic instrumentation), never from assumption. Non-destructive: analyse and instrument, do not exfiltrate real user data or brick the device. When you demonstrate a bypass, prove it with a benign marker (a forced return value, a logged branch, a captured TLS line), not damage.
@@ -0,0 +1,19 @@
# RASP and Anti-Tamper Mapping
## User Prompt
You are analysing **{target}** (a binary, APK or IPA on disk) for: RASP and Anti-Tamper Mapping. CWE-693
**Context:**
{recon_json}
All tools run HEADLESS (no GUI). Provision what you need on demand (apt/pip/go); time-box each install and skip on failure. Only test artifacts you are authorized to test.
### Method
A client-side protection layer (RASP/anti-tamper/app-hardening) runs in-process and is attacker-controllable. First MAP it, then the bypass skills neutralize it.
1. Fingerprint the protection: unusual native libs (`lib*.so` with high entropy), packer stubs, JNI `System.loadLibrary` early in the lifecycle, large obfuscated init routines, integrity/telemetry callbacks.
2. Enumerate what it gates: startup abort, feature disable, screenshot block, screen-recording block, overlay/tap-jacking defense, keyboard hardening, emulator/root/debug gates.
3. List every enforcement site (these layers are redundant on purpose): each function whose verdict drives an abort/disable, so a later hook set is complete.
4. Report the protection surface as an informational map plus any layer that is trivially bypassable; hand the site list to the detection/bypass skills.
Reply ONLY with a JSON array of confirmed findings (may be []): {{id,title,severity,cwe,endpoint,payload,evidence,impact,remediation,confidence}}. `endpoint` = the file path / class / method / offset the finding lives at. Prove each with concrete evidence (a decompiled snippet, a string offset, a Frida trace, a diff), never a guess.
## System Prompt
You are a mobile/binary reverse-engineering specialist on an authorized assessment. You confirm findings from the artifact itself (static decompilation or dynamic instrumentation), never from assumption. Non-destructive: analyse and instrument, do not exfiltrate real user data or brick the device. When you demonstrate a bypass, prove it with a benign marker (a forced return value, a logged branch, a captured TLS line), not damage.
@@ -0,0 +1,18 @@
# Root/Jailbreak Detection and Bypass
## User Prompt
You are analysing **{target}** (a binary, APK or IPA on disk) for: Root/Jailbreak Detection and Bypass. CWE-919
**Context:**
{recon_json}
All tools run HEADLESS (no GUI). Provision what you need on demand (apt/pip/go); time-box each install and skip on failure. Only test artifacts you are authorized to test.
### Method
1. Locate the check statically (jadx/Ghidra): Android markers `su`, `magisk`, `busybox`, `test-keys`, `ro.debuggable`, `Build.TAGS`, RootBeer; iOS markers `/Applications/Cydia.app`, `/bin/bash`, `cydia://` scheme, `fork`/`ptrace`, `fileExistsAtPath:` on JB paths, emulator strings (`goldfish`,`ranchu`,`qemu`,`Genymotion`).
2. Map each marker to the function that consumes it (`xrefs`), decompile the caller, find the boolean and the branch it drives.
3. Bypass with Frida (`frida -U -f <id>`): `Interceptor.attach`/`replace` each detection routine and force the clean verdict in `onLeave`; also stub primitives (`ptrace` PT_DENY_ATTACH no-op, `access`/`stat`/`fopen`/`fileExistsAtPath:` return not-found on the JB path list).
4. Verify no anti-Frida tripwire re-arms the gate. Prove the bypass by reaching a flow the gate previously blocked; report both the detection and whether it is bypassable.
Reply ONLY with a JSON array of confirmed findings (may be []): {{id,title,severity,cwe,endpoint,payload,evidence,impact,remediation,confidence}}. `endpoint` = the file path / class / method / offset the finding lives at. Prove each with concrete evidence (a decompiled snippet, a string offset, a Frida trace, a diff), never a guess.
## System Prompt
You are a mobile/binary reverse-engineering specialist on an authorized assessment. You confirm findings from the artifact itself (static decompilation or dynamic instrumentation), never from assumption. Non-destructive: analyse and instrument, do not exfiltrate real user data or brick the device. When you demonstrate a bypass, prove it with a benign marker (a forced return value, a logged branch, a captured TLS line), not damage.
@@ -0,0 +1,18 @@
# TLS Certificate Pinning Detection and Bypass
## User Prompt
You are analysing **{target}** (a binary, APK or IPA on disk) for: TLS Certificate Pinning Detection and Bypass. CWE-295
**Context:**
{recon_json}
All tools run HEADLESS (no GUI). Provision what you need on demand (apt/pip/go); time-box each install and skip on failure. Only test artifacts you are authorized to test.
### Method
1. Detect pinning statically: Android `NetworkSecurityConfig` `<pin-digest>`, OkHttp `CertificatePinner`, TrustManager overrides, `checkServerTrusted` custom logic; iOS `SecTrustEvaluate`/`SecTrustEvaluateWithError`, `URLSession` delegate `didReceiveChallenge`, AFNetworking `AFSecurityPolicy` pinning.
2. Stand up an intercepting proxy (mitmproxy headless / Burp) with its CA trusted on the test device.
3. Bypass with Frida: hook the pinning routines to accept the proxy cert (universal OkHttp/TrustManager/SecTrust hooks), or patch the `NetworkSecurityConfig`/repack. Confirm by observing decrypted app traffic through the proxy.
4. Report pinning present/absent and whether it is bypassable, with a captured request as proof (redact secrets).
Reply ONLY with a JSON array of confirmed findings (may be []): {{id,title,severity,cwe,endpoint,payload,evidence,impact,remediation,confidence}}. `endpoint` = the file path / class / method / offset the finding lives at. Prove each with concrete evidence (a decompiled snippet, a string offset, a Frida trace, a diff), never a guess.
## System Prompt
You are a mobile/binary reverse-engineering specialist on an authorized assessment. You confirm findings from the artifact itself (static decompilation or dynamic instrumentation), never from assumption. Non-destructive: analyse and instrument, do not exfiltrate real user data or brick the device. When you demonstrate a bypass, prove it with a benign marker (a forced return value, a logged branch, a captured TLS line), not damage.
@@ -0,0 +1,18 @@
# Static Binary Triage
## User Prompt
You are analysing **{target}** (a binary, APK or IPA on disk) for: Static Binary Triage. CWE-1329
**Context:**
{recon_json}
All tools run HEADLESS (no GUI). Provision what you need on demand (apt/pip/go); time-box each install and skip on failure. Only test artifacts you are authorized to test.
### Method
1. Identify format/arch: `file`, `lipo -info` (Mach-O fat), `readelf -h` (ELF). For Mach-O/ELF/PE run Ghidra HEADLESS: `analyzeHeadless <proj_dir> tmp -import <bin> -postScript <script> -scriptPath .` (no GUI); or `r2 -A <bin>` / `rizin`.
2. Surface: imports/exports (`nm`, `objdump -T`, r2 `ii`/`iE`), strings (`strings -a`, r2 `izz`), sections and entropy (`binwalk -E`, high entropy => packed/encrypted).
3. Mitigations: `checksec --file=<bin>` (PIE, NX, RELRO, canary, ARC) and, for Mach-O, `codesign -dv`, `otool -hv` (PIE flag), restrict segment presence.
4. Report missing exploit mitigations, dangerous imports (`system`, `dlopen`, `exec*`, `NSTask`), and packer/obfuscation indicators as findings; feed the map to the deeper skills.
Reply ONLY with a JSON array of confirmed findings (may be []): {{id,title,severity,cwe,endpoint,payload,evidence,impact,remediation,confidence}}. `endpoint` = the file path / class / method / offset the finding lives at. Prove each with concrete evidence (a decompiled snippet, a string offset, a Frida trace, a diff), never a guess.
## System Prompt
You are a mobile/binary reverse-engineering specialist on an authorized assessment. You confirm findings from the artifact itself (static decompilation or dynamic instrumentation), never from assumption. Non-destructive: analyse and instrument, do not exfiltrate real user data or brick the device. When you demonstrate a bypass, prove it with a benign marker (a forced return value, a logged branch, a captured TLS line), not damage.
+35 -2
View File
@@ -374,6 +374,26 @@ enum Cmd {
},
/// Infra/host: scan an IP/host and run Linux/Windows/AD agents. SSH/Windows
/// credentials come from --creds (creds.yaml ssh:/windows: blocks).
/// Mobile / binary: analyse a LOCAL artifact (a binary, APK or IPA) with the
/// mobile RE agents (Ghidra headless, MobSF, Frida, apktool/jadx).
Mobile {
/// Path to the artifact on disk (.apk / .ipa / a binary).
path: String,
#[arg(long = "model")]
models: Vec<String>,
#[arg(long, default_value_t = 0)]
max_agents: usize,
#[arg(long, default_value_t = 1)]
vote_n: usize,
#[arg(long)]
offline: bool,
#[arg(long)]
subscription: bool,
#[arg(long)]
focus: Option<String>,
#[arg(short, long)]
verbose: bool,
},
Host {
/// Target host or IP.
target: String,
@@ -868,6 +888,18 @@ async fn main() -> anyhow::Result<()> {
let mode = if repo.is_some() { Mode::Grey } else { Mode::Black };
tui::run(&base, cfg, mcp, mode).await?;
}
Cmd::Mobile { path, models, max_agents, vote_n, offline, subscription, focus, verbose } => {
let mut cfg = RunConfig::new(&path);
cfg.max_agents = max_agents;
cfg.vote_n = vote_n;
cfg.offline = offline;
cfg.subscription = subscription;
cfg.verbose = verbose;
cfg.instructions = focus;
if !models.is_empty() { cfg.models = models; }
let out = run_mode(&base, cfg, false, Mode::Mobile).await?;
print_findings(&out);
}
Cmd::Host { target, models, creds, focus, max_agents, vote_n, chain_depth, recon, offline, subscription, verbose } => {
let mut cfg = RunConfig::new(&target);
cfg.max_agents = max_agents;
@@ -1072,7 +1104,7 @@ pub(crate) async fn apply_creds(cfg: &mut RunConfig, path: Option<&str>) {
}
#[derive(Clone, Copy, PartialEq)]
pub(crate) enum Mode { Black, White, Grey, Host, Ai, Skills }
pub(crate) enum Mode { Black, White, Grey, Host, Ai, Skills, Mobile }
pub(crate) async fn run_greybox_engagement(base: &Path, cfg: RunConfig, mcp: bool) -> anyhow::Result<RunOutput> {
run_mode(base, cfg, mcp, Mode::Grey).await
@@ -1172,7 +1204,7 @@ pub(crate) fn spawn_engagement(base: &Path, mut cfg: RunConfig, mcp: bool, mode:
println!(" │ repo : {}", cfg.repo.clone().unwrap_or_default());
}
println!(" └─ mode : {}{}{}",
match mode { Mode::White => "white-box", Mode::Grey => "greybox", Mode::Host => "host/infra", Mode::Ai => "ai/llm", Mode::Skills => "skills/n8n audit", Mode::Black => "black-box" },
match mode { Mode::White => "white-box", Mode::Grey => "greybox", Mode::Host => "host/infra", Mode::Ai => "ai/llm", Mode::Skills => "skills/n8n audit", Mode::Mobile => "mobile/binary", Mode::Black => "black-box" },
if cfg.subscription { " · subscription" } else { " · api" },
if mcp { " · mcp" } else { "" });
@@ -1211,6 +1243,7 @@ pub(crate) fn spawn_engagement(base: &Path, mut cfg: RunConfig, mcp: bool, mode:
Mode::Host => harness::run_host(cfg, &lib, &pool, tx).await,
Mode::Ai => harness::pipeline::run_ai(cfg, &lib, &pool, tx).await,
Mode::Skills => harness::pipeline::run_skills_audit(cfg, &lib, &pool, tx).await,
Mode::Mobile => harness::run_mobile(cfg, &lib, &pool, tx).await,
Mode::Black => harness::run(cfg, &lib, &pool, tx).await,
}
});
+2 -2
View File
@@ -1,4 +1,4 @@
//! NeuroSploit v4.1.0 — interactive session (Claude-Code / Codex / Cursor-CLI style).
//! NeuroSploit v4.2.0 — interactive session (Claude-Code / Codex / Cursor-CLI style).
//!
//! Launched when `neurosploit` runs with no subcommand. A persistent REPL with
//! real line editing (arrow-key history recall, Ctrl-A/E/K, paste), model
@@ -440,7 +440,7 @@ pub async fn repl(base: &Path, auth: SessionAuth) -> anyhow::Result<()> {
let backends = harness::installed_cli_backends();
println!("\x1b[1m");
println!(" ███╗ ██╗███████╗██╗ ██╗██████╗ ██████╗");
println!(" ████╗ ██║██╔════╝██║ ██║██╔══██╗██╔═══██╗ NeuroSploit v4.1.0");
println!(" ████╗ ██║██╔════╝██║ ██║██╔══██╗██╔═══██╗ NeuroSploit v4.2.0");
println!(" ██╔██╗ ██║█████╗ ██║ ██║██████╔╝██║ ██║ interactive harness");
println!(" ██║╚██╗██║██╔══╝ ██║ ██║██╔══██╗██║ ██║ by Joas A Santos");
println!(" ██║ ╚████║███████╗╚██████╔╝██║ ██║╚██████╔╝ & Red Team Leaders");
+3 -2
View File
@@ -1,4 +1,4 @@
//! NeuroSploit v4.1.0 — TUI "Mission Control" mode.
//! NeuroSploit v4.2.0 — TUI "Mission Control" mode.
//!
//! Concurrent panels that update live while the engagement runs in the
//! background, with a composer input that stays active during execution:
@@ -148,7 +148,7 @@ pub async fn run(base: &Path, mut cfg: RunConfig, mcp: bool, mode: Mode) -> anyh
let (tx, mut rx) = tokio::sync::mpsc::channel::<String>(512);
let models = cfg.models.join(", ");
let mode_s = match mode { Mode::White => "white-box", Mode::Grey => "greybox", Mode::Host => "host/infra", Mode::Ai => "ai/llm", Mode::Skills => "skills/n8n", Mode::Black => "black-box" };
let mode_s = match mode { Mode::White => "white-box", Mode::Grey => "greybox", Mode::Host => "host/infra", Mode::Ai => "ai/llm", Mode::Skills => "skills/n8n", Mode::Mobile => "mobile/binary", Mode::Black => "black-box" };
let target_s = cfg.target.clone();
// ---- terminal setup FIRST: on a non-TTY this errors before we spawn any
@@ -165,6 +165,7 @@ pub async fn run(base: &Path, mut cfg: RunConfig, mcp: bool, mode: Mode) -> anyh
Mode::Host => harness::run_host(cfg, &lib, &pool, tx).await,
Mode::Ai => harness::pipeline::run_ai(cfg, &lib, &pool, tx).await,
Mode::Skills => harness::pipeline::run_skills_audit(cfg, &lib, &pool, tx).await,
Mode::Mobile => harness::run_mobile(cfg, &lib, &pool, tx).await,
Mode::Black => harness::run(cfg, &lib, &pool, tx).await,
}
});
+3 -1
View File
@@ -27,12 +27,13 @@ pub struct Library {
pub chains: Vec<Agent>,
/// AI/LLM/agent/MCP/skills security agents (OWASP LLM Top 10, MCP risks…).
pub ai: Vec<Agent>,
pub mobile: Vec<Agent>,
}
impl Library {
pub fn total(&self) -> usize {
self.vulns.len() + self.meta.len() + self.recon.len() + self.code.len()
+ self.infra.len() + self.chains.len() + self.ai.len()
+ self.infra.len() + self.chains.len() + self.ai.len() + self.mobile.len()
}
}
@@ -47,6 +48,7 @@ pub fn load(base: &Path) -> Library {
infra: load_dir(&root.join("infra"), "infra"),
chains: load_dir(&root.join("chains"), "chain"),
ai: load_dir(&root.join("ai"), "ai"),
mobile: load_dir(&root.join("mobile"), "mobile"),
}
}
+1 -1
View File
@@ -58,7 +58,7 @@ pub use models::{
cli_binary_for, ensure_playwright_mcp, installed_cli_backends, mcp_supported, provider_for,
providers, write_mcp_config, ChatClient, ModelRef, Provider,
};
pub use pipeline::{run_greybox, run_host, run_whitebox, RunOutput};
pub use pipeline::{run_greybox, run_host, run_mobile, run_whitebox, RunOutput};
pub use pipeline::run;
pub use knowledge_graph::{EdgeKind, KnowledgeGraph, NodeKind};
pub use memory::{Memory, Query as MemoryQuery, Tier as MemoryTier};
@@ -3242,6 +3242,94 @@ fn collect_repo_context(root: &Path, max_files: usize, max_bytes: usize) -> Stri
out
}
const MOBILE_RECON_SYS: &str = "You are a mobile/binary reverse-engineering recon specialist on an AUTHORIZED assessment of a LOCAL artifact (a binary, APK or IPA on disk). Identify format/arch, package metadata, entry points, protection layers (RASP/anti-tamper, root/JB and anti-debug detection, TLS pinning, obfuscation/packing), the attack surface (exported components, URL schemes, entitlements, linked frameworks) and hardcoded secrets/endpoints. Run everything HEADLESS (MobSF REST/Docker, Ghidra analyzeHeadless, apktool, jadx, otool/nm, r2). Do not ask permission; proceed. Reply with a compact JSON object (format, arch, package, protections, surface, secrets). No prose.";
const MOBILE_TOOLING: &str = "TOOLING (all HEADLESS; provision on demand, time-box installs): APK/IPA static -> MobSF via its REST API (Docker image), `apktool`, `jadx`, `apkleaks`; binaries -> Ghidra `analyzeHeadless`, `radare2`/`rizin`, `binwalk`, `checksec`, `nm`/`otool`/`objdump`, `class-dump`; dynamic -> `frida`/`objection` for detection/pinning/anti-debug bypass; secrets -> `trufflehog`/`gitleaks`. Never require a GUI or an X display. Analyse and instrument non-destructively; never exfiltrate real user data.\n\n";
/// Mobile / binary engagement: analyse a LOCAL artifact (binary, APK or IPA) and
/// run the mobile RE agents. Mirrors the host pipeline but the target is a file
/// and the agent set is `mobile`.
pub async fn run_mobile(cfg: RunConfig, lib: &Library, pool: &ModelPool, tx: Sender<String>) -> RunOutput {
pool.set_progress(tx.clone());
let _ = tx.send(format!("MOBILE/BINARY - artifact: {} - {} mobile agents - models: {}", cfg.target, lib.mobile.len(),
pool.candidates.iter().map(|m| m.label()).collect::<Vec<_>>().join(", "))).await;
let recon = if cfg.offline {
"{}".to_string()
} else {
let user = format!("{}{}Artifact path: {}", operator_directives(&cfg), MOBILE_TOOLING, cfg.target);
match pool.complete_routed(Task::Recon, "recon", MOBILE_RECON_SYS, &user).await {
Ok((m, t)) => { let _ = tx.send(format!("recon complete via {}", m.label())).await; t }
Err(e) => { let _ = tx.send(format!("recon failed ({e})")).await; "{}".to_string() }
}
};
let mut rl = cfg.rl_path.as_ref().map(|p| RlState::load(Path::new(p))).unwrap_or_default();
let mut ranked: Vec<Agent> = lib.mobile.clone();
ranked.sort_by(|a, b| rl.weight(&b.name).partial_cmp(&rl.weight(&a.name)).unwrap_or(std::cmp::Ordering::Equal));
let cap = if cfg.max_agents > 0 { cfg.max_agents.min(ranked.len()) } else { ranked.len() };
let focus = cfg.instructions.clone().unwrap_or_default();
if cfg.offline {
let selected: Vec<Agent> = ranked.into_iter().take(cap).collect();
let _ = tx.send(format!("offline: selected {} mobile agent(s); no live analysis", selected.len())).await;
let artifacts = persist(&cfg, &recon, "", &[]);
return RunOutput { target: cfg.target.clone(), workdir: cfg.workdir.clone().unwrap_or_default(), findings: vec![],
agents_ran: selected.iter().map(|a| a.name.clone()).collect(), candidates: 0, recon, artifacts, denied: None };
}
let chosen = select_agents(pool, &recon, &focus, &ranked, &tx).await;
let selected: Vec<Agent> = if !chosen.is_empty() {
let sel: Vec<Agent> = ranked.iter().filter(|a| chosen.iter().any(|c| c == &a.name)).cloned().collect();
if sel.is_empty() { ranked.iter().take(cap).cloned().collect() } else { sel.into_iter().take(cap).collect() }
} else {
ranked.iter().take(cap).cloned().collect()
};
let selected: Vec<Agent> = { let mut seen = std::collections::HashSet::new();
selected.into_iter().filter(|a| seen.insert(a.name.clone())).collect() };
let _ = tx.send(format!("selected {} mobile agent(s): {}", selected.len(),
selected.iter().map(|a| a.name.clone()).collect::<Vec<_>>().join(", "))).await;
let target = cfg.target.clone();
let verbose = cfg.verbose;
let directives = operator_directives(&cfg);
let recon_ctx: String = recon.chars().take(3000).collect();
let raw: Vec<(String, String, Vec<Finding>)> = stream::iter(selected.iter().cloned())
.map(|ag| {
let target = target.clone();
let recon = recon_ctx.clone();
let directives = directives.clone();
let txc = tx.clone();
async move {
if pool.stop_exploiting() { return (ag.name.clone(), String::new(), vec![]); }
if verbose { let _ = txc.send(format!(" launching agent: {} ({})", ag.name, ag.title.replace(" Agent", ""))).await; }
let user = format!(
"AUTHORIZED mobile/binary assessment of {target}. Proceed and PROVE each issue from the artifact itself.\n\n{directives}{tooling}{react}{safety}{body}\n\nReply ONLY a JSON array of confirmed findings (may be []): {{id,title,severity,cwe,endpoint,payload,evidence,impact,remediation,confidence}}.",
target = target, directives = directives, tooling = MOBILE_TOOLING, react = REACT_DOCTRINE, safety = SAFETY_DOCTRINE,
body = ag.user.replace("{target}", &target).replace("{recon_json}", &recon),
);
match pool.complete_routed(Task::Exploit, &ag.name, &ag.system, &user).await {
Ok((m, text)) => {
let f = extract_findings(&text, &ag.name);
let _ = txc.send(format!("test {} via {} -> {} candidate(s)", ag.name, m.label(), f.len())).await;
for c in &f { if let Ok(j) = serde_json::to_string(c) { let _ = txc.send(format!("finding_json: {j}")).await; } }
(ag.name.clone(), text, f)
}
Err(e) => { let _ = txc.send(format!("test {} failed: {e}", ag.name)).await; (ag.name.clone(), format!("ERROR: {e}"), vec![]) }
}
}
})
.buffer_unordered(cfg.concurrency)
.collect::<Vec<_>>().await;
let transcript = transcript_of(&raw);
let candidates = dedup_findings(raw.iter().flat_map(|(_, _, f)| f.clone()).collect());
let _ = tx.send(format!("{} candidate finding(s) (deduped) - validating", candidates.len())).await;
let findings = validate(candidates, pool, VOTE_SYS, effective_vote_n(&cfg), &tx).await;
let findings = refute_pass(findings, pool, effective_vote_n(&cfg), &tx).await;
finish(cfg, lib, pool, recon, transcript, findings, selected, &mut rl, crate::grounding::GroundMode::Empirical, String::new(), tx).await
}
const HOST_RECON_SYS: &str = "You are an infrastructure recon specialist on an AUTHORIZED engagement against a HOST/IP. Actively scan with rustscan/nmap (and netexec/smbclient where relevant) to map open ports, services, versions and auth surfaces. Use any provided SSH/Windows credentials to enumerate from inside. Do not ask permission; proceed. Reply with a compact JSON object (host, os, ports, services, auth, ad). No prose.";
const HOST_TOOLING: &str = "TOOLING (best on Kali): nmap/rustscan (ports), netexec/crackmapexec + smbclient (SMB/AD), ssh/sshpass + linpeas (Linux), evil-winrm + winPEAS + impacket (Windows), bloodhound-python/SharpHound (AD), hashcat (offline cracking). Use only supplied credentials; never brute force or run destructive/DoS actions.\n\n";
+1 -1
View File
@@ -242,7 +242,7 @@ pub fn html_with_pocs(target: &str, findings: &[Finding], meta: &EngagementMeta,
<h2>Executive Summary</h2><div class=summary-grid>{summary_grid}</div>\
{vuln_summary}\
<h2>Findings ({n})</h2>{body}\
<p class=footer>Authorized testing only. Confirmed findings passed multi-model voting, receipt grounding and adversarial refute; \"needs-review\" are flagged for a human.<br>NeuroSploit v4.1.0 · by <b>Joas A Santos</b> &amp; <b>Red Team Leaders</b><br><span style=\"font-family:ui-monospace,monospace\">{provenance}</span></p></body></html>",
<p class=footer>Authorized testing only. Confirmed findings passed multi-model voting, receipt grounding and adversarial refute; \"needs-review\" are flagged for a human.<br>NeuroSploit v4.2.0 · by <b>Joas A Santos</b> &amp; <b>Red Team Leaders</b><br><span style=\"font-family:ui-monospace,monospace\">{provenance}</span></p></body></html>",
t = esc(target), n = sorted.len(), body = body, summary_grid = summary_grid, vuln_summary = vuln_summary,
// Which build produced this document. A report that circulates without
// it is a report nobody can trace back to the run that made it.
+2 -2
View File
@@ -1,4 +1,4 @@
// NeuroSploit v4.1.0 — Typst report template (blank, structured).
// NeuroSploit v4.2.0 — Typst report template (blank, structured).
//
// The harness generates `report.typ` per run by prepending a `findings` array
// and a `meta` dict, then including this template's rendering logic. This file
@@ -53,7 +53,7 @@
#set page(margin: 2cm, numbering: "1", footer: context [
#set text(size: 8pt, fill: gray)
NeuroSploit v4.1.0 · #meta.target · confidential
NeuroSploit v4.2.0 · #meta.target · confidential
#h(1fr)
// Build+run identity, so a page that circulates on its own still says which
// engagement produced it.