Advertisement
Guest User

Untitled

a guest
Sep 21st, 2014
443
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.64 KB | None | 0 0
  1. #!/usr/bin/env python
  2.  
  3. # Origin: https://github.com/santoku/Santoku-Linux.git
  4.  
  5. # Authors: Thomas Cannon <tcannon@viaforensics.com>
  6. #          Seyton Bradford <sbradford@viaforensics.com>
  7. # TAGS: Android, Device, Decryption, Crespo, Bruteforce
  8. #
  9. # Parses the footer from the encrypted userdata partition
  10. # Decrypts the master key found in the footer using a supplied password
  11. # Bruteforces the pin number using the header from the encrypted partition
  12. # Written for Nexus S (crespo) running Android 4.0.4
  13. # Footer is located in file userdata_footer on the efs partition
  14. #
  15. # --
  16. # Revision 0.3 (shipped with Santoku Alpha 0.3)
  17. # ------------
  18. # Added support for more than 4-digit PINs
  19. # Speed improvements
  20. # ------------
  21. # 2014/5/14 Added 4.4 support (scrypt, etc.) [Nikolay Elenkov]
  22. # ------------
  23. # 2014/9/21 Hardcoded support for HTC ONE on Android 4.4.3 [Dmitry Ananyev]
  24. # --
  25. #
  26. # ======= Mount Insctruction =======
  27. # URL: http://esec-lab.sogeti.com/post/Exploiting-a-vulnerability-in-HTC-One-bootloader-and-bruteforcing-the-PIN-password
  28. #
  29. # (root)
  30. #
  31. # # mount encrypted volume
  32. # mkdir /mnt/decrypted_userdata
  33. # losetup -f encrypted_userdata.img
  34. # cryptsetup plainOpen -c aes-cbc-essiv:sha256 -d /path/to/decrypted_key /dev/loop0 decrypted_userdata
  35. # mount /dev/mapper/decrypted_userdata /mnt/decrypted_userdata
  36. #
  37. # # unmount encrypted volume
  38. # umount /mnt/decrypted_userdata
  39. # cryptsetup close decrypted_userdata
  40. # losetup -D
  41. #
  42.  
  43. from os import path
  44. import sys, itertools
  45. import time
  46. from struct import Struct
  47. from M2Crypto import EVP
  48. import hashlib
  49. import scrypt
  50.  
  51.  
  52. HASH_COUNT    = 2000
  53. KEY_LEN_BYTES = 32
  54. IV_LEN_BYTES  = 32
  55.  
  56. SCRYPT_ADDED_MINOR = 2
  57. KDF_PBKDF = 1
  58. KDF_SCRYPT = 2
  59.  
  60. class CryptoFooter:
  61.  
  62.     def __init__(self):
  63.         self.kdf = KDF_SCRYPT
  64.  
  65.     def unpack(self, data):
  66.         # structure taken from cryptfs.h in crespo source.
  67.         s = Struct('<'+'L H H')
  68.         ftrMagic, majorVersion, minorVersion = s.unpack_from(data)
  69.         if minorVersion < SCRYPT_ADDED_MINOR:
  70.             s = Struct('<'+'L H H L L L L L L L 64s L 48s 16s')
  71.             (self.ftrMagic, self.majorVersion, self.minorVersion,
  72.             self.ftrSize, self.flags, self.keySize, self.spare1,
  73.             self.fsSize1, self.fsSize2, self.failedDecrypt, self.cryptoType,
  74.             self.spare2, self.cryptoKey, self.cryptoSalt) = s.unpack_from(data)
  75.  
  76.             self.cryptoKey = self.cryptoKey[0:self.keySize]
  77.         else:
  78.             s = Struct('<'+'L H H L L L L L L L 64s L 48s 16s 2Q L B B B B')
  79.             (self.ftrMagic, self.majorVersion, self.minorVersion, self.ftrSize,
  80.             self.flags, self.keySize, self.spare1, self.fsSize1, self.fsSize2,
  81.             self.failedDecrypt, self.cryptoType, self.spare2, self.cryptoKey,
  82.             self.cryptoSalt, self.persistDataOffset1, self.persistDataOffset2,
  83.             self.persistDataSize, self.kdf, self.N_factor, self.r_factor,
  84.             self.p_factor) = s.unpack_from(data)
  85.  
  86.             self.cryptoKey = self.cryptoKey[0:self.keySize]
  87.             self.N = 1 << self.N_factor
  88.             self.r = 1 << self.r_factor
  89.             self.p = 1 << self.p_factor
  90.  
  91.     def dump(self):
  92.         print "Android FDE crypto footer"
  93.         print '-------------------------'
  94.         print 'Magic          :', "0x%0.8X" % self.ftrMagic
  95.         print 'Major Version  :', self.majorVersion
  96.         print 'Minor Version  :', self.minorVersion
  97.         print 'Footer Size    :', self.ftrSize, "bytes"
  98.         print 'Flags          :', "0x%0.8X" % self.flags
  99.         print 'Key Size       :', self.keySize * 8, "bits"
  100.         print 'Failed Decrypts:', self.failedDecrypt
  101.         print 'Crypto Type    :', self.cryptoType.rstrip("\0")
  102.         print 'Encrypted Key  :', "0x" + self.cryptoKey.encode("hex").upper()
  103.         print 'Salt           :', "0x" + self.cryptoSalt.encode("hex").upper()
  104.         if self.minorVersion >= SCRYPT_ADDED_MINOR:
  105.             print 'KDF            :', "PBKDF2" if self.kdf == KDF_PBKDF else "scrypt"
  106.             print 'N_factor       :', "%u   (N=%u)" % (self.N_factor, self.N)
  107.             print 'r_factor       :', "%u   (r=%u)" % (self.r_factor, self.r)
  108.             print 'p_factor       :', "%u   (p=%u)" % (self.p_factor, self.p)
  109.         print '-------------------------'
  110.        
  111.        
  112. def main(args):
  113.     # default value
  114.     maxpin_digits = 4
  115.  
  116.     if len(args) < 3:
  117.         print 'Usage: python bruteforce_stdcrypto.py [header file] [footer file] (max PIN digits)'
  118.         print ''
  119.         print '[] = Mandatory'
  120.         print '() = Optional (default is 4)'
  121.     else:
  122.         # use inputed filenames for the two files
  123.         footerFile    = args[2]
  124.         headerFile    = args[1]
  125.         try:
  126.             if args[3] != None:
  127.                 try:
  128.                     maxpin_digits = int(args[3])
  129.                     if maxpin_digits <= 3:
  130.                         print 'PIN has to be >= to 4 digits - defaulting your entered value to 4'
  131.                         time.sleep(2)
  132.                         maxpin_digits = 4
  133.                 except:
  134.                     print 'You did not entered a valid maximum number of digits to bruteforce'
  135.                     print '=> Defaulting your value to 4.'
  136.                     time.sleep(2)
  137.                     maxpin_digits = 4
  138.             else:
  139.             # default value
  140.                 maxpin_digits = 4
  141.         except:
  142.             print 'Defaulting max PIN digits to 4'
  143.             time.sleep(2)
  144.             maxpin_digits = 4
  145.  
  146.  
  147.         assert path.isfile(footerFile), "Footer file '%s' not found." % footerFile
  148.         assert path.isfile(headerFile), "Header file '%s' not found." % headerFile
  149.         fileSize = path.getsize(footerFile)
  150.         assert (fileSize >= 16384), "Input file '%s' must be at least 16384 bytes" % footerFile
  151.        
  152.         # retrive the key and salt from the footer file
  153.         cf = getCryptoData(footerFile)
  154.  
  155.         # load the header data for testing the password
  156.         headerData = open(headerFile, 'rb').read(KEY_LEN_BYTES+IV_LEN_BYTES)
  157.  
  158.         passwd = raw_input("Enter PIN: ")
  159.         result = bruteforcePIN(headerData, cf, 4, passwd)
  160.         if result:
  161.                 print 'Found PIN!: ' + result
  162.         else:
  163.             print 'Not correct pass'
  164.  
  165. def bruteforcePIN(headerData, cryptoFooter, maxdigits, passwd):
  166.     print 'Trying to Bruteforce Password... please wait'
  167.  
  168.     # try all possible 4 to maxdigits digit PINs, returns value immediately when found
  169.     #for j in itertools.product(xrange(1),repeat=1):
  170.     if 1:
  171.        
  172.         # decrypt password
  173.         #passwdTry = ''.join(str(elem) for elem in j)
  174.         passwdTry = passwd
  175.         print 'Trying: ' + passwdTry
  176.  
  177.         # -- In case you prefer printing every 100
  178.         #try:
  179.         #   if (int(passwdTry) % 100) == 0:
  180.         #       print 'ok'
  181.         #       print 'Trying passwords from %d to %d' %(int(passwdTry),int(passwdTry)+100)
  182.         #except:
  183.         #   pass
  184.        
  185.         # make the decryption key from the password
  186.         decKey = ''
  187.         if cryptoFooter.kdf == KDF_PBKDF:
  188.             decKey = decryptDecodePbkdf2Key(cryptoFooter, passwdTry)
  189.         elif cryptoFooter.kdf == KDF_SCRYPT:
  190.             decKey = decryptDecodeScryptKey(cryptoFooter, passwdTry)
  191.         else:
  192.             raise "Unknown KDF: " + cf.kdf
  193.            
  194.         print 'Decrypted Key  :', "0x" + decKey.encode("hex").upper()
  195.        
  196.        
  197.         # try to decrypt the frist 32 bytes of the header data (we don't need the iv)
  198.         decData = decryptData(decKey, "", headerData)
  199.  
  200.         print 'Decrypted Data  :', "0x" + decData.encode("hex").upper()
  201.         #print 'Decrypted Data  :', decData
  202.        
  203.         # has the test worked?
  204.         if decData[KEY_LEN_BYTES+IV_LEN_BYTES-16:KEY_LEN_BYTES+IV_LEN_BYTES] == "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0":
  205.             open("decypted_key", 'wb').write(decKey)
  206.             return passwdTry
  207.            
  208.     return None
  209.  
  210.  
  211. def getCryptoData(filename):
  212.     data = open(filename, 'rb').read()
  213.    
  214.     cf = CryptoFooter()
  215.     cf.unpack(data)
  216.     cf.dump()
  217.  
  218.     return cf
  219.  
  220. def decryptDecodePbkdf2Key(cf,password):
  221.     # make the key from the password
  222.     pbkdf2 = EVP.pbkdf2(password, cf.cryptoSalt, iter=HASH_COUNT, keylen=KEY_LEN_BYTES+IV_LEN_BYTES)
  223.  
  224.     key = pbkdf2[:KEY_LEN_BYTES]
  225.     iv = pbkdf2[KEY_LEN_BYTES:]
  226.  
  227.     # do the decrypt
  228.     cipher = EVP.Cipher(alg='aes_256_cbc', key=key, iv=iv, op=0) # 0 is DEC
  229.     cipher.set_padding(padding=0)
  230.     decKey = cipher.update(cf.cryptoKey)
  231.     decKey = decKey + cipher.final()
  232.    
  233.     return decKey
  234.  
  235. def decryptDecodeScryptKey(cf,password):
  236.  
  237.     print '... pass :', password
  238.     print '... pass :', "0x" + password.encode("hex").upper()
  239.     print '... salt :', "0x" + cf.cryptoSalt.encode("hex").upper()
  240.     print '... N :', cf.N
  241.     print '... r :', cf.r
  242.     print '... p :', cf.p
  243.  
  244.     derived = scrypt.hash(password, cf.cryptoSalt, cf.N, cf.r, cf.p)
  245.  
  246.     print '... derived :', "0x" + derived.encode("hex").upper()
  247.    
  248.     key = derived[:KEY_LEN_BYTES]
  249.     iv = derived[KEY_LEN_BYTES:]
  250.  
  251.     print '... key :', "0x" + key.encode("hex").upper()
  252.     print '... iv :', "0x" + iv.encode("hex").upper()
  253.  
  254.     # do the decrypt
  255.     cipher = EVP.Cipher(alg='aes_256_cbc', key=key, iv=iv, op=0) # 0 is DEC
  256.     cipher.set_padding(padding=0)
  257.     decKey = cipher.update(cf.cryptoKey)
  258.     decKey = decKey + cipher.final()
  259.    
  260.     return decKey
  261.  
  262. def decryptData(decKey,essiv,data):
  263.     # try to decrypt the actual data
  264.     cipher = EVP.Cipher(alg='aes_256_cbc', key=decKey, iv=essiv, op=0) # 0 is DEC
  265.     cipher.set_padding(padding=0)
  266.     decData = cipher.update(data)
  267.     decData = decData + cipher.final()
  268.     return decData
  269.  
  270. if __name__ == "__main__":
  271.     main(sys.argv)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement