什么是XSS
打靶场之前简单介绍下XSS,定义我就不说了,按我个人的理解就是,它其实就是js注入或者更准确的说是脚本代码注入,通常是js(可能比较孤陋,目前也没见谁注入别的代码)。比如给你一个文本框让你提交数据,然后服务器会读取数据并显示在客户端(浏览器)。但如果此时此刻你提交了一段如<script>alert(/你被挂马了!/)</script>这样的“文本”呢,如果代码中根本没有任何的输入数据过滤措施,这段数据就会被当程代码执行,这就是为啥我说XSS其实就是代码注入而已。SQL注入不也是在某个地方写入一些不合法的数据然后交给服务器执行。
XSS一共有三种,先来说下反射型XSS:
反射,顾名思义就是某件事情你干不了但是你可以想办法把要干的事情告诉别人,让别人给你干了并把结果反馈给你。带入到实战中就是:我想对服务器做一下不好的事情,但是我控制不了服务器,然而呢,我可以把提交一段代码给服务器,服务器会自己执行这段代码,然后反馈到浏览器,如此一来我就可以得到我想要的结果。
好,开始打靶场!
low
可能很多教程上来就给分析源码了,我倒觉得可以自己先提交一些数据做一些常规的测试,最后不行再去看看源码。这里我先提交<script>alert(/你被挂马了!/)</script>,果不其然有结果,毕竟是low级别。注意这里我还把url给截下来了一部分,可以发现它用的是GET方法。
源码分析
···
<?
header("X-XSS-Protection: 0");
// Is there any input? 就是判断GET有没有name键,且输入的文本不为空
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Feedback for end user 将输入结果输出 没有意思的过滤
echo '<pre>Hello ' . $_GET[ 'name' ] . '</pre>';
}
?>
···
medium
这个的payload是"><img src=1 onerror=alert(/xss) /> 我用的是这个,它的意思是先把前面的<input>标签闭掉,然后加载一个图片,显然这里加载不出来,因为我写了个src=1 当加载出错,就会执行onerror的代码。它使用的是黑名单机制,所以是可以绕过的。比如<SCRIPT>alert(666)</SCRIPT> 这就是大写绕过 除此之外还有很多的绕过方式。
源码分析
···
<?php
header("X-XSS-Protection: 0");
// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Get input 把<script>替换为空
$name = str_replace( '<script>', '', $_GET[ 'name' ] );
// Feedback for end user
echo "<pre>Hello ${name}</pre>";
}
?>
···
high
payload同样是"><img src=1 onerror=alert(/xss) />
源码分析
<?php
header
("X-XSS-Protection: 0");
// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Get input preg_replace() 函数将包含<script>的字符,不管大小写,不管后面跟着1个或多个与之相同的字符都转换为空。用于正则表达式的搜索和替换,这使得双写绕过、大小写混淆绕过(正则表达式中表示不区分大小写)不再有效。
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] );
// Feedback for end user
echo "<pre>Hello ${name}</pre>";
}
?>
impossible
Impossible级别的代码使用htmlspecialchars函数把预定义的字符&、”、 ’、<、>转换为HTML实体,防止浏览器将其作为HTML元素。
源码分析
<?php
// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Check Anti-CSRF token 还加上了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();
?>
接着是DOM XSS
DOM XSS与反射性XSS、存储型XSS的主要区别在于DOM XSS的XSS代码不需要服务端解析响应的直接参与,触发XSS的是浏览器端的DOM解析。如果不懂前面这句话,就只需要记住这样一句话:“DOM XSS就是通过注入代码来对当前网页代码直接进行修改。” 就好比我直接在网页源码里加了一行<script>alert('XSS')</script> 你说他能不弹吗?至于为什么可以直接修改源码呢?废话 因为有bug啊 这个bug是写js时没有考虑全面造成的。
low
看下URL 个人认为做渗透的话应该养成一种习惯,就是下意识地瞥一眼URL 尤其是提交一些数据,表单的时候。这里就可以看到使用的是GET型来接收提交的内容。接下来就可以试着改一下URL,因为表单是用下拉框做的我们无法做出修改。当然你也可以拿burp抓包放包啊 不过这里可以但没必要。测试结果如下图:
可以看到有了一些变化,那么这里就直接上payload吧 也就是<script>alert(/xss/)</script>,结果如下图
F12查看源码:
成功挂马!
源码分析:
可以看到什么都没啊,开头我也说了,此XSS主要在于浏览器端对DOM的解析 代码中没有任何过滤,所以很容易被搞。这空空如也的,学不得。
Medium
尝试上面的方法 发现没用了 可以联想到是不是加了过滤把<script>标签过滤掉了 直接F12看看代码
说明可以修改,但是直接上<script>alert(/xss/)</script>就不行,很有可能加了过滤,于是试着绕过。
你看它是不是在<option>中 然后再往前时<select> 那就把这俩标签闭掉 </option></select><img src=1 onerror=alert('xss') /> 发现绕过了过滤
源码分析
array_key_exists()用来判断_GET数组中是否存在名字为default的键且其对应的值不为空
stripos()将defaul字符串中的<script过滤掉 除此之外无任何防护。。。
High
这里要先说一下php的注释可以用#来表示 且注释后会在浏览器端进行解析。
可以看下源代码,这里是加了白名单的
所以咱俩各论各的,你用你的白名单 我写我的注释English#<script>alert("xss")</script>,结果如下:
这不就成了!
Impossible
看页面源码
这里对我们输入的参数(lang)并没有进行URL解码,而在其他级别中是有解码过程的decodeURI(lang)。所以我们输入的任何参数都是经过URL编码,然后直接赋值给option标签。
存储型 XSS
存储型XSS就是把payload留在了数据库中,以至于每次打开/刷新该页面都会触发XSS。
Low
直接上payload<script>alert("xss")</script> 即可完成XSS攻击
源码分析
stripslashes()用来删除反斜杠。可以看到没什么过滤。
Medium
源码分析
strip_tags()用来去处html xml以及PHP的标签,但允许使用<img><body><b>等标签
addslashes():在“前加上\
最主要的是htmlspecialchars():进行html实体转义
可以看到对$message参数做了很严格的过滤,杜绝了对$message关于xss的利用,但对$name参数做的过滤不严格,只是替换<script>以及转义SQL语句中使用的特殊字符,可以使用别的html标签对$name参数的防护进行绕过
因为它限制了name的提交数据长度,所以用burp修改包来做:
大写绕过搞定!
High
看下源码,它是对<script>标签做了彻底过滤,但是并不影响其它标签的使用
还是抓包修改为<img src=1 onerror=alert("xss")>搞定!
Impossible
在看源码之前可以想到肯定是对name也做了彻底的过滤,使用到了htmlspecialchars()
OK,三种XSS打完收工!
喜欢的话点个赞吧^^