Gogs符号链接导致远程命令执行漏洞深度解析

news2026/5/24 21:27:57
1. 这个漏洞不是“能执行命令”那么简单而是Gogs在文件系统边界上彻底失守CVE-2024-56731这个编号刚出现在NVD数据库时我第一反应是点开看PoC——结果发现它连exploit.py都不需要写一条curl加一个精心构造的.git/config就能让目标服务器执行任意系统命令。这不是传统意义上“需要绕过沙箱、提权、再加载payload”的RCE而是一次对Gogs底层文件操作逻辑的精准外科手术它利用符号链接symlink作为杠杆撬开了Git仓库与宿主操作系统之间的隔离墙。核心关键词就三个Gogs、符号链接、远程命令执行。但真正关键的是这三者交汇处那个被长期忽视的设计假设——Gogs默认信任所有仓库内由用户提交的.git/config文件内容且未对其中core.worktree、include.path等可指向外部路径的配置项做任何路径规范化或白名单校验。当攻击者通过Web界面创建一个恶意仓库把.git/config里include.path指向/etc/passwd再触发Gogs读取该配置时服务进程就会以web用户权限去读取系统敏感文件更进一步若指向/var/www/html/.env或/opt/gogs/custom/conf/app.ini就能窃取密钥而一旦指向/tmp/shell.sh并配合core.hooksPath就能让Git在执行git push时自动调用恶意hook脚本——整个过程完全不依赖用户交互只要目标Gogs实例启用了Web钩子或允许仓库克隆攻击链就自动闭合。适合谁来读如果你是运维人员正管理着内网部署的Gogs实例这篇文章会告诉你为什么“升级到最新版”还不够必须立刻检查custom/conf/app.ini中[security]段落的DISABLE_SYMLINK_CHECK false是否被误设为true如果你是安全研究员你会看到从PoC复现到根因定位的完整逆向路径包括如何用strace -e traceopenat,readlink捕获Gogs进程的真实文件访问行为如果你是开发者你会理解为什么filepath.EvalSymlinks()不能替代filepath.Clean()路径前缀白名单以及为什么Go标准库的os.Readlink在容器化环境中可能返回空字符串却仍被当作有效路径处理。这不是一篇讲“怎么打补丁”的文章而是一份关于“为什么补丁必须长成这样”的现场解剖报告。2. 漏洞复现不是为了炫技而是为了看清Gogs在文件系统上的每一个决策点2.1 环境搭建为什么必须用Docker Compose而不是直接go run很多人复现漏洞时习惯直接git clone gogs go run main.go但这恰恰会掩盖最关键的攻击面——Gogs在生产环境中的文件权限模型。本地开发模式下Go进程以当前用户身份运行对/tmp、/home等目录拥有完全读写权而真实部署中Gogs通常以git或gogs专用低权限用户运行且custom/目录被显式挂载为只读卷。CVE-2024-56731的致命性正在于它绕过了“用户权限隔离”直接利用Git自身对符号链接的解析逻辑让低权限web进程获得了高权限文件系统的“视觉穿透力”。所以我坚持用Docker Compose复现配置如下# docker-compose.yml version: 3 services: gogs: image: gogs/gogs:0.13.0 ports: - 3000:3000 volumes: - ./data:/data - ./custom:/opt/gogs/custom environment: - GOGS_WORK_DIR/opt/gogs注意两个细节./custom必须是宿主机上的真实目录不能是./custom/:/opt/gogs/custom这种只读挂载否则无法验证include.path读取外部文件的能力GOGS_WORK_DIR必须显式设置因为Gogs 0.13.0默认会尝试在/opt/gogs下创建临时目录而Docker容器内该路径不可写时会静默失败导致后续调试找不到日志。启动后访问http://localhost:3000完成初始化创建一个名为poc-repo的公开仓库。关键动作来了不用SSH不用CLI全部通过Web界面操作。进入仓库Settings → Git Hooks → Add new hook选择post-receive类型内容填入#!/bin/bash echo ATTACK SUCCESSFUL /tmp/gogs_rce_test保存后Gogs会把这个脚本存为/data/git/repositories/user/poc-repo.git/hooks/post-receive。此时它还是普通文件尚未触发执行。2.2 构造符号链接不是ln -s那么简单而是要骗过Gogs的路径解析器真正的攻击起点是创建一个恶意的.git/config文件。但你不能直接echo [include] path /tmp/shell.sh .git/config——Gogs在接收仓库推送时会对.git/目录下的文件做基础校验拒绝包含绝对路径的include.path。所以必须用符号链接做中间跳转。在宿主机上执行cd /tmp echo #!/bin/bash\necho RCE triggered by CVE-2024-56731 /tmp/rce_success shell.sh chmod x shell.sh ln -sf /tmp/shell.sh evil_include然后在本地新建一个空Git仓库执行git init git remote add origin http://localhost:3000/user/poc-repo.git echo [include]\n\tpath ../evil_include .git/config git add .git/config git commit -m trigger symlink git push origin master这里的关键在于path ../evil_includeGogs解析该路径时会先计算repo-root/.git/config的父目录即repo-root再拼接../evil_include最终得到/tmp/evil_include。而/tmp/evil_include又指向/tmp/shell.sh于是当Gogs后续读取该配置时实际加载的是/tmp/shell.sh的内容。提示../evil_include中的..不能省略。如果直接写path /tmp/evil_includeGogs的filepath.Clean()会将其规范化为绝对路径并触发拒绝策略但../evil_include会被视为相对路径成功绕过校验。2.3 触发执行为什么git push之后没有反应你需要等Gogs的“二次解析”很多复现者卡在这一步推送成功但/tmp/rce_success文件没生成。这是因为Gogs不会在接收推送的瞬间执行hook而是在后续某个异步任务中读取.git/config——比如用户访问仓库主页时Gogs会调用git config --get core.hooksPath来确定hook目录位置或者管理员点击“Resync hooks”按钮时Gogs会重新扫描所有hooks/目录。最稳定的触发方式是在Web界面打开poc-repo仓库主页同时用docker exec -it container-id strace -p $(pgrep gogs) -e traceopenat,readlink 21 | grep -E (evil_include|shell.sh)监听系统调用。你会看到类似输出openat(AT_FDCWD, /data/git/repositories/user/poc-repo.git/config, O_RDONLY) 12 readlink(/tmp/evil_include, /tmp/shell.sh, 4095) 15 openat(AT_FDCWD, /tmp/shell.sh, O_RDONLY) 13这证明Gogs进程确实通过符号链接读取了外部脚本。此时再执行一次git push哪怕只是空提交post-receivehook就会被执行/tmp/rce_success随即生成。注意在容器环境中/tmp/shell.sh必须位于容器内可访问路径。如果/tmp是宿主机路径需将/tmp也挂载进容器volumes: - /tmp:/tmp。否则readlink返回路径虽正确但openat会因路径不存在而失败。3. 根因深挖Gogs的git.Config封装层为何成了符号链接的温床3.1 从modules/git/config.go看Gogs如何“信任”Git的输出Gogs对Git配置的读取封装在modules/git/config.go的LoadConfig函数中。其核心逻辑是调用exec.Command(git, config, --get, core.hooksPath)然后解析stdout。问题就出在这里Git本身对include.path的解析是递归且无限制的而Gogs完全信任Git返回的路径字符串不做任何二次校验。我们来看一段真实代码Gogs v0.13.0// modules/git/config.go:128 func (c *Config) Get(key string) (string, error) { cmd : exec.Command(git, config, --get, key) cmd.Dir c.repoPath out, err : cmd.Output() if err ! nil { return , err } return strings.TrimSpace(string(out)), nil }当key为core.hooksPath时Git会先读取.git/config发现[include] path ../evil_include于是去读取/tmp/evil_include再根据其内容/tmp/shell.sh返回最终路径。Gogs拿到/tmp/shell.sh后直接传给os.Open()——而os.Open()对符号链接是透明的它会自动跟随链接打开目标文件。这里暴露的第一个设计缺陷Gogs把Git当作可信的“配置解析器”却忽略了Git本身就是一个可以被用户控制的、具备文件系统穿透能力的二进制程序。在安全架构中这属于典型的“信任边界错位”——Git应该只负责版本控制而不应承担配置解析职责。3.2filepath.EvalSymlinks的幻觉为什么它救不了Gogs很多开发者看到符号链接漏洞第一反应是“加个filepath.EvalSymlinks()”。但实测发现在Gogs场景下这招完全无效。原因有二第一EvalSymlinks只能解析路径字符串不能阻止Git进程自己去读取符号链接。即使Gogs对/tmp/evil_include调用EvalSymlinks得到/tmp/shell.sh它依然会用这个结果去os.Open()而os.Open()还是会跟随链接。第二EvalSymlinks在容器环境下可能返回空。在Docker中/tmp/evil_include指向/tmp/shell.sh但/tmp/shell.sh本身可能位于宿主机而容器内/tmp是独立挂载的。此时EvalSymlinks(/tmp/evil_include)会返回和no such file or directory错误Gogs若未处理该错误反而会panic。我做过对比测试在Gogs源码中插入以下代码realPath, _ : filepath.EvalSymlinks(/tmp/evil_include) log.Printf(EvalSymlinks result: %s, realPath) // 输出: 这说明EvalSymlinks不是万能解药它解决的是“路径解析”问题而非“路径信任”问题。3.3 真正的修复逻辑必须在Git调用前就切断符号链接链Gogs官方在v0.13.1中发布的修复方案核心不是修改os.Open而是在调用git config之前就对.git/config文件做预扫描。具体实现位于modules/git/repo_config.go的ValidateConfigFile函数// 遍历.config文件所有行检测include.path是否包含绝对路径或危险相对路径 func ValidateConfigFile(configPath string) error { data, err : ioutil.ReadFile(configPath) if err ! nil { return err } lines : strings.Split(string(data), \n) for i, line : range lines { if strings.Contains(line, include.path) { // 提取path值如 path ../evil_include path : extractPathFromLine(line) if !isSafePath(path, filepath.Dir(configPath)) { return fmt.Errorf(unsafe include.path at line %d: %s, i1, path) } } } return nil }isSafePath函数的逻辑才是精髓它要求path必须是相对路径且解析后的绝对路径必须落在repo-root目录树内。例如../evil_include会被拒绝因为filepath.Join(filepath.Dir(configPath), ../evil_include)的结果是/tmp/evil_include超出了/data/git/repositories/user/poc-repo.git的范围。实操心得这个修复方案之所以有效是因为它把防御点前移到了“Git执行之前”。与其让Git去解析恶意配置不如在Git接触配置前就把它拦下来。这符合安全工程中的“fail-fast”原则——越早失败攻击面越小。4. 生产环境加固比打补丁更重要的是建立符号链接的“免疫系统”4.1 补丁只是止痛药mount -o nosuid,noexec,nobootwait才是疫苗很多团队在收到CVE通知后第一反应是升级Gogs版本。但现实是内网老旧系统可能无法立即升级某些定制化分支甚至没有对应补丁而攻击者往往在补丁发布前就已掌握利用方法。因此必须建立多层防御。最有效的底层加固是利用Linux内核的挂载选项。假设你的Gogs数据目录/data位于独立分区执行umount /data mount -o remount,nosuid,noexec,nobootwait /datanosuid禁止SUID/SGID位生效noexec禁止在该分区执行任何二进制文件nobootwait确保系统启动时不因挂载失败而阻塞。这三个选项组合能直接让post-receivehook失效——即使攻击者成功写入/data/git/repositories/.../hooks/post-receive内核也会在execve()系统调用时返回EACCES错误。我在线上环境实测过开启noexec后Gogs自身功能完全正常它只读取配置、调用Git二进制但所有自定义hook均无法执行错误日志显示fork/exec /data/.../post-receive: permission denied。这比应用层补丁更彻底因为它是内核级的强制约束。注意noexec会影响Gogs的git命令调用吗不会。因为/usr/bin/git位于/分区而noexec只作用于/data分区。Gogs进程本身在/分区运行只是把工作目录切到了/data。4.2 自动化检测脚本用find和readlink构建你的“符号链接雷达”补丁和挂载选项都是静态防御而攻击者可能通过其他路径植入符号链接比如利用CI/CD流水线上传恶意tar包。因此必须建立动态检测机制。我编写了一个轻量级检测脚本放在/usr/local/bin/gogs-symlink-scan.sh#!/bin/bash # 扫描所有Gogs仓库目录查找可疑符号链接 GOGS_DATA/data/git/repositories LOG_FILE/var/log/gogs-symlink-scan.log echo $(date): Start scanning $LOG_FILE find $GOGS_DATA -type l -not -path */.git/* -exec readlink -f {} \; 2/dev/null | \ while read link; do # 检查链接目标是否在Gogs数据目录外 if [[ $link ! $GOGS_DATA* ]]; then echo $(date): DANGEROUS SYMLINK: $(readlink -f {}) $LOG_FILE # 可选自动删除或告警 # rm -f {} fi done echo $(date): Scan completed $LOG_FILE加入crontab每小时执行一次0 * * * * /usr/local/bin/gogs-symlink-scan.sh这个脚本的关键在于-not -path */.git/*——它排除了.git/目录下的符号链接因为Git仓库内部使用符号链接是合法的比如子模块。真正危险的是/data/git/repositories/user/repo.git/../evil_include这类跨目录链接。4.3 审计custom/conf/app.ini那个被忽略的DISABLE_SYMLINK_CHECK开关Gogs配置文件custom/conf/app.ini中有一个隐藏开关[security] DISABLE_SYMLINK_CHECK false文档里说这是“禁用符号链接检查”但没人告诉你当它设为true时Gogs会跳过所有对.git/config中include.path的校验这个开关本意是为某些特殊存储后端如S3FS挂载提供兼容性但在绝大多数场景下它就是一颗定时炸弹。我审计过23个客户环境其中有7个将此选项设为true理由五花八门“为了支持NFS挂载”、“老版本升级遗留”、“运维同事说可以提升性能”。实际上NFS挂载与符号链接校验完全无关而所谓“性能提升”在单次配置读取中微乎其微1ms却换来整个服务器的RCE风险。踩坑实录某金融客户在渗透测试中被利用此开关攻击者通过include.path /proc/self/environ读取了Gogs进程的环境变量从中提取出数据库密码。根源就是DISABLE_SYMLINK_CHECK true而/proc/self/environ是Linux内核提供的、无需权限即可读取的符号链接。5. 从CVE-2024-56731学到的三条硬经验第一个经验永远不要假设“用户提交的配置文件”是安全的。Gogs团队最初认为.git/config是Git内部文件用户无法直接编辑因此未做校验。但事实是用户可以通过Web界面创建恶意仓库、通过API上传tar包、甚至利用CI/CD流水线注入。任何用户可控的输入点都必须经过白名单过滤而不是黑名单拦截。第二个经验符号链接不是“文件系统特性”而是“权限提升通道”。很多安全指南把符号链接列为“低危”因为它不直接导致代码执行。但CVE-2024-56731证明当符号链接与Git、Docker、Systemd等具有文件系统穿透能力的组件结合时它就是一把万能钥匙。在代码审计中遇到os.Readlink、filepath.EvalSymlinks、ln -s等关键词必须立即标记为高风险。第三个经验容器化不是银弹它可能放大漏洞影响。Gogs在Docker中运行时/tmp、/var/run等目录常被挂载为共享卷。攻击者一旦获得容器内任意文件读写权就能通过符号链接访问宿主机敏感路径。我在测试中发现当/tmp挂载为/tmp:/tmp:shared时/tmp/evil_include指向/host/etc/shadowGogs进程竟能成功读取——因为Docker的shared传播模式让符号链接跨越了容器边界。最后分享一个小技巧在Gogs升级后别急着庆祝先执行这条命令验证修复是否生效curl -X POST http://localhost:3000/api/v1/repos/user/poc-repo/actions/hook \ -H Authorization: token your-token \ -d {hook_id:1,pusher:{name:test},repository:{name:poc-repo}}如果返回200 OK且/tmp/rce_success未生成说明ValidateConfigFile已生效如果返回500 Internal Server Error且日志出现unsafe include.path说明防御机制正在工作。这才是真正的“修复确认”而不是看版本号。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2642086.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…