n0fate / chainbreaker

Mac OS X Keychain Forensic Tool
GNU General Public License v2.0
833 stars 160 forks source link

Update chainbreaker.py to work with Python 3.x #27

Closed ericfitz closed 2 years ago

ericfitz commented 2 years ago

Python 2 is deprecated and is being removed from macOS in the immediate future starting with version 12.3.

Please update chainbreaker to work under Python 3.x

ericfitz commented 2 years ago

I put a $100 bounty on this issue: https://app.bountysource.com/issues/105707259-update-chainbreaker-py-to-work-with-python-3-x

caryoscelus commented 2 years ago

i've made basic work for this (there could be a couple rough edges still) . please test @ https://github.com/caryoscelus/chainbreaker/tree/py3

ericfitz commented 2 years ago

Still not working, here's the output:

┌─(~/Projects/bounty/chainbreaker)──────────────────────────────────────
└─(18:49:13-0400 on master)──> sudo python3 ./chainbreaker.py -p -o ~/Downloads/keychain-export/ --export-private-keys /Library/Keychains/System.keychain --unlock-file /var/db/SystemKey
Password:
  File "/Users/eric/Projects/bounty/chainbreaker/./chainbreaker.py", line 153
    print "private_key_offset", self._get_private_key_record(private_key_offset)
          ^
SyntaxError: invalid syntax
caryoscelus commented 2 years ago

Still not working, here's the output:

The code you're quoting is from the old version. Can you please make sure you've checked out the py3 branch?

ericfitz commented 2 years ago

Here you go:

┌─(~/Projects/bounty)───────────────────────────────────────────────────────────────────────────────────(eric@Erics-Mac-Pro:s001)─┐
└─(20:15:37-0400)──> git clone -b py3 https://github.com/caryoscelus/chainbreaker.git                          ──(Thu 2022-03-31)─┘
Cloning into 'chainbreaker'...
remote: Enumerating objects: 155, done.
remote: Counting objects: 100% (38/38), done.
remote: Compressing objects: 100% (27/27), done.
remote: Total 155 (delta 17), reused 12 (delta 11), pack-reused 117
Receiving objects: 100% (155/155), 113.17 KiB | 1.62 MiB/s, done.
Resolving deltas: 100% (83/83), done.
┌─(~/Projects/bounty)───────────────────────────────────────────────────────────────────────────────────(eric@Erics-Mac-Pro:s001)─┐
└─(20:16:33-0400)──> cd chainbreaker                                                                           ──(Thu 2022-03-31)─┘
┌─(~/Projects/bounty/chainbreaker)──────────────────────────────────────────────────────────────────────(eric@Erics-Mac-Pro:s001)─┐
└─(20:16:36-0400 on py3)──> sudo python3 ./chainbreaker.py -p -o ~/Downloads/keychain-export/ --export-private-keys /Library/Keychains/System.keychain --unlock-file /var/db/SystemKey
Password:
Unlock Password:
2022-03-31 20:17:03,425 - INFO -

ChainBreaker 2 - https://github.com/gaddie-3/chainbreaker

2022-03-31 20:17:03,425 - INFO - Runtime Command: ./chainbreaker.py -p -o /Users/eric/Downloads/keychain-export/ --export-private-keys /Library/Keychains/System.keychain --unlock-file /var/db/SystemKey
2022-03-31 20:17:03,425 - INFO - Keychain: /Library/Keychains/System.keychain
2022-03-31 20:17:03,425 - INFO - Keychain MD5: dcbe47b235cf7fbe6d478b908f2db39e
2022-03-31 20:17:03,425 - INFO - Keychain 256: fb2b63894837680590f21b8ade98340b2a2f283e20324d963fcab49c794bf16d
2022-03-31 20:17:03,425 - INFO - Dump Start: 2022-03-31 20:17:03.425032
Traceback (most recent call last):
  File "/Users/eric/Projects/bounty/chainbreaker/./chainbreaker.py", line 1287, in <module>
    keychain = Chainbreaker(args.keychain, unlock_password=args.password, unlock_key=args.key,
  File "/Users/eric/Projects/bounty/chainbreaker/./chainbreaker.py", line 82, in __init__
    self.unlock_password = unlock_password
  File "/Users/eric/Projects/bounty/chainbreaker/./chainbreaker.py", line 590, in unlock_password
    master_key = self._generate_master_key(self._unlock_password)
  File "/Users/eric/Projects/bounty/chainbreaker/./chainbreaker.py", line 352, in _generate_master_key
    return str(PBKDF2(pw, str(bytearray(self.dbblob.Salt)), 1000, Chainbreaker.KEYLEN))
  File "/Users/eric/Projects/bounty/chainbreaker/pbkdf2.py", line 35, in __init__
    h = hmac.new(self.password, None, self.hashfn)
  File "/usr/local/Cellar/python@3.9/3.9.12/Frameworks/Python.framework/Versions/3.9/lib/python3.9/hmac.py", line 170, in new
    return HMAC(key, msg, digestmod)
  File "/usr/local/Cellar/python@3.9/3.9.12/Frameworks/Python.framework/Versions/3.9/lib/python3.9/hmac.py", line 53, in __init__
    raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__)
