├── README.md ├── ScanAndroidXml.py ├── apktool.jar ├── info.jpg └── requirements.txt /README.md: -------------------------------------------------------------------------------- 1 | # ScanAndroidXML 2 | This tool analyzes Android app to find vulnerabilities in 3 | 1. AndroidManifest.xml 4 | 2. network_security_config.xml 5 | 3. Firebase URLs from strings.xml. 6 | 7 | This tool also shows Deeplinks used in Android app. 8 | 9 | JDK and Python3 are required. 10 | 11 | *How to Install:*
12 | cd ScanAndroidXML
13 | pip install -r requirements.txt
14 | 15 | *How to Run:*
16 | Move apk file into SacnAndroidXML directory 17 | python ScanAndroidXml.py <apk file>
18 | 19 | This will print the results in terminal and generate results in html file. 20 | 21 | 22 | *Sample Results:*
23 | ![Results](info.jpg) 24 | 25 | 26 | https://twitter.com/satish_patnayak 27 | 28 | -------------------------------------------------------------------------------- /ScanAndroidXml.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import re 3 | import requests 4 | import sys 5 | import os 6 | from os import path 7 | import sty 8 | from sty import fg, bg, ef, rs 9 | 10 | # Usage python ScanAndroidXml.py 11 | # fireBaseTest method will check for firebase url in /res/values/strings.xml 12 | def fireBaseTest(filename, stringsFile): 13 | #Get Firebase URL 14 | firebaseURL="" 15 | #writeResults(filename,"
[Info] --- Checking for firebase URLs") 16 | # for Strings.xml file 17 | stringsFile=pwd+"\\"+filename+stringsFile; 18 | print("[Info] - Checking for Firebase URLs"); 19 | writePassResults(filename,"

Firebase Checks ") 20 | try: 21 | #writeResults(filename,"
[Info]---Strings.xml file Location:"+ stringsFile) 22 | with open(stringsFile, errors='ignore') as f: 23 | f1=f.read() 24 | searchObj=re.findall(r'https://.*.firebaseio.com', f1) 25 | i=len(searchObj) 26 | if(i !=0): 27 | while i > 0: 28 | #print(i) 29 | i=i-1 30 | firebaseURL=searchObj[i] 31 | print ("[Info] - Firebase URL found " + firebaseURL); 32 | #writeResults(filename,"
[Info] --- Firebase URL found " + firebaseURL) 33 | firebaseURL=firebaseURL+"/.json" 34 | print ("[Info] - Accessing Firebase URL " + firebaseURL); 35 | #writeResults(filename,"
[Info] --- Accessing "+ firebaseURL) 36 | req=requests.get(firebaseURL) 37 | if req.status_code == 200: 38 | print(fg.red+"[Vuln] - Firebase "+firebaseURL+" is publicly accessible"); 39 | print(" - Strings.xml file Location:"+ stringsFile); 40 | print(" - Response ---> " + req.text + fg.rs); 41 | writeResults(filename,"

[Vulnerability] --- Firebase "+firebaseURL+" is publicly accessible

" ) 42 | writeResults(filename,"

Strings.xml file Location:"+ stringsFile) 43 | else: 44 | print("[Info] - Firebase "+firebaseURL+" is not publicly accessible"); 45 | print(" - Strings.xml file Location:"+ stringsFile); 46 | print(" - Response ---> " + req.text); 47 | writePassResults(filename,"
[Info] --- Not Vulnerable. Strings.xml file Location:"+ stringsFile+"
Response from " + firebaseURL +"
"+ req.text) 48 | else: 49 | print("[Info] - App doesn't have firebase URLs"); 50 | writePassResults(filename,"
[Info] --- App doesn't have firebase URLs") 51 | except IOError: 52 | writeResults(filename,"
Strings.xml not accessible") 53 | 54 | def network_security_config_Test(filename,nscFile): 55 | #writeResults(filename,"
[Info] --- Network security config check is in progress") 56 | stringsFile=pwd+"\\"+filename+nscFile 57 | print("[Info] - Checking for Network Security Config") 58 | writePassResults(filename,"

