CVE-2025-53547:Helm依赖更新代码注入漏洞分析及深度思考
你的瞳色是我生命苦寻的永生花, 从此在我生命里悄悄发芽
漏洞描述
CVE-2025-53547 是一个影响 Kubernetes 包管理工具 Helm 的高危代码注入漏洞。该漏洞在 Helm 3.18.4 之前的版本中存在。攻击者可以通过精心构造的 Chart.yaml 文件和符号链接的 Chart.lock 文件,在更新依赖时将恶意内容写入目标文件,从而导致本地代码执行。
漏洞修复
对比Helm官方仓库v3.18.3与v3.18.4在向Chart.lock文件写入内容之前先检查了一下文件的属性

代码分析
根据代码改动可定位到漏洞点存在于pkg/downloader/manager.go文件的writeLock函数中

该函数中在当前目录下面生成Chart.lock文件然后将data内容写入进去。data即为lock锁的内容
在进行文件写入的时候并没有检查文件类型,如果Chart.lock文件是软链接,则会对连接到的文件进行数据写入
一个demo
这个demo 向本目录下的example.txt中写入数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 package main
import (
"fmt"
"os"
)
func main() {
// 要创建的文件名
filename := "example.txt"
// 要写入的数据
data := "Hello, this is some data written to the file."
// 创建文件(如果文件已存在,会清空重写)
file, err := os.Create(filename)
if err != nil {
fmt.Println("创建文件失败:", err)
return
}
// 记得关闭文件
defer file.Close()
// 写入数据
_, err = file.WriteString(data)
if err != nil {
fmt.Println("写入数据失败:", err)
return
}
fmt.Println("文件创建并写入成功:", filename)
}在运行代码的时候 先创建一个名为
example.txt的软链接,再运行文件则会导致他想目标文件写入数据
下一步寻找调用writeLock的函数
在整个项目中全局搜索仅找到一处地方调用了writeLock函数

也就是pkg/downloader/manager.go文件中的Update()函数
相关代码
1 | func (m *Manager) Update() error { |
Update()调用wirteLock的时候传入了m.ChartPath, lock
m.ChartPath是我们执行helm命令时的路径信息
在源代码中加上一个输出函数
1 | func (m *Manager) Print() { |

然后对其进行调用 来查看m的各属性信息


m.ChartPat即为当前目录
lock是由m.resolve处理之后返回的

resolve函数中New了一个resolver对象 将m.ChartPath, m.RepositoryCache, m.RegistryClient三个属性赋给res,然后res调用Resolve

Resolve根据 Chart.yaml 里的依赖(reqs),逐一确认依赖能否满足 semver 版本约束,并填充 locked(最终写入 Chart.lock)
1 | func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string) (*chart.Lock, error) { |
在pkg/chart/dependency.go为Lock添加一个Print方法

然后在pkg/downloader/manager.go调用Print

然后运行就可以看Lock内容

这个内容就是在Chart.lock中写入的内容

到这就是整个过程POChttps://github.com/DVKunion/CVE-2025-53547-POC

尝试的挫败
目前网上已存在的利用方式是试着将Chart.lock链接到.bashrc上。。。但是当你真的这种做的时候
你就会发现这样会报错然后崩溃

再回头看Update函数

Update函数首先调用了loadChartDir()函数
loadChartDir()函数中又调用了loader.LoadDir()传入了m.ChartPath也就是.

在LoadDir()函数中会读取目录中的文件,将文件名与文件内如保存到file列表中,然后调用LoadFiles()函数
1 | func LoadDir(dir string) (*chart.Chart, error) { |
在LoadFiles()函数中如果存在Chart.lock文件则将会尝试对其进行yaml解析

那么这样一来 则就会对Chart.lock的内容要求有限制。只允许他是yaml或者空文件
那么将其连接到.bashrc上面的计划也就泡汤,因为没有上面.bashrc文件回事yaml格式或者内容为空
条件放宽与潜在利用
既然目的是想让里面的命令被执行
那么除了.bashrc这一类文件还有一类文件即存放在/ect/cron.*/目录文件会被执行
但Chart.lock链接的文件又必须存在。没办法
如果这些目录下刚好有一个空文件
或许可以进行利用了。


小插曲
网上大多标出的触发的方法是用helm dependency update命令触发的时候
但是我在复现的过程中发现helm dependency build也能触发
究其原因是如果有lock文件 Build会直接调用Update函数

参考文献:
- 【漏洞复现】CVE-2025-53547 helm恶意代码执行漏洞复现&分析 https://mp.weixin.qq.com/s/oawEoi_SbYn46NuIht0BCg
- PoC: https://github.com/DVKunion/CVE-2025-53547-POC/tree/main
- helm官方git更新: https://github.com/helm/helm/compare/v3.18.3...v3.18.4
本文首发于先知社区https://xz.aliyun.com/news/18811







