Fighting the BS in mobile application security.

Neeraj Nigam
10 min readFeb 18, 2021

I am an application security engineer. For me, security is all about making apps better and more secure. However, sometimes I come across many security engineers who invent issues out of thin air and justify them as these issues are mentioned in “Bhagwat Geeta” and came from the mouth of Lord Krishna itself. In the next section, I am going through a long rant about how security should be approached when it comes to client-side application security checks.

TLDR –

· All the attack scenarios mentioned below cannot be prevented 100% by any means.

· There will always be a bypass available for any security measure implemented for these client-side attacks.

· The physical security of a device is with the device User.

· The application developers can only implement preventive measures to an extent.

· The security measures should be implemented till it justifies cost associated as compared to the risk factor of the application code and data.

· The mobile applications should be treated as client-side code and sensitive logic should be offloaded to a secure backend whenever possible.

· The absence of client-side security checks can not be termed as “vulnerabilities” as all of them require physical access to the device. The only check which should be present is the root detection check. Rest all are optional, and kind of like post-exploitation scenarios.

· These checks are just added layers of security and it is up to the risk assessment teams to decide what checks are required and to what extent they are willing to go to implement these checks.

· If an application stores session token, PII data. Etc. in internal local storage, it doesn’t make it vulnerable to attacks. On a non-rooted device, internal storage of mobile devices provides more security compared to a web browser’s cookie storage systems or local storage. However, there are more secure options available on the android and iOS platforms for this kind of sensitive data storage. These systems should be preferred whenever possible over storing plain text data in internal storage

Root detection bypass

The android OS is built on top of the Linux kernel and follows the same user-group feature for security available in Linux-based OS.

A root user is a superuser who can access practically everything in the device including recovery storage, kernel, the private container of every application. In addition to this, the root user can also access CPU, RAM, ROM, etc., and have full control over the device, its software, and hardware. Some manufacturers do lock android boot-loader from root user access and it differs from OEM to OEM.

Rooting an android device means gaining access to the root user, which is not available by default. To root android devices there are multiple ways, finding an exploit in the android kernel and escalating privileges to the root user (using an existing application) or creating a root user by modifying the android system via android recovery. The first method to root a device is very rare as android is actively maintained and issues regular security patches. The second method of rooting is more common and easy, however, if someone tries to root an existing device using android recovery (the second method) it wipes all local data on the device due to native storage encryption enforced by the android system.

A user upon rooting via recovery gets a clean rooted device, he can install the apps again however he will lose all previously generated data present in the device.

Rooting a device with the privilege escalation method does not wipe the internal data.

Root detection:

Root detection is a method to identify if a device allows the root user access to the user/app by any means. This can be achieved in multiple ways, a few of those are — detecting “super su” binary, detecting system partition permissions (r+w), detecting root apps, detecting compromised integrity of the android system, detecting malware, etc.

The android apps are client-side apps and the code of the application runs on a device that is not controlled by the application developer. It also implies that the application code is available in public and if a User tries hard enough he can invoke any portion of the code upon his wish, just like the HTML code present in the web browser. A developer can make it hard for a User from tampering with the application code however it is nearly impossible to prevent it completely due to this nature of the android applications (and all client-side applications such as HTML/js code, android applications, ios apps, and even thick client applications). It is advised to not use any sensitive logic which should not be accessible to the particular user in the client-side applications (APK, IPA). The application developer should make sure that the user has access only to his account and functionalities assigned to him, all the user identity verification controls should be implemented at the application’s backend.

With the above-said statement why even report a rooted device?

Root detection bypass:

It is possible that some users who are using rooted devices do not completely understand the security risks associated with a rooted device, hence It is the responsibility of the developer to notify the Users about the compromised device/rooted device and risks associated with such devices. The developer should implement a basic root check with all possible root detection methods for the users who are unaware of the consequences of a rooted device. However, this does not stop the user from completely removing the root detection logic from the application, even it is impossible to implement such a feature that is 100% tamper-proof while running in an attacker-controlled environment. This makes fixing the “root detection bypass” issue unreasonable. Yes, if an application misses few root checks it should be corrected. However, fixing bypasses to root checks which incorporates application tampering with Frida hooks, modifying runtime memory, or tampering with the application code is not fruitful in terms of effort and cost of development.

Certificate Pinning bypass:

SSL/TLS

SSL/TLS stands for secure socket layer and transport layer security. As mentioned in the name it is a security mechanism used to secure the socket connections. It provides security to all the application layer protocols such as FTP, HTTP. It also provides security to those applications that use transport layer protocol TCP as a mode of communication. SSL/TLS uses encryption to prevent an unauthorized eavesdropper from reading the transported data. It basically prevents various types of man-in-the-middle attacks. To use TLS, the User device negotiates an encryption key with the server backend and uses this key to encrypt all data transported between the user device to the server and vice versa. This encryption prevents anyone from reading the data in the network as each request to the server is now encrypted using strong encryption.

SSL Pinning:

The few weaknesses to TLS are following

Ø If the encryption keys are leaked by either the server or user device the connection is compromised.

Ø If an attacker is able to intercept the key during negotiation.

