Now Reading
Don’t use ECB mode for encryption · Zola’s Weblog

Don’t use ECB mode for encryption · Zola’s Weblog

2024-01-03 07:16:42

I lately began doing CTF challenges. A couple of days in the past, I used to be engaged on a problem from 247CTF.com. I discovered a problem that, in my view, exhibits why utilizing ECB(Electronic Codebook) mode for encrypting with block ciphers like AES or Twofish isn’t a good suggestion. So, I made a decision to put in writing a collection of weblog posts the place I resolve these challenges and clarify methods to stop these sorts of assaults.

The problem was fairly easy. It was an internet site with two components: /encrypt and /get_flag. Each components wanted a hex-encoded message referred to as person.

Understanding the Supply Code

This problem supplied the supply code for us, making it fairly simple to reverse engineer and perceive the way it works:

from Crypto.Cipher import AES
from flask import Flask, request
from secret import flag, aes_key, secret_key

app = Flask(__name__)
app.config['SECRET_KEY'] = secret_key
app.config['DEBUG'] = False
flag_user = 'impossible_flag_user'

class AESCipher():
    def __init__(self):
        self.key = aes_key
        self.cipher = AES.new(self.key, AES.MODE_ECB)
        self.pad = lambda s: s + (AES.block_size - len(s) % AES.block_size) * chr(AES.block_size - len(s) % AES.block_size)
        self.unpad = lambda s: s[:-ord(s[len(s) - 1:])]

    def encrypt(self, plaintext):
        return self.cipher.encrypt(self.pad(plaintext)).encode('hex')

    def decrypt(self, encrypted):
        return self.unpad(self.cipher.decrypt(encrypted.decode('hex')))

@app.route("/")
def major():
    return "

%s

" % open(__file__).learn()

@app.route("/encrypt")
def encrypt():
    strive:
        person = request.args.get('person').decode('hex')
        if person == flag_user:
            return 'No dishonest!'
        return AESCipher().encrypt(person)
    besides:
        return 'One thing went flawed!'

@app.route("/get_flag")
def get_flag():
    strive:
        if AESCipher().decrypt(request.args.get('person')) == flag_user:
            return flag
        else:
            return 'Invalid person!'
    besides:
        return 'One thing went flawed!'

if __name__ == "__main__":
  app.run()

Simply by trying on the code, it’s apparent that we have to encrypt the impossible_flag_user utilizing the AESCipher class outlined within the code. The category employs an easy algorithm for padding and makes use of AES with ECB mode for encryption. The key secret’s imported from one other Python file, which we don’t have entry to. This implies we will’t merely rewrite the AESCipher class and encrypt no matter we would like.

However, the /encrypt route takes a hex-encoded payload named person and decodes it. If the decoded worth is the same as impossible_flag_user, it returns a ‘No dishonest!’ message. Nevertheless, to acquire the flag, we have to present the /get_flag route with a hex-encoded payload named person that, when decrypted, equals impossible_flag_user.

@app.route("/encrypt")
def encrypt():
    strive:
        person = request.args.get('person').decode('hex')
        if person == flag_user:
            return 'No dishonest!'
        return AESCipher().encrypt(person)
    besides:
        return 'One thing went flawed!'

So, what we will do is assault the implementation of the encryption scheme, which is the AESCipher class. The 2 major points that come to thoughts when it are the self-rolled padding algorithm and the usage of ECB mode.

However what’s ECB mode and the way can it assist us bypass that restriction? Effectively, ECB mode is the best approach of encrypting blocks in block cipher algorithms. It really works by breaking down the plaintext knowledge into blocks of a set dimension and encrypting every block with the important thing. This course of is repeated for every chunk till it reaches the final block. The ultimate block is then padded to match the block dimension of the block cipher, and all of the blocks are organized in collection to type the ciphertext:img

However what’s the issue? ECB mode lacks diffusion, which means it doesn’t obscure the correlation between the plaintext and the ciphertext. This weak point is what we are going to leverage to our benefit when encrypting the impossible_flag_user with it.

Performing the Assault

The very first thing that got here to my thoughts was that I may encrypt the impossible_flag_user partially to acquire some encrypted segments. To attain this, I changed the person within the plaintext with 0000 to keep up the identical size. Listed here are the outcomes:

939454b054b7379b0709a270b894025c1c3b822d1217b7af1516eccddb9349fc

Subsequent, I encrypted solely the person and obtained the next outcome:

See Also

707ece4f0913868ec5df07d131b0822d

Now, all I needed to do was substitute one block dimension size (16 bytes on this case) from the primary encrypted plaintext with the corresponding portion from the second encrypted plaintext:

939454b054b7379b0709a270b894025c707ece4f0913868ec5df07d131b0822d

Now, by sending this modified ciphertext to the /get_flag route, we receive the flag:

247CTF{ddd01e396dc1965c3fcf943f3968aa39}

The rationale this occurred is that the person was our final chunk, and since there was no random initializing vector, irrespective of what number of occasions we encrypt that final chunk, we’d get the identical outcome. Basically, we encrypted the preliminary chunks after which appended the final chunk to bypass the restriction and acquire the flag.

This assault may have been simply prevented by utilizing a cipher mode that gives diffusion and authentication, comparable to GCM_SIV. This mode eliminates the necessity for padding, and the ciphertext will be authenticated later.


This weblog is out there on my GitHub, and for those who discover the content material fascinating, you may give it a star or take into account making a donation here.

Source Link

What's Your Reaction?
Excited
0
Happy
0
In Love
0
Not Sure
0
Silly
0
View Comments (0)

Leave a Reply

Your email address will not be published.

2022 Blinking Robots.
WordPress by Doejo

Scroll To Top