当前位置: 首页 > news >正文

欺骗单页应用(SPA)渲染隐藏路由 -- trouble at the spa b01lersCTF

题目信息:I had this million-dollar app idea the other day, but I can’t get my routing to work! I’m only using state-of-the-art tools and frameworks, so that can’t be the problem… right? Can you navigate me to the endpoint of my dreams?

题目使用 vite

{"name": "src","private": true,"version": "0.0.0","type": "module","scripts": {"dev": "vite","build": "tsc -b && vite build","lint": "eslint .","preview": "vite preview"},"dependencies": {"@tailwindcss/vite": "^4.1.3","react": "^19.0.0","react-dom": "^19.0.0","react-router": "^7.5.0","tailwindcss": "^4.1.3"},"devDependencies": {"@types/react": "^19.0.10","@types/react-dom": "^19.0.4","@vitejs/plugin-react": "^4.3.4","globals": "^15.15.0","typescript": "~5.7.2","vite": "^6.2.0","vite-plugin-javascript-obfuscator": "^3.1.0"}
}

查看路由

// 从 react 库中导入 StrictMode 组件,它可以帮助我们在开发模式下发现潜在问题
import { StrictMode } from 'react';
// 从 react-dom/client 库中导入 createRoot 函数,用于创建 React 根节点
import { createRoot } from 'react-dom/client';
// 从 react-router 库中导入 BrowserRouter、Routes 和 Route 组件,用于实现路由功能
import { BrowserRouter, Routes, Route } from 'react-router';// 导入页面组件
// 导入 App 组件,作为首页展示
import App from './App.tsx';
// 导入 Flag 组件,用于 /flag 路径的页面展示
import Flag from './Flag.tsx';// 导入全局样式文件
import './index.css';/*** 使用 createRoot 函数创建一个 React 根节点,挂载到 id 为 'root' 的 DOM 元素上* 并渲染 React 应用程序*/
createRoot(document.getElementById('root')!).render(// 使用 StrictMode 组件包裹应用,在开发模式下检查潜在问题<StrictMode>{/* 使用 BrowserRouter 组件为应用提供路由功能 */}<BrowserRouter>{/* 使用 Routes 组件来定义一组路由规则 */}<Routes>{/* 定义首页路由,当路径为根路径时,渲染 App 组件 */}<Route index element={<App />} />{/* 定义 /flag 路径的路由,当路径为 /flag 时,渲染 Flag 组件 */}<Route path="/flag" element={<Flag />} /></Routes></BrowserRouter></StrictMode>
);

看看flag

export default function Flag() {return (<section className="text-center pt-24"><div className="flex items-center text-5xl font-bold justify-center">{'bctf{test_flag}'}</div></section>)
}

访问 /flag 返回 404 , 根据题目,我不可能修改服务器端代码,接下来我怎么访问 /flag?

