What makes web applications an easy target for hackers?


Web applications form a major part of an organization’s attack surface and according to Verizon’s 2020 Data Breach Investigation Report, web applications are the single most significant cause for data breaches. Web application attacks account for 43% of all successful data breaches. 

These websites contain several vulnerabilities such as Remote Code Execution (RCE), Server-Side Request Forgery (SSRF), Local File Inclusion (LFI), Server Side Template Injection (SSTI), and more. Some of these vulnerabilities allow intrusion of corporate networks. These vulnerabilities are the result of mistakes that programmers make. Developers trust and hope that their applications will end up in the right hands, which often turns out to be the biggest mistake they ever made. 

In this multi-part series about web apps, we explore the common mistakes and threats affecting web applications, as well as point out factors regarding applications that appeal to threat actors. The first part of this multi-part series focuses on web app user input and the pitfalls of not validating or sanitizing it. The article also sheds a light on the steps one can take to prevent application attacks and reduce vulnerabilities.


Rule #1: Never trust user input

While developing an application, web programmers should refrain from accepting data from users and in fact should presume all data is bad until proven otherwise. This is how threat actors leverage different vulnerabilities:  


Remote Code Execution

In an instance where the Image File Upload functionality of an application uploads the filename and contents onto a server, the server processes it further. However, if the application doesn’t validate user inputs, it permits the attacker to upload the server side language extension file, such as the .php file. This further allows the attacker to execute OS commands on the server.


Local File Inclusion 

Similarly, when web applications are coded poorly, hackers can inject local files into the include statements. For instance, an attacker can exploit the Local File Inclusion vulnerability by changing the path of a PDF file with that of another sensitive file such as passwd. If the application doesn’t validate the input, the attacker can simply read internal server files.



Test URL: https://vulnerable.site/somefile.php?file=validpdffile.pdf


Attacking URL: https://vulnerable.site/somefile.php?file=../etc/passwd


Server Side Request Forgery

In an attack that exploits this vulnerability hackers gain partial or complete access to the requests sent by the application, to abuse a functionality. This allows them to make the server-side application to configure HTTP requests that lead to malicious domains of the attacker’s choice. If the website does not validate the user input, the hacker can access internal server files and more.



Test URL: https://vulneralbe.site/somefile.php?filetocall=https://external.site/somefile.js


Attacking URL: https://vulneralbe.site/somefile.php?filetocall=file:///etc/passwd


SQL Injection

This vulnerability allows hackers to insert or inject a query into an entry field, so as to execute malicious SQL statements. This enables actors to retrieve sensitive data from the database evading any security measures.



Test URL:https://targetsite.com/somefile.php?id=2

However, if the web application does not validate the user input, the attacker can submit something like this:

Attacking URL: https://targetsite.com/somefile.php?id=’ OR ‘1’=’1’–+

From the above instances and scenarios it is clear that if the user input is not properly validated or sanitized, most web app vulnerabilities can be exploited, eventually leading to breaches and data loss.


How can you reduce vulnerabilities and prevent attacks

Let us look at the issue at hand before we suggest a solution. The following instance summarizes the problem:

This is a test application that accepts the user input and returns results based on it.

Web App normal search

An average user looks up topics such as Python or JAVA, while hackers with a malicious intent would submit something like this:

Web App unvalidated

There are a number of symbols we can inject, such as a single quote(‘), double quotes (“), open, closed angle brackets (<>), equals to (=), and open, closed brackets [()], and if the web application accepts these without validating them, attackers can used this as a weapon to steal session cookies of other people, by using advanced XSS payloads (Cross-Site scripting payloads).

Now, let’s try to understand the logic of the code:

Web App coding gone bad

The GET variable named $_GET[‘vulnparam’] at the TOP accepts the user input, which then allows the webapp to proceed with that variable name $vulparam. As you may have noticed, the user input variable $_GET[‘vulnparam’] is not validated. The web application is using it as it is.

The right way to code

In order to validate the user input first, we use the htmlentities() function that converts characters and symbols to HTML entities. This helps to prevent Cross-site Scripting (XSS) attacks and the web app proceeds further with the encoded user input.



Almost every OWASP Web Vulnerability is exploited in real world websites as web applications fail to properly validate user input, before processing it. Therefore, it is important that app developers and security testers regularly collaborate with each other. Once the programmer has built a particular feature or an app, security testers can test it before deploying them on the prod servers. Ultimately, this will save them a lot of time and prevent any data loss that could have resulted from exploitation. 

Why attackers can't resist Android apps

Why attackers can’t resist Android applications

In their quest for new attack surfaces, threat actors find easy targets among the ~2.7 million Android applications, ad infinitum.

What makes Android applications irresistible targets? 

  1. The ease with which an attacker can acquire the entire source code of an Android application.
  2. The source codes often contain API keys, secret tokens, sensitive credentials, and endpoints, which developers forget to remove after staging.

Developers often lack awareness about attack vectors on a mobile app. Owing to a false sense of security, provided by the sandboxed and permission-oriented operating systems. However, mobile apps have the same attack vectors as web apps, albeit with different exploitation techniques. 

