CTF-All-In-One/doc/6.3.1_web_hctf2017_babycrack.md
Phantom0307 ef8e772074 update
2018-01-11 21:11:02 +08:00

264 lines
6.8 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 6.3.1 web HCTF2017 babycrack
- [题目解析](#题目解析)
- [解题流程](#解题流程)
## 题目解析
题目就不用多说了,很容易发现是 JavaScript 代码审计。
整个文件的变量名/函数名可以看作是混淆了的,分析一下整个文件的结构
```
——
|- _0x180a,关键字的替换数组
|- 匿名函数,对数组元素进行重排
|- _0xa180,取出对应索引的数组元素
|- check,主要的分析函数
|- test,主要的运行函数
```
这道题结合浏览器进行动态调试,可以节省很多脑力。
首先是重排,这里不需要去深究到底逻辑原理,让引擎代替你去把数组重排好即可。结合程序员计算器和 CyberChef 分析更加方便。
## 解题流程
这样我们可以直接进入 check 函数进行分析。
```
——
|- _0x2e2f8d,又一次进行数组混淆,得到一个新数组
|- _0x50559f,获取 flag 的前四位,即 hctf
|- _0x5cea12,由 hctf 生成一个基数
|- 这里有一个 debug 的事件,个人认为是阻止使用 F12 调试用的,所以可以直接删去
|- 匿名函数,对 _0x2e2f8d 这个数组再进行排列
|- _0x43c8d1,根据输入获取数组中相应值的函数
|- _0x1c3854,将输入的 ascii 码转化为 16 进制,再加上 0x
```
以上部分可以看成是准备部分,这一部分的难点在于多次处理了数组,在动态调试时,很多函数如果多次执行就会产生与原答案不同的数组结构,因此,每次执行都需要重新初始化。
```
——
|- _0x76e1e8,以下划线分割输入,从后面分析可以得知 flag 一共有 5 段
|- _0x34f55b,这一段给出了第一个逆向的条件,结合下一句 if 条件。
```
单独来分析,其实最初我看掉了一个括号,结果弄混了符号优先级,导致觉得这个条件没有意义。
这个条件是说,**第一段的最后两个字符的 16 进制和 { 的 16 进制异或后,对第一段的长度求余应该等于 5 **
这里可以先进行如下猜测
第一段,已经有 hctf{ 了,这里正好去最后两位,先猜测第一段一共只有 7 位,这个猜测是后验的,先不细说。
```
——
|- b2c
```
理解这个函数极为重要,通过随机输入进行测试,输出结果有些眼熟,像是 base64 但不对,比对后确定是 base32 编码,知道这个就不用再去多解读它了。同时,这里也有一个 debug 需要删除
```
——
|- e第二个逆向条件
```
这一句是说,**第三段做 base32 编码,取等号前的部分,再进行 16 进制和 0x53a3f32 异或等于 0x4b7c0a73 **
```
计算 0x4b7c0a73^0x53a3f32=0x4E463541
4E463541 => NF5A 16 进制转字符
NF5A => iz base32 解码
```
因此flag 暂时如下 hctf{x\_x\_iz\_x\_x}
```
——
|- f第三个逆向条件
```
这一句是说,第四段和第三段一样编码后,和 0x4b7c0a73 异或等于 0x4315332
```
计算 0x4315332^0x4b7c0a73=0x4F4D5941
4F4D5941 => OMYA
OMYA => s0
```
flag hctf{x\_x\_iz\_s0\_x}
```
——
|- nf*e*第一段的长度(先不管)
|- h将输入字符串的每一个字符 ascii 码进行计算(*第二段长度)
后连接起来显示(字符到 ascii 码转换)
|- j将第二段以 3 分割,又后面可以确定是分成了两部分
|- 第四个逆向条件
```
首先是,**分割的两部份长度相等,第一部分和第二部分 16 进制异或等于 0x1613 **,这个条件只能后验,也先不管。
```
——
|- k输入的 ascii 码*第二段的长度
|- l第一部分逐字符 ascii 码*第二段长度等于 0x2f9b5072
```
首先0x2f9b5072 == 798707826
```
798 707 826
正好分成三个已知h是对应 ascii 码*常数,
所以假设第一部分有三个字符,那么就是变成了求解常数
也就是 798 707 826 的最大公约数
求解得常数为 7
字符 114 101 118 => rev
```
所以,第二段一共有 7 个字符,前四个字符为 rev3带入上面的后验条件 0x1613
```
0x726576^0x1613=0x727365
727365 => rse
```
flag hctf{?\_rev3rse\_iz\_s0\_?}
```
——
|- m,第五个逆向条件,第五段的前四位和第一段的长度有关
```
题目的 hint 提示,每一段都有意义,因此我们这里做个爆破,假设第一段的长度在 6-30 之间,我们可以算出 n在用 n 去算第五段前四位。
```
n = f*e*(6-30)
第五段前四位 = n % 0x2f9b5072 + 0x48a05362
```
代码:
```
import binascii
for i in range(6,31):
n = 0x4315332*0x4b7c0a73*i
strings = n%0x2f9b5072 + 0x48a05362
print binascii.a2b_hex(str(hex(strings))[2:-1])
```
结果:
```
qK┒
h4r
_;
Vn
L钔V
sr姘
j[瘶
aDx€
X-Ah
O
P
u?
l傡
ck祕
ZT~b
Q=GJ
w羆
n?
e掤t
\{籠
Sd凞
JMM,
p裦
g?n
^ⅧV
U嬃>
```
可以看到大多数字符都没有意义,除了 h4r 让人遐想联翩,可惜还是不全,但是结合已经分析出的 flag猜测应该是 h4rd。
flag hctf{??\_rev3rse\_iz\_s0\_h4rd?}
```
——
|- _0x5a6d56,将输入重复指定次数组合
|- 第六个逆向条件和第七个逆向条件
```
1. 第五段的第六位重复两次不等于倒数第 5-8 位,这个条件也让人摸不着头脑。
2. 第五段倒数第 2 位等于第五段第五位加 1
3. 第五段第 7-8 位去掉 0x 等于第五段第 7 位的 ascii 码\*第五段长度\*5
4. 第五段第五位为 2第五段 7-8 位等于第五段第 8 位重复两次
5. 结合 hint
由以上条件可以推出以下 flag
```
hctf{??_rev3ser_iz_s0_h4rd2?3??3333}
```
先假设 2 和 3 之间没有数字了,这时 7-8 位还未知但是 7-8 位相同,这时的方程
```
而且在这里,由于直接把 0x 去掉,所以 x 的 16 进制一定全为数字
字符拼接 {hex(x)hex(x)} = ascii(x)*13*5
```
爆破代码:
```
import binascii
for i in range(1,128):
string1 = hex(i)[2:]
try:
if int(string1+string1) == i*13*5:
print chr(i)
except:
continue
output e
```
验证前面的后验条件可以确定如下 flag
```
hctf{??_rev3ser_iz_s0_h4rd23ee3333}
```
只剩下最前面的两位,为了方便,利用题目提供的 sha256 结果,我就不回溯条件在判断,直接进行碰撞。
```
import hashlib
a = 'hctf{'
b = '_rev3rse_iz_s0_h4rd23ee3333}'
e1 = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k',
'l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
e2 = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k',
'l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
for i in e1:
for j in e2:
sh = hashlib.sha256()
sh.update(a+i+j+b)
if sh.hexdigest() == "d3f154b641251e319855a73b010309a168a12927f3873c97d2e5163ea5cbb443":
print a+i+j+b
```
output:
```
hctf{j5_rev3rse_iz_s0_h4rd23ee3333}
```