The site configured at this address does not contain the requested file.If this is your site, make sure that the filename case matches the URL as well as any file permissions.  
For root URLs (like `http://example.com/`) you must provide an `index.html` file.[Read the full documentation](https://help.github.com/pages/) for more information about using **GitHub Pages**.
import Header from './Header.tsx';
import AdCard from './AdCard.tsx';
import Footer from './Footer.tsx';function App() {const sponsors = ['microsoft.svg', 'google.svg', 'amazon.svg', 'netflix.svg', 'meta.svg', 'apple.svg'];return (<><Header /><section className="text-center pt-24"><h1 className="text-7xl mb-4 font-bold">Quantum b01lerchain</h1><p>Quantum-computing based blockchain technology at scale, automatically secured by cutting-edgeAI threat-assessment models.</p></section><section className="pt-14 pb-2 mb-20"><div className="w-full mx-auto -z-10 bg-gradient-to-r from-yellow-500 via-pink-400 to-red-500 transform -skew-y-3 flex flex-row"><div className="transform skew-y-3 mx-auto -my-4 flex flex-row space-x-12"><AdCardtitle="Quantum powered"src="/0f5146d5ed9441853c3f2821745a4173.jpg">Leveraging distributed quantum compute power, b01lerchain technology achieves energyefficiency where other blockchains fail.</AdCard><AdCardtitle="Blockchain at scale"src="/0bee89b07a248e27c83fc3d5951213c1.jpg">All b01lerchain transactions are backed up across 10 different blockchains,ensuring data security.</AdCard><AdCardtitle="AI++"src="/5ab557c937e38f15291c04b7e99544ad.jpg">Leveraging scalable quantum compute power, b01lerchain technology achieves energy efficiencywhere other blockchains fail.</AdCard></div></div></section><section className="mb-8"><p className="text-sm text-center text-secondary mb-3">Proudly powered by</p><div className="flex gap-x-10 gap-y-2 items-center flex-wrap justify-center px-6">{sponsors.map((l) => (<imgsrc={l}className="h-12"key={l}/>))}</div></section><h3 className="font-bold text-xl text-center mb-8">Join 1,200+ investors sharing in b01lerchain's vision.</h3><section><p className="max-w-5xl px-8 mx-auto mb-8">View our demo below:</p><imgsrc="/483032a6422b3ba7005dfa12dda874b5.jpg"className="w-full h-[30rem] object-cover object-center opacity-50"/></section><Footer /></>)
}
'use client'import { useScroll } from '../hooks/useScroll';export default function Header() {const scroll = useScroll();return (<header className={`sticky top-0 z-50 ${scroll > 0 ? 'bg-midnight/90 shadow-md backdrop-blur-sm' : 'bg-midnight hover:bg-midnight/90 hover:shadow-md hover:backdrop-blur-sm'} transition-shadow duration-300 ease-in-out`}><nav className="px-8 py-4 flex gap-4 items-center"><a href="/" className="flex items-center gap-2"><imgsrc="/icon.svg"alt="b01lerchain logo"className="size-6"/><h3 className="font-semibold">b01lerchain</h3></a><a href="/#" className="ml-auto text-inherit hover:no-underline">About</a><a href="/#" className="text-inherit hover:no-underline">FAQ</a><a href="/flag" className="text-inherit hover:no-underline">Flag</a></nav></header>)
}

查一手漏洞

Report Summary┌───────────────────┬──────┬─────────────────┬─────────┐
│      Target       │ Type │ Vulnerabilities │ Secrets │
├───────────────────┼──────┼─────────────────┼─────────┤
│ package-lock.json │ npm  │        1        │    -    │
└───────────────────┴──────┴─────────────────┴─────────┘
Legend:
- '-': Not scanned
- '0': Clean (no security findings detected)package-lock.json (npm)Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)┌─────────┬────────────────┬──────────┬────────┬───────────────────┬──────────────────────────────────────┬───────────────────────────────────────────────────────────┐
│ Library │ Vulnerability  │ Severity │ Status │ Installed Version │            Fixed Version             │                           Title                           │
├─────────┼────────────────┼──────────┼────────┼───────────────────┼──────────────────────────────────────┼───────────────────────────────────────────────────────────┤
│ vite    │ CVE-2025-32395 │ MEDIUM   │ fixed  │ 6.2.5             │ 6.2.6, 6.1.5, 6.0.15, 5.4.18, 4.5.13 │ vite: Vite has an `server.fs.deny` bypass with an invalid │
│         │                │          │        │                   │                                      │ `request-target`                                          │
│         │                │          │        │                   │                                      │ https://avd.aquasec.com/nvd/cve-2025-32395                │                                                                                                             
└─────────┴────────────────┴──────────┴────────┴───────────────────┴──────────────────────────────────────┴───────────────────────────────────────────────────────────┘

复现与修复指南:Vite再次bypass(CVE-2025-32395)

但是服务器没有 /@fs

放弃 ------------------------------------------------------------------------------------------------------------

赛后

1. SPA 是什么?
  • 定义
    SPA(单页应用)是一种通过动态重写当前页面内容(而非加载新页面)实现交互的 Web 应用。所有逻辑(路由、数据获取、渲染)均在浏览器中运行,只需加载一次 index.html,后续通过 JavaScript 与 API 交互更新内容。

  • 核心特点

    • 无整页刷新:页面切换时仅局部更新内容,体验更流畅。
    • 前端路由:通过 react-routerVue Router 等库管理 URL 路径与组件的映射。
    • 前后端分离:后端仅提供 API 接口,前端独立处理业务逻辑与渲染。
  • 技术依赖
    依赖现代前端框架(React、Vue、Angular)及工具链(Webpack、Vite)。

2. SPA 的工作原理
  1. 首次加载
    • 用户访问网站时,服务器返回 index.html 和打包后的 JS/CSS 文件。
    • 浏览器解析并执行 JS,渲染初始页面(如登录页或主页)。
  2. 后续交互
    • 用户点击链接或按钮时,前端路由库拦截请求,根据 URL 匹配对应组件。
    • 前端通过 API 异步获取数据,动态更新 DOM(无需整页刷新)。
  3. URL 管理
    • 使用 history.pushState()window.location.hash 修改 URL,避免浏览器向服务器发送请求。

我们可以使用,有效负载欺骗前端js渲染隐藏路由

以下代码实现了 修改 URL + 触发路由更新 的核心逻辑:

history.pushState(null, '', '/flag');                  // Step 1: 修改 URL
window.dispatchEvent(new PopStateEvent('popstate'));   // Step 2: 触发事件
Step 1: history.pushState 的作用
  • 底层行为
    调用浏览器 History API 的 pushState 方法,向浏览器的 会话历史栈(Session History) 中添加一条新记录。

  • 关键细节

    1. 修改 URL 但不刷新页面:仅更新地址栏显示,不触发 HTTP 请求(对比 window.location.href = '/flag' 会触发页面跳转)。
    2. 关联状态数据:第一个参数 state 允许存储任意 JSON 序列化对象(如 { page: 'flag', auth: true }),绑定到新历史记录条目。
    3. 同源策略限制:新 URL 必须与当前页面同源(Same Origin),否则抛出安全错误。
  • 数据结构示例

    history.pushState({ timestamp: Date.now(), user: 'guest' }, // 有效负载(状态数据)'',                                       // 标题(忽略)'/flag'                                   // 新 URL
    );
    
Step 2: PopStateEvent 的触发机制
  • 事件本质
    popstate 是浏览器原生事件,通常在 用户点击后退/前进按钮 或调用 history.back()/history.go() 时触发。

  • 手动触发的意义
    通过 dispatchEvent 主动派发 popstate 事件,模拟浏览器历史导航行为,欺骗前端路由库(如 React Router)执行路由更新逻辑。

  • 事件对象细节

    new PopStateEvent('popstate', {state: history.state,  // 必须与当前历史条目的 state 一致bubbles: true,         // 事件是否冒泡(默认 false)cancelable: true       // 事件是否可取消(默认 false)
    });
    
    • state 字段的强制一致性
      若手动传递的 statehistory.state 不一致,React Router 等库可能忽略此次事件(视为非法状态变更)。

相关文章:

  • 【现代深度学习技术】现代循环神经网络04:双向循环神经网络
  • 【AI论文】DeepCritic:使用大型语言模型进行有意识的批判
  • 【深度学习的灵魂】图片布局生成模型LayoutPrompt(2)·布局序列化模块
  • Linux电源管理(5)_Hibernate和Sleep功能介绍
  • Centos9 安装 RocketMQ5
  • Windows 中使用dockers创建指定java web 为镜像和运行容器
  • 深度学习系统学习系列【2】之人工神经网络(ANN)
  • 长江学者答辩ppt美化_特聘教授_校企联聘学者_青年长江学者PPT案例模板
  • 设计模式简述(十七)备忘录模式
  • 使用线性表实现通讯录管理
  • AtCoder Beginner Contest 404(ABCDE)
  • C++八股--5--设计模式--适配器模式,代理模式,观察者模式
  • Maven安装配置以及Idea中的配置教程
  • ElasticSearch深入解析(十):字段膨胀(Mapping 爆炸)问题的解决思路
  • Servlet(二)
  • 安卓基础(悬浮窗和摄像)
  • 大数据引领行业革命:深度解析与未来趋势
  • 【网络原理】深入理解HTTPS协议
  • 智能家居的OneNet云平台
  • 接口测试的核心思维(基础篇)
  • 李云泽:对受关税影响较大、经营暂时困难的市场主体,一企一策提供精准服务
  • A股三大股指集体高开大涨超1%,券商、房地产涨幅居前
  • 欧盟公布终止进口俄能源计划,2027年为最后期限
  • 城事|五一长假,哪里人最多?
  • 涉“子宫肌瘤”论文现55例男性对照观察患者?山大齐鲁医院:正在调查
  • 经济日报:以人工智能激活产业新增长