欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Week 4: CBC Padding Oracle Attack作业

程序员文章站 2022-05-11 21:07:21
...

问题

week 4最后的编程作业是根据解密方解密时返回不同类型的错误的情况来还原明文, 原题如下:

In this project you will experiment with a padding oracle attack against a toy web site hosted at crypto-class.appspot.com . Padding oracle vulnerabilities affect a wide variety of products, including secure tokens .

This project will show how they can be exploited. We discussed CBC padding oracle attacks in week 4 (segment number 6), but if you want to read more about them, see a short description here or Vaudenay’s paper on this topic.

Now to business. Suppose an attacker wishes to steal secret information from our target web site crypto-class.appspot.com . The attacker suspects that the web site embeds encrypted customer data in URL parameters such as this:

http://crypto-class.appspot.com/po?er=f20bdba6ff29eed7b046d1df9fb7000058b1ffb4210a580f748b4ac714c001bd4a61044426fb515dad3f21f18aa577c0bdf302936266926ff37dbf7035d5eeb4

That is, when customer Alice interacts with the site, the site embeds a URL like this in web pages it sends to Alice. The attacker intercepts the URL listed above and guesses that the ciphertext following the “po?er=” is a hex encoded AES CBC encryption with a random IV of some secret data about Alice’s session.

After some experimentation the attacker discovers that the web site is vulnerable to a CBC padding oracle attack. In particular, when a decrypted CBC ciphertext ends in an invalid pad the web server returns a 403 error code (forbidden request). When the CBC padding is valid, but the message is malformed, the web server returns a 404 error code (URL not found).

Armed with this information your goal is to decrypt the ciphertext listed above. To do so you can send arbitrary HTTP requests to the web site of the form

 http://crypto-class.appspot.com/po?er="your ciphertext here"

and observe the resulting error code. The padding oracle will let you

decrypt the given ciphertext one byte at a time. To decrypt a single byte you will need to send up to 256 HTTP requests to the site. Keep in mind that the first ciphertext block is the random IV. The decrypted message is ASCII encoded.

To get you started here is a short Python script that sends a ciphertext supplied on the command line to the site and prints the resulting error code. You can extend this script (or write one from scratch) to implement the padding oracle attack. Once you decrypt the given ciphertext, please enter the decrypted message in the box below.

This project shows that when using encryption you must prevent padding oracle attacks by either using encrypt-then-MAC as in EAX or GCM, or if you must use MAC-then-encrypt then ensure that the site treats padding errors the same way it treats MAC errors.

解题思路

解题前我们先了解一下CBC解密的一般流程:

Week 4: CBC Padding Oracle Attack作业

  1. C2经过**解密后会形成中间结果I2
  2. I2与前一密文块C1(也可能是IV)异或后得到明文P2

Padding规则

CBC使用AES块加密时,分块长度为16bytes,最后一个明文块不够16bytes长度时需要进行填充。填充规则如下:

  • 当最后一块明文长度恰好是16bytes时, 最后追加一个padding block, 即内容为0x10的16字节填充块
  • 当最后一块明文长度不够16 bytes时,最后会填充1616 - 最后一块长度字节, 填充字节内容为填充长度。

过程描述

猜解非填充块(非最后一块)

  1. 使用前一密文块作为当前**块的IV(即上图中C1)
  2. 从后往前按字节构造IV, 使得I2与C1异或后得到一个填充, 如C2最后一字节猜想为kk, 那么猜想IV最后一字节为填充字节, 则IV最后一字节需取值IV[last_byte]k0x01IV[last\_byte] \bigoplus k \bigoplus 0x01
  3. 将2生成的新的密文发送到解密方, 若返回结果为padding正常, 则对应位置的明文则为kk, 进入第4步;若返回padding失败, 则进入第2步尝试另一个kk
  4. 将IV最后一个值填充为V[last_byte]k0x02V[last\_byte] \bigoplus k \bigoplus 0x02, 猜想倒数第二个字节为jj, 然后重新进入第2步,尝试猜解倒数第二个字节,直到所有字节猜解完成。

猜解填充块(最后一块)

  1. 使用前一密文块作为当前**块的IV(即上图中C1)
  2. 从后往前按字节构造IV, 使得I2与C1异或后得到一个填充, 如C2最后一字节猜想为kk, 那么猜想IV最后一字节为填充字节, 则IV最后一字节需取值IV[last_byte]k0x01IV[last\_byte] \bigoplus k \bigoplus 0x01
  3. 将2生成的新的密文发送到解密方, 若返回结果为padding正常, 则修改IV倒数第二个字符值以打破填充规则,若猜解kk依然返回padding正常, 则kk为真实值;若kk猜解错误, 则继续猜解其他值。
  4. 若3猜解正确, 其余字节同猜解非填充块操作

