2020湖湘杯-CRYPTO-简单的密码3 WriteUp (CBC字节翻转)
前言
第六届湖湘杯的密码学 简单的密码3
这道题考察CBC字节翻转。
CBC模式
CBC是一种分组加密模式,CBC模式中,每一组的密文由上一组的密文参与异或运算得到。
CBC字节翻转攻击就是根据CBC解密过程中的异或关系,改变上一组密文,从而使下一组解密得到的明文达到特定的值。
加密过程
第一组明文经过初始化向量IV异或,然后经过块加密算法使用密钥Key加密,得到第一组密文。然后这一组密文又和下一组明文异或,再经过块加密算法加密,得到下一组密文,以此类推。
CBC模式中分组的长度,根据所用块加密算法的不同而有区别,比如AES-128的分组长度就是16字节。
块加密算法一般是AES、Blowfish、DES、Triple DES等对称加密算法。
初始化向量IV的长度等于分组长度,用于对加密进行随机化。加密时,IV可以影响到所有数据的加密结果。
CBC加密的数学公式为:(\(E_k\)表示块加密)
解密过程
第一组密文经过块加密算法使用密钥Key解密后,再经过初始化向量IV异或,得到第一组明文。第二组密文经过解密后,与第一组密文异或,得到第二组明文。以此类推,每一组明文都是由前一组密文参与异或运算得到的。
解密时,IV只能影响第一组数据的解密结果。
CBC解密的数学公式为:(\(D_k\)表示块解密)
CBC字节翻转攻击
通过改变前一组密文,使得其在与后一组密文的块解密结果异或后,得到特定的明文。
具体为:
假设某一组明文原来是\(P_1\),现在要将它变成\(P_2\),该组密文的块解密结果为\(D_c\),前一组密文原来是\(C_1\),需要将前一组密文构造为\(C_2\),
根据异或运算的性质:
若
\(a \oplus b = c\)
则
\(a \oplus c = b\)
由于
可得
因此只要将前一组密文替换为\(C_2\),就可以让后一组明文变成\(P_2\)。
由于改变了一组密文后,该组明文也会发生改变,要想使该组明文不变,执行相同的操作即可(修改前一组密文)。
题目
本题用nc连上后,给你三个选项,先输入用户名登陆,然后可修改iv,然后可获取flag。
直接选flag,会提示只有admin才能获取flag。输入用户名为admin,又提示error。
其实看到iv就可以猜测这个题是考CBC了。
这里用CBC反序列化,先输入一个用户名,然后输入iv使得用户名解密后成为admin。
输入iv时可以看到,iv的长度是16字节,因此明文第一组的长度也是16字节。
输入用户名时,可知加密内容是"name:"+用户名
,总长度不超过16字节,因此用户名在第一组明文中。我们只要修改iv就可以使用户名的解密结果成为admin。
假设原来的iv是\(IV_1\),要构造的iv是\(IV_2\),第一组的块解密结果是\(D_c\),原明文是\(P_1\)(输入的用户名),要修改为\(P_2\)(admin)。
由于
可得
注意这里第一组明文的前五个字节是"name:",我们输入的用户名从第六个字节开始,因此对iv的修改也应该从第六个字节开始。比如输入用户名为"world"的话,就应该修改iv中的第6到10个字节。
python脚本为:
iv1 = 'b1652f353cc1eac21e1e812fc0d51d7e'
p1 = 'world'
p2 = 'admin'
iv2 = ''
n = 0
for i in range(10,20,2):
iv2 += hex(int(iv1[i:i+2],16)^ord(p1[n])^ord(p2[n]))[2:]
n += 1
print(iv1[:10]+iv2+iv1[20:])
得到iv:
输入用户名和iv就可以获取flag。
(由于比赛结束后,平台关闭,无法复现,这里用的是船山院士师傅们的wp中的图)