IG Learner Walkthrough

Tools Required:


  1. Android SDK (ADT bundle).
  1. Will use adb mostly.
  1. Dex2jar. (Used for unpacking .apk file)
  2. jd-gui. (Java Decompiler)
  3. apktool
  4. Mercury. Link
  5. Extractor tool like Winrar.
  6. Burp Suite free
  7. Virtuous Ten Studio (optional but highly recommended)


Preparation for taking apart the app:


  1. Get your hands on the apk file and tools above.
  2. Connect the Android device to the computer and make sure the correct drivers are present such that your OS recognizes the phone.
  3. With the phone connected, check if the phone is connected by typing the following command: 
    adb devices
    You should see your 
    device in the list, if your OS recognizes it. If not – I highly recommend making sure that:
                    1) USB Debugging mode is enabled

                        2) The right USB drivers are installed
        Finally, keep in mind that you don’t have to have an Android phone in the first place to run the app. This can be done just as easily in an Android emulator.

  1. Retrieve the list of installed apps using the following command:
    adb shell pm list packages
  2. Find the learner app by looking for “Learner” in the list, then type the following command to download the apk into the current working directory:
    pull /data/app/<name of the Learner package>
    The package should look something like “com.intrepidusgroup.learner-1.apk”
  3. Use Dex2jar tool to unpack the .apk file. 
    d2j-dex2jar <path-to-.apk> -o <path-to.jar>
  4. You can drag-and-drop the .jar file into JD-Gui to de-compile all the class files.
  5. Use apktool to disassemble the APK package and its .dex files and generate the smali files.
    apktool d <path-to-.apk>
    Using this tool to disassemble files allows you to change the code, and reassemble it back to a functioning .apk file.  To do this, use apktool again, but this starting in the root directory of the disassembled file.  The apktool should be able to find apktool.yml to reassemble back.
    apktool b
  6. This will create two directories, build and dist.  dist will contain the apk file and build is the unpacked contents of the apk archive. Now, when you install the newly generated apk file in the device, it fails because the package is unsigned.  Detailed instructions for signing a package is given in the Android Package Signing  – please check that out.
    Note: You can skip the second step that says building with ant.
  7. (optional) You can try to load up the project in the Virtuous Studio Interface. Virtuous Studio uses apktool on the backend and makes a lot of things transparent, like signing and pushing the apk. That said, we still believe that for learning purposes it’s a good idea to use the command line tools for this exercise.


Lesson 1 (Android logging secrets):

Reference: Android Log

        As the name suggests this deals with Android’s logging facilities. The reference page has all the necessary instructions that are required to pass this challenge. You can either use adb  (command line) or monitor.bat or DDMS (GUI, a bit more user-friendly) to get the log messages out of the device.  

Since a lot of stuff is being thrown into logs, it may be helpful to filter  the records to find the log entries pertaining to the Learner app.


If you want to create a proper filter on the command line, in adb you would use the following syntax:

                 adb logcat filter-1 filter-2 … filter-n

                filter -> <tag>:<priority>

        where ‘tag’ is used to represent the application component that is generating the logs and ‘priority’sets the priority level for logs.


In Android Debug Monitor (monitor.bat in your Android SDK), you start logging, start the app, start lesson 1, and stop logging. You can then just scroll through the entries to find the tag that the Learner app uses: “LEARNER”. Typing  tag:LEARNER” in the filter window will only show you entries from the IG Learner app.


The following is how you would use reverse-engineering techniques to find the exact logging tag.

Using JD-GUI, figure out the tag and priority level that have been set for this particular challenge in the Lesson1Activity.class



        As you can see from the above picture the tag is “LEARNER” and the priority is set to “D” which is Debug.  Hence, the filter will look like this:

                adb logcat LEARNER:D *:S

        *:S will filter out every tag thus limiting the output to filter-1.



That’s it!  Input the above key and submit the challenge. You can now play with other filters like the ones with priority set to “E” for Errors, etc. and filter out log messages as efficiently as possible.


Note: This exercise can be done using another tool called DDMS which comes with the ADT bundle.  It is a GUI with fancy coloring. Invoke it using monitor.bat, in the menu bar goto window >>  Show View >> Android >> Logcat.


Acitivity (Screwy File Permissions):

