#DVWA Stored XSS
#DVWA
#Damn Vulnerable Web Application
#웹해킹 실습
#실습설명서
#inspect element
#HTML 삽입
#HTML Injection
#크로스사이트스크립트
#Cross-site Script
#자바스크립트 삽입
#저장형 XSS
#iframe 삽입
#홈페이지 위변조
#website defacement
#해킹 시나리오
#A3-Cross-Site Scripting (XSS)
DVWA: Stored XSS (low, medium, high level) 공략
DVWA(Damn Vulnerable Web Application) 1.9 훈련장 라이브 ISO는 다음에서 다운로드 받을 수 있다.
DVWA 1.9 훈련장 라이브 ISO를 구동하는 방법은 다음 문서에서 볼 수 있다.
여기서는 구동 후 DVWA 훈련장의 주소가 http://192.168.189.246/ 이었다.
DVWA 누리집의 로그인 정보는 admin/password 이다.
실습을 진행하기 전에 다음 두 가지 작업을 사전에 수행하야야 한다.
- "
Setup / Reset DB " 항목에서 "Create / Reset Database "를 실행한다.
- "
DVWA Security " 항목에서 "Security Level "을
시험하고자 하는 보안수준에 따라
Low , Medium , High 로 변경한다.
Vulnerability: Stored Cross Site Scripting (XSS) 실습문제는 방명록(Guestbook)이다.
사용자가 이름(Name )과 전갈(Message )을 남길 때 HTML 검증이 이루어지지 않으면
발생하는 저장형 크로스사이트스크립트 취약점을 다룬다.
댓글 기능이나 질의응답(Q&A)과 같은 일반회원을 대상으로 하는 게시판에서도 동일한 문제가 발생할 수 있다.
Vulnerability: 저장형 XSS (low level) 실습 설명
Vulnerability: Stored Cross Site Scripting (XSS) low level에서는 사용자의 입력인
txtName 과 mtxMessage 변수를 그대로 출력한다.
PHP 소스코드를 살펴보자.
// Get input
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Sanitize message input
$message = stripslashes( $message );
$message = mysql_real_escape_string( $message );
// Sanitize name input
$name = mysql_real_escape_string( $name );
// Update database
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
위에서 사용한
stripslashes() 함수 와
mysql_real_escape_string() 함수 는
작은따옴표, 큰따옴표, 줄바꾸기 등의 특수문자를 데이터로 처리하기 위한 기능이다.
HTML에 대한 처리 기능이 거의 없다.
 [ ↑ DVWA 저장형 XSS (low level): 입력란에서 inspect element 선택 ]
DVWA 저정향 XSS의 방명록 입력에는 제한이 있다.
Name 변수의 최대 문자열 길이는 10이다.
<input> 엘리먼트의 maxlength 속성을 이용하여 입력 길이을 제한한다.
Name * <input name="txtName" type="text" size="30" maxlength="10">
이렇게 HTML을 이용하여 입력을 제한하는 방법은 HTML을 수정하여 풀 수 있다.
가장 간단한 방법은 Firefox 웹브라우저의 inspect element 기능을 이용하는 것이다.
위의 그림처럼 해당 HTML에서 오른 쪽 마우스 단추를 누르면 편리하게 inspect element 를 접근할 수 있다
(Firebug도 inspect element with Firebug 에서 HTML을 편집할 수 있는 기능을 제공한다).
 [ ↑ DVWA 저장형 XSS (low level): inspect element 실행 화면, maxlength = "100" ]
위와 같이 <input> 엘리먼트에서 maxlength = "100" 으로 변경하여 입력제한을 풀 수 있다.
 [ ↑ DVWA 저장형 XSS (low level): 길이 제한을 해제한 입력 ]
Name 의 입력값은 <img src=x onerror=alert(document.cookie)> Hi~~ 이다.
자바스크립트가 실행되면 document.cookie 값을 경고창으로 띄운다.
Message 의 입력값은 <svg onload=alert('SVG_image')> Bye~~ 이다.
ECMAscript가 실행되면 - JavaScript와 거의 동일 - SVG_image 라는 문자열을 경고창으로 띄운다.
경고창이 뜨면 XSS 취약점이 존재한다는 뜻이다.
 [ ↑ DVWA 저장형 XSS (low level): docment.cookie 출력 ]
document.cookie 값이 경고창에 나타난다.
txtName 변수에 자바스크립트를 입력할 수 있는 XSS 취약점이 존재한다.
 [ ↑ DVWA 저장형 XSS (low level): SVG의 alert() 창 ]