样例程序

代码

import requests
from requests import ConnectionError
from typing import List, Tuple
from math import floor
import pickle
from time import sleep

def padding_query(c: str) -> bool:
    """
    查询padding
    :param c: 密文
    :return: 是否成功
    """
    url = "http://crypto-class.appspot.com/po"
    rsp = requests.get(url, params={
            "er": c
        }
    )
    status_code = rsp.status_code
    rsp.close()
    return True if status_code == 404 else False


def convert_hex_str_to_int_list(a: str) -> List[int]:
    return [int(a[i: i+2], 16) for i in range(0, len(a), 2)]


def split_iv_ciphers(cipher: str) -> Tuple[List[int], List[List[int]]]:
    """
    拆分出iv和密文块
    :param cipher:
    :return:
    """
    hex_cipher = convert_hex_str_to_int_list(cipher)
    block_size = 16
    block_num = floor(len(hex_cipher) / block_size)
    iv = hex_cipher[0:block_size]
    cipher_list = list()
    for i in range(1, block_num):
        cipher_list.append(hex_cipher[i*block_size: (i+1)*block_size])
    return iv, cipher_list


def convert_int_list_to_hex_str(iv: List[int], cipher: List[int]) -> str:
    result_list = []
    for i in iv:
        result_list.append("%02x" % i)

    for j in cipher:
        result_list.append("%02x" % j)
    return "".join(result_list)


def contruct_attack_iv(iv: List[int], value: int, padding_num: int) -> List[int]:
    """
    构建iv
    :param iv:
    :param value:
    :param padding_num: padding数
    :return:
    """
    iv_compute = iv[:]
    iv_compute.reverse()
    for (idx, val) in enumerate(iv_compute):
        if idx == (padding_num - 1):
            iv_compute[idx] = (val ^ value ^ padding_num)
        elif idx < padding_num - 1:
            iv_compute[idx] = (val ^ padding_num)
        else:
            pass
    iv_compute.reverse()
    return iv_compute


def padding_attack(iv: List[int], cipher: List[int], last_block: bool = False) -> List[int]:
    """
    padding攻击
    :param iv:
    :param cipher:
    :return:
    """
    total_bytes = len(cipher)
    content_list = [ -1 for i in range(total_bytes)]
    block_size = len(iv)
    iv_construct = iv[:]
    for j in range(block_size - 1, -1, -1):
        k = 0
        while k < 256:
            iv_trailed = iv_construct[:]
            iv_trailed = contruct_attack_iv(iv_trailed, k, block_size - j)
            hex_str = convert_int_list_to_hex_str(iv_trailed, cipher)
            try:
                if padding_query(hex_str):  # 找到一个
                    if last_block and j == 15:
                        # 有填充的情况
                        iv_trailed = iv_construct[:]
                        iv_trailed[j - 1] = 0
                        iv_trailed = contruct_attack_iv(iv_trailed, k, block_size - j)
                        hex_str = convert_int_list_to_hex_str(iv_trailed, cipher)
                        if padding_query(hex_str):
                            print("j: {}, k: {}, result: True, content: {}".format(j, k, content_list))
                            content_list[j] = k
                            iv_construct[j] = iv[j] ^ k
                            break
                    else:
                        print("j: {}, k: {}, result: True, content: {}".format(j, k, content_list))
                        content_list[j] = k
                        iv_construct[j] = iv[j] ^ k
                        break
                else:
                    sleep(0.1)
            except ConnectionError as e:
                sleep(1)
            else:
                k += 1
        else:
            raise Exception("no valid padding found")
    return content_list


if __name__ == '__main__':
    cipher = 'f20bdba6ff29eed7b046d1df9fb7000058b1ffb4210a580f748b4ac714c001bd4a61044426fb515dad3f21f18aa577c0bdf302936266926ff37dbf7035d5eeb4'
    iv, cipher_list = split_iv_ciphers(cipher)
    result_list = list()
    for i in range(len(cipher_list)):
        if i == len(cipher_list) - 1:
            result_list.extend(padding_attack(iv, cipher_list[i], True))
        else:
            result_list.extend(padding_attack(iv, cipher_list[i]))
        iv = cipher_list[i]

    with open("result-test.txt", "wb") as f:
        pickle.dump(result_list, f)
    print("result: {}".format("".join(map(lambda x: chr(x), result_list))))
    print("done!")

结果

Week 4: CBC Padding Oracle Attack作业

引用

  • https://www.cnblogs.com/ntestoc/p/11044433.html
  • https://blog.csdn.net/csh1989/article/details/38457377?utm_source=blogxgwz7
相关标签: 密码学