Git Product home page Git Product logo

android-otp-extractor's People

Contributors

benoit-pierre avatar deeunderscore avatar felfert avatar gergesh avatar paour avatar puddly avatar sebastianst avatar supersandro2000 avatar therealpsv avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

android-otp-extractor's Issues

"Root not found!" on rooted OPO

I am using Python 3.6.3 from from the Debian Testing repository, on a Debian 9.2 system. The phone is a OnePlusOne with LineageOS version 14.1-2017-1127-NIGHTLY-bacon.

ADB is enabled and at first run of adb devices -l a permission was granted from the phone for such access. ADB output is as expected:
List of devices attached
XXXXXXXX device usb:3-1 product:bacon model:A0001 device:A0001

Root is enabled for both apps and adb on the phone, however when I run android-otp-extractor I always get a "root not found!" error:

$ python3.6 extract_otp_tokens.py  --show-qr
Checking for root. You might have to grant ADB temporary root access.
Root not found!

ADB version reports Android Debug Bridge version 1.0.36, Revision 1:7.0.0+r33-1.

Any advice would be appreciated.

Not working on Windows

On Windows 10, the script can't find app/data folder of Android device because of Windows transforming backslashes.
Obviously, there is no problem on Linux distros or WSL.

ADB Permission problem

Hey, do you know how can i fix this?

C:\Program Files (x86)\Minimal ADB and Fastboot>python -m android_otp_extractor
2020-07-22 23:39:36 DESKTOP-5URJ0ND android_otp_extractor.adb[16904] INFO Testing if your phone uses binary: 'toybox'
2020-07-22 23:39:36 DESKTOP-5URJ0ND android_otp_extractor.adb[16904] INFO Listing contents of / as root
Traceback (most recent call last):
  File "C:\Users\walen\AppData\Local\Programs\Python\Python38\lib\runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Users\walen\AppData\Local\Programs\Python\Python38\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "C:\Users\walen\AppData\Local\Programs\Python\Python38\lib\site-packages\android_otp_extractor\__main__.py", line 3, in <module>
    main()
  File "C:\Users\walen\AppData\Local\Programs\Python\Python38\lib\site-packages\android_otp_extractor\cli.py", line 53, in main
    adb = guess_adb_interface(args.data)
  File "C:\Users\walen\AppData\Local\Programs\Python\Python38\lib\site-packages\android_otp_extractor\adb.py", line 115, in guess_adb_interface
    if not test.list_dir('/'):
  File "C:\Users\walen\AppData\Local\Programs\Python\Python38\lib\site-packages\android_otp_extractor\adb.py", line 78, in list_dir
    lines = self.run(f'{self.binary} ls -1 {shlex.quote(str(path))}', prefix=b'ls: ', root=True)
  File "C:\Users\walen\AppData\Local\Programs\Python\Python38\lib\site-packages\android_otp_extractor\adb.py", line 57, in run
    raise ValueError(f'adb command failed: {lines}')
ValueError: adb command failed: [b'Permission denied\r\n']

Unable to extract tokens.xml of freeOTP

Hi,
I would to migrate from freeOTP to andOTP. I found your script, however I'm not able to extract the file tokens.xml from the path /data/data/org.fedorahosted.freeotp/shared_prefs/. I have a rooted phone with lineageOS 14.1.
Do you have any idea how to save a new backup from freeOTP? I tried to find the file tokens.xml in the memory without success.
Thank you

Fix for #33 breaks Authy's 7 digit tokens

I think that the latest commit, 6270618, caused an issue parsing Authy's 7 digit tokens, specifically Twitch and Humble Bundle in my case. I rolled back to the previous commit and it exported all 15 accounts without issue.

Here's the output it gave on failure:

C:\Users\lorde\Desktop\platform-tools>python -m android_otp_extractor
2020-05-25 09:23:36 Morpheus android_otp_extractor.adb[2084] INFO Testing if your phone uses binary: 'toybox'
2020-05-25 09:23:36 Morpheus android_otp_extractor.adb[2084] INFO Listing contents of / as root
2020-05-25 09:23:36 Morpheus android_otp_extractor.adb[2084] INFO Reading and hashing contents of build.prop as root
2020-05-25 09:23:36 Morpheus android_otp_extractor.adb[2084] INFO Using command line utility binary: 'toybox'
2020-05-25 09:23:36 Morpheus android_otp_extractor.apps[2084] INFO Reading Authy accounts
2020-05-25 09:23:37 Morpheus android_otp_extractor.apps[2084] WARNING Transformed Authy secret XXX into xxx
2020-05-25 09:23:37 Morpheus android_otp_extractor.apps[2084] WARNING Transformed Authy secret YYY into yyy
Traceback (most recent call last):
  File "C:\Users\lorde\AppData\Local\Programs\Python\Python37\lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "C:\Users\lorde\AppData\Local\Programs\Python\Python37\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "C:\Users\lorde\AppData\Local\Programs\Python\Python37\lib\site-packages\android_otp_extractor\__main__.py", line 3, in <module>
    main()
  File "C:\Users\lorde\AppData\Local\Programs\Python\Python37\lib\site-packages\android_otp_extractor\cli.py", line 62, in main
    accounts = apps.read_accounts(adb, enabled_apps)
  File "C:\Users\lorde\AppData\Local\Programs\Python\Python37\lib\site-packages\android_otp_extractor\apps.py", line 336, in read_accounts
    new = list(app.extractor(adb))
  File "C:\Users\lorde\AppData\Local\Programs\Python\Python37\lib\site-packages\android_otp_extractor\apps.py", line 68, in read_authy_accounts
    yield TOTPAccount(account['name'], secret=base64.b32decode(pad_to_8(fixed_secret.upper())), digits=account['digits'], period=period)
  File "C:\Users\lorde\AppData\Local\Programs\Python\Python37\lib\base64.py", line 235, in b32decode
    raise binascii.Error('Incorrect padding')
