ctf中js加密题总结

1 js混淆加密的

特征是开头就是function(p,a,c,k,e,d)类型的~

题目在http://ctf.idf.cn/game/web/28/

查看网页源代码,发现这样一坨

eval(function(p,a,c,k,e,d){e=function(c){return(c<a?"":
e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};
if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);
k=[function(e){return d[e]}];
e=function(){return'\\w+'};c=1;};
while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p;}('4 a=1d("\\T\\Q\\Z\\10\\5\\Y\\n\\S\\X\\L\\W\\V\\x","");4 b="\\5\\j\\j\\0\\j\\h\\j\\k\\11\\k\\0\\0\\0\\3\\2\\0\\0\\C
\\5\\3\\p\\2\\i\\5\\5\\0\\q\\q\\3\\u\\j\\h";4 c=/.+w.+w.+/P;4 d=t;4 e=a.1(O,y);9($.A(e)==b.B(/7/D,++d).B(/8/D,d*z)){4 f=a.1(t/d,R);9(f.1(y,z)=="\\1b\\M"&&$.A(f.1(t/d,d+E))=="\\p\\2\\6
\\3\\i\\p\\3\\2\\i\\q\\u\\3\\n\\3\\h\\u\\6\\2\\h\\5\\
6\\k\\i\\k\\i\\2\\2\\0\\6\\C\\5\\6"){r=a.1(15);
9(r.m(d)-o==r.m(++d)-o&&r.m(--d)-o==r.m(--d)){4 g=l.H(1e);g=g.v()+g.v();9(r.1((++d)*E,1c)==g.19("\\h\\n\\M\\18")&&c.16(a)){d=l(s)+l(a.17)}}}};9(a.1(F,s)!=l.H(d)||a.1(F,s)=="\\12"){K("\\13\\L\\14\\1a\\N\\N\\J\\J")}U{K("\\I\\G\\I\\G\\x")}',62,77,
'x37|substr|x30|x35|var|x66|x31|||if||||||||
x65|x34|x33|x36|String|charCodeAt|x61|0x19
|x64|x38||0x1|0x0|x62|toLowerCase|_|uff01|0x5|
0x2|md5|replace|x39|ig|0x3|0x4|u559c
|fromCharCode|u606d|u3002|alert|uff0c|x73|u60f3|
0x8|gi|u5165|0x7|x67|u8f93|else|u5e74
|u5c11|u5427|x6c|u4f60|u7684|x63|x7a|u989d|
u518d|0xd|test|length|x79|concat|u53bb
|x6a|0x6|prompt|0x4f'.split('|'),0,{}))

明显经过压缩和混淆,但是这种混淆是肯定是自带解密函数的,要不浏览器也不能识别了,对于function(p,a,c,k,e,d)函数,里面有个return p,p就是解密后结果。在前面增加一句console.log(p)就能看到p的代码了。或者使用 http://www.uiej.com/demo/js_eval_function_p_a_c_k_e_d.html 工具恢复一下,然后使用网上的js在线格式化格式化一下,得到了