Network Security Config Checks") 59 | try: 60 | with open(stringsFile, errors='ignore') as f: 61 | #writeResults(filename,"
network_security_config.xml file Location:"+ stringsFile) 62 | fData=f.read() 63 | # Search for 64 | searchObj=re.search(r'', fData, re.M|re.I) 65 | if searchObj: 66 | print(fg.red+"[Vuln] - Found Misconfigured network_security_config.xml\n - "+searchObj.group()+" in network_security_config.xml which leads to MITM in Android devices API24 or above.\n - network_security_config.xml file Location:"+ stringsFile + fg.rs); 67 | writeResults(filename,"

[Vulnerability] --- Misconfigured network_security_config.xml. \n Found "+searchObj.group()+" in network_security_config.xml which leads to MITM in Android devices API24 or above.
Found <certificates src=\"user\" /> in network_security_config.xml

network_security_config.xml file Location:"+ stringsFile) 68 | else: 69 | writePassResults(filename,"
[Info] --- Not found <certificates src=\"user\" /> in network_security_config.xml
network_security_config.xml file Location:"+ stringsFile) 70 | # Search for 71 | searchObj=re.search(r'', fData, re.M|re.I) 72 | if searchObj: 73 | print(fg.red+"[Vuln] - Found Misconfigured network_security_config.xml\n - "+searchObj.group()+" in network_security_config.xml which leads to MITM in Android devices API24 or above.\n - network_security_config.xml file Location:"+ stringsFile + fg.rs); 74 | writeResults(filename,"

[Vulnerability] --- Misconfigured network_security_config.xml. \n Found "+searchObj.group()+" in network_security_config.xml which leads to MITM in Android devices API24 or above.
Found <certificates src=\"@raw/*\"/> in network_security_config.xml

network_security_config.xml file Location:"+ stringsFile) 75 | else: 76 | writePassResults(filename,"
[Info] --- Not found <certificates src=\"@raw/*\"/> in network_security_config.xml
network_security_config.xml file Location:"+ stringsFile) 77 | # Search for ClearTextTraffic 78 | searchObj=re.search(r'', fData, re.M|re.I) 79 | if searchObj: 80 | print(fg.red+"[Vuln] - Found Misconfigured network_security_config.xml\n - "+searchObj.group()+" in network_security_config.xml which leads to MITM in Android devices API24 or above.\n - network_security_config.xml file Location:"+ stringsFile + fg.rs); 81 | writeResults(filename,"

[Vulnerability] --- Misconfigured network_security_config.xml. \n Found "+searchObj.group()+" in network_security_config.xml which leads to MITM in Android devices API24 or above


network_security_config.xml file Location:"+ stringsFile) 82 | else: 83 | writePassResults(filename,"
[Info] --- Not found <domain-config cleartextTrafficPermitted=\"true\"> in network_security_config.xml
network_security_config.xml file Location:"+ stringsFile) 84 | except IOError: 85 | print("[Info] - App doesn't have network_security_config.xml"); 86 | writePassResults(filename,"
App doesn't have network_security_config.xml") 87 | 88 | def getDeepLinks(): 89 | print("[Info] - Checking for Deeplinks"); 90 | writePassResults(filename,"