binascii.Error: Incorrect padding

Battle.net authenticator

First, let me just say this project is rated by me 99999/10. I absolutely love it. Like I can't even begin to describe how much I needed this.

For this post, I heavily rely on referencing: https://gist.github.com/stbuehler/8616943

The secret token (and serial) for the Battle.net Mobile Authenticator on android is stored
in the file: /data/data/com.blizzard.bma/shared_prefs/com.blizzard.bma.AUTH_STORE.xml
in the property "com.blizzard.bma.AUTH_STORE.HASH":

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<long name="com.blizzard.bma.AUTH_STORE.CLOCK_OFFSET" value="[clock offset]" />
<int name="com.blizzard.bma.AUTH_STORE_HASH_VERSION" value="10" />
<string name="com.blizzard.bma.AUTH_STORE.HASH">["encrypted" token]</string>
<long name="com.blizzard.bma.AUTH_STORE.LAST_MODIFIED" value="[timestamp]" />
</map>

 The encrypted token is a hex string, encoding 57 bytes; decode it into a byte array, decrypt it with
 the xor "mask". The decrypted token now consists of 40 bytes hex-encoding the secret and 17 bytes with
 the serial (US|EU)-\d{4}-\d{4}-\d{4}

 The hex-decoded secret can be used with TOTP (RFC 6238; X = 30, T0 = 0, digit = 8) to generate
 the authentication codes.

The code to decypt it is a Ruby script:

def base32(str)
	cDIGITS = ('A'..'Z').to_a + ('2'..'7').to_a
	dMASK = 0x1f
	cSHIFT = 5

	bytes = str.unpack('C*')

	paddedLen = 8 * ((bytes.length + 4)/5)

	bits = 0
	haveBits = 0

	b32 = []
	bytes.each do |byte|
		bits = (bits << 8) | byte
		haveBits += 8

		while haveBits >= cSHIFT
			b32 << cDIGITS[dMASK & (bits >> (haveBits - cSHIFT))]
			haveBits -= cSHIFT
		end
		bits &= dMASK
	end

	if haveBits > 0
		b32 << cDIGITS[dMASK & (bits << (cSHIFT - haveBits))]
	end

	b32.join + "=" * (paddedLen - b32.length)
end

def otpauth(serial, token)
	"otpauth://totp/#{serial}:#{serial}?secret=#{base32(token)}&issuer=#{serial}&digits=8"
end

mask = [57,142,39,252,80,39,106,101,96,101,176,229,37,244,192,108,4,198,16,117,40,107,142,122,237,165,157,169,129,59,93,214,200,13,47,179,128,104,119,63,165,155,164,124,23,202,108,100,121,1,92,29,91,139,143,107,154]

STDOUT.puts "Enter encrypted token (or press enter to read with adb shell): "

token = STDIN.readline.strip

if token.length == 0
	IO.popen(["adb", "shell", "cat", "/data/data/com.blizzard.bma/shared_prefs/com.blizzard.bma.AUTH_STORE.xml"], "r") do |i|
		i.readlines.each do |line|
			m = /<string name="com.blizzard.bma.AUTH_STORE.HASH">(.*)<\/string>/.match(line)
			token = m[1] if m
		end
	end
end

token = [token].pack('H*').unpack('C*').zip(mask).map { |a,b| a ^ b }.pack('C*')

serial = token[40..-1]
token = [token[0..39]].pack('H*')

otpurl = otpauth(serial, token)
puts otpurl

require 'tempfile'

img = Tempfile.new(['otpauth_qr', '.png'])
if system("qrencode", "-s", "5", "-o", img.path, otpurl)
	puts "press escape to exit 'display'"
	STDERR.puts "'display' failed, maybe binary is not available" if not system("display", img.path)
else
	STDERR.puts "'qrencode' failed, maybe binary is not available?"
end

Tutorial on install

I have tried to use this multiple times on termux and it has failed, looping over the dependencies. Can you create a tutorial for this? And yes, my phone is rooted.

Usage without system-wide ADB