TypeError: key: expected bytes or bytearray, but got 'str'
ericfitz commented 2 years ago

This is also the one I struggled with when I tried to make the changes myself!

toshetah commented 2 years ago

There you go: https://github.com/n0fate/chainbreaker/pull/29

caryoscelus commented 2 years ago

@ericfitz i can go and fix those (it's just another instance of what i've already did), but i don't want to do it if competing solution arise out of nowhere

ericfitz commented 2 years ago

I'm not aware of any other solution forthcoming. I'm not working on it anymore; I posted the bounty when I hit my limit. Whoever posts a working solution first, I'll release the bounty to.

I've shown the command line that I'm going to be using to test. I'll also test the final with a couple of other of the major commands in chainbreaker. I'll be testing with latest python 3.x on Mac OS Monterey.

ericfitz commented 2 years ago

Hey @caryoscelus , any update? I did a git pull and noticed that you're tinkering, I'm ready to test when you give me the go ahead.

caryoscelus commented 2 years ago

@ericfitz i don't have access to a file to test atm so there's likely more incompatibilities, but i've updated my branch that should solve your latest exception

ericfitz commented 2 years ago

@caryoscelus

┌─(~/Projects/bounty/caryoscelus/chainbreaker)──────────────────────────────────────────────────────────(eric@Erics-Mac-Pro:s000)─┐
└─(15:53:49-0400 on py3)──> git pull                                                                           ──(Fri 2022-04-15)─┘
Already up to date.
┌─(~/Projects/bounty/caryoscelus/chainbreaker)──────────────────────────────────────────────────────────(eric@Erics-Mac-Pro:s000)─┐
└─(15:54:15-0400 on py3)──> sudo python3 ./chainbreaker.py -p -o ~/Downloads/keychain-export/ --export-private-keys /Library/Keychains/System.keychain --unlock-file /var/db/SystemKey
Password:
Unlock Password:
2022-04-15 15:54:59,972 - INFO -

ChainBreaker 2 - https://github.com/gaddie-3/chainbreaker

2022-04-15 15:54:59,973 - INFO - Runtime Command: ./chainbreaker.py -p -o /Users/eric/Downloads/keychain-export/ --export-private-keys /Library/Keychains/System.keychain --unlock-file /var/db/SystemKey
2022-04-15 15:54:59,973 - INFO - Keychain: /Library/Keychains/System.keychain
2022-04-15 15:54:59,973 - INFO - Keychain MD5: dcbe47b235cf7fbe6d478b908f2db39e
2022-04-15 15:54:59,973 - INFO - Keychain 256: fb2b63894837680590f21b8ade98340b2a2f283e20324d963fcab49c794bf16d
2022-04-15 15:54:59,973 - INFO - Dump Start: 2022-04-15 15:54:59.972798
Traceback (most recent call last):
  File "/Users/eric/Projects/bounty/caryoscelus/chainbreaker/./chainbreaker.py", line 1287, in <module>
    keychain = Chainbreaker(args.keychain, unlock_password=args.password, unlock_key=args.key,
  File "/Users/eric/Projects/bounty/caryoscelus/chainbreaker/./chainbreaker.py", line 82, in __init__
    self.unlock_password = unlock_password
  File "/Users/eric/Projects/bounty/caryoscelus/chainbreaker/./chainbreaker.py", line 590, in unlock_password
    master_key = self._generate_master_key(self._unlock_password)
  File "/Users/eric/Projects/bounty/caryoscelus/chainbreaker/./chainbreaker.py", line 352, in _generate_master_key
    return b2s(PBKDF2(pw, bytearray(self.dbblob.Salt), 1000, Chainbreaker.KEYLEN))
  File "/Users/eric/Projects/bounty/caryoscelus/chainbreaker/pbkdf2.py", line 35, in __init__
    h = hmac.new(self.password, None, self.hashfn)
  File "/usr/local/Cellar/python@3.10/3.10.2/Frameworks/Python.framework/Versions/3.10/lib/python3.10/hmac.py", line 184, in new
    return HMAC(key, msg, digestmod)
  File "/usr/local/Cellar/python@3.10/3.10.2/Frameworks/Python.framework/Versions/3.10/lib/python3.10/hmac.py", line 53, in __init__
    raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__)
