当前位置:首页 >> 网络通讯 >> 网络安全 >> 内容

一次SWF XSS挖掘和利用

时间:2013/4/19 12:10:00 作者:平凡之路 来源:xuhantao.com 浏览:

pz大牛写的…觉得不错…呵呵
[ 目录 ]
[0x00] 背景
[0x01] 挖掘漏洞
[0x02] 优雅利用 涛涛电脑知识技巧
[0x03] 从反射到rootkit
[0x04] 总结
[0x00] 背景
这篇迟到了近一年的paper是对 WooYun: Gmail某处XSS可导致账号持久劫持 漏洞的详细说明,赶在世界末日发布,希望不会太晚.:)
既然标题已经提到了SWF XSS,那么第一件事就是查找mail.google.com域下的所有swf文件.感谢万能的Google,利用下面的dork,可以搜索任意域的swf, “site:yourdomain.com filetype:swf”,进行简单的去重之后,我们得到了如下几个swf文件:

https://mail.google.com/mail/im/chatsound.swf   https://mail.google.com/mail/uploader/uploaderapi2.swf   https://mail.google.com/mail/html/audio.swf   https://mail.google.com/mail/im/sound.swf   https://mail.google.com/mail/im/media-api.swf

通过文件名以及直接打开,对这些的swf的功能应该有了一个初步的判断. chatsound.swf和sound.swf应该是播放声音用的, uploaderapi2.swf是上传文件, audio.swf是播放音频文件, media-api.swf? 还是不知道干嘛用的… 然后直接在Google里搜索这些swf的地址, 可以得到一些含有swf的地址, 比如”https://mail.google.com/mail/html/audio.swf?audioUrl= Example MP3 file”, 通过这些swf后面跟的参数, 我们可以进一步推测出这个swf的功能, 此外在反编译时搜索这些参数, 可以快速地定位到整个swf的初始化的过程. 通过以上的过程, 我们发现, 该swf不仅仅接受audioUrl参数, 还接受videoUrl参数, 说明它还是一个视频播放器, 功能上的复杂化必然会对应用的安全性有所影响, 我们决定对此SWF文件进行深入分析.

[0x01] 挖掘漏洞
下载反编译后得到该swf所有的as文件, 通过搜索’ExternalInterface.call’, ‘getURL’, ‘navigateToURL’, ‘javascript:’等关键函数和字符串, 可以快速地定位一些能够执行javascript的代码段. 当搜索’javascript:’时, 我们得到了如下有意思的代码:

==com.google.video.apps.VideoPlayback==     _loc1.onPlaybackComplete = function ()     {         if (this.playerMode_ == com.google.ui.media.MediaPlayer.PLAYER_MODE_NORMAL || this.playerMode_ == com.google.ui.media.MediaPlayer.PLAYER_MODE_MINI)         {             this.queueURL("javascript:FlashRequest(\'donePlaying\', \'\"" + this.mediaPlayer_.url + "\"\');");         } // end if         ...

一个类似javascript伪协议的字符串被代入了queueURL函数, 而且最为关键的是this.mediaPlayer_.url是被直接拼接到字符串的, 并未加以对引号的转义. 但说这是一个xss漏洞还为时过早, 因为我们不知道queueURL函数到底是做什么的, 而且对于this.mediaPlayer_.url在赋值之前是否有进行过滤, 还是处于一个未知的状态. 此外通过对函数名的判断,onPlaybackComplete应该是一个在播放完毕之后的回调函数.
我们搜索到了函数queueURL被定义的地方, 代码如下:

==com.google.video.apps.VideoPlayback==     _loc1.queueURL = function (url)     {         if (this.urlQueue_ == undefined)         {             this.urlQueue_ = new Array();         } // end if         this.urlQueue_.push(url);     };     ...

然后通过跟踪”urlQueue_”变量, 发现如下代码:

==com.google.video.apps.VideoPlayback==     _loc1.checkForPageChanges = function ()     {         ...         if (this.urlQueue_ != undefined)         {             var _loc2 = this.urlQueue_.shift();             if (_loc2 != undefined)             {                 getURL(_loc2, "_self");             } // end if         }         ...

继续跟踪”checkForPageChanges”函数:

==com.google.video.apps.VideoPlayback==     _loc1.initPlayerWithVars = function ()     {         ...         _global.setInterval(this, "checkForPageChanges", 100);         ...

搜索”initPlayerWithVars”函数:

==com.google.video.apps.VideoPlayback==     _loc1.initializePlayer = function ()     {         ...         if (this.mediaState_ != undefined && (this.mediaState_.videoUrl != undefined || this.mediaState_.audioUrl != undefined))         {             this.initPlayerWithVars();         } // end if

从函数名字initializePlayer推断, 这个应该是一个初始化播放器的函数, 在swf打开的时候应该会被执行. 通过搜索的结果, 对整个过程进行反演:initializePlayer函数初始化播放器, 通过对(this.mediaState_ != undefined && (this.mediaState_.videoUrl != undefined || this.mediaState_.audioUrl != undefined))这一逻辑的判读, 如果为true, 则执行initPlayerWithVars函数, 每隔100毫秒调用checkForPageChanges函数, checkForPageChanges函数会检查urlQueue_是否为空数组, 如果不为空, 则弹出数组成员, 直接传入getURL函数. 而onPlaybackComplete则是一回调函数, 当播放完成后自动调用, 如果满足逻辑(this.playerMode_ == com.google.ui.media.MediaPlayer.PLAYER_MODE_NORMAL || this.playerMode_ == com.google.ui.media.MediaPlayer.PLAYER_MODE_MINI), 会把this.mediaPlayer_.url参数压入urlQueue_数组.
通过以上跟踪分析, 我想我们可以得到第一个疑问的答案了,this.mediaPlayer_.url参数最终会被传入到getURL函数. 现在要来看mediaPlayer_.url参数是怎么取到的.
搜索mediaPlayer_.url:

相关文章
  • 没有相关文章
共有评论 0相关评论
发表我的评论
  • 大名:
  • 内容:
  • 徐汉涛(www.xuhantao.com) © 2024 版权所有 All Rights Reserved.
  • 部分内容来自网络,如有侵权请联系站长尽快处理 站长QQ:965898558(广告及站内业务受理) 网站备案号:蒙ICP备15000590号-1