Example #1
0
def aes_encrypt(key: bytes, msg: bytes) -> bytes:
    """
    Encrypts the input with AES and the given key
    """
    padded_msg = pkcs7_pad(msg, 16)

    cipher = AES.new(key, AES.MODE_ECB)
    encrypted_msg = cipher.encrypt(padded_msg)

    return encrypted_msg
Example #2
0
def aes_encrypt(msg: bytes) -> bytes:
    """
    Encrypts the input with AES, adding mystery padding! Spooky!
    """
    padding = b64decode(MYSTERY_PADDING)
    padded_msg = pkcs7_pad(msg + padding, 16)

    # Use our unknown but consistent key
    cipher = AES.new(KEY, AES.MODE_ECB)
    encrypted_msg = cipher.encrypt(padded_msg)

    return encrypted_msg
Example #3
0
def randcryptor(msg: bytes) -> bytes:
    """
    Encrypts the input with AES in either ECB or CBC, randomly.
    """
    # Pad the message with 5-10 random bytes
    padding = os.urandom(randint(5, 10))
    padded_msg = pkcs7_pad(padding + msg + padding, BLOCK_SIZE)

    # Generate a random key
    key = generate_aes_key()

    # Randomly choose whether to use ECB or CBC
    mode = 'cbc' if bool(randint(0, 1)) else 'ecb'
    if mode == 'cbc':
        iv = os.urandom(BLOCK_SIZE)
        encrypted_msg = cbc_encrypt(padded_msg, key, iv)
    else:  # ECB
        cipher = AES.new(key, AES.MODE_ECB)
        encrypted_msg = cipher.encrypt(padded_msg)

    return encrypted_msg, mode  # FOR TESTING ONLY
Example #4
0
def cbc_encrypt(msg: bytes, key: bytes, iv: bytes = None) -> bytes:
    """
    Encrypt a message with AES in CBC mode. If `iv` is not set, the vector is
    set to all zeroes.
    """
    assert iv is None or len(iv) == BLOCK_SIZE

    cipher = AES.new(key, AES.MODE_ECB)
    padded_msg = pkcs7_pad(msg, BLOCK_SIZE)
    previous_block = iv if iv is not None else b'\x00' * BLOCK_SIZE
    output = []
    for idx in range(0, len(padded_msg), BLOCK_SIZE):
        block = padded_msg[idx:idx+BLOCK_SIZE]

        # XOR with previous block
        xored_block = xor(block, previous_block)
        result = cipher.encrypt(xored_block)

        output.append(result)
        previous_block = result

    return b''.join(output)
Example #5
0
    api.reset()

    # 1. Create a normal message that is block-aligned (doesn't require any
    #    padding).

    # from=#4567&tx_list=#12345:123455
    txns = OrderedDict({12345: 123455})
    base_request = attacker_client.request_v2(txns)
    base_msg = base_request[:-BLOCK_SIZE]
    base_mac = base_request[-BLOCK_SIZE:]
    assert len(base_msg) % BLOCK_SIZE == 0

    # Given our desired block, modify the block by:
    # 1. XOR with our base mac, essentially zeroing that MAC out when the
    #    MAC for the longer message is computed
    # 2. XOR with the original valid MAC, knowing that that will be what is
    #    fed in in the real, server-side MAC calculation
    #
    # Append this to our original message, and then sign it to get a valid MAC
    # that we can append to the original, valid message along with the desired
    # block
    amount = 1000000
    desired_block = bytes(f';4567:{amount}'.encode())
    hacked_block = xor(xor(pkcs7_pad(desired_block), base_mac), valid_mac)
    hacked_mac = attacker_client.generate_mac(base_msg + hacked_block)

    hacked_request = valid_msg + desired_block + hacked_mac
    assert api.process_v2(hacked_request)
    assert api.accounts[
        ATTACKER_ID] == amount, "Attacker's account should have the amount credited"
Example #6
0
    # Create duplicate blocks to identify where the
    # first full block we have access to begins, after the unknown prefix
    for i in range(block_size * 2, block_size * 3):
        profile = bytes(str(profile_for(' ' * i)).encode())
        dups = detect_duplicate_blocks(aes_encrypt(key, profile))
        if dups:
            break

    # Padding to align input + unknown prefix to the next block index
    initial_padding = i - block_size * 2

    # Fails if earlier duplicates exist
    first_block = min(map(min, dups.values()))

    # Create "admin" + padding input that exactly occupies one block
    profile = initial_padding * ' ' + pkcs7_pad(b'admin').decode()
    encrypted_profile = aes_encrypt(key, bytes(str(profile_for(profile)).encode()))

    admin_block = encrypted_profile[first_block:first_block+block_size]

    # Create an input that shifts the "user" portion of "role=user" into its
    # own block
    profile = (end_align_padding + len('user')) * ' '
    encrypted_profile = aes_encrypt(key, bytes(str(profile_for(profile)).encode()))

    # Now swap out the last block with our padded "admin" block
    chopped_profile = encrypted_profile[:-block_size] + admin_block
    decrypted_profile = aes_decrypt(key, chopped_profile)

    assert b'role=admin' in decrypted_profile