在滲透測試中,繞過 CDN(Content Delivery Network)尋找後端的真實源站是非常經典且關鍵的一步。只要找到源站IP,攻擊者(或測試人員)就能繞過 CDN 的 WAF、DDoS 防禦,直接對目標伺服器進行漏洞利用。
以下是常見且有效的幾種尋找源站IP 的方法:
- 歷史記錄查詢
- 空間搜尋引擊: 全網憑證掃描,網頁圖標,網頁內容指紋
- 配置錯誤 :觸發 CDN 節點錯誤,IPv6 遺漏,特定檔案洩漏,代碼與組態洩漏
- 子網域搜集
- 利用伺服器發起的外連請求
以下是驗證源站IP的常用方法:
- 修改 /etc/hosts
- curl –resolve
- curl -H
歷史記錄查詢
很多網站是在上線一段時間後才加裝 CDN 的。這意味著在舊的 DNS 紀錄中,可能直接寫著真實的伺服器 IP。
- 作法: 使用專門收集 DNS 歷史紀錄的平台,搜尋 A 紀錄的變更歷史。
- 常用工具/網站:
- SecurityTrails/DNSTrails
- ViewDNS.info
- Censys / Shodan(查看歷史憑證綁定)
範例
假如要尋找www.shop.com的源站
1.查詢目前的現狀
輸入 nslookup www.shop.com ,得到的結果是 104.21.5.10。查一下 IP 發現這是 Cloudflare(CDN)的伺服器。
2.翻閱舊紀錄
打開 SecurityTrails 網站,搜尋 www.shop.com 並點擊 Historical Data (歷史資料),查到以下資訊:
| 變更日期 (Date) | 解析類型 | 紀錄內容 (IP / Domain) | 備註分析 |
| 2026-01-01 至今 | A Record | 104.21.5.10 | 這是加裝 Cloudflare CDN 後的 IP |
| 2025-06-01 ~ 2025-12-31 | A Record | 203.0.113.88 | 這是在掛 CDN 前的 IP |
3.關鍵驗證
使用 curl 測試命令,強制指定要連線到這個舊 IP,但要求存取 www.shop.com的內容:
curl -H "Host: www.shop.com" http://203.0.113.88
如果回傳結果成功抓到了 www.shop.com 的首頁 HTML 原始碼!這代表 203.0.113.88 就是Origin IP,且伺服器依然在運作。表示繞過了 CDN,可以直接對這個 IP 進行 Port 掃描或漏洞攻擊。
空間搜尋引擊
全網憑證掃描(SSL/TLS Certificate Matching)
當運維人員為了讓 CDN 與源站之間傳輸加密,會幫源站申請了 SSL 憑證,這張憑證的申請紀錄會被強制記錄在公開的日誌中。
- 作法: 利用CT Log(憑證透明度日誌)搜尋,或像Shodan、Censys 或 Zoomeye 這類全網掃描引擎。
- 這會直接列出全世界所有安裝了該證書的伺服器,通常真正的源站就會混在裡面。
範例:
假如要尋找victim-finance.com的源站
- 開啟憑證日誌查詢網站(如 crt.sh)。
- 在搜尋欄輸入:
%.victim-finance.com(% 是萬用字元)。 - 檢查搜尋結果中,點擊每張憑證的ID,查看 Subject Alternative Name (SAN) 欄位。
- 在某張過期的或是新申請的憑證中,你發現了以下內容
DNS Name: *.victim-finance.com
DNS Name: victim-finance.com
DNS Name: origin-web-prod.internal-cloud-infrastructure.net
這代表運維人員在申請憑證時,可能把公開網域跟那個隱蔽的源站網域寫在了同一張憑證上。
5.驗證origin-web-prod.internal-cloud-infrastructure.net的IP
dig +short origin-web-prod.internal-cloud-infrastructure.net
如果確認不是CDN IP,可以檢查是否源站,可用以下指令
curl -i -H "Host: victim-finance.com" https://origin-web-prod.internal-cloud-infrastructure.net
如果回傳的 HTML 原始碼、標頭(Headers)與公開的victim-finance.com一樣,那就表示找到源站。
網頁圖標(Favicon Hash)
源站伺服器上通常也開著 80 或 443 埠。即使它綁定了不同的域名,只要它上面的網頁檔案(例如網站的 Favicon、特定的靜態圖片或特殊的 404 頁面)與公開網站一模一樣,就能透過大數據特徵比對出來。
- 作法: 下載公開網站的 favicon.ico,並計算其 MurmurHash 值。 在到 Shodan 或 Censys 等利用該 Hash 值進行全網搜尋。
- Shodan語法範例:
http.favicon.hash:-1507567067
- Shodan語法範例:
- 這會直接列出全世界所有擁有這個相同圖標的 IP 或網域,裡面通常就會夾雜著那個「不同域名」的源站伺服器。
範例:
- 下載目標網站的圖標並用 Python 算出其特定 Hash 值:
import mmh3
import requests
import codecs
response = requests.get('https://www.victim-finance.com/favicon.ico')
favicon = codecs.encode(response.content, 'base64')
hash_value = mmh3.hash(favicon)
print(hash_value)
假設算出來的結果是:-123456789。
- 將這個 Hash 值拿到 Shodan 或 Censys 搜尋:
- Shodan 語法範例:
http.favicon.hash:-123456789
- Shodan 語法範例:
- 搜尋結果跑出兩個 IP:
- 104.26.0.1(這顯示為 Cloudflare 的 IP)
- 54.210.X.X(這顯示為 AWS 的 IP,且反查域名為 vtm-fn-origin.ap-east-1.elb.amazonaws.com)
用以下驗證54.210.X.X,如果返回內容一樣就表示為Origin IP
curl -i -H "Host: victim-finance.com" 54.210.X.X
網頁內容指紋(HTML Response Fingerprinting)
有些源站雖然隱藏在另一個域名下,但當你直接用 IP 或該內部域名存取它時,它回傳的 HTTP 標頭、HTML 原始碼中的特定關鍵字(如獨特的 JavaScript 變數、特定的 Google Analytics 追蹤碼(UA-XXXXX-Y)、備註、甚至是特定的伺服器报错資訊)會暴露身份。
- 作法: 利用自動化工具搜集目標企業旗下的所有資產網段或可能使用的網段,並抓取所有網頁的 Response。
- 比對點: 比對 HTTP 標頭中的
X-Powered-By、Server版本的微小差異,或是 HTML 的 Title、特殊 CSS 路徑。
範例:
- 在瀏覽器打開 www.victim-finance.com,按下 F12 查看原始碼。
- 尋找一段最獨特、不可能跟別人家重複的程式碼。例如:
<script>var victim_app_version = "v3.2.1-build-8849";</script> - 將這段特徵丟到 Censys 或 ZoomEye等空間搜尋引擊。
- Censys 語法範例:
services.http.response.body: "v3.2.1-build-8849"
- Censys 語法範例:
- Censys 會搜尋全球網頁的 Body 內容,最後反向列出包含這段特定程式碼的伺服器。即使源站改名叫做 secret-server.com,只要網頁內容沒變,就會在搜尋結果中現形。
配置錯誤
觸發 CDN 節點錯誤(Edge Error Triggering)
- 原理: 當滲透測試人員故意對 CDN 邊緣節點(Edge Servers)發送畸形請求、大標頭(Large Headers)或極慢速連線(Slowloris 變體)時,可能會引發 CDN 邊緣節點與後端源站之間的連線逾時(Gateway Timeout)或握手失敗(SSL Handshake Failed)。
- 做法: 某些 CDN 機制在拋出 502 / 504 錯誤網頁時,其內建的 Debug Mode 或錯誤訊息原始碼中,會不經意地暴露其嘗試連線的 Origin Hostname。仔細觀察 Response 中的 X-Cache、X-Amz-Cf-Id 或是 CDN 專屬錯誤頁面,有時能直接看到源站網域。
範例:
使用 curl 故意發送超長的、畸形的 HTTP Header 給目標網站(或是利用 Slowloris 工具進行慢速連線阻斷測試):
curl -H "X-Custom-Header: $(python3 -c 'print("A"*20000)')" https://www.victim-finance.com
由於 X-Custom-Header 大小達到 20KB,超過了前端 Nginx Reverse Proxy 的 large_client_header_buffers 限制,代理伺服器直接拋出 502 Bad Gateway,內容如下。
HTTP/1.1 502 Bad Gateway
Server: nginx/1.18.0
X-Upstream-Addr: 10.0.12.45:8080
Content-Type: text/html
<html>
<head><title>502 Bad Gateway</title></head>
<body>
<center><h1>502 Bad Gateway</h1></center>
<!-- Debug Info: Failed to connect to upstream server origin-lb-01.internal.victim-finance.com:8080 -->
</body>
</html>
在此情境中,內部維運團隊因未關閉 Nginx 的除錯回應,直接在 HTML 註解與 Header 中洩漏了內部源站負載平衡器的 FQDN (origin-lb-01.internal.victim-finance.com),接著就可以在根據此資訊去判斷Origin IP
IPv6 遺漏
有些網站只幫 IPv4 設定了 CDN,卻忘記設定 IPv6。查詢 AAAA 紀錄可能直接拿到真實的 IPv6 位址。
因為許多維運人員在配置 CDN(如 Cloudflare, Akamai)時,只將 A 紀錄(IPv4)指 an 到 CDN 代理,卻忽視了 AAAA 紀錄(IPv6),或伺服器在自動取得公網 IPv6 時,直接將 AAAA 紀錄指向了原生的 IPv6 位址。
攻擊者視角: 透過 dig domain.com AAAA 或 nslookup -type=AAAA domain.com,如果解析出非 CDN 的原生 IPv6,就能繞過 IPv4 防護直接攻擊源站(例如直接利用 IPv6 發起 HTTP 請求,或利用源站防火牆對 IPv6 規則配置鬆散的漏洞)。
範例:
查 IPv4 (A 紀錄),拿到的是 Cloudflare 的 IP,繞不過去
$ dig example.com A +short
104.16.123.99
查 IPv6 (AAAA 紀錄),直接拿到了源站真實的 IPv6 Origin IP
$ dig example.com AAAA +short
2001:db8::50
代碼與組態洩漏(Code / Config Leaks)
- GitHub / GitLab 搜尋: 維運人員在寫自動化部署指令檔(如 GitHub Actions、Terraform、Ansible)時,必須把 CDN 要導向的「真實源站網址」寫進設定檔裡。如果這些 Repo 被誤設為 Public,或者內部員工的個人 GitHub 沒藏好,搜尋 ProxyPass、origin_domain 或 backend_url 就能直接挖出該域名。
- 前端 JS 程式碼: 有時開發人員會把測試環境(Staging / UAT)的隱蔽源站域名,以註解或未拔除的除錯變數形式,殘留在正式環境的 JavaScript 檔案中。
範例:
- 到 GitHub 搜尋框,不要搜尋公司官網,而是搜尋公司名稱或工程師的名字。
- 使用進階搜尋語法尋找常見的代理或配置關鍵字:
- “victim-finance” filename:nginx.conf
- “victim-finance” “proxy_pass”
- org:victim-finance-github-org “backend_url”
- 你在某個離職員工的個人 Public GitHub 儲存庫中,找到了一個多年前寫的 docker-compose.yml 測試環境備份。裡面有一行 Nginx 的反向代理設定:
environment:
- UPSTREAM_SERVER=prod-origin-secure.vtm-finance-back.io
雖然這個網域跟公開的 .com 完全不同,但這正是他們在雲端內部架設、用來對接 CDN 的真正源站網域prod-origin-secure.vtm-finance-back.io,接著就可以在根據此資訊去判斷Origin IP
特定檔案洩漏
尋找 phpinfo.php、status頁面或日誌洩漏,裡面常常直接寫明了伺服器的環境變數與 Local/Public IP。
- phpinfo.php / 診斷頁面: PHP 的 phpinfo() 會印出完整的環境變數,包含 SERVER_ADDR、LOCAL_ADDR 或包含在 HTTP Header 中的真實 IP。
- Status 頁面(如 Apache
server-status或 Nginxstub_status): 若未設限存取,可能包含伺服器本身的真實介面 IP 或伺服器發出的請求資訊。 - 系統日誌 / Debug Log /
.env: 開發或維運留下的測試檔、備份檔或錯誤日誌中,極易包含內部/外部 IP 配置資訊。
攻擊者視角: 透過目錄爆破工具(如 gobuster、ffuf)或搜尋引擎 Dork 尋找這些殘留檔案,一旦取得源站 IP,即可繞過 CDN WAF 防護。
子網域搜集
通常維運人員只會把主站(如 www.example.com)或流量大的地方掛上 CDN,而一些不重要的子網域可能直接解析到真實伺服器,甚至這些子網域就跟主站在同一個 C 段(同一個網段)IP。不過要注意的是,在 AWS/GCP 等公用雲上,通常拿到的是動態或分散的 Elastic IP,不一定會在同一個 /24 網段內連續排列。
- 常見目標: dev.example.com、test.example.com、mail.example.com、vpn.example.com、admin.example.com。
- 作法: 找到這些子網域的 IP 後,去對比它們的 IP 網段,或者直接嘗試用這些 IP 透過修改 Host 表頭去存取主站。
範例:
1.搜集所有的周邊系統(子網域)
使用自動化工具(例如 amass)或線上網站(crt.sh)搜集 shop.com 的所有子網域,採集到以下清單:
- www.shop.com 解析到 104.21.5.10 (Cloudflare CDN)
- api.shop.com 解析到 104.21.5.11 (Cloudflare CDN)
- mail.shop.com 解析到 140.112.10.5 (中華電信/AWS 公網 IP,沒掛 CDN)
- dev.shop.com 解析到 140.112.10.12 (同樣沒掛 CDN)
2.推理並進行 C 段(同網段)掃描
維運人員在租用雲端主機或機房時,通常是一次租用一整塊連續的 IP(例如 140.112.10.1 到 140.112.10.254)。
- 因為 mail.shop.com 的 IP 是 140.112.10.5, dev.shop.com 的 IP 是 140.112.10.12。
- 推論真正的 Web 源站,極度可能也藏在 140.112.10.* 這個網段裡的某一隻 IP
3.網段碰撞驗證
準備一個簡單的腳本,對 140.112.10.*這 254 個 IP 送出 HTTP 請求,並帶上主站的 Host 表頭:
for ip in 140.112.10.{1..254}; do
curl -H "Host: www.shop.com" http://$ip
done
結果發現當掃描到 140.112.10.8 時,伺服器吐出了跟 www.shop.com一模一樣的網頁,表示己經發現Origin IP
利用伺服器發起的外連請求
如果目標網站有允許伺服器主動發起外連的功能,你可以誘騙伺服器連回你控制的伺服器,藉此直接抓到它的真實外連 IP。
SSRF(Server-Side Request Forgery)
當伺服器存在 SSRF 漏洞時,攻擊者可控制伺服器發起 HTTP/HTTPS 請求。若將請求目標設為攻擊者控制的伺服器(例如 http://your-attacker-ip),目標伺服器的網路介面會直接建立 TCP 連線,攻擊者的 Server Log 即可捕獲該連線的 源頭 IP。
注意事項:若目標網站架構包含負載平衡器(Load Balancer)、內部代理伺服器(Egress Proxy)或獨立的外連 Gateway,捕獲到的 IP 可能是出境網關(Egress IP),而不一定是 Hosting Web 應用的主機 IP,但這仍屬於目標網路設施的一部份。
頭像/圖片上傳(透過 URL)
許多 Web 應用程式提供「從 URL 匯入圖片」的功能(例如輸入相片網址自動下載為頭像)。當伺服器後端執行下載邏輯時,會主動向該 URL 發起請求,進而向監聽伺服器洩漏真實 IP。所以可以輸入你自建伺服器的圖片網址,讓目標伺服器來下載,就能觀察自己的伺服器 查到是知道是哪個IP來訪問。
Webhook 訂閱功能
Webhook 機制(如 GitHub、Payment Gateway、SaaS 服務的事件通知)會由目標伺服器主動向使用者指定的 End Point 發送 HTTP POST 請求。此動作不經過 CDN 前端防護,直接由後端服務或背景 Task Runner(如 Celery、Sidekiq)發出,極易洩漏內網或真實 Server IP。
忘記密碼/郵件發送
當網站調用本地 SMTP 服務(如 Postfix, Sendmail)直接發送郵件時,信件標頭(Email Headers)中的 Received: 鏈條會記錄信件傳送過程中的每一個 Hop,包含發信主機的原始 IP 或主機名稱。
注意事項:如果目標網站改用第三方郵件服務 API(如 SendGrid, Mailgun, AWS SES, Google Workspace),發信動作會由第三方代勞,此時採集到的只會是 Mail Service Provider 的 IP,而非網站本身的真實 IP。
驗證源站的常用方式
常見的方式,主要有3種
- 修改 /etc/hosts
這種方式是修改作業系統層級的 DNS 解析,寫入後全系統所有程式都會生效。
- curl –resolve
語法格式為 --resolve <DOMAIN>:<PORT>:<IP>。這會讓 curl 在內部強制把該域名的特定 Port 解析到你指定的 IP,同時保持標準的 TLS SNI 握手。此功能是 2010 年(curl 7.21.3)才被引入。
例如:curl -i -k --resolve example.com:443:1.2.3.4 https://example.com/
- curl -H
純 HTTP Header 偽造,使用方便,這種方式是直接指定連線目標為 IP 或domain,並在 HTTP 請求標頭(Header)中帶入 Host: example.com
例如:curl -i -k -H "Host: example.com" https://1.2.3.4
| 驗證方式 | 能否通過 SNI 檢查? | 能否通過 HTTP Host 檢查? | 瀏覽器/跨資源載入 | 結論與實務結果 |
/etc/hosts | 成功 (target.com) | 成功 (target.com) | 完全正常 | 最完整:瀏覽器能載入所有 CSS/JS,就像真實訪問一樣。 |
curl --resolve | 成功 (target.com) | 成功 (target.com) | 僅限單一 API / HTML | 最精準:CLI 最佳解,結果與修改 /etc/hosts 在單一請求上完全一致。 |
curl -H "Host: ..." | 失敗 (SNI 會變成 IP) | 成功 (target.com) | 僅限單一 API / HTML | 最容易報錯:遇到嚴格的 Nginx/Cloudflare/Envoy,會在 TLS 握手階段直接被阻斷 (403/400/Connection reset)。 |
解決源站問題
設定防火牆白名單
源站伺服器應設定 ACL(存取控制清單),只允許來自 CDN 節點的 IP 存取,拒絕所有來自公網的其他請求。
即使攻擊者透過歷史紀錄或各種手法推算出你的源站 IP,若源站伺服器(或前端的 Security Group / Cloud Firewall)設定了 ACL,只放行 CDN 廠商官方公佈的 IP 區段(例如 Cloudflare IP Ranges、Akamai Edge Nodes),來自攻擊者的直連流量會在網路層(L3/L4)直接被 DROP 或 REJECT。
不過,僅鎖 IP 白名單有時仍可能被攻擊者透過「在同一家 CDN 上租用服務並將請求轉向你的 IP」來繞過。因此,完整的做法通常會搭配 mTLS(雙向 TLS 驗證) 或 Custom HTTP Header 驗證(例如 Cloudflare Authenticated Origin Pulls),確保請求不僅來自該 CDN,且確實來自「你的 CDN 帳號」。
更換源站 IP
一旦 IP 洩漏,最安全的方法就是直接更換新的公網 IP。
IP 一旦洩漏,就如同隱藏的門牌號碼已經曝光。光靠修補 DNS 或隱藏 Header 無法撤銷已經流出的歷史紀錄(如 Censys, Shodan, SecurityTrails 等平台會永久留存)。因此,換掉公網 IP 是徹底切斷舊攻擊面的唯一方法。
正確的更換步驟(避免換了又立刻洩漏):
- 先修補洩漏源頭:檢查並修修補 SSRF 漏洞、修正 Email 伺服器設定(避免發信曝露源站 IP)、清理含有舊 IP 的 DNS 紀錄與子網域。
- 部署防火牆白名單:在新的 IP 上啟用前述的 CDN IP 白名單。
- 綁定新 IP 至 CDN:將 CDN 的 Origin 設定更新為新 IP。
- 釋放/廢棄舊 IP。