参考文献:http://drops.xmd5.com/static/drops/tips-7828.html
http://p0sec.net/index.php/archives/99/
原理:
通过损坏密文字节来改变明文字节。(借助CBC内部的模式)借由此可以绕过过滤器,或者改变用户权限提升至管理员,又或者改变应用程序预期明文。
加密过程:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15①Plaintext:待加密的数据。
②IV:用于随机化加密的比特块,保证即使对相同明文多次加密,也可以得到不同的密文。
③Key:被一些如AES的对称加密算法使用。
④Ciphertext:加密后的数据。
CBC工作于一个固定长度的比特组,将其称之为块。。
加密:
Ciphertext-0 = Encrypt(Plaintext XOR IV)—只用于第一个组块
Ciphertext-N= Encrypt(Plaintext XOR Ciphertext-N-1)—用于第二及剩下的组块
前一块的密文用来产生后一块的密文
解密:
Plaintext-0 = Decrypt(Ciphertext) XOR IV—只用于第一个组块
Plaintext-N= Decrypt(Ciphertext) XOR Ciphertext-N-1—用于第二及剩下的组块
Ciphertext-N-1(密文-N-1)是用来产生下一块明文;这就是字节翻转攻击开始发挥作用的地方。如果改变Ciphertext-N-1(密文-N-1)的一个字节,然后与下一个解密后的组块异或,就可以得到一个不同的明文了
一道相关的ctf
1 | <?php |
登录用户名如果为admin则输出flag,但是禁止了admin登录,这里就用到了CBC字节翻转攻击
解题思路
这里把登录的用户名及其密码存入数组,序列化后进行AES-CBC模式的加密,其中iv,和密文以cookie储存,可控。
使用guest
登录(因为翻转目标是admin,所以登录的用户名最好也是五位),登录后被存入数组然后序列化变成:a:2:{s:8:"username";s:5:"skctf";s:8:"password";s:5:"123";}
,也就是明文
翻转目标为:a:2:{s:8:"username";s:5:"admin";s:8:"password";s:5:"123";}
首先将明文分成16字节的四组:
1
2
3
4a:2:{s:8:"userna
me";s:5:"guest";
s:8:"password";s
:5:"123";}根据CBC攻击原理,只需修改第一组密文对应第二组’guest’的位置的密文,就可以实现第二组明文的改变。即第10-14位。
利用下面脚本重新生成密文
1
2
3
4
5
6
7
8
9
10# -*- coding: utf-8 -*-
import base64
cipher = 'HY+D3iO7JAH3cCurQDEG4EzlzTJEt4Irbcl/ahE76/JBU5CmfS/jH5uxwvuGnRIPj1cH+q5fD/3uthlP0zJWrQ=='.decode('base64')
old = "me\";s:5:\"guest\";"
new = "me\";s:5:\"admin\";"
for i in xrange(16):
cipher = cipher[:i] + chr(ord(cipher[i]) ^ ord(old[i]) ^ ord(new[i])) + cipher[i+1:]
print cipher.encode('base64').strip()
根据CBC加密原理,修改第一块的密文可以达到修改第二块密文的效果,但同时也破坏了第一块的明文,接下来就是将第一块的数据恢复。(上面得出的数据一定要进行url编码,同时也要删除username和password的值)
用上面生成的密文修改cookie:cipher得到:
获取到第一次翻转后的明文,通过修改IV来修改第一块的明文:
利用下面的脚本重新生成iv:1
2
3
4
5
6
7
8
9
10
11
12# -*- coding: utf-8 -*-
import base64
plain = 'Kksm2a9vhavRgnlN5bnsJG1lIjtzOjU6ImFkbWluIjtzOjg6InBhc3N3b3JkIjtzOjM6IjEyMyI7fQ=='.decode('base64')
iv = 'm3QrM6HM+MKYWZmfmkUPIQ=='.decode('base64')
old = plain[:16]
new = "a:2:{s:8:\"userna";
for i in xrange(16):
iv = iv[:i] + chr(ord(iv[i]) ^ ord(old[i]) ^ ord(new[i])) + iv[i+1:]
print iv.encode('base64').strip()
生成新的iv,修改cookie:iv,访问即可获得flag: