CRYPTO-You Need Python #marshal#rfc4042#_长度替换

flag{Lif3_i5_5h0r7_U_n33d_Py7h0n}

YOU NEED PYTHON:人生苦短我用Python。
文件下载地址: https://dn.jarvisoj.com/challengefiles/%E9%A2%98%E7%9B%AE%EF%BC%9Ayou_need_python.zip.74d515955b9aa607b488a48437591a14

#!/usr/bin/env python
#coding=utf-8
#flag.py
import marshal, zlib, base64
exec(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='))))
  • 第一眼看到marshal,先把源代码拿到再说。涉及到python marshal 对象序列化和反序列化,marshal.loads()将二进制数据反序列为Python对象,由于在不同版本的Python中,marshal的实现可能不一样,我们先命令行里测试一下。3里loads失败,2可以。
  • >>> a=zlib.decompress(base64.b64decode(r'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='))
    b'c\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00@\x00\x00\x00s\x92\x00\x00\x0
    0d\x00\x00d\x01\x00l\x00\x00Z\x00\x00d\x02\x00\x84\x00\x00Z\x01\x00d\x03\x00\x84
    \x00\x00Z\x02\x00d\x04\x00\x84\x00\x00Z\x03\x00e\x04\x00d\x05\x00k\x02\x00r\x8e\
    x00e\x05\x00d\x06\x00\x83\x01\x00Z\x06\x00e\x05\x00d\x07\x00\x83\x01\x00Z\x07\x0
    0e\x03\x00e\x07\x00e\x06\x00\x83\x02\x00Z\x08\x00d\x08\x00Z\t\x00e\x08\x00e\t\x0
    0k\x02\x00r\x7f\x00d\t\x00e\x07\x00\x16GHe\n\x00\x83\x00\x00\x01q\x8e\x00d\n\x00
    GHe\n\x00\x83\x00\x00\x01n\x00\x00d\x01\x00S(\x0b\x00\x00\x00i\xff\xff\xff\xffNc
    \x01\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00C\x00\x00\x00s\x13\x00\x00\x00t\
    x00\x00j\x01\x00|\x00\x00\x83\x01\x00j\x02\x00\x83\x00\x00S(\x01\x00\x00\x00N(\x
    03\x00\x00\x00t\x07\x00\x00\x00hashlibt\x04\x00\x00\x00sha1t\t\x00\x00\x00hexdig
    est(\x01\x00\x00\x00t\x06\x00\x00\x00string(\x00\x00\x00\x00(\x00\x00\x00\x00t\x
    00\x00\x00\x00R\x01\x00\x00\x00\x06\x00\x00\x00s\x02\x00\x00\x00\x00\x01c\x01\x0
    0\x00\x00\x03\x00\x00\x00\x05\x00\x00\x00C\x00\x00\x00s2\x00\x00\x00d\x01\x00}\x
    01\x00x%\x00|\x00\x00D]\x1d\x00}\x02\x00|\x01\x00t\x00\x00d\x02\x00|\x02\x00\x16
    d\x03\x00\x83\x02\x007}\x01\x00q\r\x00W|\x01\x00S(\x04\x00\x00\x00Ni\x00\x00\x00
    \x00s\x04\x00\x00\x000x%si\x10\x00\x00\x00(\x01\x00\x00\x00t\x03\x00\x00\x00int(
    \x03\x00\x00\x00t\x07\x00\x00\x00strSHA1t\x01\x00\x00\x00rt\x01\x00\x00\x00i(\x0
    0\x00\x00\x00(\x00\x00\x00\x00R\x04\x00\x00\x00t\x04\x00\x00\x00calc\t\x00\x00\x
    00s\x08\x00\x00\x00\x00\x01\x06\x01\r\x01\x1b\x01c\x02\x00\x00\x00\x06\x00\x00\x
    00\x08\x00\x00\x00C\x00\x00\x00s\xba\x00\x00\x00t\x00\x00|\x01\x00\x83\x01\x00}\
    x02\x00t\x01\x00|\x02\x00\x83\x01\x00}\x03\x00g\x00\x00}\x04\x00x\x80\x00t\x02\x
    00t\x03\x00|\x00\x00\x83\x01\x00\x83\x01\x00D]l\x00}\x05\x00|\x04\x00j\x04\x00t\
    x05\x00|\x00\x00|\x05\x00\x19\x83\x01\x00t\x06\x00d\x01\x00|\x02\x00|\x05\x00d\x
    02\x00\x16\x19\x16d\x03\x00\x83\x02\x00\x17|\x03\x00\x18\x83\x01\x00\x01t\x01\x0
    0t\x00\x00|\x00\x00|\x05\x00d\x04\x00\x17 \x83\x01\x00d\x05\x00 t\x00\x00t\x07\x
    00|\x03\x00\x83\x01\x00\x83\x01\x00d\x05\x00 \x17\x83\x01\x00}\x03\x00q1\x00Wd\x
    06\x00j\x08\x00t\t\x00d\x07\x00\x84\x00\x00|\x04\x00\x83\x02\x00\x83\x01\x00S(\x
    08\x00\x00\x00Ns\x04\x00\x00\x000x%si(\x00\x00\x00i\x10\x00\x00\x00i\x01\x00\x00
    \x00i\x14\x00\x00\x00R\x04\x00\x00\x00c\x01\x00\x00\x00\x01\x00\x00\x00\x02\x00\
    x00\x00S\x00\x00\x00s\n\x00\x00\x00t\x00\x00|\x00\x00\x83\x01\x00S(\x01\x00\x00\
    x00N(\x01\x00\x00\x00t\x03\x00\x00\x00str(\x01\x00\x00\x00t\x01\x00\x00\x00x(\x0
    0\x00\x00\x00(\x00\x00\x00\x00R\x04\x00\x00\x00t\x08\x00\x00\x00<lambda>\x16\x00
    \x00\x00s\x00\x00\x00\x00(\n\x00\x00\x00R\x01\x00\x00\x00R\t\x00\x00\x00t\x05\x0
    0\x00\x00ranget\x03\x00\x00\x00lent\x06\x00\x00\x00appendt\x03\x00\x00\x00ordR\x
    05\x00\x00\x00R\n\x00\x00\x00t\x04\x00\x00\x00joint\x03\x00\x00\x00map(\x06\x00\
    x00\x00t\x05\x00\x00\x00plaint\x03\x00\x00\x00keyt\x07\x00\x00\x00keySHA1t\x07\x
    00\x00\x00intSHA1R\x07\x00\x00\x00R\x08\x00\x00\x00(\x00\x00\x00\x00(\x00\x00\x0
    0\x00R\x04\x00\x00\x00t\x07\x00\x00\x00encrypt\x0f\x00\x00\x00s\x0e\x00\x00\x00\
    x00\x01\x0c\x01\x0c\x01\x06\x01\x19\x014\x016\x01t\x08\x00\x00\x00__main__s\x15\
    x00\x00\x00[*] Please input key:s\x16\x00\x00\x00[*] Please input flag:s\x84\x00
    \x00\x00-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-164s \x00\x00\x00[>] Co
    ngratulations! Flag is: %ss%\x00\x00\x00[!] Key or flag is wrong, try again:)(\x
    0b\x00\x00\x00R\x00\x00\x00\x00R\x01\x00\x00\x00R\t\x00\x00\x00R\x17\x00\x00\x00
    t\x08\x00\x00\x00__name__t\t\x00\x00\x00raw_inputR\x14\x00\x00\x00R\x13\x00\x00\
    x00t\x0b\x00\x00\x00encryptTextt\n\x00\x00\x00cipherTextt\x04\x00\x00\x00exit(\x
    00\x00\x00\x00(\x00\x00\x00\x00(\x00\x00\x00\x00R\x04\x00\x00\x00t\x08\x00\x00\x
    00<module>\x04\x00\x00\x00s\x1a\x00\x00\x00\x0c\x02\t\x03\t\x06\t\t\x0c\x01\x0c\
    x01\x0c\x01\x0f\x01\x06\x01\x0c\x01\t\x01\n\x02\x05\x01'
    >>> marshal.loads(a)
    <code object <module> at 000000000373A930, file "", line 4>
    
  • 熟悉的c\x00\x00\x00……要用到熟悉的uncompile6,先来补一下pyc文件头。
  • import  zlib, base64
    f1 = open(r'C:\Users\ben\Desktop\1.pyc', 'wb')
    f1.write( b'''\x03\xF3\x0D\x0A\x02\x6B\x0D\x5B''')
    f1.close()
    f1 = open(r'C:\Users\ben\Desktop\1.pyc', 'ab')
    f1.write(zlib.decompress(base64.b64decode(r'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=')))
    f1.close()
    

    执行后反编译一下得到的pyc文件,拿到源代码。

    import hashlib
    def sha1(string):
        return hashlib.sha1(string).hexdigest()
    def calc(strSHA1):
        r = 0
        for i in strSHA1:
            r += int('0x%s' % i, 16)
        return r
    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))
    if __name__ == '__main__':
        key = raw_input('[*] Please input key:')
        plain = raw_input('[*] Please input flag:')
        encryptText = encrypt(plain, key)
        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'
        if encryptText == cipherText:
            print '[>] Congratulations! Flag is: %s' % plain
            exit()
        else:
            print '[!] Key or flag is wrong, try again:)'
            exit()
    

    3.现在来处理下key,文件提示是key_is_here_but_do_you_know_rfc4042,开心的import utf9解决。

        import utf9
        f = open(r'C:\Users\ben\Desktop\key_is_here_but_do_you_know_rfc4042', 'rb').read()
        key = utf9.utf9decode(f)
        print key
    #key=_____*((__//__+___+______-____%____)**((___%(___-_))+________+(___%___+_____+_______%__+______-(______//(_____%___)))))+__*(((________/__)+___%__+_______-(________//____))**(_*(_____+_____)+_______+_________%___))+________*(((_________//__+________%__)+(_______-_))**((___+_______)+_________-(______//__)))+_______*((___+_________-(______//___-_______%__%_))**(_____+_____+_____))+__*(__+_________-(___//___-_________%_____%__))**(_________-____+_______)+(___+_______)**(________%___%__+_____+______)+(_____-__)*((____//____-_____%____%_)+_________)**(_____-(_______//_______+_________%___)+______)+(_____+(_________%_______)*__+_)**_________+_______*(((_________%_______)*__+_______-(________//________))**_______)+(________/__)*(((____-_+_______)*(______+____))**___)+___*((__+_________-_)**_____)+___*(((___+_______-______/___+__-_________%_____%__)*(___-_+________/__+_________%_____))**__)+(_//_)*(((________%___%__+_____+_____)%______)+_______-_)**___+_____*((______/(_____%___))+_______)*((_________%_______)*__+_____+_)+___//___+_________+_________/___
    

    此情此景看着又有点眼熟,因为之前也做过一道长长短短下划线计算式,连代码都没有改丢上来就是

    _ = 1
        __ = 2
        ___ = 3
        ____ = 4
        _____ = 5
        ______ = 6
        _______ = 7
        ________ = 8
        _________ = 9
        s = eval(key)
        print s, hex(s), hex(s)[2:-1], hex(s)[2:-1].decode('hex')
    #输出:5287002131074331513 0x495f346d2d6b3379L 495f346d2d6b3379 I_4m-k3y
    

    此时得到key='I_4m-k3y'

  • 然后密码学苦手有点烦,为找思路把print i,ord(plain[i]) ,int('0x%s' % keySHA1[i % 40], 16) ,intSHA1都打印出来发现第一位变成了一个一元一次方程。
    ord(x)+15-302=-185,ord(x)=102,x='f'
    既然这样那估计开头就是flag了……
  • key = 'I_4m-k3y'
    plain = 'flag'
    encryptText = encrypt(plain, key)
    print(encryptText)
    #输出:-185-147-211-221
    

    和cipher的开头匹配,破案了。每次的a+b-c=d中,b和d是已知的,a只和plain[i]有关系,c是上一轮计算得出因此也相当于已知(仅和上上轮的c、plain[:i]有关),理顺逻辑后直接写代码顺序爆破(其实要爆破吗我觉得写个减法是不是更快一点……算了,写代码的时间也是时间())。统计cipher一共有33个‘-’,即len(plain)=33.

    import hashlib,string
    def sha1(string):
        return hashlib.sha1(string).hexdigest()
    def calc(strSHA1):
        r = 0
        for i in strSHA1:
            r += int('0x%s' % i, 16)
        return r
    def encrypt(plain, key):
        keySHA1 = sha1(key) #fd7259647f1cf139d0aeaacc5c8223b79657a091
        intSHA1 = calc(keySHA1) #302
        r = []
        for i in range(len(plain)):
            #print i,ord(plain[i]) ,int('0x%s' % keySHA1[i % 40], 16) ,intSHA1
            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))
    def decrypt(cipher, key):
        keySHA1 = sha1(key) #fd7259647f1cf139d0aeaacc5c8223b79657a091
        intSHA1 = calc(keySHA1) #302
        cipher = cipher.split('-')[1:]
        plain = 'flag'
        for i in range(33):
            if i>3:
                for x in string.printable:
                    if (ord(x) + int('0x%s' % keySHA1[i % 40], 16) - intSHA1) == -int(cipher[i]):
                        plain += x
            intSHA1 = calc(sha1(plain[:i + 1])[:20] + sha1(str(intSHA1))[:20])
            print plain
    def trial():
        import utf9
        f = open(r'C:\Users\ben\Desktop\key_is_here_but_do_you_know_rfc4042', 'rb').read()
        key = utf9.utf9decode(f)
        #print key
        _ = 1
        __ = 2
        ___ = 3
        ____ = 4
        _____ = 5
        ______ = 6
        _______ = 7
        ________ = 8
        _________ = 9
        s = eval(key)
        #print s, hex(s), hex(s)[2:-1], hex(s)[2:-1].decode('hex')
        key = 'I_4m-k3y'
        cipher = '-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'
        decrypt(cipher, key)
    trial()
    
  • 看到代码里有marshal就用uncompile6先拿到源代码
  • 提示rfc4042如无意外就是UTF-9/11解码了,python3里已经装好了库。
  • 下划线长度可以用来替换1~9到底是谁先想出来的。
  • 密码学逆向先找起止位或者已知位突破,尤其一般来说如果出题人善良,密码都是用flag{}等这种固定格式……
    好吧最后还是把减法给写了,免得老师嫌弃作业质量不佳……
  • def decrypt(cipher, key):
        keySHA1 = sha1(key) #fd7259647f1cf139d0aeaacc5c8223b79657a091
        intSHA1 = calc(keySHA1) #302
        cipher = cipher.split('-')[1:]
        plain = 'flag'
        for i in range(33):
            if i>3: