#!/usr/bin/env python # -*- coding: utf-8 -*- ''' 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 = "ID=3ef729ccf0cc5" """ 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) def unpad(s): return s[:-ord(s[len(s)-1:])] # we admit the handshake produce a secret key for the session # we can use this function without having access to the secret key def encrypt( msg, iv_p=None): raw = pad(msg + SECRET_COOKIE) # SECRET_COOKIE is always appended 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('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)] # the PoC start here def run_three_request(): secret = [] fixed_known = "ID=" # the part of the request the atacker knows, can be null known_so_far = fixed_known # padding is the length we need to add to known_so_far to create a length of 15 bytes padding = 16 - len(known_so_far) - 1 known_so_far = "a"*padding + known_so_far length_block = 16 secret_length = len(SECRET_COOKIE) """ TODO: while not found entire cookie: for i in range(256): # send first request # send second request # send third request if success: # update findings # go to next step for sending requests use encrypt(chosen_plaintext, iv), keep in mind that SECRET_COOKIE is always appended first request should use iv=None to generate a fresh one, next ones should set the iv according to the protocol """ return secret # the attacker doesn't know the flag secret = run_three_request() found = ''.join(secret) print "\n" + found