var a = prompt("\u8f93\u5165\u4f60\u7684\x66\x6c\x61\x67
\u5427\uff0c\u5c11\u5e74\uff01", "");
var b = "\x66\x33\x33\x37\x33\x65\x33\x36\x63\x36\x37\x37\x37\x35\x30
\x37\x37\x39\x66\x35\x64\x30\x34\x66\x66\x37\x38\x38\x35\x62\x33\x65";
var c = /.+_.+_.+/gi;
var d = 0x0;
var e = a.substr(0x8, 0x5);
if ($.md5(e) == b.replace(/7/ig, ++d).replace(/8/ig, d * 0x2)) {
    var f = a.substr(0x0 / d, 0x7);
    if (f.substr(0x5, 0x2) == "\x6a\x73" && $.md5(f.substr(0x0 / d, d + 0x3)) == "\x64\x30\x31\x35\x34\x64\x35\x30\x34\x38\x62\x35\x61\x35\x65\x62
\x31\x30\x65\x66\x31\x36\x34\x36\x34\x30\x30\x37\x31\x39\x66\x31") {
        r = a.substr(0xd);
        if (r.charCodeAt(d) - 0x19 == r.charCodeAt(++d) - 0x19 && r.charCodeAt(--d) - 0x19 == r.charCodeAt(--d)) {
            var g = String.fromCharCode(0x4f);
            g = g.toLowerCase() + g.toLowerCase();
            if (r.substr((++d) * 0x3, 0x6) == g.concat("\x65\x61\x73\x79") && c.test(a)) {
                d = String(0x1) + String(a.length)
            }
        }
    }
};
if (a.substr(0x4, 0x1) != String.fromCharCode(d) || a.substr(0x4, 0x1) == "\x7a") {
    alert("\u989d\uff0c\u518d\u53bb\u60f3\u60f3\u3002\u3002")
} else {
    alert("\u606d\u559c\u606d\u559c\uff01")
}

这样就好多了,然后逐句的开始分析。


a是弹框输入后的值,b是一个字符串,c貌似是一个正则表达式,先忽略。d是0,e是a的字串,是9-13位。 $.md5(e) == b.replace(/7/ig, ++d).replace(/8/ig, d * 0x2)这个在console给相关变量赋值后,可以直接运行

var b = "\x66\x33\x33\x37\x33\x65\x33\x36\x63\x36\x37\x37\x37
\x35\x30\x37\x37\x39\x66\x35\x64\x30\x34\x66\x66\x37\x38\x38\x35\x62\x33\x65";
var c = /.+_.+_.+/gi;
var d = 0x0;
undefined
b.replace(/7/ig, ++d).replace(/8/ig, d * 0x2)
"f3313e36c611150119f5d04ff1225b3e"

查cmd5得到e的明文为jiami,也就是说a的9-13位是jiami

然后f是a的substr(0 / d, 7),也就是1-7位,又因为下面f.substr(0x5, 0x2) == "\x6a\x73"所以a的6-7位也是js

下面又是一个md5,cmd5得到f.substr(0x0 / d, d + 0x3)wctf,因为刚才已经++d了,所以这里是f的1-3位是wctf,也就是说a的前四位是wctf了。加上刚才算出来的,a是wctf*js*jiami*****代表未知的部分。因为flag就是wctf{...}格式的,所以第一个*就是{

r = a.substr(0xd);,r是从a的第13位开始的,而且需要r.charCodeAt(d) - 0x19 == r.charCodeAt(++d) - 0x19 && r.charCodeAt(--d) - 0x19 == r.charCodeAt(--d)才能继续运行。

charCodeAt()方法可返回指定位置的字符的 Unicode 编码。这个返回值是 0 – 65535 之间的整数。因为这里都是字母符号,返回的也就是他们的ascii码。混淆后有点难理解,好好的想一下。前面的那句r.charCodeAt(d) - 0x19 == r.charCodeAt(++d) - 0x19等价于r.charCodeAt(1) == r.charCodeAt(2),也就是2、3位字符一样的。后面的那一句r.charCodeAt(--d) - 0x19 == r.charCodeAt(--d)等价于r.charCodeAt(1) - 0x19 == r.charCodeAt(0)也就是说1、2位字符差25。

下面两句可以得到g为oog.concat("\x65\x61\x73\x79")ooeasy,由r.substr((++d) * 0x3, 0x6)得到r的4-9位是ooeasy,加上前面的就是***ooeasy,a就是wctf{js*jiami***ooeasy}。这时候我就猜是so easy,但是so还有数字0各种大小写之间都不是差25的。

c.test(a)是js的正则表达式匹配a,参考http://www.w3school.com.cn/jsref/jsref_obj_regexp.asp,得知a里面应该至少有两个下划线。然后因为a的长度不知道,先跳过下面那一句。

接着来,a.substr(0x4, 0x1) != String.fromCharCode(d) || a.substr(0x4, 0x1) == "\x7a"不成立的时候才会提示成功,两个都要不成立就行,所以a.substr(0x4, 0x1) == String.fromCharCode(d)而且a.substr(0x4, 0x1) != "z"就行了。明显,d代表一个ascii码,为123。根据前面的d = String(0x1) + String(a.length)得到a的长度为23,现在正好缺一位,应该是在最后面补上},因为有两位是一样的,现在a就是wctf{js*jiami*##ooeasy}了。

还记得前面说的这个字符串中有两个下划线后面是.+,也就是下划线后面至少有一个字符,只能两个*的位置是下划线,然后#就是比下划线ascii大25的字符x,最终得到wctf{js_jiami_xxooeasy},通过了~

QQ20150324-2@2x.png

2.js fuck

特征就是大量的[]

参考 http://www.jsfuck.com/ 和 http://ursb.org/javascript/2014/12/07/jsplay.html

只要alert一下就能看到原文了。

3.url encode

var p1 = '%66%75%6e%63%74%69%6f%6e%20%63%68%65%63%6b%53%75%62%...";

只要eval(unescape(p1))就好了~

4 base64编码

不仅仅是js,其他语言也可能出现。

 

About hackgoo 110 Articles
渗透测试人员,信息安全维护 主要技能web安全,linux运维 站在巨人的肩膀上,在学习中进步,在进步中学习,低调求生存 极客谷保留所有权利,转载请注明出处

Be the first to comment

Leave a Reply

Your email address will not be published.


*