DVWA(medium) - DOM XSS, Reflected XSS, Stored XSS
1. XSS(DOM)
로그인한 사용자의 쿠키를 훔친다.
low때는 <script>alert("1")</script>만을 사용했었다. 그러나 medium에서는 실행되지 않았다.
<?php
// Is there any input?
if ( array_key_exists( "default", $_GET ) && !is_null ($_GET[ 'default' ]) ) {
$default = $_GET['default'];
# Do not allow script tags
if (stripos ($default, "<script") !== false) {
header ("location: ?default=English");
exit;
}
}
소스코드를 확인해보니 "<script"를 대소문자에 상관없이 확인된다면 default=English로 이동하도록 하는 것을 확인할 수 있었다.
그러나
http://localhost/DVWA-master/vulnerabilities/xss_d/?default=#%3Cscript%3Ealert(1)%3C/script%3E
위와 같이 뒷부분을 #으로 주석처리한다면 실행이 되는 것을 알 수 있다. 이러한 이유는 서버에는 정상적인 html문서를 요청하고 서버에서도 정상적인 html문서를 응답하지만 #은 브라우저가 리로딩 없이 자바스크립트를 불러올 수 있기 때문에 #뒤에 스크립트문은 서버에 전송이 되지 않는다. 따라서 #뒤에 스크립트문이 실행됨을 알 수 있다. 그러면 이제 쿠키값을 받아보겠다.
localhost/DVWA-master/vulnerabilities/xss_d/?default=#<script>alert(document.cookie)</script>
쿠키값을 확인할 수 있었다.
2. XSS(Reflected)
로그인 된 사용자의 쿠키를 훔쳐라.
low때와 차이점을 알아보자. 소스코드를 먼저 보면
<?php
header ("X-XSS-Protection: 0");
// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Get input
$name = str_replace( '<script>', '', $_GET[ 'name' ] );
// Feedback for end user
echo "<pre>Hello ${name}</pre>";
}
?>
<script>를 ' ' (공백)으로 대체하는 것을 알 수 있었다.
File Inclusion때 ../를 ....//로 우회했던 것처럼 진행해보겠다. 아래 코드를 넣고 Submit했다.
<scr<script>ipt>alert(document.cookie)</script>
쿠키값을 획득한 것을 확인할 수 있다.
3. XSS (Stored)
내가 선택한 웹 페이지로부터 리다이렉팅을 해라.
low때와 차이점을 알아보기 위해서 low때 했던 방법을 그대로 해봤다.
<script>와 </script>가 필터링되어 공백으로 처리된 것을 볼 수 있다.
그래서 소스코드를 확인해보았다.
<?php
if( isset( $_POST[ 'btnSign' ] ) ) {
// Get input
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Sanitize message input
$message = strip_tags( addslashes( $message ) );
$message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$message = htmlspecialchars( $message );
// Sanitize name input
$name = str_replace( '<script>', '', $name );
$name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// Update database
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
//mysql_close();
}
?>
message부분에서 htmlspecialchars라는 처음보는 함수가 있어서 알아봤더니 문자열에서 특정한 특수 문자를 HTML엔티티로 변환하여 XSS공격을 방지하는 함수였다. 그래서 message부분에 <script>와 </script>부분이 필터링 됨을 알았다.
또한 name에서는 <script>를 ' '으로 필터링 함을 알 수 있었다. 그렇다면 name부분에 <script>대신 <scr<script>ipt>를 넣으면 되겠다 생각이 들어 바로 실행해봤다.
<scr<script>ipt>alert(document.cookie)</script>
위 코드를 name에 넣으려했는데 왜인지 글자수 제한이 없는데 <scr<scrip에서 더이상 써지지 않길래 버프슈트를 이용했다.
그결과 쿠키값을 획득할 수 있었다.