Network Layer Security - SSL Pinning bypass

este módulo de DVIA-v2 tiene 5 opciones, cada una simula un escenario distinto de la capa de red:

  • Send over HTTP - manda la data en texto plano, sin cifrado
  • Send over HTTPS - usa TLS estándar con cualquier cert de una CA válida, sin pinning
  • Send using Certificate Pinning - la app tiene el certificado embebido y lo compara exacto contra el del servidor
  • Send using Public Key Pinning - variante del pinning pero fija solo el hash de la llave pública en vez del cert completo
  • App Transport Security (ATS) - política de iOS que exige TLS 1.2+ a nivel de sistema, este lo dejamos anotado y se documenta a fondo en una página aparte dedicada a ATS, para no repetir trabajo

vamos a ir en ese mismo orden

Configuración de Burp

antes de entrar a los retos dejamos Burp listo: configuramos el proxy en el dispositivo apuntando a la IP y puerto de Burp, e instalamos el certificado de Burp como confiable en el dispositivo

primero entramos a Burp Suite, a la sección de Proxy settings

image.png

una vez ahí, en Proxy listeners, le damos click en Add

image.png

agregamos el nuevo puerto y seleccionamos la opción All Interfaces, y le damos OK

image.png

Nos debe quedar de esta manera

image.png

ahora vamos a configurar la conexión en el iPhone, entramos a nuestro WiFi

image.png

entramos a la configuración del proxy

image.png

ponemos manual, y llenamos los campos de servidor y puerto: en servidor va la IP de nuestro PC donde está Burp, y en puerto el que configuramos. le damos en guardar

image.png

Vamos a instalar el certificado de Burp: abrimos Safari y entramos a http://burp

image.png

vamos a CA Certificate y le damos en permitir

image.png

y debe salirnos un mensaje como el siguiente

image.png

ahora vamos a Ajustes, y vemos que nos aparece la opción de Perfil descargado

image.png

y nos sale esta pantalla, le damos en Instalar

image.png

nos sale este mensaje, le damos de nuevo en Instalar

image.png

y una vez más en Instalar

image.png

y con esto ya nos sale verificado

image.png

y al darle en Listo, ya vemos el perfil agregado

image.png

pero todavía nos falta darle la confianza total al certificado

vamos a Ajustes →General →Información, y bajamos hasta la opción Conf. certificados de confianza

image.png

ahí vemos PortSwigger CA con el switch apagado

image.png

lo activamos, nos sale una ventana emergente, y le damos en Continuar

image.png

ahora vamos a un navegador y entramos a https://example.com, y vemos que ya tenemos el tráfico

image.png

ahora vamos con la aplicación, y el reto dice:

Hay tres formas de enviar datos a través de la red: usar HTTP, usar HTTPS o usar SSL/fijación de certificados para verificar un certificado codificado con el certificado proporcionado por el servidor para prevenir ataques MITM. Tu tarea es interceptar la información que se envía a través de la red cuando se toca el botón ‘Enviar’ en los tres casos.

image.png

Send over HTTP

el reto dice: manda la información sin cifrar, en texto plano

aquí no hace falta bypass, solo dejamos Burp escuchando y mandamos la petición

image.png

agregamos la información y le damos en SEND OVER HTTP y con esto vemos que podemos ver el tráfico de los datos ingresados y un mensaje en la aplicación que nos dice Solicitud enviada, ¡cuidado!

image.png

con esto queda evidenciado el peor escenario posible, cualquiera en la red ve la data sin necesidad de instalar ni un certificado

Send over HTTPS

el reto dice: manda la información usando TLS estándar, sin pinning. es un caso muy similar al anterior, solo que aquí la app sí valida el certificado, pero como ya contamos con el certificado de Burp instalado, el tráfico se ve directo, sin necesidad de Frida ni Objection

image.png

Send using Certificate Pinning

El SSL Pinning es un mecanismo que usan las apps para asegurarse que solo confían en un certificado específico (o una llave pública específica), en vez de confiar en cualquier certificado válido que venga de una CA. Esto es importante porque:

  • Evita ataques Man-in-the-Middle (MITM), aunque el atacante tenga un certificado válido instalado en el dispositivo.
  • Protege el tráfico de ser interceptado por herramientas como Burp Suite o mitmproxy.
  • Dificulta el análisis dinámico de las comunicaciones de la app durante un pentest.

