As I promised in my previous article, here it is the follow up article about performing a man in the middle (MitM) attack to steal an API key, and to follow this article you will need to become the man sitting in the middle of the actual channel, using mitmproxy to help you with the task of stealing the API key. Now it should be clear why MitM stands for man in the middle!
In order to help to demonstrate how to steal an API key, I have built and released in Github the Currency Converter Demo app for Android, which uses the same JNI/NDK technique we used in the earlier Android Hide Secrets app to hide the API key.
So, in this article you will learn how to setup and run a MitM attack to intercept https traffic in a mobile device under your control, so that you can steal the API key. Finally, you will see at a high level how MitM attacks can be mitigated.
In order to perform the MitM attack you need to have mitmproxy installed, have both the computer and the mobile device on the same wifi network, set up the proxy on the mobile device, have a free API key for the third party service that provides the currency rates, and then build and install the Currency Converter demo app on the mobile device.
From Github you need to git clone the Currency Converter Demo app:
git clone --branch 0.1.3 https://github.com/approov/currency-converter-demo.git
To perform the MitM attack you should use the open source tool mitmproxy which is an interactive https proxy that can be used from the command line or from a web interface, although if you are already using other tools, such as the Charles or Fiddler Proxy, feel free to skip the install and setup for the mitmproxy.
If you don’t yet have the mitmproxy tool installed you should follow the official documentation to install it on your platform, but if you have Docker on your system then you can use their official image.
If you decided to use docker and don't want to type long commands, you can use the `./stack` bash script in the root of the demo:
The output should look similar to this:
4.0.4: Pulling from mitmproxy/mitmproxy
911c6d0c7995: Pull complete
6c177ecba9eb: Pull complete
4e66c1c16ddc: Pull complete
0a3a1ba37d3c: Pull complete
Status: Downloaded newer image for mitmproxy/mitmproxy:4.0.4
Now it’s time for a smoke test to check that mitmproxy is working:
./stack mitmweb --version
OpenSSL: OpenSSL 1.0.2o 27 Mar 2018
All mitmproxy commands in this demo will be prefixed with `./stack`, because we will run them within docker containers, but if you have mitmproxy installed in your computer just remove the prefix `./stack` when executing each command.
In order to be able to perform the MitM attack you need to connect the computer and the mobile device to the same wifi network.
Next you need to know the IP address for the wifi network and from your terminal you can execute:
ip address | grep -i wlp -
The output will be similar to this:
3: wlp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
inet 10.0.3.55/24 brd 192.168.0.255 scope global dynamic noprefixroute wlp3s0
You can also do it from the user interface. For example in Ubuntu 18.04 you can discover from going to Settings > Wi-Fi > Visible Networks and click on settings for the wifi network you are connected to:
You should take note of the IP address 10.0.3.55 in order to later use it to set up the proxy in the mobile device and to access the mitmproxy web interface.
Now that you know the wifi IP address, it’s time to launch the mitmproxy web interface to listen to all requests made into the wifi network, on port 8080, by issuing the following command:
./stack mitmweb --listen-host 10.0.3.35 --web-iface 10.0.3.35
Web server listening at http://10.0.3.35:8081/
No web browser found. Please open a browser and point it to http://10.0.3.35:8081/
Proxy server listening at http://10.0.3.35:8080
Let's do a smoke test to check if we can see the web interface for mitmproxy, by visiting in the browser http://10.0.3.55:8081:
Now that mitmproxy is listening in all traffic that goes through the wifi, on port 8080 (10.0.3.35:8080), it's time to set up our mobile device proxy to send all traffic through it.
The mitmproxy needs to be launched before you setup the mobile device, because when the mitmproxy web interface starts, a custom authority certificate is auto generated, and it will be later used to setup the proxy on the mobile device.
In android this is usually done by selecting the wifi network, then advanced options, and set the proxy to manual mode, fill the proxy hostname field with the wifi IP, in this case 10.0.3.35, and the proxy port with 8080, the one where mitmproxy is listening. Depending on your Android version it will look something like this:
In order for mitmproxy to be able to intercept all the https traffic we need to add to the mobile device a custom certificate authority. This was auto generated by mitmproxy when we started the proxy, thus is unique to this mitmproxy installation. To do so, please open the browser in the mobile device and go to http://mitm.it where you should see this page:
NOTE: If you see any other screen that means the traffic from your mobile device is not being intercepted, thus you need to review the previous steps and ensure that you followed them correctly.
Time to click on the Android symbol and install the custom authority certificate for mitmproxy by following the on screen instructions. This will require the mobile device to have authentication enabled when unlocking the screen. If you do not have it done already, you will be prompted to set it up.
For this step you first need to get an API key for the third party service that will provide the currency rates used in the mobile app in order to perform the currency conversion. Just visit this page to get your free API key.
However, before you can build the app, you need to copy/paste the free API key into the file app/src/main/cpp/api_key.h. This file does not exist yet in the project, and is not tracked by git, but you can use app/src/main/cpp/api_key.h.example as a template:
#define CURRENCY_CONVERTER_DEMO_API_KEY_H "place-the-api-key-here"
If the mobile device you are installing this app on is using Android Nougat or later OS version, then you need to uncomment this line in the code.
So this code:
This will allow the mobile app to trust the mitmproxy certificate we have already installed because, since API level 24, the Android operating system by default doesn't allow the mobile apps to trust in user supplied certificates, unless explicitly told to do so, and that is what we are doing by providing this network security config file.
Now you can build the app and install it via usb. How to do this is out of scope for this article, but you can refer to the official docs. After you have installed the Currency Converter demo app you should be presented with this screen:
This was the final step in the setup for the MitM attack, so now we just need to play with the app and watch the mitmproxy web interface for the intercepted requests.
Assuming that you still have the mitmproxy running from the setup process, just open the browser on http://your-wifi-ip-here:8081 and start playing with the android app in order to see the API requests being used to get the currency rates from a third party API being intercepted.
So let's try to convert £1000 into euros and see if we can intercept and steal the API key when the app calls the third party service to get the currency rate for exchanging pounds for euros.
Well I got €1,163.74 for £1000, and if I look into the mitmproxy web interface I can see that the https request to get the currency rate for the exchange was intercepted:
Can you spot where the API key is in the intercepted https request?
Well, I bet that you quickly found the API key as a parameter in the url, but if you haven’t, then just look a bit closer:
Congratulations, you have been able to steal the super secret API key that the developer thought to be very well protected. So just to be clear, this is the same API key you copy/pasted into the file app/src/main/cpp/api_key.h and then hid in the mobile app binary through the use of the advanced JNI/NDK technique. This technique makes it difficult to reverse engineer the binary using static analysis, but as you have seen the API key can easily be extracted with a MitM attack.
An attacker using a MitM attack to steal an API key can then create huge commercial damage to a company. They can abuse the API resources in the name of the API key owner, thus increasing their usage costs, or they can exfiltrate and exploit the data exposed by the API.
If you edit the mobile app code and switch the url to the third party API to use the http protocol, rebuild, install it again, and do some more currency conversions you will be able to compare the difference between http and https requests:
So can you spot what are the differences between intercepted requests over http and https?
If you are struggling to find any substantial differences… look a little closer:
Although they look exactly the same, there is a difference - the green bar preceding the https requests. So if until now you thought that https was enough to protect your API key, you may now see that during a MitM attack it does not offer any protection at all.
This is possible because of the custom certificate authority we installed on the mobile device when we visited http://mitm.it. Tricking a user into installing this type of custom certificate authority on a device is usually done with fake captive portals to get free wifi in public places, because some users will click on anything just to have free wifi !!!
We can mitigate the MitM attack by using certificate pinning on the connection between the mobile app and the API server, and we have an excellent article on it, Hands On Mobile API Security: Pinning Client Connections. Therefore I will not go into detail here, but I want to let you know that pinning can be an operational challenge, and unfortunately it can be bypassed, but if you read this article you will understand how to detect and prevent it from happening.
So now you may be wondering what more can be done in terms of mobile API security. I would recommend a deep dive into this series of articles to understand several other security techniques that can be employed to protect a mobile API.
While we can use advanced techniques, like JNI/NDK, to hide the API key in the mobile app code, it will not impede someone from performing a MitM attack in order to steal the API key. In fact a MitM attack is easy to the point that it can even be achieved by non developers.
We have highlighted some good resources that will show you other techniques to secure mobile APIs, like certificate pinning, even though it can be challenging to implement and to maintain. We also noted that certificate pinning by itself is not enough since it can be bypassed, thus other techniques need to be employed to guarantee that no one can steal your API key, and, if you have completed the deep dive I recommended, you will know by now that in the context of a mobile API, the API key can be protected from being stolen through a MitM attack. So if you have not already done it, please read the articles I linked to in the section about mitigating MitM attacks.
You can read more about other techniques to perform MitM attacks in the articles How to MitM Attack the API of an Android App and How to Bypass Certificate Pinning with Frida on an Android App.