Flash XSS 漏洞详解 根治的好办法

本文的目的是深层次的分析Flash的ExternalInterface的XSS漏洞,并提出比较有效的解决方案。

首先,我们看看什么情况下,会出现XSS。

第一种情况:

     把flashvars传入的参数(或者其他能被别人控制的方式)当ExternalInterface.call的第一个参数

package
{
        import flash.display.Sprite;
        import flash.external.ExternalInterface;
       
        public class XSSTest extends Sprite
       {
               public function XSSTest()
              {
                      var jsFunction:String = loaderInfo.parameters.jsFunction;
                      var param:String = "abc";
                     ExternalInterface.call(jsFunction, param);
              }
       }
}

     注意,这里通过flashvars传递了一个参数,是js的函数。这种方式比较常见,swf可以做成通用,放到不同的业务中使用,每次只需要传入对应的js函数即可。但是,这里就存在漏洞了。

     在浏览器中,构造url: XSSTest.swf?jsFunction=alert(/XSS/),访问swf,并以get参数的形式传入flashvars,结果,造成了

甚至更狠一点,jsFunction=function(){alert(1);alert(2);}。。。

当然,这么恶作剧alert一下,貌似对小白用户没什么损失,但如果在function内调用这个域名的CGI,就能带来很大的惊喜了~~~因为这里能获取到对应的cookie,时间有限,具体攻击的方式,这里不多说。

第二种情况:

     把flashvars传入的参数(或者其他能被别人控制的方式)当ExternalInterface.call的第二和第三个参数

 这次,我们使用这段代码:

   public function XSSTest()
   {
          var param:String = loaderInfo.parameters.param;
          ExternalInterface.call("console.log", param);
   }

     这个方式也许没有这么简单进行XSS,但对于黑客来说,还是有办法的。

在IE8下调试模式下,我们可以看到ExternalInterface的代码:

正常情况下,Flash player会生成这样的代码:

try { __flash__toXML(console.log("good" )) ; } catch (e) { "<undefined/>"; }

对比自己写的as代码和生成的这段js代码,可以猜测,Flash player是以一种简单的拼接字符串的方式实现的。

稍稍做个小把戏,结果就可以注入代码执行了。

是不是很神奇?怎么做到的呢?为什么url稍稍变化可以达到这样呢。我们看看现在的js代码:

try { __flash__toXML(console.log("\\" ));alert(/XSS/);}catch(e){} //")) ; } catch (e) { "<undefined/>"; }

正好跟原来的双引号对上了,结果,最后的catch也被替换了。。。也就是说,黑客可以写自己的函数了,想怎么执行都可以了。。。

至于为什么这里双引号对上了,可以简单猜测flash遇到字符串中有双引号的时候,只是简单的以  \"  方式打印成js代码,但如果用户再恶意拼一个\,就负负得正了。。。

(这里__flash__toXML的代码并不是关键点了,所以将在文章最后再列出)

第三种情况:

     没有对swf Object的id没有过滤

     页面加载Flash,我们需要设定Object或者embed的id,否则ExternalInterface会失效。而这个地方,也会被黑客利用。

     我们看看实际执行的代码:

try { document.getElementById("XSSTest" ).SetReturnValue(__flash__toXML(alert( null)) ); } catch (e) { document.getElementById("XSSTest" ).SetReturnValue("<undefined/>"); }     

     看到这里,应该发现跟上边说的第二种情况很类似,黑客可以通过修改了Object id,恶意闭合双引号,达到目的。

接下来,简洁的总结一下怎么防XSS。

对于第一和第三种情况,我们应该对字符进行过滤,例如用以下的两个函数:

               public static function checkJsFunctionValid(functionName:String):Boolean
              {
                      var reg:RegExp = /^[a-zA-Z0-9_\.]+$/;
                      return reg.test(functionName);
              }          
    
               public static function checkObjectIdValid():Boolean
              {
                      if (ExternalInterface.available)
                     {
                            var objectId:String = ExternalInterface.objectID;
                            if (!objectId || (objectId == objectId.replace(/[^0-9a-zA-Z_]/g , "")))
                                   return true;
                            else
                                   return false;
                     }
                      return true;
              }
 

对于第二种情况,我们应该尽量避免这样跟js传递数据,但如果实在无法避免。可以用这样的方式转义字符串:

