ECB模式攻擊

ECB加密

ecb模式使用相同的key分塊對(duì)明文分別進(jìn)行加密,相同的明文獲得相同的密文輸出。如下所示:


加密模式

ECB模式對(duì)明文進(jìn)行分塊,然后用key進(jìn)行加密,生成密文,然后將所有的密文組合在一起,完成加密。

加密條件

1、文明分塊長(zhǎng)度一般為16,或16的倍數(shù)
2、文明長(zhǎng)度不滿16,或16的倍數(shù),使用填充(具體看算法。默認(rèn)是\x00)

加密過程

Plaintext: 待加密的數(shù)據(jù)。
Key : 被一些如AES的對(duì)稱加密算法使用。
Ciphertext:加密后的數(shù)據(jù)。
首先將明文進(jìn)行分塊成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攻擊

服務(wù)器代碼

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()

運(yùn)行
nohub python server.py &

分析

nc連接到服務(wù)器
nc xxxx 8001
發(fā)現(xiàn)

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

利用兩點(diǎn)

1、填充加密
2、相同的明文獲得相同的密文輸出

這里輸入32字節(jié)的a[兩個(gè)16字節(jié)]

encrypt aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

結(jié)果如下
4f41ee8a60e859118bd54bcfe6a23fc04f41ee8a60e859118bd54bcfe6a23fc04a4c43aa0d91f3a4906047558d0d559024514659c34bbb29dd3567c801bb63ba

發(fā)現(xiàn)1-32與33-64位完全一樣,如下:
4f41ee8a60e859118bd54bcfe6a23fc0
4f41ee8a60e859118bd54bcfe6a23fc0
相同的文明得到相同的密文。

同時(shí)發(fā)現(xiàn)后面還有64位,說明SECRET的長(zhǎng)度在17-32之間。

枚舉SECRET長(zhǎng)度

這里進(jìn)行枚舉

輸入1個(gè)字符進(jìn)行加密,查看加密后的長(zhǎng)度并記住len
輸入2個(gè)字符進(jìn)行加密,查看加密后的長(zhǎng)度是否大于len,沒有繼續(xù)
輸入3個(gè)字符進(jìn)行加密,查看加密后的長(zhǎng)度是否大于len,沒有繼續(xù)
....
輸入14個(gè)字符進(jìn)行加密,查看加密后的長(zhǎng)度是否大于len,發(fā)現(xiàn)長(zhǎng)度變了。那么padding應(yīng)該填充13個(gè)字符

這里也知道flag長(zhǎng)度為19位。

枚舉SECRET字符

這里有個(gè)公式

當(dāng)填充為13字節(jié)時(shí),加密明文字符串為13+19=32位

當(dāng)填充為14字節(jié)時(shí),加密明文字符串為14+19=32+1位,發(fā)現(xiàn)最后一位是flag的最后一位加密[后面15位是填充]。如果我們輸入的16位中,第一個(gè)是字符,其余15個(gè)填充,當(dāng)這個(gè)字符與flag最后一個(gè)字符相同時(shí),他們的密文也相同,可以爆破出flag中的最后一位[這里我們需要多輸入16個(gè)字節(jié)構(gòu)造爆破]。當(dāng)填充為16+14字節(jié)時(shí),加密明文字符串為16+14+19=16+32+1位,可以爆破出flag中的最后一位。

當(dāng)填充為16+15字節(jié)時(shí),加密明文字符串為16+15+19=16+32+2位,最后兩位是flag的最后兩位加密[后面14位是填充],因?yàn)樯厦嬷雷詈笠晃涣薣這里的"}"],構(gòu)造第一個(gè)是字符+"}",其余14個(gè)填充。可以爆破出倒數(shù)第二位。

這樣可以一直枚舉出所有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()
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,711評(píng)論 19 139
  • 本文主要介紹移動(dòng)端的加解密算法的分類、其優(yōu)缺點(diǎn)特性及應(yīng)用,幫助讀者由淺入深地了解和選擇加解密算法。文中會(huì)包含算法的...
    蘋果粉閱讀 11,697評(píng)論 5 29
  • 0x01 目錄 常見編碼: ASCII編碼 Base64/32/16編碼 shellcode編碼 Quoted-p...
    H0f_9閱讀 13,528評(píng)論 2 17
  • CTF中那些腦洞大開的編碼和加密 0x00 前言 正文開始之前先閑扯幾句吧,玩CTF的小伙伴也許會(huì)遇到類似這樣的問...
    查無此人asdasd閱讀 6,478評(píng)論 0 19
  • 一、整潔的代碼 整潔的代碼從不隱藏設(shè)計(jì)者的意圖,充滿了干凈利落的抽象和直截了當(dāng)?shù)目刂普Z句。 讀寫的花費(fèi)時(shí)間比例超過...

友情鏈接更多精彩內(nèi)容