美文网首页
ECB模式攻击

ECB模式攻击

作者: ESE_ | 来源:发表于2018-11-05 19:59 被阅读0次

    ECB加密

    ecb模式使用相同的key分块对明文分别进行加密,相同的明文获得相同的密文输出。如下所示:


    加密模式

    ECB模式对明文进行分块,然后用key进行加密,生成密文,然后将所有的密文组合在一起,完成加密。

    加密条件

    1、文明分块长度一般为16,或16的倍数
    2、文明长度不满16,或16的倍数,使用填充(具体看算法。默认是\x00)
    

    加密过程

    Plaintext: 待加密的数据。
    Key : 被一些如AES的对称加密算法使用。
    Ciphertext:加密后的数据。
    首先将明文进行分块成Plaintext = Plaintext0+Plaintext1+...Plaintextn.

    Ciphertext0 = Encrypt(Plaintext0)
    Ciphertext1 = Encrypt(Plaintext1)
    .....
    Ciphertextn = Encrypt(Plaintextn)
    

    Ciphertext = Ciphertext0+Ciphertext1+....+Ciphertextn

    解密过程

    Plaintext0= Decrypt(Ciphertext0)
    Plaintext1= Decrypt(Ciphertext1)
    .....
    Plaintextn= Decrypt(Ciphertextn)
    

    Plaintext = Plaintext0 + Plaintext1 +.... +Plaintextn

    ECB攻击

    服务器代码

    server.py

    from twisted.internet import reactor, protocol
    from Crypto.Cipher import AES
    
    PORT = 8001
    KEY = "@Ecb_aTTack>esew"
    SECRET = "flag{ese@qq!hooray}"
    
    def encrypt_block(key, plaintext):
            encobj = AES.new(key, AES.MODE_ECB)
            return encobj.encrypt(plaintext).encode('hex')
    
    def encrypt(key, ptxt):
        if (len(ptxt) % 16 != 0):
            ptxt = ptxt + "*" * (16 - (len(ptxt) % 16))
        return encrypt_block(key, ptxt)
    
    class Server(protocol.Protocol):
    
        def connectionMade(self):
            msg = '''
            Welcome to the AES_ECB Cryptography System
            To encrypt, enter "encrypt [plaintext]". Ex, encrypt 123
            1. cliphertext = plaintext + SECRET
            2. this padding is *      
            \r\n>'''
            self.transport.write(msg)
    
        def dataReceived(self, data):
            try:
                data = data.strip().split(" ")
                print (data)
                if data[0] == "encrypt":
                    response = encrypt(KEY,data[1] + SECRET)
                else:
                    raise
                self.transport.write(">" + response + "\r\n>")
            except:
                self.transport.write(">Something is wrong here\r\n>")
    
    def main():
        factory = protocol.ServerFactory()
        factory.protocol = Server
        reactor.listenTCP(PORT, factory)
        reactor.run()
    
    if __name__ == '__main__':
        main()
    

    运行
    nohub python server.py &

    分析

    nc连接到服务器
    nc xxxx 8001
    发现

    1、加密模式AES ECB
    2、cliphertext = plaintext + SECRET
    3、this padding is * (使用填充方式为*)
    

    利用两点

    1、填充加密
    2、相同的明文获得相同的密文输出
    

    这里输入32字节的a[两个16字节]

    encrypt aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    

    结果如下
    4f41ee8a60e859118bd54bcfe6a23fc04f41ee8a60e859118bd54bcfe6a23fc04a4c43aa0d91f3a4906047558d0d559024514659c34bbb29dd3567c801bb63ba

    发现1-32与33-64位完全一样,如下:
    4f41ee8a60e859118bd54bcfe6a23fc0
    4f41ee8a60e859118bd54bcfe6a23fc0
    相同的文明得到相同的密文。

    同时发现后面还有64位,说明SECRET的长度在17-32之间。

    枚举SECRET长度

    这里进行枚举

    输入1个字符进行加密,查看加密后的长度并记住len
    输入2个字符进行加密,查看加密后的长度是否大于len,没有继续
    输入3个字符进行加密,查看加密后的长度是否大于len,没有继续
    ....
    输入14个字符进行加密,查看加密后的长度是否大于len,发现长度变了。那么padding应该填充13个字符
    

    这里也知道flag长度为19位。

    枚举SECRET字符

    这里有个公式

    当填充为13字节时,加密明文字符串为13+19=32位

    当填充为14字节时,加密明文字符串为14+19=32+1位,发现最后一位是flag的最后一位加密[后面15位是填充]。如果我们输入的16位中,第一个是字符,其余15个填充,当这个字符与flag最后一个字符相同时,他们的密文也相同,可以爆破出flag中的最后一位[这里我们需要多输入16个字节构造爆破]。当填充为16+14字节时,加密明文字符串为16+14+19=16+32+1位,可以爆破出flag中的最后一位。

    当填充为16+15字节时,加密明文字符串为16+15+19=16+32+2位,最后两位是flag的最后两位加密[后面14位是填充],因为上面知道最后一位了[这里的"}"],构造第一个是字符+"}",其余14个填充。可以爆破出倒数第二位。

    这样可以一直枚举出所有flag字符

    exp

    import socket
    import re
    
    host = '172.10.22.70'
    port = 8001
    def Tostr(st):
        return st.encode(encoding='UTF8')
    
    def connect():
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((host,port))
        return s
    
    def getCliphertext(data):
        p1 = r"(>)(.*?)(\r\n)"
        pattern1 = re.compile(p1)
        data = pattern1.findall(data)[0][1]
        return data
    
    def get_pad_len(s):
        s.recv(1024)
        for i in range(1,16):
            payload1 = "encrypt "+'a'*i
            s.send(Tostr(payload1))
            data = (s.recv(1024)).decode('utf-8')
            data = getCliphertext(data)
            if i==1:
                slen = len(data)
            if len(data)>slen:
                break
        return i-1
    
    def forcerFlag(s,slen):
        padd = 'a'*(slen+1)
        plaintext = ""
        print("start...")
        array = "`1234567890-=+qwertyuiop[]asdfghjkl;'zxcvbnm,./?<>!@#$%^&*()QWERTYUIOP{}ASDFGHJKLZXCVBNM:"
        for i in range(19):
            for ch in array:
                payload2 = "encrypt "+ch+plaintext+'*'*15+padd
                s.send(Tostr(payload2))
                data = (s.recv(1024)).decode('utf-8')
                data = getCliphertext(data)
                bp = data[:32]
                sec = data[96:128]
                if bp==sec:
                    plaintext = ch +plaintext
                    print(plaintext)
                    break
        return plaintext
    
    def exp():
        s = connect()
        slen = get_pad_len(s)
        plaintext = forcerFlag(s,slen)
        print(plaintext)
    
    if __name__ == '__main__':
        exp()
    

    相关文章

      网友评论

          本文标题:ECB模式攻击

          本文链接:https://www.haomeiwen.com/subject/xbzjxqtx.html