def gather_permissions_labels(): # FIXME: would probably put in global db? cmd = '{cli} shell getprop ro.product.model' model = catch_err(run_command(cmd, outf=MAP)).strip().replace(' ', '_') cmd = '{cli} shell pm list permissions -g -f > {outf}' #perms = catch_err(run_command(cmd, outf=model+'.permissions')) perms = catch_err( run_command(cmd, outf='static_data/android_permissions.txt'))
def _dump_phone(self, serial): print('DUMPING iOS INFO...') # FIXME: pathlib migration at some point hmac_serial = config.hmac_serial(serial) cmd = "'{}/ios_dump.sh' {} {Apps} {Info} {Jailbroken-FS} {Jailbroken-SSH}"\ .format(config.SCRIPT_DIR, hmac_serial, **config.IOS_DUMPFILES) print(cmd) path = self.dump_path(serial, fkind='Dir') # dumped = catch_err(run_command(cmd)).strip() dumpf = os.path.join(path, config.IOS_DUMPFILES['Apps']) dumpfinfo = os.path.join(path, config.IOS_DUMPFILES['Info']) #dumped = catch_err(run_command(cmd)).strip() dumped = catch_err(run_command(cmd)).strip() print('iOS DUMP RESULTS for {}:'.format(hmac_serial)) print(dumped) if dumped == serial or True: print("Dumped the data into: {}".format(dumpf)) self.parse_dump = parse_dump.IosDump(dumpf, finfo=dumpfinfo) return True else: print( "Couldn't connect to the device. Trying to reconnect. This way." ) #connected, connected_reason = self.setup() #if not connected: # print(connected_reason) return False
def isrooted(self, serial): ''' Doesn't return all reasons by default. First match will return. TODO: make consistent with iOS isrooted, which returns all reasons discovered. ''' cmd = "{cli} -s {serial} shell 'command -v su'" s = catch_err(run_command(cmd, serial=shlex.quote(serial))) if not s or s == -1 or 'not found' in s or len(s) == 0 or ( s == "[android]: Error running ''. Error (1):"): print(config.error()) reason = "couldn't find 'su' tool on the phone." return (False, reason) else: reason = "found '{}' tool on the phone. Verify whether this is a su binary.".format( s.strip()) return (True, reason) installed_apps = self.installed_apps if not installed_apps: installed_apps = self.get_apps(serial) # FIXME: load these from a private database instead. from OWASP, # https://sushi2k.gitbooks.io/the-owasp-mobile-security-testing-guide/content/0x05j-Testing-Resiliency-Against-Reverse-Engineering.html root_pkgs = ['com.noshufou.android.su','com.thirdparty.superuser',\ 'eu.chainfire.supersu', 'com.koushikdutta.superuser',\ 'com.zachspong.temprootremovejb' ,'com.ramdroid.appquarantine'] root_pkgs_check = list(set(root_pkgs) & set(installed_apps)) if root_pkgs_check: reason = "found the following app(s) on the phone: '{}'."\ .format(str(root_pkgs_check)) return (True, reason)
def uninstall(self, serial, appid): #cmd = '{cli} -i {serial} --uninstall_only --bundle_id {appid!r}' #cmd = 'ideviceinstaller --udid {} --uninstall {appid!r}'.format(serial, appid) cmd = '{}ideviceinstaller --uninstall {appid!r}'.format(self.cli) s = catch_err(run_command(cmd, appid=appid), cmd=cmd, msg="Could not uninstall") return s != -1
def uninstall(self, serial, appid): cmd = '{cli} -s {serial} uninstall {appid!r}' s = catch_err(run_command(cmd, serial=shlex.quote(serial), appid=shlex.quote(appid)), cmd=cmd, msg="Could not uninstall") return s != -1
def _get_apps_(self, serialno, flag): cmd = "{cli} -s {serial} shell pm list packages {flag} | sed 's/^package://g' | sort" s = catch_err(run_command(cmd, serial=serialno, flag=flag), msg="App search failed", cmd=cmd) if not s: self.setup() return [] else: installed_apps = [x for x in s.splitlines() if x] return installed_apps
def devices(self): def _is_device(x): """Is it looks like a serial number""" return re.match(r'[a-f0-9]+', x) is not None #cmd = '{cli} --detect -t1 | tail -n 1' cmd = '{}idevice_id -l | tail -n 1'.format(self.cli) self.serialno = None s = catch_err(run_command(cmd), cmd=cmd, msg="") d = [ l.strip() for l in s.split('\n') if l.strip() and _is_device(l.strip()) ] print("Devices found:", d) return d
def devices(self): # FIXME: check for errors related to err in runcmd.py. #cmd = '{cli} devices | tail -n +2 | cut -f2' #runcmd = catch_err(run_command(cmd), cmd=cmd).strip() #cmd = '{cli} kill-server; {cli} start-server' #s = catch_err(run_command(cmd), time=30, msg="ADB connection failed", cmd=cmd) cmd = '{cli} devices | tail -n +2' runcmd = catch_err(run_command(cmd), cmd=cmd).strip().split('\n') conn_devices = [] for rc in runcmd: d = rc.split() if len(d) != 2: continue device, state = rc.split() device = device.strip() if state.strip() == 'device': conn_devices.append(device) return conn_devices
def recent_permissions_used(appid): df = pd.DataFrame( columns=[ 'appId', 'op', 'mode', 'timestamp', 'time_ago', 'duration']) cmd = '{cli} shell appops get {app}' recently_used = catch_err(run_command(cmd, app=appid)) if 'No operations.' in recently_used: return df record = {'appId': appid} now = datetime.datetime.now() print(recently_used) for permission in recently_used.split('\n')[:-1]: permission_attrs = permission.split(';') record['op'] = permission_attrs[0].split(':')[0] record['mode'] = permission_attrs[0].split(':')[1].strip() if len(permission_attrs) == 2: record['timestamp'] = ( now - _parse_time( permission_attrs[1].split('=')[1].strip())).strftime( config.DATE_STR) # TODO: keep time_ago? that leaks when the consultation was. record['time_ago'] = permission_attrs[1].split('=')[1].strip() else: record['timestamp'] = 'unknown (op)' record['time_ago'] = 'unknown (op)' record['duration'] = 'unknown (op)' df.loc[df.shape[0]] = record continue # NOTE: can convert this with timestamp + _parse_time('duration') if len(permission_attrs) == 3: record['duration'] = permission_attrs[2].split('=')[1].strip() else: record['duration'] = 'unspecified' df.loc[df.shape[0]] = record return df.sort_values(by=['time_ago']).reset_index(drop=True)
def device_info(self, serial): m = {} cmd = '{cli} -s {serial} shell getprop ro.product.brand' m['brand'] = run_command( cmd, serial=serial).stdout.read().decode('utf-8').title() cmd = '{cli} -s {serial} shell getprop ro.product.model' m['model'] = run_command(cmd, serial=serial).stdout.read().decode('utf-8') cmd = '{cli} -s {serial} shell getprop ro.build.version.release' m['version'] = run_command( cmd, serial=serial).stdout.read().decode('utf-8').strip() cmd = '{cli} -s {serial} shell dumpsys batterystats | grep -i "Start clock time:" | head -n1' runcmd = catch_err(run_command(cmd, serial=serial), cmd=cmd) #m['last_full_charge'] = datetime.strptime(runcmd.split(':')[1].strip(), '%Y-%m-%d-%H-%M-%S') m['last_full_charge'] = datetime.now() return "{brand} {model} (running Android {version})".format(**m), m
def setup(self, attempt_remount=False): ''' FIXME: iOS setup. ''' if config.PLATFORM == 'linux' and attempt_remount: # should show GUI prompt for password. sudo apt install policykit-1 if not there. cmd = "pkexec '" + config.SCRIPT_DIR + "/ios_mount_linux.sh' mount" #mountmsg = run_command(cmd).stderr.read().decode('utf-8') if catch_err(run_command(cmd)) == -1: return (False, "Couldn't detect device. See {}/ios_mount_linux.sh."\ .format(config.SCRIPT_DIR)) cmd = '{}idevicepair pair'.format(self.cli) pairmsg = run_command(cmd).stdout.read().decode('utf-8') if "No device found, is it plugged in?" in pairmsg: return (False, pairmsg) elif "Please enter the passcode on the device and retry." in pairmsg: return (False, "Please unlock your device and follow the trust dialog"\ " (you will need to enter your passcode). Then try to scan again.") elif "SUCCESS: Paired with device" in pairmsg: return (True, "Device successfully paired. Setup complete.") elif "said that the user denied the trust dialog." in pairmsg: return (False, "The trust dialog was denied. Please unplug the device"\ ", reconnect it, and scan again -- accept the trust dialog to proceed.") return (True, "Follow trust dialog on iOS device to continue.")
def recent_permissions_used(appid): cols = ['appId', 'op', 'mode', 'timestamp', 'time_ago', 'duration'] df = pd.DataFrame([], columns=cols) cmd = '{cli} shell appops get {app}' recently_used = catch_err(run_command(cmd, app=appid)) if 'No operations.' in recently_used: return df record = {'appId': appid} now = datetime.datetime.now() print(recently_used) for permission in recently_used.split('\n')[:-1]: permission_attrs = permission.split(';') t = permission_attrs[0].split(':') if len(t) != 2: # Could not parse continue record = {c: '' for c in cols} record['op'] = t[0].strip() record['mode'] = t[1].strip() if len(permission_attrs) == 2: tt = permission_attrs[1].split('=') if len(tt) != 2: continue record['timestamp'] = (now - _parse_time(tt[1].strip()))\ .strftime(config.DATE_STR) # TODO: keep time_ago? that leaks when the consultation was. record['time_ago'] = tt[1].strip() if len(permission_attrs) == 3: tt = permission_attrs[2].split('=') if len(tt) == 2: record['duration'] = tt[1].strip() df.loc[df.shape[0]] = record return df.sort_values(by=['time_ago']).reset_index(drop=True)
DEVICE_PRIMARY_USER = { 'me': 'Me', 'child': 'A child of mine', 'partner': 'My current partner/spouse', 'family_other': 'Another family member', 'other': 'Someone else' } ANDROID_PERMISSIONS_CSV = 'static_data/android_permissions.csv' IOS_DUMPFILES = {'Jailbroken': 'ios_jailbroken.log', 'Apps': 'ios_apps.plist', 'Info': 'ios_info.xml'} TEST_APP_LIST = 'static_data/android.test.apps_list' #TITLE = "Anti-IPS: Stop Intimate Partner Surveillance" VERSION_STABLE = catch_err(run_command( 'git describe --abbrev=0 --tags')).strip() VERSION_CURRENT = catch_err(run_command('git describe --tags')).strip() TITLE = {'title': "Mobile Device Privacy Scanner{}".format(" (test)" if TEST else ''), 'version_current': '', 'version_stable': VERSION_STABLE} APP_FLAGS_FILE = 'static_data/app-flags.csv' APP_INFO_FILE = 'static_data/app-info.csv' APP_INFO_SQLITE_FILE = 'sqlite:///static_data/app-info.db' + \ ("~test" if TEST else "") SQL_DB_PATH = 'sqlite:///data/fieldstudy.db' + ("~test" if TEST else "") def set_test_mode(test): global TEST, APP_FLAGS_FILE, SQL_DB_PATH TEST = test