前言

1、在ECB模式的基础上,增强了块与块之间的联系。
2、明文块先与IV XOR运算后,在进行加密,得到的密文充当下一个明文区块的IV...
3、明文块填充方式,如果明文为abcd,长度为4,则需要填充12位,12的十六进制为\x0C,在最后加密的明文为abcd\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C

加密

upload successful

解密

upload successful

利用

padding Oracle attack

密文最后一个区块通过block cipher encryption解密,得到中间密文中间密文IV异或得到明文。

如果输入错误的IV,也是可以解密的,但是中间密文错误的IV异或后得到的填充值可能出现错误,那程序就会抛出(Padding Error)。

  • 第一步:填充错误

upload successful

  • 第二步:填充正确,填充为01

upload successful

  • 第三步:填充为0202

upload successful

  • 后续

    正确的padding值只可能为:
    1个字节的padding为0x01
    2个字节的padding为0x02,0x02
    3个字节的padding为0x03,0x03,0x03
    4个字节的padding为0x04,0x04,0x04,0x04

    ……

  • 以此类推,可以推导出所有的中间密文中间密文的第一位需要爆破

  • 控制IV可以将密文解密成任意明文(现在已知中间密文、可控IV)

例子
// index.php
<?php
error_reporting(0);
include('./key.php');
define("METHOD", "aes-128-cbc");
define("SECRET_KEY", $secret_key);
session_start();

function get_random_token(){
    $random_token='';
    for($i=0;$i<16;$i++){
        $random_token.=chr(rand(1,255));
    }
    return $random_token;
}

function get_identity()
{
    $defaultID = "heheda";
    $token = get_random_token();
    $_SESSION['id'] = base64_encode(openssl_encrypt($defaultID, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $token));
    setcookie("token", base64_encode($token));
    $_SESSION['isadmin'] = false;
}

function is_admin()
{
    if(isset($_SESSION['id'])){
        $token = base64_decode($_COOKIE['token']);
        if($id = openssl_decrypt(base64_decode($_SESSION['id']), METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $token)){
            if($id == "admin")
                $_SESSION['isadmin'] = true;
        } else {
            die("Error!");
        }
    }
}

if(!isset($_SESSION['id']))
    get_identity();
else {
    is_admin();
    if ($_SESSION["isadmin"]){
        echo "You are admin!\n";
        echo $flag;
    }else
        echo "You are not admin!\n";
}
highlight_file(__file__);
?>

// key.php
<?php
session_start();
$secret_key = 'teg2f4z5f7f5a2c1';
$flag = "flag{padding_oracle_attack_is_easy}";
?>
  • 分析代码,可以看到关键点

    upload successful

    解密时,如果出现Padding Error,则网页会显示Error!,否则会判断解密后的明文是否为admin。

  • 判断中间密文的最后一字节

    import requests
    import base64
    
    url = 'http://127.0.0.1/index.php'
    
    for i in range(1,256):
        token = '\x00'*15 + chr(i)
        cookie = {'token':base64.b64encode(token).replace("=","%3d").replace('/','%2f').replace('+','%2B'),"PHPSESSID":"gaqekj8shscuprbvdfim9hcgj0"}
        if "Error!" not in requests.get(url,cookies=cookie).content:
            print hex(i)
    

    upload successful

    这样就可以知道中间密文的最后一字节为0x3b ^ 0x1 = 0x3a

  • 判断中间密文的倒数第二个字节

    import requests
    import base64
    
    url = 'http://127.0.0.1/index.php'
    for i in range(1,256):
        token = '\x00'*14 + chr(i) + chr(0x3b^0x1^0x2)
        cookie = {'token':base64.b64encode(token).replace("=","%3d").replace('/','%2f').replace('+','%2B'),"PHPSESSID":"gaqekj8shscuprbvdfim9hcgj0"}
        if "Error!" not in requests.get(url,cookies=cookie).content:
            print hex(i)
    

    upload successful

    这样就可以知道中间密文的最后一字节为0x1a ^ 0x2 = 0x18

  • 判断中间密文的倒数第三个字节

    import requests
    import base64
    
    url = 'http://127.0.0.1/index.php'
    for i in range(1,256):
        token = '\x00'*13 + chr(i) + chr(0x1a^0x2^0x3) + chr(0x3b^0x1^0x2^0x2^0x3)
        cookie = {'token':base64.b64encode(token).replace("=","%3d").replace('/','%2f').replace('+','%2B'),"PHPSESSID":"gaqekj8shscuprbvdfim9hcgj0"}
        if "Error!" not in requests.get(url,cookies=cookie).content:
            print hex(i)
    

    upload successful

    这样就可以知道中间密文的最后一字节为0xd2 ^ 0x3 = 0xd1

  • 以此类推

    import requests
    import base64
    
    url = 'http://127.0.0.1/index.php'
    token_temp = ''
    for j in range(1,17):
        for i in range(1,256):
            token = '\x00'*(16-j) + chr(i) + token_temp
            cookie = {'token':base64.b64encode(token).replace("=","%3d").replace('/','%2f').replace('+','%2B'),"PHPSESSID":"gaqekj8shscuprbvdfim9hcgj0"}
            if "Error!" not in requests.get(url,cookies=cookie).content:
                token_temp = chr(i ^ j ^ (j+1)) + token_temp
                temp = ''
                for i in range(1,len(token_temp)):
                    temp += chr(ord(token_temp[i]) ^ j ^ (j+1))
                token_temp = token_temp[0] + temp
                break
    
    middle = ''
    for i in range(len(token_temp)):
        middle += chr(ord(token_temp[i]) ^ 16)
    
    for i in range(1,256):
        temp_middle = chr(i) + middle
        plain = 'admin' + '\x0b'*11
        token = ''
        for i in range(len(plain)):
            token += chr(ord(temp_middle[i]) ^ ord(plain[i]))
        cookie = {'token':base64.b64encode(token).replace("=","%3d").replace('/','%2f').replace('+','%2B'),"PHPSESSID":"gaqekj8shscuprbvdfim9hcgj0"}
        if 'admin' in requests.get(url,cookies=cookie).content:
            print requests.get(url,cookies=cookie).content
            break
    

    upload successful



padding oracle attack

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!