From eb4e13efea2925c3447a33ff030562536694761f Mon Sep 17 00:00:00 2001 From: CyberSecurityUP Date: Wed, 24 Jun 2026 23:21:43 -0300 Subject: [PATCH] v3.5.1: live findings + /finding + Ctrl+O/expand + 3-way /stop (soft validate) + report URL + structured Typst + IIS/CMS/CVE agents MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit REPL interactivity & findings: - Live findings registered during a run: /results shows them accumulating; /finding opens a selection menu with FULL details (PoC, command, evidence, CVSS, OWASP/CWE, remediation). Past runs too. - /expand (and Ctrl+O) dump the last full, untruncated commands. - Findings colored by severity in the feed (not all-yellow); confirmed vote = green. Stop & report: - CRITICAL: /stop no longer kills validation. New SOFT stop (pool.soft) halts launching new agents but lets in-flight + VALIDATION finish — so confirmed findings are kept. /stop now asks 3 ways: [1] validate then report, [2] report raw (no validation), [3] discard. - Report file:// URL printed on completion/stop. Report: - Typst report restructured: executive summary, a Vulnerability Summary TABLE (#, vuln, severity, CVSS, OWASP/CWE), and per-finding sections with criticality, CVSS, OWASP/CWE, description/impact, PoC, evidence, remediation. owasp passed through. Agents: +14 app-stack/CVE (IIS tilde/WebDAV/ViewState/debug/handler-bypass, CMS fingerprint + WordPress/Joomla/Drupal/default-admin, app-server consoles, exposed VCS, known-CVE & outdated-component exploitation) → 343 total. Co-Authored-By: Claude Opus 4.8 (1M context) --- .gitignore | 2 + agents_md/vulns/appserver_exposure.md | 36 ++++ agents_md/vulns/aspnet_debug_trace.md | 36 ++++ agents_md/vulns/aspnet_viewstate.md | 36 ++++ agents_md/vulns/cms_default_admin.md | 36 ++++ agents_md/vulns/cms_fingerprint.md | 37 ++++ agents_md/vulns/cve_known_exploitation.md | 40 +++++ agents_md/vulns/drupal_audit.md | 36 ++++ agents_md/vulns/git_svn_exposure_app.md | 36 ++++ agents_md/vulns/iis_handler_bypass.md | 36 ++++ agents_md/vulns/iis_tilde_shortname.md | 37 ++++ agents_md/vulns/iis_webdav.md | 36 ++++ agents_md/vulns/joomla_audit.md | 36 ++++ agents_md/vulns/outdated_dependency_cve.md | 36 ++++ agents_md/vulns/wordpress_audit.md | 36 ++++ neurosploit-rs/.neurosploit/history.txt | 7 + neurosploit-rs/.neurosploit/runs.json | 7 + neurosploit-rs/app/src/main.rs | 28 ++- neurosploit-rs/app/src/repl.rs | 161 ++++++++++++++++-- neurosploit-rs/crates/harness/src/pipeline.rs | 12 +- neurosploit-rs/crates/harness/src/pool.rs | 19 ++- neurosploit-rs/crates/harness/src/report.rs | 5 +- neurosploit-rs/templates/report.typ | 45 +++-- scripts/build_appstack_agents.py | 143 ++++++++++++++++ 24 files changed, 906 insertions(+), 33 deletions(-) create mode 100644 agents_md/vulns/appserver_exposure.md create mode 100644 agents_md/vulns/aspnet_debug_trace.md create mode 100644 agents_md/vulns/aspnet_viewstate.md create mode 100644 agents_md/vulns/cms_default_admin.md create mode 100644 agents_md/vulns/cms_fingerprint.md create mode 100644 agents_md/vulns/cve_known_exploitation.md create mode 100644 agents_md/vulns/drupal_audit.md create mode 100644 agents_md/vulns/git_svn_exposure_app.md create mode 100644 agents_md/vulns/iis_handler_bypass.md create mode 100644 agents_md/vulns/iis_tilde_shortname.md create mode 100644 agents_md/vulns/iis_webdav.md create mode 100644 agents_md/vulns/joomla_audit.md create mode 100644 agents_md/vulns/outdated_dependency_cve.md create mode 100644 agents_md/vulns/wordpress_audit.md create mode 100644 scripts/build_appstack_agents.py diff --git a/.gitignore b/.gitignore index ab02212..44e03f6 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,5 @@ neurosploit-rs/runs/ v34_gui.png data/repl_runs.json data/repl_history.txt +.neurosploit/ +/tmp/* diff --git a/agents_md/vulns/appserver_exposure.md b/agents_md/vulns/appserver_exposure.md new file mode 100644 index 0000000..0a73762 --- /dev/null +++ b/agents_md/vulns/appserver_exposure.md @@ -0,0 +1,36 @@ +# App-Server Console Exposure Agent + +## User Prompt +You are testing **{target}** for exposed Tomcat/JBoss/Jenkins/Actuator consoles. + +**Recon Context:** +{recon_json} + +**METHODOLOGY:** + +### 1. Discover +- Probe `/manager/html`, `/jmx-console`, `/jenkins`, `/actuator`, `/console`, `/admin` + +### 2. Assess +- Test default/weak creds (in scope); check unauth-exposed management endpoints + +### 3. Confirm +- Demonstrate a management action / deploy / info-leak proving exposure (→ often RCE) + +### 4. Report Format +For each CONFIRMED finding: +``` +FINDING: +- Title: App-Server Console Exposure at [endpoint] +- Severity: High +- CWE: CWE-1188 +- Endpoint: [full URL] +- Vector: [what/where] +- Payload: [exact payload/command] +- Evidence: [raw tool output proving it] +- Impact: Remote code execution / takeover +- Remediation: Authenticate & network-restrict consoles; remove defaults +``` + +## System Prompt +You are a specialist in exposed Tomcat/JBoss/Jenkins/Actuator consoles. AUTHORIZED engagement. Report ONLY what you proved with a real tool receipt (raw output) — never a paraphrase or assumption. Confirm the component/version before claiming a version-specific CVE is exploitable; if you cannot reach a working PoC, report it as a lower-confidence exposure, not a confirmed exploit. No destructive/DoS actions. Credits: Joas A Santos and Red Team Leaders. diff --git a/agents_md/vulns/aspnet_debug_trace.md b/agents_md/vulns/aspnet_debug_trace.md new file mode 100644 index 0000000..e71cf07 --- /dev/null +++ b/agents_md/vulns/aspnet_debug_trace.md @@ -0,0 +1,36 @@ +# ASP.NET Debug/Trace Exposure Agent + +## User Prompt +You are testing **{target}** for debug/trace enabled in production ASP.NET. + +**Recon Context:** +{recon_json} + +**METHODOLOGY:** + +### 1. Probe +- Request `trace.axd`; send `DEBUG` verb; check `` leakage via errors + +### 2. Assess +- Harvest request/session data, stack traces, app internals from trace output + +### 3. Confirm +- Show sensitive runtime data exposed + +### 4. Report Format +For each CONFIRMED finding: +``` +FINDING: +- Title: ASP.NET Debug/Trace Exposure at [endpoint] +- Severity: Medium +- CWE: CWE-489 +- Endpoint: [full URL] +- Vector: [what/where] +- Payload: [exact payload/command] +- Evidence: [raw tool output proving it] +- Impact: Information disclosure +- Remediation: Disable debug/trace; custom errors +``` + +## System Prompt +You are a specialist in debug/trace enabled in production ASP.NET. AUTHORIZED engagement. Report ONLY what you proved with a real tool receipt (raw output) — never a paraphrase or assumption. Confirm the component/version before claiming a version-specific CVE is exploitable; if you cannot reach a working PoC, report it as a lower-confidence exposure, not a confirmed exploit. No destructive/DoS actions. Credits: Joas A Santos and Red Team Leaders. diff --git a/agents_md/vulns/aspnet_viewstate.md b/agents_md/vulns/aspnet_viewstate.md new file mode 100644 index 0000000..403c763 --- /dev/null +++ b/agents_md/vulns/aspnet_viewstate.md @@ -0,0 +1,36 @@ +# ASP.NET ViewState Deserialization Agent + +## User Prompt +You are testing **{target}** for unprotected/known-key __VIEWSTATE deserialization. + +**Recon Context:** +{recon_json} + +**METHODOLOGY:** + +### 1. Inspect +- Capture __VIEWSTATE; check if MAC is disabled (enableViewStateMac=false) or a known/leaked machineKey is in play + +### 2. Weaponize +- With a known/guessed machineKey, craft a ysoserial.net ViewState gadget + +### 3. Confirm +- Prove code execution via OOB callback or command output tied to a unique marker + +### 4. Report Format +For each CONFIRMED finding: +``` +FINDING: +- Title: ASP.NET ViewState Deserialization at [endpoint] +- Severity: Critical +- CWE: CWE-502 +- Endpoint: [full URL] +- Vector: [what/where] +- Payload: [exact payload/command] +- Evidence: [raw tool output proving it] +- Impact: Remote code execution +- Remediation: Enable ViewState MAC; rotate machineKey; patch +``` + +## System Prompt +You are a specialist in unprotected/known-key __VIEWSTATE deserialization. AUTHORIZED engagement. Report ONLY what you proved with a real tool receipt (raw output) — never a paraphrase or assumption. Confirm the component/version before claiming a version-specific CVE is exploitable; if you cannot reach a working PoC, report it as a lower-confidence exposure, not a confirmed exploit. No destructive/DoS actions. Credits: Joas A Santos and Red Team Leaders. diff --git a/agents_md/vulns/cms_default_admin.md b/agents_md/vulns/cms_default_admin.md new file mode 100644 index 0000000..ddcd2b2 --- /dev/null +++ b/agents_md/vulns/cms_default_admin.md @@ -0,0 +1,36 @@ +# CMS Admin Panel & Default Creds Agent + +## User Prompt +You are testing **{target}** for exposed CMS admin with weak/default credentials. + +**Recon Context:** +{recon_json} + +**METHODOLOGY:** + +### 1. Locate +- Find admin (`/wp-admin`, `/administrator`, `/user/login`, `/admin`) + +### 2. Test (in scope) +- Try supplied/default credentials; respect lockout/ROE — no out-of-scope brute force + +### 3. Confirm +- Show authenticated admin access + +### 4. Report Format +For each CONFIRMED finding: +``` +FINDING: +- Title: CMS Admin Panel & Default Creds at [endpoint] +- Severity: High +- CWE: CWE-1392 +- Endpoint: [full URL] +- Vector: [what/where] +- Payload: [exact payload/command] +- Evidence: [raw tool output proving it] +- Impact: Full CMS compromise +- Remediation: Remove defaults; strong creds + MFA; restrict admin +``` + +## System Prompt +You are a specialist in exposed CMS admin with weak/default credentials. AUTHORIZED engagement. Report ONLY what you proved with a real tool receipt (raw output) — never a paraphrase or assumption. Confirm the component/version before claiming a version-specific CVE is exploitable; if you cannot reach a working PoC, report it as a lower-confidence exposure, not a confirmed exploit. No destructive/DoS actions. Credits: Joas A Santos and Red Team Leaders. diff --git a/agents_md/vulns/cms_fingerprint.md b/agents_md/vulns/cms_fingerprint.md new file mode 100644 index 0000000..24b04c8 --- /dev/null +++ b/agents_md/vulns/cms_fingerprint.md @@ -0,0 +1,37 @@ +# CMS Fingerprint & Version Agent + +## User Prompt +You are testing **{target}** for CMS identification and version disclosure. + +**Recon Context:** +{recon_json} + +**METHODOLOGY:** + +### 1. Identify +- Detect CMS via meta generator, paths (`/wp-`, `/sites/`, `/administrator/`), headers, favicon hash +- Run whatweb/wpscan-style detection without auth + +### 2. Version +- Pin exact version from readme/changelog/asset hashes + +### 3. Map +- List plugins/themes/modules and their versions for CVE correlation + +### 4. Report Format +For each CONFIRMED finding: +``` +FINDING: +- Title: CMS Fingerprint & Version at [endpoint] +- Severity: Info +- CWE: CWE-200 +- Endpoint: [full URL] +- Vector: [what/where] +- Payload: [exact payload/command] +- Evidence: [raw tool output proving it] +- Impact: Targeted exploitation surface +- Remediation: Hide version/generator; keep components updated +``` + +## System Prompt +You are a specialist in CMS identification and version disclosure. AUTHORIZED engagement. Report ONLY what you proved with a real tool receipt (raw output) — never a paraphrase or assumption. Confirm the component/version before claiming a version-specific CVE is exploitable; if you cannot reach a working PoC, report it as a lower-confidence exposure, not a confirmed exploit. No destructive/DoS actions. Credits: Joas A Santos and Red Team Leaders. diff --git a/agents_md/vulns/cve_known_exploitation.md b/agents_md/vulns/cve_known_exploitation.md new file mode 100644 index 0000000..bdee830 --- /dev/null +++ b/agents_md/vulns/cve_known_exploitation.md @@ -0,0 +1,40 @@ +# Known-CVE Exploitation Specialist Agent + +## User Prompt +You are testing **{target}** for exploiting known CVEs for the detected stack. + +**Recon Context:** +{recon_json} + +**METHODOLOGY:** + +### 1. Identify versions +- From recon, list each component + exact version (server, framework, CMS, plugins, libs) + +### 2. Map to CVEs +- Match versions to known CVEs; prioritise unauth RCE/SQLi/auth-bypass; note CVE id + CVSS +- Prefer issues with a reliable, non-destructive PoC + +### 3. Reproduce safely +- Run a benign PoC (e.g. a version/echo check or OOB callback) to confirm the CVE is actually present and exploitable — never a destructive payload + +### 4. Confirm +- Report the CVE only when the PoC produced concrete proof (output/OOB); otherwise report it as 'potentially vulnerable (version match, unconfirmed)' + +### 5. Report Format +For each CONFIRMED finding: +``` +FINDING: +- Title: Known-CVE Exploitation Specialist at [endpoint] +- Severity: Critical +- CWE: CWE-1395 +- Endpoint: [full URL] +- Vector: [what/where] +- Payload: [exact payload/command] +- Evidence: [raw tool output proving it] +- Impact: Depends on CVE — up to full compromise +- Remediation: Patch/upgrade the affected components; apply vendor advisories +``` + +## System Prompt +You are a specialist in exploiting known CVEs for the detected stack. AUTHORIZED engagement. Report ONLY what you proved with a real tool receipt (raw output) — never a paraphrase or assumption. Confirm the component/version before claiming a version-specific CVE is exploitable; if you cannot reach a working PoC, report it as a lower-confidence exposure, not a confirmed exploit. No destructive/DoS actions. Credits: Joas A Santos and Red Team Leaders. diff --git a/agents_md/vulns/drupal_audit.md b/agents_md/vulns/drupal_audit.md new file mode 100644 index 0000000..45706e9 --- /dev/null +++ b/agents_md/vulns/drupal_audit.md @@ -0,0 +1,36 @@ +# Drupal Security Audit Agent + +## User Prompt +You are testing **{target}** for Drupal core/module weaknesses (e.g. Drupalgeddon class). + +**Recon Context:** +{recon_json} + +**METHODOLOGY:** + +### 1. Enumerate +- Version (CHANGELOG, headers), enabled modules + +### 2. Correlate CVEs +- Map to known Drupal RCE/SQLi (e.g. SA-CORE highly-critical classes) + +### 3. Confirm +- Reproduce with an OOB/output proof where applicable + +### 4. Report Format +For each CONFIRMED finding: +``` +FINDING: +- Title: Drupal Security Audit at [endpoint] +- Severity: Critical +- CWE: CWE-1395 +- Endpoint: [full URL] +- Vector: [what/where] +- Payload: [exact payload/command] +- Evidence: [raw tool output proving it] +- Impact: Remote code execution +- Remediation: Patch core/modules promptly +``` + +## System Prompt +You are a specialist in Drupal core/module weaknesses (e.g. Drupalgeddon class). AUTHORIZED engagement. Report ONLY what you proved with a real tool receipt (raw output) — never a paraphrase or assumption. Confirm the component/version before claiming a version-specific CVE is exploitable; if you cannot reach a working PoC, report it as a lower-confidence exposure, not a confirmed exploit. No destructive/DoS actions. Credits: Joas A Santos and Red Team Leaders. diff --git a/agents_md/vulns/git_svn_exposure_app.md b/agents_md/vulns/git_svn_exposure_app.md new file mode 100644 index 0000000..83a09b3 --- /dev/null +++ b/agents_md/vulns/git_svn_exposure_app.md @@ -0,0 +1,36 @@ +# Exposed VCS / Build Artifacts Agent + +## User Prompt +You are testing **{target}** for exposed .git/.svn/CI artifacts on the app host. + +**Recon Context:** +{recon_json} + +**METHODOLOGY:** + +### 1. Probe +- Request `/.git/HEAD`, `/.svn/entries`, `/.env`, build/CI artifact paths + +### 2. Recover +- Dump source (git-dumper) / read secrets + +### 3. Confirm +- Show recovered source or live secret + +### 4. Report Format +For each CONFIRMED finding: +``` +FINDING: +- Title: Exposed VCS / Build Artifacts at [endpoint] +- Severity: High +- CWE: CWE-527 +- Endpoint: [full URL] +- Vector: [what/where] +- Payload: [exact payload/command] +- Evidence: [raw tool output proving it] +- Impact: Source/secret disclosure → RCE +- Remediation: Block VCS/dotfiles from web; rotate secrets +``` + +## System Prompt +You are a specialist in exposed .git/.svn/CI artifacts on the app host. AUTHORIZED engagement. Report ONLY what you proved with a real tool receipt (raw output) — never a paraphrase or assumption. Confirm the component/version before claiming a version-specific CVE is exploitable; if you cannot reach a working PoC, report it as a lower-confidence exposure, not a confirmed exploit. No destructive/DoS actions. Credits: Joas A Santos and Red Team Leaders. diff --git a/agents_md/vulns/iis_handler_bypass.md b/agents_md/vulns/iis_handler_bypass.md new file mode 100644 index 0000000..3462d76 --- /dev/null +++ b/agents_md/vulns/iis_handler_bypass.md @@ -0,0 +1,36 @@ +# IIS Handler/Extension Bypass Agent + +## User Prompt +You are testing **{target}** for auth or filter bypass via IIS handler quirks. + +**Recon Context:** +{recon_json} + +**METHODOLOGY:** + +### 1. Probe +- Test path/extension tricks: `;.asp`, `::$DATA`, trailing dot, `%20`, case, `/admin/.`/`..%2f` + +### 2. Bypass +- Reach a protected handler/endpoint via a normalization or handler-mapping quirk + +### 3. Confirm +- Show access to a resource that should be blocked + +### 4. Report Format +For each CONFIRMED finding: +``` +FINDING: +- Title: IIS Handler/Extension Bypass at [endpoint] +- Severity: High +- CWE: CWE-288 +- Endpoint: [full URL] +- Vector: [what/where] +- Payload: [exact payload/command] +- Evidence: [raw tool output proving it] +- Impact: Auth/control bypass +- Remediation: Consistent normalization; patch; tighten ACLs +``` + +## System Prompt +You are a specialist in auth or filter bypass via IIS handler quirks. AUTHORIZED engagement. Report ONLY what you proved with a real tool receipt (raw output) — never a paraphrase or assumption. Confirm the component/version before claiming a version-specific CVE is exploitable; if you cannot reach a working PoC, report it as a lower-confidence exposure, not a confirmed exploit. No destructive/DoS actions. Credits: Joas A Santos and Red Team Leaders. diff --git a/agents_md/vulns/iis_tilde_shortname.md b/agents_md/vulns/iis_tilde_shortname.md new file mode 100644 index 0000000..3d39c9d --- /dev/null +++ b/agents_md/vulns/iis_tilde_shortname.md @@ -0,0 +1,37 @@ +# IIS Tilde (~) Short-Name Enumeration Agent + +## User Prompt +You are testing **{target}** for IIS 8.3 short-name disclosure. + +**Recon Context:** +{recon_json} + +**METHODOLOGY:** + +### 1. Detect +- Probe `GET /*~1*/.aspx` style requests; a 404-vs-error differential reveals 8.3 short names +- Confirm IIS version from Server header + +### 2. Enumerate +- Brute the short names char by char to reveal hidden files/dirs + +### 3. Confirm +- Show recovered short names mapping to real sensitive files + +### 4. Report Format +For each CONFIRMED finding: +``` +FINDING: +- Title: IIS Tilde (~) Short-Name Enumeration at [endpoint] +- Severity: Medium +- CWE: CWE-200 +- Endpoint: [full URL] +- Vector: [what/where] +- Payload: [exact payload/command] +- Evidence: [raw tool output proving it] +- Impact: Discovery of hidden files/backups/configs +- Remediation: Disable 8.3 name creation; patch IIS +``` + +## System Prompt +You are a specialist in IIS 8.3 short-name disclosure. AUTHORIZED engagement. Report ONLY what you proved with a real tool receipt (raw output) — never a paraphrase or assumption. Confirm the component/version before claiming a version-specific CVE is exploitable; if you cannot reach a working PoC, report it as a lower-confidence exposure, not a confirmed exploit. No destructive/DoS actions. Credits: Joas A Santos and Red Team Leaders. diff --git a/agents_md/vulns/iis_webdav.md b/agents_md/vulns/iis_webdav.md new file mode 100644 index 0000000..9d115ee --- /dev/null +++ b/agents_md/vulns/iis_webdav.md @@ -0,0 +1,36 @@ +# IIS WebDAV Misconfiguration Agent + +## User Prompt +You are testing **{target}** for exposed/unsafe WebDAV on IIS. + +**Recon Context:** +{recon_json} + +**METHODOLOGY:** + +### 1. Detect +- `OPTIONS /` — look for DAV header / PUT/MOVE/COPY allowed + +### 2. Test write +- Attempt PUT of a benign file; if blocked, try `.txt`→MOVE→`.asp` trick + +### 3. Confirm +- Show an uploaded file is served (and if executable → RCE) + +### 4. Report Format +For each CONFIRMED finding: +``` +FINDING: +- Title: IIS WebDAV Misconfiguration at [endpoint] +- Severity: High +- CWE: CWE-650 +- Endpoint: [full URL] +- Vector: [what/where] +- Payload: [exact payload/command] +- Evidence: [raw tool output proving it] +- Impact: Arbitrary upload, potential RCE +- Remediation: Disable WebDAV or restrict methods/authn +``` + +## System Prompt +You are a specialist in exposed/unsafe WebDAV on IIS. AUTHORIZED engagement. Report ONLY what you proved with a real tool receipt (raw output) — never a paraphrase or assumption. Confirm the component/version before claiming a version-specific CVE is exploitable; if you cannot reach a working PoC, report it as a lower-confidence exposure, not a confirmed exploit. No destructive/DoS actions. Credits: Joas A Santos and Red Team Leaders. diff --git a/agents_md/vulns/joomla_audit.md b/agents_md/vulns/joomla_audit.md new file mode 100644 index 0000000..7639f06 --- /dev/null +++ b/agents_md/vulns/joomla_audit.md @@ -0,0 +1,36 @@ +# Joomla Security Audit Agent + +## User Prompt +You are testing **{target}** for Joomla core/extension weaknesses. + +**Recon Context:** +{recon_json} + +**METHODOLOGY:** + +### 1. Enumerate +- Version (`administrator/manifests/files/joomla.xml`), components/extensions + versions + +### 2. Correlate CVEs +- Map to known Joomla/extension CVEs (SQLi, LFI, object injection) + +### 3. Confirm +- Reproduce one with proof + +### 4. Report Format +For each CONFIRMED finding: +``` +FINDING: +- Title: Joomla Security Audit at [endpoint] +- Severity: High +- CWE: CWE-1395 +- Endpoint: [full URL] +- Vector: [what/where] +- Payload: [exact payload/command] +- Evidence: [raw tool output proving it] +- Impact: Site takeover / data breach +- Remediation: Update core/extensions; harden admin +``` + +## System Prompt +You are a specialist in Joomla core/extension weaknesses. AUTHORIZED engagement. Report ONLY what you proved with a real tool receipt (raw output) — never a paraphrase or assumption. Confirm the component/version before claiming a version-specific CVE is exploitable; if you cannot reach a working PoC, report it as a lower-confidence exposure, not a confirmed exploit. No destructive/DoS actions. Credits: Joas A Santos and Red Team Leaders. diff --git a/agents_md/vulns/outdated_dependency_cve.md b/agents_md/vulns/outdated_dependency_cve.md new file mode 100644 index 0000000..db0ea3b --- /dev/null +++ b/agents_md/vulns/outdated_dependency_cve.md @@ -0,0 +1,36 @@ +# Outdated Component CVE Specialist Agent + +## User Prompt +You are testing **{target}** for outdated front-end/back-end components with known CVEs. + +**Recon Context:** +{recon_json} + +**METHODOLOGY:** + +### 1. Inventory +- Extract JS libs (jQuery, Angular, etc.), server modules, framework versions from responses/JS/headers + +### 2. Correlate +- Map each to known CVEs; flag the exploitable, reachable ones + +### 3. Confirm +- Prove exploitability where a safe PoC exists; else report as version-based exposure + +### 4. Report Format +For each CONFIRMED finding: +``` +FINDING: +- Title: Outdated Component CVE Specialist at [endpoint] +- Severity: High +- CWE: CWE-1104 +- Endpoint: [full URL] +- Vector: [what/where] +- Payload: [exact payload/command] +- Evidence: [raw tool output proving it] +- Impact: Varies — XSS/RCE/info-leak +- Remediation: Upgrade components; dependency scanning in CI +``` + +## System Prompt +You are a specialist in outdated front-end/back-end components with known CVEs. AUTHORIZED engagement. Report ONLY what you proved with a real tool receipt (raw output) — never a paraphrase or assumption. Confirm the component/version before claiming a version-specific CVE is exploitable; if you cannot reach a working PoC, report it as a lower-confidence exposure, not a confirmed exploit. No destructive/DoS actions. Credits: Joas A Santos and Red Team Leaders. diff --git a/agents_md/vulns/wordpress_audit.md b/agents_md/vulns/wordpress_audit.md new file mode 100644 index 0000000..6567791 --- /dev/null +++ b/agents_md/vulns/wordpress_audit.md @@ -0,0 +1,36 @@ +# WordPress Security Audit Agent + +## User Prompt +You are testing **{target}** for WordPress core/plugin/theme weaknesses. + +**Recon Context:** +{recon_json} + +**METHODOLOGY:** + +### 1. Enumerate +- Users (`/?author=`, REST `/wp-json/wp/v2/users`), plugins/themes + versions, `xmlrpc.php` + +### 2. Correlate CVEs +- Map plugin/theme versions to known vulns (arbitrary upload, SQLi, auth bypass, LFI) + +### 3. Confirm +- Reproduce one concrete issue (e.g. unauth arbitrary file upload) with proof + +### 4. Report Format +For each CONFIRMED finding: +``` +FINDING: +- Title: WordPress Security Audit at [endpoint] +- Severity: High +- CWE: CWE-1395 +- Endpoint: [full URL] +- Vector: [what/where] +- Payload: [exact payload/command] +- Evidence: [raw tool output proving it] +- Impact: Site takeover / RCE +- Remediation: Update core/plugins/themes; harden; disable xmlrpc +``` + +## System Prompt +You are a specialist in WordPress core/plugin/theme weaknesses. AUTHORIZED engagement. Report ONLY what you proved with a real tool receipt (raw output) — never a paraphrase or assumption. Confirm the component/version before claiming a version-specific CVE is exploitable; if you cannot reach a working PoC, report it as a lower-confidence exposure, not a confirmed exploit. No destructive/DoS actions. Credits: Joas A Santos and Red Team Leaders. diff --git a/neurosploit-rs/.neurosploit/history.txt b/neurosploit-rs/.neurosploit/history.txt index c88fc3d..8071469 100644 --- a/neurosploit-rs/.neurosploit/history.txt +++ b/neurosploit-rs/.neurosploit/history.txt @@ -22,3 +22,10 @@ run /results /report /exit +/run +/status +/help +/results +/stop +/results +/exit diff --git a/neurosploit-rs/.neurosploit/runs.json b/neurosploit-rs/.neurosploit/runs.json index a1d546d..bc9dfc5 100644 --- a/neurosploit-rs/.neurosploit/runs.json +++ b/neurosploit-rs/.neurosploit/runs.json @@ -19,5 +19,12 @@ "target": "http://testasp.vulnweb.com/", "workdir": "", "findings": [] + }, + { + "id": 4, + "mode": "black-box", + "target": "http://testasp.vulnweb.com/", + "workdir": "/opt/NeurosploitFinal/runs/ns-1782353097-testasp_vulnweb_com", + "findings": [] } ] \ No newline at end of file diff --git a/neurosploit-rs/app/src/main.rs b/neurosploit-rs/app/src/main.rs index c5f6bea..aa8af72 100644 --- a/neurosploit-rs/app/src/main.rs +++ b/neurosploit-rs/app/src/main.rs @@ -359,6 +359,7 @@ pub(crate) struct Spawned { pub task: tokio::task::JoinHandle, pub rx: tokio::sync::mpsc::Receiver, pub cancel: std::sync::Arc, + pub soft: std::sync::Arc, pub workdir: PathBuf, } @@ -408,6 +409,7 @@ pub(crate) fn spawn_engagement(base: &Path, mut cfg: RunConfig, mcp: bool, mode: let refs: Vec = cfg.models.iter().map(|s| ModelRef::parse(s)).collect(); let pool = ModelPool::with_auth(refs, cfg.concurrency, cfg.subscription, mcp_config); let cancel = pool.cancel_handle(); + let soft = pool.soft_handle(); let (tx, rx) = tokio::sync::mpsc::channel::(256); let task = tokio::spawn(async move { match mode { @@ -417,7 +419,25 @@ pub(crate) fn spawn_engagement(base: &Path, mut cfg: RunConfig, mcp: bool, mode: Mode::Black => harness::run(cfg, &lib, &pool, tx).await, } }); - Spawned { task, rx, cancel, workdir } + Spawned { task, rx, cancel, soft, workdir } +} + +/// Absolute file:// URL of a run's report (PDF if present, else HTML). +pub(crate) fn report_url(workdir: &Path) -> String { + let pdf = workdir.join("report.pdf"); + let f = if pdf.is_file() { pdf } else { workdir.join("report.html") }; + let abs = f.canonicalize().unwrap_or(f); + format!("file://{}", abs.display()) +} + +/// Generate a report directly from raw (unvalidated) findings — used by the REPL +/// when the user chooses "report without validating" on /stop. +pub(crate) fn report_raw(target: &str, findings: &[harness::types::Finding], workdir: &Path) { + let mut fs = findings.to_vec(); + harness::attack_graph::enrich(&mut fs); + std::fs::write(workdir.join("findings.json"), serde_json::to_string_pretty(&fs).unwrap_or_default()).ok(); + let _ = harness::report::typst_report(target, &fs, workdir); + write_status(workdir, "stopped-raw", &format!("\"findings\":{}", fs.len())); } /// Generate the report + final status for a finished run, ensuring the workdir @@ -433,7 +453,7 @@ pub(crate) fn finalize_run(mut out: RunOutput, workdir: &Path) -> RunOutput { } async fn run_mode(base: &Path, cfg: RunConfig, mcp: bool, mode: Mode) -> anyhow::Result { - let Spawned { mut task, mut rx, cancel, workdir } = spawn_engagement(base, cfg, mcp, mode); + let Spawned { mut task, mut rx, cancel, workdir, .. } = spawn_engagement(base, cfg, mcp, mode); let printer = tokio::spawn(async move { while let Some(line) = rx.recv().await { render_line(&line); } }); @@ -465,7 +485,8 @@ async fn run_mode(base: &Path, cfg: RunConfig, mcp: bool, mode: Mode) -> anyhow: } let out = finalize_run(out, &workdir); - println!(" ✓ COMPLETE — {} validated finding(s) · status: {}/status.json", out.findings.len(), workdir.display()); + println!(" ✓ COMPLETE — {} validated finding(s)", out.findings.len()); + println!(" \x1b[36mreport: {}\x1b[0m", report_url(&workdir)); Ok(out) } @@ -560,6 +581,7 @@ pub(crate) fn render_compact(raw: &str) -> Option { if let Some((label, rest)) = stripped.split_once(' ') { who = format!("[{label}] "); line = rest; } } let (tag, rest) = line.split_once(": ").unwrap_or(("", line)); + if tag == "finding_json" { return None; } // captured for /results & /finding, not shown let s = match tag { "exec" | "danger" => format!("\x1b[33m ⌘ {who}{}\x1b[0m", trunc1(rest, 110)), "net" => format!("\x1b[36m 🌐 {who}{}\x1b[0m", trunc1(rest, 110)), diff --git a/neurosploit-rs/app/src/repl.rs b/neurosploit-rs/app/src/repl.rs index 37e9bda..15dbce2 100644 --- a/neurosploit-rs/app/src/repl.rs +++ b/neurosploit-rs/app/src/repl.rs @@ -13,7 +13,7 @@ use rustyline::highlight::Highlighter; use rustyline::hint::Hinter; use rustyline::history::FileHistory; use rustyline::validate::{ValidationContext, ValidationResult, Validator}; -use rustyline::{CompletionType, Config, Context, Editor, ExternalPrinter, Helper}; +use rustyline::{Cmd, CompletionType, Config, Context, Editor, ExternalPrinter, Helper, KeyEvent}; use serde::{Deserialize, Serialize}; use std::io::IsTerminal; use std::path::Path; @@ -28,7 +28,9 @@ struct RunLive { mode: &'static str, phase: String, started: Instant, - findings: Vec<(String, String)>, // sev, title + findings: Vec<(String, String)>, // sev, title (summary) + full: Vec, // full candidate findings (PoC, evidence) for /finding + commands: Vec, // full untruncated commands for /expand & Ctrl+O agents: usize, agents_done: usize, } @@ -67,14 +69,30 @@ impl RunLive { } } } + // Full candidate finding (with PoC/evidence) for /results & /finding. + if let Some(j) = line.strip_prefix("finding_json: ") { + if let Ok(f) = serde_json::from_str::(j) { self.full.push(f); } + } + // Full untruncated command for /expand & Ctrl+O. + let cmd_part = line.strip_prefix('@').and_then(|s| s.split_once(' ').map(|(_, r)| r)).unwrap_or(line); + if let Some(c) = cmd_part.strip_prefix("exec: ").or_else(|| cmd_part.strip_prefix("danger: ")) { + self.commands.push(c.to_string()); + if self.commands.len() > 100 { self.commands.remove(0); } + } } } +/// What to do when the user stops a run. +#[derive(Clone, Copy, PartialEq)] +enum StopMode { Run, Validate, Raw, Discard } + /// A run executing in the background of the REPL. struct ActiveRun { live: Arc>, cancel: Arc, + soft: Arc, done: Arc, + choice: Arc>, } /// All slash-commands, for Tab completion. @@ -205,6 +223,8 @@ impl Reader { .completion_type(CompletionType::List).build(); if let Ok(mut ed) = Editor::::with_config(cfg) { ed.set_helper(Some(NsHelper)); + // Ctrl+O pre-fills /expand to dump the last full (untruncated) commands. + ed.bind_sequence(KeyEvent::ctrl('o'), Cmd::Insert(1, "/expand".to_string())); let hist = proj_dir().join("history.txt"); let _ = ed.load_history(&hist); return Reader::Rl(Box::new(ed), hist); @@ -376,7 +396,21 @@ pub async fn repl(base: &Path) -> anyhow::Result<()> { } "/stop" => { match &active { - Some(a) if !a.done.load(Ordering::Relaxed) => { a.cancel.store(true, Ordering::Relaxed); println!(" ⏸ stopping — finishing in-flight work; a report is generated on completion."); } + Some(a) if !a.done.load(Ordering::Relaxed) => { + println!(" \x1b[1mStop the run — choose:\x1b[0m"); + println!(" \x1b[36m1\x1b[0m validate the findings found so far, then report \x1b[2m(recommended)\x1b[0m"); + println!(" \x1b[36m2\x1b[0m report NOW without validating (raw findings)"); + println!(" \x1b[36m3\x1b[0m discard (no report)"); + let ans = ask_line(" choice [1/2/3]:"); + match ans.trim() { + "2" => { *a.choice.lock().unwrap() = StopMode::Raw; a.cancel.store(true, Ordering::Relaxed); + println!(" ⏹ stopping — generating a RAW report from what was found…"); } + "3" => { *a.choice.lock().unwrap() = StopMode::Discard; a.cancel.store(true, Ordering::Relaxed); + println!(" 🗑 stopping — discarding this run."); } + _ => { *a.choice.lock().unwrap() = StopMode::Validate; a.soft.store(true, Ordering::Relaxed); + println!(" ⏸ stopping exploitation — validating what was found, then reporting…"); } + } + } _ => println!(" no active run."), } } @@ -394,7 +428,44 @@ pub async fn repl(base: &Path) -> anyhow::Result<()> { println!(" ↻ retest set up for {} ({} prior finding(s)) — /run to launch", r.target, titles.len()); } } - "/results" => results(&history.lock().unwrap(), arg), + "/results" => { + // Live findings while a run is active (no arg), else a past run. + match &active { + Some(a) if arg.is_empty() && !a.done.load(Ordering::Relaxed) => { + let l = a.live.lock().unwrap(); + println!(" ▶ live — {} possible finding(s) so far ({})", l.full.len(), l.phase); + let mut f = l.full.clone(); + f.sort_by_key(|x| sev_rank(&x.severity)); + for x in &f { println!(" • [{}] {} \x1b[2m({} · {})\x1b[0m", x.severity, x.title, x.agent, x.endpoint); } + if !f.is_empty() { println!(" \x1b[2m/finding — pick one to see the command & PoC\x1b[0m"); } + } + _ => results(&history.lock().unwrap(), arg), + } + } + "/finding" | "/findings" => { + // Build the finding pool: live run if active, else a past run. + let pool: Vec = match &active { + Some(a) if arg.is_empty() && !a.done.load(Ordering::Relaxed) => a.live.lock().unwrap().full.clone(), + _ => { let h = history.lock().unwrap(); pick(&h, arg).map(|r| r.findings.clone()).unwrap_or_default() } + }; + finding_detail(&pool); + } + "/expand" | "/full" => { + // Show full untruncated commands from the active run. + match &active { + Some(a) => { + let l = a.live.lock().unwrap(); + let n: usize = arg.trim().parse().unwrap_or(5); + let cmds = &l.commands; + if cmds.is_empty() { println!(" no commands captured yet."); } + else { + println!(" ── last {} command(s) (full) ──", n.min(cmds.len())); + for c in cmds.iter().rev().take(n).rev() { println!(" \x1b[33m$ {c}\x1b[0m"); } + } + } + None => println!(" no active run — /expand shows full commands while a run streams."), + } + } "/report" => open_report(&history.lock().unwrap(), arg), "/status" => { // Live status if a run is active, else a past run's status.json. @@ -585,11 +656,14 @@ async fn start_background(base: &Path, s: &Session, reader: &mut Reader, let live = Arc::new(Mutex::new(RunLive { target: target.clone(), mode: mode_s, phase: "starting".into(), - started: Instant::now(), findings: vec![], agents: 0, agents_done: 0, + started: Instant::now(), findings: vec![], full: vec![], commands: vec![], + agents: 0, agents_done: 0, })); let cancel = sp.cancel.clone(); + let soft = sp.soft.clone(); let done = Arc::new(AtomicBool::new(false)); - let (live2, done2, hist2) = (live.clone(), done.clone(), history); + let choice = Arc::new(Mutex::new(StopMode::Run)); + let (live2, done2, hist2, choice2) = (live.clone(), done.clone(), history, choice.clone()); tokio::spawn(async move { let crate::Spawned { task, mut rx, workdir, .. } = sp; @@ -597,20 +671,40 @@ async fn start_background(base: &Path, s: &Session, reader: &mut Reader, live2.lock().unwrap().ingest(&line); if let Some(out) = crate::render_compact(&line) { let _ = printer.print(out); } } - let out = crate::finalize_run(task.await.unwrap_or_default(), &workdir); + let task_out = task.await.unwrap_or_default(); + let mode_choice = *choice2.lock().unwrap(); + + if mode_choice == StopMode::Discard { + std::fs::remove_dir_all(&workdir).ok(); + let _ = printer.print(format!("\x1b[33m🗑 run discarded — {}\x1b[0m", workdir.display())); + done2.store(true, Ordering::Relaxed); + return; + } + + // Raw → report from the unvalidated candidates we captured live. + let (findings, validated_word) = if mode_choice == StopMode::Raw { + let raw = live2.lock().unwrap().full.clone(); + crate::report_raw(&target, &raw, &workdir); + (raw, "unvalidated") + } else { + let out = crate::finalize_run(task_out, &workdir); + (out.findings, "validated") + }; + let id = { let mut h = hist2.lock().unwrap(); let id = h.len() + 1; - h.push(RunRecord { id, mode: mode_s.into(), target, workdir: out.workdir.clone(), findings: out.findings.clone() }); + h.push(RunRecord { id, mode: mode_s.into(), target, workdir: workdir.display().to_string(), findings: findings.clone() }); if let Ok(j) = serde_json::to_string_pretty(&*h) { std::fs::write(proj_dir().join("runs.json"), j).ok(); } id }; let _ = printer.print(format!( - "\x1b[1;32m◀ run #{id} done — {} validated finding(s)\x1b[0m · /results {id} · /report {id}", - out.findings.len())); + "\x1b[1;32m◀ run #{id} done — {} {} finding(s)\x1b[0m · /results {id} · /finding", + findings.len(), validated_word)); + let _ = printer.print(format!("\x1b[36m report: {}\x1b[0m", crate::report_url(&workdir))); done2.store(true, Ordering::Relaxed); }); - Some(ActiveRun { live, cancel, done }) + Some(ActiveRun { live, cancel, soft, done, choice }) } /// Project-local store: `/.neurosploit/` so each project keeps its own @@ -737,6 +831,51 @@ fn diff_runs(history: &[RunRecord]) { if a == b { println!(" (no change in finding titles)"); } } +fn sev_rank(s: &str) -> u8 { + match s { "Critical" => 0, "High" => 1, "Medium" => 2, "Low" => 3, _ => 4 } +} + +/// Read one line synchronously (for the /stop choice prompt). +fn ask_line(prompt: &str) -> String { + use std::io::Write; + print!("{prompt} "); + std::io::stdout().flush().ok(); + let mut s = String::new(); + std::io::stdin().read_line(&mut s).ok(); + s +} + +/// Arrow-key selection menu over findings; prints EVERYTHING about the chosen one +/// (command/PoC, evidence, impact, remediation, votes, confidence). +fn finding_detail(pool: &[Finding]) { + if pool.is_empty() { println!(" no findings to inspect yet."); return; } + let mut f = pool.to_vec(); + f.sort_by_key(|x| sev_rank(&x.severity)); + let items: Vec = f.iter().map(|x| format!("[{}] {} — {}", x.severity, x.title, x.cwe)).collect(); + let idx = if std::io::stdin().is_terminal() { + match dialoguer::Select::with_theme(&ColorfulTheme::default()) + .with_prompt("Select a finding (↑/↓, enter)").items(&items).default(0).interact_opt() { + Ok(Some(i)) => i, _ => return, + } + } else { 0 }; + let x = &f[idx]; + println!("\n ┌─ \x1b[1m{}\x1b[0m", x.title); + println!(" │ severity : {}", x.severity); + println!(" │ cwe / cvss : {} · {}", x.cwe, x.cvss); + println!(" │ agent : {}", x.agent); + println!(" │ endpoint : {}", x.endpoint); + println!(" │ votes/conf : {} · {:.2}", x.votes, x.confidence); + println!(" ├─ \x1b[33mPayload / PoC\x1b[0m"); + for l in x.payload.lines() { println!(" │ {l}"); } + println!(" ├─ \x1b[36mEvidence (tool output)\x1b[0m"); + for l in x.evidence.lines() { println!(" │ {l}"); } + println!(" ├─ Impact"); + for l in x.impact.lines() { println!(" │ {l}"); } + println!(" ├─ Remediation"); + for l in x.remediation.lines() { println!(" │ {l}"); } + println!(" └─────"); +} + fn run_status(history: &[RunRecord], arg: &str) { let Some(r) = pick(history, arg) else { return }; match std::fs::read_to_string(Path::new(&r.workdir).join("status.json")) { diff --git a/neurosploit-rs/crates/harness/src/pipeline.rs b/neurosploit-rs/crates/harness/src/pipeline.rs index 3b59440..95244c6 100644 --- a/neurosploit-rs/crates/harness/src/pipeline.rs +++ b/neurosploit-rs/crates/harness/src/pipeline.rs @@ -159,7 +159,7 @@ pub async fn run(cfg: RunConfig, lib: &Library, pool: &ModelPool, tx: Sender { 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 { let _ = txc.send(format!("finding: [{}] {} @ {}", c.severity, c.title, c.endpoint)).await; } + for c in &f { + let _ = txc.send(format!("finding: [{}] {} @ {}", c.severity, c.title, c.endpoint)).await; + 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; diff --git a/neurosploit-rs/crates/harness/src/pool.rs b/neurosploit-rs/crates/harness/src/pool.rs index e7c39d4..469f70f 100644 --- a/neurosploit-rs/crates/harness/src/pool.rs +++ b/neurosploit-rs/crates/harness/src/pool.rs @@ -34,9 +34,11 @@ pub struct ModelPool { /// Progress channel: when set, the subscription CLI streams structured /// activity (tools called, commands run, files read) here live. progress: std::sync::Mutex>>, - /// Cooperative cancellation: when set, in-flight model calls short-circuit - /// and the pipeline stops launching new agents (graceful stop). + /// HARD cancellation: when set, in-flight model calls short-circuit (abort). cancel: std::sync::Arc, + /// SOFT stop: stop launching new EXPLOIT agents, but let in-flight finish and + /// VALIDATION still run — so "stop and validate what was found" works. + soft: std::sync::Arc, } impl ModelPool { @@ -65,6 +67,7 @@ impl ModelPool { mcp_config, progress: std::sync::Mutex::new(None), cancel: Arc::new(std::sync::atomic::AtomicBool::new(false)), + soft: Arc::new(std::sync::atomic::AtomicBool::new(false)), } } @@ -80,13 +83,23 @@ impl ModelPool { self.progress.lock().ok().and_then(|g| g.clone()) } - /// Handle to request graceful cancellation of an in-progress engagement. + /// Handle to request HARD cancellation (abort all model calls). pub fn cancel_handle(&self) -> Arc { self.cancel.clone() } + /// Handle to request a SOFT stop (stop launching new exploit agents; keep + /// validation running). + pub fn soft_handle(&self) -> Arc { + self.soft.clone() + } pub fn is_cancelled(&self) -> bool { self.cancel.load(std::sync::atomic::Ordering::Relaxed) } + /// Should the exploit phase stop launching new agents? (hard OR soft stop) + pub fn stop_exploiting(&self) -> bool { + self.cancel.load(std::sync::atomic::Ordering::Relaxed) + || self.soft.load(std::sync::atomic::Ordering::Relaxed) + } /// One completion for a model, via subscription CLI (optionally with MCP) or /// HTTP API, with a short retry/backoff. `label` (e.g. the agent name) tags diff --git a/neurosploit-rs/crates/harness/src/report.rs b/neurosploit-rs/crates/harness/src/report.rs index 4470fdc..49d396e 100644 --- a/neurosploit-rs/crates/harness/src/report.rs +++ b/neurosploit-rs/crates/harness/src/report.rs @@ -139,9 +139,10 @@ pub fn typst_report(target: &str, findings: &[Finding], dir: &Path) -> std::io:: )); data.push_str("#let findings = (\n"); for f in sorted_findings(findings) { + let owasp = if f.owasp.is_empty() { f.cwe.clone() } else { f.owasp.clone() }; data.push_str(&format!( - " (severity: {}, title: {}, agent: {}, cwe: {}, cvss: {}, endpoint: {}, payload: {}, evidence: {}, impact: {}, remediation: {}, votes: {}, confidence: {}),\n", - tq(&f.severity), tq(&f.title), tq(&f.agent), tq(&f.cwe), tq(&f.cvss), + " (severity: {}, title: {}, agent: {}, cwe: {}, owasp: {}, cvss: {}, endpoint: {}, payload: {}, evidence: {}, impact: {}, remediation: {}, votes: {}, confidence: {}),\n", + tq(&f.severity), tq(&f.title), tq(&f.agent), tq(&f.cwe), tq(&owasp), tq(&f.cvss), tq(&f.endpoint), tq(&f.payload), tq(&f.evidence), tq(&f.impact), tq(&f.remediation), tq(&f.votes), f.confidence, )); diff --git a/neurosploit-rs/templates/report.typ b/neurosploit-rs/templates/report.typ index 48e8585..31da110 100644 --- a/neurosploit-rs/templates/report.typ +++ b/neurosploit-rs/templates/report.typ @@ -71,13 +71,32 @@ ) ] +#let sorted = findings.sorted(key: f => sevrank(f.severity)) + +// ---- Vulnerability summary table ---- +#if sorted.len() > 0 [ + #v(8pt) + == Vulnerability Summary + #v(4pt) + #table( + columns: (auto, 1fr, auto, auto, auto), + inset: 6pt, align: (left + horizon, left + horizon, center + horizon, center + horizon, center + horizon), + stroke: 0.5pt + rgb("#dddddd"), + table.header( + text(weight: "bold")[\#], text(weight: "bold")[Vulnerability], + text(weight: "bold")[Severity], text(weight: "bold")[CVSS], text(weight: "bold")[OWASP / CWE], + ), + ..sorted.enumerate().map(((i, f)) => ( + str(i + 1), f.title, sevbadge(f.severity), f.cvss, f.owasp, + )).flatten() + ) +] + #v(10pt) #line(length: 100%, stroke: 0.5pt + gray) -// ---- Findings ---- +// ---- Detailed findings ---- = Findings - -#let sorted = findings.sorted(key: f => sevrank(f.severity)) #if sorted.len() == 0 [ #text(fill: gray)[_Nothing to report._] ] @@ -86,14 +105,20 @@ stroke: (left: 3pt + sevcolor.at(f.severity, default: gray), rest: 0.5pt + rgb("#dddddd")))[ #sevbadge(f.severity) #h(6pt) #text(12pt, weight: "bold")[#str(i + 1). #f.title] #v(4pt) - #text(9pt, fill: gray)[ - agent: #raw(f.agent) · CWE: #f.cwe · CVSS: #f.cvss · votes: #f.votes · confidence: #str(f.confidence) - ] - #v(2pt) #text(9pt)[Endpoint: #raw(f.endpoint)] - #v(5pt) #strong[Payload] #linebreak() #raw(f.payload) + #table( + columns: (auto, 1fr, auto, 1fr), + inset: 4pt, stroke: none, align: left + horizon, + text(8pt, fill: gray)[Criticality], text(8pt)[#f.severity], + text(8pt, fill: gray)[CVSS], text(8pt)[#f.cvss], + text(8pt, fill: gray)[OWASP/CWE], text(8pt)[#f.owasp · #f.cwe], + text(8pt, fill: gray)[Confidence], text(8pt)[#f.votes votes · #str(f.confidence)], + text(8pt, fill: gray)[Location], text(8pt)[#raw(f.endpoint)], + text(8pt, fill: gray)[Agent], text(8pt)[#raw(f.agent)], + ) + #v(4pt) #strong[Description / Impact] #linebreak() #text(9pt)[#f.impact] + #v(4pt) #strong[Proof of Concept] #linebreak() #raw(f.payload) #v(3pt) #strong[Evidence] #linebreak() #raw(f.evidence) - #v(3pt) #strong[Impact:] #f.impact - #v(2pt) #strong[Remediation:] #f.remediation + #v(3pt) #strong[Remediation] #linebreak() #text(9pt)[#f.remediation] ] #v(8pt) ] diff --git a/scripts/build_appstack_agents.py b/scripts/build_appstack_agents.py new file mode 100644 index 0000000..f4e3e61 --- /dev/null +++ b/scripts/build_appstack_agents.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +""" +NeuroSploit v3.5.1 — application-stack & CVE-hunting agents. +Adds IIS/.NET, CMS (WordPress/Drupal/Joomla/etc.), app-server and known-CVE +exploitation agents to agents_md/vulns/. Credits: Joas A Santos & Red Team Leaders. +""" +import os +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +OUT = os.path.join(ROOT, "agents_md", "vulns") + + +def render(a): + L = [f"# {a['title']} Agent\n", "## User Prompt", + f"You are testing **{{target}}** for {a['for']}.\n", + "**Recon Context:**\n{recon_json}\n", "**METHODOLOGY:**\n"] + for i, (s, bs) in enumerate(a["steps"], 1): + L.append(f"### {i}. {s}") + L += [f"- {b}" for b in bs] + L.append("") + n = len(a["steps"]) + 1 + L += [f"### {n}. Report Format", "For each CONFIRMED finding:", "```", "FINDING:", + f"- Title: {a['title']} at [endpoint]", f"- Severity: {a['sev']}", f"- CWE: {a['cwe']}", + "- Endpoint: [full URL]", "- Vector: [what/where]", "- Payload: [exact payload/command]", + "- Evidence: [raw tool output proving it]", f"- Impact: {a['impact']}", + f"- Remediation: {a['fix']}", "```\n", "## System Prompt", a["system"]] + return "\n".join(L) + "\n" + + +def A(name, title, vc, cwe, sev, steps, fix, impact): + return {"name": name, "title": title, "for": vc, "sev": sev, "cwe": cwe, "impact": impact, + "fix": fix, "steps": steps, + "system": (f"You are a specialist in {vc}. AUTHORIZED engagement. Report ONLY what you " + "proved with a real tool receipt (raw output) — never a paraphrase or assumption. " + "Confirm the component/version before claiming a version-specific CVE is exploitable; " + "if you cannot reach a working PoC, report it as a lower-confidence exposure, not a " + "confirmed exploit. No destructive/DoS actions. Credits: Joas A Santos and Red Team Leaders.")} + + +AGENTS = [ + # ---- IIS / ASP.NET ---- + A("iis_tilde_shortname", "IIS Tilde (~) Short-Name Enumeration", "IIS 8.3 short-name disclosure", + "CWE-200", "Medium", + [("Detect", ["Probe `GET /*~1*/.aspx` style requests; a 404-vs-error differential reveals 8.3 short names", + "Confirm IIS version from Server header"]), + ("Enumerate", ["Brute the short names char by char to reveal hidden files/dirs"]), + ("Confirm", ["Show recovered short names mapping to real sensitive files"])], + "Disable 8.3 name creation; patch IIS", "Discovery of hidden files/backups/configs"), + A("iis_webdav", "IIS WebDAV Misconfiguration", "exposed/unsafe WebDAV on IIS", + "CWE-650", "High", + [("Detect", ["`OPTIONS /` — look for DAV header / PUT/MOVE/COPY allowed"]), + ("Test write", ["Attempt PUT of a benign file; if blocked, try `.txt`→MOVE→`.asp` trick"]), + ("Confirm", ["Show an uploaded file is served (and if executable → RCE)"])], + "Disable WebDAV or restrict methods/authn", "Arbitrary upload, potential RCE"), + A("aspnet_viewstate", "ASP.NET ViewState Deserialization", "unprotected/known-key __VIEWSTATE deserialization", + "CWE-502", "Critical", + [("Inspect", ["Capture __VIEWSTATE; check if MAC is disabled (enableViewStateMac=false) or a known/leaked machineKey is in play"]), + ("Weaponize", ["With a known/guessed machineKey, craft a ysoserial.net ViewState gadget"]), + ("Confirm", ["Prove code execution via OOB callback or command output tied to a unique marker"])], + "Enable ViewState MAC; rotate machineKey; patch", "Remote code execution"), + A("aspnet_debug_trace", "ASP.NET Debug/Trace Exposure", "debug/trace enabled in production ASP.NET", + "CWE-489", "Medium", + [("Probe", ["Request `trace.axd`; send `DEBUG` verb; check `` leakage via errors"]), + ("Assess", ["Harvest request/session data, stack traces, app internals from trace output"]), + ("Confirm", ["Show sensitive runtime data exposed"])], + "Disable debug/trace; custom errors", "Information disclosure"), + A("iis_handler_bypass", "IIS Handler/Extension Bypass", "auth or filter bypass via IIS handler quirks", + "CWE-288", "High", + [("Probe", ["Test path/extension tricks: `;.asp`, `::$DATA`, trailing dot, `%20`, case, `/admin/.`/`..%2f`"]), + ("Bypass", ["Reach a protected handler/endpoint via a normalization or handler-mapping quirk"]), + ("Confirm", ["Show access to a resource that should be blocked"])], + "Consistent normalization; patch; tighten ACLs", "Auth/control bypass"), + # ---- CMS general & specific ---- + A("cms_fingerprint", "CMS Fingerprint & Version", "CMS identification and version disclosure", + "CWE-200", "Info", + [("Identify", ["Detect CMS via meta generator, paths (`/wp-`, `/sites/`, `/administrator/`), headers, favicon hash", + "Run whatweb/wpscan-style detection without auth"]), + ("Version", ["Pin exact version from readme/changelog/asset hashes"]), + ("Map", ["List plugins/themes/modules and their versions for CVE correlation"])], + "Hide version/generator; keep components updated", "Targeted exploitation surface"), + A("wordpress_audit", "WordPress Security Audit", "WordPress core/plugin/theme weaknesses", + "CWE-1395", "High", + [("Enumerate", ["Users (`/?author=`, REST `/wp-json/wp/v2/users`), plugins/themes + versions, `xmlrpc.php`"]), + ("Correlate CVEs", ["Map plugin/theme versions to known vulns (arbitrary upload, SQLi, auth bypass, LFI)"]), + ("Confirm", ["Reproduce one concrete issue (e.g. unauth arbitrary file upload) with proof"])], + "Update core/plugins/themes; harden; disable xmlrpc", "Site takeover / RCE"), + A("joomla_audit", "Joomla Security Audit", "Joomla core/extension weaknesses", + "CWE-1395", "High", + [("Enumerate", ["Version (`administrator/manifests/files/joomla.xml`), components/extensions + versions"]), + ("Correlate CVEs", ["Map to known Joomla/extension CVEs (SQLi, LFI, object injection)"]), + ("Confirm", ["Reproduce one with proof"])], + "Update core/extensions; harden admin", "Site takeover / data breach"), + A("drupal_audit", "Drupal Security Audit", "Drupal core/module weaknesses (e.g. Drupalgeddon class)", + "CWE-1395", "Critical", + [("Enumerate", ["Version (CHANGELOG, headers), enabled modules"]), + ("Correlate CVEs", ["Map to known Drupal RCE/SQLi (e.g. SA-CORE highly-critical classes)"]), + ("Confirm", ["Reproduce with an OOB/output proof where applicable"])], + "Patch core/modules promptly", "Remote code execution"), + A("cms_default_admin", "CMS Admin Panel & Default Creds", "exposed CMS admin with weak/default credentials", + "CWE-1392", "High", + [("Locate", ["Find admin (`/wp-admin`, `/administrator`, `/user/login`, `/admin`)"]), + ("Test (in scope)", ["Try supplied/default credentials; respect lockout/ROE — no out-of-scope brute force"]), + ("Confirm", ["Show authenticated admin access"])], + "Remove defaults; strong creds + MFA; restrict admin", "Full CMS compromise"), + # ---- app servers / panels ---- + A("appserver_exposure", "App-Server Console Exposure", "exposed Tomcat/JBoss/Jenkins/Actuator consoles", + "CWE-1188", "High", + [("Discover", ["Probe `/manager/html`, `/jmx-console`, `/jenkins`, `/actuator`, `/console`, `/admin`"]), + ("Assess", ["Test default/weak creds (in scope); check unauth-exposed management endpoints"]), + ("Confirm", ["Demonstrate a management action / deploy / info-leak proving exposure (→ often RCE)"])], + "Authenticate & network-restrict consoles; remove defaults", "Remote code execution / takeover"), + A("git_svn_exposure_app", "Exposed VCS / Build Artifacts", "exposed .git/.svn/CI artifacts on the app host", + "CWE-527", "High", + [("Probe", ["Request `/.git/HEAD`, `/.svn/entries`, `/.env`, build/CI artifact paths"]), + ("Recover", ["Dump source (git-dumper) / read secrets"]), + ("Confirm", ["Show recovered source or live secret"])], + "Block VCS/dotfiles from web; rotate secrets", "Source/secret disclosure → RCE"), + # ---- CVE hunting ---- + A("cve_known_exploitation", "Known-CVE Exploitation Specialist", "exploiting known CVEs for the detected stack", + "CWE-1395", "Critical", + [("Identify versions", ["From recon, list each component + exact version (server, framework, CMS, plugins, libs)"]), + ("Map to CVEs", ["Match versions to known CVEs; prioritise unauth RCE/SQLi/auth-bypass; note CVE id + CVSS", + "Prefer issues with a reliable, non-destructive PoC"]), + ("Reproduce safely", ["Run a benign PoC (e.g. a version/echo check or OOB callback) to confirm the CVE is actually present and exploitable — never a destructive payload"]), + ("Confirm", ["Report the CVE only when the PoC produced concrete proof (output/OOB); otherwise report it as 'potentially vulnerable (version match, unconfirmed)'"])], + "Patch/upgrade the affected components; apply vendor advisories", "Depends on CVE — up to full compromise"), + A("outdated_dependency_cve", "Outdated Component CVE Specialist", "outdated front-end/back-end components with known CVEs", + "CWE-1104", "High", + [("Inventory", ["Extract JS libs (jQuery, Angular, etc.), server modules, framework versions from responses/JS/headers"]), + ("Correlate", ["Map each to known CVEs; flag the exploitable, reachable ones"]), + ("Confirm", ["Prove exploitability where a safe PoC exists; else report as version-based exposure"])], + "Upgrade components; dependency scanning in CI", "Varies — XSS/RCE/info-leak"), +] + + +def main(): + os.makedirs(OUT, exist_ok=True) + for a in AGENTS: + open(os.path.join(OUT, a["name"] + ".md"), "w").write(render(a)) + print(f"wrote {len(AGENTS)} app-stack/CVE agents to {OUT}") + + +if __name__ == "__main__": + main()