Prerequisite: Basic Knowledge of Java.


        When you look into the drop-down menu of Lesson2Activity, you will be presented with an overview of methods and data-members present in this class. Most of the method names are self-explanatory. An important method to learn at this point is the “onCreate()” method which is called when the user selects the Lesson2Activity from the app. Note: All the activities are called in this fashion.

        When we look in this method, we find a call to “createFile()”, which seems interesting in the context of this challenge. The first line of this method shows that the data member “filename” is being set by a call to “getFileName()”.  By following this method, we find the format in which the filename is created.

        getDate() returns the current date to getFilename() in the format specified by the SimpleDateFormat object. Similarly, getPhoneNumber() as expected will return the phone number associated with the phone. The getFileName() method then appends the output from the above two methods and appends “.txt” to it. (Note: if your Android device, such as a tablet, is not associated with a number, getPhoneNumber() will return 1234567890). You can check the existence of that file by opening a shell and doing an ls -l on the file that’s been created in the default directory, /data/data/<package_name>/files. And note that you can read that file – it’s world-readable!

        Answer: 201301281234567890.txt





Activity (URI handlers Craziness):

Prerequisite: Basic Knowledge of Java.


        Solving this lesson is similar to the previous one, except that you need to understand how basic requests are handled. When you try and play with the app, you will notice that a hyperlink is generated in the white WebView window when you click on “Request URI”. Now, when you click on the hyperlink you will see “LOCKED” appear. When you look through the decompiled class of this activity, it will not be apparent where this “LOCKED” message is generated. In fact, it’s not clear at all what is happening when we click on the generated link.


        To understand what is happening here, it’s useful to think about how web servers work. You give them a request, the server processes the request and sends back a response. The handler for a web request is a web server. In order for this activity to complete, there must be a handler for the request this activity generates.

Lesson3HandlerActivity is where all the magic happens. Check the “onCreate()” method where the requested URI is processed through an intent that arrives to the getIntent() method.  The important thing here is the condition for the “if” statement that parses the Intent’s data. In particular, onCreate() checks for the presence of the substring “crazyurihandler” in the request path, and then does something to the GUI interface if it exists. It is reasonable to try to put the “crazyurihandler” in the URI window of the lesson. Watch what happens! If you have done it correctly, then you will see the “UNLOCKED” message appear.






Activity (SSL man in the middle):


        The instructions for this lesson suggest that we need to intercept the token that is sent as a request to a server. However, the request is sent via https, so the traffic when we intercept will be encrypted. We need to find a way to decrypt the traffic, so that we can get the secret token.

        We can do this using a local proxy that supports SSL connections. The proxy will generate a new certificate for the host we are connecting to. Once we accept this certificate, both the connection between server < – > proxy and the connection between proxy < – > user would be encrypted. The proxy could then decrypt the traffic using the public certificate that was issued to the user and re-encrypt the data with the certificate of the server. In this way, the proxy can see all the data in plain text.

The first step is to set up Burp Proxy (for the purposes of this exercise, any HTTP proxy will do) and use it to proxy the data from the Android device. Once Burp is loaded, go to the proxy tab and then options. In the proxy listeners, set burp to listen on all interfaces on a particular port.


Once you have done this, go to your Android device and set it up to connect to this proxy. Make sure that your Android device and the system running Burp Proxy are on the same network.



When the intercept is on in Burp, you should see requests being intercepted like this:

Now, try to visit a site using https. You will get a security error on your mobile browser like this.




Burp is sending you a certificate that is not trusted by your mobile browser. This means that even the Learner app does not trust the certificate and the connection fails. In order to avoid this issue, we need to import the Root CA of Burp proxy into the device’s certificate store. To do that, go to your browser on your computer, and allow the browser to run through the proxy as well.


These settings are for Chrome/IE. Other browsers may not be affected by changes in this interface, so you will need to configure them independently.  Once the browser is configured to run through the proxy, you will see the certificate error in your computer browser as well.



You can get additional information about the certificate through your browser. In Chrome, click on the lock symbol next to the url and Chrome will display the security information for this site, including the certificate itself. This certificate is for this host, but we need to get the Root CA of Burp which signs this per host certificate.


Click on the tab “Certification Path”, then you will see PortSwigger CA as the root for google.com. Double-click on that one and a new window will open with certificate information for the root CA. You need to export this certificate and import it into your mobile device’s trusted certification store. To do that, click on “copy to file…” and follow the wizard. Then copy the saved .cer file into the root folder of your mobile external storage. Once you have done that, go to Settings >> Security >> Install from device storage. This will load the PortSwigger CA into the trusted certificate store of the device.

        Now, your connection should happen seamlessly. The proxy can view the data in plain text. Remember that if you get a security error on your mobile browser after doing the above steps then you probably missed something, try once again.

        The certificate on your mobile browser will resemble the screenshot below. Notice that the certificate was issued by PortSwigger, but the browser says it is valid.


