戰(zhàn):.git目錄泄露導(dǎo)致的源碼裸奔與防御指南)
簡(jiǎn)介Git_Extract是一套基于Python3的Git目錄泄露檢測(cè)與提取工具包專門面向安全測(cè)試人員、開發(fā)者和運(yùn)維人員旨在解決Web服務(wù)器中.git目錄意外暴露所導(dǎo)致的信息泄露問題。通過掃描公開目錄工具能解析提交歷史、分支與文件內(nèi)容幫助用戶快速確認(rèn)敏感信息是否外泄并采取應(yīng)急加固措施。壓縮包共10個(gè)文件包含5個(gè)Python源碼腳本、4個(gè)編譯生成的pyc文件及1個(gè)Markdown說明文檔源碼腳本分別承擔(dān)數(shù)據(jù)解析、索引處理與通用輔助功能整體僅13KB輕量易部署。目前已有938人學(xué)習(xí)下載適合具備Python基礎(chǔ)、關(guān)注Web安全的入門與進(jìn)階使用者。通過該工具讀者可以掌握Git泄露攻擊的檢測(cè)與數(shù)據(jù)提取思路學(xué)會(huì)利用版本元數(shù)據(jù)分析源碼結(jié)構(gòu)并據(jù)此加固服務(wù)器訪問控制策略避免源代碼、賬戶口令等關(guān)鍵數(shù)據(jù)被惡意獲取。 拿站點(diǎn)的時(shí)候突然發(fā)現(xiàn)/.git/目錄能直接訪問那一瞬間的興奮感做過安全測(cè)試的人都懂。但你很快會(huì)發(fā)現(xiàn)瀏覽器里只能看到一堆十六進(jìn)制文件名真正的源碼根本點(diǎn)不出來。這時(shí)候手里要是有個(gè)趁手的Git_Extract.zip情況就完全不一樣了——解壓、配環(huán)境、跑腳本三步就能把整個(gè)項(xiàng)目的歷史版本連同當(dāng)前代碼一起挖出來。這篇博文從實(shí)際測(cè)試視角出發(fā)完整拆解Git_Extract.zip這個(gè)工具包的使用鏈路先說清楚為什么.git泄露等于源碼裸奔再講工具包解壓和運(yùn)行環(huán)境的坑然后是恢復(fù)源碼的核心操作最后是排錯(cuò)思路和防御建議。無論你是剛接觸目錄泄露的新手還是被各種報(bào)錯(cuò)折磨過的老手這篇都能直接對(duì)著抄作業(yè)。1. 為什么一個(gè) .git 文件夾就能讓整個(gè)項(xiàng)目裸奔1.1 Git 對(duì)象模型對(duì)恢復(fù)源碼意味著什么很多人覺得.git目錄只是存了一些提交記錄丟了也無所謂。這是最大的誤解。Git 的核心是對(duì)象數(shù)據(jù)庫所有文件內(nèi)容、目錄結(jié)構(gòu)、提交歷史全部以對(duì)象的形式存在.git/objects/下面。每個(gè)對(duì)象都有一個(gè) SHA-1 哈希值當(dāng)作文件名內(nèi)容經(jīng)過 zlib 壓縮存儲(chǔ)所以你在瀏覽器里看到的是亂碼一樣的文件名其實(shí)它們是完整的數(shù)據(jù)塊。當(dāng)你執(zhí)行g(shù)it add時(shí)文件內(nèi)容被保存為blob 對(duì)象git commit時(shí)目錄結(jié)構(gòu)被保存為tree 對(duì)象提交信息被保存為commit 對(duì)象。這三類對(duì)象互相引用、層層嵌套構(gòu)成了完整的時(shí)間線。只要.git目錄在就算工作區(qū)文件被刪光也能通過git checkout或者腳本解析對(duì)象數(shù)據(jù)庫把每一個(gè)歷史版本的文件全部恢復(fù)出來。這正是Git_Extract.zip這類工具的核心原理它模擬 Git 自身的對(duì)象解析邏輯下載.git/objects/下的對(duì)象文件識(shí)別 commit、tree、blob再按照 tree 結(jié)構(gòu)重建出源碼目錄。不需要服務(wù)器端執(zhí)行代碼不需要數(shù)據(jù)庫權(quán)限只要 HTTP 能讀到.git下的文件源碼就保不住了。1.2 目錄泄露的幾個(gè)常見入口從實(shí)際經(jīng)驗(yàn)看.git泄露最常見的是這幾種情況Web 服務(wù)把項(xiàng)目根目錄直接指向了倉庫根目錄但沒有禁止訪問.git文件夾。Nginx、Apache、IIS 默認(rèn)都不攔直接暴露。CI/CD 流水線把代碼部署到了 Web 目錄部署后沒有刪除.git。很多自動(dòng)化腳本圖省事git clone到站點(diǎn)根目錄就結(jié)束了。備份文件或壓縮包被搜索引擎收錄比如www.zip、backup.tar.gz里面往往帶了完整的.git目錄。前端項(xiàng)目構(gòu)建產(chǎn)物和源碼放在同一個(gè)目錄.git隨著靜態(tài)資源一起被發(fā)布到了 CDN 或?qū)ο蟠鎯?chǔ)。判斷方法很簡(jiǎn)單瀏覽器訪問https://target.com/.git/config如果返回類似[core] repositoryformatversion 0的內(nèi)容基本就實(shí)錘了。需要注意的是有的服務(wù)器會(huì)屏蔽點(diǎn)號(hào)開頭的路徑但通過%2e編碼、/./路徑穿越等方式可能繞過這不是本文重點(diǎn)但你要知道漏網(wǎng)之魚很多。2. 解壓與運(yùn)行環(huán)境補(bǔ)全Git_Extract.zip 的落地姿勢(shì)2.1 環(huán)境選擇Kali 還是 WindowsGit_Extract.zip里通常是 Python 腳本加說明文檔可能還帶了一個(gè)輕量的 Git 配置模板。工具本身跨平臺(tái)但我強(qiáng)烈建議在 Linux 或 Kali 環(huán)境下跑。原因不是腳本不兼容 Windows而是目標(biāo)站點(diǎn)普遍在國(guó)外網(wǎng)絡(luò)環(huán)境下Linux 下用curl、wget、python3的組合最少折騰遇到超時(shí)重試也更好寫。Windows 下跑也不是不行前提是你把環(huán)境補(bǔ)全Python 3.8并且python命令能被終端識(shí)別。Git for Windows 安裝好并勾選 Add to PATH。如果沒有curl直接裝 Git Bash里面自帶。裝了 Git Bash 后很多Git_Extract.zip里的腳本就能直接用bash跑了避免 cmd 的編碼問題。我見過太多人卡在這一步明明工具包解壓了腳本一運(yùn)行就報(bào)git 不是內(nèi)部或外部命令。這就是 PATH 沒配好。2.2 解壓報(bào)錯(cuò)與修復(fù)熱搜詞里那些 failed to copy spatial iop zip、could not find eocd 看著嚇人其實(shí)就是 zip 文件解壓失敗的典型報(bào)錯(cuò)。EOCD 是 End of Central Directory 的縮寫位于 zip 文件末尾記錄了解壓所需的目錄索引。如果unzip提示could not find eocd說明文件被截?cái)嗔嘶蛘呦螺d不完整。遇到這種情況別急著刪除重下先檢查文件大小如果壓縮包下載到一半斷了用ls -l看大小是否和頁面標(biāo)注一致不一致就重新下載。如果確認(rèn)大小沒問題還是報(bào) EOCD用zip -FF damaged.zip --out repaired.zip嘗試修復(fù)它能掃描文件把能恢復(fù)的條目重建一個(gè)可解壓的包。Windows 下也可以直接右鍵用 WinRAR 的修復(fù)壓縮文件功能原理一樣。還有一類坑是中文文件名亂碼。Git_Extract.zip里的腳本文件名可能是英文的但說明文檔如果是中文在 Windows 下解壓可能變成亂碼。建議用自帶 Unicode 支持的 7-Zip 解壓別用老舊的右鍵全部提取。2.3 依賴確認(rèn)與最小運(yùn)行清單解壓完成后建議按這個(gè)清單檢查一遍省得運(yùn)行時(shí)報(bào)錯(cuò)python3 --version git --version curl --version如果提示缺哪個(gè)就裝哪個(gè)# Debian/Ubuntu/Kali sudo apt update sudo apt install python3 git curl unzip -y裝完后把Git_Extract.zip里提取出來的腳本放在一個(gè)干凈的工作目錄。我習(xí)慣建一個(gè)rev/文件夾把工具包的對(duì)象 ID 列表文件、Python 腳本都放進(jìn)去再按目標(biāo)站點(diǎn)名字建輸出目錄后面恢復(fù)的文件全丟里面方便排查。3. 用 Git_Extract 把源碼從 .git 里挖出來核心操作鏈路3.1 目標(biāo)探測(cè)確認(rèn) .git 是否可讀跑提取腳本之前先手工確認(rèn)目標(biāo).git目錄的權(quán)限邊界。這一步能省很多無用功curl -s -m 10 https://target.com/.git/config如果返回[core]段落說明至少/config可讀。接著再測(cè)一下對(duì)象文件能不能讀# 隨便挑一個(gè)對(duì)象路徑試讀 curl -s -m 10 -o /dev/null -w %{http_code} https://target.com/.git/HEADHTTP 200 是最理想的情況。如果返回 403 或 404說明服務(wù)器對(duì).git路徑有過濾純靜態(tài)拉取的方式大概率行不通但可以試試路徑編碼繞過。這些是題外話正文里默認(rèn)場(chǎng)景是 200。3.2 提取腳本的運(yùn)行與參數(shù)說明Git_Extract.zip里的主要工具是git_extract.py它的工作流程大致如下先請(qǐng)求/.git/index拿到當(dāng)前索引文件這里記錄了工作區(qū)所有文件的路徑和對(duì)應(yīng)的 blob 對(duì)象哈希。再請(qǐng)求/.git/HEAD拿到當(dāng)前分支引用解析出指向的 commit 對(duì)象。根據(jù) commit 對(duì)象遞歸解析 tree 對(duì)象結(jié)合 index 里的 blob 哈希拼出完整的源碼路徑和內(nèi)容。把下載到的對(duì)象內(nèi)容解壓按照重建的目錄結(jié)構(gòu)寫盤。實(shí)際運(yùn)行命令一般長(zhǎng)這樣python3 git_extract.py -u https://target.com/.git/ -o ./output/參數(shù)含義-u目標(biāo).git目錄的 URL 地址建議結(jié)尾帶斜杠。-o輸出目錄腳本會(huì)自動(dòng)創(chuàng)建。-d調(diào)試模式打印每個(gè)請(qǐng)求的耗時(shí)和狀態(tài)碼遇到超時(shí)很有用。--depth限制恢復(fù)的歷史深度比如只恢復(fù)最近 3 個(gè)提交適合目標(biāo)對(duì)象文件特別多的情況。腳本跑完后./output/下就會(huì)出現(xiàn)完整的源碼樹包括index.html、app.js、config.php這些工作區(qū)文件以及.git/的鏡像。你可以直接打開源碼做代碼審計(jì)也可以進(jìn)到./output目錄里執(zhí)行g(shù)it log看提交歷史。3.3 大文件與缺失對(duì)象的補(bǔ)救式恢復(fù)現(xiàn)實(shí)情況沒那么理想。目標(biāo)站點(diǎn)如果部署時(shí)間很長(zhǎng).git/objects/里會(huì)有大量打包文件.pack單個(gè)對(duì)象直接下載可能拿不到全部?jī)?nèi)容。還有的時(shí)候腳本跑到一半網(wǎng)絡(luò)斷了對(duì)象文件缺失生成的源碼樹里會(huì)出現(xiàn)空文件或亂碼。我自己常用的補(bǔ)救方式是本地倉庫重建法cd ./output # 先看腳本把 .git 恢復(fù)到什么程度 ls -la .git/objects/pack/ # 如果拿到了 .pack 文件直接進(jìn)本地倉庫解包 git verify-pack -v .git/objects/pack/*.idx | head -20如果腳本能下載到.pack和.idx文件就可以用git index-pack重建索引然后git fsck --full檢查對(duì)象完整性。缺失的對(duì)象無法憑空恢復(fù)但因?yàn)?Git 對(duì)象之間有引用關(guān)系很多文件即使缺失當(dāng)前版本也能從歷史提交里找回上一版。我用這個(gè)思路不止一次撈回了腳本漏掉的關(guān)鍵配置文件。4. 常見報(bào)錯(cuò)與誤判EOCD、死鏈、大文件拉不動(dòng)4.1 zip 解壓類報(bào)錯(cuò)Git_Extract.zip本身如果下載不完整運(yùn)行前就會(huì)卡在解壓環(huán)節(jié)。除了前面說的 EOCD 錯(cuò)誤還有一個(gè)很常見的提示是invalid zip archive原因通常是文件被當(dāng)成文本格式傳輸過二進(jìn)制內(nèi)容被改壞了。那種情況下優(yōu)先找原始下載鏈接重下別花時(shí)間修。如果你手里的是一個(gè)加密 zip碰到zip 密碼移除暴力破解的需求我的建議是先想清楚密碼是不是常見弱口令比如123456、password、域名本身。工具方面可以用zip2john導(dǎo)出哈希再交給john跑字典速度比純 GPU 破解快得多。不過這是另一條支線和Git_Extract本身關(guān)系不大多數(shù)安全測(cè)試場(chǎng)景用不上。4.2 git 命令類報(bào)錯(cuò)恢復(fù)過程中最常報(bào)的 git 制錯(cuò)誤是fatal: not a git repository (or any of the parent directories): .git這說明你當(dāng)前目錄根本不是倉庫或者.git路徑不對(duì)。檢查ls -la是否真的有.git目錄。git: remote-http is not a git command這是 Git 沒裝完整缺少遠(yuǎn)程助手模塊重裝 Git 即可。could not read from remote repository工具腳本嘗試訪問遠(yuǎn)程倉庫地址但網(wǎng)絡(luò)不通。遇到 git 類報(bào)錯(cuò)先別懷疑工具腳本把環(huán)境變量GIT_SSL_NO_VERIFY1加上試一次。很多目標(biāo)站點(diǎn)的證書是自簽的Git 默認(rèn)嚴(yán)格校驗(yàn)會(huì)直接拒掉加上這個(gè)變量能避免大量超時(shí)和握手失敗。4.3 提取結(jié)果異常的排查思路腳本報(bào)成功完成但產(chǎn)出文件數(shù)量明顯不對(duì)這種情況最容易讓人懵。我的排查順序是看日志里 HTTP 狀態(tài)碼。如果大量 403 或 429說明目標(biāo)有 WAF 或者反爬需要降低并發(fā)加請(qǐng)求間隔??磳?duì)象文件大小。下載下來的對(duì)象如果都是 0 字節(jié)或幾百字節(jié)的報(bào)錯(cuò)頁面說明被服務(wù)器攔截了不是工具問題。對(duì)比 index 文件和實(shí)際目錄。/.git/index能讀到時(shí)里面列出的文件名就是一份清單對(duì)比恢復(fù)出來的文件就能定位哪些對(duì)象沒有拉到。還有一次我跑了半天腳本恢復(fù)出來的index.html打開全是亂碼最后發(fā)現(xiàn)是編碼問題——Git 默認(rèn)把文件內(nèi)容按二進(jìn)制存儲(chǔ)腳本寫盤時(shí)卻用了文本模式導(dǎo)致?lián)Q行符被轉(zhuǎn)換。解決辦法是在腳本里以wb二進(jìn)制模式寫文件。如果你的工具包沒修這個(gè) bug可以自己改一下下載文件的寫入邏輯。5. 拉完代碼之后授權(quán)邊界與讓泄露不再發(fā)生的防御建議5.1 授權(quán)與報(bào)告的基本底線用Git_Extract.zip恢復(fù)源碼這件事本質(zhì)是安全測(cè)試中的信息收集環(huán)節(jié)只允許在你有明確授權(quán)的目標(biāo)上執(zhí)行。自己搭的靶場(chǎng)、SRC 平臺(tái)授權(quán)的項(xiàng)目、客戶簽了授權(quán)書的滲透測(cè)試這些場(chǎng)景隨便用。沒有授權(quán)直接對(duì)線上站點(diǎn)跑無論目的是什么都越過了合規(guī)紅線。報(bào)告里我一般會(huì)這樣寫泄露路徑https://target.com/.git/config可公開訪問。影響范圍整個(gè)項(xiàng)目源碼、提交歷史、數(shù)據(jù)庫連接配置、密鑰信息。復(fù)現(xiàn)步驟訪問 URL、查看源碼、執(zhí)行恢復(fù)工具。修復(fù)建議Web 服務(wù)器禁止訪問.git目錄、部署流程剔除倉庫目錄。這樣寫的好處是對(duì)方安全團(tuán)隊(duì)能快速理解問題嚴(yán)重性修復(fù)時(shí)也有明確方向。5.2 幾行配置堵住 .git 泄露作為開發(fā)或運(yùn)維避免這種問題其實(shí)很簡(jiǎn)單。Nginx 下加一段拒絕規(guī)則location ~ ^/.*\.git { deny all; }Apache 下在.htaccess或虛擬主機(jī)配置里加RedirectMatch 404 /\.git如果用的是對(duì)象存儲(chǔ) CDN那就從源頭解決發(fā)布產(chǎn)物永遠(yuǎn)走構(gòu)建目錄不要直接發(fā)布倉庫目錄。git archive可以導(dǎo)出干凈的快照git archive --formatzip -o release.zip HEAD這樣導(dǎo)出的是當(dāng)前 HEAD 的源碼快照不包含.git目錄歷史提交和對(duì)象數(shù)據(jù)庫都不會(huì)帶出去。如果你是非要把整個(gè)倉庫放到服務(wù)器上不可的場(chǎng)景至少確認(rèn)git config http.receivepack false關(guān)閉匿名寫入權(quán)限同時(shí)把 Web 根目錄指向倉庫的子目錄而不是倉庫根目錄。多層防護(hù)疊加才能避免根目錄一開、源碼全漏的尷尬。我在實(shí)際測(cè)試中最深的體感是.git泄露往往不是單點(diǎn)失誤而是整個(gè)發(fā)布流程缺少清理倉庫元數(shù)據(jù)這一步。修好流程比臨時(shí)加一段 deny 規(guī)則更管用。工具能幫你驗(yàn)證結(jié)果但真正讓數(shù)據(jù)安全落地靠的還是流程規(guī)范。本文還有配套的精品資源點(diǎn)擊獲取