XSS
漏洞介绍
XSS 攻击是指在网页中嵌入一段恶意的客户端 Js 脚本代码片段,JS 脚本恶意代码可以获取用户的 Cookie、URL 跳转、内容篡改、会话劫持……等。
漏洞危害
xss 攻击手段本身对服务端没有直接的危害,xss 主要是借助网站传播;一般通过留言板、邮件、等其他途径向受害者发送一段恶意的 URL,受害者通过访问该恶意 URL 可能会导致恶意的 xss 脚步会在受害者的客户端浏览器中执行,实现自己的目的
漏洞原理
XSS 的攻击类别分为:反射型、存储型、DOM 型等三大类攻击类别。
反射型 XSS
反射型 XSS 会把用户输入的数据直接返回给页面,是一种非持久型攻击;这类型的 xss 是最为常见的,主要的利用方法就是恶意脚本添加到参数(URL)发送给用户诱骗用户点击后反射数据给页面。
- 页面源码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>XSS | 反射型</title>
</head>
<body>
<form action="xss.php" method="GET">
<h2>xss反射型注入攻击测试</h2>
<span>测试语句:</span>
<input type="text" name="name" />
<input type="submit" value="提交" />
</form>
</body>
</html>
- 后台源码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Text page | Return</title>
</head>
<body>
<h2>反射型测试页面</h2>
<?php
echo $_GET["name"];
?>
</body>
</html>
我们输入的内容会被执行并嵌入在 HTML 页面中;$_GET[‘name’]会触发 js 恶意代码并嵌入 HTML 页面中。
存储型 XSS
存储型 XSS 是一种持久的 xss 攻击类别,攻击者将恶意脚本植入到服务端数据库或长期的嵌入在 HTML 页面中;当用户符合触发条件后就会触发 Js 的 xss 恶意脚本。
存储型的 xss 通常会存储在客户端或数据库中,当用户访问页面即触发 xss。
存储型的 xss 不需要构造 URL 诱骗用户去点击,大大的减少暴露和增加隐秘性。
- 创建数据库和表
create table text(
uid int(10) not null auto_increment primary key,
title varchar(20) null,
content text(100) null
)engine=innodb default charset=utf8;
- HTML 页面源码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>xss | 存储型</title>
</head>
<body>
<form action="xss_storage.php" method="POST">
<span>
<h2>xss|存储型测试</h2>
<h3>留言板测试</h3>
</span>
主题:<input type="text" name="title"></br>
留言:<textarea name="content">
</textarea><!-- 文本域留言 -->
<input type="submit" name="提交">
</form>
</body>
</html>
- PHP 后台源码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>xss | 存储型</title>
</head>
<body>
<!-- create databases xss_text 创建数据库-->
<?php
$conn = mysqli_connect("127.0.0.1","root","root","xss_text") or die("数据库连接错误".mysqli_error());
// set names utf-8 -- 写入数据库采用的编码(utf-8)
mysqli_query($conn, 'set names utf-8');
if (isset($_POST["title"])) {
$title = $_POST["title"];
$content = $_POST["content"];
//向数据库添加 title content 两字段的内容
$sql = "INSERT INTO `xss_text`.`text` (`uid`, `title`, `content`) VALUES (NULL, '$title', '$content')";
echo $sql;
$result_1 = mysqli_query($conn,$sql);
// 页面回显/查询数据
$result_2 = mysqli_query($conn , "select * from text");
echo "<table boreder='1'><tr><td>标题</td><td>内容</td></tr>";
while($row = mysqli_fetch_array($result_2, MYSQLI_BOTH)) {
echo "<tr><td>" . $row['title']. "</td><td>" .$row['content']. "</td>";
}
echo "</table>";
echo $row['title'];
}
?>
</body>
</html>
漏洞复现
XSS 绕过思路
- Js 编码
JS 提供了四种字符编码的策略 - 三个八进制数字,空位补 0,***
- 两个十六进制数,空位补 0,\x**
- 四个十六进制数,空位补 0,\u****
- 控制字符,例如 \r , \h , \t
- HTML 实体编码
命名实体:命名以 “&” 开头,分号结尾;参考:实体编码字符
字符编码:十进制、十六进制 ASCII 编码或 Unicode 字符编码 - URL 编码
在线工具:http://tool.chinaz.com/tools/urlencode.aspx
线下工具:URL 编码解码工具(Burp-Decoder)
XSS 检测
beff
防护方法
开启 httponly 作用是限制 JS 访问 cooike 从而有效限制 XXS 危害
输入/输入做过滤
字符过滤
字符过滤
-
输入过滤
永远不要相信用户的输入;一般情况在客户端要设置字符验证过滤敏感的字符、限制长度、要求格式……等。当然客户端的内容用户都是可控的,单单依靠客户端是不可靠的,通过 Burp 等工具,可以轻易的修改数据包,绕过 客户端的过滤检查。 -
输出转码
千万不要把用户的输入内容完整的回显至 HTML 页面中!一般使用 HTMLEncode 进行编码处理。
htmlspecialchars()函数可以将部分特殊字符转出 HTML 实体编码。
<?php
echo htmlentities($_GET["name"]);
// echo $_GET["name"];
?>
输出的转码可以预防 xss 脚本直接回显执行
- 黑名单
使用黑名单和白名单对输入的内容进行正则匹配,不符合的则不执行并取消。开发人员将敏感的关键词 、特殊字符进行黑名单设置,将一些符合条件的字符、关键词纳入白名单。 - 前端过滤函数
HttpOnly Cookie
防止 xss 窃取 Cookie 可以使用 HttpOnlyCookie;
当一个 Cookie 在 Set-cookie 消息头中被标明为 HttpOnly 时,客户端的 js 是不可以直接访问该 cookie 的。
PHP 设置 HttpOnly
修改 php.ini
文件,设置 session.cookie_httponly =1
setcookie()函数和 setrawcookie()函数的第七个参数用来做 HttpOnly 启动选项
setcookie('','','','','','',TRUE);
setrawcookie('','','','','','',TRUE);
php 代码开启 HttpOnly
<?php
ini_set("session.cookie_httponly",1);
session_set_cookie_params(0,null,null,null,TRUE)
?>
客户端预防
用户在访问网站的时候为了防止恶意脚本在自己的客户端上执行,也可以在浏览器上安装一个插件,利用插件的功能来禁止页面的脚本执行。
目前大多高版本的浏览器集成了 XSS 防护。但防护能力有限,不建议只依靠客户端防护。
应用场景
function xss_clean($data){
// Fix &entity\n;
$data=str_replace(array('&','<','>'),array('&','<','>'),$data);
$data=preg_replace('/(&#*\w+)[\x00-\x20]+;/u','$1;',$data);
$data=preg_replace('/(&#x*[0-9A-F]+);*/iu','$1;',$data);
$data=html_entity_decode($data,ENT_COMPAT,'UTF-8');
// Remove any attribute starting with "on" or xmlns
$data=preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu','$1>',$data);
// Remove javascript: and vbscript: protocols
$data=preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([`\'"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu','$1=$2nojavascript...',$data);
$data=preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu','$1=$2novbscript...',$data);
$data=preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u','$1=$2nomozbinding...',$data);
// Only works in IE: <span style="width: expression(alert('Ping!'));"></span>
$data=preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#i','$1>',$data);
$data=preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?behaviour[\x00-\x20]*\([^>]*+>#i','$1>',$data);
$data=preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#iu','$1>',$data);
// Remove namespaced elements (we do not need them)
$data=preg_replace('#</*\w+:\w[^>]*+>#i','',$data);
do{// Remove really unwanted tags
$old_data=$data;
$data=preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i','',$data);
}while($old_data!==$data);
// we are done...
return $data;
}
- 后端过滤
<?php
//php防注入和XSS攻击通用过滤.
//by qq:831937
$_GET && SafeFilter($_GET);
$_POST && SafeFilter($_POST);
$_COOKIE && SafeFilter($_COOKIE);
function SafeFilter (&$arr)
{
$ra=Array('/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/','/script/','/javascript/','/vbscript/','/expression/','/applet/','/meta/','/xml/','/blink/','/link/','/style/','/embed/','/object/','/frame/','/layer/','/title/','/bgsound/','/base/','/onload/','/onunload/','/onchange/','/onsubmit/','/onreset/','/onselect/','/onblur/','/onfocus/','/onabort/','/onkeydown/','/onkeypress/','/onkeyup/','/onclick/','/ondblclick/','/onmousedown/','/onmousemove/','/onmouseout/','/onmouseover/','/onmouseup/','/onunload/');
if (is_array($arr))
{
foreach ($arr as $key => $value)
{
if (!is_array($value))
{
if (!get_magic_quotes_gpc())//不对magic_quotes_gpc转义过的字符使用addslashes(),避免双重转义。
{
$value = addslashes($value); //给单引号(')、双引号(")、反斜线(\)与NUL(NULL字符)加上反斜线转义
}
$value = preg_replace($ra,'',$value); //删除非打印字符,粗暴式过滤xss可疑字符串
$arr[$key] = htmlentities(strip_tags($value)); //去除 HTML 和 PHP 标记并转换为HTML实体
}
else
{
SafeFilter($arr[$key]);
}
}
}
}
?>
获取后台权限 1 获取 cookie
2 获取帐号密码
有保存 获取浏览器记住的明文密码
无保存 表单劫持 (最好是在登入页面有 XSS)
留言板 存储型 XSS XSS 蠕虫
订单信息 盲注入 或取后台管理员信息。
评论区
反馈建议
https://xsshs.cn/ 或 https://xss8.cc/
POC
绕过进行一次移除操作:
<scr
参考引用
https://gitee.com/yhtmxl/imxss/ java imxss 联系平台
https://xssfuzzer.com/fuzzer.html
https://github/s0md3v/XSStrike