With the widespread use of mobile applications and the growing concern for mobile app security, it has become crucial for developers to ensure the integrity and security of their Android applications.
One effective approach for identifying potential security vulnerabilities in Android apps is static analysis. Static analysis involves analyzing the source code of an application without executing it, to detect potential issues and vulnerabilities early in the development process.
In this blog post, we will explore the OWASP (Open Web Application Security Project) Top 10 list of the most critical security risks in Android applications, and how static analysis can help mitigate these risks.
We will also discuss some popular tools used for static analysis of Android applications that can aid developers in identifying security vulnerabilities and improving the overall security posture of their apps.
So, let’s dive in and understand how static analysis can play a critical role in securing Android apps!
Before delving deep into the blog, let us shed some light on two of the major terms that we should be aware of in the context of static analysis of Android.
Android is an open-source mobile operating system that runs on a wide range of devices, including smartphones, tablets, smart TVs, and more.
The architecture of Android is divided into four main components: the Linux kernel, the Android Runtime (ART), the Libraries, and the Application Framework.
The Linux kernel provides the core functionalities of the operating system, such as device drivers, process management, memory management, and security. Above the Linux kernel, the Android Runtime (ART) is responsible for executing and managing the applications.
ART compiles the Java code into a machine-readable format during the installation process, which makes the apps run faster.
The Libraries component contains various libraries written in C and C++, such as SQLite for database management, OpenGL for graphics rendering, and more.
The Application Framework provides higher-level tools and APIs for app developers to build user interfaces, handle user input, manage resources, and interact with system services. It includes components like Activities, Services, Broadcast Receivers, and Content Providers, which are essential for building robust Android applications.
Apps developed on Android are based on this architecture, with the Java or Kotlin code running in the Android Runtime and leveraging the libraries and APIs provided by the Application Framework to create rich, interactive, and feature-rich mobile applications.
To know more about Mobile Application Penetration Testing, you can read our blog here.
Static analysis in Android refers to a method of analyzing the source code or compiled code of an Android application without actually executing it.
It involves examining the code to identify potential issues, vulnerabilities, and code smells, as well as checking for compliance with coding standards and best practices. Static analysis is typically performed using specialized tools or plugins during the development process or as part of an automated build or continuous integration (CI) pipeline.
Static analysis in Android can help identify a wide range of issues, such as code quality problems, security vulnerabilities, performance bottlenecks, and potential crashes.
It can detect issues like unused variables, dead code, improper resource handling, memory leaks, and improper permissions usage. Static analysis can also detect security vulnerabilities such as improper input validation, insecure data storage, and potential code injection attacks.
Additionally, static analysis can check for adherence to coding standards, naming conventions, and other best practices, ensuring that the codebase is maintainable and efficient.
In this analysis, the bugs to look at in the Android applications are – excessive permission, hardcoded credentials, weak cryptographic functions, workflow bypass, hidden features, improper log management, insecure storage, etc.
The Application that we are going to use in this blog will be [InsecureBankV2].
The tool required for static code analysis is [Jadx-gui].
This tool will decode the contents of the apk file and convert the dex file into human-readable code. Previously, the tools that were used for doing the same are apktool and dex2jar.
For pentesting Android application, it is preferred to use a physical device rather than using Genymotion as it has certain limitations for the free version also it messes up the virtual network if using other virtual machine software on the system.
So Let us get started!
We will start with a static code analysis of the InsecureBankV2 application.
Note – The first thing to always check while doing static analysis is the Android Manifest file, this file will provide an abstract-level understanding of application permissions and different components of the application.
The basic vulnerabilities in Android Manifest files are Debuggable and Backup.
If the **android:debuggable=”true”** is in the android manifest file, then it provides the capability of running commands on behalf of the application by any other application or through an ADB shell.
In Layman’s terms, the application files can be accessed and activities can be triggered by ADB shell commands or through any application on the device.
The normal user in the ADB shell can go to the directory but it cannot list or access the contents present in the directory.
To access the contents the user needs to switch to application user to u0_a125 as in Android, every application has its unique username.
The impactful thing with debuggable is to launch activities through adb shell.
Note that the activities with exported=”true” can be accessed from outside the application.
Here we’ll access *”com.android.insecurebankv2.PostLogin”* as it has exported property set to true.
The activity starts through adb shell using the following command:
`am start -n <application_packagename>/<application_activityname>`
“`bash
athene_f:/data/data/com.android.insecurebankv2 $ am start -n com.android.insecurebankv2/com.android.insecurebankv2.PostLogin
The Login functionality is the bypass in this scenario and the application is ready to access with full functionality. Similarly, it is done with other exported activities as well.
If the **android:allowBackup=”true”** in the android manifest file, then it provides the capability to back up the application and all its data into a single file.
You can do it through the ADB shell using the following command:
`adb backup -f backup.ab <application_Package_name>`
“`bash
PS C:\Users\B0RN2R00T> adb backup -f insecurebank-backup.ab com.android.insecurebankv2
“`
`dd if=<bacnup-filename> bs=1 skip=24 | python -c “import zlib,sys;sys.stdout.write(zlib.decompress(sys.stdin.read()))” | tar -xvf -`
The above command is explained below:
– dd: This command requires an input file and creates an output file as options provided. So here it will create a file that will not include the first 24 bytes of data of the backup file. The rest of the data will be a zlib compressed file.
Python: The Python command will then convert the zlib file into the tar archive.
tar: The commands below will decompress the tar archive back into its original file contents.
“`bash
b0rn2r00t[11:50:47] /mnt/c/Users/B0RN2R00T/tmp $ dd if=insecurebank-backup.ab bs=1 skip=24 | python -c “import zlib,sys;sys.stdout.write(zlib.decompress(sys.stdin.read( \
)))” | tar -xvf –
“`
Now, the backup file has been extracted into respective folders and files, and digging into each file has to harvest sensitive information about the application which could not accessible otherwise.
Understanding the code requires fundamental knowledge of Java syntax. For example, how is a variable declared in Java? How are the functions declared and called in Java? how do the conditional statements work in Java? Among other things.
It is always suggested to have knowledge of the fundamentals of Java code before diving into static analysis for understanding and finding the maximum number of bugs in the code.
“`java
HttpPost httppost2 = new HttpPost(DoLogin.this.protocol + DoLogin.this.serverip + “:” + DoLogin.this.serverport + “/devlogin”);
“`
Here, it is creating the URL string which will be “http://< server-ip>:< server-port>/devlogin”. The *”/devlogin”* endpoint is a backdoor for developers to login into the application.
But, there is no proper authentication in place and the developer forgot to remove it from the production application which can lead to an endpoint disclosure to everyone who is using this application.
The reason it is not validating properly for authentication is because of the following code:
“`java
HttpPost httppost2 = new HttpPost(DoLogin.this.protocol + DoLogin.this.serverip + “:” + DoLogin.this.serverport + “/devlogin”);
List<NameValuePair> nameValuePairs = new ArrayList<>(2);
nameValuePairs.add(new BasicNameValuePair(“username”, DoLogin.this.username));
nameValuePairs.add(new BasicNameValuePair(“password”, DoLogin.this.password));
if (DoLogin.this.username.equals(“devadmin”)) {
httppost2.setEntity(new UrlEncodedFormEntity(nameValuePairs));
responseBody = httpclient.execute(httppost2);
}
“`
In the above code, `DoLogin.this.username.equals(“devadmin”)` only checks for if the username is **”devadmin”** and allows login through *”/devlogin”* endpoint with any random password value.
In Layman’s terms, anyone can gain unauthorized access to an application with the username **”devadmin”**.
After digging more into the code, it was observed that the credential of users was stored on the device in **”mySharedPreferences.xml”** file using AES encryption specified in **”CryptoClass()”**.
“`java
private void saveCreds(String username, String password) throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
SharedPreferences.Editor editor = DoLogin.this.getSharedPreferences(“mySharedPreferences”, 0).edit();
DoLogin.this.rememberme_username = username;
DoLogin.this.rememberme_password = password;
String base64Username = new String(Base64.encodeToString(DoLogin.this.rememberme_username.getBytes(), 4));
CryptoClass crypt = new CryptoClass();
DoLogin.this.superSecurePassword = crypt.aesEncryptedString(DoLogin.this.rememberme_password);
editor.commit();
}
“`
The code that is responsible for encrypting the credentials is present in
“com.android.insecurebankv2.CryptoClass”
AES requires two things for encryption and decryption:
Note – Using a strong key and a unique IV in AES encryption and decryption is critical to ensure the confidentiality and integrity of the encrypted data.
As seen in the code the iv value is 16 bytes of 0’s and the key string is **”This is the super-secret key 123″**. Now to decrypt the encrypted *”superSecurePassword”* stored in *”mySharedPreferences.xml”* file decryption code is required which is provided as below:
“`python
from Crypto.Cipher import AES
import base64
key = b”This is the super secret key 123″
ivBytes = b”\x00″*16
password = base64.b64decode(“DTrW2VXjSoFdg0e61fHxJg==”)
aes = AES.new(key, AES.MODE_CBC, ivBytes)
decrypted_password = aes.decrypt(password)
print(decrypted_password)
Now let us have a look into **View Statement** the code responsible for this functionality is present at **”com.android.insecurebankv2.ViewStatement”**.
“`java
File fileToCheck = new File(Environment.getExternalStorageDirectory(), “Statements_” + this.uname + “.html”);
“`
The above code is simply checking if the file is available to fetch or not. It is also checking the availability of the file at a specific location.
The interesting thing about the code is the location where the file is stored which is at external storage, the *”getExternalStorageDirectory()”* means *”sdcard/*” which is publicly accessible. So anyone with access to the file can view or edit the contents.
But the vulnerable part of this code is that it stores the statements in the form of an HTML file which can later be fetched by the below code.
“`java
mWebView.loadUrl(“file://” + Environment.getExternalStorageDirectory() + “/Statements_” + this.uname + “.html”);
“`
So, the file URI will look something like this: `file://sdcard/Statements_<username>.html`
To exploit this issue, just include malicious JavaScript code in the Statement file. Whenever the program attempts to execute **ViewStatement** functionality, the malicious JavaScript code hidden within the Statement file will also be executed.
Introducing SecureLayer7’s Static Analysis for Android, the cutting-edge solution that helps you protect your Android apps from potential security risks. With the rapid growth of mobile apps and increasing cyber threats, it’s crucial to ensure your Android apps are secure and resilient.
That’s where SecureLayer7 comes in.
Our advanced static analysis technology employs a comprehensive and automated approach to scan your Android app’s source code, bytecode, and other components for vulnerabilities, malicious code, and risky practices. Our solution goes beyond traditional scanning techniques to provide deep code analysis, identifying hidden threats that could be missed by other tools.
Don’t leave the security of your Android apps to chance. Partner with SecureLayer7’s Static Analysis for Android to ensure your apps are protected from security threats.
Contact us today to learn more about our advanced static analysis services and take your Android app security to the next level!