文章回顾:
0x00前言
本系列文章将带来cryptocals 这套密码学挑战的write-up.不同于通过上课或者看书的方式学习密码学,这些题目来自于现在生活中一些软件系统和密码构造中的缺陷。
本系列每一个题的wp基本是采用如下结构:题目解释、相关知识点讲解、代码实现及解释,运行测试。代码均采用python3实现,代码实现部分是参考国外大佬ricpacca的,结合自己的理解及成文需要进行部分修改。
第二套一共有八关。
第二套题目
主要是和分组密码相关的
第13题
要求写一个函数profile_for,传入profile_for("foo@bar.com"),会生成
编码为email=foo@bar.com&uid=10&role=user
注意,不需要编码@,&等符号
接着生成随机的AES密钥,然后用这个密钥加密编码后的用户信息,再解密得到编码的结果,然后解析编码的结果。
题目要去我们仅使用user和密文,要求进行攻击,使得解密,解码后得到的role是admin,而不是user
这种攻击方法的原理利用的是ECB模式分块单独加密,之后按照顺序将计算所得的数据连在一起即可,各段数据之间互不影响的特点。通过将故意构造的密文替换原密文,从而篡改解密后的信息。
具体代码如下:
定义加密函数,使用AES-128-ECB加密编码过的用户信息,以及对应的解密函数
使用key=value键值对的格式将字典对象编码为字符串,比如将
{
foo: 'bar',
baz: 'qux',
zap: 'zazzle'
}
编码为
foo=bar&baz=qux&zap=zazzle
同样写一个对应的解码函数,将key-value格式解码为字典格式
给出email地址,按指定规则进行格式化,下图中的replace是为了删除原有的&,=
下图的函数是关键,通过cut-and-paste攻击,将部分user的原密文替换成admin的。然后返回重新组合后的密文。
第一次加密的明文分为三个块,第一个块为email=xx..xx将这个填充成一个块,第二个块为admin,然后根据pkcs#7填充规则,还需填充11个\x0b,第三个块为&uid=10&role=user
第二次加密的明文分为三个块。
第一个块为email=master@me.,
第二个块为com&uid=10&role=,
第三个块为user\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c
接下来我们组合三个块成新的密文,
第一个块为email=master@me.,
第二个块为com&uid=10&role=,
第三个块为admin\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b。函数返回的就是这三个块组成的密文。
该密文被解密,然后解码后,得到的role就会是就会是admin而不是user
完整代码及执行结果如下所示
第14关
这一关比第12关难度大。要求我们生成随机数量的随机字符,作为明文的前缀。
还是要求我们拿到target-bytes的明文
思路就是:
1.首先找到块长度、加密模式,这些在12题里实现过了
2.找到前缀长度
3.一次一个byte解密target-byte,这在12题也实现了
加密函数加密的内容就是随机前缀+可控字符串+未知字符串
找到target-byte的一个字节。填充length_to_use个a,保证将块的最后一个字符设置为target-byte的第一个字符。然后计算我们将截取多少个字节进行比较,这个值在后面比较假的密文和实际密文时会用到。计算实际密文,然后暴力测试每个可能的字符,将每个可能字符加密后得到的密文与实际密文比较
检查给出的密文是否包含两个连续的相同块
计算前缀的长度。首先找到前缀在哪个块结尾,然后找到前缀结尾的精确位置,就可以计算出前缀的长度
首先分别加密空消息和一个字符的消息,得到两个密文。比较这两个密文,第一个不同的块就是前缀结束的块。然后需要精确定位是在前缀是在哪个位置结束的。
加密“两个块长度+一个随机增量”长度大小的相同的字节,如果字节数足够了(在密文中找到了两个连续的相同块),我们就可以精确计算前缀在其最后一个块中结束的位置。其在最后一块中结束的位置为块长度-i
找到块长度,判断是否为ECB模式,计算出target-byte的长度,这就是循环的次数。在循环中调用get_next_byte来计算。target-byte长度等于加密空字符串后的长度减去前缀长度
完整代码及执行结果如下
拿到了target-bytes的明文
第15题
要求实现一个函数,可以检测一段明文是否为pkcs#7填充,如果是话则去掉填充,不是的话则报异常
这个函数在s2p9.py中已经实现过了,这里不再重复。
第16关
cbc翻转攻击,这个知识点在CTF中也有出现过,那么我们看看脱去CTF的外衣,其本质是怎样的
题目要求首先生成随机的AES密钥
写一个函数接收任意输入字符串,加上前缀"comment1=cooking%20MCs;userdata=",加上后缀";comment2=%20like%20a%20pound%20of%20bacon",去掉;和=
然后,该函数应将输入填充到16字节AES块长度,并在随机AES密钥下对其进行加密。
写一个函数解密该字符串并查找“; admin = true; “。根据字符串是否存在,返回true或false。如果上一个函数正确实现,则第二个函数会返回false。实际上,可以进行cbc翻转攻击,使其返回true。我们通过修改密文来实现这一点(无需密钥)。
CBC翻转攻击技术可以通过修改密文来操纵解密后的明文。其原理就是如果对初始化向量中的任意比特进行反转,则明文分组中相应的比特也会反转,其原因是第一个明文分组会和初始化向量进行异或运算。
这样我们所要做的就是对初始化向量进行攻击。
在下面的cbc_bit_flip中我们攻击的就是;和=
代码实现:
实现加密函数,添加前缀和后缀后,使用AES-128-CBC进行加密
实现解密函数,还会检查解密后的内容中是否有;admin=true;
计算块长度。要找到一个块的长度,我们需要加密越来越长的明文,直到输出密文的大小也增加为止。发生这种情况时,我们可以轻松地计算出块的长度,其值等于新的密文长度与其初始长度之间的差
计算前缀的长度。
加密两个不同的明文字节,得到两个不同的密文,计算两个密文间相同的长度,赋给common_length,确保其为块长度的整数倍。
从1开始将越来越多的相同字节添加到明文中,分别加密,比较两个密文,直到它们有一个额外的相同块为止。如果找到了,这意味着通过添加i个字节,我们可以控制相同的输入(包括前缀)为块大小的整数倍,这样我们就可以得到前缀的长度了。
cbc翻转攻击的关键函数
首先得到块长度和前缀长度,接着计算需要添加多少字节到前缀,才能使得其长度为块长度整数倍,接着计算要添加多少字节到明文才能使得其长度为块长度整数倍。然后将明文加长1个块长度(用?填充),对其加密。使用异或的方法,我们可以通过更改明文之前的块的字节来生成所需的字节。最后将伪造的密文片段放在一起,组成完整的密文
完整代码及执行结果如下
可知,在解密之后的明文里确实找到了; admin = true;,返回了true
参考:
1.https://cryptopals.com/sets/1
2.https://github.com/ricpacca/cryptopals