CTFHub 信息泄露通关笔记11:HG泄露(4种方法)
目录
一、HG泄露
1、HG简介
2、HG泄露
3、HG安装
二、DVCS-Ripper工具
1、工具简介
2、下载安装
(1)下载安装DVCS-Ripper
① Git命令下载
② Web页面下载
(2)基本使用方法
3、利用步骤
三、渗透实战
1、打开靶场
2、目录扫描发现.svn文件
3、dvcs ripper渗透
4、原始法获取flag文件名
(1)方法1:grep法
(2)方法2:cat查看法
5、hg log法获取flag名
(1)hg log查历史记录
(2)方法3:hg diff查看区别
(3)方法4:hg log查看区别
6、hg cat获取flag失败
7、store/data查找flag失败
8、查看flag
本文使用四种方法进行CTFHub的信息泄露-HG泄露关卡的渗透实战,系统剖析了hg泄露的机制、风险及利用技术。当开发人员不慎将.hg目录部署至生产环境时,攻击者可借此获取项目源码、提交历史等关键数据。通过实战演示,文章完整呈现了从靶场目录扫描发现.hg泄露,到运用dvcs-ripper工具成功还原项目并获取flag的全过程。
一、HG泄露
1、HG简介
Mercurial(简称 hg
)是一款分布式版本控制系统(DVCS),与 Git 类似,用于跟踪文件变更、管理代码版本,支持离线操作和分布式协作。其核心特点包括:
- 每个开发者本地都有完整的版本库副本,包含所有历史提交记录。
- 仓库根目录下会生成
.hg
隐藏目录,存储版本库核心数据(如提交历史、文件快照、分支信息等)。 - 常用命令:
hg init
(初始化仓库)、hg add
(暂存文件)、hg commit
(提交变更)、hg log
(查看历史)等。
2、HG泄露
Hg 泄露 是指由于配置错误,Web 服务器将 Mercurial 仓库的元数据目录(.hg)直接暴露在了可公开访问的 Web 根目录下。攻击者可以通过浏览器或工具直接访问 .hg
目录内的文件,从而下载并重建整个源代码仓库。.hg
目录的关键目录如下所示。
.hg/store
:存储文件快照和提交对象的核心目录。.hg/history
:记录分支和提交历史的元数据。.hg/dirstate
:跟踪当前工作区文件状态的信息。
3、HG安装
后续在进行渗透过程中如果使用hg log命令进行渗透,需要使用到hg软件,如果未安装hg则需要进行安装,命令如下所示。
└─# pip3 install mercurialCollecting mercurialDownloading mercurial-7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl (7.4 MB)━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 7.4/7.4 MB 34.7 kB/s eta 0:00:00
Installing collected packages: mercurial
Successfully installed mercurial-7.1
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
二、DVCS-Ripper工具
1、工具简介
DVCS-Ripper(通常也叫 rip-*.pl
)是一款专门用于检测和利用配置错误的安全工具。它的核心功能是:当发现一个网站意外地暴露了其版本控制系统的元数据目录(如 .git
, .svn
, .hg
)时,它能够远程下载并重建整个代码仓库,从而造成源代码泄露。
项目地址: https://github.com/kost/dvcs-ripper
方面 | 描述 |
---|---|
主要用途 | 渗透测试与CTF竞赛。用于利用“源代码泄露”,帮助安全研究人员和攻击者获取网站的完整源代码,以便进一步分析(如硬编码的密钥、API令牌、数据库凭证、逻辑缺陷等)。 |
支持的系统 | 支持多种分布式版本控制系统(DVCS)和集中式系统: • Git ( rip-git.pl )• Subversion (SVN) ( rip-svn.pl )• Mercurial (Hg) ( rip-hg.pl )• Bazaar (Bzr) ( rip-bzr.pl ) |
工作原理 | 工具会模拟版本控制客户端的行为,通过HTTP请求逐个下载仓库的元数据文件(如 index , HEAD , objects/info/packs , entries 等),解析这些文件以获取文件列表和其对应的哈希值,然后根据这些哈希值下载所有代码对象,最终在本地重建出一个完整的、可用的代码仓库。 |
2、下载安装
(1)下载安装DVCS-Ripper
dvcs-ripper 的核心功能是从泄露的版本控制目录(如.git、.svn)中提取并恢复数据,它能识别版本库的文件结构,自动下载相关组件并重建完整仓库,包含源代码、历史提交记录等,可通过 Git命令下载或者在官网下载源码。
① Git命令下载
sudo git clone https://github.com/kost/dvcs-ripper
② Web页面下载
对于源码中的pl后缀的脚本,其主要功能和对应的目标系统如下表所示。
脚本名称 | 目标系统 | 主要功能 |
---|---|---|
rip-git.pl | Git (.git ) | 下载并重建暴露的 Git 仓库 |
rip-svn.pl | Subversion (.svn ) | 下载并重建暴露的 SVN 仓库 |
rip-hg.pl | Mercurial (.hg ) | 下载并重建暴露的 Hg 仓库 |
rip-bzr.pl | Bazaar (.bzr ) | 下载并重建暴露的 Bzr 仓库 |
rip-cvs.pl | CVS (CVS/ ) | 下载并重建暴露的 CVS 仓库 |
(2)基本使用方法
DVCS-Ripper 的运行依赖于一些 Perl 模块,需要安装响应的依赖库,具体如下所示。
#安装依赖文件
sudo apt-get install perl libio-socket-ssl-perl libdbd-sqlite3-perl libclass-dbi-perl libio-all-lwp-perl
进入到dvcs-ripper目录中,验证安装是否成功,具体方法如下所示。
# 进入你克隆的目录
cd dvcs-ripper# 运行工具需要指定 perl 解释器和脚本路径
perl rip-git.pl --help# 或者给脚本添加执行权限后直接运行
chmod +x rip-git.pl
./rip-git.pl --help
3、利用步骤
利用HG泄露的过程首先安装 dvcs-ripper 及依赖,克隆工具仓库并进入目录;用 rip-hg.pl 脚本,以目标含.hg 目录的 URL 为参数提取仓库;进入生成的本地目录,通过 hg log 查看提交历史获取版本号;用 hg cat 命令提取指定版本文件内容,或直接搜索.hg/store 目录下的快照文件,从中寻找敏感信息,如 CTF 中的 flag,以此完成 Hg 泄露的利用。
# 1. 安装dvcs-ripper工具及依赖(确保perl环境已配置)
sudo apt install -y perl libio-socket-ssl-perl && git clone https://github.com/kost/dvcs-ripper.git && cd dvcs-ripper# 2. 使用rip-hg.pl脚本提取目标Hg泄露的仓库(-u指定含.hg目录的URL)
perl rip-hg.pl -u http://target.com/.hg/# 3. 进入提取到的本地仓库目录(通常以目标域名命名)
cd target.com# 4. 查看仓库提交历史,获取版本号和提交记录
hg log# 5. 从历史版本中提取文件(替换版本号和文件名,如查看版本2的flag.txt)
hg cat flag.txt -r 2# 6. 若直接查看历史文件失败,搜索.hg/store目录下的快照文件(含所有版本内容)
grep -r "flag" .hg/store/# 说明:通过工具还原完整Hg仓库后,利用hg命令或直接搜索快照文件,从历史版本中挖掘敏感信息(如CTF中的flag)
三、渗透实战
1、打开靶场
打开关卡如下所示,提示信息为“来来来CTFHub在线扫端口,据说端口范围是8000-9000哦”,提示本关卡可以利用端口扫描进行渗透测试,且端口的范围是8000-9000。点击打开题目,此时系统自动创建Docker环境,下图蓝色部分的URL地址就是靶场环境。
打开靶场URL,页面提示"信息泄露-Mercurial,flag在服务端旧版本的代码中,不太好使的情况下,试着手工解决”,具体如下所示。
http://challenge-2786dc8af55340eb.sandbox.ctfhub.com:10800/
2、目录扫描发现.svn文件
通过目录扫描工具对challenge-2786dc8af55340eb.sandbox.ctfhub.com:10800进行渗透,这里选择使用dirmap工具进行渗透,命令如下所示。
sudo python3 dirmap.py -i http://challenge-2786dc8af55340eb.sandbox.ctfhub.com:10800/ -lcf
-
-i http://challenge-ef525d7f8675f9b7.sandbox.ctfhub.com:10800/:
-i
是指定扫描目标的参数,目标是challenge-2786dc8af55340eb.sandbox.ctfhub.com:10800。工具会默认对该 URL 进行目录扫描,探测潜在的隐藏目录或文件。 -
-lcf
(--loadConfigFile
):该参数表示加载项目根目录下的dirmap.conf
配置文件,使用文件中定义的详细扫描规则(如字典模式、递归扫描、请求头设置等)。
dirmap的扫描结果如下所示,在网站根目录下发现了.hg文件夹。
3、dvcs ripper渗透
使用dvcs ripper脚本对上一步发现的网站根目录下的hg文件进行渗透测试,通过dvcs ripper针对 Mercurial(hg)版本控制系统的 rip-hg.pl
脚本,以管理员权限(sudo
)从目标 URL http://challenge-2786dc8af55340eb.sandbox.ctfhub.com:10800/.hg
提取泄露的 Hg 版本库信息。完整的命令如下所示。
sudo ./rip-hg.pl -u http://challenge-2786dc8af55340eb.sandbox.ctfhub.com:10800/.hg
执行后,工具会自动解析 .hg
目录结构,下载相关文件并重建本地 Hg 仓库,具体如下所示。
根据如上返回结果可知利用是成功的,所有关键元数据都已下载完毕,但由于本地系统缺少 hg
客户端,工具无法完成最后的组装步骤。
4、原始法获取flag文件名
(1)方法1:grep法
使用grep命令查找flag相关文件,递归地搜索.HG目录下的文件。这里要特别强调,查找ctfhub关键字未找到,查找flag找到相关文件。
┌──(root㉿kali)-[/home/kali/ljn/dvcs-ripper]
└─# grep -r "ctfhub" .hg┌──(root㉿kali)-[/home/kali/ljn/dvcs-ripper]
└─# grep -r "flag" .hg
grep: .hg/dirstate: binary file matches
grep: .hg/undo.dirstate: binary file matches
.hg/last-message.txt:add flag
grep: .hg/store/undo: binary file matches
grep: .hg/store/00manifest.i: binary file matches
.hg/store/fncache:data/flag_455230392.txt.i
从搜索结果来看,.hg/store/fncache
中提到了 data/flag_455230392.txt.i
,这很可能是存储 flag 的文件快照。
(2)方法2:cat查看法
进入到.hg/store/目录中,查看fncache文件发现flag文件,具体过程如下所示。
kali@kali:~/ljn/dvcs-ripper$ cd .hg
kali@kali:~/ljn/dvcs-ripper/.hg$ ls
00changelog.i dirstate last-message.txt requires store undo.branch undo.desc undo.dirstate
kali@kali:~/ljn/dvcs-ripper/.hg$ cd store/
kali@kali:~/ljn/dvcs-ripper/.hg/store$ ls
00changelog.i 00manifest.i data fncache undo
kali@kali:~/ljn/dvcs-ripper/.hg/store$ cat fncache
data/index.html.i
data/50x.html.i
data/flag_455230392.txt.i
分析fncache中的文件内容,fncache
是 Mercurial 仓库中一个非常重要的索引文件。 它的名字是 "Filename Cache"(文件名缓存)的缩写。它的核心作用是:充当一份“地图”或“清单”,记录了在 .hg/store/data/
目录下存储的所有文件数据对象的路径。可以把 .hg/store/
想象成一个巨大的仓库,里面堆满了各种箱子(数据文件)。而 fncache
文件就是这个仓库的货物清单,它告诉你每个箱子里装的是哪件货物的数据。
-
data/index.html.i
:这条记录对应着网站主页文件index.html
的存储内容。 -
data/50x.html.i
:这条记录很可能对应着某个HTTP 50x系列错误页面(如500内部服务器错误) 的存储内容。 -
data/
flag_455230392.txt.i
:这是最关键的一条记录! 它明确指向一个文件,其原始路径名很可能就是flag.txt
。Hg 对其进行了哈希计算,得到了 flag_455230392.txt
这个名称。这极大概率就是包含Flag的文件。
对于每一行的结构:data/<hash_based_filename>.i,含义如下所示。
-
data/
:这表示该文件存储在.hg/store/data/
子目录下。所有版本控制的文件内容都放在这个data
目录里。 -
<hash_based_filename>.i
:-
<hash_based_filename>
(例如index.html
,50x.html
,flag_455230392.txt
):这不是原始文件名,而是 Hg 根据文件的原始路径名计算出的一个哈希值。Hg 用这个哈希值来唯一地命名存储的文件对象。 -
.i
:这是 Hg 数据文件的标准扩展名,表示这是一个索引文件(revlog index file)。它包含了对应文件版本的历史信息和元数据。
-
5、hg log法获取flag名
(1)hg log查历史记录
使用hg log查询历史记录,运行结果说明有两个版本,具体如下所示。
-
版本 1(1:1e7cf632c422):最新版本(tag: tip),提交信息为 "add flag",明确表明此版本添加了 flag,是最可能包含目标 flag 的版本。
-
版本 0(0:727f0a9e764f):初始版本,提交信息为 "init",通常是仓库初始化操作。
┌──(root㉿kali)-[/home/kali/ljn/dvcs-ripper]
└─# hg log
changeset: 1:1e7cf632c422
tag: tip
user: CTFHubSandBox <sandbox@ctfhub.com>
date: Tue Sep 09 16:26:30 2025 +0000
summary: add flagchangeset: 0:727f0a9e764f
user: CTFHubSandBox <sandbox@ctfhub.com>
date: Tue Sep 09 16:26:29 2025 +0000
summary: init
输出显示这个仓库有 2 次提交(changeset),Flag 是在第二次提交(changeset 1) 中被添加到项目中的,具体含义如下表所示。
信息 | 含义 |
---|---|
changeset: 1:1e7cf632c422 | 第二次提交。版本号是 1 ,变更集全局唯一ID是 1e7cf632c422 。 |
tag: tip | 这是最新的提交。tip 在 Hg 中类似于 Git 的 HEAD ,指向当前分支的最前端。 |
user: CTFHubSandBox... | 提交者的信息。 |
date: Tue Sep 09 ... | 提交时间(这是一个未来的时间,显然是CTF题目故意设置的)。 |
summary: add flag | 【最关键信息】 这次提交的说明是 “add flag”。这明确告诉我们,flag 是在这次提交中被添加到仓库里的。 |
changeset: 0:727f0a9e764f | 第一次提交。版本号是 0 ,变更集ID是 727f0a9e764f 。 |
summary: init | 这次提交的说明是 “init”,表示初始化仓库, likely 只包含一些基础文件 |
(2)方法3:hg diff查看区别
hg diff -r 0 -r 1
命令的含义是:比较并显示版本库中第 0 次初始提交(-r 0)与第 1 次提交(-r 1)之间的所有差异,包括文件的添加、删除和内容修改,具体如下所示。
# 查看第一次提交(init)和最新提交(add flag)之间的差异
└─# hg diff -r 0 -r 1
abort: flag_455230392.txt@d999632c88d9cf86e2288541a1b293eef4743fb8: no match found
运行的 hg diff -r 0 -r 1
命令报错:no match found
。错误的原因是:由于该操作试图对比一个不存在的文件(flag_455230392.txt 在版本 0 中不存在而在版本 1 中被添加),因此命令执行失败并报错 "no match found"。因为Hg 无法对一个“不存在”的文件和“存在”的文件进行差异比较,因此报错。然而这个错误信息本身也包含了文件名 flag_455230392.txt
,这已经是一个很强的提示了。
(3)方法4:hg log查看区别
hg log -v -r 1命令以详细模式(-v)显示版本库中第 1 次提交(-r 1)的完整信息,包括提交的变更集哈希值、作者、日期、文件列表和提交说明,具体如下所示。
# 查看最新提交的详细信息,包括更改的文件列表
└─# hg log -v -r 1changeset: 1:1e7cf632c422
tag: tip
user: CTFHubSandBox <sandbox@ctfhub.com>
date: Tue Sep 09 16:26:30 2025 +0000
files: flag_455230392.txt
description:
add flag
hg log -v -r 1
命令给出了最关键的答案。输出中的 files: flag_455230392.txt
这一行明确告诉了我们:在第二次提交(“add flag”提交)中,添加了一个名为 flag_455230392.txt
的文件。这个文件就是包含 flag 的文件。
6、hg cat获取flag失败
hg log
清楚地表明有一个名为 flag_455230392.txt
的文件被添加到了版本库中。但在你的工作目录中却找不到这个文件,尝试通过如下两个命令获取flag_455230392.txt
文件内容,如下所示。
# 语法:hg cat -r <版本号> <文件名>
# 从提交版本1中提取 flag_455230392.txt 的内容
hg cat -r 1 flag_455230392.txt# 或者使用变更集ID
hg cat -r 1e7cf632c422 flag_455230392.txt
但是在执行的过程中,两者全部报错no match found,且错误信息中包含了文件的完整哈希标识,使用hg cat提取flag文件内容失败。
┌──(root㉿kali)-[/home/kali/ljn/dvcs-ripper]
└─# hg cat flag_455230392.txt -r 1
abort: flag_455230392.txt@d999632c88d9cf86e2288541a1b293eef4743fb8: no match found┌──(root㉿kali)-[/home/kali/ljn/dvcs-ripper]
└─# hg cat -r 1e7cf632c422 flag_455230392.txtabort: flag_455230392.txt@d999632c88d9cf86e2288541a1b293eef4743fb8: no match found
7、store/data
查找flag失败
我们手动进入到.hg/store/data/
目录中,手动从 .hg/store/data/
目录中挖掘数据,如下所示该目录下确实没有任何文件。
8、查看flag
这时我们分析下第5步和第6步中两次本来能查到的flag_455230392.txt文件为何不好用呢,回顾下本关卡首页的提示“不太好使的情况下”试着手工解决。说明当前hg恢复的环境出了些小问题,确实不太好用,需要想办法手工解决。
上一步发现一个flag_455230392.txt文件,但是当前攻击机中没有找到这个文件。这时考虑通过URL访问根目录下的这个文件,放在url里面打开,完整URL如下所示。
challenge-2786dc8af55340eb.sandbox.ctfhub.com:10800/flag_455230392.txt
访问txt获取到如下信息flag值,具体如下所示。