SVG_image 라는 문자열이 경고창에 나타난다.
mtxMessage 변수에 자바스크립트를 입력할 수 있는 XSS 취약점이 존재한다.
이제부터 Vulnerability: Stored Cross Site Scripting (XSS) 훈련장에 접속하면 항상 두 경고창을 만나게 된다.
서버(실제로는 MySQL 데이터베이스)에 사용자의 공격 스크립트가 저장된 것이다.
이렇게 공격 결과가 서버에 남게 되는 HTML 삽입 공격을 "저장형 XSS"라고 한다.
[ 공격 시나리오: 홈페이지 위변조 ]
저장형 XSS가 가능하면 다양한 공격이 가능하다.
접속하는 모든 사용자의 세션을 탈취할 수도 있다.
Vulnerability: Stored Cross Site Scripting (XSS) 실습문제는 관리자만 접속할 수 있으므로
document.cookie 를 유출할 수 있으면 관리자 권한을 탈취하게 된다.
document.cookie 를 다른 웹 브라우저에서 삽입해보면 알 수 있다.
여기서는 홈페이지 위변조 공격을 시도해 보자.
실제 침해사고 사례는 저장형 XSS를 이용한 홈페이지 위변조 사례 문서에서 볼 수 있다.
 [ ↑ DVWA 저장형 XSS (low level): 홈페이지 위변조용 HTML 삽입 ]
파이어폭스의 inspect element 기능을 이용하여 mtxMessage 변수의 최대 입력 길이를
50에서 500으로 변경한다.
mtxMessage 변수의 입력은
<body topmargin=0 leftmargin=0 onload="document.body.innerHTML='<iframe width=100% height=800 src=http://www.daum.net/></iframe>';"> 이다.
공격자는 전갈에 이러한 HTML을 삽입한다.
피해자가 웹 브라우저로 방명록 페이지에 접근한다.
이때 <body> 가 onload 되면 자바스크립트는
<body> 엘리먼트의 내용(document.body.innerHTML )을
<iframe> 으로 바꿔치기한다.
 [ ↑ DVWA 저장형 XSS (low level): 홈페이지 위변조 결과 ]
