코드 분석
더보기
main.tsx
React 앱이 시작되는 부분이다. /flag 경로에서 FLAG를 보여주도록 라우터가 설정되어 있다.
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>
);
Flag.tsx
조건 없이 무조건 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>
)
}
Exploit
루트 경로로 접속했을 때는 index.html이 존재하기 때문에 서버가 이를 정상적으로 응답해주지만, /flag 경로로 직접 요청하면 서버는 /flag.html 또는 /flag라는 실제 파일이 있는지 먼저 확인하게 된다. 그러나 해당 파일이 존재하지 않기 때문에 서버는 404 Not Found를 반환한다.
반면, React는 SPA(Single Page Application)로 서버에서 리소스를 전달받아 렌더링하는 것이 아니라 클라이언트 사이드(JavaScript)에서 코드를 실행하여 페이지를 전환하는 구조다. 이미 React 앱이 실행 중인 상태에서는 history.pushState로 주소만 변경해도 서버 요청 없이 경로를 바꿀 수 있지만, React Router는 popstate 이벤트가 발생해야만 경로가 바뀐 것을 감지하고 페이지를 다시 렌더링한다.
따라서, 새로고침 없이 경로만 바꾸고 React Router가 이를 제대로 감지하게 하려면 pushState로 주소로 바꾼 뒤 popstate 이벤트를 강제로 발생시켜야한다. 결과적으로 브라우저 콘솔에 아래 코드를 입력하면 React Router가 경로 변경을 인식하고 <Flag /> 페이지를 정상적으로 렌더링할 수 있다.
window.history.pushState({}, '', '/flag');
window.dispatchEvent(new PopStateEvent('popstate'));
'CTF Write Up > b01lers CTF' 카테고리의 다른 글
link-shortener (0) | 2025.04.25 |
---|---|
defense-in-depth (0) | 2025.04.24 |
Atom Bomb (0) | 2025.04.24 |
when (0) | 2025.04.22 |