반응형
문제설명
Topic: XSS
분야: Web
난이도: Medium
Run alert(flag) to win!
코드분석
if(type === "alert" && message === FLAG) {
successful = true;
}
await dialog.accept();
});
- visit 함수 일부분
- alert의 메시지가 FLAG와 같으면 성공
app.get("/", async (req, res) => {
const flag = req.cookies.flag ?? "fake_flag";
const username = req.query.username ?? "guest";
let result;
if(username.includes("flag") || username.includes("alert")) {
result = "<p>invalid input</p>";
} else {
result = `<h1>Hello ${username}!</h1>`
}
const html = `<!DOCTYPE html>
<html>
<head>
<script>const flag="${flag}";</script>
</head>
<body>
${result}
<p>Try <a href="/?username=<i>admin</i>">this page?</a>
<p>Was "alert(flag)" successful? <form action="/report" method="POST"><input hidden id="username" name="username"><button>Submit this page!</button></form></p>
<script>
document.getElementById("username").value = new URLSearchParams(location.search).get("username")</script>
</body>
</html>`;
return res.send(html);
});
- 쿠키에서 flag값 읽고 없으면 fake_flag 사용
- URL 쿼리 username을 읽고 없으면 guest
- "flag"랑 "alert" 문자열만 필터
- <h1> Hello ${username}! <h1>에서 username을 그대로 삽입함
- flag를 <script>const flag"${flag}"</script>로 노출
- result를 body에 삽입
- /report로 보내는 form이 있고 hidden input username 있음
/?username= ??? 로 넣은 값이 페이지에 반영되고, 그 값이 report POST에도 전달되도록 연결된 구조
app.post("/report", async (req, res) => {
const { username } = req.body;
if (typeof username !== "string") {
return res.status(400).send("Invalid username");
}
const url = `${APP_URL}?username=${encodeURIComponent(username)}`;
try {
const result = await visit(url);
return res.send(result ? FLAG : "Failed...");
} catch (e) {
console.error(e);
return res.status(500).send("Something wrong");
}
});
- username를 폼 body에서 꺼냄
- username이 문자열이 아니면 400 에러 메시지
- 입력값을 URL 인코딩해서 내부 봇이 방문할 URL 생성
- 봇이 url 다녀오면서 alert() 메시지가 FLAG와 정확히 같으면 true
- 성공 시 FLAG, 실패 시 Failed 반환
취약점 분석
- username이 HTML 그대로 삽입됨
<h1>Hello ${username}</h1>
- flag, alert만 문자열 검사함
if(username.includes("flag") || username.includes("alert"))
- flag 재노출
<script>const flag="${flag}";</script>
익스플로잇
먼저 alert 문자열은 우회를 위해 ['al'+'ert'] 와 같이 쪼개서 필터에 걸리지 않게 함
alert => ['al'+'ert']
Httponly = true로 설정이 걸려있어 document.cookie로 쿠키를 못 읽지만 HTML에 노출된 스크립트 내용을 통해 FLAG를 획득할 수 있다.
페이지를 살펴보자.

- this page 버튼 클릭 시 /?username=<i> admin </i>로 기울림이 적용된 것을 확인
- 그렇다면 <h1> Hello </h1> <i> admin </i> <h1> ! </h1> 과 같이 HTML이 적용되는 것을 확인
- 따라서 <i>admin</i> 자리에 스크립트를 삽입
따라서 총 페이로드를
</h1><script>this['al'+'ert'](\u0066lag)</script><h1>
또한 burpsuite에서 /report 엔드포인트를 확인해 보니

body에 url 인코딩을 한 상태로 전송하는 것을 확인할 수 있음
따라서 페이로드를 인코딩해주면
%3C%2Fh1%3E%3Cscript%3Ethis%5B%27al%27%2B%27ert%27%5D%28%5Cu0066lag%29%3C%2Fscript%3E%3Ch1%3E
플래그 획득

반응형
'Alpacahack' 카테고리의 다른 글
| Another Login Challenge (0) | 2026.03.15 |
|---|---|
| Rock Paper Scissors Lizard Spock (0) | 2026.03.03 |
| Alpaca Rangers (0) | 2026.03.03 |
| omikuji (0) | 2026.02.23 |
| Emojify (0) | 2026.02.20 |