Custom URL Check") 91 | # for AndroidManifest.xml file 92 | f1=pwd+"\\"+filename+"\\"+manifestFile 93 | writePassResults(filename,"
[Info]---AndroidManifest.xml file Location: "+ f1) 94 | with open(f1, errors='ignore') as f: 95 | f2=f.read() 96 | i= f2.count(" 0: 101 | j=j-1 102 | scheme1=re.search(r'android:scheme="(.*)"', searchObj1[j], re.M|re.I) 103 | if scheme1: 104 | print(" - scheme: "+ scheme1.group(1) ); 105 | writePassResults(filename,"
scheme: "+ scheme1.group(1)) 106 | host1=searchObj1[j].replace(scheme1.group(),"") 107 | host2=re.search(r'"(.*)"', host1, re.M | re.I) 108 | if host2: 109 | print(" - host: " + host2.group(1)+"\n - Deeplink: " + scheme1.group(1) + "://"+ host2.group(1)); 110 | writePassResults(filename,"
host: " + host2.group(1)+"
Deeplink: " + scheme1.group(1) + "://"+ host2.group(1)) 111 | else: 112 | print(" - host: Not Found \n - Deeplink: " + scheme1.group(1) + "://"); 113 | writePassResults(filename,"
No host found
Deeplink: "+ scheme1.group(1) + "://") 114 | else: 115 | host3=searchObj1[j].replace('"','') 116 | host4=host3.replace('/>','') 117 | writePassResults(filename,"
no scheme found
host: " + host4 +"
Deeplink: " + "://" + host4) 118 | else: 119 | writePassResults(filename,"
NO host") 120 | searchObj=re.findall(r' 0: 124 | i=i-1 125 | host=re.search(r'android:host="(.*)"' , searchObj[i], re.M|re.I) 126 | if host: 127 | writePassResults(filename,"
host: " + host.group(1)) 128 | scheme1=searchObj[i].replace(host.group(),"") 129 | scheme=re.search(r'"(.*)"' , scheme1, re.M|re.I) 130 | if scheme: 131 | writePassResults(filename,"
scheme: " + scheme.group(1)+"
Deeplink: " + scheme.group(1)+"://"+host.group(1)) 132 | scheme=scheme1.replace(scheme.group(),"") 133 | else: 134 | writePassResults(filename,"
No Scheme found
Deeplink: "+ "://"+ host.group(1)) 135 | else: 136 | scheme=searchObj[i].replace('"','') 137 | scheme=scheme.replace('/>','') 138 | writePassResults(filename,"
no host found
scheme: " + scheme +"
Deeplink: " + scheme + "://") 139 | else: 140 | writePassResults(filename,"
No more schemes") 141 | 142 | def isDebuggableOrBackup(): 143 | f1=pwd+"\\"+filename+"\\"+manifestFile 144 | with open(f1, errors='ignore') as f: 145 | f2=f.read() 146 | print("[Info] - Checking AndroidManifest.xml"); 147 | searchObj=re.search(r'android:debuggable="true"' , f2, re.M|re.I) 148 | if searchObj: 149 | print(fg.red+"[Vuln] - Android debuggable. Found android:debuggable=true in AndroidManifest.xml file"+fg.rs); 150 | writeResults(filename,"

[Vulnerability] ---Android debuggable. \n Found android:debuggable=true in AndroidManifest.xml file

") 151 | else: 152 | writePassResults(filename,"

android:debuggable Check
[Info] --- android:debuggable not found") 153 | searchObj1=re.search(r'android:allowBackup="true"' , f2, re.M|re.I) 154 | searchObj2=re.search(r'android:allowBackup="false"' , f2, re.M|re.I) 155 | if searchObj1: 156 | print(fg.red+"[Vuln] - Android backup vulnerability. Found android:allowBackup=true in AndroidManifest.xml file"+fg.rs); 157 | writeResults(filename,"

[Vulnerability] --- Android backup vulnerability. \n Found android:allowBackup=true in AndroidManifest.xml file

") 158 | elif searchObj2: 159 | writePassResults(filename,"

android:allowBackup Check
[Info] --- android:allowBackup=\"false\" found") 160 | else: 161 | print(fg.red+"[Vuln] - Android backup vulnerability. Not found android:allowbackup=true, default value is true, in AndroidManifest.xml file"+fg.rs); 162 | writeResults(filename,"

[Vulnerability] --- Android backup vulnerability . \n Not found android:allowbackup=true, default value is true, in AndroidManifest.xml file

") 163 | 164 | def writeResults(filename,msg): 165 | f=open(resultsHtml,"a") 166 | f.write(msg) 167 | f.close() 168 | 169 | def writePassResults(filename,msg): 170 | f=open(resultsHtmlTemp,"a") 171 | f.write(msg) 172 | f.close() 173 | 174 | apkfile = sys.argv[-1] 175 | # Get file extension .apk 176 | filename, file_extension = os.path.splitext(apkfile) 177 | pwd=os.getcwd() 178 | stringsFile="\\res\\values\\strings.xml" 179 | nscFile="\\res\\xml\\network_security_config.xml" 180 | manifestFile="AndroidManifest.xml" 181 | resultsHtml=filename+".html" 182 | resultsHtmlTemp=filename+"Temp.html" 183 | head=" " 184 | endhtml=" " 185 | print(" ______ _______ _ _ _ _ _ _______ _"); 186 | print(" / _____) (_______) | | (_) | (_) (_|_______|_) "); 187 | print(" ( (____ ____ _____ ____ _______ ____ __| | ____ ___ _ __| | ___ _ _ _ _ "); 188 | print(" \____ \ / ___|____ | _ \| ___ | _ \ / _ |/ ___) _ \| |/ _ | | | | ||_|| | | "); 189 | print(" _____) | (___/ ___ | | | | | | | | | ( (_| | | | |_| | ( (_| |/ / \ \| | | | |_____ "); 190 | print(" (______/ \____)_____|_| |_|_| |_|_| |_|\____|_| \___/|_|\____|_| |_|_| |_|_______)"); 191 | print("\n Created by https://twitter.com/satish_patnayak\n"); 192 | print("This tool analyzes Android app to find vulnerabilities in \n1. AndroidManifest.xml \n2. network_security_config.xml \n3. Firebase URLs from strings.xml. \nThis tool also shows Deeplinks used in Android app.\n"); 193 | writeResults(filename, head +"

This tool analyze Android app to find vulnerabilities in AndroidManifest.xml, network_security_config.xml and Firebase URLs from strings.xml
This tool also shows Deeplinks used in Android app
Developed by Satish Patnayak satish_patnayak

Analysis results of "+apkfile+"

") 194 | if file_extension == ".apk": 195 | #Decompile APK file 196 | print("[Info] - Please wait while I am analyzing Android app" + apkfile); 197 | 198 | if path.exists(resultsHtml): 199 | os.remove(resultsHtml) 200 | writeResults(filename, head +"

This tool analyzes Android app to find vulnerabilities in AndroidManifest.xml, network_security_config.xml and Firebase URLs from strings.xml
This tool also shows Deeplinks used in Android app
Developed by Satish Patnayak satish_patnayak

Analysis results of "+apkfile+"

") 201 | os.system('java -jar apktool.jar d -q "' + apkfile +'"') 202 | isDebuggableOrBackup() 203 | network_security_config_Test(filename, nscFile) 204 | fireBaseTest(filename, stringsFile) 205 | getDeepLinks() 206 | try: 207 | f11=open(resultsHtmlTemp, "r") 208 | writeResults(filename, "

Pass cases

"+f11.read() + endhtml) 209 | f11.close() 210 | os.remove(resultsHtmlTemp) 211 | except IOError: 212 | writeResults(filename,endhtml) 213 | print("Results are printed in "+pwd+"\\"+resultsHtml) 214 | # if file extension is not .apk 215 | else: 216 | print("[Warning] - Please use apk file only"); 217 | writeResults(filename,"
Please use apk file only") -------------------------------------------------------------------------------- /apktool.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/satishpatnayak/ScanAndroidXML/af63e2de0bf2e0adcbe2ee4d03a107fa0d8d0b3f/apktool.jar -------------------------------------------------------------------------------- /info.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/satishpatnayak/ScanAndroidXML/af63e2de0bf2e0adcbe2ee4d03a107fa0d8d0b3f/info.jpg -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests --------------------------------------------------------------------------------