그 결과는 위의 그림과 같다.
URL은 Vulnerability: Stored Cross Site Scripting (XSS)
실습문제(http://192.168.189.246/vulnerabilities/xss_s/ )이지만 피해자가 보는 내용은
다음 홈페이지(http://www.daum.net )이다.
홈페이지 위변조된 것이다.
원래 누리집 기능에 접근할 수 없으므로 서비스거부(Denial of Service) 상태에 빠지게 된다.
Vulnerability: 저장형 XSS (medium level) 실습 설명
Medium level의 PHP 소스 코드를 살펴보자.
// Get input
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Sanitize message input
$message = strip_tags( addslashes( $message ) );
$message = mysql_real_escape_string( $message );
$message = htmlspecialchars( $message );
// Sanitize name input
$name = str_replace( '<script>', '', $name );
$name = mysql_real_escape_string( $name );
// Update database
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
mtxMessage 입력에 대해서는
strip_tags() 함수(HTML 제거)와 htmlspecialchars() 함수(특수문자 변환)를 적용하고 있다.
따라서 mtxMessage 변수에는 HTML을 삽입할 수 있는 방법이 제거된다.
txtName 입력에서는 str_replace() 함수를 이용하여
"<script> " 문자열을 제거한다.
이 때 대소문자를 구분한다.
이 방어법은 "<SCRIPT> "와 같은 문자열은 걸러내지 못한다.
HTML 문법은 대소문자를 구분하지 않으므로
<SCRIPT> 는 <script> 와 동일하다.
즉 이 방법은 우회가 가능하다.
 [ ↑ DVWA 저장형 XSS (medium level): HTML 삽입 시도 ]
Low level에서와 동일한 문자열을 입력해보자.
이 때 Firefox의 inspect element 기능을 사용하면 최대 입력 길이를 늘일 수 있다.
입력값은 다음과 같다.
txtName 입력: <img src=x onerror=alert(document.cookie)> Hi~~
mtxMessage 입력: <svg onload=alert('SVG_image')> Bye~~
Name 입력에 취약점이 있으면 쿠키를 확인하는 경고창이, Message 입력에 취약점이 있으면 'SVG_image' 경고창이 뜰 것이다.
 [ ↑ DVWA 저장형 XSS (medium level): HTML 삽입 결과 ]
방명록의 결과를 보면 위와 같이 쿠키 값이 alert() 창으로 뜨고 'SVG_image' 경고창은 나타나지 않는다.
즉 txtName 변수에는 XSS 취약점이 있고, mtxMessage 변수에는 취약점이 없다.
해당 출력부의 HTML 소스를 살펴보면 다음과 같다.
<div id="guestbook_comments">Name: <img src="x" onerror="alert(document.cookie)"> Hi~~ <br>Message: Bye~~ <br></div>
Name 입력에서는 HTML이 그대로 출력되고 Message 입력에서는 HTML이 완전히 제거된 것을 볼 수 있다.
Vulnerability: 저장형 XSS (high level) 실습 설명
High level에서의 HTML 삽입 방어기작을 살펴보자. 관련 PHP 소스는 다음과 같다.
// Get input
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Sanitize message input
$message = strip_tags( addslashes( $message ) );
$message = mysql_real_escape_string( $message );
$message = htmlspecialchars( $message );
// Sanitize name input
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name );
$name = mysql_real_escape_string( $name );
// Update database
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
방어기작은 medium level과 거의 동일하다.
다만 Name 입력에 대해서는 preg_relace() 함수를 이용하여
대소문자를 구분하지 않고 "<*s*c*r*i*p*t "를 제거하고 있다.
"</script ",
"<sc\ript ",
"<SCRIPT ",
"<Script ",
"<sCRIPT " 등의 다양한 우회방법을 방어할 수 있다.
하지만 자바스크립트를 삽입할 수 있는 엘리먼트는 매우 다양하므로 쉽게 우회가 가능한 방어기작이다.
Medium level과 동일하게 시험해보면 결과도 동일하다.
증빙화면은 생략하였다.
<div id="guestbook_comments">Name: <img src="x" onerror="alert(document.cookie)"> Hi~~ <br>Message: Bye~~ <br></div>
서버가 응답하는 HTML 소스도 medium level과 동일하다.
Vulnerability: 저장형 XSS (impossible level) 실습 설명
이제 HTML삽입이 불가능한 impossible level의 PHP 소스코드를 살펴보자.
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Get input
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Sanitize message input
$message = stripslashes( $message );
$message = mysql_real_escape_string( $message );
$message = htmlspecialchars( $message );
// Sanitize name input
$name = stripslashes( $name );
$name = mysql_real_escape_string( $name );
$name = htmlspecialchars( $name );
// Update database
$data = $db->prepare( 'INSERT INTO guestbook ( comment, name ) VALUES ( :message, :name );' );
Name 입력과 Message 입력 모두에 대해서
htmlspecialchars()
함수를 적용하고 있다.
이 함수는 입력에서 특수문자를 변환('<' -> '<',
'>' -> '>',
'&' -> '&',
'"' -> '"' )한다.
사용자 입력에서 HTML 삽입을 거의 원천적으로 차단하게 된다.
 [ ↑ DVWA 저장형 XSS (impossible level): HTML 삽입 결과 ]
Medium level에서와 동일한 시험을 하면 결과는 위와 같다.
부등호, 앰퍼샌드 등이 모두 변환되면서 HTML 삽입이 차단되는 것을 볼 수 있다.
서버가 응답하는 HTML 소스는 다음과 같다.
<div id="guestbook_comments">Name: &lt;img src=x onerror=alert(document.cookie)&gt; Hi~~ <br>Message: &lt;svg onload=alert(\'SVG_image\')&gt; Bye~~ <br>lt;/div>
서버의 DB에 저장될 때 htmlspecialchars() 가 한번 적용되었다.
그리고 다시 HTML에 출력할 때 다시 한번 htmlspecialchars() 가 적용되어 위와 같은 HTML 코드가 만들어졌다.
결과적으로 공격자가 의도한 HTML 삽입은 모두 차단되었다.
마무리
거의 모든 웹취약점이 그렇듯이 "HTML 삽입을 통한 자바스크립트 공격"(Cross-site Scripting)은 서버가 입력값을
제대로 검증하지 않을 때 발생한다.
특히 저장형 XSS의 경우에는 불특정 다수를 대상으로 하는 지속적인 공격뿐만 아니라
특정 소수 대상의 표적 공격이 가능하고, 반사형 XSS에 비해서 다양한 방법의 공격을 동원할 수 있으므로 매우 위험하다.
PHP의 경우에는 서버가 HTML에서 출력하는 모든 입력에 대해서
htmlspecialchars() 함수나
htmlentities() 함수를
적용하면 거의 모든 HTML 삽입 공격을 차단할 수 있다.
[처음 작성한 날: 2017.01.01]
[마지막으로 고친 날: 2017.01.01]
< 이전 글 : DVWA Reflected Cross Site Scripting (XSS) 실습 설명서 (2016.12.27)
> 다음 글 : SVG 이미지의 ECMAscript를 이용한 악성코드 배포 (2016.12.01)
이 저작물은 크리에이티브
커먼즈 저작자표시 4.0 국제 라이선스에 따라 이용할 수 있습니다.
잘못된 내용, 오탈자 및 기타 문의사항은 j1n5uk{at}daum.net으로 연락주시기 바랍니다.
.. -- -- | - .. .... | ... / .. .../ ... {] . .. .. .. ..| ...... .../ .../ ..
...... ... ... ] .. [ .../ ..../ ......./ ..
./// ../ ... .. ...
.. -- -- | - .. .... | ... / .. .../ ... {] . .. .. .. ..| ...... .../ .../ .. ./// ../ ... .. ...
...| ..../ ./ ... / ..| ....| ........ / ... / ....
...... ... ... ] .. [ .../ ..../ ......./ .....| ..../ ./ ... / ..| ....| ........ / ... / ....
...| ..../ ./ ... / ..| ....| ........ / ... / ....
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|