When an attacker meets an Android app

After getting their hands on an Android app’s source code, attackers first decompile it, analyse it for weaknesses, and then exploit it.

Decompiling the source code

The attacker first extracts files and folders from the apk file of an Android app, which is similar to unzipping a zip file. However, the files are compiled. To read the source code, the files are decompiled using:     

  • Apktool: To read the AndroidManifest.xml file. It also disassembles to small code and allows to repack the apk after modifications.
  • Dex2jar: To convert the Dex file into a Jar file.
  • Jadx/Jd-gui: To read the code in GUI format.

Analysing the source code

The attacker analyses the source code using 2 methods: 

  • Static Analysis
  • Dynamic Analysis

Static Analysis

In this approach, the attacker examines the source code for secret tokens, API keys, credentials, and secret paths. They also understand the source code, check for activities, content providers, broadcast receivers, vulnerable permissions, local storage, sensitive files, etc.

Here are some examples of what attackers look for during static analysis:

Sensitive Information 

As we can see, the strings.xml file below exposes sensitive information such as API keys, bucket name, Firebase database URL, etc.

strings.xml file exposes sensitive information about the Android app
strings.xml file exposes sensitive information
Working Credentials

Often, usernames and passwords are hidden in the source code, because developers forget to remove them. 

Exposed passwords make the Android app vulnerable
Exposed passwords
Content Providers

Content Providers allow applications to access data from other applications. And in order to access a Content Provider, you need its URI. 

Attackers check if the Content Provider attribute is ‘exported=true,’ which implies that it can be accessed by third-party applications.

The Content Provider attribute is ‘exported=true'
The Content Provider attribute is ‘exported=true’
Content Provider URI
Content Provider URI

Below we are accessing the content provider declared by the vulnerable application through the tool i.e. content, which acts as a third-party application.

Using the Content Provider to access data without a PIN
Using the Content Provider to access data without a PIN

An activity implements a screen/window in an app. So, an app usually invokes only an activity i.e. a particular screen in another app, and not the app as a whole.  

Attackers check for weaknesses in activities in the AndroindManifest.xml file. Where, if an activity is marked as ‘exported=true,’ a third-party app can initiate that activity.

Activity marked as 'exported=true'
Activity marked as ‘exported=true’

For example, the screen below has a functionality to submit a password. And only on submitting the password, we can see the dashboard. 

Password required to view dashboard
Password required to view dashboard

However, if the activity responsible for showing the dashboard is marked ‘exported= true,’ an attacker can use an Activity Manager (AM) tool to run it. 

Using an Activity Manager to run the activity
Using an Activity Manager to run the activity

And by doing this the attacker can access the dashboard without a password. 

Accessing the dashboard without a password
Accessing the dashboard without a password
Broadcast Receivers

Broadcast receivers listen for system-generated or custom generated events from other applications or from the system itself. 

Attackers check for weaknesses in Broadcast Receivers in the AndroindManifest.xml file. And if the intent-filter tag is declared ‘exported=true,’ a third-party application can easily access it. To prevent this, we need to explicitly declare ‘exported=false.’

Intent-filter tag declared ‘exported=true’
Intent-filter tag declared ‘exported=true’

After checking for the parameters that the receiver can accept, attackers can write a command that will trigger the receiver on behalf of the application.  

For example: The following command triggers the receiver to send a message to a phone number. 

Command to trigger the receiver
Command to trigger the receiver

Following which, the message is delivered to the phone number:

Message sent as per command
Message sent as per command

Dynamic analysis

In this approach, the attacker uses a binary toolkit such a Frida to hook to a targeted application and change its implementation. It also allows the attacker to bypass root detection and SSLs. 

Since Frida has the capability to access classes and functions of a targeted process/ application, the attacker injects their own JavaScript (JS) payload at runtime, to analyze the behavior of the code. 

Bypassing root detection

The following application has root detection. Hence, to access all the capabilities of the application, the attackers need to bypass root detection. 

A device that has root detection
A device that has root detection

First, the attacker needs to identify the function that is responsible for root detection. Which they can get from the source code:

Root detection function in the source code
Root detection function in the source code

If one of the functions i.e. ‘doesSuperuserApkExist(‘’) and doesSuExist(‘’)’ returns True, it will be identified as a Rooted Device.

So, the attacker needs to change the implementation of these two functions to False, in order to bypass the rooting. And this is where Frida comes to use. 

By injecting the following JS payload, the attacker changes the implementation of the functions responsible for root detection. 

JS payload to change the root detection function
JS payload to change the root detection function

With the help of use(), the attacker accesses the PostLogin class. Here, they mention the function i.e. ‘doesSUexist or doesSuperuserApkExist,’ that they need to hook. After which, the function will start returning False instead of True

Frida Client then sends the server this JS payload. And the server makes it a thread and sends it to the JS Engine. So, whenever the application calls this function, Frida will call the thread instead of the actual function declared in source code.



Given the increasing sophistication of cyber-attacks, it is important that Android apps undergo proper vulnerability assessments before publishing. Also, developers should not leave sensitive information such as API keys and credentials exposed in the source code.