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
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_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 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_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_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_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 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_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