injuredandroid
This is my first time to test on Android applications and in this walkthrough I will discuss how I was able to solve most of the challenges and also to introduce my methodology.
What is injuredandroid?
A vulnerable Android application with CTF examples based on bug bounty findings, exploitation concepts, and pure creativity.
Basic Recon
In the beginning, I liked to install the app and use it as a usual user to identify its functions and features, but this one is a type of challenge that gave me an idea about what challenges and its activities I would face.
Static Analysis
There are many tools that can perform this task for us, but I prefer the manual approach.
Let’s decompile the apk using jadx-gui
.
After decompiling the apk, I like to check two interesting files AndroidManifest.xml
and strings.xml
.
The Android Manifest is an XML file which contains important metadata about the Android app. This includes the package name, activity names, main activity (the entry point to the app), Android version support, hardware features support, permissions, and other configurations.
Strings file contains all the strings which can be used frequently in the application.
Starting with AndroidManifest.xml
file, I search for exported
components that may reveal sensitive information, bypass any restrictions or do any interesting action.
In strings.xml
file, I search for API keys, hardcoded credentials and firebase information.
Dynamic Analysis
In this phase, I focus on the components that took my attention in static analysis phase, I also focus on Root detection mechanisms and SSL pinning checks.
I also run adb logcat
while analyzing all the components and its related vulnerabilities.
In static analysis phase, I got three interesting exported activities.
First Finding
Let’s use adb
to see what it is hiding.
adb shell am start-activity -n b3nac.injuredandroid/.b25lActivity
Second Finding
Using adb
command again.
am start -n b3nac.injuredandroid/.QXV0aA
All what I got is empty page with login button.
Click on Login button, I just got Authentication succeeded
in a Toast message.
Third Finding
By doing further investigation, I found this activity uses intents.
Let’s enter this activity using adb
command.
am start -n b3nac.injuredandroid/.TestBroadcastReciever -a com.b3nac.injuredandroid.intent.action.CUSTOM_INTENT --es "url" "Hi"
After I finished testing of the interesting activities, I decided to start testing the application’s functionality and features (Challenges).
XSSText
Before analyzing the challenge code, I like first to open it to have a clue about the challenge.
As I expected, I just found a user input. So let’s analyze the code.
Search for
b3nac.injuredandroid.XSSTextActivity
inAndroidManifest.xml
file.
This activity has a simple code that takes user input as Intent
to com.b3nac.injuredandroid.DisplayPostXSS
then it starts the DisplayPostXSS
activity.
The passed user input is loaded in a webView
. The problem is with settings.setJavascriptEnabled(true);
which allows the attackers to execute JavaScript code.
Let’s inject XSS payload as there’s no any restrictions of the passed user input.
I’ve injected a basic XSS payload: <img src=1 onerror=alert("Hacked")>
Login
let’s do the same as we did in the last challenge.
It’s just a flag input field. Let’s review the source code.
It just checks if the entered flag is equal to F1ag_0n3
.
Resources
From the challenge name, It reveals that it’s related to res
directory or resources.arsc
directory.
Searching in strings.xml
, we got flag.
Login2
Just flag input as the last one.
It takes the user input and compare it with the decoded value from g().a()
Let’s review g()
class.
Here we got the base64 encoded flag, so let’s decode it.
Let’s submit the flag 4_overdone_omelets
.
Login3
Just flag input as other login challenges.
It take the user input and compare with k.a(strangeValue)
, I thought it’s base64 encoded but it’s not.
Reviewing the method’s code, the strange value is DES encryption of the flag.
Here, I decided to use frida
to get flag.
I used frida as the comparing function do, by decrypting the strange value.
Java.perform(function () {
let k = Java.use("b3nac.injuredandroid.k");
let decryptedValue = k.a("k3FElEG9lnoWbOateGhj5pX6QsXRNJKh///8Jxi8KXW7iDpk2xRxhQ==");
console.log("Flag: " + decryptedValue);
});
SQLite
Let’s open the code after we had an overview.
It takes the entered flag and compare it with encrypted flag and compared the entered password with encrypted password.
When decoding the first subtitle value, we got a hash.
Let’s break the hash.
So the password is hunter2
. Let’s move forward to the other subtitle value which is a return value of function h.c()
.
We got another strange value, but it seems that it’s roted.
Trying multiple roting amounts, we got that it’s using ROT47
.
Open the link, we got the flag S3V3N_11
.
AWS
As most of the challenges, just flag submit.
From the challenge name, It’s related to AWS and cloud. So I decided to search again for any keys and tokens in strings.xml
file.
It has no values and reviewing the does not give us much information.
After searching for a while, I got that the used bucket is open because there’s no provided values in AWS tags in strings.xml
file.
Here, I used cloud_enum
tool to enumerate the public cloud resources.
By using the keyword of the application name to reveal any cloud resources related to it.
python3 cloud_enum.py -k injuredandroid
As expected, there’s open S3 bucket revealing two files, The flag exists in C10ud_S3cur1ty_lol
file.
Firebase
Let’s review the source code.
The app first decodes the user input before comparing it with the flag.
The source code reveals a lot of information.
Let’s start with the encoded value.
The decoded value seems to be an endpoint. We got another hint related to using .json
with firebase url found in strings.xml
file.
So we will append the .json
to flags/
.
https://injuredandroid.firebaseio.com/flags/.json
When browsing the link, we got the flag. But we should first base64 encode it.
Unicode
Just flag submition input.
Like the last challenge, the source code reveals a lot of information.
Let’s start with the encoded value.
It seems to be also an endpoint, but we got another hints like Find an email address
and unicode collision
.
I google unicode collision
and I got this article.
Using the other hint about finding an email address, I used the article’s example John@Gıthub.com
as an input. But I got Not Authenticated!
.
After some time, I remmebered our Second Finding
that we can use to get authenticated.
When I got authenticated and submit the email address again, I got the flag.
Deep Links
When I click on the challenge, I just got hints like Eploit The Schema
, Check The Manifest
.
Deep links are specific URLs that, when triggered, can launch a particular activity within an app.
Let’s review AndroidManifest.xml
file.
Using flag11
as schema caught my attention as the first hint is Eploit The Schema
.
Let’s do further investigations of the source code.
It seems it’s waiting for schema flag11
and action android.intent.action.VIEW
to start the activity.
Let’s exploit the schema using adb
command.
am start -a android.intent.action.VIEW -d "flag11://"
I was able to bypass the restrictions and start the activity. But we didn’t get the flag.
Let’s get back to the code.
We got another hints, we should look for binary file in the app. We need first to decompile the app.
apktool -d injuredandroid.apk
Then look for the binary in assets
or lib
directories.
In assets
directory, we can find me'nu
file and It’s binary executable file.
When executing the file, We got the flag HIIMASTRING
.
Protected Components
When I click to open the challenge, I got Use an exported activity
as Toast message.
The activity look for totally_secure
intent and its value shoud be a URL with https
schema.
When I tried to start the activity using adb
command, I found the activity is not exported.
So let’s follow the hint and look for an exported activity to start it.
At the beginning, I thought any exported activity can start it, but after spending some time I realized that is not true and there’s only one activity that exists in
AndroidManifest.xml
file can do this.
After some searching, I found an exported activity that is able to start other activities b3nac.injuredandroid.ExportedProtectedIntent
.
Let’s reveal its code.
It uses access_protected_component
as an intent that accepts the package name of the wanted protected activity as a value and It only starts packages within the app by checking the package name.
I tried to use adb
to perform this task, but it was a little bit complicated so let’s build an app the help us perform this task and get the flag.
package com.hacking.injuredandroidaccess
import android.content.Intent
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
val intentToProtectedActivity = Intent().apply {
setClassName("b3nac.injuredandroid", "b3nac.injuredandroid.FlagTwelveProtectedActivity")
putExtra("totally_secure", "https://example.com/")
}
val triggeringIntent = Intent().apply {
setClassName("b3nac.injuredandroid", "b3nac.injuredandroid.ExportedProtectedIntent")
putExtra("access_protected_component", intentToProtectedActivity)
}
startActivity(triggeringIntent)
}
}
When I run this build app, I got redirected to protected activity.
Assembly
I got flag input and byte array [58,40,42]
when I open challenge.
When I decoded it, I just got :(*
Let’s review the code.
The app is using an exported function from a library and the value of this.z
are the byte array that are viewed in the challenge.
So let’s dig deep in the code to get from where this.z
get those value.
The exported function is from libnative-lib.so
library and the value of this.z
are the return values of the exported function.
Let’s reverse the function to have an overview of its workflow.
I got win
string and I guess it’s the flag.
In this walkthrough, we successfully exploited the vulnerabilities within the InjuredAndroid application.
Some of the challenges did not work with me.
If there’s any mistakes, please DM me. I’m waiting for your feedbacks.