TL;DR In this blogpost I show the update of the analysis on different scripts that executes the bypass of network security configuration with Frida on devices with API 27 to 29.
In the previous post I explain how and why each script works. It is not mandatory to read it before reading this one: https://cmrodriguez.me/blog/nsc-bypass/
It has been a while since I did the first analysis of different scripts used to bypass the network security configuration of Android devices. In the moment I did it we did not have in Genymotion (the VM I use for pentesting) devices with Android 27 and above, so I limited the analysis on the devices with API 24 to 26. Now we can create Android emulated devices till API 29, so I thought it was a good moment to do a review on the scripts I had collected for the first post.
I’ll use the same criteria to execute the analysis as I did before. I created three applications with different network security configurations:
Each application has three different ways to execure requests:
The scripts I used are the following ones:
The following github repository has all the applications I developed and the scripts I used.
https://github.com/CesarMRodriguez/network-security-config-frida-2
The following is a screenshot of the table I created with the results of the analysis:
Original reference: Link
I had to change the network-security-config-bypass-1.js. It threw some errors that in previous version of frida-cli worked. The errors were related to undefined variables. The change to avoid this error was to add in some variable declarations were the let or var modified.
Original Reference: Link
I had to change the network-security-config-bypass-2.js. It threw the same kind of errors as in the firs script.
Original Reference: Link
In this case I did not need to change anything from the original script
For API 28 and AÏ 29, the original script does not work. There is a change in the signatures of the methods hooked by the library, which throws the following error:
[NSC 28::com.example.bypassnsc]-> Error: ManifestConfigSource$DefaultConfigSource(): specified argument types do not match any of:
.overload('boolean', 'android.content.pm.ApplicationInfo')
at ge (frida/node_modules/frida-java-bridge/lib/class-factory.js:584)
at frida/node_modules/frida-java-bridge/lib/class-factory.js:923
at /network-security-config-bypass-2.js:16
at frida/node_modules/frida-java-bridge/lib/vm.js:11
at frida/node_modules/frida-java-bridge/index.js:446
at frida/node_modules/frida-java-bridge/index.js:431
at je (frida/node_modules/frida-java-bridge/lib/class-factory.js:633)
at frida/node_modules/frida-java-bridge/lib/class-factory.js:616
The fix was the following one:
if (DefaultConfigSource.$new.argumentTypes[1].className == "android.content.pm.ApplicationInfo") {
var ApplicationInfo = Java.use("android.content.pm.ApplicationInfo");
var appInstance = ApplicationInfo.$new();
appInstance.targetSdkVersion.value = ANDROID_VERSION_M;
appInstance.targetSandboxVersion.value = 1;
return DefaultConfigSource.$new(true,appInstance);
}
The change is neccesary because the constructor of “DefaultConfigSource” changed to the following one:
DefaultConfigSource(boolean usesCleartextTraffic, ApplicationInfo info) {
mDefaultConfig = NetworkSecurityConfig.getDefaultBuilder(info)
.setCleartextTrafficPermitted(usesCleartextTraffic)
.build();
}
I also had to set some values in the second parameter (object from class ApplicatoinInfo). In order to see what we need to set, we had to check the implementation of the method getDefaultBuilder from the NetworkSecurityConfig class:
public static Builder getDefaultBuilder(ApplicationInfo info) {
Builder builder = new Builder()
.setHstsEnforced(DEFAULT_HSTS_ENFORCED)
// System certificate store, does not bypass static pins.
.addCertificatesEntryRef(
new CertificatesEntryRef(SystemCertificateSource.getInstance(), false));
final boolean cleartextTrafficPermitted = info.targetSdkVersion < Build.VERSION_CODES.P
&& info.targetSandboxVersion < 2;
builder.setCleartextTrafficPermitted(cleartextTrafficPermitted);
// Applications targeting N and above must opt in into trusting the user added certificate
// store.
if (info.targetSdkVersion <= Build.VERSION_CODES.M && !info.isPrivilegedApp()) {
// User certificate store, does not bypass static pins.
builder.addCertificatesEntryRef(
new CertificatesEntryRef(UserCertificateSource.getInstance(), false));
}
return builder;
}
we can see that we have to set the “targetSdkVersion” to 23 in order to make the application to import UserCertificateSource, and we need to set targetSandboxVersion to 1, so the clearTextTraffic is set to true.
With this change, the script worked as intended. I also checked the parameter types to make the script compatible with older versions as well.
The results from the analysis of the scripts used for the network security config bypass show that they are as effective in the newer APIs as they were in the old ones. Two of the scripts works in all scenarios (network-security-config-1.js) and (network-security-config-cr.js).