diff options
-rwxr-xr-x | extract_token_from_browser.py | 98 |
1 files changed, 52 insertions, 46 deletions
diff --git a/extract_token_from_browser.py b/extract_token_from_browser.py index 5db183f..37549b4 100755 --- a/extract_token_from_browser.py +++ b/extract_token_from_browser.py @@ -15,6 +15,7 @@ import sys from pathlib import Path from secretstorage.exceptions import SecretStorageException from sqlite3 import OperationalError + try: import_err = None from Crypto.Cipher import AES @@ -27,16 +28,15 @@ except ModuleNotFoundError as e: class AESCipher: - def __init__(self, key): self.key = key def decrypt(self, text): - cipher = AES.new(self.key, AES.MODE_CBC, IV=(b' ' * 16)) + cipher = AES.new(self.key, AES.MODE_CBC, IV=(b" " * 16)) return self._unpad(cipher.decrypt(text)) - + def _unpad(self, s): - return s[:-ord(s[len(s) - 1:])] + return s[: -ord(s[len(s) - 1 :])] parser = argparse.ArgumentParser( @@ -45,24 +45,24 @@ parser = argparse.ArgumentParser( parser.add_argument( "browser", help="Which browser to extract from", metavar="<browser>" ) +parser.add_argument("--token", help="Extracted token", metavar="<token>", nargs="?") parser.add_argument( - "--token", help="Extracted token", metavar="<token>", nargs='?' -) -parser.add_argument( - "--profile", help="Profile to look up cookies for", metavar="<profile>", nargs='?' + "--profile", help="Profile to look up cookies for", metavar="<profile>", nargs="?" ) args = parser.parse_args() if args.browser not in ["firefox", "firefox-snap", "chrome", "chrome-beta"]: - print("Currently only firefox. firefox-snap, chrome, " - "chrome-beta are supported by this script", file=sys.stderr) + print( + "Currently only firefox. firefox-snap, chrome, " + "chrome-beta are supported by this script", + file=sys.stderr, + ) sys.exit(1) if sys.platform.startswith("linux"): iterations = 1 if args.browser == "firefox-snap": - browser_data = Path.home().joinpath( - "snap/firefox/common/.mozilla/firefox") + browser_data = Path.home().joinpath("snap/firefox/common/.mozilla/firefox") elif args.browser == "firefox": browser_data = Path.home().joinpath(".mozilla/firefox") else: @@ -71,43 +71,40 @@ elif sys.platform.startswith("darwin"): iterations = 1003 if args.browser in ["firefox", "firefox-snap"]: browser_data = Path.home().joinpath( - "Library/Application Support/Firefox/Profiles") + "Library/Application Support/Firefox/Profiles" + ) else: - browser_data = Path.home().joinpath( - "Library/Application Support/Chrome") + browser_data = Path.home().joinpath("Library/Application Support/Chrome") else: - print("Currently only Linux and macOS is supported by this script", - file=sys.stderr) + print("Currently only Linux and macOS is supported by this script", file=sys.stderr) sys.exit(1) leveldb_path = None profile = args.profile if args.browser in ["firefox", "firefox-snap"]: cookie_d_query = ( - "SELECT value FROM moz_cookies WHERE host = '.slack.com' " - "AND name = 'd'" + "SELECT value FROM moz_cookies WHERE host = '.slack.com' " "AND name = 'd'" ) cookie_ds_query = ( - "SELECT value FROM moz_cookies WHERE host = '.slack.com' " - "AND name = 'd-s'" + "SELECT value FROM moz_cookies WHERE host = '.slack.com' " "AND name = 'd-s'" ) if not profile: profile = "*.default*" default_profile_path = max( - [ x for x in browser_data.glob(profile)], key=os.path.getctime) + [x for x in browser_data.glob(profile)], key=os.path.getctime + ) if not default_profile_path: print("Couldn't find the default profile for Firefox", file=sys.stderr) sys.exit(1) cookies_path = default_profile_path.joinpath("cookies.sqlite") else: if import_err: - print("Missing required modules for Chrome browser support", - file=sys.stderr) + print("Missing required modules for Chrome browser support", file=sys.stderr) raise import_err # b'v10' is for Chromium, but not Chrome, it seems? - prefix = b'v11' + prefix = b"v11" cookie_d_query = ( "SELECT encrypted_value FROM cookies WHERE " "host_key = '.slack.com' AND name = 'd'" @@ -142,27 +139,30 @@ if args.browser in ["chrome", "chrome-beta"]: try: collection = secretstorage.get_default_collection(bus) for item in collection.get_all_items(): - if item.get_label() == 'Chrome Safe Storage': + if item.get_label() == "Chrome Safe Storage": passwd = item.get_secret() break else: - raise Exception('Chrome password not found!') + raise Exception("Chrome password not found!") except SecretStorageException: - print("Error communicating org.freedesktop.secrets, trying 'peanuts' " - "as a password", file=sys.stderr) - passwd = 'peanuts' - - salt = b'saltysalt' + print( + "Error communicating org.freedesktop.secrets, trying 'peanuts' " + "as a password", + file=sys.stderr, + ) + passwd = "peanuts" + + salt = b"saltysalt" length = 16 key = PBKDF2(passwd, salt, length, iterations) cipher = AESCipher(key) - + if cookie_d_value[:3] == prefix: - cookie_d_value = cipher.decrypt(cookie_d_value[3:]).decode('utf8') + cookie_d_value = cipher.decrypt(cookie_d_value[3:]).decode("utf8") if cookie_ds_value and cookie_ds_value[:3] == prefix: - cookie_ds_value = cipher.decrypt(cookie_ds_value[3:]).decode('utf8') + cookie_ds_value = cipher.decrypt(cookie_ds_value[3:]).decode("utf8") if cookie_ds_value: cookie_value = f"d={cookie_d_value};d-s={cookie_ds_value}" @@ -179,10 +179,13 @@ try: local_config = json.loads(local_config_str) except (OperationalError, TypeError): if not args.token and args.browser not in ["chrome", "chrome-beta"]: - print("Couldn't find the token for team, extract it manually " - "by running 'window.prompt(\"Session token:\", " - "TS.boot_data.api_token)' in your browser dev console " - "and specify it in --token", file=sys.stderr) + print( + "Couldn't find the token for team, extract it manually " + 'by running \'window.prompt("Session token:", ' + "TS.boot_data.api_token)' in your browser dev console " + "and specify it in --token", + file=sys.stderr, + ) sys.exit(1) finally: con.close() @@ -193,17 +196,20 @@ if not local_config and leveldb_path: except pIOErr: leveldb_copy = str(leveldb_path) + ".bak" os.makedirs(leveldb_copy, exist_ok=True) - shutil.copytree(leveldb_path, leveldb_copy, - dirs_exist_ok=True) - print(f"Leveldb was locked by a running browser - made an online copy " - "of it in {leveldb_copy}", file=sys.stderr) + shutil.copytree(leveldb_path, leveldb_copy, dirs_exist_ok=True) + print( + f"Leveldb was locked by a running browser - made an online copy " + "of it in {leveldb_copy}", + file=sys.stderr, + ) db = DB(str(leveldb_copy)) - local_storage_value = db.get( - b'_https://app.slack.com\x00\x01localConfig_v2') + local_storage_value = db.get(b"_https://app.slack.com\x00\x01localConfig_v2") local_config = json.loads(local_storage_value[1:]) teams = [ - team for team in local_config["teams"].values() if not team["id"].startswith("E") + team + for team in local_config["teams"].values() + if not team["id"].startswith("E") ] if not teams: |