el reto dice: la aplicación tiene un mecanismo de Certificate Pinning implementado de forma insuficiente, hay que evadirlo y capturar el tráfico

al darle en la opción SEND USING CERTIFICATE PINNING, vemos que nos sale un mensaje que nos dice La validación del certificado ha fallado. ¡Tendrás que hacerlo mejor! y no vemos trafico en el Burp

image.png

revisamos si el dispositivo está conectado

┌──(rootangussMoody)-[/mnt/angussMoody]
└─# frida-ls-devices
Id                                        Type    Name             OS
----------------------------------------  ------  ---------------  ---------------------
local                                     local   Local System     Kali GNU/Linux 2026.2
137e70f9805dfaa6291989bfed24126fc4abdd5f  usb     iOS Device       iPhone OS 16.7.16
barebone                                  remote  GDB Remote Stub
socket                                    remote  Local Socket
 
┌──(rootangussMoody)-[/mnt/angussMoody]
└─# 

buscamos el identificador de la aplicación

┌──(rootangussMoody)-[/mnt/angussMoody]
└─# frida-ps -Uai
 PID  Name             Identifier                       
----  ---------------  ---------------------------------
 728  Calendario       com.apple.mobilecal              
1169  Configuración    com.apple.Preferences            
1160  DVIA-v2          com.highaltitudehacks.DVIAswiftv2
 678  Dopamine         com.opa334.Dopamine.8MP3V4USL6   
1165  Filza            com.tigisoftware.Filza           
1164  Safari           com.apple.mobilesafari           
1167  TestFlight       com.apple.TestFlight             
1166  TrollStore Lite  com.opa334.TrollStoreLite        
   -  App Store        com.apple.AppStore               
   -  Archivos         com.apple.DocumentsApp           
   -  Atajos           com.apple.shortcuts              
   -  Bolsa            com.apple.stocks                 
   -  Brújula          com.apple.compass                
   -  Calculadora      com.apple.calculator             
   -  Casa             com.apple.Home                   
   -  Clima            com.apple.weather                
   -  Consejos         com.apple.tips                   
   -  Contactos        com.apple.MobileAddressBook      
   -  Cámara           com.apple.camera                 
   -  Drive            com.google.Drive                 
   -  Encontrar        com.apple.findmy                 
   -  FaceTime         com.apple.facetime               
   -  Fitness          com.apple.Fitness                
   -  FortiClientVPN   com.fortinet.forticlient.vpn     
   -  Fotos            com.apple.mobileslideshow        
   -  Freeform         com.apple.freeform               
   -  Libros           com.apple.iBooks                 
   -  Lulo STG         co.com.lulobank.stg.8MP3V4USL6   
   -  Lupa             com.apple.Magnifier              
   -  Mail             com.apple.mobilemail             
   -  Mapas            com.apple.Maps                   
   -  Medición         com.apple.measure                
   -  Mensajes         com.apple.MobileSMS              
   -  Música           com.apple.Music                  
   -  NewTerm          ws.hbang.Terminal                
   -  Notas            com.apple.mobilenotes            
   -  Notas de voz     com.apple.VoiceMemos             
   -  Podcasts         com.apple.podcasts               
   -  Recordatorios    com.apple.reminders              
   -  Reloj            com.apple.mobiletimer            
   -  Salud            com.apple.Health                 
   -  Sileo            org.coolstar.SileoStore          
   -  TV               com.apple.tv                     
   -  Teléfono         com.apple.mobilephone            
   -  Traducir         com.apple.Translate              
   -  Wallet           com.apple.Passbook               
   -  Watch            com.apple.Bridge                 
   -  Zebra            xyz.willy.Zebra                  
   -  iTunes Store     com.apple.MobileStore            

┌──(rootangussMoody)-[/mnt/angussMoody]
└─# 

Método 1: Objection

usamos la herramienta Objection para realizar el bypass al pinning

┌──(rootangussMoody)-[/mnt/angussMoody]
└─# objection -g "DVIA-v2" explore
DeprecationWarning: The option 'gadget' is deprecated. Please use '-n' or '--name' instead
DeprecationWarning: The command 'explore' is deprecated. Use 'objection start' instead of 'objection explore'

     _   _         _   _
 ___| |_|_|___ ___| |_|_|___ ___
