继Javascript的挑战(securityoverridehackingchallenge 解题思路汇总——JavaScript)之后,今天来进行解密的训练。加密算法在安全领域中有着重大的意义,它是很多安全设计的前提保障,因此许多加密算法都以官方的形式被公布出来,并被广泛使用。不过针对加密算法的攻击属于研究性质的工作,不论加密算法或者破解加密算法的方法已经提出,基本不会有太大变动。实际攻击中,要么是利用加密算法的已知缺陷进行攻击,要么就是想办法寻找秘钥或者暴力破解。
对于自定义的加密算法,则需要具体情况具体分析,利用当前条件进行判断。理论上来说,加密算法的攻击情况分为以下四种。(加密算法默认为公开,在实际情况中,往往自定义的加密算法也无法获取,只能通过其他手段进行推测)
这四种情况的难度依次降低,也是衡量一个加密算法的标准。在密码学中,也给出来论证安全性的方法。这个内容涉及到的层次较深,这里就不做具体介绍了,有兴趣的可以自行了解。总得来说,了解密码学也是了解安全的一个基础,应当被每一位安全研究人员所熟知。
在SecuriytOverride中,这一系列的解密题并不困难,其重点更偏重于对加密以及哈希算法的介绍,同时也演示了一些糟糕的自定义加密方案。
ROT13算是一种公开的加密算法了,其字母对换表只有一种,因此实际上不具备加密功能。通常情况下用于使得某些文字不让小白用户明白。题目里也说了,它是一种经典的弱秘钥。
Base64属于编码而非加密。Base64能将任意的数据转换为基本的符号(26个字母大小写,10个数字,+和/符号),从而避免特殊字符或者编码问题导致接收方无法正确处理。解密工具网上很多,大部分的编程语言都自带这个编码和解码库。
二进制属于机器语言。在实际编程使用中,通常情况下使用ascii表做对应关系。使用python进行转换的方法查了一下(当然,你也可以手动分割,然后一个字母一个字母的来):
>>>import binascii
>>>bin(int(binascii.hexlify('hello'), 16))
'0b110100001100101011011000110110001101111'
In reverse:
>>>n = int('0b110100001100101011011000110110001101111', 2)
>>>binascii.unhexlify('%x' % n)
'hello'
In Python 3.2+:
>>>bin(int.from_bytes('hello'.encode(), 'big'))
'0b110100001100101011011000110110001101111'
In reverse:
>>>n = int('0b110100001100101011011000110110001101111', 2)
>>>n.to_bytes((n.bit_length() + 7) // 8, 'big').decode()
'hello'
破解Hash的算法很多,大多都是基于字典,彩虹表,以及一些随机算法等等。可以尝试寻找online的破解器(不过LM似乎比较冷门,大都不支持)。最直接的办法还是用John The Ripper,linux下最热门的密码破解器了。
将密文写入文件保存为password,然后运行”john password”,提示破解成功。接着执行”john password --show”,结果如下:
其中0125450为破解成功的明文,前面的?:是用来标识的(password文件内容应当为user:password,这里因为前面省去了,所以出来了问好)。
这题我是一边跑JohnThe Ripper,一边在google破解器,在搜了10多个后终于出来了一个结果。破解Hash这种事,还是得拼秘钥库或者彩虹表的大小的。
MD5属于经典的加密算法。不过目前已经有两种攻击方式被提出来:长度扩展攻击和冲突攻击。
长度扩展攻击:即利用Merkle–Damgard架构(分块加密,前一块的结果的后一块的秘钥)的设计缺陷,可以在不知道秘钥的情况下,对传输过程校验值MAC进行计算,从而被修改明文信息可以通过验证。当然,这种攻击可以利用的场景比较有限。
冲突攻击:目前已经可以利用工具快速的生成两端MD5值相同的文件(文件内容可指定任意前缀和后缀),因此MD5的校验性质不能得到保障。
直接google哈希值,结果就出来了,运气比较不错。
自定义的加密方案,不过给出了加密方法,算是选择明文攻击了。尝试加密,’a’=’/’,’aa’=’/f’,’aaa’=’/f/’。这样加密方式就很清楚了,根据单双位进行ascii上下偏移的替换,偏移量为5。解密的话,倒过来就行了。
稍加研究就可以发现,这题的加密算法是先进行异或,然后进行base64编码。异或的话,只要执行两次相同秘钥的加密就可以了。因此,这题其实比较简单,只需要将密文先base64解码,再放到加密方法中加密一次,再base64解码就可以了。
但是很蛋疼的是,第一次解码的过程中出现了non-ascii码的字符,即第一次解码的内容无法输入到加密方法中(大概可以用Javascript编码解决问题?)。这里我先输入AAAAAAAA进行加密,然后获取密文,异或得到秘钥(执行base64解码的过程中,保证输出为16进制文件)。得到秘钥就好办了,直接解密就好。需要保证以上操作全部当做int处理,最后再转回字符串,不然会出现麻烦。
一个更复杂的自定义加密方法,同样是选择明文攻击。初步尝试可得出以下表格:
a |
955128 |
aa |
9551289409128 |
b |
970128 |
bb |
9701289604128 |
ab |
9551289604128 |
ba |
9701289409128 |
aaa |
9551289409128955128 |
ccc |
9851289801128985128 |
ddd |
1000128100001281000128 |
eee |
1015128102011281015128 |
可以看出,这个加密都是以128作为结尾,单双位存在差异,但是不对其他位产生影响。从数字大小上来看,是按照ASCII顺序进行排列的。经过更多的尝试,发现字符与字符之间的偏差是不固定的,因此无法得出一个统一的规定的来。不过还好只是单个字符转换,可以一个个试着来,试的时候注意单双位的偏差即可。