In all our previous sections, we have discussed how apps are
built and run in detail. Hello everyone, welcome back again. Today, in this
section, we will be going to understand Android app sandboxing. This mechanism
ensures the security and isolation of each application within the Android
ecosystem.
Let's delve into the intricate layers of app sandboxing to gain a comprehensive understanding.
Understanding User IDs per Application
You're probably aware that Android is based on the Linux Kernel. The way users are kept
separate in Linux also applies to Android but with a slight twist. Let's break
it down by understanding how User IDs
(UIDs) are given to processes on regular Linux systems.
As usual, we're on a Kali Linux Virtual Machine. To examine
running processes owned by a specific user, we execute the command:
┌──(kali㉿kali)-[~]
└─$ ps -U kali
PID TTY TIME CMD
1052 ? 00:00:00 systemd
1053 ? 00:00:00 (sd-pam)
--------------more------------------
156930 ? 00:00:02 qterminal
156933 pts/0 00:00:05 zsh
157149 ? 00:00:03 adb
162552 ? 00:00:00 xfconfd
164127 ? 00:00:00 tumblerd
164336 ? 00:00:00 qterminal
164339 pts/1 00:00:01 zsh
164428 pts/1 00:00:00 ps
┌──(kali㉿kali)-[~]
└─$
This presents us with a list
of currently active processes associated with the user "kali."
To filter with specific processes associated with user
“kali”, run the same command with grep “specify the process name”.
┌──(kali㉿kali)-[~]
└─$ ps -U kali | grep "zsh\|mousepad"
156933 pts/0 00:00:05 zsh
164339 pts/1 00:00:04 zsh
164670 ? 00:00:01 mousepad
┌──(kali㉿kali)-[~]
└─$
As you can notice, we can see both processes
under the same User ID. But, it's different for Android apps.
Every app on your
device has its own unique User ID (UID). This makes sure that each app and its
stuff are kept separate from others, like being in their own little sandbox.
They can't reach each other's things.
To verify this, open a new terminal and run the command:
┌──(kali㉿kali)-[~]
└─$ adb devices
List of devices attached
192.168.95.118:5555 device
┌──(kali㉿kali)-[~]
└─$ adb shell ps | grep "u0"
u0_a61 1266 1022 3796852 86464 0 0 S com.android.inputmethod.latin
u0_a31 1276 1022 3922980 192168 0 0 S com.android.systemui
u0_a51 1578 1022 3786204 72968 0 0 S com.android.deskclock
u0_a22 1615 1022 3900064 176616 0 0 S com.android.launcher3
u0_a66 1638 1022 3781820 65288 0 0 S com.android.printspooler
u0_a10 1674 1022 3785688 84832 0 0 S android.process.media
u0_a14 1723 1022 3794748 76028 0 0 S com.android.dialer
u0_a5 1825 1022 3779492 74156 0 0 S com.android.providers.calendar
u0_a9 1843 1022 3785280 67652 0 0 S com.android.contacts
u0_a23 1885 1022 3779068 62576 0 0 S com.android.managedprovisioning
u0_a30 1902 1022 3781976 64380 0 0 S com.farmerbb.taskbar.androidx86
u0_a20 1919 1022 3787104 77240 0 0 S com.google.android.packageinstaller
┌──(kali㉿kali)-[~]
└─$
This will show you that each app gets a distinct UID. If
you look at the first part of the output, you'll see that every installed app
runs as its own user with names like u0_xx.
For instance, the dialer app goes
by the user u0_a14. You'll notice similar user names for other apps.
u0_a14 1723 1022 3794748 76028 0 0 S com.android.dialer
Remember, if two apps have the same developer key, it means,
they can share data with each other.
The User IDs (UIDs) assigned to users are distinct and
individual. For instance, the user u0_a14 corresponds to the UID 1723.
To
verify the correlation between users and UIDs on a rooted device, you can
inspect the `packages.xml` file found in the `/data/system/` directory.
┌──(kali㉿kali)-[~]
└─$ adb shell
x86_64:/ $ ls -l /data/system/packages.xml
-rw-rw---- 1 system system 365653 2023-08-24 16:54 /data/system/packages.xml
x86_64:/ $
It's
important to note that the internal configurations of Android can differ, and
therefore, this approach may not always yield precise results.
To grasp this concept better, let's take a closer look at
the UID mapping for some apps. But before that, let me run a user-installed app
to observe.
After running the app, use the ps command and check the first
column of the process.
┌──(kali㉿kali)-[~]
└─$ adb shell ps | grep "u0"
u0_a61 1266 1022 3796852 86464 0 0 S com.android.inputmethod.latin
u0_a31 1276 1022 3923236 193012 0 0 S com.android.systemui
u0_a51 1578 1022 3786204 72968 0 0 S com.android.deskclock
u0_a22 1615 1022 3891080 170316 0 0 S com.android.launcher3
u0_a66 1638 1022 3781820 65288 0 0 S com.android.printspooler
u0_a10 1674 1022 3785688 84832 0 0 S android.process.media
u0_a14 1723 1022 3794748 76028 0 0 S com.android.dialer
u0_a5 1825 1022 3779492 74156 0 0 S com.android.providers.calendar
u0_a9 1843 1022 3785280 67652 0 0 S com.android.contacts
u0_a23 1885 1022 3779068 62576 0 0 S com.android.managedprovisioning
u0_a30 1902 1022 3781976 64380 0 0 S com.farmerbb.taskbar.androidx86
u0_a20 1919 1022 3787104 77240 0 0 S com.google.android.packageinstaller
u0_a73 3245 1022 3846616 152620 0 0 S com.jetstartgames.chess
┌──(kali㉿kali)-[~]
└─$
In the provided example, the application resides within the
user u0_a73.
To delve further, we can investigate the underlying User ID (UID)
mapping. Open the terminal and enter the command "cat," followed by
the path to the `packages.xml` file.
x86_64:/ # cat /data/system/packages.xml
However, the output might be overwhelming, so I'll paste it
into a text editor for clarity.
From there, search for the app by its package name. Copy and
paste the package name in the search.
<package name="com.jetstartgames.chess" codePath="/data/app/com.jetstartgames.chess-AWAN-L4GToOwbH3oP1MY5A==" nativeLibraryPath="/data/app/com.jetstartgames.chess-AWAN-L4GToOwbH3oP1MY5A==/lib" publicFlags="973651524" privateFlags="0" ft="18a1de3bd38" it="18a1de3c0cc" ut="18a1de3c0cc" version="75" userId="10073">
<sigs count="1">
<cert index="14" key="308202b9308202220209008f2b5f0605259e76300d06092a864886f70d01010505003081a0310b300906035504061302646d310d300b06035504081304646a646a311330110603550407130a6a6b686b73646a66686a31153013060355040a130c6f696d6e66636b6a61736466311a3018060355040b13116a6b68676b6a6863796864626173646c66311430120603550403130b6862636c7a6b64797566673124302206092a864886f70d01090116156a6b6273646b666a6268406b666a7662682e636f6d301e170d3135303632363031333431385a170d3432313131303031333431385a3081a0310b300906035504061302646d310d300b06035504081304646a646a311330110603550407130a6a6b686b73646a66686a31153013060355040a130c6f696d6e66636b6a61736466311a3018060355040b13116a6b68676b6a6863796864626173646c66311430120603550403130b6862636c7a6b64797566673124302206092a864886f70d01090116156a6b6273646b666a6268406b666a7662682e636f6d30819f300d06092a864886f70d010101050003818d0030818902818100cde847c7c90c9453063c1849ad45095b13c354672d255e7891d5b85c998f99e3b8f4613a6c007fde1b645ead98ad2ca1ee31cefa10a6944d6805204d39a3abba836fda50c79c50f2f73f1290b2f6be3402cf1134e3c3270ac15a3b6b49a3eed3eef60101b4572c0c0e3db4aa3c98e6daa00dcbcace73181cbe3bd6a7959641bd0203010001300d06092a864886f70d010105050003818100c482ea8d6575dcb49a2e98a1ea7674addb253d85698d840cb585ffe924450933058cb98ade9100c941a6c7e496f82c2ea169fa9a950eda1237e0b5411b1566a60961774f9e774e5f04b2fbc3cccc75361671a870a8ed134bf7cc6d4746319e5098ff798964a9513c5302ad4d5b16fbe5dfe4e146022e8055a92d8642f5594f99" />
</sigs>
<perms>
<item name="android.permission.RECEIVE_BOOT_COMPLETED" granted="true" flags="0" />
<item name="android.permission.INTERNET" granted="true" flags="0" />
<item name="android.permission.ACCESS_NETWORK_STATE" granted="true" flags="0" />
<item name="android.permission.WAKE_LOCK" granted="true" flags="0" />
</perms>
<proper-signing-keyset identifier="28" />
</package>
If you see the field
userId="10073," it means that the app with the user u0_a73 is tied to
the userid 10073.
Now, let's consider a pre-installed app such as
"com.android.deskclock," which comes preloaded in the Android VM
under the user u0_a14.
<package name="com.android.deskclock" codePath="/system/app/DeskClock" nativeLibraryPath="/system/app/DeskClock/lib" publicFlags="944258629" privateFlags="0" ft="1685113a320" it="1685113a320" ut="1685113a320" version="27" userId="10051" isOrphaned="true">
<sigs count="1">
<cert index="2" />
</sigs>
<perms>
<item name="android.permission.RECEIVE_BOOT_COMPLETED" granted="true" flags="0" />
<item name="android.permission.DISABLE_KEYGUARD" granted="true" flags="0" />
<item name="android.permission.VIBRATE" granted="true" flags="0" />
<item name="android.permission.WAKE_LOCK" granted="true" flags="0" />
</perms>
<proper-signing-keyset identifier="3" />
</package>
Upon inspecting the `packages.xml` file, you will notice
that it is associated with the userId 10051.
App sandboxing
Previously, we differentiated Sandbox on Android and
Linux and then understood the UID per app on the Android app. Next, move forward to
app sandboxing.
App sandboxing is like giving each app its own private room
in the /data/data/ directory to keep its stuff. As we saw before, each app has
its own rightful ownership of this space.
This setup is like separating each app's belongings into its
own little box, or sandbox, within the /data/data/ directory. To see this in
action, you'd need a rooted device or emulator since the /data/data/ directory
isn't available to regular users.
To take a look, first get into your device's shell using
adb. Then, head over to the /data/data/ directory by typing: cd data
slash data/. Once you're in, run the command ls -l.
┌──(kali㉿kali)-[~]
└─$ adb shell
x86_64:/ $ su
x86_64:/ # cd /data/data
x86_64:/data/data # ls -l
total 720
drwx------ 4 system system 4096 2020-02-25 01:04 android
drwx------ 4 u0_a1 u0_a1 4096 2020-02-27 08:10 com.android.backupconfirm
drwx------ 5 u0_a43 u0_a43 4096 2020-02-15 10:12 com.android.camera2
drwx------ 4 u0_a41 u0_a41 4096 2020-02-12 04:42 com.android.captiveportallogin
------------------------more---------------------------
drwx------ 4 u0_a17 u0_a17 4096 2020-02-10 11:03 com.android.emergency
drwx------ 4 u0_a13 u0_a13 4096 2020-02-18 05:56 com.android.externalstorage
drwx------ 5 u0_a56 u0_a56 4096 2020-02-06 08:17 com.android.gallery3d
drwxr-x--x 4 u0_a58 u0_a58 4096 2020-03-05 06:43 com.android.htmlviewer
drwx------ 10 u0_a71 u0_a71 4096 2023-08-24 16:39 heartratemonitor.heartrate.pulse.pulseapp
drwxr-x--x 6 u0_a40 u0_a40 4096 2023-08-24 16:55 jackpal.androidterm
drwx------ 4 u0_a11 u0_a11 4096 2020-03-05 06:00 org.lineageos.eleven
drwx------ 4 system system 4096 2020-02-11 04:30 org.zeroxlab.util.tscal
x86_64:/data/data #
If you check out the file permissions, you'll see that each
app's directory is owned by itself. And they're not open for reading or writing
by other users. It's like each app's room is locked and only they have the key.
Can we break out of this protective sandbox?
Well, according
to Google, even though the app sandbox is strong, it's not completely
unbeatable. If someone really wants to break out of it on a properly set-up
device, they'd need to compromise the security of the Linux kernel – which is a
big deal.
Here's, where we get into Android rooting. Rooting gives
someone what's like a master key for an Android system. It's similar to having
the highest authority or being the ultimate boss in a game.
In the world of computers, we call this "root"
level the supreme user level. It's like being the king or queen of the system
with the power to do anything. Normally, only the Android system's essential
parts, like the kernel, run as this "root." But when you root your
device, you're kind of opening the doors for all apps to have that same power.
So, imagine if everyone in your town suddenly became the
mayor. They could change everything, including the roads, the buildings, and
even the rules. In the Android world, when apps get this power, they can tinker
with the system's core parts – the kernel and other apps. They can even mess
with an app's personal space, the sandbox, by breaking out of it.
Just like in real life, having great power means great
responsibility. But with great rooting comes great risk. It's a trade-off
between freedom and security in the Android universe.
This compilation of insights provides us with a profound
comprehension of the internal mechanisms of Android apps. Throughout this
playlist, we've focused on grasping these internal workings, which serve as a
foundational step toward delving into Android security. The objective of this
playlist has been to furnish you with these pivotal concepts.
In our
forthcoming playlist, we'll explore the overarching strategies for targeting
Android applications.
If you have any questions related to this article, feel free
to write them in the comments section.