Data Storage on Android - Mobile Security Testing Guide

文章推薦指數: 80 %
投票人數:10人

In general sensitive data stored locally on the device should always be at least encrypted, and any keys used for encryption methods should be securely stored ... MobileSecurityTestingGuideSearch…0x01-ForewordChangelogFrontispieceOverviewIntroductiontotheMobileSecurityTestingGuideMobileAppTaxonomyMobileAppSecurityTestingGeneralMobileAppTestingGuideMobileAppAuthenticationArchitecturesTestingNetworkCommunicationCryptographyinMobileAppsTestingCodeQualityTamperingandReverseEngineeringTestingUserEducationAndroidTestingGuidePlatformOverviewAndroidBasicSecurityTestingDataStorageonAndroidAndroidCryptographicAPIsLocalAuthenticationonAndroidAndroidNetworkAPIsAndroidPlatformAPIsCodeQualityandBuildSettingsforAndroidAppsTamperingandReverseEngineeringonAndroidAndroidAnti-ReversingDefensesiOSTestingGuidePlatformOverviewiOSBasicSecurityTestingDataStorageoniOSiOSCryptographicAPIsLocalAuthenticationoniOSiOSNetworkAPIsiOSPlatformAPIsCodeQualityandBuildSettingsforiOSAppsTamperingandReverseEngineeringoniOSiOSAnti-ReversingDefensesAppendixTestingToolsSuggestedReadingPoweredByGitBookDataStorageonAndroidProtectingauthenticationtokens,privateinformation,andothersensitivedataiskeytomobilesecurity.Inthischapter,youwilllearnabouttheAPIsAndroidoffersforlocaldatastorageandbestpracticesforusingthem.Theguidelinesforsavingdatacanbesummarizedquiteeasily:Publicdatashouldbeavailabletoeveryone,butsensitiveandprivatedatamustbeprotected,or,betteryet,keptoutofdevicestorage.Thischapterisbrokenintotwosections,thefirstofwhichfocusesonthetheoryofdatastoragefromasecurityperspectiveaswellasabriefexplanationandexampleofthevariousmethodsofdatastorageonAndroid.Thesecondsectionfocusesonthetestingofthesedatastoragesolutionsthroughtheusageoftestcasesthatutilizebothstaticanddynamicanalysis.TheoryOverview​Storingdataisessentialtomanymobileapps.Conventionalwisdomsuggeststhataslittlesensitivedataaspossibleshouldbestoredonpermanentlocalstorage.Inmostpracticalscenarios,however,sometypeofuserdatamustbestored.Forexample,askingtheusertoenteraverycomplexpasswordeverytimetheappstartsisn'tagreatideaintermsofusability.Mostappsmustlocallycachesomekindofauthenticationtokentoavoidthis.Personallyidentifiableinformation(PII)andothertypesofsensitivedatamayalsobesavedifagivenscenariocallsforit.Sensitivedataisvulnerablewhenitisnotproperlyprotectedbytheappthatispersistentlystoringit.Theappmaybeabletostorethedatainseveralplaces,forexample,onthedeviceoronanexternalSDcard.Whenyou'retryingtoexploitthesekindsofissues,considerthatalotofinformationmaybeprocessedandstoredindifferentlocations.First,itisimportanttoidentifythekindofinformationprocessedbythemobileapplicationandinputbytheuser.Next,determiningwhatcanbeconsideredsensitivedatathatmaybevaluabletoattackers(e.g.,passwords,creditcardinformation,PII)isnotalwaysatrivialtaskanditstronglydependsonthecontextofthetargetapplication.Youcanfindmoredetailsregardingdataclassificationinthe"IdentifyingSensitiveData"sectionofthechapter"MobileAppSecurityTesting".ForgeneralinformationonAndroidDataStorageSecurity,refertotheSecurityTipsforStoringDataintheAndroiddeveloper'sguide.Disclosingsensitiveinformationhasseveralconsequences,includingdecryptedinformation.Ingeneral,anattackermayidentifythisinformationanduseitforadditionalattacks,suchassocialengineering(ifPIIhasbeendisclosed),accounthijacking(ifsessioninformationoranauthenticationtokenhasbeendisclosed),andgatheringinformationfromappsthathaveapaymentoption(toattackandabusethem).Nexttoprotectingsensitivedata,youneedtoensurethatdatareadfromanystoragesourceisvalidatedandpossiblysanitized.Thevalidationusuallyrangesfromcheckingforthecorrectdatatypestousingadditionalcryptographiccontrols,suchasanHMAC,youcanvalidatetheintegrityofthedata.DataStorageMethodsOverviewAndroidprovidesanumberofmethodsfordatastoragedependingontheneedsoftheuser,developer,andapplication.Forexample,someappsusedatastoragetokeeptrackofusersettingsoruser-provideddata.Datacanbestoredpersistentlyforthisusecaseinseveralways.ThefollowinglistofpersistentstoragetechniquesarewidelyusedontheAndroidplatform:SharedPreferencesSQLiteDatabasesFirebaseDatabasesRealmDatabasesInternalStorageExternalStorageKeystoreInadditiontothis,thereareanumberofotherfunctionsinAndroidbuiltforvarioususecasesthatcanalsoresultinthestorageofdataandrespectivelyshouldalsobetested,suchas:LoggingFunctionsAndroidBackupsProcessesMemoryKeyboardCachesScreenshotsItisimportanttounderstandeachrelevantdatastoragefunctioninordertocorrectlyperformtheappropriatetestcases.Thisoverviewaimstoprovideabriefoutlineofeachofthesedatastoragemethods,aswellaspointtesterstofurtherrelevantdocumentation.SharedPreferencesTheSharedPreferencesAPIiscommonlyusedtopermanentlysavesmallcollectionsofkey-valuepairs.DatastoredinaSharedPreferencesobjectiswrittentoaplain-textXMLfile.TheSharedPreferencesobjectcanbedeclaredworld-readable(accessibletoallapps)orprivate.MisuseoftheSharedPreferencesAPIcanoftenleadtoexposureofsensitivedata.Considerthefollowingexample:ExampleforJava:1SharedPreferencessharedPref=getSharedPreferences("key",MODE_WORLD_READABLE);2SharedPreferences.Editoreditor=sharedPref.edit();3editor.putString("username","administrator");4editor.putString("password","supersecret");5editor.commit();Copied!ExampleforKotlin:1varsharedPref=getSharedPreferences("key",Context.MODE_WORLD_READABLE)2vareditor=sharedPref.edit()3editor.putString("username","administrator")4editor.putString("password","supersecret")5editor.commit()Copied!Oncetheactivityhasbeencalled,thefilekey.xmlwillbecreatedwiththeprovideddata.Thiscodeviolatesseveralbestpractices.Theusernameandpasswordarestoredincleartextin/data/data//shared_prefs/key.xml.123administrator4supersecret5Copied!MODE_WORLD_READABLEallowsallapplicationstoaccessandreadthecontentsofkey.xml.1[email protected]:/data/data/sg.vp.owasp_mobile.myfirstapp/shared_prefs#ls-la2-rw-rw-r--u0_a1181702016-04-2316:51key.xmlCopied!PleasenotethatMODE_WORLD_READABLEandMODE_WORLD_WRITEABLEweredeprecatedstartingonAPIlevel17.Althoughnewerdevicesmaynotbeaffectedbythis,applicationscompiledwithanandroid:targetSdkVersionvaluelessthan17maybeaffectediftheyrunonanOSversionthatwasreleasedbeforeAndroid4.2(APIlevel17).DatabasesTheAndroidplatformprovidesanumberofdatabaseoptionsasaforementionedinthepreviouslist.Eachdatabaseoptionhasitsownquirksandmethodsthatneedtobeunderstood.SQLiteDatabase(Unencrypted)SQLiteisanSQLdatabaseenginethatstoresdatain.dbfiles.TheAndroidSDKhasbuilt-insupportforSQLitedatabases.Themainpackageusedtomanagethedatabasesisandroid.database.sqlite.Forexample,youmayusethefollowingcodetostoresensitiveinformationwithinanactivity:ExampleinJava:1SQLiteDatabasenotSoSecure=openOrCreateDatabase("privateNotSoSecure",MODE_PRIVATE,null);2notSoSecure.execSQL("CREATETABLEIFNOTEXISTSAccounts(UsernameVARCHAR,PasswordVARCHAR);");3notSoSecure.execSQL("INSERTINTOAccountsVALUES('admin','AdminPass');");4notSoSecure.close();Copied!ExampleinKotlin:1varnotSoSecure=openOrCreateDatabase("privateNotSoSecure",Context.MODE_PRIVATE,null)2notSoSecure.execSQL("CREATETABLEIFNOTEXISTSAccounts(UsernameVARCHAR,PasswordVARCHAR);")3notSoSecure.execSQL("INSERTINTOAccountsVALUES('admin','AdminPass');")4notSoSecure.close()Copied!Oncetheactivityhasbeencalled,thedatabasefileprivateNotSoSecurewillbecreatedwiththeprovideddataandstoredinthecleartextfile/data/data//databases/privateNotSoSecure.Thedatabase'sdirectorymaycontainseveralfilesbesidestheSQLitedatabase:​Journalfiles:Thesearetemporaryfilesusedtoimplementatomiccommitandrollback.​Lockfiles:Thelockfilesarepartofthelockingandjournalingfeature,whichwasdesignedtoimproveSQLiteconcurrencyandreducethewriterstarvationproblem.SensitiveinformationshouldnotbestoredinunencryptedSQLitedatabases.SQLiteDatabases(Encrypted)WiththelibrarySQLCipher,SQLitedatabasescanbepassword-encrypted.ExampleinJava:1SQLiteDatabasesecureDB=SQLiteDatabase.openOrCreateDatabase(database,"password123",null);2secureDB.execSQL("CREATETABLEIFNOTEXISTSAccounts(UsernameVARCHAR,PasswordVARCHAR);");3secureDB.execSQL("INSERTINTOAccountsVALUES('admin','AdminPassEnc');");4secureDB.close();Copied!ExampleinKotlin:1varsecureDB=SQLiteDatabase.openOrCreateDatabase(database,"password123",null)2secureDB.execSQL("CREATETABLEIFNOTEXISTSAccounts(UsernameVARCHAR,PasswordVARCHAR);")3secureDB.execSQL("INSERTINTOAccountsVALUES('admin','AdminPassEnc');")4secureDB.close()Copied!Securewaystoretrievethedatabasekeyinclude:AskingtheusertodecryptthedatabasewithaPINorpasswordoncetheappisopened(weakpasswordsandPINsarevulnerabletobruteforceattacks)Storingthekeyontheserverandallowingittobeaccessedfromawebserviceonly(sothattheappcanbeusedonlywhenthedeviceisonline)FirebaseReal-timeDatabasesFirebaseisadevelopmentplatformwithmorethan15products,andoneofthemisFirebaseReal-timeDatabase.ItcanbeleveragedbyapplicationdeveloperstostoreandsyncdatawithaNoSQLcloud-hosteddatabase.ThedataisstoredasJSONandissynchronizedinreal-timetoeveryconnectedclientandalsoremainsavailableevenwhentheapplicationgoesoffline.AmisconfiguredFirebaseinstancecanbeidentifiedbymakingthefollowingnetworkcall:https://_firebaseProjectName_.firebaseio.com/.jsonThefirebaseProjectNamecanberetrievedfromthemobileapplicationbyreverseengineeringtheapplication.Alternatively,theanalystscanuseFirebaseScanner,apythonscriptthatautomatesthetaskaboveasshownbelow:1pythonFirebaseScanner.py-p2​3pythonFirebaseScanner.py-fCopied!RealmDatabasesTheRealmDatabaseforJavaisbecomingmoreandmorepopularamongdevelopers.Thedatabaseanditscontentscanbeencryptedwithakeystoredintheconfigurationfile.1//thegetKey()methodeithergetsthekeyfromtheserverorfromaKeyStore,orisderivedfromapassword.2RealmConfigurationconfig=newRealmConfiguration.Builder()3.encryptionKey(getKey())4.build();5​6Realmrealm=Realm.getInstance(config);Copied!Ifthedatabaseisnotencrypted,youshouldbeabletoobtainthedata.Ifthedatabaseisencrypted,determinewhetherthekeyishard-codedinthesourceorresourcesandwhetheritisstoredunprotectedinsharedpreferencesorsomeotherlocation.InternalStorageYoucansavefilestothedevice'sinternalstorage.Filessavedtointernalstoragearecontainerizedbydefaultandcannotbeaccessedbyotherappsonthedevice.Whentheuseruninstallsyourapp,thesefilesareremoved.Thefollowingcodesnippetswouldpersistentlystoresensitivedatatointernalstorage.ExampleforJava:1FileOutputStreamfos=null;2try{3fos=openFileOutput(FILENAME,Context.MODE_PRIVATE);4fos.write(test.getBytes());5fos.close();6}catch(FileNotFoundExceptione){7e.printStackTrace();8}catch(IOExceptione){9e.printStackTrace();10}Copied!ExampleforKotlin:1varfos:FileOutputStream?=null2fos=openFileOutput("FILENAME",Context.MODE_PRIVATE)3fos.write(test.toByteArray(Charsets.UTF_8))4fos.close()Copied!Youshouldcheckthefilemodetomakesurethatonlytheappcanaccessthefile.YoucansetthisaccesswithMODE_PRIVATE.ModessuchasMODE_WORLD_READABLE(deprecated)andMODE_WORLD_WRITEABLE(deprecated)mayposeasecurityrisk.SearchfortheclassFileInputStreamtofindoutwhichfilesareopenedandreadwithintheapp.ExternalStorageEveryAndroid-compatibledevicesupportssharedexternalstorage.Thisstoragemayberemovable(suchasanSDcard)orinternal(non-removable).Filessavedtoexternalstorageareworld-readable.TheusercanmodifythemwhenUSBmassstorageisenabled.Youcanusethefollowingcodesnippetstopersistentlystoresensitiveinformationtoexternalstorageasthecontentsofthefilepassword.txt.ExampleforJava:1Filefile=newFile(Environment.getExternalFilesDir(),"password.txt");2Stringpassword="SecretPassword";3FileOutputStreamfos;4fos=newFileOutputStream(file);5fos.write(password.getBytes());6fos.close();Copied!ExampleforKotlin:1valpassword="SecretPassword"2valpath=context.getExternalFilesDir(null)3valfile=File(path,"password.txt")4file.appendText(password)Copied!Thefilewillbecreatedandthedatawillbestoredinacleartextfileinexternalstorageoncetheactivityhasbeencalled.It'salsoworthknowingthatfilesstoredoutsidetheapplicationfolder(data/data//)willnotbedeletedwhentheuseruninstallstheapplication.Finally,it'sworthnotingthattheexternalstoragecanbeusedbyanattackertoallowforarbitrarycontroloftheapplicationinsomecases.Formoreinformation:seetheblogfromCheckpoint.KeyStoreTheAndroidKeyStoresupportsrelativelysecurecredentialstorage.AsofAndroid4.3(APIlevel18),itprovidespublicAPIsforstoringandusingapp-privatekeys.Anappcanuseapublickeytocreateanewprivate/publickeypairforencryptingapplicationsecrets,anditcandecryptthesecretswiththeprivatekey.YoucanprotectkeysstoredintheAndroidKeyStorewithuserauthenticationinaconfirmcredentialflow.Theuser'slockscreencredentials(pattern,PIN,password,orfingerprint)areusedforauthentication.Youcanusestoredkeysinoneoftwomodes:1.Usersareauthorizedtousekeysforalimitedperiodoftimeafterauthentication.Inthismode,allkeyscanbeusedassoonastheuserunlocksthedevice.Youcancustomizetheperiodofauthorizationforeachkey.Youcanusethisoptiononlyifthesecurelockscreenisenabled.Iftheuserdisablesthesecurelockscreen,allstoredkeyswillbecomepermanentlyinvalid.2.Usersareauthorizedtouseaspecificcryptographicoperationthatisassociatedwithonekey.Inthismode,usersmustrequestaseparateauthorizationforeachoperationthatinvolvesthekey.Currently,fingerprintauthenticationistheonlywaytorequestsuchauthorization.ThelevelofsecurityaffordedbytheAndroidKeyStoredependsonitsimplementation,whichdependsonthedevice.Mostmoderndevicesofferahardware-backedKeyStoreimplementation:keysaregeneratedandusedinaTrustedExecutionEnvironment(TEE)oraSecureElement(SE),andtheoperatingsystemcan'taccessthemdirectly.Thismeansthattheencryptionkeysthemselvescan'tbeeasilyretrieved,evenfromarooteddevice.Youcanverifyhardware-backedkeyswithKeyAttestationYoucandeterminewhetherthekeysareinsidethesecurehardwarebycheckingthereturnvalueoftheisInsideSecureHardwaremethod,whichispartoftheKeyInfoclass.NotethattherelevantKeyInfoindicatesthatsecretkeysandHMACkeysareinsecurelystoredonseveraldevicesdespiteprivatekeysbeingcorrectlystoredonthesecurehardware.Thekeysofasoftware-onlyimplementationareencryptedwithaper-userencryptionmasterkey.Anattackercanaccessallkeysstoredonrooteddevicesthathavethisimplementationinthefolder/data/misc/keystore/.Becausetheuser'slockscreenpin/passwordisusedtogeneratethemasterkey,theAndroidKeyStoreisunavailablewhenthedeviceislocked.FormoresecurityAndroid9(APIlevel28)introducestheunlockedDeviceRequiedflag.BypassingtruetothesetUnlockedDeviceRequiredmethodtheapppreventsitskeysstoredinAndroidKeystorefrombeingdecryptedwhenthedeviceislocked,anditrequiresthescreentobeunlockedbeforeallowingdecryption.Hardware-backedAndroidKeyStoreAsmentionedbefore,hardware-backedAndroidKeyStoregivesanotherlayertodefense-in-depthsecurityconceptforAndroid.KeymasterHardwareAbstractionLayer(HAL)wasintroducedwithAndroid6(APIlevel23).Applicationscanverifyifthekeyisstoredinsidethesecurityhardware(bycheckingifKeyInfo.isinsideSecureHardwarereturnstrue).DevicesrunningAndroid9(APIlevel28)andhighercanhaveaStrongBoxKeymastermodule,animplementationoftheKeymasterHALthatresidesinahardwaresecuritymodulewhichhasitsownCPU,Securestorage,atruerandomnumbergeneratorandamechanismtoresistpackagetampering.Tousethisfeature,truemustbepassedtothesetIsStrongBoxBackedmethodineithertheKeyGenParameterSpec.BuilderclassortheKeyProtection.BuilderclasswhengeneratingorimportingkeysusingAndroidKeystore.TomakesurethatStrongBoxisusedduringruntime,checkthatisInsideSecureHardwarereturnstrueandthatthesystemdoesnotthrowStrongBoxUnavailableExceptionwhichgetsthrowniftheStrongBoxKeymasterisn'tavailableforthegivenalgorithmandkeysizeassociatedwithakey.Descriptionoffeaturesonhardware-basedkeystorecanbefoundonAOSPpages.KeymasterHALisaninterfacetohardware-backedcomponents-TrustedExecutionEnvironment(TEE)oraSecureElement(SE),whichisusedbyAndroidKeystore.Anexampleofsuchahardware-backedcomponentisTitanM.KeyAttestationFortheapplicationswhichheavilyrelyonAndroidKeystoreforbusiness-criticaloperationssuchasmulti-factorauthenticationthroughcryptographicprimitives,securestorageofsensitivedataattheclient-side,etc.AndroidprovidesthefeatureofKeyAttestationwhichhelpstoanalyzethesecurityofcryptographicmaterialmanagedthroughAndroidKeystore.FromAndroid8.0(APIlevel26),thekeyattestationwasmademandatoryforallnew(Android7.0orhigher)devicesthatneedtohavedevicecertificationforGoogleapps.SuchdevicesuseattestationkeyssignedbytheGooglehardwareattestationrootcertificateandthesamecanbeverifiedthroughthekeyattestationprocess.Duringkeyattestation,wecanspecifythealiasofakeypairandinreturn,getacertificatechain,whichwecanusetoverifythepropertiesofthatkeypair.IftherootcertificateofthechainistheGoogleHardwareAttestationRootcertificateandthechecksrelatedtokeypairstorageinhardwarearemadeitgivesanassurancethatthedevicesupportshardware-levelkeyattestationandthekeyisinthehardware-backedkeystorethatGooglebelievestobesecure.Alternatively,iftheattestationchainhasanyotherrootcertificate,thenGoogledoesnotmakeanyclaimsaboutthesecurityofthehardware.Althoughthekeyattestationprocesscanbeimplementedwithintheapplicationdirectlybutitisrecommendedthatitshouldbeimplementedattheserver-sideforsecurityreasons.Thefollowingarethehigh-levelguidelinesforthesecureimplementationofKeyAttestation:TheservershouldinitiatethekeyattestationprocessbycreatingarandomnumbersecurelyusingCSPRNG(CryptographicallySecureRandomNumberGenerator)andthesameshouldbesenttotheuserasachallenge.TheclientshouldcallthesetAttestationChallengeAPIwiththechallengereceivedfromtheserverandshouldthenretrievetheattestationcertificatechainusingtheKeyStore.getCertificateChainmethod.Theattestationresponseshouldbesenttotheserverfortheverificationandfollowingchecksshouldbeperformedfortheverificationofthekeyattestationresponse:Verifythecertificatechain,uptotherootandperformcertificatesanitycheckssuchasvalidity,integrityandtrustworthiness.ChecktheCertificateRevocationStatusListmaintainedbyGoogle,ifnoneofthecertificatesinthechainwasrevoked.CheckiftherootcertificateissignedwiththeGoogleattestationrootkeywhichmakestheattestationprocesstrustworthy.Extracttheattestationcertificateextensiondata,whichappearswithinthefirstelementofthecertificatechainandperformthefollowingchecks:Verifythattheattestationchallengeishavingthesamevaluewhichwasgeneratedattheserverwhileinitiatingtheattestationprocess.Verifythesignatureinthekeyattestationresponse.VerifythesecurityleveloftheKeymastertodetermineifthedevicehassecurekeystoragemechanism.Keymasterisapieceofsoftwarethatrunsinthesecuritycontextandprovidesallthesecurekeystoreoperations.ThesecuritylevelwillbeoneofSoftware,TrustedEnvironmentorStrongBox.Theclientsupportshardware-levelkeyattestationifsecuritylevelisTrustedEnvironmentorStrongBoxandattestationcertificatechaincontainsarootcertificatesingedwithGoogleattestationrootkey.Verifyclient'sstatustoensurefullchainoftrust-verifiedbootkey,lockedbootloaderandverifiedbootstate.Additionally,youcanverifythekeypair'sattributessuchaspurpose,accesstime,authenticationrequirement,etc.Note,ifforanyreasonthatprocessfails,itmeansthatthekeyisnotinsecurityhardware.Thatdoesnotmeanthatthekeyiscompromised.ThetypicalexampleofAndroidKeystoreattestationresponselookslikethis:1{2"fmt":"android-key",3"authData":"9569088f1ecee3232954035dbd10d7cae391305a2751b559bb8fd7cbb229bd...",4"attStmt":{5"alg":-7,6"sig":"304402202ca7a8cfb6299c4a073e7e022c57082a46c657e9e53...",7"x5c":[8"308202ca30820270a003020102020101300a06082a8648ce3d040302308188310b30090603550406130...",9"308202783082021ea00302010202021001300a06082a8648ce3d040302308198310b300906035504061...",10"3082028b30820232a003020102020900a2059ed10e435b57300a06082a8648ce3d040302308198310b3..."11]12}13}Copied!IntheaboveJSONsnippet,thekeyshavethefollowingmeaning:fmt:AttestationstatementformatidentifierauthData:Itdenotestheauthenticatordatafortheattestationalg:ThealgorithmthatisusedfortheSignaturesig:Signaturex5c:AttestationcertificatechainNote:ThesigisgeneratedbyconcatenatingauthDataandclientDataHash(challengesentbytheserver)andsigningthroughthecredentialprivatekeyusingthealgsigningalgorithmandthesameisverifiedattheserver-sidebyusingthepublickeyinthefirstcertificate.Formoreunderstandingontheimplementationguidelines,GoogleSampleCodecanbereferred.ForthesecurityanalysisperspectivetheanalystsmayperformthefollowingchecksforthesecureimplementationofKeyAttestation:Checkifthekeyattestationistotallyimplementedattheclient-side.Insuchscenario,thesamecanbeeasilybypassedbytamperingtheapplication,methodhooking,etc.Checkiftheserverusesrandomchallengewhileinitiatingthekeyattestation.Asfailingtodothatwouldleadtoinsecureimplementationthusmakingitvulnerabletoreplayattacks.Also,checkspertainingtotherandomnessofthechallengeshouldbeperformed.Checkiftheserververifiestheintegrityofkeyattestationresponse.Checkiftheserverperformsbasiccheckssuchasintegrityverification,trustverification,validity,etc.onthecertificatesinthechain.SecureKeyImportintoKeystoreAndroid9(APIlevel28)addstheabilitytoimportkeyssecurelyintotheAndroidKeystore.FirstAndroidKeystoregeneratesakeypairusingPURPOSE_WRAP_KEYwhichshouldalsobeprotectedwithanattestationcertificate,thispairaimstoprotecttheKeysbeingimportedtoAndroidKeystore.TheencryptedkeysaregeneratedasASN.1-encodedmessageintheSecureKeyWrapperformatwhichalsocontainsadescriptionofthewaystheimportedkeyisallowedtobeused.ThekeysarethendecryptedinsidetheAndroidKeystorehardwarebelongingtothespecificdevicethatgeneratedthewrappingkeysotheyneverappearasplaintextinthedevice'shostmemory.​​ExampleinJava:1KeyDescription::=SEQUENCE{2keyFormatINTEGER,3authorizationListAuthorizationList4}5​6SecureKeyWrapper::=SEQUENCE{7wrapperFormatVersionINTEGER,8encryptedTransportKeyOCTET_STRING,9initializationVectorOCTET_STRING,10keyDescriptionKeyDescription,11secureKeyOCTET_STRING,12tagOCTET_STRING13}Copied!ThecodeabovepresentthedifferentparameterstobesetwhengeneratingtheencryptedkeysintheSecureKeyWrapperformat.ChecktheAndroiddocumentationonWrappedKeyEntryformoredetails.WhendefiningtheKeyDescriptionAuthorizationList,thefollowingparameterswillaffecttheencryptedkeyssecurity:ThealgorithmparameterSpecifiesthecryptographicalgorithmwithwhichthekeyisusedThekeySizeparameterSpecifiesthesize,inbits,ofthekey,measuringinthenormalwayforthekey'salgorithmThedigestparameterSpecifiesthedigestalgorithmsthatmaybeusedwiththekeytoperformsigningandverificationoperationsOlderKeyStoreImplementationsOlderAndroidversionsdon'tincludeKeyStore,buttheydoincludetheKeyStoreinterfacefromJCA(JavaCryptographyArchitecture).YoucanuseKeyStoresthatimplementthisinterfacetoensurethesecrecyandintegrityofkeysstoredwithKeyStore;BouncyCastleKeyStore(BKS)isrecommended.Allimplementationsarebasedonthefactthatfilesarestoredonthefilesystem;allfilesarepassword-protected.Tocreateone,youcanusetheKeyStore.getInstance("BKS","BC")method,where"BKS"istheKeyStorename(BouncyCastleKeystore)and"BC"istheprovider(BouncyCastle).YoucanalsouseSpongyCastleasawrapperandinitializetheKeyStoreasfollows:KeyStore.getInstance("BKS","SC").BeawarethatnotallKeyStoresproperlyprotectthekeysstoredintheKeyStorefiles.KeyChainTheKeyChainclassisusedtostoreandretrievesystem-wideprivatekeysandtheircorrespondingcertificates(chain).TheuserwillbepromptedtosetalockscreenpinorpasswordtoprotectthecredentialstorageifsomethingisbeingimportedintotheKeyChainforthefirsttime.NotethattheKeyChainissystem-wide,everyapplicationcanaccessthematerialsstoredintheKeyChain.InspectthesourcecodetodeterminewhethernativeAndroidmechanismsidentifysensitiveinformation.Sensitiveinformationshouldbeencrypted,notstoredincleartext.Forsensitiveinformationthatmustbestoredonthedevice,severalAPIcallsareavailabletoprotectthedataviatheKeyChainclass.Completethefollowingsteps:MakesurethattheappisusingtheAndroidKeyStoreandCiphermechanismstosecurelystoreencryptedinformationonthedevice.LookforthepatternsAndroidKeystore,importjava.security.KeyStore,importjavax.crypto.Cipher,importjava.security.SecureRandom,andcorrespondingusages.Usethestore(OutputStreamstream,char[]password)functiontostoretheKeyStoretodiskwithapassword.Makesurethatthepasswordisprovidedbytheuser,nothard-coded.StoringaKey-exampleTomitigateunauthorizeduseofkeysontheAndroiddevice,AndroidKeyStoreletsappsspecifyauthorizedusesoftheirkeyswhengeneratingorimportingthekeys.Oncemade,authorizationscannotbechanged.StoringaKey-frommostsecuretoleastsecure:thekeyisstoredinhardware-backedAndroidKeyStoreallkeysarestoredonserverandareavailableafterstrongauthenticationmasterkeyisstoredonserverandusetoencryptotherkeys,whicharestoredinAndroidSharedPreferencesthekeyisderivedeachtimefromastronguserprovidedpassphrasewithsufficientlengthandsaltthekeyisstoredinsoftwareimplementationofAndroidKeyStoremasterkeyisstoredinsoftwareimplementationofAndroidKeystoreandusetoencryptotherkeys,whicharestoredinSharedPreferences[notrecommended]allkeysarestoredinSharedPreferences[notrecommended]hardcodedencryptionkeysinthesourcecode[notrecommended]predictablekeyderivationfunctionbasedonstableattributes[notrecommended]storedgeneratedkeysinpublicplaces(like/sdcard/)Themostsecurewayofhandlingkeymaterial,issimplyneverstoringitonthedevice.Thatcanbeachievedbyusinghardware-backedAndroidKeyStoreifdeviceisrunningAndroid7.0(APIlevel24)andabovewithavailablehardwarecomponent(TrustedExecutionEnvironment(TEE)oraSecureElement(SE)).ThatcanbecheckbyusingguidelinesprovidedforthesecureimplementationofKeyAttestation.Ifhardwarecomponentisnotavailableand/orsupportforAndroid6.0(APIlevel23)andbelowisrequired,thenthatcanbeachievedbystoringakeyonremoteserverandmakeakeyavailableafterauthentication.Pleasenotethatifthekeysarestoredontheserver,theappneedtobeonlinetodecryptthedata.Thismightbealimitationinsomeusecaseofmobileappsandshouldbecarefullythoughtthroughasthisbecomespartofthearchitectureoftheapp.Amorecommonsolution(regardingAndroidAPIlevel),howeverless-userfriendlyandwithsomeweaknessesistoderiveakeyfromuserprovidedpassphrase.Thismeansthattheusershouldbepromptedtoinputapassphraseeverytimetheapplicationneedstoperformacryptographicoperation.Thisisnottheidealimplementationfromauserpointofviewandpasswordsorpass-phrasesmightbereusedbytheuseroreasytoguess.Howeverthisapproachmakesakeyavailableinanarrayinmemorywhileitisbeingusedandwhenthekeyisnotneededanymore,thearraycanbezeroedout.Thislimitstheavailablewaysofattacksonakeyasnokeymaterialanditsartifacts(likeapassphrase)touchthefilesystemandtheyarenotstored.Howevertherearesomeweaknesseswhichneedtobetakenintoconsideration.Firstofall,akeyderivedfrompassphrasehasitsownweaknesses.Additionally,thekeymaterialshouldbeclearedoutfrommemoryassoonasitisnotneedanymore.However,notethatsomeciphersdonotproperlycleanuptheirbyte-arrays.Forinstance,theAESCipherinBouncyCastledoesnotalwayscleanupitslatestworkingkeyleavingsomecopiesofthebyte-arrayinmemory.Next,BigIntegerbasedkeys(e.g.privatekeys)cannotberemovedfromtheheapnorzeroedoutjustlikethat.ClearingbytearraycanbeachievedbywritingawrapperwhichimplementsDestroyable.Moreuser-friendlyandrecommendedwayistousetheAndroidKeyStoreAPIsystem(itselforthroughKeyChain)tostorekeymaterial.Ifitispossible,hardware-backedstorageshouldbeused.Otherwise,itshouldfallbacktosoftwareimplementationofAndroidKeystore.However,beawarethattheAndroidKeyStoreAPIhasbeenchangedsignificantlythroughoutvariousversionsofAndroid.Inearlierversions,theAndroidKeyStoreAPIonlysupportedstoringpublic/privatekeypairs(e.g.,RSA).SymmetrickeysupporthasonlybeenaddedsinceAndroid6.0(APIlevel23).Asaresult,adeveloperneedstohandlethedifferentAndroidAPIlevelstosecurelystoresymmetrickeys.InordertosecurelystoresymmetrickeysondevicesrunningonAndroid5.1(APIlevel22)orlower,weneedtogenerateapublic/privatekeypair.WeencryptthesymmetrickeyusingthepublickeyandstoretheprivatekeyintheAndroidKeyStore.Theencryptedsymmetrickeycanencodedusingbase64andstoredintheSharedPreferences.Wheneverweneedthesymmetrickey,theapplicationretrievestheprivatekeyfromtheAndroidKeyStoreanddecryptsthesymmetrickey.Alesssecurewayofstoringencryptionkeys,isintheSharedPreferencesofAndroid.WhenSharedPreferencesareused,thefileisonlyreadablebytheapplicationthatcreatedit.However,onrooteddevicesanyotherapplicationwithrootaccesscansimplyreadtheSharedPreferencefileofotherapps.ThisisnotthecasefortheAndroidKeyStore.SinceAndroidKeyStoreaccessismanagedonkernellevel,whichneedsconsiderablymoreworkandskilltobypasswithouttheAndroidKeyStoreclearingordestroyingthekeys.Thelastthreeoptionsaretousehardcodedencryptionkeysinthesourcecode,havingapredictablekeyderivationfunctionbasedonstableattributes,andstoringgeneratedkeysinpublicplaceslike/sdcard/.Obviously,hardcodedencryptionkeysarenotthewaytogo.Thismeanseveryinstanceoftheapplicationusesthesameencryptionkey.Anattackerneedsonlytodotheworkonce,toextractthekeyfromthesourcecode-whetherstorednativelyorinJava/Kotlin.Consequently,anattackercandecryptanyotherdatawhichwasencryptedbytheapplication.Next,whenyouhaveapredictablekeyderivationfunctionbasedonidentifierswhichareaccessibletootherapplications,theattackeronlyneedstofindtheKDFandapplyittothedeviceinordertofindthekey.Lastly,storingencryptionkeyspubliclyalsoishighlydiscouragedasotherapplicationscanhavepermissiontoreadthepublicpartitionandstealthekeys.ThirdPartylibrariesThereareseveraldifferentopen-sourcelibrariesthatofferencryptioncapabilitiesspecificfortheAndroidplatform.​JavaAESCrypto-AsimpleAndroidclassforencryptinganddecryptingstrings.​SQLCipher-SQLCipherisanopensourceextensiontoSQLitethatprovidestransparent256-bitAESencryptionofdatabasefiles.​SecurePreferences-AndroidSharedpreferencewrapperthanencryptsthekeysandvaluesofSharedPreferences.PleasekeepinmindthataslongasthekeyisnotstoredintheKeyStore,itisalwayspossibletoeasilyretrievethekeyonarooteddeviceandthendecryptthevaluesyouaretryingtoprotect.LogsTherearemanylegitimatereasonstocreatelogfilesonamobiledevice,suchaskeepingtrackofcrashes,errors,andusagestatistics.Logfilescanbestoredlocallywhentheappisofflineandsenttotheendpointoncetheappisonline.However,loggingsensitivedatamayexposethedatatoattackersormaliciousapplications,anditmightalsoviolateuserconfidentiality.Youcancreatelogfilesinseveralways.ThefollowinglistincludestwoclassesthatareavailableforAndroid:​LogClass​​LoggerClass​BackupsAndroidprovidesuserswithanauto-backupfeature.Thebackupsusuallyincludecopiesofdataandsettingsforallinstalledapps.Givenitsdiverseecosystem,Androidsupportsmanybackupoptions:StockAndroidhasbuilt-inUSBbackupfacilities.WhenUSBdebuggingisenabled,youcanusetheadbbackupcommandtocreatefulldatabackupsandbackupsofanapp'sdatadirectory.Googleprovidesa"BackUpMyData"featurethatbacksupallappdatatoGoogle'sservers.TwoBackupAPIsareavailabletoappdevelopers:​Key/ValueBackup(BackupAPIorAndroidBackupService)uploadstotheAndroidBackupServicecloud.​AutoBackupforApps:WithAndroid6.0(APIlevel23)andabove,Googleaddedthe"AutoBackupforAppsfeature".Thisfeatureautomaticallysyncsatmost25MBofappdatawiththeuser'sGoogleDriveaccount.OEMsmayprovideadditionaloptions.Forexample,HTCdeviceshavea"HTCBackup"optionthatperformsdailybackupstothecloudwhenactivated.Appsmustcarefullyensurethatsensitiveuserdatadoesn'tendwithinthesebackupsasthismayallowanattackertoextractit.ProcessMemoryAllapplicationsonAndroidusememorytoperformnormalcomputationaloperationslikeanyregularmodern-daycomputer.Itisofnosurprisethenthatattimessensitiveoperationswillbeperformedwithinprocessmemory.Forthisreason,itisimportantthatoncetherelevantsensitivedatahasbeenprocessed,itshouldbedisposedfromprocessmemoryasquicklyaspossible.Theinvestigationofanapplication'smemorycanbedonefrommemorydumps,andfromanalyzingthememoryinrealtimeviaadebugger.Thisisfurtherexplainedinthe'CheckingMemoryforSensitiveData'section.TestingLocalStorageforSensitiveData(MSTG-STORAGE-1andMSTG-STORAGE-2)OverviewThistestcasefocusesonidentifyingpotentiallysensitivedatastoredbyanapplicationandverifyingifitissecurelystored.Thefollowingchecksshouldbeperformed:Analyzedatastorageinthesourcecode.Besuretotriggerallpossiblefunctionalityintheapplication(e.g.byclickingeverywherepossible)inordertoensuredatageneration.Checkallapplicationgeneratedandmodifiedfilesandensurethatthestoragemethodissufficientlysecure.ThisincludesSharedPreferences,SQLdatabases,RealmDatabases,InternalStorage,ExternalStorage,etc.Ingeneralsensitivedatastoredlocallyonthedeviceshouldalwaysbeatleastencrypted,andanykeysusedforencryptionmethodsshouldbesecurelystoredwithintheAndroidKeystore.Thesefilesshouldalsobestoredwithintheapplicationsandbox.Ifachievablefortheapplication,sensitivedatashouldbestoredoffdeviceor,evenbetter,notstoredatall.StaticAnalysisFirstofall,trytodeterminethekindofstorageusedbytheAndroidappandtofindoutwhethertheappprocessessensitivedatainsecurely.CheckAndroidManifest.xmlforread/writeexternalstoragepermissions,forexample,uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE".CheckthesourcecodeforkeywordsandAPIcallsthatareusedtostoredata:Filepermissions,suchas:MODE_WORLD_READABLEorMODE_WORLD_WRITABLE:YoushouldavoidusingMODE_WORLD_WRITEABLEandMODE_WORLD_READABLEforfilesbecauseanyappwillbeabletoreadfromorwritetothefiles,eveniftheyarestoredintheapp'sprivatedatadirectory.Ifdatamustbesharedwithotherapplications,consideracontentprovider.Acontentprovideroffersreadandwritepermissionstootherappsandcangrantdynamicpermissiononacase-by-casebasis.Classesandfunctions,suchas:theSharedPreferencesclass(storeskey-valuepairs)theFileOutPutStreamclass(usesinternalorexternalstorage)thegetExternal*functions(useexternalstorage)thegetWritableDatabasefunction(returnsaSQLiteDatabaseforwriting)thegetReadableDatabasefunction(returnsaSQLiteDatabaseforreading)thegetCacheDirandgetExternalCacheDirsfunction(usecachedfiles)EncryptionshouldbeimplementedusingprovenSDKfunctions.Thefollowingdescribesbadpracticestolookforinthesourcecode:Locallystoredsensitiveinformation"encrypted"viasimplebitoperationslikeXORorbitflipping.Theseoperationsshouldbeavoidedbecausetheencrypteddatacanberecoveredeasily.KeysusedorcreatedwithoutAndroidonboardfeatures,suchastheAndroidKeyStoreKeysdisclosedbyhard-codingAtypicalmisusearehard-codedcryptographickeys.Hard-codedandworld-readablecryptographickeyssignificantlyincreasethepossibilitythatencrypteddatawillberecovered.Onceanattackerobtainsthedata,decryptingitistrivial.Symmetriccryptographykeysmustbestoredonthedevice,soidentifyingthemisjustamatteroftimeandeffort.Considerthefollowingcode:1this.db=localUserSecretStore.getWritableDatabase("SuperPassword123");Copied!Obtainingthekeyistrivialbecauseitiscontainedinthesourcecodeandidenticalforallinstallationsoftheapp.Encryptingdatathiswayisnotbeneficial.Lookforhard-codedAPIkeys/privatekeysandothervaluabledata;theyposeasimilarrisk.Encoded/encryptedkeysrepresentanotherattempttomakeitharderbutnotimpossibletogetthecrownjewels.Considerthefollowingcode:ExampleinJava:1//AmorecomplicatedefforttostoretheXOR'edhalvesofakey(insteadofthekeyitself)2privatestaticfinalString[]myCompositeKey=newString[]{3"oNQavjbaNNSgEqoCkT9Em4imeQQ=","3o8eFOX4ri/F8fgHgiy/BS47"4};Copied!ExampleinKotlin:1privatevalmyCompositeKey=arrayOf("oNQavjbaNNSgEqoCkT9Em4imeQQ=","3o8eFOX4ri/F8fgHgiy/BS47")Copied!Thealgorithmfordecodingtheoriginalkeymightbesomethinglikethis:ExampleinJava:1publicvoiduseXorStringHiding(StringmyHiddenMessage){2byte[]xorParts0=Base64.decode(myCompositeKey[0],0);3byte[]xorParts1=Base64.decode(myCompositeKey[1],0);4​5byte[]xorKey=newbyte[xorParts0.length];6for(inti=0;i2SuperApp3Helloworld!4Settings5My_Secret_Key6Copied!buildconfigs,suchasinlocal.propertiesorgradle.propertiesExample:1buildTypes{2debug{3minifyEnabledtrue4buildConfigField"String","hiddenPassword","\"${hiddenPassword}\""5}6}Copied!DynamicAnalysisInstallandusetheapp,executingallfunctionsatleastonce.Datacanbegeneratedwhenenteredbytheuser,sentbytheendpoint,orshippedwiththeapp.Thencompletethefollowing:Checkbothinternalandexternallocalstorageforanyfilescreatedbytheapplicationthatcontainsensitivedata.Identifydevelopmentfiles,backupfiles,andoldfilesthatshouldn'tbeincludedwithaproductionrelease.DeterminewhetherSQLitedatabasesareavailableandwhethertheycontainsensitiveinformation.SQLitedatabasesarestoredin/data/data//databases.IdentifyifSQLitedatabasesareencrypted.Ifso,determinehowthedatabasepasswordisgeneratedandstoredandifthisissufficientlyprotectedasdescribedinthe"StoringaKey"sectionoftheKeystoreoverview.CheckSharedPreferencesthatarestoredasXMLfiles(in/data/data//shared_prefs)forsensitiveinformation.SharedPreferencesareinsecureandunencryptedbydefault.Someappsmightopttousesecure-preferencestoencryptthevaluesstoredinSharedPreferences.Checkthepermissionsofthefilesin/data/data/.Onlytheuserandgroupcreatedwhenyouinstalledtheapp(e.g.,u0_a82)shouldhaveuserread,write,andexecutepermissions(rwx).Otherusersshouldnothavepermissiontoaccessfiles,buttheymayhaveexecutepermissionsfordirectories.CheckfortheusageofanyFirebaseReal-timedatabasesandattempttoidentifyiftheyaremisconfiguredbymakingthefollowingnetworkcall:https://_firebaseProjectName_.firebaseio.com/.jsonDeterminewhetheraRealmdatabaseisavailablein/data/data//files/,whetheritisunencrypted,andwhetheritcontainssensitiveinformation.Bydefault,thefileextensionisrealmandthefilenameisdefault.InspecttheRealmdatabasewiththeRealmBrowser.TestingLocalStorageforInputValidation(MSTG-PLATFORM-2)OverviewForanypubliclyaccessibledatastorage,anyprocesscanoverridethedata.Thismeansthatinputvalidationneedstobeappliedthemomentthedataisreadbackagain.Note:SimilarholdsforprivateaccessibledataonarooteddeviceStaticanalysisUsingSharedPreferencesWhenyouusetheSharedPreferences.Editortoreadorwriteint/boolean/longvalues,youcannotcheckwhetherthedataisoverriddenornot.However:itcanhardlybeusedforactualattacksotherthanchainingthevalues(e.g.noadditionalexploitscanbepackedwhichwilltakeoverthecontrolflow).InthecaseofaStringoraStringSetyoushouldbecarefulwithhowthedataisinterpreted.Usingreflectionbasedpersistence?Checkthesectionon"TestingObjectPersistence"forAndroidtoseehowitshouldbevalidated.UsingtheSharedPreferences.Editortostoreandreadcertificatesorkeys?MakesureyouhavepatchedyoursecurityprovidergivenvulnerabilitiessuchasfoundinBouncyCastle.Inallcases,havingthecontentHMACedcanhelptoensurethatnoadditionsand/orchangeshavebeenapplied.UsingOtherStorageMechanismsIncaseotherpublicstoragemechanisms(thantheSharedPreferences.Editor)areused,thedataneedstobevalidatedthemomentitisreadfromthestoragemechanism.TestingLogsforSensitiveData(MSTG-STORAGE-3)OverviewThistestcasefocusesonidentifyinganysensitiveapplicationdatawithinbothsystemandapplicationlogs.Thefollowingchecksshouldbeperformed:Analyzesourcecodeforloggingrelatedcode.Checkapplicationdatadirectoryforlogfiles.Gathersystemmessagesandlogsandanalyzeforanysensitivedata.Asageneralrecommendationtoavoidpotentialsensitiveapplicationdataleakage,loggingstatementsshouldberemovedfromproductionreleasesunlessdeemednecessarytotheapplicationorexplicitlyidentifiedassafe,e.g.asaresultofasecurityaudit.StaticAnalysisApplicationswilloftenusetheLogClassandLoggerClasstocreatelogs.Todiscoverthis,youshouldaudittheapplication'ssourcecodeforanysuchloggingclasses.Thesecanoftenbefoundbysearchingforthefollowingkeywords:Functionsandclasses,suchas:android.util.LogLog.d|Log.e|Log.i|Log.v|Log.w|Log.wtfLoggerKeywordsandsystemoutput:System.out.print|System.err.printlogfilelogginglogsWhilepreparingtheproductionrelease,youcanusetoolslikeProGuard(includedinAndroidStudio).Todeterminewhetherallloggingfunctionsfromtheandroid.util.Logclasshavebeenremoved,checktheProGuardconfigurationfile(proguard-rules.pro)forthefollowingoptions(accordingtothisexampleofremovingloggingcodeandthisarticleaboutenablingProGuardinanAndroidStudioproject):1-assumenosideeffectsclassandroid.util.Log2{3publicstaticbooleanisLoggable(java.lang.String,int);4publicstaticintv(...);5publicstaticinti(...);6publicstaticintw(...);7publicstaticintd(...);8publicstaticinte(...);9publicstaticintwtf(...);10}Copied!NotethattheexampleaboveonlyensuresthatcallstotheLogclass'methodswillberemoved.Ifthestringthatwillbeloggedisdynamicallyconstructed,thecodethatconstructsthestringmayremaininthebytecode.Forexample,thefollowingcodeissuesanimplicitStringBuildertoconstructthelogstatement:ExampleinJava:1Log.v("Privatekeytag","Privatekey[byteformat]:"+key);Copied!ExampleinKotlin:1Log.v("Privatekeytag","Privatekey[byteformat]:$key")Copied!Thecompiledbytecode,however,isequivalenttothebytecodeofthefollowinglogstatement,whichconstructsthestringexplicitly:ExampleinJava:1Log.v("Privatekeytag",newStringBuilder("Privatekey[byteformat]:").append(key.toString()).toString());Copied!ExampleinKotlin:1Log.v("Privatekeytag",StringBuilder("Privatekey[byteformat]:").append(key).toString())Copied!ProGuardguaranteesremovaloftheLog.vmethodcall.Whethertherestofthecode(newStringBuilder...)willberemoveddependsonthecomplexityofthecodeandtheProGuardversion.Thisisasecurityriskbecausethe(unused)stringleaksplaintextdataintomemory,whichcanbeaccessedviaadebuggerormemorydumping.Unfortunately,nosilverbulletexistsforthisissue,butoneoptionwouldbetoimplementacustomloggingfacilitythattakessimpleargumentsandconstructsthelogstatementsinternally.1SecureLog.v("Privatekey[byteformat]:",key);Copied!ThenconfigureProGuardtostripitscalls.DynamicAnalysisUseallthemobileappfunctionsatleastonce,thenidentifytheapplication'sdatadirectoryandlookforlogfiles(/data/data/).Checktheapplicationlogstodeterminewhetherlogdatahasbeengenerated;somemobileapplicationscreateandstoretheirownlogsinthedatadirectory.ManyapplicationdevelopersstilluseSystem.out.printlnorprintStackTraceinsteadofaproperloggingclass.Therefore,yourtestingstrategymustincludealloutputgeneratedwhiletheapplicationisstarting,runningandclosing.TodeterminewhatdataisdirectlyprintedbySystem.out.printlnorprintStackTrace,youcanuseLogcatasexplainedinthechapter"BasicSecurityTesting",section"MonitoringSystemLogs".RememberthatyoucantargetaspecificappbyfilteringtheLogcatoutputasfollows:1$adblogcat|grep"$(adbshellps|grep|awk'{print$2}')"Copied!IfyoualreadyknowtheappPIDyoumaygiveitdirectlyusing--pidflag.Youmayalsowanttoapplyfurtherfiltersorregularexpressions(usinglogcat'sregexflags-e,--regex=forexample)ifyouexpectcertainstringsorpatternstocomeupinthelogs.DeterminingWhetherSensitiveDataIsSharedwithThirdParties(MSTG-STORAGE-4)OverviewSensitiveinformationmightbeleakedtothirdpartiesbyseveralmeans,whichincludebutarenotlimitedtothefollowing:Third-partyServicesEmbeddedintheAppThefeaturestheseservicesprovidecaninvolvetrackingservicestomonitortheuser'sbehaviorwhileusingtheapp,sellingbanneradvertisements,orimprovingtheuserexperience.Thedownsideisthatdevelopersdon'tusuallyknowthedetailsofthecodeexecutedviathird-partylibraries.Consequently,nomoreinformationthanisnecessaryshouldbesenttoaservice,andnosensitiveinformationshouldbedisclosed.Mostthird-partyservicesareimplementedintwoways:withastandalonelibrarywithafullSDKAppNotificationsItisimportanttounderstandthatnotificationsshouldneverbeconsideredprivate.WhenanotificationishandledbytheAndroidsystemitisbroadcastedsystem-wideandanyapplicationrunningwithaNotificationListenerServicecanlistenforthesenotificationstoreceivetheminfullandmayhandlethemhoweveritwants.TherearemanyknownmalwaresamplessuchasJoker,andAlienwhichabusestheNotificationListenerServicetolistenfornotificationsonthedeviceandthensendthemtoattacker-controlledC2infrastructure.Commonlythisisdoneinordertolistenfortwo-factorauthentication(2FA)codesthatappearasnotificationsonthedevicewhicharethensenttotheattacker.Asaferalternativefortheuserwouldbetousea2FAapplicationthatdoesnotgeneratenotifications.FurthermorethereareanumberofappsontheGooglePlayStorethatprovidenotificationlogging,whichbasicallylogslocallyanynotificationsontheAndroidsystem.ThishighlightsthatnotificationsareinnowayprivateonAndroidandaccessiblebyanyotherapponthedevice.Forthisreasonallnotificationusageshouldbeinspectedforconfidentialorhighriskinformationthatcouldbeusedbymaliciousapplications.StaticAnalysisThird-partyServicesEmbeddedintheAppTodeterminewhetherAPIcallsandfunctionsprovidedbythethird-partylibraryareusedaccordingtobestpractices,reviewtheirsourcecode,requestedpermissionsandcheckforanyknownvulnerabilities(see"CheckingforWeaknessesinThirdPartyLibraries(MSTG-CODE-5)").Alldatathat'ssenttothird-partyservicesshouldbeanonymizedtopreventexposureofPII(PersonalIdentifiableInformation)thatwouldallowthethirdpartytoidentifytheuseraccount.Nootherdata(suchasIDsthatcanbemappedtoauseraccountorsession)shouldbesenttoathirdparty.AppNotificationsSearchforanyusageoftheNotificationManagerclasswhichmightbeanindicationofsomeformofnotificationmanagement.Iftheclassisbeingused,thenextstepwouldbetounderstandhowtheapplicationisgeneratingthenotificationsandwhichdataendsupbeingshown.DynamicAnalysisThird-partyServicesEmbeddedintheAppCheckallrequeststoexternalservicesforembeddedsensitiveinformation.Tointercepttrafficbetweentheclientandserver,youcanperformdynamicanalysisbylaunchingaman-in-the-middle(MITM)attackwithBurpSuiteProfessionalorOWASPZAP.Onceyouroutethetrafficthroughtheinterceptionproxy,youcantrytosniffthetrafficthatpassesbetweentheappandserver.Allapprequeststhataren'tsentdirectlytotheserveronwhichthemainfunctionishostedshouldbecheckedforsensitiveinformation,suchasPIIinatrackeroradservice.AppNotificationsRuntheapplicationandstarttracingallcallstofunctionsrelatedtothenotificationscreation,e.g.setContentTitleorsetContentTextfromNotificationCompat.Builder.Observethetraceintheendandevaluateifitcontainsanysensitiveinformationwhichanotherappmighthaveeavesdropped.DeterminingWhethertheKeyboardCacheIsDisabledforTextInputFields(MSTG-STORAGE-5)OverviewWhenuserstypeininputfields,thesoftwareautomaticallysuggestsdata.Thisfeaturecanbeveryusefulformessagingapps.However,thekeyboardcachemaydisclosesensitiveinformationwhentheuserselectsaninputfieldthattakesthistypeofinformation.StaticAnalysisInthelayoutdefinitionofanactivity,youcandefineTextViewsthathaveXMLattributes.IftheXMLattributeandroid:inputTypeisgiventhevaluetextNoSuggestions,thekeyboardcachewillnotbeshownwhentheinputfieldisselected.Theuserwillhavetotypeeverythingmanually.1Copied!ThecodeforallinputfieldsthattakesensitiveinformationshouldincludethisXMLattributetodisablethekeyboardsuggestions.DynamicAnalysisStarttheappandclickintheinputfieldsthattakesensitivedata.Ifstringsaresuggested,thekeyboardcachehasnotbeendisabledforthesefields.DeterminingWhetherSensitiveStoredDataHasBeenExposedviaIPCMechanisms(MSTG-STORAGE-6)OverviewAspartofAndroid'sIPCmechanisms,contentprovidersallowanapp'sstoreddatatobeaccessedandmodifiedbyotherapps.Ifnotproperlyconfigured,thesemechanismsmayleaksensitivedata.StaticAnalysisThefirststepistolookatAndroidManifest.xmltodetectcontentprovidersexposedbytheapp.Youcanidentifycontentprovidersbytheelement.Completethefollowingsteps:Determinewhetherthevalueoftheexporttag(android:exported)is"true".Evenifitisnot,thetagwillbesetto"true"automaticallyifanhasbeendefinedforthetag.Ifthecontentismeanttobeaccessedonlybytheappitself,setandroid:exportedto"false".Ifnot,settheflagto"true"anddefineproperread/writepermissions.Determinewhetherthedataisbeingprotectedbyapermissiontag(android:permission).Permissiontagslimitexposuretootherapps.Determinewhethertheandroid:protectionLevelattributehasthevaluesignature.Thissettingindicatesthatthedataisintendedtobeaccessedonlybyappsfromthesameenterprise(i.e.,signedwiththesamekey).Tomakethedataaccessibletootherapps,applyasecuritypolicywiththeelementandsetaproperandroid:protectionLevel.Ifyouuseandroid:permission,otherapplicationsmustdeclarecorrespondingelementsintheirmanifeststointeractwithyourcontentprovider.Youcanusetheandroid:grantUriPermissionsattributetograntmorespecificaccesstootherapps;youcanlimitaccesswiththeelement.Inspectthesourcecodetounderstandhowthecontentproviderismeanttobeused.Searchforthefollowingkeywords:android.content.ContentProviderandroid.database.Cursorandroid.database.sqlite.query.update.deleteToavoidSQLinjectionattackswithintheapp,useparameterizedquerymethods,suchasquery,update,anddelete.Besuretoproperlysanitizeallmethodarguments;forexample,theselectionargumentcouldleadtoSQLinjectionifitismadeupofconcatenateduserinput.Ifyouexposeacontentprovider,determinewhetherparameterizedquerymethods(query,update,anddelete)arebeingusedtopreventSQLinjection.Ifso,makesurealltheirargumentsareproperlysanitized.WewillusethevulnerablepasswordmanagerappSieveasanexampleofavulnerablecontentprovider.InspecttheAndroidManifestIdentifyalldefinedelements:161112Copied!AsshownintheAndroidManifest.xmlabove,theapplicationexportstwocontentproviders.Notethatonepath("/Keys")isprotectedbyreadandwritepermissions.InspectthesourcecodeInspectthequeryfunctionintheDBContentProvider.javafiletodeterminewhetheranysensitiveinformationisbeingleaked:ExampleinJava:1publicCursorquery(finalUriuri,finalString[]array,finalStrings,finalString[]array2,finalStrings2){2finalintmatch=this.sUriMatcher.match(uri);3finalSQLiteQueryBuildersqLiteQueryBuilder=newSQLiteQueryBuilder();4if(match>=100&&match<200){5sqLiteQueryBuilder.setTables("Passwords");6}7elseif(match>=200){8sqLiteQueryBuilder.setTables("Key");9}10returnsqLiteQueryBuilder.query(this.pwdb.getReadableDatabase(),array,s,array2,(String)null,(String)null,s2);11}Copied!ExampleinKotlin:1funquery(uri:Uri?,array:Array?,s:String?,array2:Array?,s2:String?):Cursor{2valmatch:Int=this.sUriMatcher.match(uri)3valsqLiteQueryBuilder=SQLiteQueryBuilder()4if(match>=100&&match<200){5sqLiteQueryBuilder.tables="Passwords"6}elseif(match>=200){7sqLiteQueryBuilder.tables="Key"8}9returnsqLiteQueryBuilder.query(this.pwdb.getReadableDatabase(),array,s,array2,nullasString?,nullasString?,s2)10}Copied!Hereweseethatthereareactuallytwopaths,"/Keys"and"/Passwords",andthelatterisnotbeingprotectedinthemanifestandisthereforevulnerable.WhenaccessingaURI,thequerystatementreturnsallpasswordsandthepathPasswords/.Wewilladdressthisinthe"DynamicAnalysis"sectionandshowtheexactURIthatisrequired.DynamicAnalysisTestingContentProvidersTodynamicallyanalyzeanapplication'scontentproviders,firstenumeratetheattacksurface:passtheapp'spackagenametotheDrozermoduleapp.provider.info:1dz>runapp.provider.info-acom.mwr.example.sieve2Package:com.mwr.example.sieve3Authority:com.mwr.example.sieve.DBContentProvider4ReadPermission:null5WritePermission:null6ContentProvider:com.mwr.example.sieve.DBContentProvider7MultiprocessAllowed:True8GrantUriPermissions:False9PathPermissions:10Path:/Keys11Type:PATTERN_LITERAL12ReadPermission:com.mwr.example.sieve.READ_KEYS13WritePermission:com.mwr.example.sieve.WRITE_KEYS14Authority:com.mwr.example.sieve.FileBackupProvider15ReadPermission:null16WritePermission:null17ContentProvider:com.mwr.example.sieve.FileBackupProvider18MultiprocessAllowed:True19GrantUriPermissions:FalseCopied!Inthisexample,twocontentprovidersareexported.Bothcanbeaccessedwithoutpermission,exceptforthe/KeyspathintheDBContentProvider.Withthisinformation,youcanreconstructpartofthecontentURIstoaccesstheDBContentProvider(theURIsbeginwithcontent://).ToidentifycontentproviderURIswithintheapplication,useDrozer'sscanner.provider.findurismodule.ThismoduleguessespathsanddeterminesaccessiblecontentURIsinseveralways:1dz>runscanner.provider.finduris-acom.mwr.example.sieve2Scanningcom.mwr.example.sieve...3UnabletoQuerycontent://com.mwr.example.sieve.DBContentProvider/4...5UnabletoQuerycontent://com.mwr.example.sieve.DBContentProvider/Keys6AccessiblecontentURIs:7content://com.mwr.example.sieve.DBContentProvider/Keys/8content://com.mwr.example.sieve.DBContentProvider/Passwords9content://com.mwr.example.sieve.DBContentProvider/Passwords/Copied!Onceyouhavealistofaccessiblecontentproviders,trytoextractdatafromeachproviderwiththeapp.provider.querymodule:1dz>runapp.provider.querycontent://com.mwr.example.sieve.DBContentProvider/Passwords/--vertical2_id:13service:Email4username:incognitoguy505password:PSFjqXIMVa5NJFudgDuuLVgJYFD+8w==(Base64-encoded)6email:[email protected]Copied!YoucanalsouseDrozertoinsert,update,anddeleterecordsfromavulnerablecontentprovider:Insertrecord1dz>runapp.provider.insertcontent://com.vulnerable.im/messages2--stringdate13317638503253--stringtype04--integer_id7Copied!Updaterecord1dz>runapp.provider.updatecontent://settings/secure2--selection"name=?"3--selection-argsassisted_gps_enabled4--integervalue0Copied!Deleterecord1dz>runapp.provider.deletecontent://settings/secure2--selection"name=?"3--selection-argsmy_settingCopied!SQLInjectioninContentProvidersTheAndroidplatformpromotesSQLitedatabasesforstoringuserdata.BecausethesedatabasesarebasedonSQL,theymaybevulnerabletoSQLinjection.YoucanusetheDrozermoduleapp.provider.querytotestforSQLinjectionbymanipulatingtheprojectionandselectionfieldsthatarepassedtothecontentprovider:1dz>runapp.provider.querycontent://com.mwr.example.sieve.DBContentProvider/Passwords/--projection"'"2unrecognizedtoken:"'FROMPasswords"(code1):,whilecompiling:SELECT'FROMPasswords3​4dz>runapp.provider.querycontent://com.mwr.example.sieve.DBContentProvider/Passwords/--selection"'"5unrecognizedtoken:"')"(code1):,whilecompiling:SELECT*FROMPasswordsWHERE(')Copied!IfanapplicationisvulnerabletoSQLInjection,itwillreturnaverboseerrormessage.SQLInjectiononAndroidmaybeusedtomodifyorquerydatafromthevulnerablecontentprovider.Inthefollowingexample,theDrozermoduleapp.provider.queryisusedtolistallthedatabasetables:1dz>runapp.provider.querycontent://com.mwr.example.sieve.DBContentProvider/Passwords/--projection"*2FROMSQLITE_MASTERWHEREtype='table';--"3|type|name|tbl_name|rootpage|sql|4|table|android_metadata|android_metadata|3|CREATETABLE...|5|table|Passwords|Passwords|4|CREATETABLE...|6|table|Key|Key|5|CREATETABLE...|Copied!SQLInjectionmayalsobeusedtoretrievedatafromotherwiseprotectedtables:1dz>runapp.provider.querycontent://com.mwr.example.sieve.DBContentProvider/Passwords/--projection"*FROMKey;--"2|Password|pin|3|thisismypassword|9876|Copied!Youcanautomatethesestepswiththescanner.provider.injectionmodule,whichautomaticallyfindsvulnerablecontentproviderswithinanapp:1dz>runscanner.provider.injection-acom.mwr.example.sieve2Scanningcom.mwr.example.sieve...3InjectioninProjection:4content://com.mwr.example.sieve.DBContentProvider/Keys/5content://com.mwr.example.sieve.DBContentProvider/Passwords6content://com.mwr.example.sieve.DBContentProvider/Passwords/7InjectioninSelection:8content://com.mwr.example.sieve.DBContentProvider/Keys/9content://com.mwr.example.sieve.DBContentProvider/Passwords10content://com.mwr.example.sieve.DBContentProvider/Passwords/Copied!FileSystemBasedContentProvidersContentproviderscanprovideaccesstotheunderlyingfilesystem.Thisallowsappstosharefiles(theAndroidsandboxnormallypreventsthis).YoucanusetheDrozermodulesapp.provider.readandapp.provider.downloadtoreadanddownloadfiles,respectively,fromexportedfile-basedcontentproviders.Thesecontentprovidersaresusceptibletodirectorytraversal,whichallowsotherwiseprotectedfilesinthetargetapplication'ssandboxtoberead.1dz>runapp.provider.downloadcontent://com.vulnerable.app.FileProvider/../../../../../../../../data/data/com.vulnerable.app/database.db/home/user/database.db2Written24488bytesCopied!Usethescanner.provider.traversalmoduletoautomatetheprocessoffindingcontentprovidersthataresusceptibletodirectorytraversal:1dz>runscanner.provider.traversal-acom.mwr.example.sieve2Scanningcom.mwr.example.sieve...3VulnerableProviders:4content://com.mwr.example.sieve.FileBackupProvider/5content://com.mwr.example.sieve.FileBackupProviderCopied!Notethatadbcanalsobeusedtoquerycontentproviders:1$adbshellcontentquery--uricontent://com.owaspomtg.vulnapp.provider.CredentialProvider/credentials2Row:0id=1,username=admin,password=StrongPwd3Row:1id=2,username=test,password=test4...Copied!CheckingforSensitiveDataDisclosureThroughtheUserInterface(MSTG-STORAGE-7)OverviewEnteringsensitiveinformationwhen,forexample,registeringanaccountormakingpayments,isanessentialpartofusingmanyapps.Thisdatamaybefinancialinformationsuchascreditcarddataoruseraccountpasswords.Thedatamaybeexposediftheappdoesn'tproperlymaskitwhileitisbeingtyped.Inordertopreventdisclosureandmitigateriskssuchasshouldersurfingyoushouldverifythatnosensitivedataisexposedviatheuserinterfaceunlessexplicitlyrequired(e.g.apasswordbeingentered).Forthedatarequiredtobepresentitshouldbeproperlymasked,typicallybyshowingasterisksordotsinsteadofcleartext.CarefullyreviewallUIcomponentsthateithershowsuchinformationortakeitasinput.Searchforanytracesofsensitiveinformationandevaluateifitshouldbemaskedorcompletelyremoved.StaticAnalysisTextFieldsTomakesureanapplicationismaskingsensitiveuserinput,checkforthefollowingattributeinthedefinitionofEditText:1android:inputType="textPassword"Copied!Withthissetting,dots(insteadoftheinputcharacters)willbedisplayedinthetextfield,preventingtheappfromleakingpasswordsorpinstotheuserinterface.AppNotificationsWhenstaticallyassessinganapplication,itisrecommendedtosearchforanyusageoftheNotificationManagerclasswhichmightbeanindicationofsomeformofnotificationmanagement.Iftheclassisbeingused,thenextstepwouldbetounderstandhowtheapplicationisgeneratingthenotifications.ThesecodelocationscanbefedintotheDynamicAnalysissectionbelow,providinganideaofwhereintheapplicationnotificationsmaybedynamicallygenerated.DynamicAnalysisTodeterminewhethertheapplicationleaksanysensitiveinformationtotheuserinterface,runtheapplicationandidentifycomponentsthatcouldbedisclosinginformation.TextFieldsIftheinformationismaskedby,forexample,replacinginputwithasterisksordots,theappisn'tleakingdatatotheuserinterface.AppNotificationsToidentifytheusageofnotificationsrunthroughtheentireapplicationandallitsavailablefunctionslookingforwaystotriggeranynotifications.Considerthatyoumayneedtoperformactionsoutsideoftheapplicationinordertotriggercertainnotifications.Whilerunningtheapplicationyoumaywanttostarttracingallcallstofunctionsrelatedtothenotificationscreation,e.g.setContentTitleorsetContentTextfromNotificationCompat.Builder.Observethetraceintheendandevaluateifitcontainsanysensitiveinformation.TestingBackupsforSensitiveData(MSTG-STORAGE-8)OverviewThistestcasefocusesonensuringthatbackupsdonotstoresensitiveapplicationspecificdata.Thefollowingchecksshouldbeperformed:CheckAndroidManifest.xmlforrelevantbackupflags.Attempttobackuptheapplicationandinspectthebackupforsensitivedata.StaticAnalysisLocalAndroidprovidesanattributecalledallowBackuptobackupallyourapplicationdata.ThisattributeissetintheAndroidManifest.xmlfile.Ifthevalueofthisattributeistrue,thedeviceallowsuserstobackuptheapplicationwithAndroidDebugBridge(ADB)viathecommand$adbbackup.Topreventtheappdatabackup,settheandroid:allowBackupattributetofalse.Whenthisattributeisunavailable,theallowBackupsettingisenabledbydefault,andbackupmustbemanuallydeactivated.Note:Ifthedevicewasencrypted,thenthebackupfileswillbeencryptedaswell.ChecktheAndroidManifest.xmlfileforthefollowingflag:1android:allowBackup="true"Copied!Iftheflagvalueistrue,determinewhethertheappsavesanykindofsensitivedata(checkthetestcase"TestingforSensitiveDatainLocalStorage").CloudRegardlessofwhetheryouusekey/valuebackuporautobackup,youmustdeterminethefollowing:whichfilesaresenttothecloud(e.g.,SharedPreferences)whetherthefilescontainsensitiveinformationwhethersensitiveinformationisencryptedbeforebeingsenttothecloud.Ifyoudon'twanttosharefileswithGoogleCloud,youcanexcludethemfromAutoBackup.Sensitiveinformationstoredatrestonthedeviceshouldbeencryptedbeforebeingsenttothecloud.AutoBackup:YouconfigureAutoBackupviathebooleanattributeandroid:allowBackupwithintheapplication'smanifestfile.AutoBackupisenabledbydefaultforapplicationsthattargetAndroid6.0(APIlevel23).Youcanusetheattributeandroid:fullBackupOnlytoactivateautobackupwhenimplementingabackupagent,butthisattributeisavailableforAndroidversions6.0andaboveonly.OtherAndroidversionsusekey/valuebackupinstead.1android:fullBackupOnlyCopied!Autobackupincludesalmostalltheappfilesandstoresup25MBofthemperappintheuser'sGoogleDriveaccount.Onlythemostrecentbackupisstored;thepreviousbackupisdeleted.Key/ValueBackup:Toenablekey/valuebackup,youmustdefinethebackupagentinthemanifestfile.LookinAndroidManifest.xmlforthefollowingattribute:1android:backupAgentCopied!Toimplementkey/valuebackup,extendoneofthefollowingclasses:​BackupAgent​​BackupAgentHelper​Tocheckforkey/valuebackupimplementations,lookfortheseclassesinthesourcecode.DynamicAnalysisAfterexecutingallavailableappfunctions,attempttobackupviaadb.Ifthebackupissuccessful,inspectthebackuparchiveforsensitivedata.Openaterminalandrunthefollowingcommand:1$adbbackup-apk-nosystemCopied!ADBshouldrespondnowwith"Nowunlockyourdeviceandconfirmthebackupoperation"andyoushouldbeaskedontheAndroidphoneforapassword.Thisisanoptionalstepandyoudon'tneedtoprovideone.Ifthephonedoesnotpromptthismessage,trythefollowingcommandincludingthequotes:1$adbbackup"-apk-nosystem"Copied!Theproblemhappenswhenyourdevicehasanadbversionpriorto1.0.31.Ifthat'sthecaseyoumustuseanadbversionof1.0.31alsoonyourhostcomputer.Versionsofadbafter1.0.32brokethebackwardscompatibility.​ApprovethebackupfromyourdevicebyselectingtheBackupmydataoption.Afterthebackupprocessisfinished,thefile.abwillbeinyourworkingdirectory.Runthefollowingcommandtoconvertthe.abfiletotar.1$ddif=mybackup.abbs=24skip=1|opensslzlib-d>mybackup.tarCopied!Incaseyougettheerroropenssl:Error:'zlib'isaninvalidcommand.youcantrytousePythoninstead.1$ddif=backup.abbs=1skip=24|python-c"importzlib,sys;sys.stdout.write(zlib.decompress(sys.stdin.read()))">backup.tarCopied!TheAndroidBackupExtractorisanotheralternativebackuptool.Tomakethetooltowork,youhavetodownloadtheOracleJCEUnlimitedStrengthJurisdictionPolicyFilesforJRE7orJRE8andplacethemintheJRElib/securityfolder.Runthefollowingcommandtoconvertthetarfile:1$java-jarabe.jarunpackbackup.abCopied!ifitshowssomeCipherinformationandusage,whichmeansithasn'tunpackedsuccessfully.Inthiscaseyoucangiveatrywithmorearguments:1$abe[-debug][-useenv=yourenv]unpack[password]Copied![password]:isthepasswordwhenyourandroiddeviceaskedyouearlier.Forexamplehereis:1231$java-jarabe.jarunpackbackup.abbackup.tar123Copied!Extractthetarfiletoyourworkingdirectory.1$tarxvfmybackup.tarCopied!FindingSensitiveInformationinAuto-GeneratedScreenshots(MSTG-STORAGE-9)OverviewManufacturerswanttoprovidedeviceuserswithanaestheticallypleasingexperienceatapplicationstartupandexit,sotheyintroducedthescreenshot-savingfeatureforusewhentheapplicationisbackgrounded.Thisfeaturemayposeasecurityrisk.Sensitivedatamaybeexposediftheuserdeliberatelyscreenshotstheapplicationwhilesensitivedataisdisplayed.Amaliciousapplicationthatisrunningonthedeviceandabletocontinuouslycapturethescreenmayalsoexposedata.Screenshotsarewrittentolocalstorage,fromwhichtheymayberecoveredbyarogueapplication(ifthedeviceisrooted)orsomeonewhohasstolenthedevice.Forexample,capturingascreenshotofabankingapplicationmayrevealinformationabouttheuser'saccount,credit,transactions,andsoon.StaticAnalysisAscreenshotofthecurrentactivityistakenwhenanAndroidappgoesintobackgroundanddisplayedforaestheticpurposeswhentheappreturnstotheforeground.However,thismayleaksensitiveinformation.Todeterminewhethertheapplicationmayexposesensitiveinformationviatheappswitcher,findoutwhethertheFLAG_SECUREoptionhasbeenset.Youshouldfindsomethingsimilartothefollowingcodesnippet:ExampleinJava:1getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,2WindowManager.LayoutParams.FLAG_SECURE);3​4setContentView(R.layout.activity_main);Copied!ExampleinKotlin:1window.setFlags(WindowManager.LayoutParams.FLAG_SECURE,2WindowManager.LayoutParams.FLAG_SECURE)3​4setContentView(R.layout.activity_main)Copied!Iftheoptionhasnotbeenset,theapplicationisvulnerabletoscreencapturing.DynamicAnalysisWhileblack-boxtestingtheapp,navigatetoanyscreenthatcontainssensitiveinformationandclickthehomebuttontosendtheapptothebackground,thenpresstheappswitcherbuttontoseethesnapshot.Asshownbelow,ifFLAG_SECUREisset(leftimage),thesnapshotwillbeempty;iftheflaghasnotbeenset(rightimage),activityinformationwillbeshown:​ \Ondevicessupportingfile-basedencryption(FBE),snapshotsarestoredinthe/data/system_ce//folder.dependsonthevendorbutmostcommonnamesaresnapshotsandrecent_images.Ifthedevicedoesn'tsupportFBE,the/data/system/folderisused.Accessingthesefoldersandthesnapshotsrequiresroot.CheckingMemoryforSensitiveData(MSTG-STORAGE-10)OverviewAnalyzingmemorycanhelpdevelopersidentifytherootcausesofseveralproblems,suchasapplicationcrashes.However,itcanalsobeusedtoaccesssensitivedata.Thissectiondescribeshowtocheckfordatadisclosureviaprocessmemory.Firstidentifysensitiveinformationthatisstoredinmemory.Sensitiveassetshavelikelybeenloadedintomemoryatsomepoint.Theobjectiveistoverifythatthisinformationisexposedasbrieflyaspossible.Toinvestigateanapplication'smemory,youmustfirstcreateamemorydump.Youcanalsoanalyzethememoryinreal-time,e.g.,viaadebugger.Regardlessofyourapproach,memorydumpingisaveryerror-proneprocessintermsofverificationbecauseeachdumpcontainstheoutputofexecutedfunctions.Youmaymissexecutingcriticalscenarios.Inaddition,overlookingdataduringanalysisisprobableunlessyouknowthedata'sfootprint(eithertheexactvalueorthedataformat).Forexample,iftheappencryptswitharandomlygeneratedsymmetrickey,youlikelywon'tbeabletospotitinmemoryunlessyoucanrecognizethekey'svalueinanothercontext.Therefore,youarebetteroffstartingwithstaticanalysis.StaticAnalysisForanoverviewofpossiblesourcesofdataexposure,checkthedocumentationandidentifyapplicationcomponentsbeforeyouexaminethesourcecode.Forexample,sensitivedatafromabackendmaybeintheHTTPclient,theXMLparser,etc.Youwantallthesecopiestoberemovedfrommemoryassoonaspossible.Inaddition,understandingtheapplication'sarchitectureandthearchitecture'sroleinthesystemwillhelpyouidentifysensitiveinformationthatdoesn'thavetobeexposedinmemoryatall.Forexample,assumeyourappreceivesdatafromoneserverandtransfersittoanotherwithoutanyprocessing.Thatdatacanbehandledinanencryptedformat,whichpreventsexposureinmemory.However,ifyouneedtoexposesensitivedatainmemory,youshouldmakesurethatyourappisdesignedtoexposeasfewdatacopiesaspossibleasbrieflyaspossible.Inotherwords,youwantthehandlingofsensitivedatatobecentralized(i.e.,withasfewcomponentsaspossible)andbasedonprimitive,mutabledatastructures.Thelatterrequirementgivesdevelopersdirectmemoryaccess.Makesurethattheyusethisaccesstooverwritethesensitivedatawithdummydata(typicallyzeroes).Examplesofpreferabledatatypesincludebyte[]andchar[],butnotStringorBigInteger.WheneveryoutrytomodifyanimmutableobjectlikeString,youcreateandchangeacopyoftheobject.Usingnon-primitivemutabletypeslikeStringBufferandStringBuildermaybeacceptable,butit'sindicativeandrequirescare.TypeslikeStringBufferareusedtomodifycontent(whichiswhatyouwanttodo).Toaccesssuchatype'svalue,however,youwouldusethetoStringmethod,whichwouldcreateanimmutablecopyofthedata.Thereareseveralwaystousethesedatatypeswithoutcreatinganimmutablecopy,buttheyrequiremoreeffortthansimplyusingaprimitivearray.SafememorymanagementisonebenefitofusingtypeslikeStringBuffer,butthiscanbeatwo-edgedsword.Ifyoutrytomodifythecontentofoneofthesetypesandthecopyexceedsthebuffercapacity,thebuffersizewillautomaticallyincrease.Thebuffercontentmaybecopiedtoadifferentlocation,leavingtheoldcontentwithoutareferenceyoucanusetooverwriteit.Unfortunately,fewlibrariesandframeworksaredesignedtoallowsensitivedatatobeoverwritten.Forexample,destroyingakey,asshownbelow,doesn'treallyremovethekeyfrommemory:ExampleinJava:1SecretKeysecretKey=newSecretKeySpec("key".getBytes(),"AES");2secretKey.destroy();Copied!ExampleinKotlin:1valsecretKey:SecretKey=SecretKeySpec("key".toByteArray(),"AES")2secretKey.destroy()Copied!Overwritingthebackingbyte-arrayfromsecretKey.getEncodeddoesn'tremovethekeyeither;theSecretKeySpec-basedkeyreturnsacopyofthebackingbyte-array.SeethesectionsbelowfortheproperwaytoremoveaSecretKeyfrommemory.TheRSAkeypairisbasedontheBigIntegertypeandthereforeresidesinmemoryafteritsfirstuseoutsidetheAndroidKeyStore.Someciphers(suchastheAESCipherinBouncyCastle)donotproperlycleanuptheirbyte-arrays.User-provideddata(credentials,socialsecuritynumbers,creditcardinformation,etc.)isanothertypeofdatathatmaybeexposedinmemory.Regardlessofwhetheryouflagitasapasswordfield,EditTextdeliverscontenttotheappviatheEditableinterface.Ifyourappdoesn'tprovideEditable.Factory,user-provideddatawillprobablybeexposedinmemoryforlongerthannecessary.ThedefaultEditableimplementation,theSpannableStringBuilder,causesthesameissuesasJava'sStringBuilderandStringBuffercause(discussedabove).Insummary,whenperformingstaticanalysistoidentifysensitivedatathatisexposedinmemory,youshould:Trytoidentifyapplicationcomponentsandmapwheredataisused.Makesurethatsensitivedataishandledbyasfewcomponentsaspossible.Makesurethatobjectreferencesareproperlyremovedoncetheobjectcontainingthesensitivedataisnolongerneeded.Makesurethatgarbagecollectionisrequestedafterreferenceshavebeenremoved.Makesurethatsensitivedatagetsoverwrittenassoonasitisnolongerneeded.Don'trepresentsuchdatawithimmutabledatatypes(suchasStringandBigInteger).Avoidnon-primitivedatatypes(suchasStringBuilder).Overwritereferencesbeforeremovingthem,outsidethefinalizemethod.Payattentiontothird-partycomponents(librariesandframeworks).PublicAPIsaregoodindicators.DeterminewhetherthepublicAPIhandlesthesensitivedataasdescribedinthischapter.Thefollowingsectiondescribespitfallsofdataleakageinmemoryandbestpracticesforavoidingthem.Don'tuseimmutablestructures(e.g.,StringandBigInteger)torepresentsecrets.Nullifyingthesestructureswillbeineffective:thegarbagecollectormaycollectthem,buttheymayremainontheheapaftergarbagecollection.Nevertheless,youshouldaskforgarbagecollectionaftereverycriticaloperation(e.g.,encryption,parsingserverresponsesthatcontainsensitiveinformation).Whencopiesoftheinformationhavenotbeenproperlycleaned(asexplainedbelow),yourrequestwillhelpreducethelengthoftimeforwhichthesecopiesareavailableinmemory.Toproperlycleansensitiveinformationfrommemory,storeitinprimitivedatatypes,suchasbyte-arrays(byte[])andchar-arrays(char[]).Asdescribedinthe"StaticAnalysis"sectionabove,youshouldavoidstoringtheinformationinmutablenon-primitivedatatypes.Makesuretooverwritethecontentofthecriticalobjectoncetheobjectisnolongerneeded.Overwritingthecontentwithzeroesisonesimpleandverypopularmethod:ExampleinJava:1byte[]secret=null;2try{3//getorgeneratethesecret,doworkwithit,makesureyoumakenolocalcopies4}finally{5if(null!=secret){6Arrays.fill(secret,(byte)0);7}8}Copied!ExampleinKotlin:1valsecret:ByteArray?=null2try{3//getorgeneratethesecret,doworkwithit,makesureyoumakenolocalcopies4}finally{5if(null!=secret){6Arrays.fill(secret,0.toByte())7}8}Copied!Thisdoesn't,however,guaranteethatthecontentwillbeoverwrittenatruntime.Tooptimizethebytecode,thecompilerwillanalyzeanddecidenottooverwritedatabecauseitwillnotbeusedafterwards(i.e.,itisanunnecessaryoperation).EvenifthecodeisinthecompiledDEX,theoptimizationmayoccurduringthejust-in-timeorahead-of-timecompilationintheVM.Thereisnosilverbulletforthisproblembecausedifferentsolutionshavedifferentconsequences.Forexample,youmayperformadditionalcalculations(e.g.,XORthedataintoadummybuffer),butyou'llhavenowaytoknowtheextentofthecompiler'soptimizationanalysis.Ontheotherhand,usingtheoverwrittendataoutsidethecompiler'sscope(e.g.,serializingitinatempfile)guaranteesthatitwillbeoverwrittenbutobviouslyimpactsperformanceandmaintenance.Then,usingArrays.filltooverwritethedataisabadideabecausethemethodisanobvioushookingtarget(seethechapter"TamperingandReverseEngineeringonAndroid"formoredetails).Thefinalissuewiththeaboveexampleisthatthecontentwasoverwrittenwithzeroesonly.Youshouldtrytooverwritecriticalobjectswithrandomdataorcontentfromnon-criticalobjects.Thiswillmakeitreallydifficulttoconstructscannersthatcanidentifysensitivedataonthebasisofitsmanagement.Belowisanimprovedversionofthepreviousexample:ExampleinJava:1byte[]nonSecret=somePublicString.getBytes("ISO-8859-1");2byte[]secret=null;3try{4//getorgeneratethesecret,doworkwithit,makesureyoumakenolocalcopies5}finally{6if(null!=secret){7for(inti=0;istrings.txt3​4#usingrabin25$rabin2-ZZmemory>strings.txtCopied!Openstrings.txtinyourfavoriteeditoranddigthroughittoidentifysensitiveinformation.Howeverifyou'dliketoinspectotherkindofdata,you'dratherwanttouseradare2anditssearchcapabilities.Seeradare2'shelponthesearchcommand(/?)formoreinformationandalistofoptions.Thefollowingshowsonlyasubsetofthem:1$r22​3[0x00000000]>/?4Usage:/[!bf][arg]Searchstuff(see'e??search'foroptions)5|Useio.vaforsearchinginnonvirtualaddressingspaces6|/foo\x00searchforstring'foo\0'7|/c[ar]searchforcryptomaterials8|/e/E.F/imatchregularexpression9|/ifoosearchforstring'foo'ignoringcase10|/m[?][ebm]magicfilesearchformagic,filesystemsorbinaryheaders11|/v[1248]valuelookforan`cfg.bigendian`32bitvalue12|/wfoosearchforwidestring'f\0o\0o\0'13|/xff0033searchforhexstring14|/zminmaxsearchforstringsofgivensize15...Copied!RuntimeMemoryAnalysisInsteadofdumpingthememorytoyourhostcomputer,youcanalternativelyuser2frida.Withit,youcananalyzeandinspecttheapp'smemorywhileit'srunning.Forexample,youmayruntheprevioussearchcommandsfromr2fridaandsearchthememoryforastring,hexadecimalvalues,etc.Whendoingso,remembertoprependthesearchcommand(andanyotherr2fridaspecificcommands)withabackslash\afterstartingthesessionwithr2frida://usb//.Formoreinformation,optionsandapproaches,pleaserefertosection"In-MemorySearch"inthechapter"TamperingandReverseEngineeringonAndroid".ExplicitlyDumpingandAnalyzingtheJavaHeapForrudimentaryanalysis,youcanuseAndroidStudio'sbuilt-intools.TheyareontheAndroidMonitortab.Todumpmemory,selectthedeviceandappyouwanttoanalyzeandclickDumpJavaHeap.Thiswillcreatea.hproffileinthecapturesdirectory,whichisontheapp'sprojectpath.​\Tonavigatethroughclassinstancesthatweresavedinthememorydump,selectthePackageTreeViewinthetabshowingthe.hproffile.​\Formoreadvancedanalysisofthememorydump,usetheEclipseMemoryAnalyzerTool(MAT).ItisavailableasanEclipsepluginandasastandaloneapplication.ToanalyzethedumpinMAT,usethehprof-convplatformtool,whichcomeswiththeAndroidSDK.1$./hprof-convmemory.hprofmemory-mat.hprofCopied!MATprovidesseveraltoolsforanalyzingthememorydump.Forexample,theHistogramprovidesanestimateofthenumberofobjectsthathavebeencapturedfromagiventype,andtheThreadOverviewshowsprocesses'threadsandstackframes.TheDominatorTreeprovidesinformationaboutkeep-alivedependenciesbetweenobjects.Youcanuseregularexpressionstofiltertheresultsthesetoolsprovide.ObjectQueryLanguagestudioisaMATfeaturethatallowsyoutoqueryobjectsfromthememorydumpwithanSQL-likelanguage.ThetoolallowsyoutotransformsimpleobjectsbyinvokingJavamethodsonthem,anditprovidesanAPIforbuildingsophisticatedtoolsontopoftheMAT.1SELECT*FROMjava.lang.StringCopied!Intheexampleabove,allStringobjectspresentinthememorydumpwillbeselected.Theresultswillincludetheobject'sclass,memoryaddress,value,andretaincount.Tofilterthisinformationandseeonlythevalueofeachstring,usethefollowingcode:1SELECTtoString(object)FROMjava.lang.StringobjectCopied!Or1SELECTobject.toString()FROMjava.lang.StringobjectCopied!SQLsupportsprimitivedatatypesaswell,soyoucandosomethinglikethefollowingtoaccessthecontentofallchararrays:1SELECTtoString(arr)FROMchar[]arrCopied!Don'tbesurprisedifyougetresultsthataresimilartothepreviousresults;afterall,StringandotherJavadatatypesarejustwrappersaroundprimitivedatatypes.Nowlet'sfiltertheresults.ThefollowingsamplecodewillselectallbytearraysthatcontaintheASN.1OIDofanRSAkey.Thisdoesn'timplythatagivenbytearrayactuallycontainsanRSA(thesamebytesequencemaybepartofsomethingelse),butthisisprobable.1SELECT*FROMbyte[]bWHEREtoString(b).matches(".*1\.2\.840\.113549\.1\.1\.1.*")Copied!Finally,youdon'thavetoselectwholeobjects.ConsideranSQLanalogy:classesaretables,objectsarerows,andfieldsarecolumns.Ifyouwanttofindallobjectsthathavea"password"field,youcandosomethinglikethefollowing:1SELECTpasswordFROM".*"WHERE(null!=password)Copied!Duringyouranalysis,searchfor:Indicativefieldnames:"password","pass","pin","secret","private",etc.Indicativepatterns(e.g.,RSAfootprints)instrings,chararrays,bytearrays,etc.Knownsecrets(e.g.,acreditcardnumberthatyou'veenteredoranauthenticationtokenprovidedbythebackend)etc.Repeatingtestsandmemorydumpswillhelpyouobtainstatisticsaboutthelengthofdataexposure.Furthermore,observingthewayaparticularmemorysegment(e.g.,abytearray)changesmayleadyoutosomeotherwiseunrecognizablesensitivedata(moreonthisinthe"Remediation"sectionbelow).TestingtheDevice-Access-SecurityPolicy(MSTG-STORAGE-11)OverviewAppsthatprocessorquerysensitiveinformationshouldruninatrustedandsecureenvironment.Tocreatethisenvironment,theappcancheckthedeviceforthefollowing:PIN-orpassword-protecteddevicelockingRecentAndroidOSversionUSBDebuggingactivationDeviceencryptionDevicerooting(seealso"TestingRootDetection")StaticAnalysisTotestthedevice-access-securitypolicythattheappenforces,awrittencopyofthepolicymustbeprovided.Thepolicyshoulddefineavailablechecksandtheirenforcement.Forexample,onecheckcouldrequirethattheapprunonlyonAndroid6.0(APIlevel23)oramorerecentversion,closingtheappordisplayingawarningiftheAndroidversionislessthan6.0.Checkthesourcecodeforfunctionsthatimplementthepolicyanddeterminewhetheritcanbebypassed.YoucanimplementchecksontheAndroiddevicebyqueryingSettings.Secureforsystempreferences.DeviceAdministrationAPIofferstechniquesforcreatingapplicationsthatcanenforcepasswordpoliciesanddeviceencryption.DynamicAnalysisThedynamicanalysisdependsonthechecksenforcedbytheappandtheirexpectedbehavior.Ifthecheckscanbebypassed,theymustbevalidated.ReferencesOWASPMASVSMSTG-STORAGE-1:"Systemcredentialstoragefacilitiesneedtobeusedtostoresensitivedata,suchasPII,usercredentialsorcryptographickeys."MSTG-STORAGE-2:"Nosensitivedatashouldbestoredoutsideoftheappcontainerorsystemcredentialstoragefacilities."MSTG-STORAGE-3:"Nosensitivedataiswrittentoapplicationlogs."MSTG-STORAGE-4:"Nosensitivedataissharedwiththirdpartiesunlessitisanecessarypartofthearchitecture."MSTG-STORAGE-5:"Thekeyboardcacheisdisabledontextinputsthatprocesssensitivedata."MSTG-STORAGE-6:"NosensitivedataisexposedviaIPCmechanisms."MSTG-STORAGE-7:"Nosensitivedata,suchaspasswordsorpins,isexposedthroughtheuserinterface."MSTG-STORAGE-8:"Nosensitivedataisincludedinbackupsgeneratedbythemobileoperatingsystem."MSTG-STORAGE-9:"Theappremovessensitivedatafromviewswhenmovedtothebackground."MSTG-STORAGE-10:"Theappdoesnotholdsensitivedatainmemorylongerthannecessary,andmemoryisclearedexplicitlyafteruse."MSTG-STORAGE-11:"Theappenforcesaminimumdevice-access-securitypolicy,suchasrequiringtheusertosetadevicepasscode."MSTG-PLATFORM-2:"Allinputsfromexternalsourcesandtheuserarevalidatedandifnecessarysanitized.ThisincludesdatareceivedviatheUI,IPCmechanismssuchasintents,customURLs,andnetworksources."LibrariesJavaAESCrypto-https://github.com/tozny/java-aes-crypto​SQLCipher-https://www.zetetic.net/sqlcipher/sqlcipher-for-android​SecurePreferences-https://github.com/scottyab/secure-preferences​AndroidTestingGuide-PreviousAndroidBasicSecurityTestingNext-AndroidTestingGuideAndroidCryptographicAPIsLastmodified23dagoCopylinkContentsTheoryOverviewDataStorageMethodsOverviewSharedPreferencesDatabasesInternalStorageExternalStorageKeyStoreLogsBackupsProcessMemoryTestingLocalStorageforSensitiveData(MSTG-STORAGE-1andMSTG-STORAGE-2)OverviewStaticAnalysisDynamicAnalysisTestingLocalStorageforInputValidation(MSTG-PLATFORM-2)OverviewStaticanalysisTestingLogsforSensitiveData(MSTG-STORAGE-3)OverviewStaticAnalysisDynamicAnalysisDeterminingWhetherSensitiveDataIsSharedwithThirdParties(MSTG-STORAGE-4)OverviewThird-partyServicesEmbeddedintheAppAppNotificationsStaticAnalysisDynamicAnalysisDeterminingWhethertheKeyboardCacheIsDisabledforTextInputFields(MSTG-STORAGE-5)OverviewStaticAnalysisDynamicAnalysisDeterminingWhetherSensitiveStoredDataHasBeenExposedviaIPCMechanisms(MSTG-STORAGE-6)OverviewStaticAnalysisDynamicAnalysisCheckingforSensitiveDataDisclosureThroughtheUserInterface(MSTG-STORAGE-7)OverviewStaticAnalysisDynamicAnalysisTestingBackupsforSensitiveData(MSTG-STORAGE-8)OverviewStaticAnalysisDynamicAnalysisFindingSensitiveInformationinAuto-GeneratedScreenshots(MSTG-STORAGE-9)OverviewStaticAnalysisDynamicAnalysisCheckingMemoryforSensitiveData(MSTG-STORAGE-10)OverviewStaticAnalysisDynamicAnalysisTestingtheDevice-Access-SecurityPolicy(MSTG-STORAGE-11)OverviewStaticAnalysisDynamicAnalysisReferencesOWASPMASVSLibraries



請為這篇文章評分?