I am using:

  • Manjaro 17.1.10 (latest stable)
  • Python 3.6.5
  • this script from 34337a6
  • Authy 23.2.6
  • AndOTP 0.5.1
  • Android 8.1 (June 5 patch)
  • Magisk 16.0

Here's how I tried to use this script:

  1. Got ADB from Google (guess I could've gotten it through some AUR package but didn't want to try them all)
  2. Got this script .py file
  3. Unpacked both
  4. Ran ./adb devices in it's directory to make sure it connects to the phone
  5. Ran python extract_otp_tokens.py to see what happens, obviously FileNotFoundError: [Errno 2] No such file or directory: 'adb': 'adb'
  6. Moved adb to same folder as the script, replaced 'adb' with './adb' in the script to make it work
  7. Ran python extract_otp_tokens.py, accepted root permission on phone
  8. Got a bit confused due to lack of output, so ran python extract_otp_tokens.py --show-qr
  9. file:///tmp/tmp... opened in (where ... is a random ending string) browser with title "OTP QR Codes" and no content (source is valid HTML though)
  10. Tried python extract_otp_tokens.py --andotp-backup ANDOTP_BACKUP which produced file ANDOTP_BACKUP with contents []

The succeeded commands had the following log in terminal:

Listing directory /data/data
Reading file /data/data/com.authy.authy/shared_prefs/com.authy.storage.tokens.authenticator.xml
Reading file /data/data/com.authy.authy/shared_prefs/com.authy.storage.tokens.authy.xml
Reading file /data/data/com.duosecurity.duomobile/files/duokit/accounts.json
Reading file /data/data/org.fedorahosted.freeotp/shared_prefs/tokens.xml
Reading file /data/data/com.google.android.apps.authenticator2/databases/databases
Reading file /data/data/com.azure.authenticator/databases/PhoneFactor
Listing directory /data/data/com.valvesoftware.android.steam.community/files

Any ideas?

Microsoft authenticator mismatch

I'm seeing a mismatch with MS authenticator. The tool doesn't throw any errors. The codes do not match though. Please let me know if you need any debugging info. From the other issue, I used the script to generate this dump:

'_id': 3,
 'aad_authority': '',
 'aad_ngc_totp_enabled': 1,
 'aad_security_defaults_policy_enabled': 0,
 'aad_tenant_id': 'xxx',
 'aad_user_id': 'xxx',
 'account_capability': 5,
 'account_type': 2,
 'cached_pin': '',
 'cid': '',
 'encrypted_oath_secret_key': '',
 'group_key': 'xxx',
 'has_password': 1,
 'identity_provider': '',
 'is_totp_code_shown': 1,
 'mfa_pin_encryption_key_alias': '',
 'name': 'xxx',
 'ngc_ski': '',
 'oath_enabled': 1,
 'oath_secret_key': 'xxx',
 'paws_url': 'https://mobileappcommunicator.auth.microsoft.com/mac/MobileAppCommunicator.svc/055465524',
 'restore_capability': 0,
 'update_flags': 1,
 'username': '[email protected]',
 'ux_position': 1}

freeotp title/tags cosmetic issue

freeotp tokens have multiple fields (issuerExt, issuerInt and label). I think different providers use them differently. The script only retains the label. For most of my freeotp tokens, the label is just my email. That makes it hard to distinguish different tokens.

gvfs-open: data:text/html;base64 error opening location: The specified location is not supported

I am not able to open the QR codes in the browser. The script exits with the following error:

gvfs-open: data:text/html;base64 error opening location: The specified location is not supported

Between "gvfs-open: data:text/html;base64" and "error opening location..." there is a big hash or something like that. I do not now if this hash is OTP relevant or not.
Everything seems to run fine until the browser should be opened to show the QR codes.
My system:
Linux Mint 18.3 Cinnamon 64-bit
Android Debug Bridge version 1.0.32
Revision debian
LineageOS 15.1

Can't create backup protected passwords

I allowed broadcasts to create password protected backups but I always get a notification that password protected backups are not supported. Any idea why this is happening and if this is an issue with andOTP?

Reading Google Authenticator accounts broken since 70f51be

The commit 455c45f broke google authenticator extraction for me:

./extract_otp_tokens.py --show-qr
[2019-02-26 13:29:41,343]     INFO [<module>:561] Testing if your phone uses toybox...
[2019-02-26 13:29:41,566]     INFO [<module>:576] It does!
[2019-02-26 13:29:41,566]     INFO [<module>:583] Checking for root by listing the contents of $ANDROID_DATA/data. You might have to grant ADB temporary root access.
[2019-02-26 13:29:41,729]     INFO [<module>:589] Checking if files can be properly read by reading $ANDROID_ROOT/build.prop
[2019-02-26 13:29:41,880]     INFO [<module>:610] Reading AndOTP accounts
[2019-02-26 13:29:42,012]     INFO [<module>:615] Found 0 accounts (0 new)
[2019-02-26 13:29:42,012]     INFO [<module>:610] Reading Authy accounts
[2019-02-26 13:29:42,291]     INFO [<module>:615] Found 0 accounts (0 new)
[2019-02-26 13:29:42,291]     INFO [<module>:610] Reading Duo accounts
[2019-02-26 13:29:42,424]     INFO [<module>:615] Found 0 accounts (0 new)
[2019-02-26 13:29:42,424]     INFO [<module>:610] Reading FreeOTP accounts
[2019-02-26 13:29:42,562]     INFO [<module>:615] Found 0 accounts (0 new)
[2019-02-26 13:29:42,562]     INFO [<module>:610] Reading Google Authenticator accounts
Traceback (most recent call last):
  File "./extract_otp_tokens.py", line 611, in <module>
    new = list(function(adb, args.data))
  File "./extract_otp_tokens.py", line 322, in read_google_authenticator_accounts
    with open_remote_sqlite_database(adb, data_root/'com.google.android.apps.authenticator2/databases/databases') as connection:
  File "/usr/lib64/python3.6/contextlib.py", line 81, in __enter__
    return next(self.gen)
  File "./extract_otp_tokens.py", line 255, in open_remote_sqlite_database
    connection = sqlite3.connect(temp_dir/database.name)
TypeError: argument 1 must be str, not PosixPath

When checking out an earlier commit, everything works except the bugs this commit fixed.

Interface with the Android KeyStore

Apps are slowly beginning to use the Android KeyStore to encrypt database entries or the entire database itself, making it impossible to extract information without interfacing with the Android KeyStore. Thankfully we don't really care about the encryption keys themselves and just want to ask the KeyStore to decrypt data, which is just what the KeyStore is for.

Using some of the setup code from scrcpy's Android server, I've written a small Java tool that can be pushed to the device and run as an app's user to provide an interactive KeyStore interface for the Python code.

Checklist:

  • Successfully interact with the Android KeyStore as an app user via su.
  • Interact with the Android KeyStore without having to call setenforce 0.
  • The current ADB wrapper is a little fragile due to the various quirks exhibited by old ADB servers and BusyBox versions (or lack of thereof) installed on old devices. The major issue right now is the inability to interactively send and receive commands during a shell session and instead being forced to run commands one-by-one via adb shell. This is more a performance optimization than anything else but it taking a minute to read and decrypt a few files is annoying.
    • One possible solution to both problems is to integrate file reading and related commands into the KeyStore proxy, which would remove the BusyBox dependency. This would require the KeyStore proxy to have the ability to execute commands as other users (including itself).

Steam doesn't show letters, just numbers

Hi,
It seems that codes displayed for Steam are showing 5 digits rather than 5 alphanumeric characters.
A steam code should have both a mixture of letters and numbers.

I use WinAuth for my emergency backup portable 2FA solution. It does support Steam 2FA and successfully shows alphanumeric instead of all just numbers.

-I would recommend looking at the WinAuth source code to see how the author successfully decodes Steam 2FA to show alphanumeric characters for Steam URIs.
-In order to decipher Steam OTP's, WinAuth requires &issuer=Steam in the OTPAuth URI. Please consider appending this to anything exported from Steam (I did it manually... not a big deal. Just would add support for others using WinAuth)

error on readding Steam codes

After fixing #17, another error occurs when trying to read Steam codes:

Traceback (most recent call last):
  File "./extract_otp_tokens.py", line 532, in <module>
    accounts.update(read_steam_authenticator_accounts(args.data))
  File "./extract_otp_tokens.py", line 412, in read_steam_authenticator_accounts
    yield SteamAccount(account_json['account_name'], secret)
  File "./extract_otp_tokens.py", line 37, in __init__
    self.secret = normalize_secret(secret)
  File "./extract_otp_tokens.py", line 187, in normalize_secret
    return secret.upper().rstrip('=')
TypeError: a bytes-like object is required, not 'str'

Google Authenticator import misses the last three keys

I have 20 keys in total in my Google Authenticator and only the first 17 get extracted. I deleted one key in the middle and still, the last three keys are omitted. The verbose output doesn't show anything suspicious.

Authenticator Plus

Hi, I've started looking into how we can add support for some more popular Authenticator apps.
I am going to open this and close it- I don't need it personally- but if you want to implement it, I will reopen this and I am happy to test.
Happy to do the same for any other authenticator too and help test- I really like this project and happy to help. I have wanted a way of extracting OTPauths out of Authenticators for YEARS.

Authenticator Plus is a common one I've seen on the play store for years:
Data is stored in SQLCipher encrypted database at
/sdcard/AuthenticatorPlus/.synced_authplus.db

A master password is required to use Authenticator Plus.
Master password is stored in the Android local database.
In rooted device, PIN lock is mandated, and your master password is encrypted with your PIN

More technical directions:
https://authenticatorplus.freshdesk.com/support/solutions/articles/5000541895-technical-details-of-authenticator-plus

Play store link:
https://play.google.com/store/apps/details?id=com.mufri.authenticatorplus&hl=en_CA&gl=US