| . | . | | -_|  _|  _| | . |   |
|___|___| |___|___|_| |_|___|_|_|
      |___|(object)inject(ion) v1.12.5

     Runtime Mobile Exploration
        by: @leonjza from @sensepost

[tab] for command suggestions
DVIA-v2 (run) on (iPhone OS: 16.7.16) [usb] # 

una vez adentro, ejecutamos el comando ios sslpinning disable, que desactiva el pinning en la app

┌──(rootangussMoody)-[/mnt/angussMoody]
└─# objection -g "DVIA-v2" explore
DeprecationWarning: The option 'gadget' is deprecated. Please use '-n' or '--name' instead
DeprecationWarning: The command 'explore' is deprecated. Use 'objection start' instead of 'objection explore'

     _   _         _   _
 ___| |_|_|___ ___| |_|_|___ ___
| . | . | | -_|  _|  _| | . |   |
|___|___| |___|___|_| |_|___|_|_|
      |___|(object)inject(ion) v1.12.5

     Runtime Mobile Exploration
        by: @leonjza from @sensepost

[tab] for command suggestions
DVIA-v2 (run) on (iPhone OS: 16.7.16) [usb] # ios sslpinning disable
(agent) Hooking common framework methods
(agent) Found NSURLSession based classes. Hooking known pinning methods.
(agent) Hooking lower level SSL methods
(agent) Hooking lower level TLS methods
(agent) Hooking BoringSSL methods
(agent) Registering job 648846. Name: ios-sslpinning-disable
DVIA-v2 (run) on (iPhone OS: 16.7.16) [usb] # 

volvemos al reto para probar si el tráfico ya se ve en Burp

en el dispositivo, le damos en SEND USING CERTIFICATE PINNING

al tocar el botón del reto, la app intenta la conexión y ahí vemos dos líneas nuevas en la terminal: Called SSL_CTX_set_custom_verify() confirma que la app registró su callback de validación de certificado justo en ese momento, y Called custom SSL context verify callback, returning SSL_VERIFY_NONE confirma que el hook de Objection interceptó esa llamada y forzó el resultado a “sin verificación” o sea, el pinning quedó desactivado exactamente cuando la app intentó validar el certificado.

┌──(rootangussMoody)-[/mnt/angussMoody]
└─# objection -g "DVIA-v2" explore
DeprecationWarning: The option 'gadget' is deprecated. Please use '-n' or '--name' instead
DeprecationWarning: The command 'explore' is deprecated. Use 'objection start' instead of 'objection explore'

     _   _         _   _
 ___| |_|_|___ ___| |_|_|___ ___
| . | . | | -_|  _|  _| | . |   |
|___|___| |___|___|_| |_|___|_|_|
      |___|(object)inject(ion) v1.12.5

     Runtime Mobile Exploration
        by: @leonjza from @sensepost

[tab] for command suggestions
DVIA-v2 (run) on (iPhone OS: 16.7.16) [usb] # ios sslpinning disable
(agent) Hooking common framework methods
(agent) Found NSURLSession based classes. Hooking known pinning methods.
(agent) Hooking lower level SSL methods
(agent) Hooking lower level TLS methods
(agent) Hooking BoringSSL methods
(agent) Registering job 648846. Name: ios-sslpinning-disable
(agent) [648846] Called SSL_CTX_set_custom_verify(), setting custom callback.
(agent) [648846] Called custom SSL context verify callback, returning SSL_VERIFY_NONE.
DVIA-v2 (run) on (iPhone OS: 16.7.16) [usb] # 

vemos que ya no sale la ventana emergente, y el tráfico aparece en Burp Suite

image.png

Método 2: Frida con script propio

ahora vamos a hacer el mismo bypass pero con un script de Frida directo, sin usar Objection, para documentar las dos formas

primero dejamos el dispositivo en el mismo estado, conectado y con el proxy de Burp configurado

Este script ataca el pinning a un nivel más bajo que el anterior, en vez de hookear SecTrustEvaluate (que es parte del framework Security de iOS), va directo a BoringSSL, la librería que Apple usa internamente para el handshake TLS desde iOS 13. hookea SSL_set_custom_verify, que es la función donde la app registra su callback de validación de certificado, y la reemplaza por una que siempre retorna SSL_VERIFY_NONE (0), o sea, que nunca rechaza el certificado sin importar qué mande el servidor. también parcha SSL_get_psk_identity por si la app usa autenticación PSK. como actúa más abajo en la pila que el hook anterior, suele funcionar incluso cuando el pinning está implementado de forma custom o cuando el hook a SecTrustEvaluate no alcanza a cubrirlo.

