puddly / android-otp-extractor

Extracts OTP tokens from rooted Android devices
GNU General Public License v3.0
231 stars 22 forks source link

Support for newer LineageOS #40

Closed felfert closed 3 years ago

felfert commented 3 years ago

Hi,

This PR adds support for recent LineageOS. Since a while, LineageOS has an additional switch in its debugging setting called "Root-Debugging" which allows to enable/disable the adb root command. After enabling this, one first runs adb root and after that, any adb shell ... runs as root without the need for using a su command. In fact, by default, there is no su command unless one installs something called addonsu (which appears to be broken for me, BTW).

The PR introduces a new flag named require_su and 2 new methods in ADBInterface:

Furthermore, it adds 3 new methods in SingleBinaryADBInterface:

Finally, adb_uid() and adb_gid() are used in guess_adb_interface() to check the effective uid/gid and if it is not 0, enable_root() is used to attempt to switch to root access. If the uid/gid is 0, set_require_su(False) is used, to disable the use of su -c

About the wrapper for shlex.quote:

shlex.quote quotes with single quotes. Therefore, shell vaiables don't get expanded (at first). When using su -c "cmd '$VAR/arg'"' however, a second shell-invocation is performed, effectively eliminating the quotes alltogether which then allows expanding. In order to work without su -c, the outer single quotes have to be replaced by double quotes. That is exactly, what q(string) does.

Cheers -Fritz

felfert commented 3 years ago

BTW: The whole thing should backwards-compatible, because in case that feature is not available, adb root just prints an error and does nothing. Therefore, the second uid/gid-check turns false and the require_su flag is left unchanged (True).

puddly commented 3 years ago

Interesting, I was not aware of this change. I have usually been running LineageOS with Magisk, which does provide a su binary, but I have yet to try out the native LineageOS rooting functionality.

I need to test the quoting a little bit but the other changes look good to me. shlex.quote is not very complicated:

import re

_find_unsafe = re.compile(r'[^\w@%+=:,./-]', re.ASCII).search

def quote(s):
    """Return a shell-escaped version of the string *s*."""
    if not s:
        return "''"

    if _find_unsafe(s) is None:
        return s

    # use single quotes, and put single quotes into double quotes
    # the string $'b is then quoted as '$'"'"'b'
    return "'" + s.replace("'", "'\"'\"'") + "'"

So the q method effectively becomes:

def q(self, s):
    if not s or _find_unsafe(s) is None:
        return s

    return '"' + s.replace("'", "'\"'\"'") + '"'
puddly commented 3 years ago

Yeah, the q method doesn't work too well with reading bad filenames as root using sh:

#!/usr/bin/env python3
import pprint
import logging
import coloredlogs

from android_otp_extractor import TRACE
from android_otp_extractor.cli import LOGGER
from android_otp_extractor.adb import guess_adb_interface

LOGGER.parent.setLevel(TRACE)
coloredlogs.install(level=TRACE)
adb = guess_adb_interface('/data/data/')

f = adb.read_file('$EXTERNAL_STORAGE/Download/test file (1).txt')
pprint.pprint(f.read())

The resulting path is not quoted properly:

su -c "toybox base64 "$EXTERNAL_STORAGE/Download/test file (1).txt"; echo 3bb22bb739c29e435151cb38"

Does merely replacing the call to su -c with sh -c if root is detected work for your phone?

felfert commented 3 years ago

Nice idea, let me give it a try

felfert commented 3 years ago

It does. See above commit, reverting the quoting stuff and using sh -c instead.

puddly commented 3 years ago

Great! It passes my rudimentary test (admittedly a poor substitute for proper unit testing) so this change looks good to me.

Thank you

felfert commented 3 years ago

Interesting, I was not aware of this change. I have usually been running LineageOS with Magisk, which does provide a su binary, but I have yet to try out the native LineageOS rooting functionality.

I believe, that feature was introduced in LineageOS 17.1