OSError: b"Unknown option '-1'. Aborting."

I'm running your script on my Windows 10 Pro machine with Python 3.6.4 and ADB 1.0.3.9.
My rooted Android 4.4.2 tablet with kernel 3.4.0 is connected via USB with debugging enabled.

When executing the script, I get the following error:

C:\Program Files (x86)\Minimal ADB and Fastboot>py -3 D:\Downloads\android-otp-extractor-master\extract_otp_tokens.py
[2018-10-09 19:09:28,088]     INFO [<module>:519] Checking for root by listing the contents of data/data. You might have to grant ADB temporary root access.
Traceback (most recent call last):
  File "D:\Downloads\android-otp-extractor-master\extract_otp_tokens.py", line 521, in <module>
    if not adb_list_dir(args.data):
  File "D:\Downloads\android-otp-extractor-master\extract_otp_tokens.py", line 175, in adb_list_dir
    lines = adb_fast_run(f'su -c "ls -1 {shlex.quote(str(path))}"', prefix=b'ls: ')
  File "D:\Downloads\android-otp-extractor-master\extract_otp_tokens.py", line 167, in adb_fast_run
    raise IOError(message)
OSError: b"Unknown option '-1'. Aborting."

How can I solve this issue?

Thank you!

Failed to perform extract from GAuth

Hi!

First I've got this error:

  File "/usr/local/lib/python3.7/site-packages/android_otp_extractor/apps.py", line 132, in read_google_authenticator_accounts
    name = row['name'] if row['name'] is not None else row['email']
IndexError: No item with that key

I don't know python very good (this is why I didn't prepare PR :) ) and don't find the way to fix it to support both fields, so I've just replaced this line with name = row['email']. It worked for some codes but failed for one in lowercase with

  File "/usr/local/lib/python3.7/site-packages/android_otp_extractor/apps.py", line 136, in read_google_authenticator_accounts
    secret = base64.b32decode(row['secret'])
  File "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/base64.py", line 231, in b32decode
    raise binascii.Error('Non-base32 digit found') from None
binascii.Error: Non-base32 digit found

I've tried to change the line with secret = base64.b32decode(row['secret'].upper()), it worked for this code but failed for later one with

  File "/usr/local/lib/python3.7/site-packages/android_otp_extractor/apps.py", line 136, in read_google_authenticator_accounts
    secret = base64.b32decode(row['secret'].upper())
  File "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/base64.py", line 205, in b32decode
    raise binascii.Error('Incorrect padding')
binascii.Error: Incorrect padding

So finally I got it working with

secret = row['secret']
# and 
class OTPAccount:
    def secret(self):
        # return base64.b32encode(self._secret).decode('ascii').rstrip('=')
        return self._secret

I've compared imported code in andOTP and they appear to be the same as in GAuth.

I hope this helps.

Microsoft Authenticator import wrong

The TOTP for the Microsoft Account in the Microsoft Authenticator app is 8 numbers long. The code the tool generates tells andOTP to only generate 6 tokens which is not accepted at Microsofts end.

Simply changing to 8 digits does not work either.

Can't get root/access

Hey,

Just tried your software.
I have some problems with andotp. I would like to update my RRemix system. After the update I can't use andotp even with the plan backups.

Anyway..
I tried your software and a pop up popped up and I gave it access. It stopped with
Checking for root. You might have to grant ADB temporary root access. Unknown id: TEST Root not found! .
But I can get access with adb shell.

Can I use a command to get my 2fa accounts showed up in my browser or something?
I tried to read your code but I'm not good at this. Adb shell as well.

So, root and adb access is available.

Thanks

Edit:
Sry, just saw there are already 2 closed issues.
I read this #3 but I don't really understand this.

error on readding Authy/Steam codes

Traceback (most recent call last):
  File "./extract_otp_tokens.py", line 515, in <module>
    accounts.update(read_authy_accounts(args.data))
  File "./extract_otp_tokens.py", line 41, in __hash__
    return hash(self.as_uri())
  File "./extract_otp_tokens.py", line 62, in as_uri
    return f'otpauth://{self.type}/{quote(name)}?' + urlencode(sorted(params.items()))
UnboundLocalError: local variable 'name' referenced before assignment

Looks like the first patch hunk of 0649bc6 is the reason.

This work:

diff --git i/extract_otp_tokens.py w/extract_otp_tokens.py
index 981ae51..4dcb74c 100755
--- i/extract_otp_tokens.py
+++ w/extract_otp_tokens.py
@@ -58,6 +58,8 @@ def as_uri(self, prepend_issuer=False):
 
         if prepend_issuer and self.issuer:
             name = f'{self.issuer}: {self.name}'
+        else:
+            name = self.name or "Unknown"
 
         return f'otpauth://{self.type}/{quote(name)}?' + urlencode(sorted(params.items()))

Broken sqlite database from `adb exec-out`

Thanks for this tool!

