puddly / android-otp-extractor Goto Github PK
View Code? Open in Web Editor NEWExtracts OTP tokens from rooted Android devices
License: GNU General Public License v3.0
Extracts OTP tokens from rooted Android devices
License: GNU General Public License v3.0
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.
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.
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']
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
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
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
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.
Only 3 out of 7 got imported successfully. Using --show-qr
and manually adding the missing ones work (like for Google), except for one: Steam (Invalid QR code
).
I am using:
Here's how I tried to use this script:
.py
file./adb devices
in it's directory to make sure it connects to the phonepython extract_otp_tokens.py
to see what happens, obviously FileNotFoundError: [Errno 2] No such file or directory: 'adb': 'adb'
adb
to same folder as the script, replaced 'adb'
with './adb'
in the script to make it workpython extract_otp_tokens.py
, accepted root permission on phonepython extract_otp_tokens.py --show-qr
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)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?
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 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.
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
https://play.google.com/store/apps/details?id=com.lastpass.authenticator&hl=en
how to extract authenticator from lastpass?
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?
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.
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:
su
.setenforce 0
.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.
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)
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'
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.
I think this works for Duo if Duo is set to use TOTP/HOTP, but Duo has it's own internal protocol, for which this doesn't work.
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
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!
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.
KeyError: 'shared_secret'
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.
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.
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()))
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
.
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}
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?
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.
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']
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!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.