bugku-login4-CBC字节翻转攻击

CBC模式:Cipher Black Chaining mode(密码分组链接模式)

CBC模式进行加解密是都需要一个随机初始向量iv,在第一轮进行加解密是都需要与iv进行xor的。

 


 

1.加解密过程

0x01:加密过程如下图(来自《图解密码技术》一书)

 0x02:解密过程(来自《图解密码技术》一书)

CBC模式的加密过程主要分为这几步:

  1. 将明文分为若干组(16个字节为一组),最后一组不足则用特殊字符填充

  2.生成一个初始向量iv和密钥

  3.用iv与第一组明文异或(iv只影响第一组生成的密文)

  4. 然后再用前n组密文与后n+1组明文异或生成第n+1组密文,以次重复

  5.最后将生成的密文拼接起来,就成了最终密文

 

CBC模式的解密过程主要分为这几步:

  1.将密文分组

  2.用iv与第一组密文xor,解密得到第一组明文

  3.用第n组密文与第n+1组密文xor,解密得到第n+1组明文,以此类推

  4.将各组的明文拼接在一起就是最终要得到的明文了

 

这里注意一下:解密的时候前一组密文只影响后一组明文的结果,而不会影响其他组明文的结果,由图也可看得出,这个也是进行攻击的重要之处。

 

2.CBC字节翻转攻击:

我们需要改变前一组密文的一个字节,然后与下一组的密文异或,我们就可以得到一个不同的明文了,从而就能达到攻击的效果。如图:

举个例子:

我现在有个明文序列:helloworld,现在我以它2个字节为一组进行分组(一般是16个字节为一组,但是这里为了方便起见就以2个字节为一组了)

第一组:he

第二组:ll

第三组:ow

第四组:or

第五组:ld

现在我想把第三组 “ow”中的o翻转为x,那么我们就需要改变第二组的密文从而改变第三的明文

phaintext="helloworld"

enc=encrypt(phaintext)

enc1=chr(ord(enc[5])^ord("o")^ord("x"))  #enc[5]即是与“o”相同比特位的密文,也就是说第三组只有"o"这个比特位受影响,而“w”不受影响

result=decrypt(enc1)

这里注意一下:任何字符与本身xor都是为0,任何字符与0xor都为本身,如A xor A=0,A xor 0=A

3.实战—bugku-login4

打开是一个登陆界面,随便输入一个账号密码就能登陆,但是admin不能登陆。

抓包发现,有个iv和cipher,猜测是CBC模式的加密

 

扫描一波发现有源码泄露

vim -r index.php.swp恢复后得到源代码,审计关键代码

这里对usernmae进行了检测只有admin才能看得到flag,但是admin又不允许登陆,这里看起来有点矛盾,但是我们再看看前面的代码,这个对登陆信息进行序列化然后用CBC模式的加密方式进行加密最后base64_encode,然后我们要做的是以admin的身份登陆,我们可以操作cookie中的iv和cipher进行CBC字节翻转攻击。

 

然后我们以账号为admia,密码为12345登陆

得到的明文是:a:2:{s:8:"username";s:5:"admia";s:8:"password";s:5:"12345"}

然后16个字节分组得到

s:2:{s:8:"userna

me";s:5:"admia";

s:8:"password";s

:3:"12345";}

所以我们要翻转的是第二组的“a”翻转为“n”,所以我们要改变第一组的密文从而达到攻击的效果

 代码如下

 

1 import base64
2 cipher="yQQeUDxlzRvPToe631KV1vcy8DyI4e0kz7Knb9K6GIH4yP8Q32kufQvWoD7oN3hzi2EpiBxx6t/7sfIH1pCExg=="
3 plain=base64.b64decode(cipher)
4 result=plain[0:13]+chr(ord(plain[13])^ord("n")^ord("a"))+plain[14:]
5 print base64.b64encode(result)
6 #print R0dGVia+fJ24Ei3t29NC90P5kRbHXnW+D690WNWHnATH3UHvC4h+btceizE5jotDgG0QZLa9LOdwSAg9LcsCdw==

 

 

 

  POST过去提示不能正常反序列化,因为我们修改了第一组的密文,导致第一组的密文与iv xor会出错,从而导致了第一组明文不能正常解密,所以我们还要对iv进行修改

代码如下(由于我中途输入错了iv,所以代码中的iv和cipher和图中可能会不一样,但是思路是一样的):

注意一下第二步不要修改cipher,只需要修改iv就行了,因为我两个图中的cipher是不一样的,所以我还是要说一下的,以免误人子弟

1 import base64
2 cipher="wRPT3VONV2zFV6D2PbHjIm1lIjtzOjU6ImFkbWluIjtzOjg6InBhc3N3b3JkIjtzOjU6IjEyMzQ1Ijt9"
3 plain=base64.b64decode(cipher)
4 oldiv=base64.b64decode("uxrq4TtskqrNJh7JUZV9rg==")
5 one='a:2:{s:8:"userna'
6 iv=""
7 for i in range(0,16):
8     iv=iv+chr(ord(one[i])^ord(plain[i])^ord(oldiv[i]))
9 print base64.b64encode(iv)#iv=GzMLBhOS//4yU8tMCVbw7Q==

将新的iv POST过去成功getflag

 

最后:写得不太好,若有师傅发现错误,望请斧正

posted @ 2018-09-26 18:22  By七友  阅读(847)  评论(0编辑  收藏  举报