Cómo omitir la configuración de seguridad de red de Android
Sin embargo, esta característica puede afectar la evaluación de seguridad de las aplicaciones móviles de Android. Si necesita interceptar el tráfico HTTPS, debe instalar un certificado de proxy y también debe instalarse en un "certificado de usuario", que no es de confianza de forma predeterminada.
A continuación, presentaremos el modo operativo de este nuevo mecanismo y cómo modificar el comportamiento predeterminado de este nuevo mecanismo de seguridad mediante la recompilación o el mecanismo de enlace en tiempo de ejecución.
¿Cómo utilizan los desarrolladores esta función?
Para modificar la configuración predeterminada, necesitamos crear un archivo XML en el directorio de recursos para especificar información de configuración personalizada. Aquí hay un archivo de configuración de muestra que configura los certificados de usuario para todos los enlaces HTTPS a la aplicación:
lt? versión xml = "1.0" codificación = "utf-8"? gt
ltConfiguración de seguridad de red gt
ltConfiguración básica gt
ltAnclaje de confianzagt.
ltcertificado src="system"/gt.
ltcertificado src="usuario"/gt.
lt/trust-anchors gt
lt/base-config gt
lt/network-security-config
Además, también es necesario hacer referencia a este archivo en el archivo AndroidManifest, es decir, especificarlo en el parámetro android:networkSecurityConfig de la pestaña de la aplicación:
lt? versión xml = "1.0" codificación = "utf-8"? gt
ltDisplay... gt
ltapplication Android: networkSecurityConfig = " @ XML/network_security_config "
... gt
...
lt/application gt;
lt/manifest gt;
¿Cómo puede un probador de penetración evitar esta característica?
Recompilar
Si la aplicación que se va a probar se ejecuta en la plataforma Android Android 7 y superior (o la clave targetSdkVersion está configurada en la versión 24 o superior), la aplicación El programa más Probablemente use una configuración predeterminada. Por lo tanto, la aplicación no confiará en los certificados de usuario (como los certificados de CA proxy).
Generalmente la forma de modificar la configuración predeterminada es recompilar la aplicación después de insertar el contenido XML (activando el contenedor de certificados). A continuación, usaremos apktool para modificar la aplicación.
Primero, lo que debemos hacer es usar apktool para descompilar la aplicación. Una vez completado, también debemos crear un archivo XML en el directorio de recursos y modificar los parámetros relevantes en el archivo AndroidManifest.xml (que apunta al archivo de configuración de seguridad de la red). En este punto, podemos usar apktool para recompilar la aplicación nuevamente y luego usar la herramienta jarsigner para firmar el archivo APK generado.
Cuando volvemos a firmar el archivo APK con cualquier certificado, podemos instalarlo en el teléfono usando adb. Si el teléfono está configurado para enviar tráfico a través de un proxy intermediario (como Burp Suite), podemos interceptar el tráfico HTTPS siempre que el certificado CA esté instalado en el sistema telefónico.
Enganches de tiempo de ejecución
Pero en algunos casos, el método que acabamos de introducir puede no ser factible. Por ejemplo, si una aplicación utiliza shareId para compartir el mismo Id con otras aplicaciones y necesitamos acceder a sus datos directamente, entonces ambas aplicaciones deben estar firmadas con el mismo certificado. Si la aplicación se vuelve a compilar y volver a firmar, esta función de protección es redundante y es imposible firmar el APK modificado con el certificado original del desarrollador.
Para este escenario, podemos utilizar tecnología de construcción dinámica, porque este método nos permite modificar el comportamiento del programa en tiempo de ejecución sin modificar el código de la aplicación. Para lograr esto, necesitamos crear un script Frida para ajustar el comportamiento predeterminado de la configuración de seguridad de red de la aplicación (versión SDK de destino >= 24).
El paquete android.security.net.config implementa el módulo de configuración de seguridad de red y su clase principal ManifestConfigSource puede cargar información de configuración personalizada en archivos XML. Si el archivo de recursos no existe, cargará la configuración predeterminada. El código relevante es el siguiente:
Empaquetado de Android. net. config;
La clase pública manifestconfigsource implementa ConfigSource {
. . .
Fuente de configuración privada getConfigSource() {? sincronización(bloquear){
. . .
if(mconfigresoureid!= 0) {
. . .
source = newXmlConfigSource(m context, mConfigResourceId, debugBuild, mTargetSdkVersion, mtargetsandboxveversion
} En caso contrario {
. . .
fuente = new DefaultConfigSource(usesCleartextTraffic, mTargetSdkVersion, mtargetsandboxveversion);
}
mConfigSource = fuente? Devuelve mConfigSource
}
}
. . .
}
La clase DefaultConfigSource es una clase privada definida en la clase ManifestConfigSource.
Si la información de configuración no se modifica mediante un archivo XML, el sistema utilizará esta clase de forma predeterminada:
Embalaje de seguridad de Android;
La clase pública manifestconfigsource implementa ConfigSource.
...
La clase final estática privada DefaultConfigSource implementa ConfigSource {? configuración de seguridad de red final privada mDefaultConfig;? public DefaultConfigSource(boolean usesCleartextTraffic, inttargetSdkVersion, int targetandboxveversion){
mDefaultConfig = networksecurityconfig . getdefaultbuilder(targetSdkVersion,
targetSandboxVesrsion)
. setcleartexttraffic permitido(usaCleartextTraffic)
. build();
} ?@Override
Configuración de seguridad de red pública getDefaultConfig() {? Volver mDefaultConfig
} ?@Override
Configuración pública ltPair lt dominio, configuración de seguridad de red gt gtgetPerDomainConfigs() {? Return null
}
}
}
Eche un vistazo al constructor de esta clase, que puede recibir tres parámetros. entre los cuales uno es la versión SDK de destino de la aplicación. Este valor se puede utilizar para construir la clase NetworkSecurityConfig utilizando el método getDefaultBuilder(). En el último fragmento de código, si el valor de targetSdkVersion es menor o igual a 23 (Android Marshmallow, Android 6.0), el código cargará el certificado de usuario.
Empaquetado Android.security.net.config;
Clase final pública Configuración de seguridad de red {
...
Final estática pública Constructor getDefaultBuilder(int targetSdkVersion, inttargetsandboxveversion) {
Constructor constructor = new Builder()
. setHstsEnforced(default_HSTS_forced)? // Almacén de certificados del sistema, no omite los pines estáticos.
.
addCertificatesEntryRef(
newCertificatesEntryRef(systemcertificatesource. getinstance(), false));? final booleancleartexttraffickpermitted = targetandboxversion lt;
constructor .setcleartexttraffickpermitted(cleartexttraffickpermitted);? //Las aplicaciones orientadas a N y superiores deben optar por confiar en los certificados agregados por el usuario
//Almacenamiento.
if(targetSdkVersion lt;=Build.VersionCode.M) {? //Almacenamiento de certificados de usuario, no omite los pines estáticos.
constructor . addcertificatesentryref(
newCertificatesEntryRef(usercertificatesource . getinstance(), false));
} ?Devolver constructor
}
...
A continuación, necesitamos usar el script Frida para conectar el constructor de la clase DefaultConfigSource y modificar el valor targetSdkVersion allí. Además, el script debe vincular el método getDefaultBuilder() para garantizar que el valor se haya modificado correctamente.
Java.perform(function(){
var ANDROID _ VERSION _ M = 23
var DefaultConfigSource = Java . use(" Android . security . net config . manifestconfigsource $ DefaultConfigSource ");
var NetworkSecurityConfig = Java . use(" Android . security . net . config . NetworkSecurityConfig ");
DefaultConfigSource.$init.overload( "boolean", "int"). implementación = function(usesCleartextTraffic, targetSdkVersion){
console.log("[ ]Modificar el constructor DefaultConfigSource"); , utilizaCleartextTraffic, ANDROID_VERSION_M);
};
DefaultConfigSource.$init.overload("boolean", "int", " int ").
implementación = function(usesCleartextTraffic, targetSdkVersion, targetSandboxVersion){
console . log("[ ]Modificar el constructor DefaultConfigSource"); $init.overload("booleano","int","int"). call(this, usesCleartextTraffic, ANDROID_VERSION_M, targetandboxcversion);
};
networksecurityconfig . implementación = function(targetSdkVersion){
console . log("[ ]getDefaultBuilder targetSdkVersion original = gt; targetsdkversion . tostring()); devuelve esto . getdefaultbuilder . sobrecarga(" int "). call(this, ANDROID_VERSION_M);
};
networksecurityconfig.getdefaultbuilder.overload("int","int").implementation=function(targetSdkVersion,targetSandboxVersion){
console . log("[ ]getDefaultBuilder targetSdkVersion original = gt; targetsdkversion . tostring()); devuelve este . getdefaultbuilder . sobrecarga(" int ", " int "). call(this, ANDROID_VERSION_M, targetandboxcversion);
};
});
Ahora, con la ayuda del script de Frida proporcionado anteriormente, podemos usar un Proxy HTTP similar a Burp Suite para interceptar aplicaciones (todas las versiones del SDK de destino >= 24 aplicaciones).
$ Frida-U-l NTC .js-f lt;nombre_paquete gt-not-pause