def validate(queue): results = [] wv_dec_list=find_webviews() #remove empty list items wv_dec_list=filter(None,wv_dec_list) #remove duplicates #Need to check why duplicates would even occur, may lead to false negatives wv_dec_list=common.dedup(wv_dec_list) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData("FOUND " + str(len(wv_dec_list)) + " WEBVIEWS:") results.append(issue) #BUG IN OUTPUT for p in wv_dec_list: issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(str(p)) results.append(issue) #logger.info(str(p)) #print "\n" #search for WebView configuration settings wv_decs=find_wv_settings_dec(wv_dec_list, results) queue.put(results) return
def validate(queue): results = [] wv_dec_list = find_webviews() #remove empty list items wv_dec_list = filter(None, wv_dec_list) #remove duplicates #Need to check why duplicates would even occur, may lead to false negatives wv_dec_list = common.dedup(wv_dec_list) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData("FOUND " + str(len(wv_dec_list)) + " WEBVIEWS:") results.append(issue) #BUG IN OUTPUT for p in wv_dec_list: issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(str(p)) results.append(issue) #logger.info(str(p)) #print "\n" #search for WebView configuration settings wv_decs = find_wv_settings_dec(wv_dec_list, results) queue.put(results) return
#Look for TapJacking vulnerabilities #Native protection was added in API v. 9, so previous likely vulnerable if common.minSdkVersion >8: common.logger.debug("Beginning TapJacking testing") findTapJacking.start(common.sourceDirectory) else: common.logger.log(common.VULNERABILITY_LEVEL,"Since the minSdkVersion is less that 9, it is likely this application is vulnerable to TapJacking. QARK made no attempt to confirm, as the protection would have to be custom code, which is difficult for QARK to examine and understand properly. This vulnerability allows a malicious application to lay on top of this app, while letting the key strokes pass through to the application below. This can cause users to take unwanted actions, within the victim application, similar to Clickjacking on websites. Please select the appropriate options in the exploitation menus to verify manually using QARK's exploit APK. Note: The QARK proof-of-concept is transparent, but in real-world attacks, it would likely not be. This is done solely to aid in testing. For more information: https://media.blackhat.com/ad-12/Niemietz/bh-ad-12-androidmarcus_niemietz-WP.pdf") ########### #Look for Content Provider issues if len(common.text_scan(common.java_files,cp_imp_rex)) > 1: common.logger.info("Content Providers appear to be in use, locating...") cp_dec_list=contentProvider.find_content_providers() cp_dec_list=filter(None,cp_dec_list) cp_dec_list=common.dedup(cp_dec_list) common.logger.info("FOUND " + str(len(cp_dec_list)) + " CONTENTPROVIDERS:") for p in cp_dec_list: common.logger.info(str(p)) query_rex=r'\.query\(.*\)' update_rex=r'\.update\(.*\)' delete_rex=r'\.delete\(.*\)' insert_rex=r'\.insert\(.*\)' #TODO - Add SQLi checks #VERY LAME SQL INJECTION DETECTION (GUESSING) statement_list=[] statement_list.append([]) for p in cp_dec_list: if len(p)>1:
def show_adb_commands(component,compType,packageName): #Print ADB commands for exploitation cmd_list=[] cmd_list.append([]) #BUG - THIS PRINTS DUPS extra_parameters=[] extra_parameters.append('[-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]') extra_parameters.append('[--esn <EXTRA_KEY> ...]') extra_parameters.append('[--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]') extra_parameters.append('[--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]') extra_parameters.append('[--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]') extra_parameters.append('[--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE> ...]') extra_parameters.append('[--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]') extra_parameters.append('[--ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE>]') extra_parameters.append('[--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]') extra_parameters.append('[--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]') extra_parameters.append('[--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]') extra_parameters.append('[--esa <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]') type_list=['String','StringArray','StringArrayList','Boolean','BooleanArray','Int','Float','Long','LongArray','[]','','IntArray','IntegerArrayList','FloatArray','Double','Char','CharArray','CharSequence','CharSequenceArray','CharSequenceArrayList','Byte','ByteArray', 'Bundle','Short','ShortArray','Serializable','Parcelable','ParcelableArrayList','ParcelableArray','unknownType'] #TODO - Need to add #TODO - -d for data uri if str(compType)=='activity': for node in common.xmldoc.getElementsByTagName('activity'): if node.attributes['android:name'].value == component: if len(node.getElementsByTagName('intent-filter'))>0: for x in node.getElementsByTagName('intent-filter'): for a in node.getElementsByTagName('action'): cmd_list.append([a.attributes['android:name'].value,component]) cmd_list=common.dedup(cmd_list) for c in cmd_list: if len(c)>0: #find extra suggestions for the intents in c[1], if any extras_list=[] extras_list.append([]) entries=common.get_entry_for_component('activity') output=False for n in entries: tmp_extra=findExtras.find_extras(str(c[1]),n) if tmp_extra not in extras_list: extras_list+=tmp_extra if len(extras_list)>2: for t in range(1,(len(extras_list)-1)): if str(extras_list[t]) not in type_list: if re.match(r'^\..*',str(c[1])): baseIntent = "adb shell am start -a \"" + c[0] + "\" -n \""+packageName+"/"+packageName+str(c[1])+"\"" else: baseIntent = "adb shell am start -a \"" + c[0] + "\" -n \""+packageName+"/"+str(c[1])+"\"" simple_type=True if extras_list[t+1]=='String': baseIntent+=" --es " elif extras_list[t+1]=='Boolean': baseIntent+=" --ez " elif extras_list[t+1]=='Int': baseIntent+=" --ei " elif extras_list[t+1]=='Long': baseIntent+=" --el " elif extras_list[t+1]=='Float': baseIntent+=" --ef " else: simple_type=False if simple_type: extra_type=str(extras_list[t+1]) print baseIntent+"\""+str(extras_list[t])+"\" \"Insert"+extra_type+"Here\"" output=True #TODO, Need to think of a better way to do this #This is excluding all the known types, because every second element is type elif str(extras_list[t]) not in type_list: common.logger.info("Extra: " + str(extras_list[t])+" is not a simple type, or could not be determined. You'll need to append the parameter which corresponds with the correct data type, followed by a key and value, both in quotes.") print "Example: "+baseIntent+str(" --es \"YOURKEYHERE\" \"YOURVALUEHERE\"") print "Here are your options for different data types: " for x in extra_parameters: print str(x) print "\n" output=True report.write_adb_commands("adbcommands-issues-list", common.Severity.VULNERABILITY, baseIntent, None, "activity") extras_list=[] if not output: if re.match(r'^\..*',str(c[1])): baseIntent = "adb shell am start -a \"" + c[0] + "\" -n \""+packageName+"/"+packageName+str(c[1])+"\"" else: baseIntent = "adb shell am start -a \"" + c[0] + "\" -n \""+packageName+"/"+str(c[1])+"\"" print baseIntent else: common.logger.debug("No intent filter on: " + str(component)) extras_list=[] entries=common.get_entry_for_component('activity') output=False last_extra='' for n in entries: tmp_extra=findExtras.find_extras(str(component),n) if tmp_extra not in extras_list: if str(tmp_extra)!=str(last_extra): extras_list+=tmp_extra last_extra=str(tmp_extra) if len(extras_list)>0: for t in range(1,(len(extras_list)-1)): if str(extras_list[t]) not in type_list: if re.match(r'^\..*',str(component)): baseIntent = "adb shell am start -n \""+packageName+"/"+packageName+str(component)+"\"" else: baseIntent = "adb shell am start -n \""+packageName+"/"+str(component)+"\"" simple_type=True if extras_list[t+1]=='String': baseIntent+=" --es " elif extras_list[t+1]=='Boolean': baseIntent+=" --ez " elif extras_list[t+1]=='Int': baseIntent+=" --ei " elif extras_list[t+1]=='Long': baseIntent+=" --el " elif extras_list[t+1]=='Float': baseIntent+=" --ef " elif extras_list[t+1]=='Uri': baseIntent+=" -d " else: simple_type=False if simple_type: extra_type=str(extras_list[t+1]) print baseIntent+str(extras_list[t])+" \"Insert"+extra_type+"Here\"" output=True #TODO, Need to think of a better way to do this #This is excluding all the known types, because every second element is type elif str(extras_list[t]) not in type_list: common.logger.info("Extra: " + str(extras_list[t])+" is not a simple type, or could not be determined. You'll need to append the parameter which corresponds with the correct data type, followed by a key and value, both in quotes.") print "Example: "+baseIntent+str(" --es \"YOURKEYHERE\" \"YOURVALUEHERE\"") print "Here are your options for different data types: " for x in extra_parameters: print str(x) print "\n" ouput=True report.write_adb_commands("adbcommands-issues-list", common.Severity.VULNERABILITY, baseIntent, None, "activity") extras_list=[] if not output: if re.match(r'^\..*',str(component)): baseIntent = "adb shell am start -n \""+packageName+"/"+packageName+str(component)+"\"" else: baseIntent = "adb shell am start -n \""+packageName+"/"+str(component)+"\"" print baseIntent elif str(compType)=='service': #BUG - THIS PRINTS DUPS without the below for node in common.xmldoc.getElementsByTagName('service'): if node.attributes['android:name'].value == component: if len(node.getElementsByTagName('intent-filter'))>0: for x in node.getElementsByTagName('intent-filter'): for a in node.getElementsByTagName('action'): cmd_list.append([a.attributes['android:name'].value,component]) cmd_list=common.dedup(cmd_list) for c in cmd_list: if len(c)>0: output=False extras_list=[] entries=common.get_entry_for_component('service') for n in entries: tmp_extra=findExtras.find_extras(str(c[1]),n) if tmp_extra not in extras_list: extras_list+=tmp_extra if len(extras_list)>0: for t in range(1,(len(extras_list)-1)): if str(extras_list[t]) not in type_list: if re.match(r'^\..*',str(c[1])): baseIntent = "adb shell am startservice -n \"" +packageName+"/"+packageName+str(c[1])+"\""+" -a \""+str(c[0])+"\"" else: baseIntent = "adb shell am startservice -n \"" +packageName+"/"+str(c[1])+"\""+" -a \""+str(c[0])+"\"" simple_type=True if extras_list[t+1]=='String': baseIntent+=" --es " elif extras_list[t+1]=='Boolean': baseIntent+=" --ez " elif extras_list[t+1]=='Int': baseIntent+=" --ei " elif extras_list[t+1]=='Long': baseIntent+=" --el " elif extras_list[t+1]=='Float': baseIntent+=" --ef " elif extras_list[t+1]=='Uri': baseIntent+=" -d " else: simple_type=False if simple_type: extra_type=str(extras_list[t+1]) print baseIntent+str(extras_list[t])+" \"Insert"+extra_type+"Here\"" output=True #TODO, Need to think of a better way to do this #This is excluding all the known types, because every second element is type elif str(extras_list[t]) not in type_list: common.logger.info("Extra: " + str(extras_list[t])+" is not a simple type, or could not be determined. You'll need to append the parameter which corresponds with the correct data type, followed by a key and value, both in quotes.") print "Example: "+baseIntent+str(" --es \"YOURKEYHERE\" \"YOURVALUEHERE\"") print "Here are your options for different data types: " for x in extra_parameters: print str(x) print "\n" output=True report.write_adb_commands("adbcommands-issues-list", common.Severity.VULNERABILITY, baseIntent, None, "service") extras_list=[] if not output: if re.match(r'^\..*',str(c[1])): baseIntent = "adb shell am startservice -n \"" +packageName+"/"+packageName+str(c[1])+"\"" else: baseIntent = "adb shell am startservice -n \"" +packageName+"/"+str(c[1])+"\"" print baseIntent report.write_adb_commands("adbcommands-issues-list", common.Severity.VULNERABILITY, baseIntent, None, "service") elif str(compType)=='receiver': for node in common.xmldoc.getElementsByTagName('receiver'): if node.attributes['android:name'].value==component: if len(node.getElementsByTagName('intent-filter'))>0: for x in node.getElementsByTagName('intent-filter'): for a in node.getElementsByTagName('action'): cmd_list.append([a.attributes['android:name'].value,component]) try: cmd_list=common.dedup(cmd_list) except Exception as e: common.logger.error("Error de-duplicating command list in adb.py while processing receivers: " + str(e)) for c in cmd_list: if len(c)>0: output=False extras_list=[] try: entries=common.get_entry_for_component('receiver') except Exception as e: common.logger.error("Error getting entry point for receivers in adb.py: " + str(e) ) for n in entries: try: tmp_extra=findExtras.find_extras(str(c[1]),n) except Exception as e: common.logger.error("Error finding extras for receivers in adb.py: " + str(e)) if tmp_extra not in extras_list: extras_list+=tmp_extra if len(extras_list)>0: for t in range(1,(len(extras_list)-1)): if str(extras_list[t]) not in type_list: baseIntent="adb shell am broadcast -a \""+str(c[0])+"\"" simple_type=True if extras_list[t+1]=='String': baseIntent+=" --es " elif extras_list[t+1]=='Boolean': baseIntent+=" --ez " elif extras_list[t+1]=='Int': baseIntent+=" --ei " elif extras_list[t+1]=='Long': baseIntent+=" --el " elif extras_list[t+1]=='Float': baseIntent+=" --ef " elif extras_list[t+1]=='Uri': baseIntent+=" -d " else: simple_type=False if simple_type: extra_type=str(extras_list[t+1]) print baseIntent+"\""+str(extras_list[t])+"\" \"Insert"+extra_type+"Here\"" output=True #TODO, Need to think of a better way to do this #This is excluding all the known types, because every second element is type elif str(extras_list[t]) not in type_list: common.logger.info("Extra: " + str(extras_list[t])+" is not a simple type, or could not be determined. You'll need to append the parameter which corresponds with the correct data type, followed by a key and value, both in quotes.") print "Example: "+baseIntent+str(" --es \"YOURKEYHERE\" \"YOURVALUEHERE\"") print "Here are your options for different data types: " for x in extra_parameters: print str(x) print "\n" output=True report.write_adb_commands("adbcommands-issues-list", common.Severity.VULNERABILITY, baseIntent, None, "receiver") extras_list=[] if not output: baseIntent = "adb shell am broadcast -a \""+str(c[0])+"\"" print baseIntent report.write_adb_commands("adbcommands-issues-list", common.Severity.VULNERABILITY, baseIntent, None, "receiver") elif str(compType)=='provider': for node in common.xmldoc.getElementsByTagName('provider'): if node.attributes['android:name'].value == component: print "TO INSERT DATA:" print "adb shell content insert --uri <URI> [--user <USER_ID>] --bind <BINDING> [--bind <BINDING>...]" print "TO UPDATE DATA:" print "adb shell content update --uri <URI> [--user <USER_ID>] [--where <WHERE>]" print "TO DELETE DATA:" print "adb shell content delete --uri <URI> [--user <USER_ID>] --bind <BINDING> [--bind <BINDING>...]" \ "[--where <WHERE>]" print "TO QUERY DATA: " print "adb shell content query --uri <URI> [--user <USER_ID>] [--projection <PROJECTION>]" \ "[--where <WHERE>] [--sort <SORT_ORDER>]" print "TO CALL THE PROVIDER DIRECTLY" print "adb shell content call --uri <URI> --method <METHOD> [--arg <ARG>]" return
def find_extras(stub_file_name, path): """ Find all extras given a filename """ # TODO - This needs to be gutted and re-writtten extras = [] filename = re.search(r'\w+$', stub_file_name) filename = filename.group() fname = common.grep(path, r'' + str(filename) + '\.java') rextras = [] rextras.append(r'getExtras\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getStringExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getIntExtra\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getIntArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getFloatExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getFloatArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getDoubleExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getDoubleArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getCharExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getCharArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getByteExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getByteArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getBundleExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getBooleanExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getBooleanArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getCharSequenceArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getCharSequenceArrayListExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getCharSequenceExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getInterArrayListExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getLongArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getLongExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getParcelableArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getParcelableArrayListExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getParcelableExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getSeriablizableExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getShortArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getShortExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getStringArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getStringArrayListExtra\(\s*[0-9A-Za-z_\"\'.]+') # These are not necessarily Intent extras, but may contain them rextras.append(r'getString\(\s*[0-9A-Za-z_\"\'.]+') # TODO add data types to the extras, so we can provide better suggestions if len(fname) > 0: x_tmp = [] x_tmp.append([]) for r in rextras: x_tmp = common.text_scan(fname, r) for m in x_tmp: if len(m) > 0: i = 0 for l in m: if type(l) is list: sigh = [] for s in l: sigh.append(re.sub(r'.*\(', '', str(s))) sigh[i] = re.sub(r'\).*', '', sigh[i]) sigh[i] = re.sub(r'\s*,.*', '', sigh[i]) extras += sigh i += 1 extras = common.dedup(extras) if len(extras) < 1: common.logger.debug("No extras found in " + str(fname[0]) + " to suggest.\n") common.parsingerrors.add(str(fname[0])) else: # BUG - seems like a flow can come here without the fname; Ex: Flagship S - 4 common.logger.error("Sorry, we could not find a filename while looking for extras\n") # Trying to get rid of empty first element return extras
def find_content_providers(): """ Find all content providers and return the list """ cp_list = common.find_ext('ContentProvider') growing = 1 # TODO - This is ugly and needs to be re-written # The intention here is to loop endlessly until all extensions are found while growing: cp_list_count_old = len(cp_list) cp_list += common.tree(cp_list) if len(cp_list) == cp_list_count_old: growing = 0 cp_list.append(['ContentProvider', '']) cp_decs = [] cp_decs.append([]) for x in cp_list: if len(x) > 0: tmp = r'' + re.escape(str(x[0])) + r'\s\w+[;=]' cp_decs += common.text_scan(common.java_files, tmp) tmp = r'(private .*|protected.*)' + re.escape(str( x[0])) + r'\s\w+;' cp_decs += common.text_scan(common.java_files, tmp) tmp = r'\w+\s[;=]\snew\s' + re.escape(str(x[0])) + r'\(' cp_decs += common.text_scan(common.java_files, tmp) tmp = r'\(.*' + re.escape( str(x[0]) ) + r'\s\w+.*\)' # Need to ensure this is working properly tmp_list2 = [] tmp_list2.append([]) for z in cp_decs: if len(z) > 0: # conditional declarations will cause conditional positives # BUG sometimes Z[0] is a list, rather than just a list element. Need to separate, remove and re-parse if (len(z[0]) > 1 and not isinstance(z[0], str)): for x in z[0]: foo = [x, z[1]] tmp_list2.append(foo) cp_decs.pop() continue else: tmp_list2.append(z) else: tmp_list2.append(z) tmp_list2 = filter(None, tmp_list2) for y in tmp_list2: if len(y) > 0: y[0] = re.sub(r';\\n', '', str(y[0]).strip('[]\'')) y[0] = re.sub(r'\\t*', '', y[0]) y[0] = re.sub(r'\s*private\b', '', y[0]) y[0] = re.sub(r'\s*protected\b', '', y[0]) y[0] = re.sub(r'\s*static\b', '', y[0]) y[0] = re.sub(r'^\s*ContentProvider\b', '', y[0]) y[0] = re.sub(r'\s*[;=]\s*new\sContentProvider\s.*', '', y[0]) y[0] = re.sub(r'\s*[;=]\s*new\s\w+\(.*\)', '', y[0]) y[0] = re.sub(r'^\s*', '', y[0]) y[0] = re.sub(r'\s*$', '', y[0]) y[0] = re.sub(r'^\w+\s', '', y[0]) y[0] = re.sub(r';$', '', y[0]) # remove whitespace y[0] = y[0].strip(' \t\r\n') tmp_list2 = common.dedup(tmp_list2) return tmp_list2
def find_webviews(): """ Finds all webviews in the decompiled source code """ #1. Look for classes that extend WebView #Find classes that extend Web View wv_list=find_ext('WebView') #2. Look for classes that extend classes that extend WebView while len(common.tree(wv_list)) > 1: wv_list+=common.tree(wv_list) wv_list.append(['WebView','']) #3. Cleanup? #4. Look for all declaration of WebViews using normal and extended class names #BUG sometimes multiple declarations are coming back for z[0], need to figure out what is going on there #Currently there may be false negatives #BUG - Need to review this for optional/multiple spaces wv_decs=[] wv_decs.append([]) for x in wv_list: if len(x)>0: tmp=r''+re.escape(str(x[0]))+r'\s\w+[;=]' wv_decs+=common.text_scan(common.java_files,tmp) tmp=r'(private .*|protected.*)'+ re.escape(str(x[0]))+r'\s\w+;' wv_decs+=common.text_scan(common.java_files,tmp) tmp=r'\w+\s[;=]\snew\s'+re.escape(str(x[0]))+r'\(' wv_decs+=common.text_scan(common.java_files,tmp) tmp=r'\(.*'+re.escape(str(x[0]))+r'\s\w+.*\)' # Need to ensure this is working properly tmp_list2=[] tmp_list2.append([]) for z in wv_decs: if len(z)>0: #conditional declarations will cause conditional positives #BUG sometimes Z[0] is a list, rather than just a list element. Need to separate, remove and re-parse if (len(z[0])>1 and not isinstance(z[0],str)): for x in z[0]: foo=[x,z[1]] tmp_list2.append(foo) wv_decs.pop() continue else: tmp_list2.append(z) else: tmp_list2.append(z) tmp_list2=filter(None,tmp_list2) for y in tmp_list2: if len(y)>0: y[0]=re.sub(r';\\n','',str(y[0]).strip('[]\'')) y[0]=re.sub(r'\\t*','',y[0]) y[0]=re.sub(r'\s*private\b','',y[0]) y[0]=re.sub(r'\s*protected\b','',y[0]) y[0]=re.sub(r'\s*static\b','',y[0]) y[0]=re.sub(r'^\s*WebView\b','',y[0]) y[0]=re.sub(r'\s*[;=]\s*new\sWebView\s.*','',y[0]) y[0]=re.sub(r'\s*[;=]\s*new\s\w+\(.*\)','',y[0]) y[0]=re.sub(r'^\s*','',y[0]) y[0]=re.sub(r'\s*$','',y[0]) y[0]=re.sub(r'^\w+\s','',y[0]) y[0]=re.sub(r';$','',y[0]) #remove whitespace y[0]=y[0].strip(' \t\r\n') tmp_list2=common.dedup(tmp_list2) return tmp_list2
def find_webviews(): """ Finds all webviews in the decompiled source code """ #1. Look for classes that extend WebView #Find classes that extend Web View wv_list = find_ext('WebView') #2. Look for classes that extend classes that extend WebView while len(common.tree(wv_list)) > 1: wv_list += common.tree(wv_list) wv_list.append(['WebView', '']) #3. Cleanup? #4. Look for all declaration of WebViews using normal and extended class names #BUG sometimes multiple declarations are coming back for z[0], need to figure out what is going on there #Currently there may be false negatives #BUG - Need to review this for optional/multiple spaces wv_decs = [] wv_decs.append([]) for x in wv_list: if len(x) > 0: tmp = r'' + re.escape(str(x[0])) + r'\s\w+[;=]' wv_decs += common.text_scan(common.java_files, tmp) tmp = r'(private .*|protected.*)' + re.escape(str( x[0])) + r'\s\w+;' wv_decs += common.text_scan(common.java_files, tmp) tmp = r'\w+\s[;=]\snew\s' + re.escape(str(x[0])) + r'\(' wv_decs += common.text_scan(common.java_files, tmp) tmp = r'\(.*' + re.escape( str(x[0]) ) + r'\s\w+.*\)' # Need to ensure this is working properly tmp_list2 = [] tmp_list2.append([]) for z in wv_decs: if len(z) > 0: #conditional declarations will cause conditional positives #BUG sometimes Z[0] is a list, rather than just a list element. Need to separate, remove and re-parse if (len(z[0]) > 1 and not isinstance(z[0], str)): for x in z[0]: foo = [x, z[1]] tmp_list2.append(foo) wv_decs.pop() continue else: tmp_list2.append(z) else: tmp_list2.append(z) tmp_list2 = filter(None, tmp_list2) for y in tmp_list2: if len(y) > 0: y[0] = re.sub(r';\\n', '', str(y[0]).strip('[]\'')) y[0] = re.sub(r'\\t*', '', y[0]) y[0] = re.sub(r'\s*private\b', '', y[0]) y[0] = re.sub(r'\s*protected\b', '', y[0]) y[0] = re.sub(r'\s*static\b', '', y[0]) y[0] = re.sub(r'^\s*WebView\b', '', y[0]) y[0] = re.sub(r'\s*[;=]\s*new\sWebView\s.*', '', y[0]) y[0] = re.sub(r'\s*[;=]\s*new\s\w+\(.*\)', '', y[0]) y[0] = re.sub(r'^\s*', '', y[0]) y[0] = re.sub(r'\s*$', '', y[0]) y[0] = re.sub(r'^\w+\s', '', y[0]) y[0] = re.sub(r';$', '', y[0]) #remove whitespace y[0] = y[0].strip(' \t\r\n') tmp_list2 = common.dedup(tmp_list2) return tmp_list2
def showAdbCommands(component, compType, packageName): #Print ADB commands for exploitation cmd_list = [] cmd_list.append([]) #BUG - THIS PRINTS DUPS #TODO - re-implement the extras, just want to make sure it looks good first #suggest_extras=raw_input("Would you like us to suggest extras to add? (y/n) ") if str(compType) == 'activity': for node in common.xmldoc.getElementsByTagName('activity'): if node.attributes['android:name'].value == component: if len(node.getElementsByTagName('intent-filter')) > 0: for x in node.getElementsByTagName('intent-filter'): for a in node.getElementsByTagName('action'): cmd_list.append([ a.attributes['android:name'].value, component ]) cmd_list = common.dedup(cmd_list) for c in cmd_list: if len(c) > 0: #find extra suggestions for the intents in c[1], if any extras_list = [] extras_list += intents.find_extras( str(c[1]), common.sourceDirectory) if len(extras_list) > 0: for t in extras_list: if re.match(r'^\..*', str(c[1])): command = "adb shell am start -a \"" + c[ 0] + "\" -n \"" + packageName + "/" + packageName + str( c[1] ) + "\"" + " --es " + str( t ) + " \"EXTRA_VALUE_IN_QUOTES\"" else: command = "adb shell am start -a \"" + c[ 0] + "\" -n \"" + packageName + "/" + str( c[1] ) + "\"" + " --es " + str( t ) + " \"EXTRA_VALUE_IN_QUOTES\"" print command report.write_adb_commands( "adbcommands-issues-list", common.Severity.VULNERABILITY, command, None, "activity") else: if re.match(r'^\..*', str(c[1])): command = "adb shell am start -a \"" + c[ 0] + "\" -n \"" + packageName + "/" + packageName + str( c[1]) + "\"" else: command = "adb shell am start -a \"" + c[ 0] + "\" -n \"" + packageName + "/" + str( c[1]) + "\"" print command report.write_adb_commands( "adbcommands-issues-list", common.Severity.VULNERABILITY, command, None, "activity") else: common.logger.debug("No intent filter on: " + str(component)) extras_list = [] extras_list += intents.find_extras(str(component), common.sourceDirectory) if len(extras_list) > 0: if re.match(r'^\..*', str(component)): command = "adb shell am start -n \"" + packageName + "/" + packageName + component + "\"" else: command = "adb shell am start -n \"" + packageName + "/" + component + "\"" print command extras = [] for e in extras_list: extras.append("Possible extras to send: " + str(e)) print "Possible extras to send: " + str(e) report.write_adb_commands( "adbcommands-issues-list", common.Severity.VULNERABILITY, command, extras, "activity") else: if re.match(r'^\..*', str(component)): command = "adb shell am start -n \"" + packageName + "/" + packageName + component + "\"" else: command = "adb shell am start -n \"" + packageName + "/" + component + "\"" print command report.write_adb_commands( "adbcommands-issues-list", common.Severity.VULNERABILITY, command, None, "activity") elif str(compType) == 'service': #BUG - THIS PRINTS DUPS without the below for node in common.xmldoc.getElementsByTagName('service'): if node.attributes['android:name'].value == component: if len(node.getElementsByTagName('intent-filter')) > 0: for x in node.getElementsByTagName('intent-filter'): for a in node.getElementsByTagName('action'): cmd_list.append([ a.attributes['android:name'].value, component ]) cmd_list = common.dedup(cmd_list) for c in cmd_list: if len(c) > 0: extras_list = [] extras_list += intents.find_extras( str(c[1]), common.sourceDirectory) if len(extras_list) > 0: for t in extras_list: if re.match(r'^\..*', str(c[1])): command = "adb shell am startservice " + packageName + "/" + packageName + str( c[1]) + " --es " + str(t) else: command = "adb shell am startservice " + packageName + "/" + str( c[1]) + " --es " + str(t) print command report.write_adb_commands( "adbcommands-issues-list", common.Severity.VULNERABILITY, command, None, "service") else: if re.match(r'^\..*', str(c[1])): command = "adb shell am startservice " + packageName + "/" + packageName + str( c[1]) else: command = "adb shell am startservice " + packageName + "/" + str( c[1]) print command report.write_adb_commands( "adbcommands-issues-list", common.Severity.VULNERABILITY, command, None, "service") elif str(compType) == 'receiver': for node in common.xmldoc.getElementsByTagName('receiver'): if node.attributes['android:name'].value == component: for x in node.getElementsByTagName('intent-filter'): for a in node.getElementsByTagName('action'): cmd_list.append( [a.attributes['android:name'].value, component]) cmd_list = common.dedup(cmd_list) for c in cmd_list: if len(c) > 0: extras_list = [] extras_list += intents.find_extras( str(c[1]), common.sourceDirectory) if len(extras_list) > 0: for t in extras_list: baseIntent = "adb shell am broadcast -a \"" + str( c[0]) + "\"" print "Possible Extra: " + str(t) baseIntent += " --es " + str( t) + " \"YOURDATAHERE\"" print baseIntent report.write_adb_commands( "adbcommands-issues-list", common.Severity.VULNERABILITY, baseIntent, None, "receiver") common.logger.info( "Sorry, the dynamic extra suggestions is still a work in progress. In the mean time, know that the --es flag is used for sending key/value pairs which are strings." ) common.logger.info( "If the suggested extra does not appear quoted, it is either a CONSTANT or String variable, it should not be used literally as shown" ) else: command = "adb shell am broadcast -a \"" + str( c[0]) + "\"" print command report.write_adb_commands( "adbcommands-issues-list", common.Severity.VULNERABILITY, command, None, "receiver") elif str(compType) == 'provider': for node in common.xmldoc.getElementsByTagName('provider'): if node.attributes['android:name'].value == component: print "TO INSERT DATA:" print "adb shell content insert --uri <URI> [--user <USER_ID>] --bind <BINDING> [--bind <BINDING>...]" print "TO UPDATE DATA:" print "adb shell content update --uri <URI> [--user <USER_ID>] [--where <WHERE>]" print "TO DELETE DATA:" print "adb shell content delete --uri <URI> [--user <USER_ID>] --bind <BINDING> [--bind <BINDING>...]" \ "[--where <WHERE>]" print "TO QUERY DATA: " print "adb shell content query --uri <URI> [--user <USER_ID>] [--projection <PROJECTION>]" \ "[--where <WHERE>] [--sort <SORT_ORDER>]" print "TO CALL THE PROVIDER DIRECTLY" print "adb shell content call --uri <URI> --method <METHOD> [--arg <ARG>]" return
def find_content_providers(): """ Find all content providers and return the list """ cp_list = common.find_ext('ContentProvider') growing = 1 # TODO - This is ugly and needs to be re-written # The intention here is to loop endlessly until all extensions are found while growing: cp_list_count_old = len(cp_list) cp_list += common.tree(cp_list) if len(cp_list) == cp_list_count_old: growing = 0 cp_list.append(['ContentProvider', '']) cp_decs = [] cp_decs.append([]) for x in cp_list: if len(x) > 0: tmp = r'' + re.escape(str(x[0])) + r'\s\w+[;=]' cp_decs += common.text_scan(common.java_files, tmp) tmp = r'(private .*|protected.*)' + re.escape(str(x[0])) + r'\s\w+;' cp_decs += common.text_scan(common.java_files, tmp) tmp = r'\w+\s[;=]\snew\s' + re.escape(str(x[0])) + r'\(' cp_decs += common.text_scan(common.java_files, tmp) tmp = r'\(.*' + re.escape(str(x[0])) + r'\s\w+.*\)' # Need to ensure this is working properly tmp_list2 = [] tmp_list2.append([]) for z in cp_decs: if len(z) > 0: # conditional declarations will cause conditional positives # BUG sometimes Z[0] is a list, rather than just a list element. Need to separate, remove and re-parse if (len(z[0]) > 1 and not isinstance(z[0], str)): for x in z[0]: foo = [x, z[1]] tmp_list2.append(foo) cp_decs.pop() continue else: tmp_list2.append(z) else: tmp_list2.append(z) tmp_list2 = filter(None, tmp_list2) for y in tmp_list2: if len(y) > 0: y[0] = re.sub(r';\\n', '', str(y[0]).strip('[]\'')) y[0] = re.sub(r'\\t*', '', y[0]) y[0] = re.sub(r'\s*private\b', '', y[0]) y[0] = re.sub(r'\s*protected\b', '', y[0]) y[0] = re.sub(r'\s*static\b', '', y[0]) y[0] = re.sub(r'^\s*ContentProvider\b', '', y[0]) y[0] = re.sub(r'\s*[;=]\s*new\sContentProvider\s.*', '', y[0]) y[0] = re.sub(r'\s*[;=]\s*new\s\w+\(.*\)', '', y[0]) y[0] = re.sub(r'^\s*', '', y[0]) y[0] = re.sub(r'\s*$', '', y[0]) y[0] = re.sub(r'^\w+\s', '', y[0]) y[0] = re.sub(r';$', '', y[0]) # remove whitespace y[0] = y[0].strip(' \t\r\n') tmp_list2 = common.dedup(tmp_list2) return tmp_list2
def showAdbCommands(component,compType,packageName): #Print ADB commands for exploitation cmd_list=[] cmd_list.append([]) #BUG - THIS PRINTS DUPS #TODO - re-implement the extras, just want to make sure it looks good first #suggest_extras=raw_input("Would you like us to suggest extras to add? (y/n) ") if str(compType)=='activity': for node in common.xmldoc.getElementsByTagName('activity'): if node.attributes['android:name'].value == component: if len(node.getElementsByTagName('intent-filter'))>0: for x in node.getElementsByTagName('intent-filter'): for a in node.getElementsByTagName('action'): cmd_list.append([a.attributes['android:name'].value,component]) cmd_list=common.dedup(cmd_list) for c in cmd_list: if len(c)>0: #find extra suggestions for the intents in c[1], if any extras_list=[] extras_list+=intents.find_extras(str(c[1]),common.sourceDirectory) if len(extras_list)>0: for t in extras_list: if re.match(r'^\..*',str(c[1])): command = "adb shell am start -a \"" + c[0] + "\" -n \""+packageName+"/"+packageName+str(c[1])+"\""+" --es "+str(t)+" \"EXTRA_VALUE_IN_QUOTES\"" else: command = "adb shell am start -a \"" + c[0] + "\" -n \""+packageName+"/"+str(c[1])+"\""+" --es "+str(t)+" \"EXTRA_VALUE_IN_QUOTES\"" print command report.write_adb_commands("adbcommands-issues-list", common.Severity.VULNERABILITY, command, None, "activity") else: if re.match(r'^\..*',str(c[1])): command = "adb shell am start -a \"" + c[0] + "\" -n \""+packageName+"/"+packageName+str(c[1])+"\"" else: command = "adb shell am start -a \"" + c[0] + "\" -n \""+packageName+"/"+str(c[1])+"\"" print command report.write_adb_commands("adbcommands-issues-list", common.Severity.VULNERABILITY, command, None, "activity") else: common.logger.debug("No intent filter on: " + str(component)) extras_list=[] extras_list+=intents.find_extras(str(component),common.sourceDirectory) if len(extras_list)>0: if re.match(r'^\..*',str(component)): command = "adb shell am start -n \""+packageName+"/"+packageName+component+"\"" else: command = "adb shell am start -n \""+packageName+"/"+component+"\"" print command extras = [] for e in extras_list: extras.append("Possible extras to send: " + str(e)) print "Possible extras to send: " + str(e) report.write_adb_commands("adbcommands-issues-list", common.Severity.VULNERABILITY, command, extras, "activity") else: if re.match(r'^\..*',str(component)): command = "adb shell am start -n \""+packageName+"/"+packageName+component+"\"" else: command = "adb shell am start -n \""+packageName+"/"+component+"\"" print command report.write_adb_commands("adbcommands-issues-list", common.Severity.VULNERABILITY, command, None, "activity") elif str(compType)=='service': #BUG - THIS PRINTS DUPS without the below for node in common.xmldoc.getElementsByTagName('service'): if node.attributes['android:name'].value == component: if len(node.getElementsByTagName('intent-filter'))>0: for x in node.getElementsByTagName('intent-filter'): for a in node.getElementsByTagName('action'): cmd_list.append([a.attributes['android:name'].value,component]) cmd_list=common.dedup(cmd_list) for c in cmd_list: if len(c)>0: extras_list=[] extras_list+=intents.find_extras(str(c[1]),common.sourceDirectory) if len(extras_list)>0: for t in extras_list: if re.match(r'^\..*',str(c[1])): command = "adb shell am startservice " +packageName+"/"+packageName+str(c[1])+" --es "+str(t) else: command = "adb shell am startservice " +packageName+"/"+str(c[1])+" --es "+str(t) print command report.write_adb_commands("adbcommands-issues-list", common.Severity.VULNERABILITY, command, None, "service") else: if re.match(r'^\..*',str(c[1])): command = "adb shell am startservice " +packageName+"/"+packageName+str(c[1]) else: command = "adb shell am startservice " +packageName+"/"+str(c[1]) print command report.write_adb_commands("adbcommands-issues-list", common.Severity.VULNERABILITY, command, None, "service") elif str(compType)=='receiver': for node in common.xmldoc.getElementsByTagName('receiver'): if node.attributes['android:name'].value==component: for x in node.getElementsByTagName('intent-filter'): for a in node.getElementsByTagName('action'): cmd_list.append([a.attributes['android:name'].value,component]) cmd_list=common.dedup(cmd_list) for c in cmd_list: if len(c)>0: extras_list=[] extras_list+=intents.find_extras(str(c[1]),common.sourceDirectory) if len(extras_list)>0: for t in extras_list: baseIntent="adb shell am broadcast -a \""+str(c[0])+"\"" print "Possible Extra: " + str(t) baseIntent+=" --es "+str(t)+" \"YOURDATAHERE\"" print baseIntent report.write_adb_commands("adbcommands-issues-list", common.Severity.VULNERABILITY, baseIntent, None, "receiver") common.logger.info("Sorry, the dynamic extra suggestions is still a work in progress. In the mean time, know that the --es flag is used for sending key/value pairs which are strings.") common.logger.info("If the suggested extra does not appear quoted, it is either a CONSTANT or String variable, it should not be used literally as shown") else: command = "adb shell am broadcast -a \""+str(c[0])+"\"" print command report.write_adb_commands("adbcommands-issues-list", common.Severity.VULNERABILITY, command, None, "receiver") elif str(compType)=='provider': for node in common.xmldoc.getElementsByTagName('provider'): if node.attributes['android:name'].value == component: print "TO INSERT DATA:" print "adb shell content insert --uri <URI> [--user <USER_ID>] --bind <BINDING> [--bind <BINDING>...]" print "TO UPDATE DATA:" print "adb shell content update --uri <URI> [--user <USER_ID>] [--where <WHERE>]" print "TO DELETE DATA:" print "adb shell content delete --uri <URI> [--user <USER_ID>] --bind <BINDING> [--bind <BINDING>...]" \ "[--where <WHERE>]" print "TO QUERY DATA: " print "adb shell content query --uri <URI> [--user <USER_ID>] [--projection <PROJECTION>]" \ "[--where <WHERE>] [--sort <SORT_ORDER>]" print "TO CALL THE PROVIDER DIRECTLY" print "adb shell content call --uri <URI> --method <METHOD> [--arg <ARG>]" return
def find_extras(stub_file_name,path): """ Find all extras given a filename """ #TODO - This needs to be gutted and re-writtten extras=[] filename=re.search(r'\w+$',stub_file_name) filename=filename.group() fname=common.grep(path,r''+str(filename)+'\.java') rextras=[] rextras.append(r'getExtras\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getStringExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getIntExtra\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getIntArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getFloatExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getFloatArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getDoubleExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getDoubleArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getCharExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getCharArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getByteExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getByteArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getBundleExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getBooleanExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getBooleanArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getCharSequenceArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getCharSequenceArrayListExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getCharSequenceExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getInterArrayListExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getLongArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getLongExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getParcelableArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getParcelableArrayListExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getParcelableExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getSeriablizableExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getShortArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getShortExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getStringArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getStringArrayListExtra\(\s*[0-9A-Za-z_\"\'.]+') #These are not necessarily Intent extras, but may contain them rextras.append(r'getString\(\s*[0-9A-Za-z_\"\'.]+') #TODO add data types to the extras, so we can provide better suggestions if len(fname)>0: x_tmp=[] x_tmp.append([]) for r in rextras: x_tmp=common.text_scan(fname,r) for m in x_tmp: if len(m)>0: i=0 for l in m: if type(l) is list: sigh=[] for s in l: sigh.append(re.sub(r'.*\(','',str(s))) sigh[i]=re.sub(r'\).*','',sigh[i]) sigh[i]=re.sub(r'\s*,.*','',sigh[i]) extras+=sigh i+=1 extras=common.dedup(extras) if len(extras)<1: common.logger.debug("No extras found in " + str(fname[0]) + " to suggest.\n") common.parsingerrors.add(str(fname[0])) else: #BUG - seems like a flow can come here without the fname; Ex: Flagship S - 4 common.logger.error("Sorry, we could not find a filename while looking for extras\n") #Trying to get rid of empty first element return extras
#Look for TapJacking vulnerabilities #Native protection was added in API v. 9, so previous likely vulnerable if common.minSdkVersion >8: common.logger.debug("Beginning TapJacking testing") findTapJacking.start(common.sourceDirectory) else: common.logger.error("Since the minSdkVersion is less that 9, it is likely this application is vulnerable to TapJacking. QARK made no attempt to confirm, as the protection would have to be custom code, which is difficult for QARK to examine and understand properly. This vulnerability allows a malicious application to lay on top of this app, while letting the key strokes pass through to the application below. This can cause users to take unwanted actions, within the victim application, similar to Clickjacking on websites. Please select the appropriate options in the exploitation menus to verify manually using QARK's exploit APK. Note: The QARK proof-of-concept is transparent, but in real-world attacks, it would likely not be. This is done solely to aid in testing. For more information: https://media.blackhat.com/ad-12/Niemietz/bh-ad-12-androidmarcus_niemietz-WP.pdf") ########### #Look for Content Provider issues if len(common.text_scan(common.java_files,cp_imp_rex)) > 1: common.logger.info("Content Providers appear to be in use, locating...") cp_dec_list=contentProvider.find_content_providers() cp_dec_list=filter(None,cp_dec_list) cp_dec_list=common.dedup(cp_dec_list) common.logger.info("FOUND " + str(len(cp_dec_list)) + " CONTENTPROVIDERS:") for p in cp_dec_list: common.logger.info(str(p)) query_rex=r'\.query\(.*\)' update_rex=r'\.update\(.*\)' delete_rex=r'\.delete\(.*\)' insert_rex=r'\.insert\(.*\)' #TODO - Add SQLi checks #VERY LAME SQL INJECTION DETECTION (GUESSING) statement_list=[] statement_list.append([]) for p in cp_dec_list: if len(p)>1:
def show_adb_commands(component, compType, packageName): #Print ADB commands for exploitation cmd_list = [] cmd_list.append([]) #BUG - THIS PRINTS DUPS extra_parameters = [] extra_parameters.append('[-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]') extra_parameters.append('[--esn <EXTRA_KEY> ...]') extra_parameters.append('[--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]') extra_parameters.append('[--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]') extra_parameters.append('[--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]') extra_parameters.append('[--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE> ...]') extra_parameters.append('[--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]') extra_parameters.append('[--ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE>]') extra_parameters.append( '[--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]') extra_parameters.append( '[--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]') extra_parameters.append( '[--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]') extra_parameters.append( '[--esa <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]') type_list = [ 'String', 'StringArray', 'StringArrayList', 'Boolean', 'BooleanArray', 'Int', 'Float', 'Long', 'LongArray', '[]', '', 'IntArray', 'IntegerArrayList', 'FloatArray', 'Double', 'Char', 'CharArray', 'CharSequence', 'CharSequenceArray', 'CharSequenceArrayList', 'Byte', 'ByteArray', 'Bundle', 'Short', 'ShortArray', 'Serializable', 'Parcelable', 'ParcelableArrayList', 'ParcelableArray', 'unknownType' ] #TODO - Need to add #TODO - -d for data uri if str(compType) == 'activity': for node in common.xmldoc.getElementsByTagName('activity'): if node.attributes['android:name'].value == component: if len(node.getElementsByTagName('intent-filter')) > 0: for x in node.getElementsByTagName('intent-filter'): for a in node.getElementsByTagName('action'): cmd_list.append([ a.attributes['android:name'].value, component ]) cmd_list = common.dedup(cmd_list) for c in cmd_list: if len(c) > 0: #find extra suggestions for the intents in c[1], if any extras_list = [] extras_list.append([]) entries = common.get_entry_for_component( 'activity') output = False for n in entries: tmp_extra = findExtras.find_extras( str(c[1]), n) if tmp_extra not in extras_list: extras_list += tmp_extra if len(extras_list) > 2: for t in range(1, (len(extras_list) - 1)): if str(extras_list[t]) not in type_list: if re.match(r'^\..*', str(c[1])): baseIntent = "adb shell am start -a \"" + c[ 0] + "\" -n \"" + packageName + "/" + packageName + str( c[1]) + "\"" else: baseIntent = "adb shell am start -a \"" + c[ 0] + "\" -n \"" + packageName + "/" + str( c[1]) + "\"" simple_type = True if extras_list[t + 1] == 'String': baseIntent += " --es " elif extras_list[t + 1] == 'Boolean': baseIntent += " --ez " elif extras_list[t + 1] == 'Int': baseIntent += " --ei " elif extras_list[t + 1] == 'Long': baseIntent += " --el " elif extras_list[t + 1] == 'Float': baseIntent += " --ef " else: simple_type = False if simple_type: extra_type = str(extras_list[t + 1]) print baseIntent + "\"" + str( extras_list[t] ) + "\" \"Insert" + extra_type + "Here\"" output = True #TODO, Need to think of a better way to do this #This is excluding all the known types, because every second element is type elif str(extras_list[t] ) not in type_list: common.logger.info( "Extra: " + str(extras_list[t]) + " is not a simple type, or could not be determined. You'll need to append the parameter which corresponds with the correct data type, followed by a key and value, both in quotes." ) print "Example: " + baseIntent + str( " --es \"YOURKEYHERE\" \"YOURVALUEHERE\"" ) print "Here are your options for different data types: " for x in extra_parameters: print str(x) print "\n" output = True report.write_adb_commands( "adbcommands-issues-list", common.Severity.VULNERABILITY, baseIntent, None, "activity") extras_list = [] if not output: if re.match(r'^\..*', str(c[1])): baseIntent = "adb shell am start -a \"" + c[ 0] + "\" -n \"" + packageName + "/" + packageName + str( c[1]) + "\"" else: baseIntent = "adb shell am start -a \"" + c[ 0] + "\" -n \"" + packageName + "/" + str( c[1]) + "\"" print baseIntent else: common.logger.debug("No intent filter on: " + str(component)) extras_list = [] entries = common.get_entry_for_component('activity') output = False last_extra = '' for n in entries: tmp_extra = findExtras.find_extras(str(component), n) if tmp_extra not in extras_list: if str(tmp_extra) != str(last_extra): extras_list += tmp_extra last_extra = str(tmp_extra) if len(extras_list) > 0: for t in range(1, (len(extras_list) - 1)): if str(extras_list[t]) not in type_list: if re.match(r'^\..*', str(component)): baseIntent = "adb shell am start -n \"" + packageName + "/" + packageName + str( component) + "\"" else: baseIntent = "adb shell am start -n \"" + packageName + "/" + str( component) + "\"" simple_type = True if extras_list[t + 1] == 'String': baseIntent += " --es " elif extras_list[t + 1] == 'Boolean': baseIntent += " --ez " elif extras_list[t + 1] == 'Int': baseIntent += " --ei " elif extras_list[t + 1] == 'Long': baseIntent += " --el " elif extras_list[t + 1] == 'Float': baseIntent += " --ef " elif extras_list[t + 1] == 'Uri': baseIntent += " -d " else: simple_type = False if simple_type: extra_type = str(extras_list[t + 1]) print baseIntent + str( extras_list[t] ) + " \"Insert" + extra_type + "Here\"" output = True #TODO, Need to think of a better way to do this #This is excluding all the known types, because every second element is type elif str(extras_list[t]) not in type_list: common.logger.info( "Extra: " + str(extras_list[t]) + " is not a simple type, or could not be determined. You'll need to append the parameter which corresponds with the correct data type, followed by a key and value, both in quotes." ) print "Example: " + baseIntent + str( " --es \"YOURKEYHERE\" \"YOURVALUEHERE\"" ) print "Here are your options for different data types: " for x in extra_parameters: print str(x) print "\n" ouput = True report.write_adb_commands( "adbcommands-issues-list", common.Severity.VULNERABILITY, baseIntent, None, "activity") extras_list = [] if not output: if re.match(r'^\..*', str(component)): baseIntent = "adb shell am start -n \"" + packageName + "/" + packageName + str( component) + "\"" else: baseIntent = "adb shell am start -n \"" + packageName + "/" + str( component) + "\"" print baseIntent elif str(compType) == 'service': #BUG - THIS PRINTS DUPS without the below for node in common.xmldoc.getElementsByTagName('service'): if node.attributes['android:name'].value == component: if len(node.getElementsByTagName('intent-filter')) > 0: for x in node.getElementsByTagName('intent-filter'): for a in node.getElementsByTagName('action'): cmd_list.append([ a.attributes['android:name'].value, component ]) cmd_list = common.dedup(cmd_list) for c in cmd_list: if len(c) > 0: output = False extras_list = [] entries = common.get_entry_for_component('service') for n in entries: tmp_extra = findExtras.find_extras( str(c[1]), n) if tmp_extra not in extras_list: extras_list += tmp_extra if len(extras_list) > 0: for t in range(1, (len(extras_list) - 1)): if str(extras_list[t]) not in type_list: if re.match(r'^\..*', str(c[1])): baseIntent = "adb shell am startservice -n \"" + packageName + "/" + packageName + str( c[1]) + "\"" + " -a \"" + str( c[0]) + "\"" else: baseIntent = "adb shell am startservice -n \"" + packageName + "/" + str( c[1]) + "\"" + " -a \"" + str( c[0]) + "\"" simple_type = True if extras_list[t + 1] == 'String': baseIntent += " --es " elif extras_list[t + 1] == 'Boolean': baseIntent += " --ez " elif extras_list[t + 1] == 'Int': baseIntent += " --ei " elif extras_list[t + 1] == 'Long': baseIntent += " --el " elif extras_list[t + 1] == 'Float': baseIntent += " --ef " elif extras_list[t + 1] == 'Uri': baseIntent += " -d " else: simple_type = False if simple_type: extra_type = str(extras_list[t + 1]) print baseIntent + str( extras_list[t] ) + " \"Insert" + extra_type + "Here\"" output = True #TODO, Need to think of a better way to do this #This is excluding all the known types, because every second element is type elif str(extras_list[t] ) not in type_list: common.logger.info( "Extra: " + str(extras_list[t]) + " is not a simple type, or could not be determined. You'll need to append the parameter which corresponds with the correct data type, followed by a key and value, both in quotes." ) print "Example: " + baseIntent + str( " --es \"YOURKEYHERE\" \"YOURVALUEHERE\"" ) print "Here are your options for different data types: " for x in extra_parameters: print str(x) print "\n" output = True report.write_adb_commands( "adbcommands-issues-list", common.Severity.VULNERABILITY, baseIntent, None, "service") extras_list = [] if not output: if re.match(r'^\..*', str(c[1])): baseIntent = "adb shell am startservice -n \"" + packageName + "/" + packageName + str( c[1]) + "\"" else: baseIntent = "adb shell am startservice -n \"" + packageName + "/" + str( c[1]) + "\"" print baseIntent report.write_adb_commands( "adbcommands-issues-list", common.Severity.VULNERABILITY, baseIntent, None, "service") elif str(compType) == 'receiver': for node in common.xmldoc.getElementsByTagName('receiver'): if node.attributes['android:name'].value == component: if len(node.getElementsByTagName('intent-filter')) > 0: for x in node.getElementsByTagName('intent-filter'): for a in node.getElementsByTagName('action'): cmd_list.append([ a.attributes['android:name'].value, component ]) try: cmd_list = common.dedup(cmd_list) except Exception as e: common.logger.error( "Error de-duplicating command list in adb.py while processing receivers: " + str(e)) for c in cmd_list: if len(c) > 0: output = False extras_list = [] try: entries = common.get_entry_for_component( 'receiver') except Exception as e: common.logger.error( "Error getting entry point for receivers in adb.py: " + str(e)) for n in entries: try: tmp_extra = findExtras.find_extras( str(c[1]), n) except Exception as e: common.logger.error( "Error finding extras for receivers in adb.py: " + str(e)) if tmp_extra not in extras_list: extras_list += tmp_extra if len(extras_list) > 0: for t in range(1, (len(extras_list) - 1)): if str(extras_list[t] ) not in type_list: baseIntent = "adb shell am broadcast -a \"" + str( c[0]) + "\"" simple_type = True if extras_list[t + 1] == 'String': baseIntent += " --es " elif extras_list[t + 1] == 'Boolean': baseIntent += " --ez " elif extras_list[t + 1] == 'Int': baseIntent += " --ei " elif extras_list[t + 1] == 'Long': baseIntent += " --el " elif extras_list[t + 1] == 'Float': baseIntent += " --ef " elif extras_list[t + 1] == 'Uri': baseIntent += " -d " else: simple_type = False if simple_type: extra_type = str( extras_list[t + 1]) print baseIntent + "\"" + str( extras_list[t] ) + "\" \"Insert" + extra_type + "Here\"" output = True #TODO, Need to think of a better way to do this #This is excluding all the known types, because every second element is type elif str(extras_list[t] ) not in type_list: common.logger.info( "Extra: " + str(extras_list[t]) + " is not a simple type, or could not be determined. You'll need to append the parameter which corresponds with the correct data type, followed by a key and value, both in quotes." ) print "Example: " + baseIntent + str( " --es \"YOURKEYHERE\" \"YOURVALUEHERE\"" ) print "Here are your options for different data types: " for x in extra_parameters: print str(x) print "\n" output = True report.write_adb_commands( "adbcommands-issues-list", common.Severity.VULNERABILITY, baseIntent, None, "receiver") extras_list = [] if not output: baseIntent = "adb shell am broadcast -a \"" + str( c[0]) + "\"" print baseIntent report.write_adb_commands( "adbcommands-issues-list", common.Severity.VULNERABILITY, baseIntent, None, "receiver") elif str(compType) == 'provider': for node in common.xmldoc.getElementsByTagName('provider'): if node.attributes['android:name'].value == component: print "TO INSERT DATA:" print "adb shell content insert --uri <URI> [--user <USER_ID>] --bind <BINDING> [--bind <BINDING>...]" print "TO UPDATE DATA:" print "adb shell content update --uri <URI> [--user <USER_ID>] [--where <WHERE>]" print "TO DELETE DATA:" print "adb shell content delete --uri <URI> [--user <USER_ID>] --bind <BINDING> [--bind <BINDING>...]" \ "[--where <WHERE>]" print "TO QUERY DATA: " print "adb shell content query --uri <URI> [--user <USER_ID>] [--projection <PROJECTION>]" \ "[--where <WHERE>] [--sort <SORT_ORDER>]" print "TO CALL THE PROVIDER DIRECTLY" print "adb shell content call --uri <URI> --method <METHOD> [--arg <ARG>]" return