0%

CBC字节翻转攻击

0x00前言

web有关CBC的题偶尔就出现,老是忘,要经常复习QWQ,这里总结一下翻字节攻击

0X01 分析

CBC解密过程:

image.png

需要知道的点

aes-cbc 是分组加密,一般16个字节一组一块,iv也为16字节
中间值是指密文块解密之后的数据
iv会与第一组中间值异或最后得到明文,往后则是每一组的密文与下一组的中间值

例如iv的第5位改变,那么第一组解密明文的第五位也会被改变

往后则是,如果第一组密文的第5位改变,就会影响到第二组解密出来的明文的第5位(16位一组就是第21位被改了),以此类推

0x02测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?php

define("METHOD","aes-128-cbc");
define("SECRET_KEY", "17a8922b-11c1-11ea-bace-f430b9537591");


function get_random_token(){
$random_token='';
for($i=0;$i<16;$i++){
$random_token.=chr(rand(1,255));
}
return $random_token;
}
$iv = get_random_token(16);
$info = '{"role_id":3,"user_id":1,"name":"tinmin"}';
$c = openssl_encrypt($info, METHOD, SECRET_KEY, OPENSSL_RAW_DATA,$iv );

//change role_id:1

echo "cipher: ".base64_encode($c).PHP_EOL;
echo "iv: ".base64_encode($iv ).PHP_EOL;

$newiv1 = $iv;
$newiv1[11] = $iv[11] ^ '1' ^ '3';
echo "plain: ".openssl_decrypt($c,METHOD,SECRET_KEY,OPENSSL_RAW_DATA,$newiv1 ).PHP_EOL;


//change user_id=2
$c[8] = $c[8] ^ '1' ^ '3'; //改23位对应的上一组也就数8
$plain = openssl_decrypt($c,METHOD,SECRET_KEY,OPENSSL_RAW_DATA,$iv );
echo "plain: ".$plain.PHP_EOL;
$group1 = '{"role_id":1,"us';
$newiv2 = "";

for($i=0;$i<strlen($group1);$i++){
$newiv2 .= $group1[$i] ^ $iv[$i] ^ $plain[$i];
}
echo "plain: ".openssl_decrypt($c,METHOD,SECRET_KEY,OPENSSL_RAW_DATA,$newiv2 ).PHP_EOL;

分组情况:

1
2
3
{"role_id":3,"us
er_id":1,"name":
"tinmin"}

修改第一组

第一次为了修改role_id,将其修改为1,数了一下,它是第12位,于是修改iv的第12位

我们知道

1
a ^ a ^ b = b

我们知道原来的值为3,那么就有

1
$iv[11] = $iv[11] ^ '1' ^ '3';

解密出来

1
{"role_id":1,"user_id":1,"name":"tinmin"}

可可可

修改第二组

第二次为了修改user_id,将其修改为3,数了一下,它是第23位,是第二组的第8位,于是修改第一组密文的第8位

就有

1
$c[8] = $c[8] ^ '1' ^ '3';

解密出来前面乱码

1
F���9f�󨪴 �er_id":1."name":"tinmin"}

为了恢复正常,我们要修改iv,来达到修改第一组密文的目的

目标字符串为

1
{"role_id":3,"us

生成新的iv

1
2
3
4
$newiv2 = "";
for($i=0;$i<strlen($group1);$i++){
$newiv2 .= $group1[$i] ^ $iv[$i] ^ $plain[$i];
}

解密

1
{"role_id":1,"user_id":1."name":"tinmin"}

正常了