B01lersCTF - Trouble at the SPA (Web)
Overview
This whitebox challenge is running on a Vite/React server as a SPA (as the title of challenge suggests).
Reviewing the code
After taking a look at the code, we notice that the flag is located inside a JSX/TSX component called Flag()
but it’s not directly exposed on the GitHub Pages instance, this is a common misconfiguration mistake. It happens because web servers like Apache and Nginx don’t handle routing the way React Router does (you can read more here).
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { BrowserRouter, Routes, Route } from 'react-router';
// Pages
import App from './App.tsx';
import Flag from './Flag.tsx';
import './index.css';
createRoot(document.getElementById('root')!).render(
<StrictMode>
<BrowserRouter>
<Routes>
<Route index element={<App />} />
<Route path="/flag" element={<Flag />} />
</Routes>
</BrowserRouter>
</StrictMode>
);
We can see that the Flag
component has been imported and used inside a <Route>
, which means that Webpack included it in the bundle when the developer was deploying it to GitHub Pages.
<BrowserRouter>
tells us that the Router is listening to the browser’s history. So we can manually navigate to /flag
like this:
window.history.pushState({}, '', '/flag');
window.dispatchEvent(new PopStateEvent('popstate'));
This will, update the URL to /flag
, and then trigger React Router to re-render the virtual DOM by dispatching an event.
You can read more about BrowserRouter here
Epilogue
Thanks for reading! Hope you had fun with this challenge