試Shell腳本:請(qǐng)求頭與路徑變形實(shí)戰(zhàn))
簡(jiǎn)介這是一份面向Web安全初學(xué)者與滲透測(cè)試人員的Shell工具腳本聚焦于403訪問(wèn)限制的繞過(guò)測(cè)試場(chǎng)景。資源以zip壓縮包形式提供共包含3個(gè)文件整體約50KB主要文件類(lèi)型為sh腳本、md說(shuō)明文檔與png效果截圖sh腳本承載核心繞過(guò)邏輯md文檔交代用法與安裝步驟png則直觀展示不同條件下的響應(yīng)對(duì)比結(jié)果。腳本在curl支持下集成了13種已知的403繞過(guò)方式可通過(guò)傳入目標(biāo)站點(diǎn)與路徑參數(shù)快速發(fā)起測(cè)試也能用于橫向比較各類(lèi)繞過(guò)條件下的響應(yīng)差異幫助使用者理解訪問(wèn)控制策略的薄弱點(diǎn)。目前已有984人學(xué)習(xí)下載適合剛接觸Web安全、希望動(dòng)手驗(yàn)證403繞過(guò)原理的讀者參考也可作為日常安全測(cè)試中的輕量輔助工具便于快速定位與復(fù)現(xiàn)問(wèn)題。1. 403 繞不過(guò)去時(shí)我靠一個(gè) Shell 腳本省下整晚排查時(shí)間做授權(quán)測(cè)試的人大概都遇到過(guò)這種場(chǎng)景目標(biāo)路徑明明存在返回的卻是 403。你翻遍請(qǐng)求頭、換過(guò) UA、試過(guò)路徑變形瀏覽器里能打開(kāi)腳本里就是不行。那天晚上我對(duì)著一個(gè)后臺(tái)入口折騰到凌晨?jī)牲c(diǎn)最后發(fā)現(xiàn)只是少了一個(gè)X-Forwarded-For頭。第二天我把常見(jiàn)繞過(guò)手法整理成一個(gè) Shell 腳本取名 bypass-403專(zhuān)門(mén)用來(lái)批量試探 403 路徑。它不復(fù)雜甚至有點(diǎn)土但勝在能跑、能改、能看懂。這篇不講玄學(xué)只講這個(gè)腳本怎么用、每個(gè)參數(shù)什么意思、失敗時(shí)該看哪里以及我在真實(shí)授權(quán)場(chǎng)景里踩過(guò)的坑。如果你也在為 403 頭疼或者想找一個(gè)能直接抄作業(yè)的旁路測(cè)試起點(diǎn)往下看。2. 旁路 403 的常見(jiàn)思路從請(qǐng)求頭到路徑變形的六種打法2.1 為什么 403 不等于沒(méi)戲403 只說(shuō)明服務(wù)器理解了請(qǐng)求但拒絕執(zhí)行不代表路徑不存在。很多中間件、反向代理、WAF 在規(guī)則命中時(shí)統(tǒng)一返回 403真正的業(yè)務(wù)邏輯可能藏在后面。我一般會(huì)先確認(rèn)三件事響應(yīng)體長(zhǎng)度是否和 404 一致、響應(yīng)頭里有沒(méi)有Server或X-Powered-By泄露、換一個(gè) HTTP 方法是否返回不同狀態(tài)碼。這三步能快速判斷是「真拒絕」還是「假拒絕」。如果是假拒絕旁路就有空間。腳本里我默認(rèn)會(huì)先發(fā)一個(gè)基線請(qǐng)求記錄狀態(tài)碼、長(zhǎng)度和關(guān)鍵頭后續(xù)所有變體都跟基線對(duì)比避免把 404 誤判成繞過(guò)成功。2.2 請(qǐng)求頭類(lèi)旁路最容易被忽略的入口請(qǐng)求頭旁路的核心是讓后端認(rèn)為請(qǐng)求來(lái)自內(nèi)網(wǎng)或可信來(lái)源。常見(jiàn)的有X-Forwarded-For、X-Real-IP、X-Originating-IP、X-Remote-IP、X-Client-IP、X-Host、X-Forwarded-Host。腳本里我把這些頭做成一個(gè)數(shù)組逐個(gè)替換127.0.0.1、localhost、10.0.0.1等值。注意不是所有頭都有效有些中間件只認(rèn)特定頭有些會(huì)校驗(yàn)格式。我一般會(huì)先跑一輪全量看哪個(gè)頭能讓狀態(tài)碼從 403 變成 200 或 302。如果全量都沒(méi)反應(yīng)再考慮組合頭比如同時(shí)帶X-Forwarded-For和X-Forwarded-Host。# 請(qǐng)求頭旁路核心邏輯遍歷頭名和值逐個(gè)試探 HEADERS(X-Forwarded-For X-Real-IP X-Originating-IP X-Remote-IP X-Client-IP X-Host X-Forwarded-Host) VALUES(127.0.0.1 localhost 10.0.0.1 192.168.1.1 0.0.0.0) for h in ${HEADERS[]}; do for v in ${VALUES[]}; do code$(curl -s -o /dev/null -w %{http_code} -H $h: $v $TARGET) # 只記錄與基線不同的狀態(tài)碼避免噪音 if [ $code ! $BASELINE_CODE ]; then echo [] $h: $v - $code fi done done這段邏輯很直白外層遍歷頭名內(nèi)層遍歷值每次發(fā)一個(gè)請(qǐng)求只輸出狀態(tài)碼變化的組合。-o /dev/null丟棄響應(yīng)體-w %{http_code}只取狀態(tài)碼速度夠快。實(shí)際用時(shí)可以把TARGET換成你的目標(biāo) URLBASELINE_CODE換成基線狀態(tài)碼。如果目標(biāo)有速率限制把內(nèi)層循環(huán)加個(gè)sleep 0.2別把人家打掛了。2.3 路徑變形類(lèi)旁路斜杠、點(diǎn)號(hào)和編碼的排列組合路徑變形是另一大類(lèi)。常見(jiàn)手法包括在路徑末尾加/、加/.、加//、加%2e、加%2f、大小寫(xiě)混寫(xiě)、在中間插..;/。不同框架對(duì)路徑解析的嚴(yán)格程度不一樣有的會(huì)先規(guī)范化再匹配規(guī)則有的直接拿原始路徑去比對(duì)。腳本里我用一個(gè)路徑變體數(shù)組對(duì)每個(gè)變體發(fā)請(qǐng)求同樣只記錄狀態(tài)碼變化。這里有個(gè)細(xì)節(jié)curl默認(rèn)會(huì)對(duì) URL 做一次編碼如果你要發(fā)原始%2e得用--path-as-is參數(shù)否則會(huì)被二次編碼成%252e結(jié)果全錯(cuò)。# 路徑變形旁路注意 --path-as-is 防止 curl 二次編碼 VARIANTS(/ /. // /%2e/ /%2f/ /..;/ /%252e/) for v in ${VARIANTS[]}; do url${TARGET}${v} code$(curl -s -o /dev/null -w %{http_code} --path-as-is $url) if [ $code ! $BASELINE_CODE ]; then echo [] $url - $code fi done--path-as-is是關(guān)鍵不加的話%2e會(huì)變成%252e測(cè)試就白做了。另外路徑變形經(jīng)常和請(qǐng)求頭組合使用比如X-Forwarded-For: 127.0.0.1加上/%2e/效果比單用更好。腳本里我留了組合開(kāi)關(guān)默認(rèn)關(guān)閉需要時(shí)手動(dòng)打開(kāi)。2.4 HTTP 方法切換PUT、DELETE、PATCH 的意外收獲有些應(yīng)用只對(duì) GET 和 POST 做了權(quán)限校驗(yàn)PUT、DELETE、PATCH、OPTIONS 反而漏了。腳本里我會(huì)把常見(jiàn)方法都跑一遍看哪個(gè)方法返回 200 或 405 以外的狀態(tài)碼。405 說(shuō)明方法不被允許但路徑存在如果返回 200那基本就是權(quán)限配置遺漏。注意PUT 和 DELETE 有破壞性授權(quán)測(cè)試?yán)镂抑辉诿鞔_允許的范圍內(nèi)用且只發(fā)空請(qǐng)求體不實(shí)際修改數(shù)據(jù)。2.5 協(xié)議與端口變體HTTP/1.0、HTTP/2 和大小寫(xiě) Host協(xié)議版本和 Host 頭大小寫(xiě)偶爾也能觸發(fā)差異。比如某些老中間件對(duì) HTTP/1.0 請(qǐng)求不做嚴(yán)格校驗(yàn)或者對(duì)Host: target.com和Host: TARGET.COM處理不同。腳本里我加了--http1.0和--http2開(kāi)關(guān)以及 Host 頭大小寫(xiě)變體。這部分命中率不高但成本極低順手跑一遍不虧。2.6 組合拳為什么單發(fā)一個(gè)頭往往不夠真實(shí)環(huán)境里單發(fā)一個(gè)X-Forwarded-For就能繞過(guò)的場(chǎng)景越來(lái)越少。更多時(shí)候需要組合一個(gè)頭加一個(gè)路徑變形或者兩個(gè)頭同時(shí)帶。腳本里我設(shè)計(jì)了一個(gè)簡(jiǎn)單的笛卡爾積模式把頭名、頭值、路徑變體、HTTP 方法四個(gè)維度做有限組合但默認(rèn)只跑單維度組合模式需要手動(dòng)開(kāi)啟并限制并發(fā)。原因很簡(jiǎn)單組合爆炸會(huì)讓請(qǐng)求量指數(shù)上升容易觸發(fā)風(fēng)控也容易把目標(biāo)打慢。我一般會(huì)先跑單維度找到有反應(yīng)的維度再針對(duì)性地做二維組合。3. 腳本參數(shù)與實(shí)戰(zhàn)配置從單目標(biāo)到批量清單3.1 核心參數(shù)表每個(gè)開(kāi)關(guān)對(duì)應(yīng)什么場(chǎng)景腳本本身不復(fù)雜但參數(shù)設(shè)計(jì)決定了它能不能適應(yīng)不同場(chǎng)景。下面這張表是我在實(shí)際使用中反復(fù)調(diào)整后定下來(lái)的每個(gè)參數(shù)都有明確的適用場(chǎng)景。參數(shù)含義默認(rèn)值適用場(chǎng)景-u單個(gè)目標(biāo) URL無(wú)快速驗(yàn)證一個(gè)路徑-f目標(biāo)清單文件無(wú)批量測(cè)試多個(gè)路徑-mHTTP 方法GET切換方法測(cè)試-H自定義請(qǐng)求頭無(wú)補(bǔ)充腳本未覆蓋的頭-t超時(shí)秒數(shù)10目標(biāo)響應(yīng)慢時(shí)調(diào)大-d請(qǐng)求間隔秒數(shù)0有速率限制時(shí)調(diào)大-c開(kāi)啟組合模式關(guān)閉單維度無(wú)反應(yīng)時(shí)嘗試-v輸出詳細(xì)過(guò)程關(guān)閉排查為什么沒(méi)命中-f和-u互斥優(yōu)先讀文件。-d是我最常用的參數(shù)默認(rèn) 0 是為了快速跑完但真實(shí)授權(quán)測(cè)試?yán)镂乙话銜?huì)設(shè)成 0.3 到 0.5避免給目標(biāo)造成壓力。-v在調(diào)試腳本本身時(shí)有用能看到每個(gè)請(qǐng)求的完整命令和響應(yīng)頭。3.2 單目標(biāo)快速驗(yàn)證三分鐘跑完一輪拿到一個(gè) 403 路徑我一般先跑單目標(biāo)模式命令大概長(zhǎng)這樣# 單目標(biāo)快速驗(yàn)證先跑請(qǐng)求頭和路徑變形間隔 0.3 秒 ./bypass-403.sh -u https://target.example.com/admin -d 0.3 -v跑完后看輸出如果有狀態(tài)碼變化腳本會(huì)打印[]開(kāi)頭的行。沒(méi)有變化也不代表沒(méi)戲可能是目標(biāo)對(duì)速率敏感或者需要組合。這時(shí)候我會(huì)看-v輸出里基線請(qǐng)求的響應(yīng)頭確認(rèn)Server和X-Powered-By再?zèng)Q定下一步試什么。比如看到Server: nginx我會(huì)重點(diǎn)試路徑變形看到X-Powered-By: PHP我會(huì)重點(diǎn)試請(qǐng)求頭。3.3 批量清單模式一次跑完幾十個(gè)路徑批量模式適合已經(jīng)收集到一批 403 路徑的情況。清單文件每行一個(gè) URL腳本會(huì)逐行讀取對(duì)每個(gè) URL 跑一輪單維度測(cè)試。輸出會(huì)按 URL 分組方便對(duì)比。這里有個(gè)坑如果清單里有重復(fù)路徑或相似路徑請(qǐng)求量會(huì)翻倍。我一般會(huì)先用sort -u去重再喂給腳本。# 批量模式先去重再跑間隔 0.5 秒 sort -u targets.txt targets_uniq.txt ./bypass-403.sh -f targets_uniq.txt -d 0.5sort -u去重是血淚經(jīng)驗(yàn)有一次我沒(méi)去重同一個(gè)路徑跑了三遍結(jié)果觸發(fā)了目標(biāo)的風(fēng)控IP 被臨時(shí)封了半小時(shí)。從那以后我每次批量跑之前都強(qiáng)制去重。3.4 結(jié)果解讀200、302、401 分別意味著什么狀態(tài)碼變化只是線索不是結(jié)論。200 說(shuō)明請(qǐng)求成功但響應(yīng)體可能是登錄頁(yè)或錯(cuò)誤頁(yè)得看內(nèi)容長(zhǎng)度和關(guān)鍵詞。302 說(shuō)明跳轉(zhuǎn)跳轉(zhuǎn)目標(biāo)可能是登錄頁(yè)也可能是后臺(tái)首頁(yè)得跟一下Location頭。401 說(shuō)明需要認(rèn)證路徑存在但沒(méi)權(quán)限這本身也是信息。我一般會(huì)把狀態(tài)碼變化的請(qǐng)求單獨(dú)存下來(lái)用curl -i重放一次看完整響應(yīng)頭和響應(yīng)體前幾百字節(jié)再判斷是不是真的繞過(guò)了。4. 避坑與排查那些讓我白忙半天的細(xì)節(jié)4.1 現(xiàn)象腳本跑完全是 403一個(gè)變化都沒(méi)有原因最常見(jiàn)的是基線請(qǐng)求本身就不對(duì)。比如目標(biāo)需要特定 Cookie 或 Token腳本沒(méi)帶所有請(qǐng)求都被統(tǒng)一拒絕。另一個(gè)原因是目標(biāo)有 WAF對(duì)高頻請(qǐng)求直接返回 403跟路徑和頭都沒(méi)關(guān)系。解決先用瀏覽器或curl -i手動(dòng)發(fā)一次基線請(qǐng)求確認(rèn)不帶任何變體時(shí)返回什么。如果手動(dòng)也 403先把認(rèn)證信息補(bǔ)上。如果手動(dòng) 200 但腳本 403檢查腳本的 UA 和默認(rèn)頭是否被 WAF 識(shí)別。我一般會(huì)在腳本里加一個(gè)-H User-Agent: Mozilla/5.0的默認(rèn)頭減少被簡(jiǎn)單規(guī)則攔截的概率。4.2 現(xiàn)象狀態(tài)碼變了但響應(yīng)體是登錄頁(yè)原因302 跳轉(zhuǎn)到登錄頁(yè)或者 200 返回的是前端路由的 index.html。這種情況說(shuō)明路徑存在但權(quán)限校驗(yàn)在應(yīng)用層旁路沒(méi)真正生效。解決不要只看狀態(tài)碼要看響應(yīng)體長(zhǎng)度和關(guān)鍵詞。腳本里我加了一個(gè)簡(jiǎn)單的長(zhǎng)度對(duì)比如果變化后的長(zhǎng)度和基線差距在 10% 以內(nèi)標(biāo)記為「疑似無(wú)效」。更穩(wěn)妥的做法是重放請(qǐng)求抓取響應(yīng)體前 500 字節(jié)搜login、signin、unauthorized等關(guān)鍵詞。4.3 現(xiàn)象--path-as-is加了但%2e還是被編碼原因curl版本差異。某些老版本curl對(duì)--path-as-is支持不完整或者 shell 本身對(duì)%做了處理。解決用單引號(hào)包裹 URL避免 shell 解釋。如果還不行改用python的requests庫(kù)發(fā)原始路徑或者用nc手寫(xiě) HTTP 請(qǐng)求。我一般會(huì)在腳本里檢測(cè)curl --version低于 7.40 的版本提示用戶升級(jí)或換工具。4.4 現(xiàn)象組合模式跑了一半目標(biāo)沒(méi)響應(yīng)了原因請(qǐng)求量太大觸發(fā)了目標(biāo)限流或防火墻。組合模式默認(rèn)是四維笛卡爾積頭名 7 個(gè)、頭值 5 個(gè)、路徑變體 7 個(gè)、方法 4 個(gè)乘起來(lái)接近 1000 個(gè)請(qǐng)求間隔 0 的話幾秒內(nèi)打完很容易被封。解決組合模式必須配合-d使用間隔至少 0.5 秒。另外組合模式應(yīng)該分階段跑先跑二維看有沒(méi)有反應(yīng)再?zèng)Q定要不要上三維。我一般會(huì)把組合模式的最大請(qǐng)求數(shù)限制在 200 以內(nèi)超過(guò)就分批。4.5 現(xiàn)象腳本在本地跑正常放到服務(wù)器上全超時(shí)原因服務(wù)器 DNS 解析或出網(wǎng)策略不同或者目標(biāo)對(duì)來(lái)源 IP 有地域限制。解決先在服務(wù)器上用curl -I手動(dòng)測(cè)一個(gè)目標(biāo)確認(rèn)網(wǎng)絡(luò)通。如果 DNS 慢加--resolve參數(shù)直接指定 IP。如果目標(biāo)有地域限制這個(gè)腳本幫不了你得換出口節(jié)點(diǎn)。注意這里說(shuō)的換節(jié)點(diǎn)是指授權(quán)測(cè)試中合法的網(wǎng)絡(luò)環(huán)境調(diào)整不是其他用途。5. 從腳本到習(xí)慣我后來(lái)怎么把 403 測(cè)試流程化這個(gè)腳本我用了大半年最大的收獲不是它幫我繞過(guò)了多少 403而是它逼我把測(cè)試流程標(biāo)準(zhǔn)化了。以前我遇到 403 就憑感覺(jué)試試到哪算哪現(xiàn)在我會(huì)先跑基線、再跑單維度、再看響應(yīng)體、最后決定要不要組合。這套流程寫(xiě)進(jìn)了我的授權(quán)測(cè)試檢查清單每次遇到 403 都強(qiáng)制走一遍。腳本本身也在迭代最早只有請(qǐng)求頭后來(lái)加了路徑變形、方法切換、批量模式現(xiàn)在大概 200 行出頭純 Shell沒(méi)有依賴扔到任何 Linux 環(huán)境都能跑。如果你要拿這個(gè)腳本去用我的建議是先讀懂每一段在干什么再按自己的場(chǎng)景改。比如你的目標(biāo)對(duì)X-Forwarded-For特別敏感就把值列表加長(zhǎng)如果你的目標(biāo)路徑規(guī)則復(fù)雜就把路徑變體數(shù)組擴(kuò)充。不要直接跑組合模式先從單維度開(kāi)始找到有反應(yīng)的維度再深入。另外授權(quán)測(cè)試?yán)镆欢ㄒ刂普?qǐng)求頻率別把人家業(yè)務(wù)打掛了這是底線。腳本我放在了資源包里里面還有一份我整理的 403 旁路檢查清單按請(qǐng)求頭、路徑、方法、協(xié)議四個(gè)維度列了常見(jiàn)變體可以直接對(duì)照著用。拿過(guò)去之后先跑一遍單目標(biāo)確認(rèn)環(huán)境沒(méi)問(wèn)題再上批量。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取