Today we are going to practice some Android pentesting with a challenge made by Hackerone platform.
I’ll explain different techniques used in Android pentesting with a practical overview.
This article was made for the day 2 of the hack event organised by The Hacking News B’Darija.
Challenge
We can access the challenege using https://ctf.hacker101.com/ctf
Intentional Exercise Challenge setup
https://86c65fe0ecf5117f91f7d2eaf9adf25e.ctf.hacker101.com/
1
**Your Android APK is building. Please refresh in a few seconds.**
1
https://86c65fe0ecf5117f91f7d2eaf9adf25e.ctf.hacker101.com/level13.apk
https://book.hacktricks.xyz/mobile-pentesting/android-app-pentesting
Instal the apk using Bluestackes
I didn’t have time to setup a clean setup for an Android emulator on my Linux machine, so i just used my Windows machine with Bluestacks emulator. It’s probably simple to setup Burpsuite proxy with it, right ? :unamused:
After installing the app, we can see it in your app menu.
Proxy setup with Burpsuite
To intercept requests from our android app, I’ll use Burpsuite. You can use the community version it’s free https://portswigger.net/burp
We need to set the proxy used by bluestackes using HD-ConfigHttpProxy.exe. You can find it in your application installation.
Now let’s add our burp proxy.
After setting a proxy, you need to restart Bluestacks. You can use the reset option to go back to default settings.
Now we need to :
Use BlueStacks Tweaker to root the emulator.
Install root certificate manager from the Google Play store.
Import the burp certificate. You can export it from the proxy tab.
Intercept requests while opening the app
Before the app shows the webview, we can see a request to https://86c65fe0ecf5117f91f7d2eaf9adf25e.ctf.hacker101.com/appRoot?&hash=61f4518d844a9bd27bb971e55a23cd6cf3a9f5ef7f46285461cf6cf135918a1a
Here is the response :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
HTTP/1.1 200 OK
Date: Wed, 27 Jul 2022 19:29:48 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 64
Connection: close
Server: openresty/1.21.4.1
<h1>Welcome to Level13</h1><a href="appRoot/flagBearer">Flag</a>
After forwarding the requests, let’s see what happens after clicking “Flag.”
We can see a new request to /appRoot/flagBearer same output as our first request. After forwarding the request, we see an output with an invalid request
Here is the response :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
HTTP/1.1 200 OK
Date: Wed, 27 Jul 2022 19:32:18 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 15
Connection: close
Server: openresty/1.21.4.1
Invalid request
Now let’s try to analyze what we were able to find :
Leaked the used domain : 86c65fe0ecf5117f91f7d2eaf9adf25e.ctf.hacker101.com
Hash parametre with /appRoot : hash=61f4518d844a9bd27bb971e55a23cd6cf3a9f5ef7f46285461cf6cf135918a1a
openresty/1.21.4.1 : Web server version. It’s probably the load blanacer https://openresty.org/en/
The app may be trying to verify a hash token with /appRoot to access/appRoot/flagBearer which is our final access.
We can check the links with our browser, It’s seems like the app is using a webview. We can get the same behavior.
We did some testing with the app, now let’s switch to some reversing with the apk file.
What is an apk file ?
A file with the APK file extention is an Android Package file that’s used to distribute apps on Google’s Android operating system
APK files are saved in the ZIP format and are typically downloaded directly to Android devices, usually via Google Play, but can also be found on other websites.
APKLeaks
There is a tool called APKLeaks that helps with getting urls, endpoints, and secrets from our apk files. It’s used by bug bounty hunters https://github.com/dwisiswant0/apkleaks
As we can see, there are some android xml files and a domain used with a endpoint or maybe a directory /appRoot.
Expectation :
And then you’ll be like, “emm, some juicy cash money for my bug bounty report :smirk: “
Reality : :skull:
Apktool
It’s a tool for reverse engineering Android apk files. We are going to use it to extract files from our apk. You can check the documentation for more details https://ibotpeaches.github.io/Apktool/
You can see instructions here to install it.
As i’m using Kali Linux, there is a package for it. We can use apt to install sudo apt install apktool
Let’s extract the apk file
- The AndroidManifest.xml is important for security research, it’s has the permissions required by the app, which can be abused if it’s not configured properly. We can read more about that :
https://pentestlab.blog/2017/01/24/security-guidelines-for-android-manifest-files/
https://www.briskinfosec.com/blogs/blogsdetail/Android-Manifest-File-Analysis-101
- Our focus today is the classes.dex file. The code is packed into .dex files. Dex stands for Dalvik Executable. A Dex file contains code that is ultimately executed by the Android Runtime. We can convert dex files to jar files using the dex2jar tool.
Now let’s decompile the jar file using JD-GUI http://java-decompiler.github.io/
As we can see here, the application configuration details.
Now let’s go to our target, the MainActivity.class. It’s like the main code from our Android app. We can read more about Android app development to get more details about it.
MainActivity.class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.hacker101.level13;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
setContentView(2131296284);
WebView webView = (WebView)findViewById(2131165328);
webView.setWebViewClient(new WebViewClient());
Uri uri = getIntent().getData();
String str1 = "https://86c65fe0ecf5117f91f7d2eaf9adf25e.ctf.hacker101.com/appRoot";
String str3 = "";
if (uri != null) {
str3 = uri.toString().substring(28);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("https://86c65fe0ecf5117f91f7d2eaf9adf25e.ctf.hacker101.com/appRoot");
stringBuilder.append(str3);
str1 = stringBuilder.toString();
}
String str2 = str1;
if (!str1.contains("?")) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(str1);
stringBuilder.append("?");
str2 = stringBuilder.toString();
}
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update("s00p3rs3cr3tk3y".getBytes(StandardCharsets.UTF_8));
messageDigest.update(str3.getBytes(StandardCharsets.UTF_8));
byte[] arrayOfByte = messageDigest.digest();
BigInteger bigInteger = new BigInteger();
this(1, arrayOfByte);
String str = String.format("%064x", new Object[] { bigInteger });
StringBuilder stringBuilder = new StringBuilder();
this();
stringBuilder.append(str2);
stringBuilder.append("&hash=");
stringBuilder.append(str);
webView.loadUrl(stringBuilder.toString());
} catch (NoSuchAlgorithmException noSuchAlgorithmException) {
noSuchAlgorithmException.printStackTrace();
}
}
}
Now we have the source code what to do ?
It’s just the app code for us x)
As we see from our first interaction with app http requests, we need to understand how to get the hash to access /appRoot/flagBearer or maybe use it for other things.
Start analyzing
- First we can see the libraires imported and used.
- The app sets a webview to be able to see urls.
- Start to build a url insied URI class probably https://developer.android.com/reference/java/net/URI
We can see the code when URI is null
1
2
3
4
5
6
7
if (uri != null) {
str3 = uri.toString().substring(28);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("https://86c65fe0ecf5117f91f7d2eaf9adf25e.ctf.hacker101.com/appRoot");
stringBuilder.append(str3);
str1 = stringBuilder.toString();
}
- str1 = “https://86c65fe0ecf5117f91f7d2eaf9adf25e.ctf.hacker101.com/appRoot”;
- build the str2 with str1 + append “?”
- Try to do some fancy encryption for a string to convert it to a hash and build the final URL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update("s00p3rs3cr3tk3y".getBytes(StandardCharsets.UTF_8));
messageDigest.update(str3.getBytes(StandardCharsets.UTF_8));
byte[] arrayOfByte = messageDigest.digest();
BigInteger bigInteger = new BigInteger();
this(1, arrayOfByte);
String str = String.format("%064x", new Object[] { bigInteger });
StringBuilder stringBuilder = new StringBuilder();
this();
stringBuilder.append(str2);
stringBuilder.append("&hash=");
stringBuilder.append(str);
webView.loadUrl(stringBuilder.toString());
} catch (NoSuchAlgorithmException noSuchAlgorithmException) {
noSuchAlgorithmException.printStackTrace();
}
If you can’t understand what the code does, you can simply create a Java code and start importing the used libraries and print each line to see the output. We need to add used string variables and also set a URI value for testing.
1
2
3
4
5
6
7
8
9
10
11
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
class test {
public static void main(String[] args) {
// here we need to the add used URI and string values.
// put the try catch and start analysing using System.out.println()
}
}
After doing some testing, let’s get back to our way of finding the hash.
- for URI, I abused the function that shows how the URI is built if it’s null.
1
2
3
4
5
6
7
if (uri != null) {
str3 = uri.toString().substring(28);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("https://86c65fe0ecf5117f91f7d2eaf9adf25e.ctf.hacker101.com/appRoot");
stringBuilder.append(str3);
str1 = stringBuilder.toString();
}
As we can see, it does a substring of 28 and takes the last part https://www.javatpoint.com/substring
1
2
3
4
5
6
7
class test {
public static void main(String[] args) {
String URI = "AAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBB";
System.out.println(URI.toString().substring(28));
}
}
1
BBBBBBB
for the str1 we have an URL + str3 (URI.toString().substring(28))
1
https://86c65fe0ecf5117f91f7d2eaf9adf25e.ctf.hacker101.com/appRoot + str3
We use “BBBB” for str3 at the moment. We can see that the beginning is probably a “/”
Now str1 = https://86c65fe0ecf5117f91f7d2eaf9adf25e.ctf.hacker101.com/appRoot/BBBB
The str2 is str1 + “?”
1
https://86c65fe0ecf5117f91f7d2eaf9adf25e.ctf.hacker101.com/appRoot/BBBB?
At the encryption part, we can see that the code appends another &hash=
and the hash value to the final string.
1
2
3
stringBuilder.append(str2);
stringBuilder.append("&hash=");
stringBuilder.append(str);
1
https://86c65fe0ecf5117f91f7d2eaf9adf25e.ctf.hacker101.com/appRoot/BBBB?hash=X
It looks familiar, right ? If we go back to our requests analysis at the beginning, we can see the same format.
1
https://86c65fe0ecf5117f91f7d2eaf9adf25e.ctf.hacker101.com/appRoot?&hash=61f4518d844a9bd27bb971e55a23cd6cf3a9f5ef7f46285461cf6cf135918a1a
For the BBBB part, it’s possible that it has flagBearer or /appRoot/flagBearer. URI Format can be URL/appRoot/flagBearer
Now let’s go for our solution. I used the same Main code with some modifications to get our hash. We can use an online Java compiler or execute it from your system if you have Java installed.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
class get_hash {
public static void main(String[] args) {
String uri = "AAAAAAAAAAAAAAAAAAAAAAAAAAAA/flagBearer";
String str1 = "https://86c65fe0ecf5117f91f7d2eaf9adf25e.ctf.hacker101.com/appRoot";
String str3 = "";
if (uri != null) {
str3 = uri.toString().substring(28);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("https://86c65fe0ecf5117f91f7d2eaf9adf25e.ctf.hacker101.com/appRoot");
stringBuilder.append(str3);
str1 = stringBuilder.toString();
}
String str2 = str1;
if (!str1.contains("?")) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(str1);
stringBuilder.append("?");
str2 = stringBuilder.toString();
}
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update("s00p3rs3cr3tk3y".getBytes(StandardCharsets.UTF_8));
messageDigest.update(str3.getBytes(StandardCharsets.UTF_8));
byte[] arrayOfByte = messageDigest.digest();
BigInteger bigInteger = new BigInteger(1, arrayOfByte);
String str = String.format("%064x", new Object[] { bigInteger });
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(str2);
stringBuilder.append("&hash=");
stringBuilder.append(str);
System.out.println(stringBuilder.toString());
} catch (NoSuchAlgorithmException noSuchAlgorithmException) {
noSuchAlgorithmException.printStackTrace();
}
}
}
Output
1
https://86c65fe0ecf5117f91f7d2eaf9adf25e.ctf.hacker101.com/appRoot/flagBearer?&hash=8743a18df6861ced0b7d472b34278dc29abba81b3fa4cf836013426d6256bd5e
Let’s visit the url
We were able to solve the challenge with right hash value.
Conclusion
I hope you find this article useful. You can learn more about Android application pentesting. There are many interesting attacks. You can take a look at :
- https://book.hacktricks.xyz/mobile-pentesting/android-app-pentesting
- ANDROID APP SECURITY BASICS https://www.youtube.com/watch?v=a8Gh7d8GebA
- HACKING ANDROID WebViews https://www.youtube.com/watch?v=qS5PkC-37io