Drozer Basics
Drozer is an Android Security Assessment and Attack Framework. It consists of a client/server model where the ‘server’ runs on the Android device, and the client run on your laptop. Drozer was originally written in Python2, but has recently been updated to support Python3. As such, it is now the leading framework to assess security of applications on the Android platform.
Note that the Drozer commands will be run from the dz>
prompt. Any commands showing a %
prompt, these are run in the shell.
Drozer is also available for Docker, but we do not go into the Docker usage in this guide.
Starting Drozer
Starting Drozer is a two-step process; enable the server in the Agent app, and start the console on your computer. On the device, launch the Drozer Agent app, and tap the button at the bottom for the Embedded Server. When the server is not running the button will say Off, and it will change to On with a blue line below it when it starts.
The default TCP port of the server is 31415. This is changeable in the app settings.
Next, open a terminal on your computer. First, we will setup a TCP forwarding for adb
. Then we can startup the Drozer Console.
% adb forward tcp:31415 tcp:31415
31415
% drozer console connect
Selecting a1ce4b441b83a735 (Google Pixel 6 15)
.. ..:.
..o.. .r..
..a.. . ....... . ..nd
ro..idsnemesisand..pr
.otectorandroidsneme.
.,sisandprotectorandroids+.
..nemesisandprotectorandroidsn:.
.emesisandprotectorandroidsnemes..
..isandp,..,rotecyayandro,..,idsnem.
.isisandp..rotectorandroid..snemisis.
,andprotectorandroidsnemisisandprotec.
.torandroidsnemesisandprotectorandroid.
.snemisisandprotectorandroidsnemesisan:
.dprotectorandroidsnemesisandprotector.
drozer Console (v3.1.0)
dz>
Drozer Usage
All of these examples are from the Sieve app.
Search for a specific package:
dz> run app.package.list -f sieve
Attempting to run shell module
com.withsecure.example.sieve (Sieve)
Obtain package information:
dz> run app.package.info -a com.withsecure.example.sieve
Attempting to run shell module
Package: com.withsecure.example.sieve
Application Label: Sieve
Process Name: com.withsecure.example.sieve
Version: 1.0
Data Directory: /data/user/0/com.withsecure.example.sieve
APK Path: /data/app/~~CRNfFGiNQfvogwu0oW1_iQ==/com.withsecure.example.sieve-G5JBKde1tOGpfgzE6_LjZg==/base.apk
UID: 10297
GID: [3003]
Shared Libraries: [/system/framework/android.test.base.jar]
Shared User ID: null
Uses Permissions:
- android.permission.POST_NOTIFICATIONS
- android.permission.INTERNET
- com.withsecure.example.sieve.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION
Defines Permissions:
- com.withsecure.example.sieve.READ_KEYS
- com.withsecure.example.sieve.WRITE_KEYS
- com.withsecure.example.sieve.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION
Get the attack surface of the app:
dz> run app.package.attacksurface com.withsecure.example.sieve
Attempting to run shell module
Attack Surface:
3 activities exported
1 broadcast receivers exported
2 content providers exported
2 services exported
is debuggable
Print out the app permissions:
dz> permissions com.withsecure.example.sieve
Has ApplicationContext: YES
Available Permissions:
- android.permission.INTERNET
- android.permission.QUERY_ALL_PACKAGES
- com.withsecure.dz.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION
Print out the AndroidManifest.xml file:
dz> run app.package.manifest com.withsecure.example.sieve
Attempting to run shell module
<manifest versionCode="1"
versionName="1.0"
compileSdkVersion="34"
compileSdkVersionCodename="14"
package="com.withsecure.example.sieve"
platformBuildVersionCode="34"
platformBuildVersionName="14">
<uses-sdk minSdkVersion="17"
targetSdkVersion="28">
</uses-sdk>
<uses-permission name="android.permission.POST_NOTIFICATIONS">
</uses-permission>
<uses-permission name="android.permission.INTERNET">
</uses-permission>
<permission name="com.withsecure.example.sieve.READ_KEYS"
protectionLevel="0x1">
</permission>
<permission name="com.withsecure.example.sieve.WRITE_KEYS"
protectionLevel="0x1">
</permission>
<permission name="com.withsecure.example.sieve.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"
protectionLevel="0x2">
</permission>
<uses-permission name="com.withsecure.example.sieve.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION">
</uses-permission>
<application theme="@2131821169"
label="@2131755040"
icon="@2131623936"
debuggable="true"
allowBackup="true"
supportsRtl="true"
extractNativeLibs="true"
fullBackupContent="@2131951616"
appComponentFactory="androidx.core.app.CoreComponentFactory"
dataExtractionRules="@2131951617">
<activity label="@2131755040"
name="com.withsecure.example.sieve.activity.MainLoginActivity"
exported="true"
launchMode="2"
windowSoftInputMode="0x14">
<intent-filter>
<action name="android.intent.action.MAIN">
</action>
<category name="android.intent.category.LAUNCHER">
</category>
</intent-filter>
</activity>
<activity label="@2131755234"
name="com.withsecure.example.sieve.activity.FileSelectActivity"
exported="true"
clearTaskOnLaunch="true">
</activity>
<activity label="@2131755236"
name="com.withsecure.example.sieve.activity.PWList"
exported="true"
clearTaskOnLaunch="true">
</activity>
<activity label="@2131755237"
name="com.withsecure.example.sieve.activity.SettingsActivity"
clearTaskOnLaunch="true">
</activity>
<activity label="@2131755233"
name="com.withsecure.example.sieve.activity.AddEntryActivity"
clearTaskOnLaunch="true">
</activity>
<activity label="@2131755238"
name="com.withsecure.example.sieve.activity.ShortLoginActivity"
clearTaskOnLaunch="true">
</activity>
<activity label="@2131755239"
name="com.withsecure.example.sieve.activity.WelcomeActivity"
clearTaskOnLaunch="true">
</activity>
<activity label="@2131755235"
name="com.withsecure.example.sieve.activity.PINActivity"
clearTaskOnLaunch="true">
</activity>
<service name="com.withsecure.example.sieve.service.AuthService"
exported="true"
process=":remote">
</service>
<service name="com.withsecure.example.sieve.service.CryptoService"
exported="true"
process=":remote">
</service>
<provider name="com.withsecure.example.sieve.provider.DBContentProvider"
exported="true"
multiprocess="true"
authorities="com.withsecure.example.sieve.provider.DBContentProvider">
<path-permission readPermission="com.withsecure.example.sieve.READ_KEYS"
writePermission="com.withsecure.example.sieve.WRITE_KEYS"
path="/Keys">
</path-permission>
<path-permission readPermission="com.withsecure.example.sieve.READ_KEYS"
writePermission="com.withsecure.example.sieve.WRITE_KEYS"
path="/Keys/*">
</path-permission>
</provider>
<provider name="com.withsecure.example.sieve.provider.FileBackupProvider"
exported="true"
multiprocess="true"
authorities="com.withsecure.example.sieve.provider.FileBackupProvider">
</provider>
<provider name="androidx.startup.InitializationProvider"
exported="false"
authorities="com.withsecure.example.sieve.androidx-startup">
<meta-data name="androidx.emoji2.text.EmojiCompatInitializer"
value="androidx.startup">
</meta-data>
<meta-data name="androidx.lifecycle.ProcessLifecycleInitializer"
value="androidx.startup">
</meta-data>
<meta-data name="androidx.profileinstaller.ProfileInstallerInitializer"
value="androidx.startup">
</meta-data>
</provider>
<receiver name="androidx.profileinstaller.ProfileInstallReceiver"
permission="android.permission.DUMP"
enabled="true"
exported="true"
directBootAware="false">
<intent-filter>
<action name="androidx.profileinstaller.action.INSTALL_PROFILE">
</action>
</intent-filter>
<intent-filter>
<action name="androidx.profileinstaller.action.SKIP_FILE">
</action>
</intent-filter>
<intent-filter>
<action name="androidx.profileinstaller.action.SAVE_PROFILE">
</action>
</intent-filter>
<intent-filter>
<action name="androidx.profileinstaller.action.BENCHMARK_OPERATION">
</action>
</intent-filter>
</receiver>
</application>
</manifest>
Get details of exported Activities:
dz> run app.activity.info -a com.withsecure.example.sieve
Attempting to run shell module
Package: com.withsecure.example.sieve
com.withsecure.example.sieve.activity.MainLoginActivity
Permission: null
com.withsecure.example.sieve.activity.FileSelectActivity
Permission: null
com.withsecure.example.sieve.activity.PWList
Permission: null
Get Provider details:
dz> run app.provider.info -a com.withsecure.example.sieve
Attempting to run shell module
Package: com.withsecure.example.sieve
Authority: com.withsecure.example.sieve.provider.DBContentProvider
Read Permission: null
Write Permission: null
Content Provider: com.withsecure.example.sieve.provider.DBContentProvider
Multiprocess Allowed: True
Grant Uri Permissions: False
Uri Permission Patterns:
Path Permissions:
Path: /Keys
Type: PATTERN_LITERAL
Read Permission: com.withsecure.example.sieve.READ_KEYS
Write Permission: com.withsecure.example.sieve.WRITE_KEYS
Path: /Keys/*
Type: PATTERN_LITERAL
Read Permission: com.withsecure.example.sieve.READ_KEYS
Write Permission: com.withsecure.example.sieve.WRITE_KEYS
Authority: com.withsecure.example.sieve.provider.FileBackupProvider
Read Permission: null
Write Permission: null
Content Provider: com.withsecure.example.sieve.provider.FileBackupProvider
Multiprocess Allowed: True
Grant Uri Permissions: False
Uri Permission Patterns:
Path Permissions:
Get Service details:
dz> run app.service.info -a com.withsecure.example.sieve
Attempting to run shell module
Package: com.withsecure.example.sieve
com.withsecure.example.sieve.service.AuthService
Permission: null
com.withsecure.example.sieve.service.CryptoService
Permission: null
Other commands:
dz> list
app.activity.forintent Find activities that can handle the given intent
app.activity.info Gets information about exported activities.
app.activity.start Start an Activity
app.broadcast.info Get information about broadcast receivers
app.broadcast.send Send broadcast using an intent
app.broadcast.sniff Register a broadcast receiver that can sniff
particular intents
app.package.attacksurface Get attack surface of package
app.package.backup Lists packages that use the backup API (returns true
on FLAG_ALLOW_BACKUP)
app.package.debuggable Find debuggable packages
app.package.info Get information about installed packages
app.package.launchintent Get launch intent of package
app.package.list List Packages
app.package.manifest Get AndroidManifest.xml of package
app.package.native Find Native libraries embedded in the application.
app.package.shareduid Look for packages with shared UIDs
app.provider.columns List columns in content provider
app.provider.delete Delete from a content provider
app.provider.download Download a file from a content provider that supports
files
app.provider.finduri Find referenced content URIs in a package
app.provider.info Get information about exported content providers
app.provider.insert Insert into a Content Provider
app.provider.query Query a content provider
app.provider.read Read from a content provider that supports files
app.provider.update Update a record in a content provider
app.service.info Get information about exported services
app.service.send Send a Message to a service, and display the reply
app.service.start Start Service
app.service.stop Stop Service
auxiliary.webcontentresolver
Start a web service interface to content providers.
exploit.jdwp.check Open @jdwp-control and see which apps connect
exploit.pilfer.general.apnprovider
Reads APN content provider
exploit.pilfer.general.settingsprovider
Reads Settings content provider
information.datetime Print Date/Time
information.deviceinfo Get verbose device information
information.permissions Get a list of all permissions used by packages on the
device
scanner.activity.browsable Get all BROWSABLE activities that can be invoked from
the web browser
scanner.misc.native Find native components included in packages
scanner.misc.readablefiles Find world-readable files in the given folder
scanner.misc.secretcodes Search for secret codes that can be used from the
dialer
scanner.misc.sflagbinaries Find suid/sgid binaries in the given folder (default
is /system).
scanner.misc.writablefiles Find world-writable files in the given folder
scanner.provider.finduris Search for content providers that can be queried from
our context.
scanner.provider.injection Test content providers for SQL injection
vulnerabilities.
scanner.provider.sqltables Find tables accessible through SQL injection
vulnerabilities.
scanner.provider.traversal Test content providers for basic directory traversal
vulnerabilities.
shell.exec Execute a single Linux command.
shell.send Send an ASH shell to a remote listener.
shell.start Enter into an interactive Linux shell.
tools.file.download Download a File
tools.file.md5sum Get md5 Checksum of file
tools.file.size Get size of file
tools.file.upload Upload a File
tools.setup.busybox Install Busybox.
tools.setup.minimalsu Prepare 'minimal-su' binary installation on the
device.