mirror of
https://github.com/CyberSecurityUP/NeuroSploit.git
synced 2026-09-30 13:09:36 +02:00
v3.5.1: infra/host engagements — IP + SSH/Windows-AD creds + Linux/Win/AD agents + REPL context bar
Infra: - creds.yaml gains `ssh:` (host/port/user/password/key) and `windows:`/`ad:` (host/user/password/domain/ntlm-hash) blocks; multi-block YAML parser. host_instruction() tells agents how to authenticate to the host. - 14 infra agents (agents_md/infra/): port/service scan, SMB enum, Linux privesc/ sudo/cron/SSH, Windows privesc/SMB-signing/WinRM, AD kerberoast/asreproast/ACL/ DCSync/default-creds. Loader gains `infra` category → 317 agents total. - run_host pipeline + `neurosploit host <ip> --creds creds.yaml` (and Mode::Host in run_mode/TUI): host recon (nmap/netexec) → infra agent selection → test → validate → chain → report, with host tooling doctrine + supplied creds. REPL: - Context/status bar above the prompt: "model auth · cwd · mode▸target" (e.g. claude-opus-4-8 sub · /opt/projeto · black-box▸app.acme.com). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
969af20a8e
commit
f8d70ce9c5
23 files changed
+893
-32
No files matched your search
@@ -0,0 +1,35 @@
|
|||||||
|
# AD ACL / DACL Abuse Agent
|
||||||
|
|
||||||
|
## User Prompt
|
||||||
|
You are testing **{target}** (a host/infrastructure target) for dangerous Active Directory ACLs.
|
||||||
|
|
||||||
|
**Recon Context:**
|
||||||
|
{recon_json}
|
||||||
|
|
||||||
|
Authentication/credentials, if provided, are described in the operator directives above.
|
||||||
|
|
||||||
|
**METHODOLOGY:**
|
||||||
|
|
||||||
|
### 1. Map
|
||||||
|
- Collect with bloodhound-python/SharpHound; find GenericAll/WriteDACL/ForceChangePassword edges
|
||||||
|
|
||||||
|
### 2. Confirm
|
||||||
|
- Demonstrate one safe, reversible control step (e.g. shadow-cred / targeted password reset in a lab) proving the path
|
||||||
|
|
||||||
|
### 3. Report Format
|
||||||
|
For each CONFIRMED finding:
|
||||||
|
```
|
||||||
|
FINDING:
|
||||||
|
- Title: AD ACL / DACL Abuse on [host]
|
||||||
|
- Severity: High
|
||||||
|
- CWE: CWE-269
|
||||||
|
- Endpoint: [host/service]
|
||||||
|
- Vector: [how]
|
||||||
|
- Payload: [command/PoC]
|
||||||
|
- Evidence: [raw tool output proving it]
|
||||||
|
- Impact: Domain privilege escalation
|
||||||
|
- Remediation: Tighten ACLs; tiered admin model
|
||||||
|
```
|
||||||
|
|
||||||
|
## System Prompt
|
||||||
|
You are an infrastructure pentest specialist for dangerous Active Directory ACLs. AUTHORIZED engagement. Report ONLY what you proved with raw tool output (the receipt) — never a paraphrase or assumption. If you lack access/observation to confirm, say so and gather more first. Stay in scope; never run destructive or DoS actions. Credits: Joas A Santos & Red Team Leaders.
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# AD AS-REP Roasting Agent
|
||||||
|
|
||||||
|
## User Prompt
|
||||||
|
You are testing **{target}** (a host/infrastructure target) for accounts with Kerberos pre-auth disabled.
|
||||||
|
|
||||||
|
**Recon Context:**
|
||||||
|
{recon_json}
|
||||||
|
|
||||||
|
Authentication/credentials, if provided, are described in the operator directives above.
|
||||||
|
|
||||||
|
**METHODOLOGY:**
|
||||||
|
|
||||||
|
### 1. Enumerate
|
||||||
|
- impacket GetNPUsers / `netexec ldap {target} --asreproast out.txt` for DONT_REQ_PREAUTH accounts
|
||||||
|
|
||||||
|
### 2. Crack & confirm
|
||||||
|
- Crack the AS-REP (hashcat -m 18200); confirm a recovered password
|
||||||
|
|
||||||
|
### 3. Report Format
|
||||||
|
For each CONFIRMED finding:
|
||||||
|
```
|
||||||
|
FINDING:
|
||||||
|
- Title: AD AS-REP Roasting on [host]
|
||||||
|
- Severity: High
|
||||||
|
- CWE: CWE-522
|
||||||
|
- Endpoint: [host/service]
|
||||||
|
- Vector: [how]
|
||||||
|
- Payload: [command/PoC]
|
||||||
|
- Evidence: [raw tool output proving it]
|
||||||
|
- Impact: Account compromise
|
||||||
|
- Remediation: Require Kerberos pre-auth; strong passwords
|
||||||
|
```
|
||||||
|
|
||||||
|
## System Prompt
|
||||||
|
You are an infrastructure pentest specialist for accounts with Kerberos pre-auth disabled. AUTHORIZED engagement. Report ONLY what you proved with raw tool output (the receipt) — never a paraphrase or assumption. If you lack access/observation to confirm, say so and gather more first. Stay in scope; never run destructive or DoS actions. Credits: Joas A Santos & Red Team Leaders.
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# AD DCSync Exposure Agent
|
||||||
|
|
||||||
|
## User Prompt
|
||||||
|
You are testing **{target}** (a host/infrastructure target) for replication rights enabling DCSync.
|
||||||
|
|
||||||
|
**Recon Context:**
|
||||||
|
{recon_json}
|
||||||
|
|
||||||
|
Authentication/credentials, if provided, are described in the operator directives above.
|
||||||
|
|
||||||
|
**METHODOLOGY:**
|
||||||
|
|
||||||
|
### 1. Check rights
|
||||||
|
- Identify principals with DS-Replication-Get-Changes(-All) via BloodHound/ACL review
|
||||||
|
|
||||||
|
### 2. Confirm
|
||||||
|
- With authorized creds, prove replication right (e.g. impacket secretsdump -just-dc-user for a single test account)
|
||||||
|
|
||||||
|
### 3. Report Format
|
||||||
|
For each CONFIRMED finding:
|
||||||
|
```
|
||||||
|
FINDING:
|
||||||
|
- Title: AD DCSync Exposure on [host]
|
||||||
|
- Severity: Critical
|
||||||
|
- CWE: CWE-269
|
||||||
|
- Endpoint: [host/service]
|
||||||
|
- Vector: [how]
|
||||||
|
- Payload: [command/PoC]
|
||||||
|
- Evidence: [raw tool output proving it]
|
||||||
|
- Impact: Full domain credential compromise
|
||||||
|
- Remediation: Remove replication rights from non-DC principals
|
||||||
|
```
|
||||||
|
|
||||||
|
## System Prompt
|
||||||
|
You are an infrastructure pentest specialist for replication rights enabling DCSync. AUTHORIZED engagement. Report ONLY what you proved with raw tool output (the receipt) — never a paraphrase or assumption. If you lack access/observation to confirm, say so and gather more first. Stay in scope; never run destructive or DoS actions. Credits: Joas A Santos & Red Team Leaders.
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# AD/Host Default & Reused Credentials Agent
|
||||||
|
|
||||||
|
## User Prompt
|
||||||
|
You are testing **{target}** (a host/infrastructure target) for default or reused credentials across the domain.
|
||||||
|
|
||||||
|
**Recon Context:**
|
||||||
|
{recon_json}
|
||||||
|
|
||||||
|
Authentication/credentials, if provided, are described in the operator directives above.
|
||||||
|
|
||||||
|
**METHODOLOGY:**
|
||||||
|
|
||||||
|
### 1. Spray (authorized, throttled)
|
||||||
|
- With supplied account list, `netexec smb {target} -u users -p pass --continue-on-success` within ROE
|
||||||
|
|
||||||
|
### 2. Confirm
|
||||||
|
- Show a successful authentication that should not have worked (reused/default cred)
|
||||||
|
|
||||||
|
### 3. Report Format
|
||||||
|
For each CONFIRMED finding:
|
||||||
|
```
|
||||||
|
FINDING:
|
||||||
|
- Title: AD/Host Default & Reused Credentials on [host]
|
||||||
|
- Severity: High
|
||||||
|
- CWE: CWE-798
|
||||||
|
- Endpoint: [host/service]
|
||||||
|
- Vector: [how]
|
||||||
|
- Payload: [command/PoC]
|
||||||
|
- Evidence: [raw tool output proving it]
|
||||||
|
- Impact: Lateral movement, domain access
|
||||||
|
- Remediation: Rotate defaults; enforce unique strong passwords; lockout
|
||||||
|
```
|
||||||
|
|
||||||
|
## System Prompt
|
||||||
|
You are an infrastructure pentest specialist for default or reused credentials across the domain. AUTHORIZED engagement. Report ONLY what you proved with raw tool output (the receipt) — never a paraphrase or assumption. If you lack access/observation to confirm, say so and gather more first. Stay in scope; never run destructive or DoS actions. Credits: Joas A Santos & Red Team Leaders.
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# AD Kerberoasting Agent
|
||||||
|
|
||||||
|
## User Prompt
|
||||||
|
You are testing **{target}** (a host/infrastructure target) for service accounts with crackable SPNs.
|
||||||
|
|
||||||
|
**Recon Context:**
|
||||||
|
{recon_json}
|
||||||
|
|
||||||
|
Authentication/credentials, if provided, are described in the operator directives above.
|
||||||
|
|
||||||
|
**METHODOLOGY:**
|
||||||
|
|
||||||
|
### 1. Request
|
||||||
|
- `netexec ldap {target} -u <user> -p <pass> --kerberoasting out.txt` or impacket GetUserSPNs
|
||||||
|
|
||||||
|
### 2. Crack & confirm
|
||||||
|
- Crack the TGS hash offline (hashcat -m 13100); confirm a recovered service-account password
|
||||||
|
|
||||||
|
### 3. Report Format
|
||||||
|
For each CONFIRMED finding:
|
||||||
|
```
|
||||||
|
FINDING:
|
||||||
|
- Title: AD Kerberoasting on [host]
|
||||||
|
- Severity: High
|
||||||
|
- CWE: CWE-522
|
||||||
|
- Endpoint: [host/service]
|
||||||
|
- Vector: [how]
|
||||||
|
- Payload: [command/PoC]
|
||||||
|
- Evidence: [raw tool output proving it]
|
||||||
|
- Impact: Service-account compromise, lateral movement
|
||||||
|
- Remediation: Strong/long service-account passwords; gMSA
|
||||||
|
```
|
||||||
|
|
||||||
|
## System Prompt
|
||||||
|
You are an infrastructure pentest specialist for service accounts with crackable SPNs. AUTHORIZED engagement. Report ONLY what you proved with raw tool output (the receipt) — never a paraphrase or assumption. If you lack access/observation to confirm, say so and gather more first. Stay in scope; never run destructive or DoS actions. Credits: Joas A Santos & Red Team Leaders.
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# Host Port & Service Scan Agent
|
||||||
|
|
||||||
|
## User Prompt
|
||||||
|
You are testing **{target}** (a host/infrastructure target) for open ports and service/version discovery.
|
||||||
|
|
||||||
|
**Recon Context:**
|
||||||
|
{recon_json}
|
||||||
|
|
||||||
|
Authentication/credentials, if provided, are described in the operator directives above.
|
||||||
|
|
||||||
|
**METHODOLOGY:**
|
||||||
|
|
||||||
|
### 1. Scan
|
||||||
|
- `rustscan -a {target} -- -sV` if present, else `nmap -sV -sC -Pn {target}`
|
||||||
|
- Identify open TCP/UDP ports, service banners and versions
|
||||||
|
|
||||||
|
### 2. Triage
|
||||||
|
- Flag risky services (SMB, RDP, SSH, WinRM, LDAP, databases) and outdated versions
|
||||||
|
- Correlate versions to known CVEs for downstream agents
|
||||||
|
|
||||||
|
### 3. Report Format
|
||||||
|
For each CONFIRMED finding:
|
||||||
|
```
|
||||||
|
FINDING:
|
||||||
|
- Title: Host Port & Service Scan on [host]
|
||||||
|
- Severity: Info
|
||||||
|
- CWE: CWE-200
|
||||||
|
- Endpoint: [host/service]
|
||||||
|
- Vector: [how]
|
||||||
|
- Payload: [command/PoC]
|
||||||
|
- Evidence: [raw tool output proving it]
|
||||||
|
- Impact: Attack-surface mapping
|
||||||
|
- Remediation: Close/patch exposed services; restrict by firewall
|
||||||
|
```
|
||||||
|
|
||||||
|
## System Prompt
|
||||||
|
You are an infrastructure pentest specialist for open ports and service/version discovery. AUTHORIZED engagement. Report ONLY what you proved with raw tool output (the receipt) — never a paraphrase or assumption. If you lack access/observation to confirm, say so and gather more first. Stay in scope; never run destructive or DoS actions. Credits: Joas A Santos & Red Team Leaders.
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# SMB/NetBIOS Enumeration Agent
|
||||||
|
|
||||||
|
## User Prompt
|
||||||
|
You are testing **{target}** (a host/infrastructure target) for SMB shares, sessions and misconfigurations.
|
||||||
|
|
||||||
|
**Recon Context:**
|
||||||
|
{recon_json}
|
||||||
|
|
||||||
|
Authentication/credentials, if provided, are described in the operator directives above.
|
||||||
|
|
||||||
|
**METHODOLOGY:**
|
||||||
|
|
||||||
|
### 1. Enumerate
|
||||||
|
- `netexec smb {target}` / `crackmapexec smb {target}` for hosts, signing, null sessions
|
||||||
|
- `smbclient -L //{target}/ -N` to list shares; check anonymous read/write
|
||||||
|
|
||||||
|
### 2. Assess
|
||||||
|
- Flag SMB signing disabled (relay risk), guest/anonymous access, writable shares
|
||||||
|
|
||||||
|
### 3. Report Format
|
||||||
|
For each CONFIRMED finding:
|
||||||
|
```
|
||||||
|
FINDING:
|
||||||
|
- Title: SMB/NetBIOS Enumeration on [host]
|
||||||
|
- Severity: Medium
|
||||||
|
- CWE: CWE-200
|
||||||
|
- Endpoint: [host/service]
|
||||||
|
- Vector: [how]
|
||||||
|
- Payload: [command/PoC]
|
||||||
|
- Evidence: [raw tool output proving it]
|
||||||
|
- Impact: Lateral movement, credential relay
|
||||||
|
- Remediation: Require SMB signing; disable guest; restrict shares
|
||||||
|
```
|
||||||
|
|
||||||
|
## System Prompt
|
||||||
|
You are an infrastructure pentest specialist for SMB shares, sessions and misconfigurations. AUTHORIZED engagement. Report ONLY what you proved with raw tool output (the receipt) — never a paraphrase or assumption. If you lack access/observation to confirm, say so and gather more first. Stay in scope; never run destructive or DoS actions. Credits: Joas A Santos & Red Team Leaders.
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# Writable Cron / Service Abuse Agent
|
||||||
|
|
||||||
|
## User Prompt
|
||||||
|
You are testing **{target}** (a host/infrastructure target) for world-writable cron jobs or unit files.
|
||||||
|
|
||||||
|
**Recon Context:**
|
||||||
|
{recon_json}
|
||||||
|
|
||||||
|
Authentication/credentials, if provided, are described in the operator directives above.
|
||||||
|
|
||||||
|
**METHODOLOGY:**
|
||||||
|
|
||||||
|
### 1. Find
|
||||||
|
- Inspect /etc/cron*, systemd units, and scripts they call for writable paths
|
||||||
|
|
||||||
|
### 2. Confirm
|
||||||
|
- Plant a benign marker that the privileged job executes, proving control
|
||||||
|
|
||||||
|
### 3. Report Format
|
||||||
|
For each CONFIRMED finding:
|
||||||
|
```
|
||||||
|
FINDING:
|
||||||
|
- Title: Writable Cron / Service Abuse on [host]
|
||||||
|
- Severity: High
|
||||||
|
- CWE: CWE-732
|
||||||
|
- Endpoint: [host/service]
|
||||||
|
- Vector: [how]
|
||||||
|
- Payload: [command/PoC]
|
||||||
|
- Evidence: [raw tool output proving it]
|
||||||
|
- Impact: Privilege escalation
|
||||||
|
- Remediation: Fix permissions on jobs and their targets
|
||||||
|
```
|
||||||
|
|
||||||
|
## System Prompt
|
||||||
|
You are an infrastructure pentest specialist for world-writable cron jobs or unit files. AUTHORIZED engagement. Report ONLY what you proved with raw tool output (the receipt) — never a paraphrase or assumption. If you lack access/observation to confirm, say so and gather more first. Stay in scope; never run destructive or DoS actions. Credits: Joas A Santos & Red Team Leaders.
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# Linux Privilege Escalation Agent
|
||||||
|
|
||||||
|
## User Prompt
|
||||||
|
You are testing **{target}** (a host/infrastructure target) for local privilege-escalation paths on a Linux host.
|
||||||
|
|
||||||
|
**Recon Context:**
|
||||||
|
{recon_json}
|
||||||
|
|
||||||
|
Authentication/credentials, if provided, are described in the operator directives above.
|
||||||
|
|
||||||
|
**METHODOLOGY:**
|
||||||
|
|
||||||
|
### 1. Enumerate (authenticated via SSH)
|
||||||
|
- Run linpeas/`sudo -l`, SUID/SGID (`find / -perm -4000`), cron, capabilities, writable PATH
|
||||||
|
- Check kernel version for known local exploits
|
||||||
|
|
||||||
|
### 2. Confirm
|
||||||
|
- Demonstrate an actual escalation to root (or a clear, reachable path) with command output
|
||||||
|
|
||||||
|
### 3. Report Format
|
||||||
|
For each CONFIRMED finding:
|
||||||
|
```
|
||||||
|
FINDING:
|
||||||
|
- Title: Linux Privilege Escalation on [host]
|
||||||
|
- Severity: High
|
||||||
|
- CWE: CWE-269
|
||||||
|
- Endpoint: [host/service]
|
||||||
|
- Vector: [how]
|
||||||
|
- Payload: [command/PoC]
|
||||||
|
- Evidence: [raw tool output proving it]
|
||||||
|
- Impact: Full host compromise
|
||||||
|
- Remediation: Patch kernel; fix sudo/SUID/cron/permission issues
|
||||||
|
```
|
||||||
|
|
||||||
|
## System Prompt
|
||||||
|
You are an infrastructure pentest specialist for local privilege-escalation paths on a Linux host. AUTHORIZED engagement. Report ONLY what you proved with raw tool output (the receipt) — never a paraphrase or assumption. If you lack access/observation to confirm, say so and gather more first. Stay in scope; never run destructive or DoS actions. Credits: Joas A Santos & Red Team Leaders.
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# SSH Weak Authentication Agent
|
||||||
|
|
||||||
|
## User Prompt
|
||||||
|
You are testing **{target}** (a host/infrastructure target) for weak/guessable SSH credentials or misconfig.
|
||||||
|
|
||||||
|
**Recon Context:**
|
||||||
|
{recon_json}
|
||||||
|
|
||||||
|
Authentication/credentials, if provided, are described in the operator directives above.
|
||||||
|
|
||||||
|
**METHODOLOGY:**
|
||||||
|
|
||||||
|
### 1. Assess
|
||||||
|
- Check allowed auth methods; test provided creds with `ssh`/`sshpass`
|
||||||
|
- Only test supplied credentials — never brute force out of scope
|
||||||
|
|
||||||
|
### 2. Confirm
|
||||||
|
- Show authenticated shell access with the credentials, capturing the session banner
|
||||||
|
|
||||||
|
### 3. Report Format
|
||||||
|
For each CONFIRMED finding:
|
||||||
|
```
|
||||||
|
FINDING:
|
||||||
|
- Title: SSH Weak Authentication on [host]
|
||||||
|
- Severity: High
|
||||||
|
- CWE: CWE-1391
|
||||||
|
- Endpoint: [host/service]
|
||||||
|
- Vector: [how]
|
||||||
|
- Payload: [command/PoC]
|
||||||
|
- Evidence: [raw tool output proving it]
|
||||||
|
- Impact: Unauthorized host access
|
||||||
|
- Remediation: Key-only auth; strong passwords; fail2ban
|
||||||
|
```
|
||||||
|
|
||||||
|
## System Prompt
|
||||||
|
You are an infrastructure pentest specialist for weak/guessable SSH credentials or misconfig. AUTHORIZED engagement. Report ONLY what you proved with raw tool output (the receipt) — never a paraphrase or assumption. If you lack access/observation to confirm, say so and gather more first. Stay in scope; never run destructive or DoS actions. Credits: Joas A Santos & Red Team Leaders.
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# Linux Sudo Misconfiguration Agent
|
||||||
|
|
||||||
|
## User Prompt
|
||||||
|
You are testing **{target}** (a host/infrastructure target) for exploitable sudo rules.
|
||||||
|
|
||||||
|
**Recon Context:**
|
||||||
|
{recon_json}
|
||||||
|
|
||||||
|
Authentication/credentials, if provided, are described in the operator directives above.
|
||||||
|
|
||||||
|
**METHODOLOGY:**
|
||||||
|
|
||||||
|
### 1. Enumerate
|
||||||
|
- `sudo -l`; look for NOPASSWD binaries and GTFObins-exploitable entries
|
||||||
|
|
||||||
|
### 2. Confirm
|
||||||
|
- Escalate via a permitted binary and show `id`=root output
|
||||||
|
|
||||||
|
### 3. Report Format
|
||||||
|
For each CONFIRMED finding:
|
||||||
|
```
|
||||||
|
FINDING:
|
||||||
|
- Title: Linux Sudo Misconfiguration on [host]
|
||||||
|
- Severity: High
|
||||||
|
- CWE: CWE-250
|
||||||
|
- Endpoint: [host/service]
|
||||||
|
- Vector: [how]
|
||||||
|
- Payload: [command/PoC]
|
||||||
|
- Evidence: [raw tool output proving it]
|
||||||
|
- Impact: Privilege escalation to root
|
||||||
|
- Remediation: Restrict sudo to least privilege; avoid shell-capable binaries
|
||||||
|
```
|
||||||
|
|
||||||
|
## System Prompt
|
||||||
|
You are an infrastructure pentest specialist for exploitable sudo rules. AUTHORIZED engagement. Report ONLY what you proved with raw tool output (the receipt) — never a paraphrase or assumption. If you lack access/observation to confirm, say so and gather more first. Stay in scope; never run destructive or DoS actions. Credits: Joas A Santos & Red Team Leaders.
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# Windows Privilege Escalation Agent
|
||||||
|
|
||||||
|
## User Prompt
|
||||||
|
You are testing **{target}** (a host/infrastructure target) for local privilege escalation on a Windows host.
|
||||||
|
|
||||||
|
**Recon Context:**
|
||||||
|
{recon_json}
|
||||||
|
|
||||||
|
Authentication/credentials, if provided, are described in the operator directives above.
|
||||||
|
|
||||||
|
**METHODOLOGY:**
|
||||||
|
|
||||||
|
### 1. Enumerate (authenticated)
|
||||||
|
- Run winPEAS/`whoami /priv`; check unquoted service paths, weak service perms, AlwaysInstallElevated, token privileges (SeImpersonate)
|
||||||
|
|
||||||
|
### 2. Confirm
|
||||||
|
- Demonstrate escalation to SYSTEM/admin with command output (e.g. via a Potato technique where applicable)
|
||||||
|
|
||||||
|
### 3. Report Format
|
||||||
|
For each CONFIRMED finding:
|
||||||
|
```
|
||||||
|
FINDING:
|
||||||
|
- Title: Windows Privilege Escalation on [host]
|
||||||
|
- Severity: High
|
||||||
|
- CWE: CWE-269
|
||||||
|
- Endpoint: [host/service]
|
||||||
|
- Vector: [how]
|
||||||
|
- Payload: [command/PoC]
|
||||||
|
- Evidence: [raw tool output proving it]
|
||||||
|
- Impact: Full host compromise
|
||||||
|
- Remediation: Patch; fix service perms; remove dangerous privileges
|
||||||
|
```
|
||||||
|
|
||||||
|
## System Prompt
|
||||||
|
You are an infrastructure pentest specialist for local privilege escalation on a Windows host. AUTHORIZED engagement. Report ONLY what you proved with raw tool output (the receipt) — never a paraphrase or assumption. If you lack access/observation to confirm, say so and gather more first. Stay in scope; never run destructive or DoS actions. Credits: Joas A Santos & Red Team Leaders.
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# SMB Signing & Relay Exposure Agent
|
||||||
|
|
||||||
|
## User Prompt
|
||||||
|
You are testing **{target}** (a host/infrastructure target) for SMB signing not required (NTLM relay risk).
|
||||||
|
|
||||||
|
**Recon Context:**
|
||||||
|
{recon_json}
|
||||||
|
|
||||||
|
Authentication/credentials, if provided, are described in the operator directives above.
|
||||||
|
|
||||||
|
**METHODOLOGY:**
|
||||||
|
|
||||||
|
### 1. Detect
|
||||||
|
- `netexec smb {target}` — note `signing:False`
|
||||||
|
|
||||||
|
### 2. Assess
|
||||||
|
- Explain the NTLM-relay exposure; confirm a coercible auth path only if in scope
|
||||||
|
|
||||||
|
### 3. Report Format
|
||||||
|
For each CONFIRMED finding:
|
||||||
|
```
|
||||||
|
FINDING:
|
||||||
|
- Title: SMB Signing & Relay Exposure on [host]
|
||||||
|
- Severity: Medium
|
||||||
|
- CWE: CWE-294
|
||||||
|
- Endpoint: [host/service]
|
||||||
|
- Vector: [how]
|
||||||
|
- Payload: [command/PoC]
|
||||||
|
- Evidence: [raw tool output proving it]
|
||||||
|
- Impact: Credential relay, lateral movement
|
||||||
|
- Remediation: Enforce SMB signing; disable NTLM where possible
|
||||||
|
```
|
||||||
|
|
||||||
|
## System Prompt
|
||||||
|
You are an infrastructure pentest specialist for SMB signing not required (NTLM relay risk). AUTHORIZED engagement. Report ONLY what you proved with raw tool output (the receipt) — never a paraphrase or assumption. If you lack access/observation to confirm, say so and gather more first. Stay in scope; never run destructive or DoS actions. Credits: Joas A Santos & Red Team Leaders.
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# WinRM Authenticated Access Agent
|
||||||
|
|
||||||
|
## User Prompt
|
||||||
|
You are testing **{target}** (a host/infrastructure target) for remote management access via WinRM.
|
||||||
|
|
||||||
|
**Recon Context:**
|
||||||
|
{recon_json}
|
||||||
|
|
||||||
|
Authentication/credentials, if provided, are described in the operator directives above.
|
||||||
|
|
||||||
|
**METHODOLOGY:**
|
||||||
|
|
||||||
|
### 1. Connect
|
||||||
|
- `evil-winrm -i {target} -u <user> -p <pass>` (or -H <hash>) with supplied creds/hash
|
||||||
|
|
||||||
|
### 2. Confirm
|
||||||
|
- Show an authenticated remote shell and the host context (`whoami`, hostname)
|
||||||
|
|
||||||
|
### 3. Report Format
|
||||||
|
For each CONFIRMED finding:
|
||||||
|
```
|
||||||
|
FINDING:
|
||||||
|
- Title: WinRM Authenticated Access on [host]
|
||||||
|
- Severity: Medium
|
||||||
|
- CWE: CWE-287
|
||||||
|
- Endpoint: [host/service]
|
||||||
|
- Vector: [how]
|
||||||
|
- Payload: [command/PoC]
|
||||||
|
- Evidence: [raw tool output proving it]
|
||||||
|
- Impact: Remote host control
|
||||||
|
- Remediation: Restrict WinRM; strong creds; network segmentation
|
||||||
|
```
|
||||||
|
|
||||||
|
## System Prompt
|
||||||
|
You are an infrastructure pentest specialist for remote management access via WinRM. AUTHORIZED engagement. Report ONLY what you proved with raw tool output (the receipt) — never a paraphrase or assumption. If you lack access/observation to confirm, say so and gather more first. Stay in scope; never run destructive or DoS actions. Credits: Joas A Santos & Red Team Leaders.
|
||||||
@@ -130,6 +130,29 @@ enum Cmd {
|
|||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
mcp: bool,
|
mcp: bool,
|
||||||
},
|
},
|
||||||
|
/// Infra/host: scan an IP/host and run Linux/Windows/AD agents. SSH/Windows
|
||||||
|
/// credentials come from --creds (creds.yaml ssh:/windows: blocks).
|
||||||
|
Host {
|
||||||
|
/// Target host or IP.
|
||||||
|
target: String,
|
||||||
|
#[arg(long = "model")]
|
||||||
|
models: Vec<String>,
|
||||||
|
/// Credentials YAML (ssh / windows / ad blocks).
|
||||||
|
#[arg(long)]
|
||||||
|
creds: Option<String>,
|
||||||
|
#[arg(long)]
|
||||||
|
focus: Option<String>,
|
||||||
|
#[arg(long, default_value_t = 0)]
|
||||||
|
max_agents: usize,
|
||||||
|
#[arg(long, default_value_t = 3)]
|
||||||
|
vote_n: usize,
|
||||||
|
#[arg(long)]
|
||||||
|
offline: bool,
|
||||||
|
#[arg(long)]
|
||||||
|
subscription: bool,
|
||||||
|
#[arg(short, long)]
|
||||||
|
verbose: bool,
|
||||||
|
},
|
||||||
/// Show agent library counts.
|
/// Show agent library counts.
|
||||||
Agents,
|
Agents,
|
||||||
/// List providers and models.
|
/// List providers and models.
|
||||||
@@ -178,8 +201,8 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
Cmd::Agents => {
|
Cmd::Agents => {
|
||||||
let lib = agents::load(&base);
|
let lib = agents::load(&base);
|
||||||
println!(
|
println!(
|
||||||
"{{\"vulns\":{},\"recon\":{},\"code\":{},\"meta\":{},\"total\":{}}}",
|
"{{\"vulns\":{},\"recon\":{},\"code\":{},\"infra\":{},\"meta\":{},\"total\":{}}}",
|
||||||
lib.vulns.len(), lib.recon.len(), lib.code.len(), lib.meta.len(), lib.total()
|
lib.vulns.len(), lib.recon.len(), lib.code.len(), lib.infra.len(), lib.meta.len(), lib.total()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Cmd::Models => {
|
Cmd::Models => {
|
||||||
@@ -251,6 +274,21 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
let mode = if repo.is_some() { Mode::Grey } else { Mode::Black };
|
let mode = if repo.is_some() { Mode::Grey } else { Mode::Black };
|
||||||
tui::run(&base, cfg, mcp, mode).await?;
|
tui::run(&base, cfg, mcp, mode).await?;
|
||||||
}
|
}
|
||||||
|
Cmd::Host { target, models, creds, focus, max_agents, vote_n, offline, subscription, verbose } => {
|
||||||
|
let mut cfg = RunConfig::new(&target);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
apply_creds(&mut cfg, creds.as_deref()).await;
|
||||||
|
let out = run_mode(&base, cfg, false, Mode::Host).await?;
|
||||||
|
print_findings(&out);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -274,6 +312,13 @@ pub(crate) async fn apply_creds(cfg: &mut RunConfig, path: Option<&str>) {
|
|||||||
if cfg.auth.is_none() {
|
if cfg.auth.is_none() {
|
||||||
cfg.auth = c.auth_header();
|
cfg.auth = c.auth_header();
|
||||||
}
|
}
|
||||||
|
// Host credentials (SSH / Windows-AD) → tell the agents how to authenticate
|
||||||
|
// to the host so they can run on-host enumeration / privesc / AD checks.
|
||||||
|
if let Some(hi) = c.host_instruction() {
|
||||||
|
let base = cfg.instructions.clone().unwrap_or_default();
|
||||||
|
cfg.instructions = Some(format!("{hi}\n{base}"));
|
||||||
|
println!(" [*] host credentials loaded (SSH/Windows-AD)");
|
||||||
|
}
|
||||||
// No direct material but a login flow → perform it now.
|
// No direct material but a login flow → perform it now.
|
||||||
if cfg.auth.is_none() {
|
if cfg.auth.is_none() {
|
||||||
if let Some(login) = &c.login {
|
if let Some(login) = &c.login {
|
||||||
@@ -296,7 +341,7 @@ pub(crate) async fn apply_creds(cfg: &mut RunConfig, path: Option<&str>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
pub(crate) enum Mode { Black, White, Grey }
|
pub(crate) enum Mode { Black, White, Grey, Host }
|
||||||
|
|
||||||
pub(crate) async fn run_greybox_engagement(base: &Path, cfg: RunConfig, mcp: bool) -> anyhow::Result<RunOutput> {
|
pub(crate) async fn run_greybox_engagement(base: &Path, cfg: RunConfig, mcp: bool) -> anyhow::Result<RunOutput> {
|
||||||
run_mode(base, cfg, mcp, Mode::Grey).await
|
run_mode(base, cfg, mcp, Mode::Grey).await
|
||||||
@@ -327,7 +372,7 @@ async fn run_mode(base: &Path, mut cfg: RunConfig, mcp: bool, mode: Mode) -> any
|
|||||||
println!(" │ repo : {}", cfg.repo.clone().unwrap_or_default());
|
println!(" │ repo : {}", cfg.repo.clone().unwrap_or_default());
|
||||||
}
|
}
|
||||||
println!(" └─ mode : {}{}{}",
|
println!(" └─ mode : {}{}{}",
|
||||||
match mode { Mode::White => "white-box", Mode::Grey => "greybox", Mode::Black => "black-box" },
|
match mode { Mode::White => "white-box", Mode::Grey => "greybox", Mode::Host => "host/infra", Mode::Black => "black-box" },
|
||||||
if cfg.subscription { " · subscription" } else { " · api" },
|
if cfg.subscription { " · subscription" } else { " · api" },
|
||||||
if mcp { " · mcp" } else { "" });
|
if mcp { " · mcp" } else { "" });
|
||||||
|
|
||||||
@@ -376,6 +421,7 @@ async fn run_mode(base: &Path, mut cfg: RunConfig, mcp: bool, mode: Mode) -> any
|
|||||||
let out = match mode {
|
let out = match mode {
|
||||||
Mode::White => harness::run_whitebox(cfg, &lib, &pool, tx).await,
|
Mode::White => harness::run_whitebox(cfg, &lib, &pool, tx).await,
|
||||||
Mode::Grey => harness::run_greybox(cfg, &lib, &pool, tx).await,
|
Mode::Grey => harness::run_greybox(cfg, &lib, &pool, tx).await,
|
||||||
|
Mode::Host => harness::run_host(cfg, &lib, &pool, tx).await,
|
||||||
Mode::Black => harness::run(cfg, &lib, &pool, tx).await,
|
Mode::Black => harness::run(cfg, &lib, &pool, tx).await,
|
||||||
};
|
};
|
||||||
out
|
out
|
||||||
|
|||||||
@@ -131,8 +131,6 @@ impl Default for Session {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const PROMPT: &str = "\x1b[35mneurosploit›\x1b[0m ";
|
|
||||||
|
|
||||||
/// Line reader: full rustyline editing (Tab-complete, history, multiline) when
|
/// Line reader: full rustyline editing (Tab-complete, history, multiline) when
|
||||||
/// interactive, plain stdin when piped.
|
/// interactive, plain stdin when piped.
|
||||||
enum Reader {
|
enum Reader {
|
||||||
@@ -157,9 +155,10 @@ impl Reader {
|
|||||||
|
|
||||||
/// Returns None to exit (EOF / Ctrl-D), Some(line) otherwise. Ctrl-C cancels
|
/// Returns None to exit (EOF / Ctrl-D), Some(line) otherwise. Ctrl-C cancels
|
||||||
/// the current line (returns an empty string) instead of exiting.
|
/// the current line (returns an empty string) instead of exiting.
|
||||||
fn read(&mut self) -> Option<String> {
|
/// `prompt` is the dynamic context bar + prompt to show.
|
||||||
|
fn read(&mut self, prompt: &str) -> Option<String> {
|
||||||
match self {
|
match self {
|
||||||
Reader::Rl(ed, hist) => match ed.readline(PROMPT) {
|
Reader::Rl(ed, hist) => match ed.readline(prompt) {
|
||||||
Ok(l) => {
|
Ok(l) => {
|
||||||
// Join multiline input: a trailing `\` continued the line.
|
// Join multiline input: a trailing `\` continued the line.
|
||||||
let l = l.replace("\\\n", " ").replace('\n', " ");
|
let l = l.replace("\\\n", " ").replace('\n', " ");
|
||||||
@@ -174,7 +173,7 @@ impl Reader {
|
|||||||
},
|
},
|
||||||
Reader::Plain(stdin) => {
|
Reader::Plain(stdin) => {
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
print!("{PROMPT}");
|
print!("{prompt}");
|
||||||
std::io::stdout().flush().ok();
|
std::io::stdout().flush().ok();
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
match stdin.read_line(&mut s) {
|
match stdin.read_line(&mut s) {
|
||||||
@@ -209,7 +208,7 @@ pub async fn repl(base: &Path) -> anyhow::Result<()> {
|
|||||||
show(&s);
|
show(&s);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let Some(line) = reader.read() else { println!("\n bye."); break };
|
let Some(line) = reader.read(&context_prompt(&s)) else { println!("\n bye."); break };
|
||||||
let line = line.trim();
|
let line = line.trim();
|
||||||
if line.is_empty() {
|
if line.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
@@ -590,5 +589,26 @@ fn parse_range(r: &str) -> Option<(usize, usize)> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Context/status bar shown above the prompt — model · cwd · mode/target,
|
||||||
|
/// e.g. "claude-opus-4-8 · /opt/projeto · black-box▸target".
|
||||||
|
fn context_prompt(s: &Session) -> String {
|
||||||
|
let model = s.models.first().map(|m| m.split(':').next_back().unwrap_or(m)).unwrap_or("?");
|
||||||
|
let auth = if s.subscription { "sub" } else { "api" };
|
||||||
|
let cwd = std::env::current_dir().ok()
|
||||||
|
.map(|p| p.display().to_string())
|
||||||
|
.unwrap_or_else(|| ".".into());
|
||||||
|
let mode = match (&s.repo, &s.target) {
|
||||||
|
(Some(_), Some(_)) => "greybox",
|
||||||
|
(Some(_), None) => "white-box",
|
||||||
|
(None, Some(_)) => "black-box",
|
||||||
|
_ => "idle",
|
||||||
|
};
|
||||||
|
let tgt = s.target.clone().or_else(|| s.repo.clone()).unwrap_or_default();
|
||||||
|
let tgt = if tgt.is_empty() { String::new() } else { format!("▸{}", tgt.replace("https://", "").replace("http://", "")) };
|
||||||
|
format!(
|
||||||
|
"\x1b[2m{model} {auth} · {cwd} · {mode}{tgt}\x1b[0m\n\x1b[35mneurosploit›\x1b[0m "
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn onoff(b: bool) -> &'static str { if b { "on" } else { "off" } }
|
fn onoff(b: bool) -> &'static str { if b { "on" } else { "off" } }
|
||||||
fn trunc(s: &str, n: usize) -> String { if s.len() <= n { s.to_string() } else { format!("{}…", &s[..n.saturating_sub(1)]) } }
|
fn trunc(s: &str, n: usize) -> String { if s.len() <= n { s.to_string() } else { format!("{}…", &s[..n.saturating_sub(1)]) } }
|
||||||
@@ -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 (tx, mut rx) = tokio::sync::mpsc::channel::<String>(512);
|
||||||
let models = cfg.models.join(", ");
|
let models = cfg.models.join(", ");
|
||||||
let mode_s = match mode { Mode::White => "white-box", Mode::Grey => "greybox", Mode::Black => "black-box" };
|
let mode_s = match mode { Mode::White => "white-box", Mode::Grey => "greybox", Mode::Host => "host/infra", Mode::Black => "black-box" };
|
||||||
let target_s = cfg.target.clone();
|
let target_s = cfg.target.clone();
|
||||||
|
|
||||||
// ---- terminal setup FIRST: on a non-TTY this errors before we spawn any
|
// ---- terminal setup FIRST: on a non-TTY this errors before we spawn any
|
||||||
@@ -162,6 +162,7 @@ pub async fn run(base: &Path, mut cfg: RunConfig, mcp: bool, mode: Mode) -> anyh
|
|||||||
match mode {
|
match mode {
|
||||||
Mode::White => harness::run_whitebox(cfg, &lib, &pool, tx).await,
|
Mode::White => harness::run_whitebox(cfg, &lib, &pool, tx).await,
|
||||||
Mode::Grey => harness::run_greybox(cfg, &lib, &pool, tx).await,
|
Mode::Grey => harness::run_greybox(cfg, &lib, &pool, tx).await,
|
||||||
|
Mode::Host => harness::run_host(cfg, &lib, &pool, tx).await,
|
||||||
Mode::Black => harness::run(cfg, &lib, &pool, tx).await,
|
Mode::Black => harness::run(cfg, &lib, &pool, tx).await,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -23,11 +23,12 @@ pub struct Library {
|
|||||||
pub meta: Vec<Agent>,
|
pub meta: Vec<Agent>,
|
||||||
pub recon: Vec<Agent>,
|
pub recon: Vec<Agent>,
|
||||||
pub code: Vec<Agent>,
|
pub code: Vec<Agent>,
|
||||||
|
pub infra: Vec<Agent>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Library {
|
impl Library {
|
||||||
pub fn total(&self) -> usize {
|
pub fn total(&self) -> usize {
|
||||||
self.vulns.len() + self.meta.len() + self.recon.len() + self.code.len()
|
self.vulns.len() + self.meta.len() + self.recon.len() + self.code.len() + self.infra.len()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,6 +40,7 @@ pub fn load(base: &Path) -> Library {
|
|||||||
meta: load_dir(&root.join("meta"), "meta"),
|
meta: load_dir(&root.join("meta"), "meta"),
|
||||||
recon: load_dir(&root.join("recon"), "recon"),
|
recon: load_dir(&root.join("recon"), "recon"),
|
||||||
code: load_dir(&root.join("code"), "code"),
|
code: load_dir(&root.join("code"), "code"),
|
||||||
|
infra: load_dir(&root.join("infra"), "infra"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,12 +31,34 @@ pub struct Login {
|
|||||||
pub success: String,
|
pub success: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// SSH credentials for Linux host testing.
|
||||||
|
#[derive(Default, Debug, Clone)]
|
||||||
|
pub struct Ssh {
|
||||||
|
pub host: String,
|
||||||
|
pub port: String, // default 22
|
||||||
|
pub user: String,
|
||||||
|
pub password: String,
|
||||||
|
pub key: String, // path to a private key
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Windows / Active Directory credentials.
|
||||||
|
#[derive(Default, Debug, Clone)]
|
||||||
|
pub struct Win {
|
||||||
|
pub host: String,
|
||||||
|
pub user: String,
|
||||||
|
pub password: String,
|
||||||
|
pub domain: String,
|
||||||
|
pub hash: String, // NTLM hash for pass-the-hash (LM:NT or NT)
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone)]
|
#[derive(Default, Debug, Clone)]
|
||||||
pub struct Creds {
|
pub struct Creds {
|
||||||
pub jwt: Option<String>,
|
pub jwt: Option<String>,
|
||||||
pub header: Option<String>,
|
pub header: Option<String>,
|
||||||
pub cookie: Option<String>,
|
pub cookie: Option<String>,
|
||||||
pub login: Option<Login>,
|
pub login: Option<Login>,
|
||||||
|
pub ssh: Option<Ssh>,
|
||||||
|
pub win: Option<Win>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Creds {
|
impl Creds {
|
||||||
@@ -44,8 +66,10 @@ impl Creds {
|
|||||||
let text = std::fs::read_to_string(path).ok()?;
|
let text = std::fs::read_to_string(path).ok()?;
|
||||||
let mut c = Creds::default();
|
let mut c = Creds::default();
|
||||||
let mut login = Login { method: "POST".into(), ..Default::default() };
|
let mut login = Login { method: "POST".into(), ..Default::default() };
|
||||||
let mut in_login = false;
|
let mut ssh = Ssh { port: "22".into(), ..Default::default() };
|
||||||
let mut have_login = false;
|
let mut win = Win::default();
|
||||||
|
let (mut have_login, mut have_ssh, mut have_win) = (false, false, false);
|
||||||
|
let mut block = ""; // "", "login", "ssh", "windows"
|
||||||
for raw in text.lines() {
|
for raw in text.lines() {
|
||||||
let line = raw.split('#').next().unwrap_or("");
|
let line = raw.split('#').next().unwrap_or("");
|
||||||
if line.trim().is_empty() {
|
if line.trim().is_empty() {
|
||||||
@@ -56,25 +80,49 @@ impl Creds {
|
|||||||
Some((k, v)) => (k.trim().to_string(), unquote(v.trim())),
|
Some((k, v)) => (k.trim().to_string(), unquote(v.trim())),
|
||||||
None => continue,
|
None => continue,
|
||||||
};
|
};
|
||||||
if k == "login" && v.is_empty() {
|
// Enter a nested block (header line with empty value).
|
||||||
in_login = true;
|
if v.is_empty() && !indented {
|
||||||
have_login = true;
|
block = match k.as_str() {
|
||||||
|
"login" => { have_login = true; "login" }
|
||||||
|
"ssh" => { have_ssh = true; "ssh" }
|
||||||
|
"windows" | "win" | "ad" => { have_win = true; "windows" }
|
||||||
|
_ => "",
|
||||||
|
};
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if in_login && indented {
|
if indented {
|
||||||
match k.as_str() {
|
match block {
|
||||||
"url" => login.url = v,
|
"login" => match k.as_str() {
|
||||||
"method" => login.method = v.to_uppercase(),
|
"url" => login.url = v,
|
||||||
"username_field" => login.username_field = v,
|
"method" => login.method = v.to_uppercase(),
|
||||||
"password_field" => login.password_field = v,
|
"username_field" => login.username_field = v,
|
||||||
"username" | "user" => login.username = v,
|
"password_field" => login.password_field = v,
|
||||||
"password" | "pass" => login.password = v,
|
"username" | "user" => login.username = v,
|
||||||
"success" => login.success = v,
|
"password" | "pass" => login.password = v,
|
||||||
|
"success" => login.success = v,
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
"ssh" => match k.as_str() {
|
||||||
|
"host" | "ip" => ssh.host = v,
|
||||||
|
"port" => ssh.port = v,
|
||||||
|
"user" | "username" => ssh.user = v,
|
||||||
|
"password" | "pass" => ssh.password = v,
|
||||||
|
"key" | "keyfile" | "identity" => ssh.key = v,
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
"windows" => match k.as_str() {
|
||||||
|
"host" | "ip" => win.host = v,
|
||||||
|
"user" | "username" => win.user = v,
|
||||||
|
"password" | "pass" => win.password = v,
|
||||||
|
"domain" => win.domain = v,
|
||||||
|
"hash" | "ntlm" => win.hash = v,
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
in_login = false;
|
block = "";
|
||||||
match k.as_str() {
|
match k.as_str() {
|
||||||
"jwt" | "token" => c.jwt = Some(v),
|
"jwt" | "token" => c.jwt = Some(v),
|
||||||
"header" => c.header = Some(v),
|
"header" => c.header = Some(v),
|
||||||
@@ -82,15 +130,37 @@ impl Creds {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if have_login && !login.url.is_empty() {
|
if have_login && !login.url.is_empty() { c.login = Some(login); }
|
||||||
c.login = Some(login);
|
if have_ssh && !ssh.host.is_empty() { c.ssh = Some(ssh); }
|
||||||
}
|
if have_win && !win.host.is_empty() { c.win = Some(win); }
|
||||||
if c.jwt.is_none() && c.header.is_none() && c.cookie.is_none() && c.login.is_none() {
|
if c.jwt.is_none() && c.header.is_none() && c.cookie.is_none()
|
||||||
|
&& c.login.is_none() && c.ssh.is_none() && c.win.is_none() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Some(c)
|
Some(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A directive describing the host credentials available to the agents, so
|
||||||
|
/// they can authenticate to Linux (SSH) / Windows (AD) hosts.
|
||||||
|
pub fn host_instruction(&self) -> Option<String> {
|
||||||
|
let mut s = String::new();
|
||||||
|
if let Some(h) = &self.ssh {
|
||||||
|
let auth = if !h.key.is_empty() { format!("private key {}", h.key) } else { "password (provided)".into() };
|
||||||
|
s.push_str(&format!(
|
||||||
|
"SSH ACCESS (Linux): host {}:{} as user '{}' via {}. Use `ssh`/`sshpass` to run \
|
||||||
|
enumeration and privilege-escalation checks on the host.\n",
|
||||||
|
h.host, h.port, h.user, auth));
|
||||||
|
}
|
||||||
|
if let Some(w) = &self.win {
|
||||||
|
let auth = if !w.hash.is_empty() { "NTLM hash (pass-the-hash)".to_string() } else { "password".into() };
|
||||||
|
s.push_str(&format!(
|
||||||
|
"WINDOWS/AD ACCESS: host {} domain '{}' as user '{}' via {}. Use tools like \
|
||||||
|
crackmapexec/netexec, impacket, evil-winrm, bloodhound-python for host and AD checks.\n",
|
||||||
|
w.host, if w.domain.is_empty() { "(workgroup)" } else { &w.domain }, w.user, auth));
|
||||||
|
}
|
||||||
|
if s.is_empty() { None } else { Some(s) }
|
||||||
|
}
|
||||||
|
|
||||||
/// The auth material to send with each request, as a header line.
|
/// The auth material to send with each request, as a header line.
|
||||||
pub fn auth_header(&self) -> Option<String> {
|
pub fn auth_header(&self) -> Option<String> {
|
||||||
if let Some(h) = &self.header {
|
if let Some(h) = &self.header {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ pub use models::{
|
|||||||
cli_binary_for, ensure_playwright_mcp, installed_cli_backends, mcp_supported, provider_for,
|
cli_binary_for, ensure_playwright_mcp, installed_cli_backends, mcp_supported, provider_for,
|
||||||
providers, write_mcp_config, ChatClient, ModelRef, Provider,
|
providers, write_mcp_config, ChatClient, ModelRef, Provider,
|
||||||
};
|
};
|
||||||
pub use pipeline::{run_greybox, run_whitebox, RunOutput};
|
pub use pipeline::{run_greybox, run_host, run_whitebox, RunOutput};
|
||||||
pub use pipeline::run;
|
pub use pipeline::run;
|
||||||
pub use pool::{ModelPool, Task};
|
pub use pool::{ModelPool, Task};
|
||||||
pub use types::{Finding, RunConfig};
|
pub use types::{Finding, RunConfig};
|
||||||
@@ -864,3 +864,98 @@ fn collect_repo_context(root: &Path, max_files: usize, max_bytes: usize) -> Stri
|
|||||||
}
|
}
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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";
|
||||||
|
|
||||||
|
/// Infrastructure engagement: scan/enumerate an IP/host and run Linux/Windows/AD
|
||||||
|
/// agents. Mirrors the web pipeline but selects from the `infra` agent set.
|
||||||
|
pub async fn run_host(cfg: RunConfig, lib: &Library, pool: &ModelPool, tx: Sender<String>) -> RunOutput {
|
||||||
|
pool.set_progress(tx.clone());
|
||||||
|
let _ = tx.send(format!("HOST · target: {} · {} infra agents · models: {}", cfg.target, lib.infra.len(),
|
||||||
|
pool.candidates.iter().map(|m| m.label()).collect::<Vec<_>>().join(", "))).await;
|
||||||
|
|
||||||
|
let recon = if cfg.offline {
|
||||||
|
"{}".to_string()
|
||||||
|
} else {
|
||||||
|
let user = format!("{}{}Target host: {}", operator_directives(&cfg), HOST_TOOLING, cfg.target);
|
||||||
|
match pool.complete_routed(Task::Recon, "recon", HOST_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.infra.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 {} infra agent(s); no live testing", 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 };
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {} infra 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.is_cancelled() { 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 host engagement on {target}. Proceed and PROVE each issue with raw tool output.\n\n{directives}{tooling}{react}{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 = HOST_TOOLING, react = REACT_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 { let _ = txc.send(format!("finding: [{}] {} @ {}", c.severity, c.title, c.endpoint)).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 mut findings = validate(candidates, pool, VOTE_SYS, cfg.vote_n, &tx).await;
|
||||||
|
let chained = chain_round(pool, &cfg.target, &recon, &operator_directives(&cfg), &findings, &tx).await;
|
||||||
|
if !chained.is_empty() {
|
||||||
|
let extra = validate(dedup_findings(chained), pool, VOTE_SYS, cfg.vote_n, &tx).await;
|
||||||
|
findings.extend(extra);
|
||||||
|
findings = dedup_findings(findings);
|
||||||
|
}
|
||||||
|
finish(cfg, lib, recon, transcript, findings, selected, &mut rl, tx).await
|
||||||
|
}
|
||||||
@@ -20,3 +20,18 @@ login:
|
|||||||
username: admin
|
username: admin
|
||||||
password: password
|
password: password
|
||||||
success: Logout # text that appears on a successful login
|
success: Logout # text that appears on a successful login
|
||||||
|
|
||||||
|
# --- infra/host credentials (used by `neurosploit host <ip> --creds creds.yaml`) ---
|
||||||
|
ssh:
|
||||||
|
host: 10.0.0.5
|
||||||
|
port: 22
|
||||||
|
user: ubuntu
|
||||||
|
password: s3cret # or:
|
||||||
|
key: /home/op/id_ed25519
|
||||||
|
|
||||||
|
windows: # also used for Active Directory
|
||||||
|
host: 10.0.0.10
|
||||||
|
domain: CORP
|
||||||
|
user: jdoe
|
||||||
|
password: Winter2026! # or pass-the-hash:
|
||||||
|
hash: aad3b435b51404eeaad3b435b51404ee:NThashhere
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
NeuroSploit v3.5.1 — infrastructure host agents (Linux / Windows / Active Directory).
|
||||||
|
Writes agents_md/infra/*.md. 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", "infra")
|
||||||
|
|
||||||
|
|
||||||
|
def render(a):
|
||||||
|
L = [f"# {a['title']} Agent\n", "## User Prompt",
|
||||||
|
f"You are testing **{{target}}** (a host/infrastructure target) for {a['for']}.\n",
|
||||||
|
"**Recon Context:**\n{recon_json}\n",
|
||||||
|
"Authentication/credentials, if provided, are described in the operator directives above.\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']} on [host]", f"- Severity: {a['sev']}", f"- CWE: {a['cwe']}",
|
||||||
|
"- Endpoint: [host/service]", "- Vector: [how]", "- Payload: [command/PoC]",
|
||||||
|
"- 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 an infrastructure pentest specialist for {vc}. AUTHORIZED engagement. "
|
||||||
|
"Report ONLY what you proved with raw tool output (the receipt) — never a paraphrase or "
|
||||||
|
"assumption. If you lack access/observation to confirm, say so and gather more first. "
|
||||||
|
"Stay in scope; never run destructive or DoS actions. Credits: Joas A Santos & Red Team Leaders."}
|
||||||
|
|
||||||
|
|
||||||
|
INFRA = [
|
||||||
|
# ---- recon / network ----
|
||||||
|
A("infra_port_service_scan", "Host Port & Service Scan", "open ports and service/version discovery", "CWE-200", "Info",
|
||||||
|
[("Scan", ["`rustscan -a {target} -- -sV` if present, else `nmap -sV -sC -Pn {target}`",
|
||||||
|
"Identify open TCP/UDP ports, service banners and versions"]),
|
||||||
|
("Triage", ["Flag risky services (SMB, RDP, SSH, WinRM, LDAP, databases) and outdated versions",
|
||||||
|
"Correlate versions to known CVEs for downstream agents"])],
|
||||||
|
"Close/patch exposed services; restrict by firewall", "Attack-surface mapping"),
|
||||||
|
A("infra_smb_enum", "SMB/NetBIOS Enumeration", "SMB shares, sessions and misconfigurations", "CWE-200", "Medium",
|
||||||
|
[("Enumerate", ["`netexec smb {target}` / `crackmapexec smb {target}` for hosts, signing, null sessions",
|
||||||
|
"`smbclient -L //{target}/ -N` to list shares; check anonymous read/write"]),
|
||||||
|
("Assess", ["Flag SMB signing disabled (relay risk), guest/anonymous access, writable shares"])],
|
||||||
|
"Require SMB signing; disable guest; restrict shares", "Lateral movement, credential relay"),
|
||||||
|
# ---- linux ----
|
||||||
|
A("linux_priv_esc", "Linux Privilege Escalation", "local privilege-escalation paths on a Linux host", "CWE-269", "High",
|
||||||
|
[("Enumerate (authenticated via SSH)", ["Run linpeas/`sudo -l`, SUID/SGID (`find / -perm -4000`), cron, capabilities, writable PATH",
|
||||||
|
"Check kernel version for known local exploits"]),
|
||||||
|
("Confirm", ["Demonstrate an actual escalation to root (or a clear, reachable path) with command output"])],
|
||||||
|
"Patch kernel; fix sudo/SUID/cron/permission issues", "Full host compromise"),
|
||||||
|
A("linux_ssh_weak_auth", "SSH Weak Authentication", "weak/guessable SSH credentials or misconfig", "CWE-1391", "High",
|
||||||
|
[("Assess", ["Check allowed auth methods; test provided creds with `ssh`/`sshpass`",
|
||||||
|
"Only test supplied credentials — never brute force out of scope"]),
|
||||||
|
("Confirm", ["Show authenticated shell access with the credentials, capturing the session banner"])],
|
||||||
|
"Key-only auth; strong passwords; fail2ban", "Unauthorized host access"),
|
||||||
|
A("linux_sudo_misconfig", "Linux Sudo Misconfiguration", "exploitable sudo rules", "CWE-250", "High",
|
||||||
|
[("Enumerate", ["`sudo -l`; look for NOPASSWD binaries and GTFObins-exploitable entries"]),
|
||||||
|
("Confirm", ["Escalate via a permitted binary and show `id`=root output"])],
|
||||||
|
"Restrict sudo to least privilege; avoid shell-capable binaries", "Privilege escalation to root"),
|
||||||
|
A("linux_cron_writable", "Writable Cron / Service Abuse", "world-writable cron jobs or unit files", "CWE-732", "High",
|
||||||
|
[("Find", ["Inspect /etc/cron*, systemd units, and scripts they call for writable paths"]),
|
||||||
|
("Confirm", ["Plant a benign marker that the privileged job executes, proving control"])],
|
||||||
|
"Fix permissions on jobs and their targets", "Privilege escalation"),
|
||||||
|
# ---- windows ----
|
||||||
|
A("windows_priv_esc", "Windows Privilege Escalation", "local privilege escalation on a Windows host", "CWE-269", "High",
|
||||||
|
[("Enumerate (authenticated)", ["Run winPEAS/`whoami /priv`; check unquoted service paths, weak service perms, AlwaysInstallElevated, token privileges (SeImpersonate)"]),
|
||||||
|
("Confirm", ["Demonstrate escalation to SYSTEM/admin with command output (e.g. via a Potato technique where applicable)"])],
|
||||||
|
"Patch; fix service perms; remove dangerous privileges", "Full host compromise"),
|
||||||
|
A("windows_smb_signing", "SMB Signing & Relay Exposure", "SMB signing not required (NTLM relay risk)", "CWE-294", "Medium",
|
||||||
|
[("Detect", ["`netexec smb {target}` — note `signing:False`"]),
|
||||||
|
("Assess", ["Explain the NTLM-relay exposure; confirm a coercible auth path only if in scope"])],
|
||||||
|
"Enforce SMB signing; disable NTLM where possible", "Credential relay, lateral movement"),
|
||||||
|
A("windows_winrm_access", "WinRM Authenticated Access", "remote management access via WinRM", "CWE-287", "Medium",
|
||||||
|
[("Connect", ["`evil-winrm -i {target} -u <user> -p <pass>` (or -H <hash>) with supplied creds/hash"]),
|
||||||
|
("Confirm", ["Show an authenticated remote shell and the host context (`whoami`, hostname)"])],
|
||||||
|
"Restrict WinRM; strong creds; network segmentation", "Remote host control"),
|
||||||
|
# ---- active directory ----
|
||||||
|
A("ad_kerberoasting", "AD Kerberoasting", "service accounts with crackable SPNs", "CWE-522", "High",
|
||||||
|
[("Request", ["`netexec ldap {target} -u <user> -p <pass> --kerberoasting out.txt` or impacket GetUserSPNs"]),
|
||||||
|
("Crack & confirm", ["Crack the TGS hash offline (hashcat -m 13100); confirm a recovered service-account password"])],
|
||||||
|
"Strong/long service-account passwords; gMSA", "Service-account compromise, lateral movement"),
|
||||||
|
A("ad_asreproasting", "AD AS-REP Roasting", "accounts with Kerberos pre-auth disabled", "CWE-522", "High",
|
||||||
|
[("Enumerate", ["impacket GetNPUsers / `netexec ldap {target} --asreproast out.txt` for DONT_REQ_PREAUTH accounts"]),
|
||||||
|
("Crack & confirm", ["Crack the AS-REP (hashcat -m 18200); confirm a recovered password"])],
|
||||||
|
"Require Kerberos pre-auth; strong passwords", "Account compromise"),
|
||||||
|
A("ad_acl_privesc", "AD ACL / DACL Abuse", "dangerous Active Directory ACLs", "CWE-269", "High",
|
||||||
|
[("Map", ["Collect with bloodhound-python/SharpHound; find GenericAll/WriteDACL/ForceChangePassword edges"]),
|
||||||
|
("Confirm", ["Demonstrate one safe, reversible control step (e.g. shadow-cred / targeted password reset in a lab) proving the path"])],
|
||||||
|
"Tighten ACLs; tiered admin model", "Domain privilege escalation"),
|
||||||
|
A("ad_dcsync", "AD DCSync Exposure", "replication rights enabling DCSync", "CWE-269", "Critical",
|
||||||
|
[("Check rights", ["Identify principals with DS-Replication-Get-Changes(-All) via BloodHound/ACL review"]),
|
||||||
|
("Confirm", ["With authorized creds, prove replication right (e.g. impacket secretsdump -just-dc-user for a single test account)"])],
|
||||||
|
"Remove replication rights from non-DC principals", "Full domain credential compromise"),
|
||||||
|
A("ad_default_creds", "AD/Host Default & Reused Credentials", "default or reused credentials across the domain", "CWE-798", "High",
|
||||||
|
[("Spray (authorized, throttled)", ["With supplied account list, `netexec smb {target} -u users -p pass --continue-on-success` within ROE"]),
|
||||||
|
("Confirm", ["Show a successful authentication that should not have worked (reused/default cred)"])],
|
||||||
|
"Rotate defaults; enforce unique strong passwords; lockout", "Lateral movement, domain access"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
os.makedirs(OUT, exist_ok=True)
|
||||||
|
for a in INFRA:
|
||||||
|
open(os.path.join(OUT, a["name"] + ".md"), "w").write(render(a))
|
||||||
|
print(f"wrote {len(INFRA)} infra agents to {OUT}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in new issue
Block a user