def ExecuteADB(request): print "\n[INFO] Executing ADB Commands" try: if request.method == 'POST': data = {} CMD=request.POST['cmd'] ''' #Allow it Since it's functional if re.findall(";|\$\(|\|\||&&",CMD): print "[ATTACK] Possible RCE" return HttpResponseRedirect('/error/') ''' TOOLSDIR=os.path.join(settings.BASE_DIR, 'DynamicAnalyzer/tools/') #TOOLS DIR adb=getADB(TOOLSDIR) args=[adb, "-s", getIdentifier()] + CMD.split(' ') resp="error" try: resp=subprocess.check_output(args) except: PrintException("[ERROR] Executing ADB Commands") data = {'cmd': 'yes','resp': resp} return HttpResponse(json.dumps(data), content_type='application/json') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] Executing ADB Commands") return HttpResponseRedirect('/error/')
def Touch(request): print "\n[INFO] Sending Touch Events" try: data = {} if (request.method == 'POST') and (is_number( request.POST['x'])) and (is_number(request.POST['y'])): x_axis = request.POST['x'] y_axis = request.POST['y'] TOOLSDIR = os.path.join(settings.BASE_DIR, 'DynamicAnalyzer/tools/') #TOOLS DIR adb = getADB(TOOLSDIR) args = [ adb, "-s", getIdentifier(), "shell", "input", "tap", x_axis, y_axis ] data = {'status': 'success'} try: subprocess.call(args) except: data = {'status': 'error'} PrintException("[ERROR] Performing Touch Action") else: data = {'status': 'failed'} return HttpResponse(json.dumps(data), content_type='application/json') except: PrintException("[ERROR] Sending Touch Events") return HttpResponseRedirect('/error/')
def ExportedActivityTester(request): print "\n[INFO] Exported Activity Tester" try: MD5=request.POST['md5'] PKG=request.POST['pkg'] m=re.match('[0-9a-f]{32}',MD5) if m: if re.findall(";|\$\(|\|\||&&",PKG): print "[ATTACK] Possible RCE" return HttpResponseRedirect('/error/') if request.method == 'POST': DIR=settings.BASE_DIR APP_DIR=os.path.join(settings.UPLD_DIR, MD5+'/') TOOLS_DIR=os.path.join(DIR, 'DynamicAnalyzer/tools/') #TOOLS DIR SCRDIR=os.path.join(APP_DIR,'screenshots-apk/') data = {} adb=getADB(TOOLS_DIR) DB=StaticAnalyzerAndroid.objects.filter(MD5=MD5) if DB.exists(): print "\n[INFO] Fetching Exported Activity List from DB" EXPORTED_ACT=python_list(DB[0].EXPORTED_ACT) if len(EXPORTED_ACT)>0: n=0 print "\n[INFO] Starting Exported Activity Tester..." print "\n[INFO] "+str(len(EXPORTED_ACT))+" Exported Activities Identified" for line in EXPORTED_ACT: try: n+=1 print "\n[INFO] Launching Exported Activity - "+ str(n)+ ". "+line subprocess.call([adb, "-s", getIdentifier(), "shell", "am","start", "-n", PKG+"/"+line]) Wait(4) subprocess.call([adb, "-s", getIdentifier(), "shell", "screencap", "-p", "/data/local/screen.png"]) #? get appended from Air :-() if activity names are used subprocess.call([adb, "-s", getIdentifier(), "pull", "/data/local/screen.png", SCRDIR + "expact-"+str(n)+".png"]) print "\n[INFO] Activity Screenshot Taken" subprocess.call([adb, "-s", getIdentifier(), "shell", "am", "force-stop", PKG]) print "\n[INFO] Stopping App" except: PrintException("[ERROR] Exported Activity Tester") data = {'expacttest': 'done'} else: print "\n[INFO] Exported Activity Tester - No Activity Found!" data = {'expacttest': 'noact'} return HttpResponse(json.dumps(data), content_type='application/json') else: print "\n[ERROR] Entry does not exist in DB." return HttpResponseRedirect('/error/') else: return HttpResponseRedirect('/error/') else: return HttpResponseRedirect('/error/') except: PrintException("ERROR] Exported Activity Tester") return HttpResponseRedirect('/error/')
def GetRes(): print "\n[INFO] Getting Screen Resolution" try: TOOLSDIR = os.path.join(settings.BASE_DIR, 'DynamicAnalyzer/tools/') #TOOLS DIR adb = getADB(TOOLSDIR) resp = subprocess.check_output( [adb, "-s", getIdentifier(), "shell", "dumpsys", "window"]) resp = resp.split("\n") res = "" for line in resp: if "mUnrestrictedScreen" in line: res = line break res = res.split("(0,0)")[1] res = res.strip() res = res.split("x") if len(res) == 2: return res[0], res[1] #width, height return "", "" except: PrintException("[ERROR] Getting Screen Resolution") return "", ""
def UpdateDB(): try: url = "https://www.malwaredomainlist.com/mdlcsv.php" response = urllib2.urlopen(url) data = response.read() TMP_DIR = os.path.join(MALWARE_DB_DIR,'tmp/') TMP_DWD = os.path.join(TMP_DIR,'malwaredomainlist') DB = os.path.join(MALWARE_DB_DIR,'malwaredomainlist') if not os.path.exists(TMP_DIR): os.makedirs(TMP_DIR) with open(TMP_DWD,'wb') as f: f.write(data) #Check1: SHA256 Change if sha256(TMP_DWD) != sha256(DB): #DB needs update #Check2: DB Syntax Changed rd = io.open(TMP_DWD,mode='r',encoding="utf8",errors="ignore") line = rd.readline() rd.close() lst = line.split('",') if len(lst) == 10: #DB Format is not changed. Let's update DB print "\n[INFO] Updating Malware Database...." shutil.copyfile(TMP_DWD,DB) else: print "\n[WARNING] Malware Database format from malwaredomainlist.com changed. Database is not updated. Please report to: https://github.com/ajinabraham/Mobile-Security-Framework-MobSF/issues" else: print "\n[INFO] Malware Database is up-to-date." if os.path.isfile(TMP_DWD): os.remove(TMP_DWD) except: PrintException("[ERROR] Malware DB Update")
def TakeScreenShot(request): print "\n[INFO] Taking Screenshot" try: if request.method == 'POST': MD5=request.POST['md5'] m=re.match('[0-9a-f]{32}',MD5) if m: data = {} r=random.randint(1, 1000000) DIR=settings.BASE_DIR SCRDIR=os.path.join(settings.UPLD_DIR, MD5+'/screenshots-apk/')#make sure that list only png from this directory TOOLSDIR=os.path.join(DIR, 'DynamicAnalyzer/tools/') #TOOLS DIR adb=getADB(TOOLSDIR) subprocess.call([adb, "-s", getIdentifier() ,"shell", "screencap", "-p", "/data/local/screen.png"]) subprocess.call([adb, "-s", getIdentifier() ,"pull", "/data/local/screen.png", SCRDIR + "screenshot-"+str(r)+".png"]) print "\n[INFO] Screenshot Taken" data = {'screenshot': 'yes'} return HttpResponse(json.dumps(data), content_type='application/json') else: return HttpResponseRedirect('/error/') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] Taking Screenshot") return HttpResponseRedirect('/error/')
def ConnectInstallRun(TOOLSDIR,ADB_CON_ID,APKPATH,PACKAGE,LAUNCH,isACT): print "\n[INFO] Starting App for Dynamic Analysis" try: adb=getADB(TOOLSDIR) subprocess.call([adb, "kill-server"]) subprocess.call([adb, "start-server"]) print "\n[INFO] ADB Started" Wait(5) print "\n[INFO] Connecting to VM/Device" subprocess.call([adb, "connect", ADB_CON_ID]) subprocess.call([adb, "wait-for-device"]) print "\n[INFO] Mounting" if settings.REAL_DEVICE: subprocess.call([adb, "-s", getIdentifier(), "shell", "su", "-c", "mount", "-o", "rw,remount,rw", "/system"]) else: subprocess.call([adb, "-s", getIdentifier(), "shell", "su", "-c", "mount", "-o", "rw,remount,rw", "/system"]) #This may not work for VMs other than the default MobSF VM subprocess.call([adb, "-s", getIdentifier(), "shell", "mount", "-o", "rw,remount", "-t", "rfs", "/dev/block/sda6", "/system"]) print "\n[INFO] Installing APK" subprocess.call([adb, "-s", getIdentifier(), "install", "-r", APKPATH]) if isACT: runApp = PACKAGE + "/" + LAUNCH print "\n[INFO] Launching APK Main Activity" subprocess.call([adb, "-s", getIdentifier(), "shell", "am", "start", "-n", runApp]) else: print "\n[INFO] App Doesn't have a Main Activity" #Handle Service or Give Choice to Select in Future. pass print "[INFO] Testing Environment is Ready!" except: PrintException("[ERROR] Starting App for Dynamic Analysis")
def MalwareCheck(urllist): RESULT = {} domainlist = list() try: domainlist = getDomains(urllist) if len(domainlist) > 0: if isInternetAvailable(): UpdateDB(); else: print "\n[WARNING] No Internet Connection. Skipping Malware Database Update." DB = os.path.join(MALWARE_DB_DIR,'malwaredomainlist') with io.open(DB,mode='r',encoding="utf8",errors="ignore") as f: entry_list = f.readlines() for entry in entry_list: enlist = entry.split('","') if len(enlist) > 5: details_dict = dict() details_dict["domain_or_url"] = enlist[1] details_dict["ip"] = enlist[2] details_dict["desc"] = enlist[4] details_dict["bad"] = "yes" for domain in domainlist: if (domain in details_dict["domain_or_url"]) or (domain in details_dict["ip"]): RESULT[domain] = details_dict for domain in domainlist: if domain not in RESULT: x = dict() x["bad"] = "no" RESULT[domain] = x except: PrintException("[ERROR] Performing Malware Check") return RESULT
def HandleSqlite(SFile): print "\n[INFO] SQLite DB Extraction" try: data='' con = sq.connect(SFile) cur = con.cursor() cur.execute("SELECT name FROM sqlite_master WHERE type='table';") tables=cur.fetchall() for table in tables: data+= "\nTABLE: "+str(table[0]).decode('utf8', 'ignore')+" \n=====================================================\n" cur.execute("PRAGMA table_info('%s')" % table) rows=cur.fetchall() head='' for r in rows: head+=str(r[1]).decode('utf8', 'ignore') + " | " data+=head + " \n=====================================================================\n" cur.execute("SELECT * FROM '%s'" % table) rows=cur.fetchall() for r in rows: dat='' for x in r: dat+=str(x).decode('utf8', 'ignore') + " | " data+=dat+"\n" return data except: PrintException("[ERROR] SQLite DB Extraction") pass
def ScreenCast(request): print "\n[INFO] Invoking ScreenCast Service in VM/Device" try: global tcp_server_mode data = {} if (request.method == 'POST'): mode = request.POST['mode'] TOOLSDIR = os.path.join(settings.BASE_DIR, 'DynamicAnalyzer/tools/') #TOOLS DIR adb = getADB(TOOLSDIR) IP = settings.SCREEN_IP PORT = str(settings.SCREEN_PORT) if mode == "on": args = [ adb, "-s", getIdentifier(), "shell", "am", "startservice", "-a", IP + ":" + PORT, "opensecurity.screencast/.StartScreenCast" ] data = {'status': 'on'} tcp_server_mode = "on" elif mode == "off": args = [ adb, "-s", getIdentifier(), "shell", "am", "force-stop", "opensecurity.screencast" ] data = {'status': 'off'} tcp_server_mode = "off" if (mode == "on") or (mode == "off"): try: subprocess.call(args) t = threading.Thread(target=ScreenCastService) t.setDaemon(True) t.start() except: PrintException("[ERROR] Casting Screen") data = {'status': 'error'} return HttpResponse(json.dumps(data), content_type='application/json') else: data = {'status': 'failed'} else: data = {'status': 'failed'} return HttpResponse(json.dumps(data), content_type='application/json') except: PrintException("[ERROR] Casting Screen") return HttpResponseRedirect('/error/')
def getIdentifier(): try: if settings.REAL_DEVICE: return settings.DEVICE_IP + ":" + str(settings.DEVICE_ADB_PORT) else: return settings.VM_IP + ":" + str(settings.VM_ADB_PORT) except: PrintException("[ERROR] Getting ADB Connection Identifier for Device/VM")
def PushtoRecent(NAME, MD5, URL): try: DB = RecentScansDB.objects.filter(MD5=MD5) if not DB.exists(): NDB = RecentScansDB(NAME=NAME, MD5=MD5, URL=URL, TS=timezone.now()) NDB.save() except: PrintException("[ERROR] Adding Scan URL to Database")
def DumpData(request): #Closing External Services and Dumping data print "\n[INFO] Device Data Dump" try: if request.method == 'POST': data = {} PACKAGE=request.POST['pkg'] MD5=request.POST['md5'] m=re.match('[0-9a-f]{32}',MD5) if m: if re.findall(";|\$\(|\|\||&&",PACKAGE): print "[ATTACK] Possible RCE" return HttpResponseRedirect('/error/') DIR=settings.BASE_DIR APKDIR=os.path.join(settings.UPLD_DIR, MD5+'/') TOOLSDIR=os.path.join(DIR, 'DynamicAnalyzer/tools/') #TOOLS DIR adb=getADB(TOOLSDIR) Proxy("","","","") #Let's try to close Proxy a bit early as we don't have much control on the order of thread execution print "\n[INFO] Deleting Dump Status File" subprocess.call([adb, "-s", getIdentifier(), "shell", "rm","/sdcard/mobsec_status"]) print "\n[INFO] Creating TAR of Application Files." subprocess.call([adb, "-s", getIdentifier(), "shell", "am", "startservice", "-a", PACKAGE, "opensecurity.ajin.datapusher/.GetPackageLocation"]) print "\n[INFO] Waiting for TAR dump to complete..." if settings.REAL_DEVICE: timeout=settings.DEVICE_TIMEOUT else: timeout=settings.VM_TIMEOUT start_time=time.time() while True: current_time=time.time() if "MOBSEC-TAR-CREATED" in subprocess.check_output([adb, "-s", getIdentifier(), "shell", "cat", "/sdcard/mobsec_status"]): break if (current_time-start_time) > timeout: print "\n[ERROR] TAR Generation Failed. Process timed out." break print "\n[INFO] Dumping Application Files from Device/VM" subprocess.call([adb, "-s", getIdentifier(), "pull", "/data/local/"+PACKAGE+".tar", APKDIR+PACKAGE+".tar"]) print "\n[INFO] Stopping ADB" subprocess.call([adb, "-s", getIdentifier(), "kill-server"]) data = {'dump': 'yes'} return HttpResponse(json.dumps(data), content_type='application/json') else: return HttpResponseRedirect('/error/') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] Device Data Dump") return HttpResponseRedirect('/error/')
def getDomains(urls): try: DOMAINS=list() for url in urls: parsed_uri = urlparse(url) domain = '{uri.netloc}'.format(uri=parsed_uri) if ((domain not in DOMAINS) and (len(domain) > 2) and ("." in domain) and (domain.endswith(".")==False and re.search('[a-zA-Z0-9]', domain))): DOMAINS.append(domain) return DOMAINS except: PrintException("[ERROR] Extracting Domain form URL") pass
def FinalTest(request): #Closing Services in VM/Device global tcp_server_mode print "\n[INFO] Collecting Data and Cleaning Up" try: if request.method == 'POST': data = {} MD5=request.POST['md5'] PACKAGE=request.POST['pkg'] if re.findall(";|\$\(|\|\||&&",PACKAGE): print "[ATTACK] Possible RCE" return HttpResponseRedirect('/error/') m=re.match('[0-9a-f]{32}',MD5) if m: #Stop ScreenCast Client if it is running tcp_server_mode = "off" DIR=settings.BASE_DIR APKDIR=os.path.join(settings.UPLD_DIR, MD5+'/') TOOLSDIR=os.path.join(DIR, 'DynamicAnalyzer/tools/') #TOOLS DIR adb=getADB(TOOLSDIR) #Change to check output of subprocess when analysis is done #Can't RCE os.system(adb+' -s '+getIdentifier()+' logcat -d dalvikvm:W ActivityManager:I > "'+APKDIR + 'logcat.txt"') print "\n[INFO] Downloading Logcat logs" #os.system(adb+' -s '+getIdentifier()+' logcat -d Xposed:I *:S > "'+APKDIR + 'x_logcat.txt"') subprocess.call([adb, "-s", getIdentifier(), "pull", "/data/data/de.robv.android.xposed.installer/log/error.log", APKDIR + "x_logcat.txt"]) print "\n[INFO] Downloading Droidmon API Monitor Logcat logs" #Can't RCE os.system(adb+' -s '+getIdentifier()+' shell dumpsys > "'+APKDIR + 'dump.txt"'); print "\n[INFO] Downloading Dumpsys logs" subprocess.call([adb, "-s", getIdentifier(), "shell", "am", "force-stop", PACKAGE]) print "\n[INFO] Stopping Application" subprocess.call([adb, "-s", getIdentifier(), "shell", "am", "force-stop", "opensecurity.screencast"]) print "\n[INFO] Stopping ScreenCast Service" data = {'final': 'yes'} return HttpResponse(json.dumps(data), content_type='application/json') else: return HttpResponseRedirect('/error/') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] Clean Up") return HttpResponseRedirect('/error/')
def RefreshVM(uuid,snapshot_uuid,vbox_exe): print "\n[INFO] Refreshing MobSF VM" try: #Close VM args=[vbox_exe,'controlvm',uuid,'poweroff'] subprocess.call(args) print "\n[INFO] VM Closed" #Restore Snapshot args=[vbox_exe,'snapshot',uuid,'restore',snapshot_uuid] subprocess.call(args) print "\n[INFO] VM Restore Snapshot" #Start Fresh VM args=[vbox_exe,'startvm',uuid] subprocess.call(args) print "\n[INFO] VM Starting" except: PrintException("[ERROR] Refreshing MobSF VM")
def DynamicAnalyzer(request): print "\n[INFO] Dynamic Analysis Started" try: if request.method == 'POST': MD5 = request.POST['md5'] PKG = request.POST['pkg'] LNCH = request.POST['lng'] if re.findall(";|\$\(|\|\||&&", PKG) or re.findall( ";|\$\(|\|\||&&", LNCH): print "[ATTACK] Possible RCE" return HttpResponseRedirect('/error/') m = re.match('[0-9a-f]{32}', MD5) if m: # Delete ScreenCast Cache SCREEN_FILE = os.path.join(settings.STATIC_DIR, 'screen/screen.png') if os.path.exists(SCREEN_FILE): os.remove(SCREEN_FILE) # Delete Contents of Screenshot Dir SCRDIR = os.path.join(settings.UPLD_DIR, MD5 + '/screenshots-apk/') if os.path.isdir(SCRDIR): shutil.rmtree(SCRDIR) #Start DM Proxy("", "", "", "") if settings.REAL_DEVICE: print "\n[INFO] MobSF will perform Dynamic Analysis on real Android Device" else: #Refersh VM RefreshVM(settings.UUID, settings.SUUID, settings.VBOX) context = { 'md5': MD5, 'pkg': PKG, 'lng': LNCH, 'title': 'Start Testing', } template = "start_test.html" return render(request, template, context) else: return HttpResponseRedirect('/error/') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] DynamicAnalyzer") return HttpResponseRedirect('/error/')
def View(request): print "\n[INFO] Viewing File" try: typ = '' fil = '' rtyp = '' dat = '' m = re.match('[0-9a-f]{32}', request.GET['md5']) if m: fil = request.GET['file'] MD5 = request.GET['md5'] typ = request.GET['type'] SRC = os.path.join(settings.UPLD_DIR, MD5 + '/DYNAMIC_DeviceData/') sfile = os.path.join(SRC, fil) #Prevent Directory Traversal Attacks if (("../" in fil) or ("%2e%2e" in fil) or (".." in fil) or ("%252e" in fil)): return HttpResponseRedirect('/error/') else: with io.open(sfile, mode='r', encoding="utf8", errors="ignore") as f: dat = f.read() if ((fil.endswith('.xml')) and (typ == 'xml')): rtyp = 'xml' elif typ == 'db': dat = HandleSqlite(sfile) dat = dat.decode("windows-1252").encode("utf8") rtyp = 'plain' elif typ == 'others': rtyp = 'plain' else: return HttpResponseRedirect('/error/') context = { 'title': escape(ntpath.basename(fil)), 'file': escape(ntpath.basename(fil)), 'dat': dat, 'type': rtyp, } template = "view.html" return render(request, template, context) else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] Viewing File") return HttpResponseRedirect('/error/')
def RunProcess(args): try: proc = subprocess.Popen( args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, ) dat = '' while True: line = proc.stdout.readline() if not line: break dat += line return dat except: PrintException("[ERROR] Finding Java path - Cannot Run Process") return ""
def GetEnv(request): print "\n[INFO] Setting up Dynamic Analysis Environment" try: if request.method == 'POST': data = {} MD5 = request.POST['md5'] PKG = request.POST['pkg'] LNCH = request.POST['lng'] if re.findall(";|\$\(|\|\||&&", PKG) or re.findall( ";|\$\(|\|\||&&", LNCH): print "[ATTACK] Possible RCE" return HttpResponseRedirect('/error/') m = re.match('[0-9a-f]{32}', MD5) if m: DIR = settings.BASE_DIR APP_DIR = os.path.join(settings.UPLD_DIR, MD5 + '/') #APP DIRECTORY APP_FILE = MD5 + '.apk' #NEW FILENAME APP_PATH = APP_DIR + APP_FILE #APP PATH TOOLS_DIR = os.path.join(DIR, 'DynamicAnalyzer/tools/') #TOOLS DIR DWD_DIR = settings.DWD_DIR ADB_CON_ID = getIdentifier() PROXY_IP = settings.PROXY_IP #Proxy IP PORT = str(settings.PORT) #Proxy Port WebProxy(APP_DIR, PROXY_IP, PORT) ConnectInstallRun( TOOLS_DIR, ADB_CON_ID, APP_PATH, PKG, LNCH, True) #Change True to support non-activity components SCREEN_WIDTH, SCREEN_HEIGHT = GetRes() data = { 'ready': 'yes', 'screen_witdth': SCREEN_WIDTH, 'screen_height': SCREEN_HEIGHT, } return HttpResponse(json.dumps(data), content_type='application/json') else: return HttpResponseRedirect('/error/') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] Setting up Dynamic Analysis Environment") return HttpResponseRedirect('/error/')
def getADB(TOOLSDIR): print "\n[INFO] Getting ADB Location" try: adb='adb' if platform.system()=="Darwin": adb_dir=os.path.join(TOOLSDIR, 'adb/mac/') subprocess.call(["chmod", "777", adb_dir]) adb=os.path.join(TOOLSDIR , 'adb/mac/adb') elif platform.system()=="Linux": adb_dir=os.path.join(TOOLSDIR, 'adb/linux/') subprocess.call(["chmod", "777", adb_dir]) adb=os.path.join(TOOLSDIR , 'adb/linux/adb') elif platform.system()=="Windows": adb=os.path.join(TOOLSDIR , 'adb/windows/adb.exe') return adb except: PrintException("[ERROR] Getting ADB Location") return "adb"
def MobSFCA(request): try: if request.method == 'POST': data = {} act = request.POST['action'] TOOLSDIR = os.path.join(settings.BASE_DIR, 'DynamicAnalyzer/tools/') #TOOLS DIR ROOTCA = os.path.join(settings.BASE_DIR, 'DynamicAnalyzer/pyWebProxy/ca.crt') adb = getADB(TOOLSDIR) if act == "install": print "\n[INFO] Installing MobSF RootCA" subprocess.call([ adb, "-s", getIdentifier(), "push", ROOTCA, "/data/local/tmp/" + settings.ROOT_CA ]) subprocess.call([ adb, "-s", getIdentifier(), "shell", "su", "-c", "cp", "/data/local/tmp/" + settings.ROOT_CA, "/system/etc/security/cacerts/" + settings.ROOT_CA ]) subprocess.call([ adb, "-s", getIdentifier(), "shell", "rm", "/data/local/tmp/" + settings.ROOT_CA ]) data = {'ca': 'installed'} elif act == "remove": print "\n[INFO] Removing MobSF RootCA" subprocess.call([ adb, "-s", getIdentifier(), "shell", "su", "-c", "rm", "/system/etc/security/cacerts/" + settings.ROOT_CA ]) data = {'ca': 'removed'} return HttpResponse(json.dumps(data), content_type='application/json') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] MobSF RootCA Handler") return HttpResponseRedirect('/error/')
def Download(MD5,DWDDIR,APKDIR,PKG): print "\n[INFO] Generating Downloads" try: Logcat=os.path.join(APKDIR,'logcat.txt') xLogcat=os.path.join(APKDIR,'x_logcat.txt') Dumpsys=os.path.join(APKDIR,'dump.txt') Sshot=os.path.join(APKDIR,'screenshots-apk/') Web=os.path.join(APKDIR,'WebTraffic.txt') Star=os.path.join(APKDIR, PKG+'.tar') DLogcat=os.path.join(DWDDIR,MD5+'-logcat.txt') DxLogcat=os.path.join(DWDDIR,MD5+'-x_logcat.txt') DDumpsys=os.path.join(DWDDIR,MD5+'-dump.txt') DSshot=os.path.join(DWDDIR,MD5+'-screenshots-apk/') DWeb=os.path.join(DWDDIR,MD5+'-WebTraffic.txt') DStar=os.path.join(DWDDIR,MD5+'-AppData.tar') #Delete existing data dellist = [DLogcat,DxLogcat,DDumpsys,DSshot,DWeb,DStar] for item in dellist: if os.path.isdir(item): shutil.rmtree(item) elif os.path.isfile(item): os.remove(item) #Copy new data shutil.copyfile(Logcat,DLogcat) shutil.copyfile(xLogcat,DxLogcat) shutil.copyfile(Dumpsys,DDumpsys) try: shutil.copytree(Sshot,DSshot) except: pass try: shutil.copyfile(Web,DWeb) except: pass try: shutil.copyfile(Star,DStar) except: pass except: PrintException("[ERROR] Generating Downloads")
def ScreenCastService(): global tcp_server_mode print "\n[INFO] ScreenCast Service Status: " + tcp_server_mode try: SCREEN_DIR = os.path.join(settings.STATIC_DIR, 'screen/') if not os.path.exists(SCREEN_DIR): os.makedirs(SCREEN_DIR) s = socket.socket() if tcp_server_mode == "on": s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) ADDR = (settings.SCREEN_IP, settings.SCREEN_PORT) s.bind(ADDR) s.listen(10) while (tcp_server_mode == "on"): ss, address = s.accept() print "Got Connection from: ", address[0] if settings.REAL_DEVICE: IP = settings.DEVICE_IP else: IP = settings.VM_IP if address[0] == IP: ''' Very Basic Check to ensure that only MobSF VM/Device is allowed to connect to MobSF ScreenCast Service. ''' with open(SCREEN_DIR + 'screen.png', 'wb') as f: while True: data = ss.recv(1024) if not data: break f.write(data) else: print "\n[ATTACK] An unknown client :" + address[ 0] + " is trying to make a connection with MobSF ScreenCast Service!" elif tcp_server_mode == "off": s.close() except: s.close() PrintException("[ERROR] ScreenCast Server") pass
def SaveOnExit(): print "\n[INFO] Saving Captured Web Proxy Data" try: global REQUEST_LIST, URLS, TRAFFIC, log print "\n[INFO] Saving URLS" with open(os.path.join(log, "urls"), "w") as f2: URLS = list(set(URLS)) URLS = '\n'.join(URLS) f2.write(URLS) print "\n[INFO] Saving WebTraffic" with open(os.path.join(log, "WebTraffic.txt"), "w") as f3: f3.write(TRAFFIC) print "\n[INFO] Saving Request Objects" with codecs.open(os.path.join(log, "requestdb"), "w", "utf-8") as f: json.dump(REQUEST_LIST, f) except: PrintException("[ERROR] Saving Captured Web Proxy Data") REQUEST_LIST = [] URLS = [] TRAFFIC = ""
def Upload(request): try: response_data = {} response_data['url'] = '' response_data['description'] = '' response_data['status'] = '' if request.method == 'POST': form = UploadFileForm(request.POST, request.FILES) if form.is_valid(): file_type = request.FILES['file'].content_type print "[INFO] MIME Type: " + file_type + " FILE: " + str( request.FILES['file'].name) if (file_type == "application/octet-stream" or file_type == "application/vnd.android.package-archive" or file_type == "application/x-zip-compressed" ) and request.FILES['file'].name.endswith('.apk'): #APK md5 = handle_uploaded_file(request.FILES['file'], '.apk') response_data[ 'url'] = 'StaticAnalyzer/?name=' + request.FILES[ 'file'].name + '&type=apk&checksum=' + md5 response_data['status'] = 'success' PushtoRecent(request.FILES['file'].name, md5, response_data['url']) print "\n[INFO] Performing Static Analysis of Android APK" elif (file_type == "application/zip" or file_type == "application/octet-stream" or file_type == "application/x-zip-compressed" ) and request.FILES['file'].name.endswith( '.zip'): #Android /iOS Zipped Source md5 = handle_uploaded_file(request.FILES['file'], '.zip') response_data[ 'url'] = 'StaticAnalyzer/?name=' + request.FILES[ 'file'].name + '&type=zip&checksum=' + md5 response_data['status'] = 'success' PushtoRecent(request.FILES['file'].name, md5, response_data['url']) print "\n[INFO] Performing Static Analysis of Android/iOS Source Code" elif ((file_type == "application/octet-stream" or file_type == "application/x-itunes-ipa" or file_type == "application/x-zip-compressed") and request.FILES['file'].name.endswith('.ipa') ): #iOS Binary if platform.system() == "Darwin": md5 = handle_uploaded_file(request.FILES['file'], '.ipa') response_data[ 'url'] = 'StaticAnalyzer_iOS/?name=' + request.FILES[ 'file'].name + '&type=ipa&checksum=' + md5 response_data['status'] = 'success' PushtoRecent(request.FILES['file'].name, md5, response_data['url']) print "\n[INFO] Performing Static Analysis of iOS IPA" else: response_data['url'] = 'MAC_ONLY/' response_data['status'] = 'success' print "\n[ERROR] Static Analysis of iOS IPA requires OSX" else: response_data['url'] = '' response_data['description'] = 'File format not Supported!' response_data['status'] = 'error' print "\n[ERROR] File format not Supported!" else: response_data['url'] = '' response_data['description'] = 'Invalid Form Data!' response_data['status'] = 'error' print "\n[ERROR] Invalid Form Data!" else: response_data['url'] = '' response_data['description'] = 'Method not Supported!' response_data['status'] = 'error' print "\n[ERROR] Method not Supported!" form = UploadFileForm() r = HttpResponse(json.dumps(response_data), content_type="application/json") r['Access-Control-Allow-Origin'] = '*' return r except: PrintException("[ERROR] Uploading File:")
def FindJava(): try: if platform.system() == "Windows": print "\n[INFO] Finding JDK Location in Windows...." WIN_JAVA_LIST = [ "C:/Program Files/Java/", "C:/Program Files (x86)/Java/" ] #JDK 7 jdk1.7.0_17/bin/ for WIN_JAVA_BASE in WIN_JAVA_LIST: JDK = [] for dirname in os.listdir(WIN_JAVA_BASE): if "jdk" in dirname: JDK.append(dirname) if len(JDK) == 1: print "\n[INFO] Oracle JDK Identified. Looking for JDK 1.7 or above" j = ''.join(JDK) if re.findall(JAVA_VER, j): WIN_JAVA = WIN_JAVA_BASE + j + "/bin/" args = [WIN_JAVA + "java"] dat = RunProcess(args) if "oracle" in dat: print "\n[INFO] Oracle Java (JDK >= 1.7) is installed!" return WIN_JAVA elif len(JDK) > 1: print "\n[INFO] Multiple JDK Instances Identified. Looking for JDK 1.7 or above" for j in JDK: if re.findall(JAVA_VER, j): WIN_JAVA = WIN_JAVA_BASE + j + "/bin/" break else: WIN_JAVA = "" if len(WIN_JAVA) > 1: args = [WIN_JAVA + "java"] dat = RunProcess(args) if "oracle" in dat: print "\n[INFO] Oracle Java (JDK >= 1.7) is installed!" return WIN_JAVA PrintException("[ERROR] Oracle JDK 1.7 or above is not found!") return "" else: print "\n[INFO] Finding JDK Location in Linux/MAC...." MAC_LINUX_JAVA = "/usr/bin/" args = [MAC_LINUX_JAVA + "java"] dat = RunProcess(args) if "oracle" in dat: print "\n[INFO] Oracle Java is installed!" args = [MAC_LINUX_JAVA + "java", '-version'] dat = RunProcess(args) f_line = dat.split("\n")[0] if re.findall(JAVA_VER, f_line): print "\n[INFO] JDK 1.7 or above is available" return MAC_LINUX_JAVA else: PrintException( "[ERROR] Please install Oracle JDK 1.7 or above") return "" else: PrintException( "[ERROR] Oracle Java JDK 1.7 or above is not found!") return "" except: PrintException("[ERROR] Oracle Java (JDK >=1.7) is not found!") return ""
def RunAnalysis(APKDIR,MD5,PACKAGE): print "\n[INFO] Dynamic File Analysis" Web=os.path.join(APKDIR,'WebTraffic.txt') Logcat=os.path.join(APKDIR,'logcat.txt') xLogcat=os.path.join(APKDIR,'x_logcat.txt') traffic='' wb='' xlg='' try: with io.open(Web,mode='r',encoding="utf8",errors="ignore") as f: wb=f.read() except: pass with io.open(Logcat,mode='r',encoding="utf8",errors="ignore") as f: traffic=f.read() with io.open(xLogcat,mode='r',encoding="utf8",errors="ignore") as f: xlg=f.read() traffic=wb+traffic+xlg URLS=[] #URLs My Custom regex p = re.compile(ur'((?:https?://|s?ftps?://|file://|javascript:|data:|www\d{0,3}[.])[\w().=/;,#:@?&~*+!$%\'{}-]+)', re.UNICODE) urllist=re.findall(p, traffic.lower()) for url in urllist: if url not in URLS: URLS.append(url) #Email Etraction Regex EMAILS=[] regex = re.compile(("[\w.-]+@[\w-]+\.[\w.]+")) for email in regex.findall(traffic.lower()): if ((email not in EMAILS) and (not email.startswith('//'))): if email=="*****@*****.**": pass else: EMAILS.append(email) #Extract Device Data try: TARLOC=os.path.join(APKDIR,PACKAGE+'.tar') UNTAR_DIR = os.path.join(APKDIR,'DYNAMIC_DeviceData/') if not os.path.exists(UNTAR_DIR): os.makedirs(UNTAR_DIR) with tarfile.open(TARLOC) as tar: try: tar.extractall(UNTAR_DIR) except: pass except: PrintException("[ERROR] TAR EXTRACTION FAILED") #Do Static Analysis on Data from Device xmlfiles='' SQLiteDB='' OtherFiles='' typ='' UNTAR_DIR = os.path.join(APKDIR,'DYNAMIC_DeviceData/') if not os.path.exists(UNTAR_DIR): os.makedirs(UNTAR_DIR) try: for dirName, subDir, files in os.walk(UNTAR_DIR): for jfile in files: file_path=os.path.join(UNTAR_DIR,dirName,jfile) if "+" in file_path: shutil.move(file_path,file_path.replace("+","x")) file_path=file_path.replace("+","x") fileparam=file_path.replace(UNTAR_DIR,'') if jfile=='lib': pass else: if jfile.endswith('.xml'): typ='xml' xmlfiles+="<tr><td><a href='../View/?file="+escape(fileparam)+"&md5="+MD5+"&type="+typ+"'>"+escape(fileparam)+"</a></td><tr>" else: with io.open(file_path, mode='r',encoding="utf8",errors="ignore") as f: b=f.read(6) if b=="SQLite": typ='db' SQLiteDB+="<tr><td><a href='../View/?file="+escape(fileparam)+"&md5="+MD5+"&type="+typ+"'>"+escape(fileparam)+"</a></td><tr>" elif not jfile.endswith('.DS_Store'): typ='others' OtherFiles+="<tr><td><a href='../View/?file="+escape(fileparam)+"&md5="+MD5+"&type="+typ+"'>"+escape(fileparam)+"</a></td><tr>" except: PrintException("[ERROR] Dynamic File Analysis") pass return URLS,EMAILS,wb,xmlfiles,SQLiteDB,OtherFiles
def APIAnalysis(PKG,LOCATION): print "\n[INFO] Dynamic API Analysis" dat="" API_BASE64=[] API_FILEIO=[] API_RELECT=[] API_SYSPROP=[] API_CNTRSLVR=[] API_CNTVAL=[] API_BINDER=[] API_CRYPTO=[] API_ACNTMNGER=[] API_DEVICEINFO=[] API_NET=[] API_DEXLOADER=[] API_CMD=[] API_SMS=[] try: with open(LOCATION,"r") as f: dat=f.readlines() ID="Droidmon-apimonitor-" + PKG +":" for line in dat: line = line.decode('utf8', 'ignore') if (ID) in line: #print "LINE: " + line param, value = line.split(ID,1) #print "PARAM is :" + param #print "Value is :"+ value try: APIs=json.loads(value,strict=False) RET='' CLS='' MTD='' ARGS='' MTD= str(APIs["method"]) CLS= str(APIs["class"]) #print "Called Class: " + CLS #print "Called Method: " + MTD if APIs.get('return'): RET=str(APIs["return"]) #print "Return Data: " + RET else: #print "No Return Data" RET = "No Return Data" if APIs.get('args'): ARGS=str(APIs["args"]) #print "Passed Arguments" + ARGS else: #print "No Arguments Passed" ARGS= "No Arguments Passed" #XSS Safe D="</br>METHOD: "+ escape(MTD) + "</br>ARGUMENTS: "+ escape(ARGS) + "</br>RETURN DATA: "+escape(RET) if re.findall("android.util.Base64",CLS): API_BASE64.append(D) if re.findall('libcore.io|android.app.SharedPreferencesImpl$EditorImpl',CLS): API_FILEIO.append(D) if re.findall('java.lang.reflect',CLS): API_RELECT.append(D) if re.findall('android.content.ContentResolver|android.location.Location|android.media.AudioRecord|android.media.MediaRecorder|android.os.SystemProperties',CLS): API_SYSPROP.append(D) if re.findall('android.app.Activity|android.app.ContextImpl|android.app.ActivityThread',CLS): API_BINDER.append(D) if re.findall('javax.crypto.spec.SecretKeySpec|javax.crypto.Cipher|javax.crypto.Mac',CLS): API_CRYPTO.append(D) if re.findall('android.accounts.AccountManager|android.app.ApplicationPackageManager|android.app.NotificationManager|android.net.ConnectivityManager|android.content.BroadcastReceiver',CLS): API_ACNTMNGER.append(D) if re.findall('android.telephony.TelephonyManager|android.net.wifi.WifiInfo|android.os.Debug',CLS): API_DEVICEINFO.append(D) if re.findall('dalvik.system.BaseDexClassLoader|dalvik.system.DexFile|dalvik.system.DexClassLoader|dalvik.system.PathClassLoader',CLS): API_DEXLOADER.append(D) if re.findall('java.lang.Runtime|java.lang.ProcessBuilder|java.io.FileOutputStream|java.io.FileInputStream|android.os.Process',CLS): API_CMD.append(D) if re.findall('android.content.ContentValues',CLS): API_CNTVAL.append(D) if re.findall('android.telephony.SmsManager',CLS): API_SMS.append(D) if re.findall('java.net.URL|org.apache.http.impl.client.AbstractHttpClient',CLS): API_NET.append(D) except: PrintException("[ERROR] Parsing JSON Failed for: " + value) except: PrintException("[ERROR] Dynamic API Analysis") pass return list(set(API_NET)),list(set(API_BASE64)), list(set(API_FILEIO)), list(set(API_BINDER)), list(set(API_CRYPTO)), list(set(API_DEVICEINFO)), list(set(API_CNTVAL)), list(set(API_SMS)), list(set(API_SYSPROP)),list(set(API_DEXLOADER)),list(set(API_RELECT)),list(set(API_ACNTMNGER)),list(set(API_CMD))
def WebProxy(APKDIR,ip,port): print "\n[INFO] Starting Web Proxy" try: Proxy(ip,port,APKDIR,"on") except: PrintException("[ERROR] Starting Web Proxy")