@iPhan
2018-07-06T14:26:00.000000Z
字数 2971
阅读 650
step1: zipCrypto known plain text attack
step2 reverse py2exe
python script
from Crypto.PublicKey import RSAfrom Crypto.Cipher import PKCS1_v1_5, AESfrom Crypto.Util.number import bytes_to_long, long_to_bytesfrom os import urandombs = 16def xor(x, y):return bytes(a ^ b for a, b in zip(x, y))class Pubcipher(object):def __init__(self):self._rsa = RSA.generate(1024)self._pkcs = PKCS1_v1_5.new(self._rsa)def encrypt(self, msg):'''msg must be bytes'''return self._pkcs.encrypt(msg)def decrypt(self, ciphertext):return self._pkcs.decrypt(ciphertext, None)class Sycipher(object):def __init__(self):self.iv = urandom(AES.block_size)def _pad(self, s):return s + (AES.block_size - len(s) % AES.block_size) * bytes((AES.block_size - len(s) % AES.block_size, ))def _unpad(self, s):return s[0:-s[-1]]def encrypt(self, msg, key):self.cipher = AES.new(key, AES.MODE_OFB, self.iv)return self.cipher.encrypt(self._pad(msg))def decrypt(self, msg, key):self.cipher = AES.new(key, AES.MODE_OFB, self.iv)return self._unpad(self.cipher.decrypt(msg))def main():with open('admin.key', 'rb') as f:admin_key = f.read(bs)print('Welc.')pub = Pubcipher()sy = Sycipher()print(pub._rsa.e)print(pub._rsa.n)while True:choice = input("[t]icke or [k]ey or [f]lag :>>")if not choice:breakif choice[0] == 't':name = input('ur name:>>')if len(name) > 50:exit()name = bytes(name, 'ISO-8859-1')pw = input('ur 16bytes passwd:>>')if len(pw) != bs:exit()pw = bytes(pw, 'ISO-8859-1')tic = name + pw + urandom(bs) + admin_keytry:tic = pub.encrypt(tic)except ValueError:print('Plz input again. Remove space plz.')continueprint(tic.hex())elif choice[0] == 'k':tmp_k = input('Input the key:>>')tmp_k = bytes.fromhex(tmp_k)if tmp_k != admin_key:exit()print(admin_key.hex())elif choice[0] == 'f':name = input('ur name:>>')if len(name) > 50:exit()name = bytes(name, 'ISO-8859-1')pw = input('ur 16bytes passwd:>>')if len(pw) != bs:exit()pw = bytes(pw, 'ISO-8859-1')tic = input('ur ticket:>>')try:tic = bytes.fromhex(tic)except Exception:continuep = pub.decrypt(tic)try:_name = p[-4 * bs:-3 * bs]_pw = p[-3 * bs:-2 * bs]_admin_key = p[-bs:]seed = p[-2 * bs:-bs]if _name != name or _pw != pw or _admin_key != admin_key:raise ValueErrorexcept Exception:print('u input wrong passwd or username')continuekey = xor(seed, pw)with open('attach.bin', 'rb') as f:flag = f.read()flag = sy.encrypt(flag, key)print(flag.hex())else:exit()if __name__ == '__main__':main()
step3 PKCS#1 v1.5 decrypt oracle
Between 106th line-116th line:
try:_name = p[-4 * bs:-3 * bs]_pw = p[-3 * bs:-2 * bs]_admin_key = p[-bs:]seed = p[-2 * bs:-bs]if _name != name or _pw != pw or _admin_key != admin_key:raise ValueErrorexcept Exception:print('u input wrong passwd or username')continue
As the decrypt function for pkcs is initialize like this:
def decrypt(self, ciphertext):return self._pkcs.decrypt(ciphertext, None)
It won't raise an error when PKCS detect some error for padding, decrypt function will just return None, and when it try to _name = p[-4 * bs:-3 * bs], an error will raise.
SO here is a decrypt oracle. We can leak the information about whether the first 2 bytes is '0002'. Actualle, it is an old attack. Chosen Ciphertext Attacks Against Protocols Based on the RSA Encryption Standard PKCS #1
Why I choose this one? Because this paper. Real world never realize the danger from cryptography bug.