function encryption_oracle($data, $iv = '') { $modes = array('ecb', 'cbc'); $key = random_aes_key(32); $data = random_aes_key(rand(5, 10)) . $data . random_aes_key(rand(5, 10)); return $modes[rand(0, 1)] == 'ecb' ? mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, 'ecb') : encrypt_aes_cbc($key, $data, random_aes_key(16)); }
function random_enc($key) { $strings = array('MDAwMDAwTm93IHRoYXQgdGhlIHBhcnR5IGlzIGp1bXBpbmc=', 'MDAwMDAxV2l0aCB0aGUgYmFzcyBraWNrZWQgaW4gYW5kIHRoZSBWZWdhJ3MgYXJlIHB1bXBpbic=', 'MDAwMDAyUXVpY2sgdG8gdGhlIHBvaW50LCB0byB0aGUgcG9pbnQsIG5vIGZha2luZw==', 'MDAwMDAzQ29va2luZyBNQydzIGxpa2UgYSBwb3VuZCBvZiBiYWNvbg==', 'MDAwMDA0QnVybmluZyAnZW0sIGlmIHlvdSBhaW4ndCBxdWljayBhbmQgbmltYmxl', 'MDAwMDA1SSBnbyBjcmF6eSB3aGVuIEkgaGVhciBhIGN5bWJhbA==', 'MDAwMDA2QW5kIGEgaGlnaCBoYXQgd2l0aCBhIHNvdXBlZCB1cCB0ZW1wbw==', 'MDAwMDA3SSdtIG9uIGEgcm9sbCwgaXQncyB0aW1lIHRvIGdvIHNvbG8=', 'MDAwMDA4b2xsaW4nIGluIG15IGZpdmUgcG9pbnQgb2g=', 'MDAwMDA5aXRoIG15IHJhZy10b3AgZG93biBzbyBteSBoYWlyIGNhbiBibG93'); $iv = random_aes_key(16); $enc = encrypt_aes_cbc($key, base64_decode($strings[rand(0, count($strings) - 1)]), $iv); return array($iv, $enc); }
function strip_pkcs7($padded_str) { $len = strlen($padded_str); $pad = ord($padded_str[$len - 1]); if (substr($padded_str, $len - $pad) != str_repeat(chr($pad), $pad)) { throw new Exception(__FUNCTION__ . '(): Bad padding.'); } return substr($padded_str, 0, $len - $pad); } function aes_cbc_cookie($string, $key) { $string = preg_replace('/(=|;)/', "'\$1'", $string); $string = "comment1=cooking%20MCs;userdata={$string};comment2=%20like%20a%20pound%20of%20bacon"; return encrypt_aes_cbc($key, $string, 'YELLOW SUBMARINE'); } function check_cookie($enc, $key) { return strpos(decrypt_aes_cbc($key, $enc, 'YELLOW SUBMARINE'), ';admin=true;') !== false; } $bsize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC); $evil = str_repeat('A', $bsize) . '1234;dmi=rue'; // Create a sacrificial block. The appended string ends up as the size of a single block, which is to be bit-flipped. $key = random_aes_key(16); $enc = aes_cbc_cookie($evil, $key); $flip = "'FIS"; // The four characters (in order) to be XOR'd with the single quotes to produce '1234;admin=true'. $evil = "{$flip[0]}{$flip[1]}{$flip[2]}{$flip[3]}"; $evil = str_repeat("", $bsize * 2) . $evil . str_repeat("", $bsize * 4); if (check_cookie($enc ^ $evil, $key)) { echo 'You win! :~)', PHP_EOL; }
break; } } } for ($i = $bsize * $mult - 1; $i >= 0; $i--, $prefix_len++) { $enc = encrypt_aes_ecb(str_repeat('A', $i), $key); $blocks = str_split($enc, $bsize); if ($blocks[$index] != $blocks[$index - 1]) { $prefix_len += $bsize * ($index - $mult + 1); break; } } return $prefix_len; } $key = random_aes_key(16); $rand_prefix = random_aes_key(rand(0, 32)); $bsize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB); $mode = detect_aes_mode(encrypt_aes_ecb(str_repeat('A', $bsize * 2), $key)); $chars = range(chr(0), chr(255)); $prefix_len = get_prefix_len($key); echo "Block size: {$bsize}\nRandom-prefix length: {$prefix_len}\nCipher mode: {$mode}\n\n"; // The length of the random-prefix is in the interval [0,32], so incorporate the following properties into the original attack code: // 1. 47 ($bsize * 3 - 1) 'A's is the maximum and safest width for a mix of padding and alignment of the first byte to attack. // 2. Skip the first 32 ($bsize * 2) bytes, as tampering of the tailing block is all that is necessary. for ($i = 0, $j = 1, $end = $bsize, $dec = ''; $i < $end; $i++, $j++) { $str = str_repeat('A', $bsize * 3 - $prefix_len - $j); $block = substr(encrypt_aes_ecb($str, $key), $bsize * 2, $end); $str2 = $str . $dec; foreach ($chars as $char) { $dict[$char] = substr(encrypt_aes_ecb($str2 . $char, $key), $bsize * 2, $end); }