题目是我很早以前做的sctf q1中的web500,我做的时候踩了坑,所以花了很久,感觉题目很有意思,所以就修改了题目又放上来了。
正解wp
https://github.com/sternze/CTF_writeups/blob/master/sCTF/2016_Q1/obfuscat/readme.md
最终分数:124
完成队伍:64
解题人数意外的多,感觉还是有很多py的人,迷…
分析代码
1 | h = new MersenneTwister(parseInt(btoa(answer[_[$[6]]](0, 4)), 32)); |
首先我们根据第一句得到h,h为一个伪随机的数组,根据前四位构成,所以flag的头hctf很重要。
紧接着很多伪随机数都成了固定的数字,也就便于分析了
1 | o = answer.split("_"); |
这里把输入根据下划线分割得到o
1 | e =- (this[_[$[42]]](_[$[31]](o[1])) ^ s[0]); if (-e != $[21]) return false; |
根据这部分,相互异或得到了中间两部分的ascii码,这里其实分析逻辑容易进入误区,这里要肯定的是,其实flag一定是可显示的字符,所以肯定不可以是3位或更多位分割,这么一来就很容易确认了
代码到了这里
1 | a += _[$[31]](o[3].substring(o[3].length - 2)).split("x")[1]; |
出现了很多可变的东西,首先是a
a由o[0]和o[3]共同决定
1 | a = parseInt(_[$[23]]("1", Math.max(o[0].length, o[3].length)), 3) ^ eval(_[$[31]](o[0])); |
其次a会在十进制的基础上,拼接上o[3]出大括号的后两位的十六进制,转十进制a += _[$[31]](o[3].substring(o[3].length - 2)).split("x")[1];
和a相比较的后面的代码,其中有一个可变量为o[3]的倒数第三位,这里出现了隐藏条件
1、中间的o[3]倒数第三位转十六进制后不允许存在字母
2、整体转16进制之后,除了后四位不能存在字母
3、倒数2位必须可显
综合上面的条件,我们就需要脚本来解决问题了
1 | for i in range(30,120): |
下面我们得到了7条,紧接着,筛选可显示字符
只剩下3个了
1 | 64 |
只剩下这个了,那么最后二位是??,倒数第三位是d
那么我们现在还得到了o[3]和o[0]相关的关系,那么我们接下去看
1 | i = 0xffff; |
这里我们拆解0x32ab得到119和101
得到两个字符分别为e和w,那么可以确定2位,但是不确定顺序
下面接着分析
1 | i = 0xffff; |
这里的s判断给了我们新的信息,因为h已知,所以我们就能得到o[3]的第一位和第五位,这么一来,o[3]所有的位我们都知道了是neee3eeed??
现在我们知道了长度,可以肯定的是,o[3]肯定比o[1]长,那么基本可以得到o[1]了,回到刚才的逻辑
1 | a = parseInt(_[$[23]]("1", Math.max(o[0].length, o[3].length)), 3) ^ eval(_[$[31]](o[0])); |
这里我们得到的o[0]为h3r3
, 特别的是,我们刚才得到o[0]第一位为w,这里有个小坑,由于parseInt(_[$[23]]("1", Math.max(o[0].length, o[3].length)), 3)
过小,所以异或没有影响到所有的位,根据意思,我们加上了w,那么getflag
1 | hctf{wh3r3_iz_y0ur_neee3eeed??} |