As more and more applications and manufactures upgrade their Android APIs or device software versions, many security testers will face an interesting dilemma. The days of simply trusting a supplied Certificate Authority (CA) and forwarding all device traffic to an HTTPS proxy are gone. This is due to some major trust changes made in the plumbing of Android N and beyond.
To summarize, Google made serious strides in helping to ensure device and application transport security are bolstered in their newest operating system. These changes are known as Android Network Security Configuration. The updates mean it is now dead-simple for apps to pin certificates, add custom trust anchors (such as Intermediary certs), or even whitelist CAs with a simple manifest attribute. Additionally, there is now a cleartext traffic opt-out option available. This helps mitigate attacks such as TLS Stripping, and is as simple as a
<domain-config cleartextTrafficPermitted="false"> configuration update in the new network_security_config.xml file.
What do these Android Network Security changes mean for developers?
Uniformly offering ways for application developers to minimize security implications at the Transport Layer is a huge win. A month doesn't go by in which the industry isn't in an uproar about a major service violating the CA-Browser Forum Baseline Requirements. Furthermore, upgrades to auditing and logging like Certificate Transparency have significantly enhanced outsiders view of certificate issuance. This has brought the concerns from closed-door conversations or armchair critiques, all the way to enterprise and even layman concerns over homograph and punycode URI attacks. In addition, full public view has been brought to certificate misissuance or "test" certificate abuse scenarios, which may have previously gone undetected.
All of this said, offering easy, documented, and native solutions to minimizing this attack surface cannot be understated. No longer does an enterprise have to pin to a single (or perhaps single plus backup) certificate in hopes of mitigating MiTM attacks. Rather, a CA of choice can be chosen as the sole issuer of TLS certificates. This means if a breach occurs, or if someone finds a validation error in XYZ Corp CA's validation mechanism, the application is still safe as this CA was never in it's own trusted list.
To put it anecdotally, think of the following scenario. A child is required to have a permission slip to leave school early. In the current system, the school accepts any guardian on the school's curated list to provide said excuse, even if that guardian does not have a relationship with this particular child. However, this new Android feature is akin to the school pinning a note to the child confirming that only authorized members of a certain family which are on that note are allowed to provide the permission slip. It's just common sense for it to work this way.
This is an example of what whitelisting of particular CAs would look like in the Network Security Config:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config> <domain includeSubdomains="true">permissionslip.primaryschool.com</domain> <trust-anchors> <!-- added trusted CAs to res/raw/trusted_roots --> <certificates src="@raw/trusted_roots"/> </trust-anchors> </domain-config> </network-security-config>
Another developer win is Android's support for trusted custom CAs for debugging. A simple Network Security Config entry can be created to provide developers the ability to proxy traffic with custom CAs while the app is marked debuggable. This provides the opportunity of testing and tampering with HTTPS traffic to be performed without disabling TLS entirely or affecting production security.
Third-party solutions and frameworks which provide similar functionality have existed for several years, however native functionality enforced at the Operating System level is a huge win.
What do these Android Network Security changes mean for security testers?
White box testing which includes access to full, uncompiled source code does not change much. A tester can simply add a custom CA to the config file. However, security practitioners who test a lot of applications from a bevy of different developer shops may not have that luxury. Many times these testers are lucky to simply obtain a working APK, or are relegated to downloading a production app from the Play Store.
In addition to the changes made above to assist developers in their attempts to proactively secure their applications, Google also implemented major changes to the way Android trusts user or admin supplied CA certificates.
One of the first steps in the mobile testing process is to provide a trusted, proxy-specific CA which can generate custom certificates for each domain. These certificates are used in lieu of the original TLS certificates between the device and the proxy software. However, Android N+ no longer trusts these certificates.
If an attacker, device owner, or even a company administrator attempts to install a supplied CA the application will not trust it. This means the traditional steps of side-loading your Burp CA via the steps on Portswigger's (or proxy of choice) FAQ will no longer work. Thus, assessors now have an additional hurdle to overcome before they can attempt to look at the traffic.
Luckily there is a way around this testing limitation, as we can install a trusted CA at the Android OS level, but it requires a few requisites.
- A rooted device or emulator
- Android Debugging Bridge (adb)
- A CA Certificate in PEM format
Step One: Obtain the CA hash
Utilize the following command, substituting your CA name in
openssl x509 -inform PEM -subject_hash -in BurpCA.pem | head -1
The output of the above command will be something similar to:
Step Two: Create the CA file
Next you will create a file named with the above hash ending in
.0 and we will output the content of the pem file into this new file using the following command
cat BurpCA.pem > 9a5ba580.0
Step Three: Finalizing the
.0 file with the CA file contents
The final step of the CA file preparation is to append the cert text to the bottom of the file with:
openssl x509 -inform PEM -text -in BurpCA.pem -out /dev/null >> 9a5ba580.0
Step Four: Connect to the device with adb as root
Step Five: Set the /system partition as writable
By default, the /system partition is read-only, use adb to remount as writeable:
Step Six: Push the cert file to cacerts
Use adb to push the
.0 cert file to the /system/etc/security/cacerts/ directory:
adb push 9a5ba580.0 /system/etc/security/cacerts/
Step Seven: Modify the cert file permissions
chmod 644 /system/etc/security/cacerts/9a5ba580.0
Step Eight: Reboot and confirm
Reboot the device, then check
Settings > Security > Trusted Credentials > SYSTEM to confirm your newly added CA is listed.
Once the CA is confirmed to be a Trusted Credential, a security tester is once again able to proxy applications that do not pin TLS traffic to a particular certificate or trust anchor.