Threats for Mobile applications
As web and desktop applications, mobile applications also bring several threats that could lead to the data used by the application being compromised or even go further if the attacker is able to find information about the back-end system.
In practice, the application should ensure that the data stored on the device is securely stored and that the network traffic cannot be intercepted in order to read information. In addition, if the data are sensitive, like in banking applications, the application should ensure that the device is compliant with the vendor’s security rules. In fact, the application should check if the device is rooted for Android systems or jailbroken for iOS systems. Plus, the application should also check if it was altered or running in debug mode. If these checks are not made, the data used by the application could be prone to attackers in case of the installation of an application containing malware.
Another threat for mobile applications, like desktops, is that the applications are provided to users and they could reverse the application. In the case of intellectual properties, the vendor is recommended to obfuscate the application to avoid competitors from easily reversing algorithms and being able to copy it without research and development cost. Besides, obfuscation should also be used to protect the whole application from attackers that could alter it and use it maliciously.
If the vendors/developers do not know the threats for mobile applications, an attacker could be able to perform malicious actions.
For example, if no certificate pinning is in place, it would be possible for an attacker to intercept data and view the content of requests made by the application with a man in the middle position.
Then, if the application is not properly secured – does not detect the root state of the device – it would be possible for an attacker to use it on a rooted/jailbroken take memory dump, view hidden files, or bypass security features provided by the operating system.
Finally, even when the application implements these security features, if there is no obfuscation, an attacker could reverse engineer the application and bypass them, although it would take a considerable time. By doing so, the security measures established by the application would no longer be effective.
A quick view of a Xamarin Android pentest
The following steps were made during a pentest of a mobile application. This section will be limited to Xamarin Android applications, but several steps could also be reproduced with other types of frameworks and on iOS.
First usage of the application
When a client gives an application to the consultant, the first step is to install it on both rooted and non-rooted devices to check its behaviour. This also allows the pentester to have a quick overview of the application and its functionalities.
A second step is to unpack and repack the application with the Apktool utility. The pentester unpacks, repacks and signs the APK without alteration. In some cases, the application checks its integrity, and that kind of test allows the tester to get a quick answer on that point.
In the case of a mobile pentest that will be detailed further in this article, the application was not running on a rooted device and an integrity check was made before the start of the application. Therefore, one of the objectives of the pentest was to try to bypass the integrity checks and root detection.
The application could be installed by using the PlayStore or the provided APK directly. Then, the application could be extracted on a workstation to be analyzed.
The following step was to unpack the application to check the content. This can be compared to just unzipping a zip file. The archive contains files that are present for the operating system, like the Manifest. This file will give information about the permission that the application needs, the services that will be installed, and some flags like the one allowing the application to be debugged or not. Then, most of the other files are the application itself and the resources like images or translation files. With android, the source code is compiled and stored in a DEX file. For example, that file could be reversed by using the tool jadx. With the source code, the pentester could be able to check some security features by searching patterns like isrooted, isjailbroken, iscompliant, integrity check, certificates, pinning, and more. That could help the pentester find interesting functions that should be bypassed to go deeper during the pentest.
In that case, the application embeds some DLL. That gave some clues to the pentester that the application could be developed with the Xamarin framework. Like the DEX file, the DLL could also be reversed by using a tool like DNSpy . However, these DLL are in a specific format, see below the XALZ as magic bytes and not the wanted MZ.
With some research, the pentester found the Xamarin decompress GitHub tool to retrieve the DLL in the good format.
Then the DLL was opened with DNSpy to retrieve the C# source code. After that step, the pentester searched for functions like IntegrityCheck or isRooted for example. In addition, as the application displayed an error message in case of root detected or integrity change, the pentester also searched for that string and tried to go back all the call-ins in order to find a function to alter.
This research finished on the following OnAppearing function. That function calls two functions checking the root stat and the integrity check and stores the result on a Boolean wasCompromised.
The wasCompromised variable is given to a function named DisabledIfCompromised that shows the error message previously found. That function then calls indefinitely itself to block access to the application. However, if the Boolean given is false, the function does nothing and the standard flow of the application will be followed with the last 5 lines of that function.
It should be noticed that the application is using the DotFuscator tool. The purpose of that tool is to check the root detection and perform integrity checks. The second function used was a customed one that will check some files that could inform the application that the device is rooted.
After finding the desired function to alter, the pentester should alter it and repack the application.
For that, the pentester used the DNSpy as it makes it possible to update the assembly and save the result in a new DLL.
The first try was to edit the C# code. However, some references were not found by the tool as the code was compiled still a bit obfuscated due to DotFuscator for example.
Therefore, the pentester tried to update the code by updating the IL code directly. The IL code, or “intermediate language”, is a kind of assembly language but not directly executed on the CPU. An additional step will be made by the framework to interpret that intermediate language and translate it into valid Android or iOS instructions.
The following picture shows the IL code for the end of the function. The pentester just needs to remove the beginning of the function to keep only the part that calls the HomePage function which is a kind of entry point of the application.
A tricky point is that the IL code cannot be changed. If the pentester removes the lines, the offset of some function and code will be changed since it can contain relative jumps, for instance.
Therefore, the technique used was to replace the instruction with NOP. The NOP instruction, for No OPperation, is like an empty line. When the NOP is interpreted, the CPU does nothing except increment the instruction pointer to go to the next instruction. Therefore, the pentester replaced all non-wanted instructions with NOPs. The following screenshot shows the NOP from line 1 (which is hidden) to line 159.
Then by validating the change, the DNSpy tool shows the new code. This one only contains the instructions to run the HomePage of the application.
The next step was to save the assembly thanks to DNSpy and replace the original with the altered one. We can notice that the compression of the DLL was not mandatory even if other DLL are compressed.
By following these steps, the pentester was able to bypass the root detection and the integrity check.
Another bypass? Xamarin App
The application also implements custom certificate pinning. This one is working well, but like most certificate pinning checks, the weakest point of the chain is a function that takes a certificate as input and some other parameters and just returns a Boolean. If the function returns true, that implies that the certificate is trusted and is the good one. However, if the application is using a custom certificate, like the one of Burp, the function will return false.
By finding that function, the pentester was able to repeat the steps in the previous section to alter the function and replace all the code by a simple “return true”.
Again, by replacing the instruction with NOPs like so:
The ValidateServerCertficate function now simply returns true.
Consequences for Xamarin App
With that action, the pentester was also able to bypass the certificate pinning and analyze the network traffic between the application and the server. In some cases, Web application could be used to get the calls that could be made on the server, but in the case of this mobile application, it made some additional requests to the API server that the Web application did not.
Therefore, by reversing the mobile application and bypassing the integrity check, the root detection, and the certificate pinning, the pentester was able to go deeper and try some attacks on the API server.
The key to success for the pentester was to be able to find the function that checks the root and integrity easily. That was due to the name of the function and the possibility to trace the call from the string displayed on the error message. Another point was the fact that only one alteration should be made in order to bypass one security feature.
To remediate that kind of issue, the obfuscation should be increased, especially on security features. Some companies can spend a lot of money to obfuscate some intellectual properties like algorithms, but the same process should be used on security features.
The name of function could be changed to not contain root, jailbreak, check, pinning, integrity, compliant, etc. That kind of obfuscation could be made directly by the developers.
Then, if the company uses a third-party tool, like DotFuscator, this one should be customized to use all the functionalities and in the higher compatible mode. The pentester should not be able to understand how the root detection and integrity check was made. If these two functions are not bypassable without spending a huge amount of time, the certificate pinning will not be bypassable either as it is not possible to alter the application due to the integrity check.
Xamarin App in a nutshell
Even if the company spends some time and money to add security features, these could be bypassable if the application can be reversed easily and if the result is human readable.
Some third parties allow to have good detection of the root state of the device, to have an integrity check or to implement certificate pinning, but if the application is not enough obfuscated, all these security features are not useful.
Sensitive functionalities like business functions should be obfuscated in order to ensure the secret of an algorithm for example, but obfuscation should also occur on security features that were implemented in order to harden the application and avoid the attacker to be able to perform malicious action with these.
- OWASP Mobile Security Testing Guide
- Mobile_App_Security_Checklist-English_1.1.2_xamarin.xlsx – Google Drive
- Decompressing Xamarin DLLs | X41 D-SEC (x41-dsec.de)
- NickstaDB/xamarin-decompress: Decompress Xamarin .NET compressed binaries so they can be decompiled. (github.com)
- Xamarin | Open-source mobile app platform for .NET (microsoft.com)
- dnSpyEx/dnSpy: Revival of the well known .NET debugger and assembly editor, dnSpy (github.com)
Did you like the reading? Find more articles in our blog section.