填充提示攻击--破解CBC模式的AES加密

填充提示攻击--破解CBC模式的AES加密

本文参考
Padding Oracle Attack(填充提示攻击)详解及验证

今天看shiro的历史漏洞的时候看到了这样的内容
shiro 550 主要利用的就是shiro cookie中的rememberme字段在服务端解析的时候会经过base64解码-AES解密-反序列化的过程,既然存在反序列化的函数,那么就可能存在发序列化的漏洞,那么要实现反序列化的利用条件,上述的 三个过程中比较难控制的就是我们不知道AES加密方式的秘钥是多少。而该漏洞发生的位置正好就在这儿,在shiro 1.2.24版本以下,AES的解密秘钥是硬编码在代码中的,而shiro是一个开源程序,那么我们就可以收集各个版本的秘钥咯,然后挨个秘钥尝试,如果成功解密的话服务端会返回200,解密失败的话会返回500,通过观察返回的状态码就可以判断当前的秘钥,然后构造序列化字符串进行getshell 或者执行命令。
shiro 721 这个漏洞可谓是通杀了!!原理和shiro550是一样的,不过不需要知道AES的秘钥,只需要暴力猜解明文与密文就好了,通过观察服务端返回状态码,来判断解密是否成功,从而构造payload进行攻击,这个shiro 721就是填充提示攻击padding oracle attacking
我们来看看这种方式为啥能够成功
shiro使用的AES加密模式是CBC,这种加密模式的加密过程是这样的。
需要两个关键数据,一个是秘钥,一个是IV invoke vector—初始向量,初始向量的存在保证了即便是同一个秘钥加密同一份数据也会得到不同的加密结果。具体是这样的,AES加密前会先对原始明文数据进行分组,比如按照8个字节分为一组,那么明文数据最后一组可能就凑不够8个字节,那么不足的部分就要使用数据进行填充,填充的规则是,如果有N字节不足,那么就填充N个0x0N。然后通过我们的IV对每个分组进行异或操作,得到一个中间值,然后使用秘钥对该中间值进行加密变换得到第一组明文的加密结果,然后将该加密结果作为第二组明文的IV,依次循环直到最后一组明文被加密完毕,可以想象如果要解密,我们得知道IV,所以该IV被连同所有的密文一起传输,保存在了最终结果的第一组,就是说最终的计算结果的第二组开始才是正经的密文。
解密的过程就是加密的逆向。
那么我们又是怎样猜解密文还原明文的呢?
我用我的参考文章中的例子
现在我们有这样一个url

http://www.example.com/decrypt.jsp?data=7B216A634951170FF851D6CC68FC9537858795A28ED4AAC6

后面那一串就是密文,现在进行分组

初始化向量: 7B 21 6A 63 49 51 17 0F
第一组密文: F8 51 D6 CC 68 FC 95 37
第二组密文: 85 87 95 A2 8E D4 AA C6

我们应该怎样破解第一组密文的明文呢?
首先我们构造这样的url

http://www.example.com/decrypt.jsp?data=00000000000000000F851D6CC68FC9537

将第一组密文的初始化向量全部设置为0,然后访问,很明显服务端会响应500,因为我的IV错了,在进行解密的时候,服务端首先用自己保存的AES秘钥对密文进行解密得到中间值,然后将中间值与IV进行异或运算得到明文,然后在检查明文的填充字节的时候发现最后一个字节的值与填充的位数不匹配,所以解密失败!!要解密成功则需要最终的解密结果满足填充的规则。那么这时候应该怎么办呢?假设正确的填充字节只有一个,我们可以这样,依次遍历我们IV的最后一个字节从0x01-0xFF,直到最终的解密结果的明文的最后一个字节为0x01,此时就算解密成功了,服务器会返回200或者302的响应码,因为虽然解密成功了,但结果不满足服务端的处理逻辑,所以会出现203的结果,此时我们就知道了IV的最后一个字节和填充字符,这时候将二者进行异或操作就可以得到中间值的最后一个字节,然后我们可以通过同样的方式猜解出来前面的中间值,直到获得完整的中间值。也就是假设填充值有2个字节,那么填充值就是0x02 0x02 ,这个时候我们已经知道了中间值的最后一个字节,将其与0x02进行异或将得到IV的最后一个字节,这时候只需要将IV的倒数第二个字节从0x01-0xFF进行遍历再与解密后的密文进行异或得到值为0X02,此时的IV值即是正确的,再将IV与填充字符进行异或就得到了中间值的第二个字节。依次计算直到计算出所有。在猜出了所有的中间值之后,再将其与IV进行异或操作即可得到第一组密文的明文结果。解密也就完成了,然后将第一组的密文作为第二组密文的IV对第二组密文进行解密。
这是解密的过程,至于加密的过程,文章中没有详细讲。就让我在睡梦中想一想怎么整吧!!!!!

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是Java实现AES加密填充模式为AES/CBC/ZeroBytePadding的示例代码: ```java import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.util.Base64; public class AesUtil { private static final String CIPHER_ALGORITHM = "AES/CBC/ZeroBytePadding"; public static String encrypt(String data, String key, String iv) throws Exception { byte[] byteKey = key.getBytes("UTF-8"); byte[] byteIv = iv.getBytes("UTF-8"); SecretKeySpec keySpec = new SecretKeySpec(byteKey, "AES"); IvParameterSpec ivSpec = new IvParameterSpec(byteIv); Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); byte[] encrypted = cipher.doFinal(data.getBytes("UTF-8")); return Base64.getEncoder().encodeToString(encrypted); } public static String decrypt(String data, String key, String iv) throws Exception { byte[] byteKey = key.getBytes("UTF-8"); byte[] byteIv = iv.getBytes("UTF-8"); SecretKeySpec keySpec = new SecretKeySpec(byteKey, "AES"); IvParameterSpec ivSpec = new IvParameterSpec(byteIv); Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(data)); return new String(decrypted, "UTF-8"); } } ``` 使用方法如下: ```java public static void main(String[] args) throws Exception { String data = "Hello, World!"; String key = "0123456789012345"; String iv = "0123456789012345"; String encrypted = AesUtil.encrypt(data, key, iv); String decrypted = AesUtil.decrypt(encrypted, key, iv); System.out.println("Encrypted: " + encrypted); System.out.println("Decrypted: " + decrypted); } ``` 注意事项: - key和iv的长度必须为16字节; - 使用ZeroBytePadding填充模式时,原始数据长度必须为16字节的倍数,否则会抛出异常。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值