{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Androids Encryption" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Introduction\n", "\n", "__Solved by__: [hyperc](https://twitter.com/hyperc54).\n", "\n", "__Event__: Pwn2Win 2020: [https://ctftime.org/event/961](https://ctftime.org/event/961)\n", "\n", "__Challenge name__: Androids Encryption (115 pts)\n", "\n", "__Description__: We intercept an algorithm that is used among Androids. There are many hidden variables. Is it possible to recover the message?\n", "\n", "__File__: `server.py`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Encryption logic" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The challenge was accessible on a remote server which provided us with two options:\n", "* Get an encrypted version of a plaintext provided by the user\n", "* Get an encrypted version of the flag\n", " \n", "The Python implementation of the server was also provided in `server.py` and allowed us to understand the logic behind the encryption method." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The main method of this app is the `encrypt` function. \n", "\n", "Given a plaintext, a key and an initialisation vector (IV), it:\n", "* Encrypts the plaintext using AES algorithm in the [PCBC mode](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Propagating_cipher_block_chaining_(PCBC)). \n", "* Returns the ciphertext concatenated with the IV used." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```\n", "def encrypt(txt, key, iv):\n", " global key2, iv2\n", " assert len(key) == BLOCK_SIZE, f'Invalid key size'\n", " assert len(iv) == BLOCK_SIZE, 'Invalid IV size'\n", " assert len(txt) % BLOCK_SIZE == 0, 'Invalid plaintext size'\n", " bs = len(key)\n", " blocks = to_blocks(txt)\n", " ctxt = b''\n", " aes = AES.new(key, AES.MODE_ECB)\n", " curr = iv\n", " for block in blocks:\n", " ctxt += aes.encrypt(xor(block, curr))\n", " curr = xor(ctxt[-bs:], block)\n", " iv2 = AES.new(key2, AES.MODE_ECB).decrypt(iv2)\n", " key2 = xor(to_blocks(ctxt))\n", " return str(base64.b64encode(iv+ctxt), encoding='utf8')\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "which can be illustrated by the following diagram:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![](../_images/android-encryption-1.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `encrypt` function also does another important thing: it modifies two global variables, `iv2` and `key2` that are exactly the key and initialisation vector used by the application to return an encrypted version of the flag to the user." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```\n", "key2 = xor(to_blocks(ctxt))\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Hence, `key2` is reinitialised after each encryption to the result of our previous encryption, which we obviously have. \n", "\n", "Since this type of encryption is symmetric, getting `key2` enables us to decrypt the encrypted flag." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Step by step" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Send a random plaintext to the server and get the response ciphertext" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "response1 = 'qal7b3mi7fEvSccj+NcaYtqU4i4io4qT1g88K9wY2nQ='\n", "iv_plus_ctext = base64.b64decode(response1)\n", "ctext = al[16:] # IV is 16 bytes long" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Get key2 from the recevied ciphertext" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "key2 = xor(to_blocks(ctext))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Query the encrypted flag from the server" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "enc_flag = '36X0Ug8ZEIvrRDeus6c3GBynEY7La36H0/A1Bqoy87go8FyYOeRQOuN7b0fXJXMYqWZ9lo9MWkS8EaN9/8Tl7A=='\n", "enc_flag = base64.b64decode(enc_flag)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Decrypt the ciphertext following the diagram above" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from Crypto.Cipher import AES\n", "\n", "iv2 = enc_flag[:16] \n", "c1 = enc_flag[16:32]\n", "c2 = enc_flag[32:48]\n", "c3 = enc_flag[48:64]\n", "\n", "aes = AES.new(key2, AES.MODE_ECB)\n", "\n", "p1 = xor(aes.decrypt(c1),iv2)\n", "p2 = xor(aes.decrypt(c2),xor(c1,p1))\n", "p3 = xor(aes.decrypt(c3),xor(c2,p2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### And find the flag!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "assert(p1+p2+p3 == b'CTF-BR{kn3W_7h4T_7hEr3_4r3_Pc8C_r3pe471ti0ns?!?}')" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.4" } }, "nbformat": 4, "nbformat_minor": 4 }