.git文件夹泄漏时泄漏了什么信息?

0x00 背景

最近碰到一个站泄露了.git目录,所以来研究一下通过.git目录可以获得什么信息。

0x01 讨论

一. directory listing enable时

当服务器enable了directory listing时,我们可以取得.git文件夹里的所有文件,这时可以轻易还原出git里保存的源代码

二. diretory listing disable时

这时可以分为两种情况:

1.在本地进行开发,没有手动或者自动执行过git gc
这时所有object文件都是unpacked的,存储于.git/objects/xx/xxxxxxxxx…xxxxx下。具体的文件名可以从.git/refs/heads/master一步一步反推出来。反推方法见此文:https://en.internetwache.org/dont-publicly-expose-git-or-how-we-downloaded-your-websites-sourcecode-an-analysis-of-alexas-1m-28-07-2015/
通过这种方法我们可以把所有objects/文件夹下的文件全部下载下来,还原出git里的源代码。
以下是一个git repo init后并经过一次commit之后的构造。

.git
├── branches
├── COMMIT_EDITMSG
├── config
├── description
├── HEAD
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── prepare-commit-msg.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   └── update.sample
├── index
├── info
│   └── exclude
├── logs
│   ├── HEAD
│   └── refs
│   └── heads
│   └── master
├── objects
│   ├── 5d
│   │   └── 308e1d060b0c387d452cf4747f89ecb9935851
│   ├── 88
│   │   └── ec14fd86c91b3350e7594378d09a612829115a
│   ├── a3
│   │   └── a29260366f26f3a4d3ee9ed5ac2754564af15d
│   ├── b4
│   │   └── 3365601deda38ead8e75a666ffdbd3773ea1bd
│   ├── info
│   └── pack
└── refs
├── heads
│   └── master
└── tags

2.在本地进行开发,手动或者自动执行过git gc
这时所有object文件都会被pack,存储于.git/objects/pack/文件夹之下,目录构造如下:

.git
├── branches
├── COMMIT_EDITMSG
├── config
├── description
├── HEAD
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── prepare-commit-msg.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   └── update.sample
├── index
├── info
│   ├── exclude
│   └── refs
├── logs
│   ├── HEAD
│   └── refs
│   └── heads
│   └── master
├── objects
│   ├── info
│   │   └── packs
│   └── pack
│   ├── pack-42c330e67bac7f112a99372cb56aee7667e063d6.idx
│   └── pack-42c330e67bac7f112a99372cb56aee7667e063d6.pack
├── packed-refs
└── refs
├── heads
└── tags

我们发现形如.git/objects/xx/xxxxxxxxx…xxxxx的文件全部不见了,取而代之的是pack-xxxx….xxxx.idx和pack-xxxx….xxxx.pack文件。而pack-xxxx….xxxx.idx和pack-xxxx….xxxx.pack文件的文件名存储于.git/objects/info/packs文件里,这样我们就可以把pack文件全部下载下来,从而还原git repo。

3.从远程的repo里直接clone到本地。
远程repo (your_repo.git)的构造如下:

.
├── branches
├── config
├── description
├── HEAD
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── prepare-commit-msg.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   └── update.sample
├── info
│   └── exclude
├── objects
│   ├── 5d
│   │   └── 308e1d060b0c387d452cf4747f89ecb9935851
│   ├── 88
│   │   └── ec14fd86c91b3350e7594378d09a612829115a
│   ├── a3
│   │   └── a29260366f26f3a4d3ee9ed5ac2754564af15d
│   ├── b4
│   │   └── 3365601deda38ead8e75a666ffdbd3773ea1bd
│   ├── info
│   └── pack
└── refs
├── heads
│   └── master
└── tags

注意到即使你在本地执行git gc之后再push到远程,远程repo仍然是unpack状态的。
当我们从这样一个远程repo clone到本地时,这是本地的.git目录构造如下:

.git
├── branches
├── config
├── description
├── HEAD
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── prepare-commit-msg.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   └── update.sample
├── index
├── info
│   └── exclude
├── logs
│   ├── HEAD
│   └── refs
│   ├── heads
│   │   └── master
│   └── remotes
│   └── origin
│   └── HEAD
├── objects
│   ├── info
│   └── pack
│   ├── pack-95a62b7c7880bdb792bf328aed8e1fb8a9220d97.idx
│   └── pack-95a62b7c7880bdb792bf328aed8e1fb8a9220d97.pack
├── packed-refs
└── refs
├── heads
│   └── master
├── remotes
│   └── origin
│   └── HEAD
└── tags

可以看出来clone出的repo是packed的,并且没有objects/info/packs这个关键的文件,没有这个文件,我们就无法得知pack-xxxx….xxxx.idx和pack-xxxx….xxxx.pack的具体名字,也就无法下载这两个文件,无法还原出git repo。

4.从远端clone后并在本地进行了修改,commit。

这时.git文件夹如下:

.git/
├── branches
├── COMMIT_EDITMSG
├── config
├── description
├── HEAD
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── prepare-commit-msg.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   └── update.sample
├── index
├── info
│   ├── exclude
│   └── refs
├── logs
│   ├── HEAD
│   └── refs
│   ├── heads
│   │   └── master
│   └── remotes
│   └── origin
│   └── master
├── objects
│   ├── 75
│   │   └── 84f016876a06afb7000d9c96b855b4d3b53447
│   ├── 89
│   │   └── c6ec37e6314b8e80c93a1a6615882009567e6e
│   ├── af
│   │   └── bcec0667a1462f12797a0d8e9972909c9b530c
│   ├── info
│   │   └── packs
│   └── pack
│   ├── pack-505dc4aea6a63d778cd2d3f3a7665319c852ad51.idx
│   └── pack-505dc4aea6a63d778cd2d3f3a7665319c852ad51.pack
├── packed-refs
└── refs
├── heads
│   └── master
├── remotes
│   └── origin
│   └── master
└── tags

一部分是packed的文件,另一部分是unpacked文件,unpacked文件可以使用1.中的方法获得文件名并进行下载,而packed文件依然无法得知文件名而无法下载。这种情况下我们可以获原git repo的一部分内容,即在本地进行过commit的文件的内容。

0x02 总结

所以说,如果你在生产环境下使用git进行开发提交,那么当你的生产环境.git/文件夹泄露时,你的源代码有很大可能被泄露;但是如果你只是把远程的repo clone到成产环境下,那么即使你生产机器商上的.git/文件夹泄露,攻击者也不太可能获得你的源代码。

0x03 工具

GitTools