str.replace( /[\"\\]/g , function(d:String, b:*, c:*){ return '\\' + d.charCodeAt(0).toString(8); });

简单解释一下,这里把双引号和反斜杠这样比较敏感的字符,替换为转义表示。再输出成js代码时,正好又还原回去了。

例如:

\\\"\\\"})));}catch(e){alert(/xss/);}// 变成了     \134\42\134\42})));}catch(e){alert(/xss/);}//

附带额外的在IE8 开发工具中抓获到的代码:

function __flash__arrayToXML(obj) {
         var s = "<array>" ;
         for (var i=0; i<obj.length; i++) {
                s += "<property id=\"" + i + "\">" + __flash__toXML(obj[i]) + "</property>";
        }
         return s+"</array>" ;
}
function __flash__argumentsToXML(obj,index) {
         var s = "<arguments>" ;
         for (var i=index; i<obj.length; i++) {
                s += __flash__toXML(obj[i]);
        }
         return s+"</arguments>" ;
}
function __flash__objectToXML(obj) {
         var s = "<object>" ;
         for (var prop in obj) {
                s += "<property id=\"" + prop + "\">" + __flash__toXML(obj[prop]) + "</property>" ;
        }
         return s+"</object>" ;
}
function __flash__escapeXML(s) {
         return s.replace(/&/g, "&amp;" ).replace(/</g, "&lt;").replace(/>/g, "&gt;" ).replace(/"/g, "&quot; ").replace(/'/g, "&apos;");
}
function __flash__toXML(value) {
   var type = typeof(value);
         if (type == "string" ) {
                 return "<string>" + __flash__escapeXML(value) + "</string>";
        } else if (type == "undefined") {
        return "<undefined/>" ;
        } else if (type == "number") {
        return "<number>" + value + "</number>";
        } else if (value == null) {
        return "<null/>" ;
        } else if (type == "boolean") {
        return value ? "<true/>" : "<false/>";
        } else if (value instanceof Date) {
        return "<date>" + value.getTime() + "</date>";
   } else if (value instanceof Array) {
       return __flash__arrayToXML(value);
   } else if (type == "object") {
       return __flash__objectToXML(value);
   } else {
            return "<null/>" ; //???
        }
}
function __flash__addCallback(instance, name) {
  instance[name] = function () {
    return eval(instance.CallFunction("<invoke name=\"" +name+"\" returntype=\"javascript\">" + __flash__argumentsToXML(arguments,0) + "</invoke>" ));
  }
}
function __flash__removeCallback(instance, name) {
  instance[name] = null;
}
  

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏WeTest质量开放平台团队的专栏

Unity3d底层数据传递分析

这篇文章主要分析了在Mono框架下,非托管堆、运行时、托管堆如何关联,以及通过哪些方式调用。内存方面,介绍了什么是封送,以及类和结构体的关系和区别。

1052
来自专栏tkokof 的技术,小趣及杂念

HGE系列之六 管中窥豹(资源管理)

记的上次浮光掠影的讲了一些HGE中的基础类别,不知大家了解了多少,仔细看过的朋友肯定知道当时在讲述一个类别的构造函数时我打了个马虎,直接略过了,原因说的好像是...

731
来自专栏jojo的技术小屋

原 荐 自己写JSON编辑器

作者:汪娇娇 时间:2018年1月15日 下一篇:自己写代码对比工具 时间过得好快,一下子就2018年了,想起好久没写博客,不觉有些浪费了时光,今天便来补一篇。...

7637
来自专栏陈树义

简单笔记

1、类的表面类型和实际类型 实例对象有两个类型:表面类型(Apparent Type)和实际类型(ActualType),表面类型是声明时的类型,实际类型是对象...

2575
来自专栏北京马哥教育

最详细的 linux grep命令教程

grep (global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印...

1050
来自专栏Golang语言社区

GO语言标准库概览

在Go语言五周系列教程的最后一部分中,我们将带领大家一起来浏览一下Go语言丰富的标准库。 Go标准库包含了大量包,提供了丰富广泛的功能特性。这里提供了概览仅仅是...

6826
来自专栏张戈的专栏

Linux运维基础技能: 脚本编程与Linux命令

本系列文章一共三篇,分别为《脚本编程与 Linux 命令》、《接入层与网络基础》和《 MySQL 与 SQL 优化》,由腾讯高级工程师 luaruan(阮永顺)...

1582
来自专栏逆向技术

异常处理第二讲,结构化异常(微软未公开)

            异常处理第二讲,结构化异常(微软未公开) 讲解之前,请熟悉WinDbg的使用,工具使用的博客链接 一丶认识段寄存器FS的内容,以及作用 ...

2097
来自专栏逸鹏说道

C# 温故而知新:Stream篇(六)

BufferedStream 目录: 简单介绍一下BufferedStream 如何理解缓冲区? BufferedStream的优势 从BufferedStre...

3375
来自专栏nnngu

百度搜索 “Java面试题” 前200页(面试必看)

本文中的题目来源于网上的一篇文章《百度搜索 “Java面试题” 前200页》,但该文章里面只有题目,没有答案。因此,我整理了一些答案发布于本文。本文整理答案的原...

72611

扫码关注云+社区