ADD file via upload

master
pcfkh8sw5 2 years ago
parent 5a218899df
commit 0fb19056a2

@ -0,0 +1,362 @@
from Crypto.Cipher import AES
from gmssl import func # 该模块用于bytes与列表之间的转换
# 密钥设置请设置为16.24.32
# ENCKEY = '1234567812345678'
def po_main(plain=None, iv=None, enckey=None, attacker_enc=None, plain_want=None):
"""
函数作用主函数用于基本信息的输入和整体提示信息的输出
调用其他函数完成攻击流程
"""
print("=== Padding Oricle Attrack POC(CBC-MODE) ===")
# 服务端默认设置
cipher = "aes" # 加密方式当前代码只支持AES)
block_size = 16 # 分组大小AES默认为16
# 测试设置(实际使用时请注释掉)
# iv = "1234567812345678".encode('utf-8') # 初始向量
# plain = "111111111111111122222".encode('utf-8') # 明文
# plain_want = "opaas".encode('utf-8') # 想要获取密文的明文
iv = iv.encode('utf-8')
# 判断IV是否长度是否符合要求
if len(iv) != block_size:
print("[-] IV must be" + str(block_size) + "bytes long!")
return False
if plain:
plain = plain.encode('utf-8')
print("=== Generate Target Ciphertext ===")
# 调用函数加密
ciphertext = encrypt(plain, iv, cipher, enckey)
if not ciphertext:
print("[-] Encrypt Error!")
return False
# 输出一些基本信息
print("[+] plaintext is: " + str(plain, encoding="utf-8"))
print("[+] iv is: ", iv.decode("utf-8"))
print("[+] ciphertext is: ", ciphertext)
return ciphertext
if attacker_enc:
print(attacker_enc)
print(type(attacker_enc))
if plain_want:
plain_want = plain_want.encode('utf-8')
# 开始进行Padding Oracle攻击
print("=== Start Padding Oracle Decrypt ===")
print("[+] Choosing Cipher: " + cipher.upper())
guess = padding_oracle_decrypt(cipher, attacker_enc, iv, block_size=block_size, enckey=enckey)
if guess:
print("[+] Guess intermediary value is: ", guess["intermediary"])
print("[+] plaintext = intermediary_value XOR original_IV")
print("[+] Guess plaintext is: ", guess["plaintext"])
# 开始利用获取的中间值求解指定明文加密后的密文
if plain_want:
print("=== Start Padding Oracle Encrypt ===")
print("[+] plaintext want to encrypt is: ", plain_want)
print("[+] Choosing Cipher: " + cipher.upper())
en = padding_oracle_encrypt(cipher, attacker_enc, plain_want, iv, block_size=block_size, enckey=enckey)
if en:
print("[+] Encrypt Success!")
print("[+] The ciphertext you want is: ", en[block_size:])
print("[+] IV is: ", iv)
print("=== Let's verify the custom encrypt result ===")
print("[+] Decrypt of ciphertext ", en[block_size:], " is:")
de = decrypt(en[block_size:], en[:block_size], cipher, enckey)
if de == add_PKCS5_padding(plain_want, block_size):
print(de)
print("[+] Bingo!")
else:
print("[-] It seems something wrong happened!")
return False
return guess["plaintext"], en[block_size:]
else:
return False
def padding_oracle_encrypt(cipher, ciphertext, plaintext, iv, enckey, block_size=16):
""""
函数功能完成指定明文加密的功能
输入
cipher:加密类型
ciphertext:已知的密文
plaintext:需要加密的明文
iv:初始向量
block_size:分组大小
输出
guess_cipher猜测的密文包含IV和密文
注意这个函数功能的实现是在前面攻击的基础上实现的即已经获取到了中间值
"""
guess_cipher = ciphertext[0 - block_size:]
plaintext = add_PKCS5_padding(plaintext, block_size)
print("[*] After padding, plaintext becomes to: ", plaintext)
block = len(plaintext)
iv_nouse = iv # 用不到,只需要中间值
prev_cipher = ciphertext[0 - block_size:] # init with the last cipher block
while block > 0:
tmp = padding_oracle_decrypt_block(cipher, prev_cipher, iv_nouse, block_size=block_size, debug=False, enckey=enckey)
prev_cipher = xor_str(plaintext[block - block_size:block], tmp["intermediary"])
guess_cipher = prev_cipher + guess_cipher.decode(encoding="ISO-8859-1")
block = block - block_size
guess_cipher = guess_cipher.encode(encoding="ISO-8859-1")
return guess_cipher
# 一个简单的异或操作,用于求解明文
def xor(first, second):
return bytearray(x ^ y for x, y in zip(first, second))
def padding_oracle_decrypt(cipher, ciphertext, iv, enckey, block_size=8, debug=True):
""""
函数功能对密文进行分组并调用函数攻击每一个分组以获取中间值
输入
cipher:加密类型
ciphertext:已知的密文
iv:初始向量
block_size:分组大小
输出
result获取的中间值和明文信息
注意这个函数不是主要的攻击函数而是完成分组和调用攻击函数的功能
"""
# 将密文进行分组
cipher_block = split_cipher_block(ciphertext, block_size)
if cipher_block:
result = {}
result["intermediary"] = ''
result["plaintext"] = ''
counter = 0
for c in cipher_block:
if debug:
print("[*] Now try to decrypt block " + str(counter))
print("[*] Block " + str(counter) + "'s ciphertext is: ", c)
# 调用真正的攻击函数(每一次攻击一个分组)
guess = padding_oracle_decrypt_block(cipher, c, iv, block_size=block_size, debug=debug, enckey=enckey)
if guess:
iv = c
guess_inter = guess["intermediary"].decode(encoding="ISO-8859-1")
result["intermediary"] += guess_inter
guess_plain = guess["plaintext"].decode(encoding="ISO-8859-1")
result["plaintext"] += guess_plain
if debug:
print("[+] Block " + str(counter) + " decrypt!")
print("[+] intermediary value is: ", guess["intermediary"])
print("[+] The plaintext of block " + str(counter) + " is: ", guess["plaintext"])
counter = counter + 1
else:
print("[-] padding oracle decrypt error!")
return False
# 返回值的格式要进行转换
result["intermediary"] = result["intermediary"].encode(encoding="ISO-8859-1")
result["plaintext"] = result["plaintext"].encode(encoding="ISO-8859-1")
return result
else:
print("[-] ciphertext's block_size is incorrect!")
return False
def padding_oracle_decrypt_block(cipher, ciphertext, iv, enckey, block_size=16, debug=True):
""""
函数功能对单个分组进行攻击获取中间值和明文
输入
cipher:加密类型
ciphertext:已知的密文分组
iv:初始向量
block_size:分组大小
输出
result获取的中间值和明文信息单个分组
注意这个函数不是主要的攻击函数而是完成分组和调用攻击函数的功能
"""
result = {}
intermediary = bytearray(16) # 中间值
iv_p = bytearray(16) # 用于猜测的IV向量
# 通过for循环实现猜测的功能
for i in range(1, block_size + 1):
for b in range(0, 256):
iv_p[16 - i] = b
iv_bytes = bytes(iv_p)
plain = decrypt(ciphertext, iv_bytes, cipher, enckey)
# 最关键的一步用于模拟服务器的回显即padding是否符合要求
if check_PKCS5_padding(plain, i):
if debug:
print("[*] Try IV: ", func.bytes_to_list(iv_bytes))
print("[*] Found padding oracle: ", hex_s(plain))
intermediary[16 - i] = i ^ b
for m in range(1, i + 1):
iv_p[16 - m] = (i + 1) ^ intermediary[16 - m]
plain = xor(iv, intermediary)
result["plaintext"] = plain
result["intermediary"] = bytes(intermediary)
return result
# 一个简单的分组函数
def split_cipher_block(ciphertext, block_size=8):
if len(ciphertext) % block_size != 0:
return False
result = []
length = 0
while length < len(ciphertext):
# 每一个分组都是一个字符串
result.append(ciphertext[length:length + block_size])
length += block_size
return result
def check_PKCS5_padding(plain, p):
""""
函数功能服务器回显判断
输入
plain:明文
p:正在猜测的位数
输出
True or False
注意这个函数用于模拟服务端给出回显
"""
if len(plain) % 16 != 0:
return False
# 字符串反向,为了下面便于比较
plain = plain[::-1]
ch = 0
found = 0 # 相等的位数
while ch < p:
if bytes(plain[ch]) == bytes(p):
found += 1
ch += 1
if found == p:
return True
else:
return False
def add_PKCS5_padding(plaintext, block_size):
""""
函数功能PKCS5填充
输入
plaintext:明文
block_size:分组大小
输出
plaintext填充后的明文
注意这个函数用于填充缺失值是本次攻击可以实施的本源
"""
s = ''
if len(plaintext) % block_size == 0:
return plaintext
if len(plaintext) < block_size:
padding = block_size - len(plaintext)
else:
padding = block_size - (len(plaintext) % block_size)
plaintext = str(plaintext, encoding="utf-8")
for i in range(0, padding):
plaintext += chr(padding)
plaintext = bytes(plaintext, encoding="utf-8")
return plaintext
def decrypt(ciphertext, iv, cipher, enckey):
""""
函数功能解密密文AES)
输入
ciphertext:密文
iv:初始向量
cipher:加解密方式
输出
o.decrypt(ciphertext)解密后的明文
注意这个函数在本次实验里主要是用于验证密文的有效性
"""
key = enckey
if cipher.lower() == "aes":
o = AES.new(key, AES.MODE_CBC, iv)
else:
return False
if len(iv) % 16 != 0:
return False
if len(ciphertext) % 16 != 0:
return False
return o.decrypt(ciphertext)
def encrypt(plaintext, iv, cipher, enckey):
""""
函数功能加密明文AES)
输入
plaintext:明文
iv:初始向量
cipher:加解密方式
输出
o.encrypt(plaintext)加密后的密文
注意这个函数在本次实验里主要是用于初始服务端加密以获取到密文
"""
key = enckey
if cipher.lower() == "aes":
if len(key) != 16 and len(key) != 24 and len(key) != 32:
print("[-] AES key must be 16/24/32 bytes long!")
return False
o = AES.new(key, AES.MODE_CBC, iv)
else:
return False
plaintext = add_PKCS5_padding(plaintext, len(iv))
return o.encrypt(plaintext)
# 这个函数主要用于第二段攻击时某个值的计算
def xor_str(a, b):
if len(a) != len(b):
return False
c = []
for i in range(0, len(a)):
c.append(a[i] ^ b[i])
c = bytes(c)
return c.decode(encoding="ISO-8859-1")
# 可有可无
def hex_s(str2):
re = []
re = func.bytes_to_list(str2)
return re
if __name__ == "__main__":
po_main()
Loading…
Cancel
Save