Ø If the user device is not able to properly identify the backend server and wrongly negotiate encryption keys with an attacker-controlled server.

The SSL pinning concerns the third scenario where the user device negotiates encryption keys with the attacker-controlled server thinking of it as a genuine application backend, and the attacker-controlled server acts as a proxy to the application backend. This makes the attacker a man in the middle, he can read and tamper with all the communication between the user device and backend server.

To prevent such proxy-based man-in-the-middle attacks the application should properly identify certificate signing authority and should not allow any communication with the backend if the server certificate is invalid. However, to identify certificate authority android system uses pre-installed certificate authorities. These preinstalled certificates are installed in the android system and a non-root user cannot tamper with these certificates. For self-signed certificates, the user needs to manually install them into the android device. This requires the user to enable the android screen lock feature as these certificates are stored using encryption in a device with screen lock as an encryption key. Also, the android system displays a notification in the notification bar saying “network is being monitored” if a user installs a self-signed certificate into the system. Theoretically, all the communication from the device can be intercepted by a proxy server that has hold of this user’s installed self-signed certificate.

To pull this man in the middle attack the attacker needs to

Ø Unlock the user device using screen-lock, pin, or pattern

Ø Successfully installed self-signed certificate

Ø Successfully route the data via his proxy server.

Ø Make sure the attacker-controlled proxy is reachable via the user device.

Ø Hope user ignores the “device network is monitored” notification in the notification bar.

If an attacker can complete all these steps, he can intercept all the traffic from the user device in his proxy server (this excludes traffic from web-view components as from android 6.0, android has disabled use of user-installed certificates in web-views).

What does certificate pinning do?

Certificate pinning is a feature in which an application developer discards system and user certificates and uses their own certificate while identifying server identity. This prevents anyone from setting up a proxy and starts listening to the device to backend communication. However, certificate pinning is again a client-side measure. If the device is compromised (rooted) or the user himself tries to read what data his device is sending to the backend no one can stop him, the application developer can only make it hard. Due to this reason, any data coming from the client device should be treated as untrusted data and all the validations should be implemented at the application backend.

The whole idea of TLS/SSL and Certificate pinning is to prevent a third party from eavesdropping in the communication between user device and backend. If the User itself is compromised all these security measures do not make sense, and to prevent such scenarios the application backend should implement proper measures.

Data in the memory dump

What is a memory dump?

All the applications running on the android devices are assigned a user-id and group-id. The application data such as internally generated files and run-time memory are protected from other applications in an isolated container. Only the processes running as root users have access to the /proc/ filesystem, these apps can access all the runtime memory allocations and data for each process on a Linux-based system. Since Android OS is built on top of Linux it follows the same architecture for security.

A Memory dump is a snapshot of the memory of any running process at an instance. Since the process uses random access memory for its execution each variable, function, object, file stream, etc. can be located inside a process’s memory. The memory for a process does contain sensitive information like cryptography keys, keys related to SSL/TLS, the sensitive information such as passwords or any data generated by the application at runtime. The memory dump can be helpful for developers in identifying various memory-related issues such as memory leaks, out-of-memory errors, etc.

However, to dump the memory of a running process, the User can either do it on a rooted device or by hooking into the process (again on a rooted device, or by patching the application with a custom hook patch).

Memory dump prevention

The memory dump is a good way to either debug the application or use it to reverse engineer the application, and like other client-side attacks like root detection and certificate pinning, there is no 100% certainty that an application can prevent it. However, an application can implement root detection and code tampering checks to prevent (to some extent) someone from taking a memory dump.

Few security analysts suggest that sensitive information should be short-lived in the memory and the objects should be destroyed once they are no longer in use, however, this is again pointless as in a rooted environment an attacker can specifically choose which lines of code should execute and what can be omitted, this allows an attacker to record values of these short-lived objects. Even the variables created in function calls are stored on the memory stack and can be read during runtime. No matter how short-lived an object or data is, it can be intercepted with the help of a debugger since application code is executed line by line and a debugger (Frida hook, objection, etc) can read theoretically every data generated during runtime by the application in a rooted device.

Sensitive data in plain text in local storage

The android local storage is protected as an isolated container from other applications. Even the plain text Shared Preference file cannot be accessed on a non-rooted device unless explicitly created as world-readable (deprecated starting on API level 17.).

The internal storage of an application can be considered as cookie storage or local storage in a web browser (although in web browsers anyone can access cookie storage and local storage without root). Unless an application deliberately exposes data by misconfigured IPC there is no method available to read Internal application data without root. In the case of a rooted device, the User itself becomes an attacker and he should be less interested in seeing his own PII data in a plain text format.

However, in critical applications such as banking and payment services PCI/DSS compliance ask developers to encrypt internal storage and store the keys in a secure location. In the case of financial applications, it makes sense too, as financial applications have a huge motivational factor for attackers to go through all the hassles of obtaining the secret internal data. In the case of financial applications, this internal data is more valuable than the effort required to obtain that data, hence the extra layer of security weighs the effort required to implement those checks.

In the end, I can only wish that security analysts can become more mature while reporting these issues as our job is to enhance security and not make life miserable for poor developers.

--

--