大数跨境

[CTF每日一题]you_need_python_by_sunnyelf

[CTF每日一题]you_need_python_by_sunnyelf Linus SEO海外流量玩家
2019-07-04
2
导读:一个比较有意思的加解密综合题目,新手也可以尝试下哦~

前言

一个比较有意思的 MISC 类加解密综合题目,阅读可能有点困难。


题目和脚本地址:you_need_python_by_sunnyelf[1]

开干

解压zip有两个文件,一个是 flag.py,一个是 key_is_here_but_do_you_know_rfc4042。

首先第一步看提示 rfc4042 的文件,查询可得,它是 utf9 或者是 utf18 的编码。在github上找到 utf9 解码的库,代码如下:

import utf9
dt = ''with open('key_is_here_but_do_you_know_rfc4042', 'r') as f: t = f.read() dt = utf9.utf9decode(t) print dt

解出为

_____*((__//__+___+______-____%____)**((___%(___-_))+________+(___%___+_____+_______%__+______-(______//(_____%___)))))+__*(((________/__)+___%__+_______-(________//____))**(_*(_____+_____)+_______+_________%___))+________*(((_________//__+________%__)+(_______-_))**((___+_______)+_________-(______//__)))+_______*((___+_________-(______//___-_______%__%_))**(_____+_____+_____))+__*(__+_________-(___//___-_________%_____%__))**(_________-____+_______)+(___+_______)**(________%___%__+_____+______)+(_____-__)*((____//____-_____%____%_)+_________)**(_____-(_______//_______+_________%___)+______)+(_____+(_________%_______)*__+_)**_________+_______*(((_________%_______)*__+_______-(________//________))**_______)+(________/__)*(((____-_+_______)*(______+____))**___)+___*((__+_________-_)**_____)+___*(((___+_______-______/___+__-_________%_____%__)*(___-_+________/__+_________%_____))**__)+(_//_)*(((________%___%__+_____+_____)%______)+_______-_)**___+_____*((______/(_____%___))+_______)*((_________%_______)*__+_____+_)+___//___+_________+_________/___

刚开始还以为是类似brainfuck之类的东西,但是观察到有括号和运算符,于是猜测是不是下划线的个数代表数字,验证了一下结果是正确的。运算之后得到了一串数字,应该为key。

# 似乎不能直接u'_'会验证不出来,因此用dt[0]代替ul = dt[0]cnt = 0ns = ''for i in dt:    if i is ul:        cnt += 1    else:        if cnt != 0:            ns += str(cnt)            cnt = 0            ns += i        else:            ns += i# addns += str(cnt)ns = ns.replace('//', '/')print nskey = eval(ns)print key# 5287002131074331513 key

第二步是难点,看marshal.loads()应该处理之后的是编译后的二进制流,查阅资料 使用uncompyle2直接反编译python字节码文件pyo/pyc[2] 找到反编译的方法,因此用uncompyle2是最好不过的了,反编译得出py文件。

import marshal, zlib, base64
bs = marshal.loads(zlib.decompress(base64.b64decode('eJxtVP9r21YQvyd/ieWm66Cd03QM1B8C3pggUuzYCSWstHSFQijyoJBhhGq9OXJl2ZFeqAMOK6Q/94f9Ofvn1s+d7Lgtk/3O997du/vc584a0eqpYP2GVfwDEeOrKCU6g2LRRyiK4oooFsVVUSqkqxTX6J1F+SfSNYrrdKPorC76luhbpOEGCZNFZw2KG3Rmk26QtuXi3xTb7ND6/aVu0g2RuvhEcZNut5lAGbTvAFbyH57TkYLKy8J6xpDvQxiiiaIlcdqJxVcHbXY6bXNlZgviPCrO0+StqfKd88gzNh/qRZyMdWHE29TZZvIkG7eZFRGGRcBmsXJaUoKCQ9fWKHwSqNeKFnsM5PnwJ7q2aKk4AFhcWtQCh+ChB5+Lu/RmyYUxmtOEYxas7i/2iuR7Ti14OEOSmU0RADd4+dQzbM1FJhukAUeQ+kZROuLyioagrau76kc1slY1NNaY/y3LAxDQBrAICJisV2hMdF2lxQcyFuMoqcX3+TCl6xotqzSpkqmxYVmjXVjAXiwBsEfBrd1VvTvLCj2EXRnhoryAKdpxcIgJcowUB68yAx/tlCAuPHqDuZo0CN3CUGHwkPhGMA7aXMfphjbmQLhLhJcHa0a+mpgB191c1U1lnHJQbgkHx+WGxeJbejnpkzSavo2jkxZ7i725npGAaTc8FXmUjbUETHUmkxXN5zqL5WiWxwE7Bc11yyYzNJpN02jerq+DzNNodfxOX8kE4FcmYKscDdYD1oPGGucXYNmgs1F+NTf3GOt3Mg7b+NTVruqoQyX1hOEUacKw+AGbP38ZOq9THRXaSbL5pXGQ8bho/Z/lrzQaHxdoCrlev+t6nZ7re57r+57rHXag93Deh37k+vuw9zorO/Qj/B50cAf2oyOsvut3D+ADWxdxfN/1Drqu39mHzvcRswv/Hvz7sHeg9w8Qzy99DzuFwxhPhs6zWTbOI3OZRiaZZcVj5wVwOklx7OwVxR47PR46r/SVM8ulBJic9zku/eqY/MqJxiDj+Gd55wS3f35pbLCzHoEwzKKpDkN5i+TR+1AYCWTo5IV0Z0P9H3phDDd6lMzPdS5bbo9eJGbTsW9nbDqLL1N9Iq+rRxDbll2x67a9Lf27hw5uK1s1rZr6DOPF+FI=')))import uncompyle2with open('f.py', 'w') as f: uncompyle2.uncompyle('2.7', bs, f)

看encrypt函数,加密方法如下:

def encrypt(plain, key):    keySHA1 = sha1(key)    intSHA1 = calc(keySHA1)    r = []    for i in range(len(plain)):        r.append(ord(plain[i]) + int('0x%s' % keySHA1[i % 40], 16) - intSHA1)        intSHA1 = calc(sha1(plain[:i + 1])[:20] + sha1(str(intSHA1))[:20])
return ''.join(map(lambda x: str(x), r))

1.对key进行sha1加密为16进制串,再处理为10进制串保存到intSHA1;2.对plain里面的每一位ascii编码与keySHA1的某位进行相加后减去intSHA1,放入r中;3.intSHA1变化为plain前i位的sha1前二十位与intSHA1的SHA1前二十位相加的十进制值;4.将r中的元素转化为字符串得到加密后的字符串,因此,该加密方法是前后字符关联的,第n位的加密都与前n-1位有关。

了解了加密方法后,接下来尝试用第一步爆出的key爆破,爆破代码如下:

...if __name__ == '__main__'    cipherText = '-185-147-211-221-164-217-188-169-205-174-211-225-191-234-148-199-198-253-175-157-222-135-240-229-201-154-178-187-244-183-212-222-164'
key = '5287002131074331513' flag ='' for i in range(len(cipherText)/4): for j in range(31, 128): # 一般31-128才是常用字符 if encrypt(flag+chr(j), key) == cipherText[0:i*4+4]: print j, flag += chr(j) break print flag

发现爆破出的都是无意义字符串,猜想是否key有问题,尝试将key转换为16进制、16进制转字符串发现有意义字符串I_4m-k3y

hk = hex(key)[2:]print hkkk = ''for i in range(len(hk)/2):kk += chr(int('0x' + hk[i*2:i*2+2], 16))print kk

将key代入爆破代码即可解出flag。

References

[1] you_need_python_by_sunnyelf: https://github.com/Leezj9671/CTF_subjects/tree/master/you_need_python_by%20sunnyelf
[2] 使用uncompyle2直接反编译python字节码文件pyo/pyc: http://www.cnblogs.com/rainduck/p/3524557.html

【声明】内容源于网络
0
0
Linus SEO海外流量玩家
1234
内容 24
粉丝 0
Linus SEO海外流量玩家 1234
总阅读0
粉丝0
内容24