思路很棒的一个题,对AES-CBC模式的攻击也不是一次两次了,其实题目也给了思路,只是自己不清楚原理,导致看不懂提示做不出来
题目代码:
#coding: UTF-8
import socket
import flag
from Crypto.Cipher import AES
def padding(message):
toPadByte = 16 - len(message) % 16
paddedMessage = message + chr(toPadByte) * toPadByte
return paddedMessage
def encrypt(plain):
key = flag.flag[5:-1]
assert len(key) == 16
iv = key
plain = padding(plain)
aes = AES.new(key, AES.MODE_CBC, iv)
cipher = aes.encrypt(plain)
cipher = cipher.encode("base_64")
return cipher
def runTheClient():
s = socket.socket()
host = socket.gethostname() # set this to the host's IP address
port = flag.port
plain = "blablabla_" + "I_enjoy_cryptography" + "_blablabla"
cipher = encrypt(plain)
s.connect((host, port))
s.send(cipher)
print s.recv(1024).strip()
s.close()
if __name__ == "__main__":
runTheClient()
这里需要把握的重点有两个,A:iv = key,B:plain的提示:分为三个部分,第一部分和第三部分很类似!
首先,贴出来CBC模式加密解密原理图:
https://blog.poxiao.me/p/advanced-encryption-standard-and-block-cipher-mode/
图片来自维基百科
所以我们可以看一看,如果plain的第一部分和第三部分都相等,会出现什么情况
IV ^ BCD(C1,K) = PLAIN1
C1 ^ BCD(C2,K) = PLAIN2
C2 ^ BCD(C3 , K) = PLAIN3
IV = K
我们与服务器通信时,控制的是密文,服务器回传解密,所以采取选择密文攻击,从而对IV也就是K进行信息泄露:
当C1 = C3,且C2 = 0时,发现:K = IV = PLAIN1 ^ PLAIN3!
https://www.anquanke.com/post/id/146419#h3-20
所以,代码如下:(来自上面的链接)
#coding: UTF-8
import socket
import flag
from Crypto.Cipher import AES
def padding(message):
toPadByte = 16 - len(message) % 16
paddedMessage = message + chr(toPadByte) * toPadByte
return paddedMessage
def encrypt(plain):
key = flag.flag[5:-1]
assert len(key) == 16
iv = key
plain = padding(plain)
aes = AES.new(key, AES.MODE_CBC, iv)
cipher = aes.encrypt(plain)
cipher = cipher.encode("base_64")
return cipher
def runTheClient(cipher):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "registry.asuri.org"
port = 10003
# plain = "blablabla_" + "I_enjoy_cryptography" + "_blablabla"
# cipher = encrypt(plain)message = s.recv(1024)
s.connect((host, port))
# message = s.recv(1024)
# print message
s.send(cipher)
message = s.recv(1024)
print message
s.close()
return message
def crack():
block = "A" * 16
cipher = block + "x00"*16 + block
cipher = cipher.encode("base_64") + "n"
message = runTheClient(cipher)
if "high ASCII" in message:
begin = message.find(":")
plain = message[begin+1:].strip().decode("base_64")
block1 = plain[:16]
block3 = plain[32:48]
key = ""
for i in range(16):
key = key + chr(ord(block1[i]) ^ ord(block3[i]))
print "key", key
if __name__ == "__main__":
crack()