image-crackme

想用IDA Pro逆向结果打开到一半就崩溃了,只能靠猜了。试着运行几次image-crackme.exe,发现生成的MeePwn.ascii的内容总是160x160的一大堆乱七八糟的字符,同时目录下还有一个MeePwn.jpg,尺寸同样是160x160,而且缺少这个文件程序就没法运行,推测图片中的像素和输出有某种联系,用画图做了一张160x160的纯白色图片替换了原来的图(为了使所有的像素都相同),然后试着输入0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}(ASCII48-126)作为key,产生了十分有规律的输出:

这个pattern就很有意思了,可以推测输入的key是被循环扩展到160x160(即ABCDEF->ABCDEFABCDEF…),然后每个字节分别和MeePwn.jpg中对应的像素进行某种运算,才会产生这种循环的输出。

题目提示说flag是MeePwn{…}的形式,可以根据这一特点,用不同长度的flag作为输入,比较输出的MeePwn.ascii和MeePwn.ascii.bak中相同符号的个数,从而得出flag的真正长度。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import os


def march():
    maxlen=160
    marches=0
    s1=open('MeePwn.ascii').read().split('\n')
    s2=open('MeePwn.ascii.bak').read().split('\n')
    for i in range(maxlen):
        for j in range(maxlen):
            if s1[i][j]==s2[i][j]:
                marches+=1
    return marches


def main():
    alla=160*160
    maxklen=40
    mars=[]
    keys=[]
    for klen in range(1,maxklen):
        key='MeePwn{'+'?'*klen+'}'
        os.system('echo %s|.\\image_crackme.exe'%key)
        marches=march()
        mars.append(marches)
        keys.append(key)
    print(mars)
    print(keys)
    for i in range(len(mars)):
        print('%d/%d %s %d'%(mars[i],alla,keys[i],len(keys[i])))


if __name__=='__main__':
    main()


'''RESULT
2880/25600 MeePwn{????????????????????????} 32
8107/25600 MeePwn{?????????????????????????} 33
2836/25600 MeePwn{??????????????????????????} 34
'''

结果中key长度为33时相同符号个数明显高于其他(同样高的还有33的因数11),因此flag长度为33,得到这一长度后,只要逐字符爆破就可以了,即比对key中某个字符循环扩展后所在位置上相同符号的个数。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import os


def march(index,klen):
    alla=25600
    i=index
    marches=0
    s1=''.join(open('MeePwn.ascii').read().split('\n'))
    s2=''.join(open('MeePwn.ascii.bak').read().split('\n'))
    while i<alla:
        if s1[i]==s2[i]:
            marches+=1
        i+=klen
    return marches


def test(rawkey,index,charset):
    keylen=33
    keys=[]
    mars=[]
    for ch in charset:
        key=rawkey[:index]+ch+rawkey[index+1:]
        os.system('echo %s|.\\image_crackme.exe'%key)
        marches=march(index,keylen)
        mars.append(marches)
        keys.append(key)
    keychars=[]
    for i in range(len(charset)):
        if mars[i]>700:
            keychars.append(charset[i])
    print(keychars)
    return keychars


def main():
    keycharss=[]
    rawkey='MeePwn{?????????????????????????}'
    charset='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-=?!+@%*/\\'
    for index in range(7,32):
        keycharss.append(test(rawkey,index,charset))
    #keycharss=[['g'], ['0'], ['l'], ['4'], ['n'], ['g'], ['_'], ['A'], ['s'], ['c'], ['1'], ['1'], ['A'], ['r'], ['t'], ['_'], ['1'], ['S'], ['_'], ['4'], ['w'], ['S'], ['0'], ['m'], ['e']]
    flag='MeePwn{'+(''.join(map(lambda x:x[0],keycharss)))+'}'
    assert(len(flag)==33)
    print(flag)


if __name__=='__main__':
    main()

flag:MeePwn{g0l4ng_Asc11Art_1S_4wS0me}

不得不承认自己和真正的CTF选手还是有很大的差距的,别的题看的一头雾水,毫无思路。