Now, run the app and check your proxy for the secret token.


Activity (Advanced MITM):

References: 1.Certificate Pinning 2. Android Package Signing 3. Understanding Smali

Tools: 1. Moxie’s Pin.py tool (https://github.com/moxie0/AndroidPinning/blob/master/pin.py)


        The goal of this lesson is very similar to the previous lesson except that the certificate is pinned to the hostname. This means the app is hardcoded with the fingerprint of the certificate issued by the valid server, and the app checks the received certificate against this fingerprint instead of checking with the certificate store. So, the certificate issued by Burp will not match the fingerprint and will cause a certificate error in the app.

        In order to bypass this error, we need to know where the check is performed and what the attacker has influence on. If we can find where in the app the pin is hardcoded, we can replace it with a pin generated from the Burp certificate and re-package the app. The certificate issued by Burp can be easily retrieved like we did in the above lesson, except that we need to export the host certificate, instead of the PortSwigger CA, to generate the pin.

You can use the pin.py tool mentioned in the Moxie’s blog to generate a pin for new certificates.

(Note: the certificate that you import must be Base64 encoded. This option is available on the import wizard)

The HttpRequestTaskWithPinning class has the pin hardcoded inside. However, jd-gui couldn’t decompile the class files for this file, so we need to use apktool to generate smali files:


        Re-packaging instructions are provided in “Preparing for App assessment” section of this tutorial. Once you finish re-packaging and signing the app, you need to re-install it on your device and try Lesson 5 again:




Activity (Encryption vs Encraption):


Note: logging is there to help you in case you get frustrated…


        As the title suggests, this lesson is about encryption. Specifically, it concentrates difficulties with key management and why relying on client-side encryption to generate secrets may not be a good idea. As you look through the list of methods in the Lesson6Activity class, “encryptNumberWithAES()” looks interesting.

Looking at this method closely, we see the algorithm used for encryption is AES, with the key hard coded into the code. Since AES is a symmetric encryption algorythm, we can use this key to encrypt new data or decrypt any data that has been previously encrypted.

Using this key, encrypt the number displayed in the app using AES and output it to a readable form using Base64 encoding (you’ll need Base64 output to type your answer into the challenge). The following is a sample Java code snippet to do this:



import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.*;
import org.apache.commons.codec.binary.Base64;
public class Aes {
        public static void main(String[] args) throws Exception {
                byte[] key = "intrepidlearner1".getBytes();
                byte[] input = args[0].getBytes();
                Cipher c = Cipher.getInstance("AES");
                c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"));
                byte[] encVal = c.doFinal(input);


Activity (Providers shared with the world):

Reference: 1. Android Docs   2. Mercury Docs


        Mercury is an Android assessment framework which helps identify vulnerabilities in your app. Content providers are quite simply backend databases where the app can store and retrieve data for later use. Insecure storage often leads to data leakage, which is the focus of this lesson.

        Mercury allows you to display the information about the Content provider a particular app is using.

The following figure shows you the information regarding the provider for the Learner app. As you can see it lists the various permissions and the Authority of the provider for this app.



In order to access the data in a provider, you need to know its Content URI. A content URI is one that identifies data in a provider. It is of the form



Reverse engineering the app we find its content URI.



You can run a query in Mercury to display the data of the provider using the Content URI just discovered.



Activity: (Malcious Intents)


References: 1. Intents 2. Android Package Signing 3. Understanding Smali

Addt. Tools: apktool


        In this lesson we are going to use apktool as we did in lesson 5. This is once again because apktool converts the dalvik binary into a language called Smali, which is translated directly from the binary itself. A key benefit of this is that it allows you to change code or any other resources and convert the changed code back into a functional .apk file. jd-gui doesn’t allow you to do that.

        Smali may be confusing at first but once you get familiar with the code style, it’s pretty easy. The goal of this lesson is to manipulate an Intent so that a hidden activity gets displayed. So ,we need to figure out how the intent is parsed and what checks are being performed.

        In order to read the code easily, we will start with jd-gui when we look at Lesson8AuxApp’s MinActivity class. There, we see that an Intent is being prepared and sent when the user clicks the send button.



  Let’s look at Lesson8 AuxActivity class from Ig-Learner and see what it is doing with the intent.



p class=”c1 c6″>getAction() needs to be equal to something that is being refer

Call us before you need us.

Our experts will help you.

Get in touch
%d bloggers like this: