DVWA 通关指南:XSS(Reflected)
XSS(Reflected)
"Cross-Site Scripting (XSS)" attacks are a type of injection problem, in which malicious scripts are injected into the otherwise benign and trusted web sites. XSS attacks occur when an attacker uses a web application to send malicious code, generally in the form of a browser side script, to a different end user. Flaws that allow these attacks to succeed are quite widespread and occur anywhere a web application using input from a user in the output, without validating or encoding it.
跨站点脚本(XSS)攻击是一种注入攻击,恶意脚本会被注入到可信的网站中。当攻击者使用 web 应用程序将恶意代码(通常以浏览器端脚本的形式)发送给其他最终用户时,就会发生 XSS 攻击。允许这些攻击成功的漏洞很多,并且在 web 应用程序的任何地方都有可能发生,这些漏洞会在使用用户的输入,没有对其进行验证或编码。
An attacker can use XSS to send a malicious script to an unsuspecting user. The end user's browser has no way to know that the script should not be trusted, and will execute the JavaScript. Because it thinks the script came from a trusted source, the malicious script can access any cookies, session tokens, or other sensitive information retained by your browser and used with that site. These scripts can even rewrite the content of the HTML page.
攻击者可以使用 XSS 向不知情的用户发送恶意脚本,用户的浏览器并不知道脚本不应该被信任,并将执行 JavaScript。因为它认为脚本来自可信来源,所以恶意脚本可以访问浏览器并作用于该站点的任何 cookie、会话令牌或其他敏感信息,甚至可以重写 HTML 页面的内容。
Because its a reflected XSS, the malicious code is not stored in the remote web application, so requires some social engineering (such as a link via email/chat).
由于现在的情景是反射型 XSS,恶意代码不会存储在远程 web 应用程序中,因此需要一些社会工程(例如通过电子邮件/聊天链接)进行攻击。
One way or another, steal the cookie of a logged in user.
不管怎样,尝试窃取登录用户的 cookie。
Low Level
Low level will not check the requested input, before including it to be used in the output text.
将请求的输入包含在输出文本中之前,Low level 将不检查请求的输入。
源码审计
源码如下,服务器只是判断了 name 参数是否为空,如果不为空的话就直接打印出来。服务器并没有对 name 参数做任何的过滤和检查,存在明显的 XSS 漏洞。
<?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>';
}
?>
攻击方式
HTML DOM 有个 alert() 方法,用于显示带有一条指定消息和一个 OK 按钮的警告框。document.cookie 里面可以读到 cookie 信息,我们可以把 cookie 放在一个 alert() 生成的警告框中,回显时就会得到我们想要的信息了。注入的payload 如下所示:
<script>alert(document.cookie)</script>
注入 payload 之后,前端的代码中会加入下面这个结点。
Medium Level
The developer has tried to add a simple pattern matching to remove any references to "< script >", to disable any JavaScript.
开发人员尝试添加一个简单的模式匹配来删除对 “< script >” 的任何引用,从而禁用任何 JavaScript 脚本。
源码审计
源码如下,array_key_exists() 函数检查某个数组中是否存在指定的键名,如果键名存在返回 true,键名不存在则返回 false。str_replace() 函数替换字符串中的一些字符(区分大小写),此处会检查 name 参数中是否有 “< script >”,如果有则替换为空。
<?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>";
}
?>
攻击方式
虽然服务器把 “< script >” 过滤了,但是这并没有什么用,因为将该标签大写也能起到相同的效果。使用大写绕过构造 payload:
<SCRIPT>alert(document.cookie)</SCRIPT>
当然绕过方式不唯一,使用双写绕过也行。
<sc<script>ript>alert(/xss/)</script>
High Level
The developer now believes they can disable all JavaScript by removing the pattern "<script".
开发人员相信可以通过删除模式 “<script” 来禁用所有的 JavaScript。
源码审计
源码如下,preg_replace() 函数执行一个正则表达式的搜索和替换,“*” 代表一个或多个任意字符,“i” 代表不区分大小写。也就是说 “< script >” 标签在这里被完全过滤了,但是我们可以通过其他的标签例如 img、body 等标签的事件或者iframe 等标签的 src 注入 JS 攻击脚本。
<?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>";
}
?>
攻击方式
这种防御形同虚设,因为我们可以直接注入标签将 cookie 显示出来。HTML 的 < img > 标签定义 HTML 页面中的图像,该标签支持 onerror 事件,在装载文档或图像的过程中如果发生了错误就会触发。使用这些内容构造出 payload 如下,因为我们没有图片可供载入,因此会出错从而触发 onerror 事件输出 cookie。
<img src = 1 onerror = alert(document.cookie)>
Impossible Level
Using inbuilt PHP functions (such as "htmlspecialchars()"), its possible to escape any values which would alter the behaviour of the input.
使用内置的 PHP 函数(例如 “htmlspecialchars()”),可以转义任何会改变输入行为的值。
<?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 "<pre>Hello ${name}</pre>";
}
// Generate Anti-CSRF token
generateSessionToken();
?>
htmlspecialchars() 函数用于把预定义的字符 "<" 和 ">" 转换为 HTML 实体,防止了我们注入 HTML 标签。例如我们注入 “”,htmlspecialchars 函数会将 < 和 > 转换成 html 实体而不是当做标签,所以我们插入的语句并不会被执行。同时加入 Anti-CSRF token 防护 CSRF 攻击,进一步提高安全性。
总结与防御
跨站脚本 (Cross-Site Scripting) 是一种针对 Web 程序的代码注入型漏洞攻击,它允许攻击者将恶意脚本注入网页,使得其他用户浏览网页时收到影响。所谓反射型 XSS 就是提交了恶意脚本实现的 XSS 仅对这次访问产生了影响,并非持久性的 XSS 攻击。
XSS 的攻击方式为攻击者请求一个带有 payload 的 URL,服务器的响应不会以任何形式包含攻击者的脚本。XSS 漏洞的修复方式有以下 2 种:
- 过滤输入的字符,例如 “ ' ”,“ " ”,“<”,“>” 等非法字符;
- 对输出到页面的数据进行编码。