In this blog, we will dive into an interesting method for intercepting traffic from applications implementing SSL Pinning and applications that do not respect system proxies. Xamarin, for instance, relies on the Mono runtime, which introduces its network stack instead of using the platform’s native APIs directly. Similarly, Flutter, with its Dart programming language, operates on its networking layer, abstracting away platform-specific network APIs. There might be numerous such frameworks that can cause similar situations.
Usually, in these situations, pentesters have to decompile the application, identify the framework, and make modifications to the binary to essentially disable the SSL verification check or add custom code (in its assembly/byte-code form) to add a proxy at the application level. This is pretty tedious and can take a lot of trial and error to get things working right.
One highly effective approach that has consistently worked for me is intercepting DNS queries using DNSChef. For those unfamiliar with the tool, DNSChef is a configurable DNS proxy that enables the creation of a fake DNS server to intercept all incoming DNS queries. It allows for the redirection of a chosen domain (e.g., api.original.com) to a local IP address (e.g., 192.168.1.22), such as the Burp Suite proxy.
Once the fake DNS server is configured in the client’s network settings, all requests will be routed through the proxy instead of the default DNS server (e.g., 8.8.8.8 or the gateway DNS).
The following diagram provides a high-level understanding of how the process operates. Let’s delve into the setup and step-by-step guide with an example.
Notice that the client application is specified as “Modified” in the above diagram since we must modify the client application to disable the SSL. In this setup, we are going to setup an invisible proxy in the burp suite to view the traffic in the burp proxy. Since most of the applications(even default frameworks) enable SSL pinning, you will not be able to see the https traffic even after using an invisible proxy. The client simply refuses to connect upon failing to verify the certificate provided by Burp Suite instead of the Target server.
To disable this step, we can simply modify all instances of https:// to http:// for the target domain i.e https://api.original.com to http://api.original.com.
python3
and pip3
are installedpip3 install -r requirements.txt
I will describe my approach assuming the target application is not even using the known framework. The first step is identifying the target domain. You just have to setup the DNSchef proxy and configure the DNS in your mobile device.
python3 ./dnschef.py -i 10.0.0.36
This will start a fake DNS server on the interface (10.0.0.36) which is my local network adapter. You must ensure that the mobile device is also on the same network range.
Now, configure the DNS in your mobile device.
Once this is done, you can start using the application, you will soon start seeing incoming DNS queries in the console like below.
Note: Sometimes, due to the presence of a local DNS cache, you may not receive any new DNS queries. In this case, you can just reset the network or restart the device.
There can be numerous queries coming up, but you can perform specific tasks like Login, and notice the domain in dnschef console immediately to identify the target domain requested by the application.
Now that we have the target domain, we have to make the modifications in the app for the domains to change https://api.original.com to http://api.original.com
Decompile the application and review various files in the decompiled application. It might sometimes be obvious which framework it is, just by seeing the files, for instance if you see a file
index.android.bundle
in assets
it is likely a react-native application.libmonodroid.so
might indicate it is a Xamarin build.libapp.so
and libflutter.so
means it is a flutter application.If you are already familiar with the files to be modified for the identified framework, you specifically update those files. Or you can use simple grep method to identify all instances of the domain across all files.
You can see the list of occurrences in the console. It is recommended to modify all instances since we are not clearly aware of which instance exactly used to make requests.
Once you have identified the file to modify for example `libapp.so`. You can use any hex editor to replace the https:// bytes with http://. Follow the below steps to make the changes.
For Android: recompile the application and sign the build apk using uber apk signer (https://github.com/patrickfav/uber-apk-signer)
For iOS: zip it back https://reverseengineering.stackexchange.com/questions/31537/decompile-and-re-compile-ios-app-ipa-file
Note: Sometimes, you may have multiple domains in interest to be intercepted. You can try to update the port while keeping the length the same. For instance, changing https://auth.original.com to http://auth.orig.com:8080. In the later steps, you may be able to set up multiple listeners to intercept traffic from all these domains.
You can also use the below script to make the replacements in all occurences. Just update the directory_path replaced_domain, and original_domain in the script.
import os
import glob
from concurrent.futures import ThreadPoolExecutor
def replace_in_file(file_path, keyword, replacement):
with open(file_path, "r+b") as file:
content = bytearray(file.read())
index = content.find(keyword)
while index != -1:
# Replace the keyword with the replacement
content[index:index + len(keyword)] = replacement
index = content.find(keyword, index + len(replacement))
file.seek(0)
file.write(content)
def replace_in_directory(directory, keyword, replacement):
file_pattern = os.path.join(directory, '**/*.*')
with ThreadPoolExecutor() as executor:
executor.map(lambda file_path: replace_in_file(file_path, keyword, replacement), glob.iglob(file_pattern, recursive=True))
if __name__ == "__main__":
directory_path = "./decompiled_output/"
original_domain = b"https://api.original.com"
replaced_domain = b"http://aapi.original.com"
replace_in_directory(directory_path, original_domain, replaced_domain)
Now that we have replaced all the instances. We can easily configure an invisible proxy and fake DNS entry to route the traffic to the burp proxy server.
python ./dnschef.py --fakedomains aapi.original.com --fakeip 10.0.0.36 -i 10.0.0.36
Now all DNS requests for aapi.original.com will be redirected to 10.0.0.36 and since aapi.original.com uses http:// in the modified application, it connects to port 80.
Alternatively, You can edit /etc/hosts file in your mobile device to create a fake DNS entry.
# This is a sample /etc/hosts file
# It maps hostnames to IP addresses
# IPv4 addresses
127.0.0.1 localhost
255.255.255.255 broadcasthost
::1 localhost
aapi.original.com 10.0.0.36 # Target domain is now pointing to fake IP address
Now, if everything works, you should be able to intercept the traffic successfully.
In conclusion, mobile application penetration testing often presents numerous challenges, as outlined in the blog post. The approach detailed in the post can be particularly useful for pentesters aiming to bypass SSL pinning and intercept traffic from proxy-unaware applications. This method involves utilizing tools such as DNSchef and employing a relatively straightforward technique to modify the client application and intercept its traffic. While there are various techniques available, including universal bypass Frida scripts, this particular method consistently proves effective in overcoming interception issues across different types of applications.
Penetration Testing Across Industries: Requirements and Assessment Scope
How to Conduct an Effective Phishing Audit
Security and Penetration Testing for Banking & Finance Companies