Lab 06 - TLS Attacks - BEAST

Cipher Block Chaining (CBC)

SSLv3/TLS1.0 are protocols to encrypt/decrypt and secure your data. In our case, they both use the CBC cipher mode chaining. The plaintext is divided into block regarding the encryption algorithm (AES, DES, 3DES) and the length is a multiple of 8 or 16. If the plaintext does not fill the length, a padding is added at the end to complete the missing space. In CBC mode, each block of plaintext is XORed with the previous ciphertext block before being encrypted. This way, each ciphertext block depends on all plaintext blocks processed up to that point.

C[i] = Ek(P[i] XOR C[i-1]), C[0] = IV

P[i] = Dk(C[i]) XOR C[i-1], P[0] = IV

To make each message unique, an initialization vector must be used in the first block. When encrypting with CBC mode, the Initialization Vector (IV) is:

  • Random
  • Unpredictable
  • Not secret

CBC encryption CBC decryption

BEAST Attack

In TLS1.0 and SSLv3 the first IV of the request is random, fine. But to gain some time and not generate a new random IV every time, the implementation of TLS1.0 and SSLv3 used the last block of the previous cipher text has an IV. In other words, the IV is now guessable. We will assume the length of each block will be 16 (AES) and the attacker can set up a MITM to retrieve all the ciphertext. Additionally, the attacker can inject malicious code in the victim's browser and can use a socket to send data in the name of the client. This is called a Chosen plaintext attack and can be seen below. Original description: BEAST paper 2011. BEAST Attack

In this attack we assume the client is using a secret COOKIE to authenticate to the server and the attacker would like to obtain this COOKIE. Furthermore, we assume that the attacker can force the client (via the malicious script) to send an encryption of any message followed by the secret COOKIE (this would be a response to a server request).

Let's say that we want to find the first character of the COOKIE, we will instruct the victim to encrypt the following message: 'B'*15 + COOKIE. Remember that the block length is 16 bytes, therefore the first block of the message will be 'BBBBBBBBBBBBBBB?' (let's call it m1).

Because this is the first request, the IV will be random. Observing the ciphertext we can extract two informations: 'Ek(m1 XOR IV)' and 'F[-16:]' will be the IV for the second request. Here F is the encryption of this first request.

For the second request we know what the IV will be. Let's send the same message as in the first request. We will get: Ek(m1 XOR F[-16:0]) as the first block. Last block of the ciphertext ('S[-16:]') will be the next IV. Here S is the encryption of this second request.

For the third request, we will craft a special block P = m_guess XOR F[-16:] XOR S[-16:0], where m_guess is 'B'*15 + our guess for the first character of the cookie. Try to find what the first block of the third ciphertext should look like. Use the technique to find the entire secret cookie.

You may use the code below to implement the attack:

'beast_attack.py'
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pdb
 
'''
    TLS BEAST attack - PoC
    Implementation of the cryptographic path behind the attack
'''
 
import random
import binascii
import sys
from Crypto.Cipher import AES
from Crypto import Random
 
SECRET_COOKIE = b"ID=3ef729ccf0cc5"
BLOCK_LENGTH = 16
 
last_iv = None
 
"""
    AES-CBC
    function encrypt, decrypt, pad, unpad
    You can fix the IV in the function encrypt() because TLS 1.0 fix the IV
    for the second, third... request (to gain time)
"""
 
def pad(s):
    return s + (16 - len(s) % 16) * chr(16 - len(s) % 16).encode()
 
def unpad(s):
    return s[:-ord(s[len(s)-1:])]
 
# we admit the handshake produce a secret key for the session
# of course we do not have any HMAC etc .. but there are not usefull in this attack
# we can use this function without having access to the secret key
def encrypt(msg, iv_p=None):
    raw = pad(msg)
    if iv_p is None:
        iv = Random.new().read(AES.block_size)
    else:
        iv = iv_p
    global key
    key = Random.new().read(AES.block_size)
    cipher = AES.new(b'V38lKILOJmtpQMHp', AES.MODE_CBC, iv)
    return cipher.encrypt(raw)
 
"""
    The PoC of BEAST attack -
    Implementation of the cryptographic path behind the attack
    - the attacker can retrieve the request send be the client
    - but also make the client send requests with the plain text of his choice
"""
 
def xor_strings(xs, ys, zs):
    return "".join(chr(ord(x) ^ ord(y) ^ ord(z)) for x, y, z in zip(xs, ys, zs))
 
def xor_block(vector_init, previous_cipher, p_guess):
    xored = xor_strings(vector_init, previous_cipher, p_guess)
    return xored
 
def split_len(seq, length):
    return [seq[i:i+length] for i in range(0, len(seq), length)]
 
def send_request(msg):
    global last_iv
    enc = encrypt(msg + SECRET_COOKIE, last_iv)
    last_iv = enc[-BLOCK_LENGTH:]
    return enc
 
 
# the PoC start here
def run_three_request():
    secret = []
 
    # the part of the request the atacker knows, can be null
    known_so_far = b"ID="
 
    # retrieve all the bytes of the cookie (in total 16 bytes, all fit in one block)
    for t in range(len(SECRET_COOKIE)):
        padding = 16 - len(known_so_far) - 1
 
        for i in range(0,256):
            # TODO send first request
 
            # TODO send second request
 
            # TODO craft and send third request
 
            # TODO check if the guess is correct
            if False: # change condition here
                known_so_far += chr(i)
                break
            elif i == 255:
                print("Unable to find the char...")
                return known_so_far
    return known_so_far
 
 
# the attacker doesn't know the cookie
secret = run_three_request()
 
print(secret)
ac/laboratoare/06.txt ยท Last modified: 2023/11/09 19:57 by vlad_andrei.badoiu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0