Fuente original: codeshare.frida.re/@federicodotta/ios13-pinning-bypass

try {
    Module.ensureInitialized("libboringssl.dylib");
} catch (err) {
    console.log("libboringssl.dylib no cargado, cargando manualmente...");
    Module.load("libboringssl.dylib");
}

var SSL_VERIFY_NONE = 0;

var boringssl = Process.getModuleByName("libboringssl.dylib");

var ssl_set_custom_verify = new NativeFunction(
    boringssl.getExportByName("SSL_set_custom_verify"),
    'void', ['pointer', 'int', 'pointer']
);

var ssl_get_psk_identity = new NativeFunction(
    boringssl.getExportByName("SSL_get_psk_identity"),
    'pointer', ['pointer']
);

var ssl_verify_result_t = new NativeCallback(function (ssl, out_alert) {
    return SSL_VERIFY_NONE;
}, 'int', ['pointer', 'pointer']);

Interceptor.replace(ssl_set_custom_verify, new NativeCallback(function (ssl, mode, callback) {
    ssl_set_custom_verify(ssl, mode, ssl_verify_result_t);
}, 'void', ['pointer', 'int', 'pointer']));

Interceptor.replace(ssl_get_psk_identity, new NativeCallback(function (ssl) {
    return Memory.allocUtf8String("notarealPSKidentity");
}, 'pointer', ['pointer']));

console.log("[+] Bypass de pinning (BoringSSL) cargado correctamente");

con el archivo listo, ejecutamos

┌──(rootangussMoody)-[/mnt/angussMoody]
└─# frida -U -f com.highaltitudehacks.DVIAswiftv2 -l script.js
     ____
    / _  |   Frida 17.15.3 - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at https://frida.re/docs/home/
   . . . .
   . . . .   Connected to iOS Device (id=137e70f9805dfaa6291989bfed24126fc4abdd5f)
Spawning `com.highaltitudehacks.DVIAswiftv2`...                         
libboringssl.dylib no cargado, cargando manualmente...
[+] Bypass de pinning (BoringSSL) cargado correctamente
Spawned `com.highaltitudehacks.DVIAswiftv2`. Resuming main thread!      
[iOS Device::com.highaltitudehacks.DVIAswiftv2 ]-> 

volvemos a Burp y confirmamos que el tráfico se ve igual que con Objection

image.png

asi quedan documentadas las dos formas, con Objection y con Frida directo

Send using Public Key Pinning

para este reto usamos el mismo proceso que en Certificate Pinning, tanto con Objection como con el script.js de Frida, sin necesidad de cambiar nada. la razón es que ninguno de los dos bypasses distingue entre comparar el certificado completo o solo el hash de la llave pública ios sslpinning disable desactiva la validación en todos los puntos donde la app pueda estar chequeando esto, y el script de BoringSSL actúa un paso antes, en SSL_set_custom_verify, que es la función que decide si la conexión es confiable o no, sin importar qué método de comparación use la app después. como el bypass ocurre antes de que se ejecute esa comparación, da igual si la app está validando el certificado completo o solo la llave pública: nunca llega a hacer esa validación.

Al realizar la validación de SEND USING PUBLIC KEY PINNING vemos que podemos tener el tráfico desde la aplicación.

image.png

App Transport Security (ATS)

App Transport Security es la política que Apple exige a nivel de sistema desde iOS 9, obligando a que toda conexión de red use TLS 1.2 o superior salvo que la app declare excepciones explícitas en su Info.plist. a diferencia de los retos anteriores, que se resuelven en tiempo de ejecución con Frida/Objection, este análisis es principalmente estático: se revisa el Info.plist de la app buscando banderas como NSAllowsArbitraryLoads desactiva ATS por completo, excepciones de dominio con NSExceptionAllowsInsecureHTTPLoads permite HTTP plano para dominios específicos, y la versión mínima de TLS permitida por excepción. por su naturaleza distinta al resto de este módulo, este reto lo vamos a documentar en una página aparte, dedicada solo a ATS.

image.png