I tried to dump Google Authenticator secrets but that failed because adb exec-out does not dump the complete database file in my case (don't know why, reproducible when run manually). I ended up copying the file (as root) to a temp directory and and than from phone to pc via adb pull.

Microsoft Authenticator

Hi,
I am having an issue with my Microsoft Authenticator
its not grabbing my personal 8 digit microsoft.com code
I simply set up the default Microsoft.com personal authenticator with the Microsoft Authenticator app. Very vanilla install.
It works with my 3 work Microsoft OTPs, but it does not work with my very standard Microsoft.com personal one

root@Debian10:~/Desktop# python3 -m android_otp_extractor --verbose --include microsoft_authenticator
2021-06-01 12:26:20 Debian10 android_otp_extractor.adb[1038] INFO Testing if your phone uses binary: 'toybox'
2021-06-01 12:26:20 Debian10 android_otp_extractor.adb[1038] INFO Checking if adb already runs as root
2021-06-01 12:26:20 Debian10 android_otp_extractor.adb[1038] INFO Attempting to enable adb root
2021-06-01 12:26:20 Debian10 android_otp_extractor.adb[1038] INFO Listing contents of / as root
2021-06-01 12:26:20 Debian10 android_otp_extractor.adb[1038] DEBUG Listing directory /
2021-06-01 12:26:20 Debian10 android_otp_extractor.adb[1038] INFO Reading and hashing contents of build.prop as root
2021-06-01 12:26:20 Debian10 android_otp_extractor.adb[1038] DEBUG Hashing file $ANDROID_ROOT/build.prop
2021-06-01 12:26:20 Debian10 android_otp_extractor.adb[1038] DEBUG Trying to read file $ANDROID_ROOT/build.prop
2021-06-01 12:26:20 Debian10 android_otp_extractor.adb[1038] DEBUG Successfully read 2018 bytes
2021-06-01 12:26:20 Debian10 android_otp_extractor.adb[1038] DEBUG Hashing file $ANDROID_ROOT/build.prop
2021-06-01 12:26:20 Debian10 android_otp_extractor.adb[1038] DEBUG Trying to read file $ANDROID_ROOT/build.prop
2021-06-01 12:26:20 Debian10 android_otp_extractor.adb[1038] DEBUG Successfully read 2018 bytes
2021-06-01 12:26:20 Debian10 android_otp_extractor.adb[1038] INFO Using command line utility binary: 'toybox'
2021-06-01 12:26:20 Debian10 android_otp_extractor.apps[1038] INFO Reading Microsoft Authenticator accounts
2021-06-01 12:26:20 Debian10 android_otp_extractor.adb[1038] DEBUG Trying to read file $ANDROID_DATA/data/com.azure.authenticator/databases/PhoneFactor
2021-06-01 12:26:20 Debian10 android_otp_extractor.adb[1038] DEBUG Successfully read 24576 bytes
2021-06-01 12:26:20 Debian10 android_otp_extractor.adb[1038] DEBUG Trying to read file $ANDROID_DATA/data/com.azure.authenticator/databases/PhoneFactor-journal
2021-06-01 12:26:20 Debian10 android_otp_extractor.adb[1038] DEBUG Trying to read file $ANDROID_DATA/data/com.azure.authenticator/databases/PhoneFactor-wal
2021-06-01 12:26:20 Debian10 android_otp_extractor.adb[1038] DEBUG Successfully read 309032 bytes
2021-06-01 12:26:20 Debian10 android_otp_extractor.adb[1038] DEBUG Trying to read file $ANDROID_DATA/data/com.azure.authenticator/databases/PhoneFactor-shm
2021-06-01 12:26:20 Debian10 android_otp_extractor.adb[1038] DEBUG Successfully read 32768 bytes

2021-06-01 12:26:20 Debian10 android_otp_extractor.apps[1038] WARNING Unknown Microsoft account type: 1

{'_id': 2,
 'aad_authority': '',
 'aad_ngc_totp_enabled': 0,
 'aad_security_defaults_policy_enabled': 0,
 'aad_tenant_id': '',
 'aad_user_id': '',
 'account_capability': 7,
 'account_type': 1,
 'cached_pin': '',
 'cid': 'XXXXXXXXXXXXXXXX',
 'encrypted_oath_secret_key': '',
 'group_key': '00000000000000000000000000000000',
 'has_password': 1,
 'identity_provider': '',
 'is_totp_code_shown': 0,
 'mfa_pin_encryption_key_alias': '',
 'name': 'Microsoft',
 'ngc_ski': 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
 'oath_enabled': 1,
 'oath_secret_key': 'XXXXXXXXXXXXXXXX',
 'paws_url': '',
 'restore_capability': 0,
 'username': '[email protected]',
 'ux_position': 2}

Got Permission Error

Running on a Windows 10 system, with python-3.6.5-amd64 installed.
temp folder is at R:\temp and I'm running the script with an administrative user on a rooted phone

r:>extract_otp_tokens.py
Checking for root by listing the contents of /data/data. You might have to grant ADB temporary root access.
Listing directory /data/data
Reading file /data/data/com.authy.authy/shared_prefs/com.authy.storage.tokens.authenticator.xml
Reading file /data/data/com.authy.authy/shared_prefs/com.authy.storage.tokens.authy.xml
Reading file /data/data/com.duosecurity.duomobile/files/duokit/accounts.json
Reading file /data/data/org.fedorahosted.freeotp/shared_prefs/tokens.xml
Reading file /data/data/com.google.android.apps.authenticator2/databases/databases
Traceback (most recent call last):
File "R:\extract_otp_tokens.py", line 335, in
accounts.update(read_google_authenticator_accounts(args.data))
File "R:\extract_otp_tokens.py", line 166, in read_google_authenticator_accounts
os.unlink(temp_handle.name)
PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'R:\Temp\tmpp9lauv0b.html'

Any ideas why it wouldn't work?

ValueError: Invalid suffix '-journal'

error details:

โžœ  ~ python -m android_otp_extractor --andotp-backup otp.json
2020-02-28 13:05:04 oSdb android_otp_extractor.cli[9195] INFO Checking for root by listing the contents of $ANDROID_DATA/data. You might have to grant ADB temporary root access.
2020-02-28 13:05:04 oSdb android_otp_extractor.cli[9195] INFO Checking if files can be properly read by reading $ANDROID_ROOT/build.prop
2020-02-28 13:05:04 oSdb android_otp_extractor.apps[9195] INFO Reading Authy accounts
2020-02-28 13:05:04 oSdb android_otp_extractor.apps[9195] INFO Found 0 accounts (0 new)
2020-02-28 13:05:04 oSdb android_otp_extractor.apps[9195] INFO Reading FreeOTP accounts
2020-02-28 13:05:04 oSdb android_otp_extractor.apps[9195] INFO Found 0 accounts (0 new)
2020-02-28 13:05:04 oSdb android_otp_extractor.apps[9195] INFO Reading FreeOTP+ accounts
2020-02-28 13:05:04 oSdb android_otp_extractor.apps[9195] INFO Found 0 accounts (0 new)
2020-02-28 13:05:04 oSdb android_otp_extractor.apps[9195] INFO Reading Duo accounts
2020-02-28 13:05:05 oSdb android_otp_extractor.apps[9195] INFO Found 0 accounts (0 new)
2020-02-28 13:05:05 oSdb android_otp_extractor.apps[9195] INFO Reading Google Authenticator accounts
Traceback (most recent call last):
  File "/home/zzndb/.pyenv/versions/3.7.1/lib/python3.7/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/home/zzndb/.pyenv/versions/3.7.1/lib/python3.7/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/home/zzndb/.pyenv/versions/virtual-env-3.7.1/lib/python3.7/site-packages/android_otp_extractor/__main__.py", line 3, in <module>
    main()
  File "/home/zzndb/.pyenv/versions/virtual-env-3.7.1/lib/python3.7/site-packages/android_otp_extractor/cli.py", line 74, in main
    accounts = apps.read_accounts(adb, enabled_apps)
  File "/home/zzndb/.pyenv/versions/virtual-env-3.7.1/lib/python3.7/site-packages/android_otp_extractor/apps.py", line 318, in read_accounts
    new = list(app.extractor(adb))
  File "/home/zzndb/.pyenv/versions/virtual-env-3.7.1/lib/python3.7/site-packages/android_otp_extractor/apps.py", line 118, in read_google_authenticator_accounts
    with open_remote_sqlite_database(adb, adb.data_root/'com.google.android.apps.authenticator2/databases/databases') as connection:
  File "/home/zzndb/.pyenv/versions/3.7.1/lib/python3.7/contextlib.py", line 112, in __enter__
    return next(self.gen)
  File "/home/zzndb/.pyenv/versions/virtual-env-3.7.1/lib/python3.7/site-packages/android_otp_extractor/contrib.py", line 21, in open_remote_sqlite_database
    remote_file = database.with_suffix(suffix)
  File "/home/zzndb/.pyenv/versions/3.7.1/lib/python3.7/pathlib.py", line 827, in with_suffix
    raise ValueError("Invalid suffix %r" % (suffix))
ValueError: Invalid suffix '-journal'

--

intall the latest version.
get the same error from system python and virtualenv python environment.

Unhandled Exceptions

Hi,
When the phone isn't plugged in and you try to run the script, it gives a Value Error
I believe you should try and catch ADB errors as an exception and display it nicely to the user, and ask if the phone is plugged in, if ADB is running, of USB Debugging is enabled, etc.

2021-05-31 10:06:24 BlackPearl android_otp_extractor.adb[39864] INFO Testing if your phone uses binary: 'toybox'
2021-05-31 10:06:24 BlackPearl android_otp_extractor.adb[39864] INFO Checking if adb already runs as root
Traceback (most recent call last):
  File "c:\python3\lib\runpy.py", line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "c:\python3\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "c:\python3\lib\site-packages\android_otp_extractor\__main__.py", line 3, in <module>
    main()
  File "c:\python3\lib\site-packages\android_otp_extractor\cli.py", line 53, in main
    adb = guess_adb_interface(args.data)
  File "c:\python3\lib\site-packages\android_otp_extractor\adb.py", line 136, in guess_adb_interface
    if '0' == test.adb_uid() and '0' == test.adb_gid():
  File "c:\python3\lib\site-packages\android_otp_extractor\adb.py", line 89, in adb_uid
    lines = self.run(f'{self.binary} id -u', prefix=b'id: ', root=False)
  File "c:\python3\lib\site-packages\android_otp_extractor\adb.py", line 71, in run
    raise ValueError(f'adb command failed: {lines}')
ValueError: adb command failed: [b'error: no devices/emulators found\r\n']

Similar error but on my Raspberry Pi

2021-05-31 10:42:19 Harbormaster android_otp_extractor.adb[25587] INFO Testing if your phone uses binary: 'toybox'
2021-05-31 10:42:19 Harbormaster android_otp_extractor.adb[25587] INFO Checking if adb already runs as root
Traceback (most recent call last):
  File "/usr/lib/python3.7/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/lib/python3.7/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/usr/local/lib/python3.7/dist-packages/android_otp_extractor/__main__.py", line 3, in <module>
    main()
  File "/usr/local/lib/python3.7/dist-packages/android_otp_extractor/cli.py", line 53, in main
    adb = guess_adb_interface(args.data)
  File "/usr/local/lib/python3.7/dist-packages/android_otp_extractor/adb.py", line 136, in guess_adb_interface
    if '0' == test.adb_uid() and '0' == test.adb_gid():
  File "/usr/local/lib/python3.7/dist-packages/android_otp_extractor/adb.py", line 89, in adb_uid
    lines = self.run(f'{self.binary} id -u', prefix=b'id: ', root=False)
  File "/usr/local/lib/python3.7/dist-packages/android_otp_extractor/adb.py", line 71, in run
    raise ValueError(f'adb command failed: {lines}')
ValueError: adb command failed: [b'error: device offline\n']

Error trying to read Duo accounts

Try to run this and it fails on reading back Duo accounts, which is the only app I'm actually using and want the data out of.

021-04-21 23:14:33 localhost.localdomain android_otp_extractor.adb[3141] INFO Testing if your phone uses binary: 'toybox' 2021-04-21 23:14:33 localhost.localdomain android_otp_extractor.adb[3141] INFO Checking if adb already runs as root 2021-04-21 23:14:33 localhost.localdomain android_otp_extractor.adb[3141] INFO Listing contents of / as root 2021-04-21 23:14:33 localhost.localdomain android_otp_extractor.adb[3141] INFO Reading and hashing contents of build.prop as root 2021-04-21 23:14:34 localhost.localdomain android_otp_extractor.adb[3141] INFO Using command line utility binary: 'toybox' 2021-04-21 23:14:34 localhost.localdomain android_otp_extractor.apps[3141] INFO Reading Authy accounts 2021-04-21 23:14:34 localhost.localdomain android_otp_extractor.apps[3141] INFO Found 0 accounts (0 new) 2021-04-21 23:14:34 localhost.localdomain android_otp_extractor.apps[3141] INFO Reading FreeOTP accounts 2021-04-21 23:14:34 localhost.localdomain android_otp_extractor.apps[3141] INFO Found 0 accounts (0 new) 2021-04-21 23:14:34 localhost.localdomain android_otp_extractor.apps[3141] INFO Reading FreeOTP+ accounts 2021-04-21 23:14:34 localhost.localdomain android_otp_extractor.apps[3141] INFO Found 0 accounts (0 new) 2021-04-21 23:14:34 localhost.localdomain android_otp_extractor.apps[3141] INFO Reading Duo accounts Traceback (most recent call last): File "/usr/lib64/python3.9/runpy.py", line 197, in _run_module_as_main return _run_code(code, main_globals, None, File "/usr/lib64/python3.9/runpy.py", line 87, in _run_code exec(code, run_globals) File "/home/kent/.local/lib/python3.9/site-packages/android_otp_extractor/__main__.py", line 3, in <module> main() File "/home/kent/.local/lib/python3.9/site-packages/android_otp_extractor/cli.py", line 62, in main accounts = apps.read_accounts(adb, enabled_apps) File "/home/kent/.local/lib/python3.9/site-packages/android_otp_extractor/apps.py", line 353, in read_accounts new = list(app.extractor(adb)) File "/home/kent/.local/lib/python3.9/site-packages/android_otp_extractor/apps.py", line 116, in read_duo_accounts secret = base64.b32decode(account['otpGenerator']['otpSecret']) File "/usr/lib64/python3.9/base64.py", line 231, in b32decode raise binascii.Error('Non-base32 digit found') from None binascii.Error: Non-base32 digit found

Hoping to get my accounts out of Duo before switching phones. Any help appreciated!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.