参考:
https://zh.wikipedia.org/wiki/JSFuck
https://blog.csdn.net/qq_36539075/category_7591719.html
https://chinese.freecodecamp.org/news/javascript-implicit-type-conversion/
前言
第一次看到jsfuck编码还是在hgame 2022的week1中一个在线小游戏的ctf题目,只是在注释中发现了一段有很多[]的内容,搜索后发现是jsfuck编码,在控制台中执行就得到了flag,其实也不是很懂jsfuck的原理,只是单纯觉得比较神奇,今天又在一篇安全相关的文章中看到了jsfuck cheat sheet于是就想深入了解一下jsfuck。
什么是jsfuck
先贴一段wiki对jsfuck的解释,JSFuck是一种深奥的 JavaScript 编程风格。以这种风格写成的代码中仅使用 [
、]
、(
、)
、!
和 +
六种字符。此编程风格的名字派生自仅使用较少符号写代码的Brainfuck语言。与其他深奥的编程语言不同,以JSFuck风格写出的代码不需要另外的编译器或解释器来执行,无论浏览器或JavaScript引擎中的原生 JavaScript 解释器皆可直接运行。鉴于 JavaScript 是弱类型语言,编写者可以用数量有限的字符重写 JavaScript 中的所有功能,且可以用这种方式执行任何类型的表达式。
为什么可以只用6种字符编码js
显然一段js代码只用6种字符去写,毫无疑问可以绕过很多关键词的过滤,但是在使用之前会有一个疑问就是为什么可以这样编码一段js代码。
其实这是由于js的隐式类型转换导致的,对于逻辑表达式[]==![]
,js会返回true
先来说说对于运算符==
的运算规则
NaN
和其他任何类型比较永远返回false
(包括和他自己)NaN == NaN // false
Boolean
和其他任何类型比较,Boolean 首先被转换为 Number 类型。true == '2' // false true -> 1
String
和Number
比较,先将String
转换为Number
类型。123 == '123' // true, '123' -> 123
null == undefined
比较结果是true
,除此之外,null
、undefined
和其他任何结果的比较值都为false
。原始类型
和引用类型
做比较时,引用类型会依照ToPrimitive
规则转换为原始类型。
⭐️
ToPrimitive
规则,是引用类型向原始类型转变的规则,它遵循先valueOf
后toString
的模式期望得到一个原始类型。如果还是没法得到一个原始类型,就会抛出TypeError
。
我们再来看看[]==![]
,取非运算优先级最高,[]
是空数组,对一个空数组取非得到false
,那么[]==![]
会变成 []==false
,然后因为Boolean
和其他任何类型比较,Boolean 首先被转换为 Number 类型,false -> 0
,变成[]==0
,然后再因为原始类型
和引用类型
做比较时,引用类型会依照ToPrimitive
规则转换为原始类型,[].valueOf().toString()
的值为''
,String
和``Number比较会把
String转换成
Number,也就是
‘’ -> 0,最终变成
0==0`得到true。
看明白上面的例子后会发现,js的隐式类型转换使得我们可以组合上述的6个符号来替换一些我们希望得到的字符,符号等等内容,所以这也是为什么js代码可以用这样简单的6个符号用来表达,当然这么说其实也还是很难有信服力,我们接下来解析一下如何使用jsfuck编码alert()
。
数字的话比较简单有1有0我们一直加想要多少就多少,然后我们肯定需要26个字符对吧,那字符的话其实是用截取的方式,alert
的话我们可以用true
和false
截取就可以实现
1 |
|
但是26个字母其他的又该怎么实现呢,我们这里看一下jsfuck的官方仓库中是如何获取指定字符的,那更多的字符就需要去看jsfuck的源码啦
1 | 'a': '(false+"")[1]', |
利用jsfuck绕过过滤
因为jsfuck只用6个字符编码,这样的话很多时候可以绕过一些对恶意代码的检测,看到渗透测试中大多数对jsfuck的运用就是绕XSS的过滤,比如这篇文章,文章中xss的payload结合jsfuck编码绕过对alert
等一些危险函数的利用。ctf中我也没怎么看到过jsfuck绕过过滤的题目,只看到过一段js代码里面就直接是flag的题,因此也没有机会仔细研究一下,也许明年hgame可以出个有意思的题考考新生hhh。