最近,在和一些人聊天的过程中发现,好多人可以很从容淡定的说出信息收集需要收集Git信息泄露,至于深入的去谈这个漏洞产生的原理时,貌似不太直到这个问题以及相关工具的原理是什么?但作为小白的我始终觉得,对于一个问题只有深入的了解它的原理,并且利用的核心思想才能更好的挖掘和利用它。(可能思想有些“吹毛求疵”了,欢迎大佬们来指教)
那这篇文章,我就尝试从原理上分析一下这个漏洞以及漏洞的利用思想吧!(当然,借鉴了很多前辈的文章,感谢前辈们的分享)
官方给出的解释是:Git是一个开源的分布式版本控制系统 ,我们简单的理解为Git 是一个内容寻址文件系统,也就是说Git 的核心部分是键值对数据库。 当我们向 Git 仓库中插入任意类型的内容(开发者们在其中做的版本信息修改之类的操作),它会返回一个唯一的键,通过该键可以在任意时刻再次取回该内容
Git是一个可以实现有效控制应用版本的系统,但是在一旦在代码发布的时候,存在不规范的操作及配置,就很可能将源代码泄露出去。那么,一旦攻击者或者黑客发现这个问题之后,就可能利用其获取网站的源码、数据库等重要资源信息,进而造成严重的危害。
正如简介所说,在配置不当的情况下,可能会将“.git”文件直接部署到线上环境,这就造成了git泄露问题。
攻击者利用该漏洞下载.git文件夹中的所有内容。如果文件夹中存在敏感信息(数据库账号密码、源码等),通过白盒的审计等方式就可能直接获得控制服务器的权限和机会!
.git目录:使用git init初始化git仓库的时候,生成的隐藏目录,git会将所有的文件,目录,提交等转化为git对象,压缩存储在这个文件夹当中。
COMMIT_EDITMSG:保存最新的commit message,Git系统不会用到这个文件,用户一个参考文件
config:Git仓库的配置文件
description:仓库的描述信息,主要给gitweb等git托管系统使用
HEAD:这个文件包含了一个档期分支(branch)的引用,通过这个文件Git可以得到下一次commit的parent
hooks:这个目录存放一些shell脚本,可以设置特定的git命令后触发相应的脚本;在搭建gitweb系统或其他
git托管系统会经常用到hook script(钩子脚本)
index:这个文件就是我们前面提到的暂存区(stage),是一个二进制文件
info:包含仓库的一些信息
logs:保存所有更新的引用记录
objects:所有的Git对象都会存放在这个目录中,对象的SHA1哈希值的前两位是文件夹名称,后38位作为对象文件名
refs:这个目录一般包括三个子文件夹,heads、remotes和tags,heads中的文件标识了项目中的各个分支指向的当前commit
ORIG_HEAD:HEAD指针的前一个状态
git init 初始化一个git仓库
git add && git commit //git 添加文件和提交文件
git status 查看当前仓库状态和内存状态
git ls-files -u 显示冲突的文件,-s是显示标记为冲突已解决的文件
git diff 对比工作区和stage文件的差异
git diff -cached 对比stage和branch之间的差异
git ls-files -stage 检查保存在stage的文件
git log 显示到HEAD所指向的commit为止的所有commit记录
git reset -hard HEAD放弃工作区和index的改动,HEAD指针仍然指向当前的commit
git仓库中的文件存在三种状态:
①Untracked files:文件未被跟踪
②Changes to be commited:文件已暂存,指向下一次提交的内容
③Changes not staged for commit:已跟踪文件的内容发生了变化,但是还没有放到暂存区
commit:指向一个tree,它用来标记项目某个特定时间点的状态
一般包含以下信息:
①代表commit的哈希值
②指向tree对象的哈希值
③作者
④提交者
⑤注释
tree:可以简单的理解成这是一个对象关系树,用来管理一些tree和blob
一般包含以下信息:
①代表blob的哈希值
②指向tree对象的哈希值
blob:这种对象用来保存文件内容
tag:给某个提交增添的标记
(画一个比较简陋的对应图,稍微形象一点,哈哈哈,虽然很丑,但自我感觉这个图还是挺直观的)
每个git对象都有个哈希值代表这个对象,也就是上面所说的键值对的对应形式。这个哈希值是通过SHA算法计算出来的,长度为40个字符。
那么,接下来我们就从实际案例出发,希望能帮助大家更清楚git的内存寻址思想!
首先,初始化一个git仓库:(这时候会产生一个隐藏的.git目录)
观察初始化的时候生成的git目录的内容:(初始化的时候是八个文件)
当前目录创建一个文件并写入内容,并利用git add .命令,将更改写入到.git/index文件中,然后再观察.git文件夹的变化(这个步骤相当于“通知”git,我对版本信息做了修改了!麻烦你记录一下哈!--粗浅的理解)
这时候,对比一下初始化的目录结构,我们可以很清晰的发现多了一个index文件(对应的是二进制文件),我们用winhex等二进制工具打开看看,index文件里面存储的内容是什么?
发现其中存储了,我们刚刚新创建的文件,那么,我们直到git中存储的都是对象信息,那么我们刚才创建的文件也就自然而然在git系统中会以对象的形式被存储,这时候我们去看看对应存储对象的目录中去看看:
这时候,我们发现当前目录下多了一个19文件夹,对比刚才index的内容,很轻易的发现,index文件中不仅存储了我们创建的文件名,还有文件在git存储中对应的对象信息:
而19文件夹打开后发现里面存储的是对应除去开头19的对象对应的“地址”信息:
在git中,这些对象存储文件都是通过zlib进行压缩的,所以我们可以使用zlib将其解压出来,来看看这个文件里面存储的内容是什么:
解压代码如下:
import zlib
import requests
urla = "解压文件地址"
re = requests.get(urla)
ss = re.content
word = zlib.decompress(ss)
print(word)
解压之后,发现objects对应文件标记了是blob对象,存储的是新建的test.txt文件的内容。
由上面一个简单的过程,就可以很形象的直到git在解析存储版本信息的时候,利用的是内存地址寻址的方式分布式存储版本信息的。
那么,一旦这个.git文件夹泄露,我们就可以通过zlib解压的方式获取到网站的相关版本信息等,进而进行代码审计等操作,分析应用的漏洞以及社工等。
首先,我们需要对应的授权站点是否存在这个漏洞:
①可以先观察一下站点是否有醒目地指出Git,如果有的话,那就说明站点很大可能是存在这个问题的
②如果站点没有醒目的提示的话,可以利用dirsearch这类扫描工具,如果存在./git泄露的问题的话,会被扫描出来的,哈哈
③最直观的方式,就是直接通过网页访问.git目录,如果能访问就说明存在
当确认存在这个漏洞之后,就可以通过工具来下载git泄露的全部源码(工具例如:GitHack等等)
关于具体怎么利用,我们就直接利用buuctf中的[GXYCTF2019]禁止套娃来演示一下吧:
通过分析源码发现preg_match()函数过滤传参中的一些关键字,通过解析可以推导出来,允许传入的参数值格式是:A(B(C(…))),这种很明显是函数模式,那么就好说了,我们首先思考一下我们需要做的是什么?
查看目录里面的所有文件,那么php中恰好就有一个函数scandir()浏览目录内的所有文件;--vardump(scandir("."))
我们直到.是代表当前目录的意思,那么也就是说我们要满足scandir中接收的参数是".",而PHP中localeconv() 函数可返回一包含本地数字及货币格式信息的数组 --vardump(scandir(localecnov())))
然后,我们就只需要让指针指向这个数组内的第一个值就好了
exp=vardump(scandir(current(localecnov()))));
尝试访问上面构造的payload:http://586fb95a-e475-4ebb-afe0-2d9a2e8fdcd1.node4.buuoj.cn:81/?exp=vardump(scandir(current(localecnov()))));
这时候,我们可以成功看到有一个flag.php文件
接下来,我们就需要想办法把该文件的内容读取出来:
next() 函数将内部指针指向数组中的下一个元素,并输出。
array_reverse() 函数返回翻转顺序的数组。
exp=show_source(next(array_reverse(scandir(current(localeconv())))));
这段代码是什么意思呢?就还是利用scandir()函数查看当前目录的文件,然后利用next()函数和array_reverse()函数将文件中的内容读取出来,最后调用show_source()函数将内容展示到页面上
这样,这道题就解出来了。。。
好了,这个基础的文章就先写到这,关于git泄露如果还有什么奇淫技巧,欢迎大佬们指教。。。哈哈