0x00 写在前面
最近比较忙,本来续爷给了我一个洞,让我发来着,准备复现的时候,发现找不到对应版本,问续爷也没回我,不知道是不是在睡觉,想了想从电脑上搜了搜,找了个相对完成度比较高而且不那么水的文章,感谢大家的阅读。
文章主要是本地使用node
的解法,代码量大的时候用chrome调试台,电脑受不了,很久以前遇到过一道用jsfuck加密的题目,编码后代码量很大,打开都卡。
0x01 关于jsfuck
项目地址:https://github.com/aemkei/jsfuck
其实jsfuck本身编码起来,有三种模式
第一种是把输入作为字符串进行编码,这样运行完了会return一个字符串
第二种是将其作为js代码进行编码,但这样的运行结果最后会带一对括号(),实际上删掉这对括号,就能直接输出对应的代码了,官方给的demo称之为Eval Source
第三种是作为js代码进行编码,但不带括号,官方给的demo称之为Run In Parent Scope
除此之外,jsfuck由于本身编码的特性,换行将不适用,这时候如果你的源代码里面有一句单行注释,比如
alert(1);//弹出1
alert(2);
在编码完成之后,看起来就会变得像这样
alert(1);//弹出1alert(2);
显然,后面的语句将被注释掉,这个feature也许可以作为CTF的一个考点
0x02 本地编码 jsfuck
用浏览器编码挺卡的,但是浏览器编码支持“Eval Source”甚至“ Run In Parent Scope”模式,本地使用node默认是不支持的,默认是只编码成字符串。
比如这个链接是支持以上两种模式的。
本地编码是运行FUCK.js
,跟进浏览器调用的函数,我们可以定位到以下两句
var script = lib.JSFuck.encode(chunk.toString());
...
var output = lib.JSFuck.encode(data, false);
改为
var script = lib.JSFuck.encode(chunk.toString(), true, true);
...
var output = lib.JSFuck.encode(data, true, true);
就可以了。
然后执行fuck.js
的话,控制台写入js代码,就会输出对应的编码串。
0x03 解码jsfuck
对于js编码的解决方案,有一种是通用的,就是用chrome去调试,持续跟进,最终可以找到源代码。
除了调试之外,因为js是通过一对括号进行函数调用的,往往只要找到这对括号,删掉,或者加上.toString() / console.log 就可以了。
上面说了有三种格式,字符串
,Eval Source
,Run In Parent Scope
。
字符串没什么好说的。
Eval Source
删除最后的小括号()
,改为toString()
,删除最前面的方括号[]
(这里也可以不删,无关紧要),然后整个用console.log
包起来,用node运行就可以了。
删除最前面的[]
之后代码是原来的代码,像这样
var flag="flag{f_f_l_u_a_c_g_k}";alert('flag is not here');
不删的话是解析器格式化后的,多了一层包裹而已,类似下面这样
function anonymous() {
var flag="flag{f_f_l_u_a_c_g_k}";alert('flag is not here');
}
Run In Parent Scope + Eval Source
两者都勾选了的话,删除编码串里第一个()
及之前的所有代码,然后用console.log
包起来,用node运行就可以了。
0x04 解决方案demo
这样的话,我们就能够有一个类似的解决方案(文末),通过node进行处理,比起浏览器调试的好处,主要在于大文件编码不会再明显卡顿了
我们可以这样使用这个demo
# 编码为字符串
node fuck.js clean.js
# Eval Source
node fuck.js clean.js 1
# Run In Parent Scope
node fuck.js clean.js 1 1
# 解码
node defuck.js encoded.js
甚至你可以用它来编码一些其他文件,只要文件不含\r\n,比如使用base64编码一下
当然,解码后的文件照常可以打开,只不过编码的文件大小几乎是源文件的20000倍,不过如果编码的文件太大,会导致内存溢出解码失败(如果按照单词替换来解决就不会有这个问题)
如果包含换行,那么换行就会消失,就像这样
jsfuck.zip (4.3 KB)