`
kidneyball
  • 浏览: 329052 次
  • 性别: Icon_minigender_1
  • 来自: 南太平洋
社区版块
存档分类
最新评论

一段有趣的Javascript代码及分析

阅读更多
在2011年的BlackHat DC 2011大会上Ryan Barnett给出了一段关于XSS的示例javascript代码:
($=[$=[]][(__=!$+$)[_=-~-~-~$]+({}+$)[_/_]+($$=($_=!''+$)[_/_]+$_[+$])])()[__[_/_]+__[_+~$]+$_[_]+$$](_/_)


这是一段完全合法的javascript代码,效果相当于alert(1)。它可以在大部分浏览器上运行。(虽然目前我测试过手头的浏览器都能运行,但理论上不能保证所有浏览器都能正确运行,原因见下文)

这段代码的好处(对于黑客)是,它不包含任何字符或数字,可以逃过某些过滤器的检查。比如说,如果假定一个AJAX请求将返回一个只包含数字的JSON,于是很可能会简单判断了一下其中不含字母就直接eval了,结果给黑客们留下了后门。上面的代码功能很简单,只是alert(1),但使用同样的原理,完全可以干出更复杂的事,例如alert(document.cookie)。更重要的是,这段代码再一次提醒我,黑客的想象力是无限的……正如Ryan Barnett的演讲标题:"XSS:The only rule is no rule"。

那么这段代码是如何工作的呢?

我们可以把它分为两个部分来理解:
第一部分:
($=[$=[]][(__=!$+$)[_=-~-~-~$]+({}+$)[_/_]+($$=($_=!''+$)[_/_]+$_[+$])])()

第二部分:
[__[_/_]+__[_+~$]+$_[_]+$$](_/_)


其中第一部分是核心,我们首先对它进行分析,先缩进一下:
($= [$=[]][
        (__=!$+$)[_=-~-~-~$] +
        ({}+$)[_/_] +
        ($$= ($_=!''+$)[_/_] + $_[+$])
    ]
)()

显然,最外层是(...)()形式的函数调用,我们需要看看这里究竟调用了什么函数,返回了什么。下一步,我们把原来代码中赋值表达式提取出来,将其改写为以下等价形式:
$ = []; //1
__ = !$+$; //2
_ = -~-~-~$; //3
$_=!''+$;  //4
$$ = $_[_/_] + $_[+$];  //5

$= [$][
        __[_] +  //6
        ({}+$)[_/_] +  //7
        $$  //8
    ];  //9

$(); //10


现在来一行行看:
1. $先赋值为一个空数组  (后面会被覆盖)

2. __ = ![] + [] = false + [] = "false"  这里利用了javascript运算的强制类型转换特性。首先空数组是一个非null值,因此![]的结果是false(布尔型)。在计算false + []时,由于数组对象无法与其他值相加,在加法之前会先做一个toString的转换,空数组的toString就是"",因此事实上在计算false + ""。这时false被自动转换为字符串。最终结果是"false"+"" = "false"。  **换句话说,在$为空数组时,使用 “+$”的方式可以将任何一个值转为字符串**

3. 在计算~[]时,~需要一个数字操作数,空数组无法直接转换为数字,则作为0处理。因此~[] = ~0 = -1。
参考:
~3 = -4
~[3] = -4
~[3,2] = -1  (无法转为数字)
~"3" = -4
~"abc" = -1

因此: _ = -~-~-~[] = -~-~-(-1) = -~-~1 = -~-(-2) = -~2 = -(-3) = 3  理论上,可以用这种方式得出1-9所有数字

4. !''是true,使用+$将其变为字符串 "true"

5. 这里需要注意的是,之前一直用“值+[]”来获得“值”的字符串形式。而“+[]”则是0(正号导致[]被自动转换为数值0)。因此:$$ = "true"[3/3] + "true"[+[]] = "true"[1] + "true"[0] = "rt"

6. __[_] = "false"[3] = "s"

7. ({} + [])导致空对象{}被转换为字符串"[object Object]", 因此({}+$)[_/_] = "[object Object]"[1] = "o"

9. 这里把$覆盖为 [[]]["s"+"o"+"rt"]。注意这里[[]]本身是一个包含空数组的数组,其实对这一步来说,任何一个数组都没有关系(不一定要是嵌套数组),但作者巧妙地把$的首次赋值式放在了数组内部,使代码更为紧凑。最终结果是,$ = [[]]["sort"] = [[]].sort = Array.prototype.sort

10. 调用$(),作为整个表达式最终的取值。需要注意,$是全局范围的,是window的一个属性,相当于window.$。而Array.prototype.sort会返回this。对于window.$来说,this就是window。因此,整个第一部分的值,就是window本身!当然,这个过程的正确运作依赖于当前浏览器的Array.prototype.sort实现能对this为window的情况容错。

通过第一部分,我们已经获得将任何值转换为字符串的简单方法,并能产生任意的数值,理论上就可以从javascript的取值系统中提取出大部分字母(不知道是不是全部,需要考证)。并且,我们获取到了window的引用。下面就可以开始上下其手,为所欲为了。木哈哈哈哈哈!

可以看出,上面的第10步是与浏览器的具体实现相关的,因此也存在着某些浏览器下需要对代码作出修改的可能。

现在看第二部分,事实上已经非常明朗了,唯一需要注意的是,现在$是一个函数,因此~$ = ~0 (无法直接转换为数字则作为0处理) = -1。
[__[_/_]+__[_+~$]+$_[_]+$$](_/_) = ["false"[1]+"false"[3+(-1)]+"true"[3]+"rt"](1) = ["a"+"l"+"e"+"rt"](1)


所以,整条式子相当于:
window["alert"](1)


最后只想再感慨一次:黑客的想象力是无限的。理解代码并不难,问题是一开始时他们是怎么能想出来的。。。
分享到:
评论
16 楼 gds718 2011-03-10  
强大,带回去研究下
15 楼 kidneyball 2011-03-10  
hardPass 写道


还没听说过这个运算符 : "~"

请问 ~是个什么东西?学名叫啥?


按位取反
14 楼 kidneyball 2011-03-10  
ztcwh 写道
sdyancai 写道
ie8就不行。。。。。。。。。。。

已验证,是不行。


可以在地址栏输入
javascript:$=[].sort;alert($())

来验证,如果没有弹出"[object Window]"字样,说明这个浏览器的Array.prototype.sort的实现对this为window的情况不容错。有兴趣的话可以找找有没有其他返回this的内部函数可用。顶楼的代码经测试在FF3.x,chrome,opera11下可用。
13 楼 hardPass 2011-03-10  
kidneyball 写道
在2011年的BlackHat DC 2011大会上Ryan Barnett给出了一段关于XSS的示例javascript代码:
($=[$=[]][(__=!$+$)[_=-~-~-~$]+({}+$)[_/_]+($$=($_=!''+$)[_/_]+$_[+$])])()[__[_/_]+__[_+~$]+$_[_]+$$](_/_)


这是一段完全合法的javascript代码,效果相当于alert(1)。它可以在大部分浏览器上运行。(虽然目前我测试过手头的浏览器都能运行,但理论上不能保证所有浏览器都能正确运行,原因见下文)

这段代码的好处(对于黑客)是,它不包含任何字符或数字,可以逃过某些过滤器的检查。比如说,如果假定一个AJAX请求将返回一个只包含数字的JSON,于是很可能会简单判断了一下其中不含字母就直接eval了,结果给黑客们留下了后门。上面的代码功能很简单,只是alert(1),但使用同样的原理,完全可以干出更复杂的事,例如alert(document.cookie)。更重要的是,这段代码再一次提醒我,黑客的想象力是无限的……正如Ryan Barnett的演讲标题:"XSS:The only rule is no rule"。

那么这段代码是如何工作的呢?

我们可以把它分为两个部分来理解:
第一部分:
($=[$=[]][(__=!$+$)[_=-~-~-~$]+({}+$)[_/_]+($$=($_=!''+$)[_/_]+$_[+$])])()

第二部分:
[__[_/_]+__[_+~$]+$_[_]+$$](_/_)


其中第一部分是核心,我们首先对它进行分析,先缩进一下:
($= [$=[]][
        (__=!$+$)[_=-~-~-~$] +
        ({}+$)[_/_] +
        ($$= ($_=!''+$)[_/_] + $_[+$])
    ]
)()

显然,最外层是(...)()形式的函数调用,我们需要看看这里究竟调用了什么函数,返回了什么。下一步,我们把原来代码中赋值表达式提取出来,将其改写为以下等价形式:
$ = []; //1
__ = !$+$; //2
_ = -~-~-~$; //3
$_=!''+$;  //4
$$ = $_[_/_] + $_[+$];  //5

$= [$][
        __[_] +  //6
        ({}+$)[_/_] +  //7
        $$  //8
    ];  //9

$(); //10


现在来一行行看:
1. $先赋值为一个空数组  (后面会被覆盖)

2. __ = ![] + [] = false + [] = "false"  这里利用了javascript运算的强制类型转换特性。首先空数组是一个非null值,因此![]的结果是false(布尔型)。在计算false + []时,由于数组对象无法与其他值相加,在加法之前会先做一个toString的转换,空数组的toString就是"",因此事实上在计算false + ""。这时false被自动转换为字符串。最终结果是"false"+"" = "false"。  **换句话说,在$为空数组时,使用 “+$”的方式可以将任何一个值转为字符串**

3. 在计算~[]时,~需要一个数字操作数,空数组无法直接转换为数字,则作为0处理。因此~[] = ~0 = -1。
参考:
~3 = -4
~[3] = -4
~[3,2] = -1  (无法转为数字)
~"3" = -4
~"abc" = -1

因此: _ = -~-~-~[] = -~-~-(-1) = -~-~1 = -~-(-2) = -~2 = -(-3) = 3  理论上,可以用这种方式得出1-9所有数字

4. !''是true,使用+$将其变为字符串 "true"

5. 这里需要注意的是,之前一直用“值+[]”来获得“值”的字符串形式。而“+[]”则是0(正号导致[]被自动转换为数值0)。因此:$$ = "true"[3/3] + "true"[+[]] = "true"[1] + "true"[0] = "rt"

6. __[_] = "false"[3] = "s"

7. ({} + [])导致空对象{}被转换为字符串"[object Object]", 因此({}+$)[_/_] = "[object Object]"[1] = "o"

9. 这里把$覆盖为 [[]]["s"+"o"+"rt"]。注意这里[[]]本身是一个包含空数组的数组,其实对这一步来说,任何一个数组都没有关系(不一定要是嵌套数组),但作者巧妙地把$的首次赋值式放在了数组内部,使代码更为紧凑。最终结果是,$ = [[]]["sort"] = [[]].sort = Array.prototype.sort

10. 调用$(),作为整个表达式最终的取值。需要注意,$是全局范围的,是window的一个属性,相当于window.$。而Array.prototype.sort会返回this。对于window.$来说,this就是window。因此,整个第一部分的值,就是window本身!当然,这个过程的正确运作依赖于当前浏览器的Array.prototype.sort实现能对this为window的情况容错。

通过第一部分,我们已经获得将任何值转换为字符串的简单方法,并能产生任意的数值,理论上就可以从javascript的取值系统中提取出大部分字母(不知道是不是全部,需要考证)。并且,我们获取到了window的引用。下面就可以开始上下其手,为所欲为了。木哈哈哈哈哈!

可以看出,上面的第10步是与浏览器的具体实现相关的,因此也存在着某些浏览器下需要对代码作出修改的可能。

现在看第二部分,事实上已经非常明朗了,唯一需要注意的是,现在$是一个函数,因此~$ = ~0 (无法直接转换为数字则作为0处理) = -1。
[__[_/_]+__[_+~$]+$_[_]+$$](_/_) = ["false"[1]+"false"[3+(-1)]+"true"[3]+"rt"](1) = ["a"+"l"+"e"+"rt"](1)


所以,整条式子相当于:
window["alert"](1)


最后只想再感慨一次:黑客的想象力是无限的。理解代码并不难,问题是一开始时他们是怎么能想出来的。。。



惊为天人、叹为观止!

还没听说过这个运算符 : "~"

请问 ~是个什么东西?学名叫啥?
12 楼 lovelydog 2011-03-10  
我靠,太犀利了,五体投地膜拜
11 楼 ztcwh 2011-03-10  
sdyancai 写道
ie8就不行。。。。。。。。。。。

已验证,是不行。
10 楼 vruc 2011-03-09  
这个真的要膜拜下,不服不行~~
9 楼 chaiying 2011-03-09  
BT的黑客智商!用符号代替一起的程序  在它们手里不算多么困难度事吧!
8 楼 sdyancai 2011-03-09  
ie8就不行。。。。。。。。。。。
7 楼 wdz567 2011-03-09  
黑客的智商 比90%的程序员都要高吧
不然怎么能这么BT呢
6 楼 cremains 2011-03-09  
大神出没了。。。。大神出没了,我很激动。
5 楼 slccie 2011-03-09  
厉害,没想到JS也可以这么好玩,开眼了
4 楼 tangfei326 2011-03-09  
实在太犀利了。不得不佩服,如此强悍。叫我情何以堪
3 楼 fory 2011-03-09  
我X,我来拜大神的
2 楼 b_lee 2011-03-09  

最后只想再感慨一次:黑客的想象力是无限的。理解代码并不难,问题是一开始时他们是怎么能想出来的。。。
1 楼 b_lee 2011-03-09  
杀花 
支持一下(居然不能使用我×××××顶)
五个字了没?

相关推荐

    超实用的javascript代码段 源码

    "超实用的javascript代码段"是席新亮著作的一个资源集合,提供了许多实际开发中常用且高效的代码片段,对于学习和提升JavaScript编程技能非常有帮助。 一、基础语法与类型 JavaScript的基础语法包括变量声明(var、...

    对下载驱动攻击和恶意代码JavaScript代码的监测与分析

    ### 对下载驱动攻击和恶意代码JavaScript代码的监测与分析 #### 摘要与背景 在当前复杂的网络环境中,下载驱动攻击(drive-by-download attacks)和恶意JavaScript代码日益成为网络安全领域的一大挑战。这类攻击...

    一段好玩的JavaScript代码

    这段JavaScript代码是一个简单的动画效果,它能够改变网页中所有图片的位置,从而创造出一种动态流动的视觉体验。在浏览器的地址栏中输入这段代码并回车后,如果当前页面包含多个图片,这些图片将会按照预设的规则...

    Javascript解释器在ECMAScript中运行Javascript代码

    总之,JavaScript解释器在ECMAScript规范下运行JavaScript代码,涉及词法分析、语法分析、编译和执行等多个步骤。通过理解这些过程,开发者可以更好地调试和优化代码,同时利用各种工具和库来提升开发效率。

    JavaScript前端开发案例教程-源代码.rar

    总之,"JavaScript前端开发案例教程-源代码.rar"提供了一个全面学习和实践JavaScript前端开发的平台,通过分析和运行这些源代码,你不仅可以巩固基础知识,还能了解前沿技术,提升自己的开发能力。建议按照文件的...

    14-编译器和解释器:V8是如何执行一段JavaScript代码的?_For_vip_user_0011

    V8在处理JavaScript代码时,采用了编译器与解释器相结合的策略,这种混合模式使得它能够在保持快速启动的同时,也能提供高效的运行性能。 1. **词法分析与语法分析**: 当V8接收到JavaScript源代码时,首先进行...

    JavaScript学习(一)

    7. **ES6及更新版本的新特性**:自ES6(ECMAScript 2015)以来,JavaScript不断引入新的特性和语法糖,如箭头函数、模板字符串、类、模块、解构赋值等,使得代码更简洁易读。 8. **调试技巧**:学会使用开发者工具...

    超实用的JavaScript代码段(代码逆袭)1

    调试JavaScript代码时,可以利用各种浏览器内置的调试工具,如Chrome的WebInspector、Firefox的Firebug,以及专门的JavaScript调试器。控制台是调试过程中不可或缺的部分,用于输出变量值、跟踪错误和执行测试代码。...

    javascript实用代码压缩工具

    "javascript实用代码压缩工具"就是这样一个帮助开发者优化JavaScript代码的工具。 JavaScript代码压缩主要有两个目的:一是去除代码中的空格、换行符和注释,这种过程称为"混淆";二是通过变量重命名、合并函数等...

    表白代码,前端代码基于javascript

    这个项目可能是用JavaScript编写的一段交互式代码,它可能包含动画效果、音乐播放、文字滚动或者图片展示等元素,用于创造一种浪漫的氛围,帮助程序员向他们的“女神”表达心意。JavaScript可以方便地操作DOM(文档...

    一段简单实用的代码.zip

    标题 "一段简单实用的代码.zip" 提供的信息表明,这个压缩包包含的是一段或一组可用于实际应用的代码。在IT行业中,简单的实用代码通常指的是能够解决特定问题、易于理解和执行的小型代码片段。这样的代码可能涵盖...

    javascript代码格式化工具

    1. **jscisetup.exe**:这通常是一个安装程序,用于在用户的计算机上安装JavaScript代码格式化工具。用户需要运行这个文件来设置环境,使代码格式化工具可以集成到他们的开发环境中,如Visual Studio Code、Sublime ...

    drek一种静态代码分析工具可用于执行以安全性为重点的代码审查

    总之,`drek`作为一个静态代码分析工具,为JavaScript开发提供了强大的安全保障。通过理解和熟练使用drek,开发者可以显著提高代码的安全性和质量,降低潜在的风险,确保项目的稳定性和可靠性。

    商城代码javascript:void(0);

    根据提供的信息来看,这段文本似乎并不包含实际意义上的“商城代码”或者JavaScript代码。相反,它看起来更像是某种游戏或系统的配置文件的一部分,其中包含了各种各样的项目标识符(例如`<itemshow=30853>`)以及...

    CRC16校验-Javascript代码

    下面我们将详细分析这段代码的关键部分及其工作原理。 ##### 1. CRC表初始化 代码中首先定义了两个数组`var_auchCRCHi`和`var_auchCRCLo`,分别用于存储CRC查表的高位和低位部分。这些数值是预计算好的,用于加速...

    一段多浏览器的"复制到剪贴板"javascript代码.docx

    ### 一段多浏览器的“复制到剪贴板”JavaScript代码详解 #### 一、引言 随着Web技术的发展,用户对网页交互体验的要求越来越高。其中,“复制到剪贴板”的功能已经成为很多网站不可或缺的一部分,尤其是在代码分享...

    javascript源代码集

    通过学习和分析这些代码,你可以加深对JavaScript的理解,提升编程技能。 总的来说,无论你是初学者还是经验丰富的开发者,这个"javascript源代码集"都可能成为你学习和进阶的宝贵资源。它涵盖了JavaScript的基础到...

    javascript代码和网页演示

    在本资料中,"javascript代码和网页演示"提供了JavaScript源码及其在实际网页中的应用实例,这对于初学者或者希望深入理解JavaScript的人而言,是一份非常有价值的资源。 首先,JavaScript的基础知识点包括变量、...

    javascript脚本代码

    在这段代码中,有两个主要的JavaScript函数:`xuanxiang` 和 `fangxuan`。 - **`xuanxiang`** 函数用于处理全选逻辑。 - **`fangxuan`** 函数用于处理反选逻辑。 #### 2. 全选功能实现(`xuanxiang`) ```...

    js packer PHP版,加密js源代码文件

    `example-inline.php`可能包含一段内联的JavaScript代码,通过调用`JavaScriptPacker`的函数进行加密。而`example-file.php`可能是读取一个外部JS文件,然后对其进行加密处理。这些示例代码可以帮助初学者快速理解和...

Global site tag (gtag.js) - Google Analytics