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