TypeError: key: expected bytes or bytearray, but got 'str'
ericfitz commented 2 years ago

@toshetah

┌─(~/Projects/bounty/toshetah/chainbreaker)─────────────────────────────────────────────────────────────(eric@Erics-Mac-Pro:s000)─┐
└─(15:58:23-0400 on Support-python-3)──> git pull                                                              ──(Fri 2022-04-15)─┘
Already up to date.
┌─(~/Projects/bounty/toshetah/chainbreaker)─────────────────────────────────────────────────────────────(eric@Erics-Mac-Pro:s000)─┐
└─(15:58:28-0400 on Support-python-3)──> sudo python3 ./chainbreaker.py -p -o ~/Downloads/keychain-export/ --export-private-keys /Library/Keychains/System.keychain --unlock-file /var/db/SystemKey
Unlock Password:
2022-04-15 15:58:35,628 - INFO -

ChainBreaker 2 - https://github.com/gaddie-3/chainbreaker

2022-04-15 15:58:35,628 - INFO - Runtime Command: ./chainbreaker.py -p -o /Users/eric/Downloads/keychain-export/ --export-private-keys /Library/Keychains/System.keychain --unlock-file /var/db/SystemKey
2022-04-15 15:58:35,628 - INFO - Keychain: /Library/Keychains/System.keychain
2022-04-15 15:58:35,628 - INFO - Keychain MD5: dcbe47b235cf7fbe6d478b908f2db39e
2022-04-15 15:58:35,628 - INFO - Keychain 256: fb2b63894837680590f21b8ade98340b2a2f283e20324d963fcab49c794bf16d
2022-04-15 15:58:35,628 - INFO - Dump Start: 2022-04-15 15:58:35.628258
2022-04-15 15:58:35,629 - WARNING - Keychain signature does not match. are you sure this is a valid keychain file?
Traceback (most recent call last):
  File "/Users/eric/Projects/bounty/toshetah/chainbreaker/./chainbreaker.py", line 1290, in <module>
    keychain = Chainbreaker(args.keychain, unlock_password=args.password, unlock_key=args.key,
  File "/Users/eric/Projects/bounty/toshetah/chainbreaker/./chainbreaker.py", line 77, in __init__
    self.unlock_password = unlock_password
  File "/Users/eric/Projects/bounty/toshetah/chainbreaker/./chainbreaker.py", line 584, in unlock_password
    master_key = self._generate_master_key(self._unlock_password)
  File "/Users/eric/Projects/bounty/toshetah/chainbreaker/./chainbreaker.py", line 348, in _generate_master_key
    return str(PBKDF2(pw, str(bytearray(self.dbblob.Salt)), 1000, Chainbreaker.KEYLEN))
  File "/Users/eric/Projects/bounty/toshetah/chainbreaker/pbkdf2.py", line 38, in __init__
    T += PBKDF2._pbkdf2_f(h, self.salt, self.itercount, i)
  File "/Users/eric/Projects/bounty/toshetah/chainbreaker/pbkdf2.py", line 59, in _pbkdf2_f
    U = PBKDF2._prf(h, salt + pack('>i', blocknum))
TypeError: can only concatenate str (not "bytes") to str
ericfitz commented 2 years ago

@khalid6468:

┌─(~/Projects/bounty/khalid6468/chainbreaker)───────────────────────────────────────────────────────────(eric@Erics-Mac-Pro:s000)─┐
└─(16:00:23-0400 on m_branch)──> git pull                                                                      ──(Fri 2022-04-15)─┘
Already up to date.
┌─(~/Projects/bounty/khalid6468/chainbreaker)───────────────────────────────────────────────────────────(eric@Erics-Mac-Pro:s000)─┐
└─(16:00:28-0400 on m_branch)──> sudo python3 ./chainbreaker.py -p -o ~/Downloads/keychain-export/ --export-private-keys /Library/Keychains/System.keychain --unlock-file /var/db/SystemKey
Unlock Password:
2022-04-15 16:00:39,403 - INFO -

ChainBreaker 2 - https://github.com/gaddie-3/chainbreaker

2022-04-15 16:00:39,404 - INFO - Runtime Command: ./chainbreaker.py -p -o /Users/eric/Downloads/keychain-export/ --export-private-keys /Library/Keychains/System.keychain --unlock-file /var/db/SystemKey
2022-04-15 16:00:39,404 - INFO - Keychain: /Library/Keychains/System.keychain
2022-04-15 16:00:39,404 - INFO - Keychain MD5: dcbe47b235cf7fbe6d478b908f2db39e
2022-04-15 16:00:39,404 - INFO - Keychain 256: fb2b63894837680590f21b8ade98340b2a2f283e20324d963fcab49c794bf16d
2022-04-15 16:00:39,404 - INFO - Dump Start: 2022-04-15 16:00:39.403744
Traceback (most recent call last):
  File "/Users/eric/Projects/bounty/khalid6468/chainbreaker/./chainbreaker.py", line 1287, in <module>
    keychain = Chainbreaker(args.keychain, unlock_password=args.password, unlock_key=args.key,
  File "/Users/eric/Projects/bounty/khalid6468/chainbreaker/./chainbreaker.py", line 80, in __init__
    self.unlock_file = unlock_file
  File "/Users/eric/Projects/bounty/khalid6468/chainbreaker/./chainbreaker.py", line 616, in unlock_file
    self.db_key = self._find_wrapping_key(unlock_key_blob.MasterKey)
  File "/Users/eric/Projects/bounty/khalid6468/chainbreaker/./chainbreaker.py", line 359, in _find_wrapping_key
    plain = Chainbreaker._kcdecrypt(master, self.dbblob.IV, ciphertext)
  File "/Users/eric/Projects/bounty/khalid6468/chainbreaker/./chainbreaker.py", line 651, in _kcdecrypt
    pad = ord(plain[-1])
TypeError: ord() expected string of length 1, but int found
caryoscelus commented 2 years ago

@ericfitz another attempt https://github.com/caryoscelus/chainbreaker/tree/py3

ericfitz commented 2 years ago

@caryoscelus

No, still broken:

┌─(~/Projects/bounty/caryoscelus/chainbreaker)──────────────────────────────────────────────────────────(eric@Erics-Mac-Pro:s000)─┐
└─(17:02:48-0400 on py3)──> sudo python3 ./chainbreaker.py -p -o ~/Downloads/keychain-export/ -e /Users/$USER/Desktop/chainbreaker-test-keychain.keychain
Unlock Password:
2022-04-18 17:03:01,190 - INFO -

ChainBreaker 2 - https://github.com/gaddie-3/chainbreaker

2022-04-18 17:03:01,190 - INFO - Runtime Command: ./chainbreaker.py -p -o /Users/eric/Downloads/keychain-export/ -e /Users/eric/Desktop/chainbreaker-test-keychain.keychain
2022-04-18 17:03:01,190 - INFO - Keychain: /Users/eric/Desktop/chainbreaker-test-keychain.keychain
2022-04-18 17:03:01,190 - INFO - Keychain MD5: 32db2130d6f64502cde128d634c475c4
2022-04-18 17:03:01,190 - INFO - Keychain 256: e48d2d3d64fd5e1e1190e70b141cae7449856f0c403537eae5fffa06a50e44d7
2022-04-18 17:03:01,190 - INFO - Dump Start: 2022-04-18 17:03:01.190371
2022-04-18 17:03:01,229 - WARNING - 20360
2022-04-18 17:03:01,229 - INFO - 1 Keychain Password Hash
2022-04-18 17:03:01,230 - INFO -     [-] Exported: /Users/eric/Downloads/keychain-export/keychain_password_hash.20.txt
Traceback (most recent call last):
  File "/Users/eric/Projects/bounty/caryoscelus/chainbreaker/./chainbreaker.py", line 1387, in <module>
    record.write_to_disk(record_collection.get('write_directory', args.output))
  File "/Users/eric/Projects/bounty/caryoscelus/chainbreaker/./chainbreaker.py", line 748, in write_to_disk
    fp.write(export_content)
TypeError: a bytes-like object is required, not 'str'
caryoscelus commented 2 years ago

since this latest problem is already at export stage, this may finally fix it. if the problems persists, please contact me via email (@gmx.com) or matrix (:matrix.org)

Khalid6468 commented 2 years ago

@ericfitz please mark the issue as closed if it is fixed so that I can submit a claim in bountysource.

ericfitz commented 2 years ago

Fixed here: https://github.com/ericfitz/chainbreaker

Resolving.

ericfitz commented 2 years ago

@caryoscelus Your solution did not work.

┌─(~/Projects/bounty/caryoscelus/chainbreaker)──────────────────────────────────────────────────────────(eric@Erics-Mac-Pro:s001)─┐
└─(13:42:08-0400 on py3 ✹)──> sudo python3 ./chainbreaker.py -p -o ~/Downloads/keychain-export/ -e /Users/$USER/Desktop/chainbreaker-test-keychain.keychain
Unlock Password:
2022-05-03 13:42:13,850 - INFO -

ChainBreaker 2 - https://github.com/gaddie-3/chainbreaker

2022-05-03 13:42:13,851 - INFO - Runtime Command: ./chainbreaker.py -p -o /Users/eric/Downloads/keychain-export/ -e /Users/eric/Desktop/chainbreaker-test-keychain.keychain
2022-05-03 13:42:13,851 - INFO - Keychain: /Users/eric/Desktop/chainbreaker-test-keychain.keychain
2022-05-03 13:42:13,851 - INFO - Keychain MD5: 32db2130d6f64502cde128d634c475c4
2022-05-03 13:42:13,851 - INFO - Keychain 256: e48d2d3d64fd5e1e1190e70b141cae7449856f0c403537eae5fffa06a50e44d7
2022-05-03 13:42:13,851 - INFO - Dump Start: 2022-05-03 13:42:13.850901
2022-05-03 13:42:13,891 - WARNING - 20360
2022-05-03 13:42:13,891 - INFO - 1 Keychain Password Hash
2022-05-03 13:42:13,892 - INFO -     [-] Exported: /Users/eric/Downloads/keychain-export/keychain_password_hash.30.txt
2022-05-03 13:42:13,892 - INFO -
2022-05-03 13:42:13,893 - INFO - 2 Generic Passwords
2022-05-03 13:42:13,893 - INFO -     [-] Exported: /Users/eric/Downloads/keychain-export/passwords/generic/b'test-password'.6.txt
2022-05-03 13:42:13,893 - INFO -
2022-05-03 13:42:13,894 - INFO -     [-] Exported: /Users/eric/Downloads/keychain-export/passwords/generic/b'test-secure-note'.6.txt
2022-05-03 13:42:13,894 - INFO -
2022-05-03 13:42:13,894 - INFO - 0 Internet Passwords
2022-05-03 13:42:13,894 - INFO - 0 Appleshare Passwords
2022-05-03 13:42:13,894 - INFO - 0 Private Keys
2022-05-03 13:42:13,894 - INFO - 0 Public Keys
2022-05-03 13:42:13,894 - INFO - 1 x509 Certificates
Traceback (most recent call last):
  File "/Users/eric/Projects/bounty/caryoscelus/chainbreaker/./chainbreaker.py", line 1389, in <module>
    record.write_to_disk(record_collection.get('write_directory', args.output))
  File "/Users/eric/Projects/bounty/caryoscelus/chainbreaker/./chainbreaker.py", line 749, in write_to_disk
    fp.write(b2s(export_content))
  File "/Users/eric/Projects/bounty/caryoscelus/chainbreaker/util.py", line 3, in b2s
    return b.decode('utf-8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x82 in position 1: invalid start byte