• 新闻动态
  • 行业动态
  • 公司新闻
  • 关于我们
  • 公司简介
  • 经典活动
  • writeup
    cryptopals解密之旅 (三)
    2020-06-22 13:45

    0x00前言

    本系列文章将带来cryptocals 这套密码学挑战的write-up.不同于通过上课或者看书的方式学习密码学,这些题目来自于现在生活中一些软件系统和密码构造中的缺陷。

    本系列每一个题的wp基本是采用如下结构:题目解释、相关知识点讲解、代码实现及解释,运行测试。代码均采用python3实现,代码实现部分是参考国外大佬ricpacca的,结合自己的理解及成文需要进行部分修改。

    第二套一共有八关。

    第二套题目

    1.png

    主要是和分组密码相关的

    0x01

    先来看第9题

     2.png

    对于分组密码而言,通过会将整数的块的明文转为密文,但是我们一般碰到的消息长度不会是块的整数倍的,这时候就需要将其填充(padding)成块的整数倍大小。最流行的一种填充模式是PKCS#7

    题目要求我们用代码实现PKCS#7

     在分组加密算法中,进行分组时,划分后最后一组如果不够块大小时,需要填充,常见的填充模式有PKCS#5,PKCS#7。对于PKCS#5而言,明确定义Block的大小是8位,而在PKCS7Padding定义中,对于块的大小是不确定的,可以在1-255之间。

    填充字符串由一个字节序列组成,填充的字节都是一个相同的字节,该字节的值就是要填充的字节的个数。

    比如要填充7个字节,则需要填充7个0x7

    实现一个函数,用于进行PKCS#7填充。如果消息长度等于块大小的话,无需填充,直接返回;否则先计算需要填充的长度,然后将其附加在原消息之后

    3.png

    实现一个函数,用于判断数据是否经过PKCS#7填充。假设是正常实现的填充,将所填充的字符串存入padding,然后根据“填充的字节都是一个相同的字节,该字节的值就是要填充的字节的个数“进行检查。如果检查通过,则是经过PKCS#7填充的。

    4.png

    可以对应实现一个函数,实现逆PKCS#7填充,也就是将被填充的数据还原,通过is_pkcs_padded函数检查,如果没被填充过则直接返回,如果被填充过,则直接截取被填充后的字符串的前一部分(即原始数据)返回

    5.png

    完整代码及执行结果如下

    6.png

    顺便使用断言测试pacs7_unpad是否可用

    7.png

    没有报错,说明正常执行

    实验推荐--CTFCrypto练习之分组密码 

    (通过本实验的学习,你能够了解CTF竞赛中的密码学题型,掌握分组密码以及AES加密算法,学会分组密码ECB模式的攻击方法)

    0x02

    第10题

    8.png

    要求我们实现CBC模式,并对给出的文本文件进行解密。并提示我们复用之前写过的EBC代码(不过此时是写加密的函数)和XOR代码。还给出了密钥和IV

    这里涉及的知识点是CBC模式

    其中文全称是密码分组链接模式(Cipher Block Chaining (CBC))

    这种模式是先将明文切分成若干小段,然后每一小段与初始块(IV)或者上一段的密文段进行异或运算后,再与密钥进行加密。如下所示

    9.png

    实现ASES-ECB加密函数。数据加密前常需要PKCS#7填充。

    0.png

    异或函数

    11.png 

    实现AES-CBC加密函数,其接收的参数就是明文、密钥、IV

    分块进行处理,分块后先进行填充padding,再进行与IV或上一个密文块进行异或,然后AES-ECB加密(即前面将CBC实现图中的加密器部分),接着处理下一块

    12.png

    实现AES-CBC解密函数,可以返回填充或未填充的明文。同样需要分块进行,和加密函数倒着来就行,先AES-ECB解密,然后XOR。

    13.png

    14.png

    完整代码及执行后得到的明文如下

    15.png

    实验推荐--CBC字节翻转攻击 

    (通过该实验了解CBC模式实现流程、异或运算的高级应用、python中crypto库的使用以及cbc字节翻转攻击的原理与代码实现)

    0x03

    第11题

    16.png

    要求写一个函数实现生成随机的16字节AES 密钥

    写一个函数根据随机密钥进行加密,在加密前在明文的前后各添加5到10字节随机值,随机选取加密方式为ECB或CBC,如果是CBC,还需要选择随机的IV

    要求我们能够写一个函数,能够判断某个被加密的块是使用CBC还是ECB模式

    根据填充后明文,随机生成的key,随机决定采用的模式(ECB或CBC)进行加密,如果是CBC的话,其IV也是随机的,所以用Random.new()

    该数据填充上5到10字节随机数作为前缀和后缀

    17.png

    根据count_aes_ecb_repetitions返回的结果来判断是ECB还是CBC加密模式

    18.png

    我们选择重复的输入数据,这样我们就可以结合ECB的特点来探测其是否为ECB模式,不是ECB则是CBC模式。

    19.png 

    完整代码及执行断言结果如下

    20.png

    没有报错,说明写的这些函数都能成功执行。

    0x04

    第12题

    21.png

    该函数使用ECB模式,使用同一个但是未知的key

    在加密前,在明文后附加给出的字符串(在附加之前先对该字符串base64解密我们有一个函数可以计算AES-128-ECB(your-string || unknown-string, random-key),而ECB Byte at a time技术可以让我们需要控制your-string,就可以在不知道random-key的情况下得到unkown-string。

    基本流程如下:

    1.将相同的字符串字节传入函数1,从传入1个字节(A)开始,然后AA,AAA。。。直到找到密文的块的大小

    2.测试加密模式是否为ECB

    3. 知道块的大小后,设计一个恰好少1字节的输入块(例如,如果块大小为8字节,则输入“ AAAAAAA”)。思考一下oracle函数将在最后一个字节位置放置什么。

    4. 通过将不同的字符串输入到oracle中,为每个可能的最后一个字节创建字典;例如“ AAAAAAAA”,“ AAAAAAAB”,“ AAAAAAAC”,记住每个调用的第一个块。

    5. 将one-byte-short输入的输出与字典中的一项匹配。 现在,我们就已经发现了unknown-string的第一个字节。

    6.针对下一个字节继续重复

    这里的原理还是基于ECB模式自身缺陷

    假设我们有aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab,16字节分组后如下所示

    22.png

    对于前两个块,他们的输入都是16个a,他们对应的输出是一样的。也就是说相同输入会有相同输出,我们就可以根据这一点进行攻击。

    举个实际生活中的例子,假设找到一个网站,它的会话cookies是这么生成的:

    AES_ECB(USERNAME + SECRET, KEY),我们作为攻击者可以任意改变username,得到不同的密文。作为攻击者,我们想要得到secret。来看看我们是怎么攻击的。

    首先我们将15个a作为username,得到密文

    23.png

    可知作为一个16字节大小的块,第16字节是来自secret的未知字符

    接下来暴力测试第16个字节的可能值,将得到的相应密文与上图的密文对比

    24.png

    如上所示,当第16字节为c时,生成的密文和之前得到的密文是相同的,所以我们就知道secret的第1个字节是c了。

    接下来我们设置username为14个a,则在构造块时,第15字节是secret的第一个字节c,那么第16个字节自然是来自secret的第二个字节,暂时未知,同样可以得到密文

    25.png

    然后暴力测试第16个字节的可能值

    26.png

    第16个字节为o时,密文才是一样的,所以可知secret的第二个字节为o

    以此类推,就可以得到secret的明文了

    回到题目本身,我们来看看如何实现

    填充后使用AES-128-ECB模式加密

    27.png

    该函数用于返回encryption_oracle使用的块密码的块长度。

    要找到一个块的长度,我们将加密越来越长的明文,直到输出密文的大小也增加为止。发生这种情况时,我们可以轻松地计算出一个块的长度,其值等于新的密文长度与其初始长度之间的差。

    28.png

    该函数用于获取依次获取unknown-string的下一个字节,这个函数是本题的关键。

    首先计算要用作输入的字符数,以使unkown-string的第一个未知的字符置于块的末尾。接着计算我们从伪造的密文和实际密文得到的字节数,进行比较,这个值在后面的密文比较中用于截取数据。然后计算实际的密文。之后是暴力尝试,通过比较密文,来找到待求的字符

    29.png

    获取块长度,通过判断密文中是否有重复的字符串来判断是否为ECB模式。然后获取要解密的字符数量,其值等于我们加密空信息时得到的密文长度。该值在最后的循环中会用到,在循环体里,一个字符一个字符地操作。

    30.png

    完整代码及执行结果如下:

    31.png

    可以看到成功拿到了unknown_string的明文

    也可以使用断言测试

    32.png

    参考:

    1. https://cryptopals.com/sets/1

    2. https://github.com/ricpacca/cryptopals

    上一篇:PlaidCTF2020 Mooz Chat 复盘
    下一篇:“第五空间”智能安全大赛部分WP
    版权所有 合天智汇信息技术有限公司 2013-2020 湘ICP备14001562号-6
    Copyright © 2013-2020 Heetian Corporation, All rights reserved
    4006-123-731