
IOSSecuritySuite v2.3.0
Biblioteca Swift de seguridad y anti-manipulación para plataforma iOS
⭐️ ¿Quieres convertirte en un Ingeniero de Seguridad de Aplicaciones iOS certificado? ⭐️
Consulta nuestro curso práctico y completamente en línea en: https://courses.securing.pl/courses/iase

Descripción de ISS

por @_r3ggi
🌏 iOS Security Suite es una librería avanzada y fácil de usar de seguridad de plataforma y anti-manipulación, escrita en Swift puro. Si desarrollas para iOS y quieres proteger tu aplicación según el estándar OWASP MASVS, capítulo v8, ¡entonces esta librería podría ahorrarte mucho tiempo! 🚀
Lo que ISS detecta:
- Jailbreak 🧨
- Depurador adjunto 👨🏻🚀
- Si una aplicación se ejecutó en un emulador 👽
- Herramientas comunes de ingeniería inversa ejecutándose en el dispositivo 🔭
Configuración
Hay 4 formas de empezar a usar IOSSecuritySuite
1. Agregar fuente
Agrega los archivos IOSSecuritySuite/*.swift a tu proyecto
2. Configurar con CocoaPods
pod 'IOSSecuritySuite'
3. Configurar con Carthage
github "securing/IOSSecuritySuite"
4. Configurar con Swift Package Manager
.package(url: "https://github.com/securing/IOSSecuritySuite.git", from: "1.5.0")
Actualizar Info.plist
Después de agregar ISS a tu proyecto, también necesitarás actualizar tu Info.plist principal. Hay una verificación en el módulo de detección de jailbreak que usa el método canOpenURL(_:) y requiere especificar las URLs que se consultarán.
<key>LSApplicationQueriesSchemes</key>
<array>
<string>undecimus</string>
<string>sileo</string>
<string>zbra</string>
<string>filza</string>
</array>
Precios
Consulta nuestra licencia EULA para más detalles.
Resumen: Si tu empresa emplea:
- 0-99 personas - uso gratuito
- 100-1000 - 3k EUR/año
- 1000+ - 10k EUR/año
Si quieres vender un módulo que use iOS Security Suite (no se usa directamente en tu aplicación) - 10k EUR/año
Aviso
iOS Security Suite está diseñado para usarse en iOS/iPadOS. No debe usarse en Macs con Apple Silicon.
Cómo usar
Módulo detector de jailbreak
- El método más simple devuelve Verdadero/Falso si solo quieres saber si el dispositivo está jailbroken o no
if IOSSecuritySuite.amIJailbroken() {
print("Este dispositivo está jailbroken")
} else {
print("Este dispositivo no está jailbroken")
}
- Detallado, si también quieres saber qué indicadores fueron identificados
let jailbreakStatus = IOSSecuritySuite.amIJailbrokenWithFailMessage()
if jailbreakStatus.jailbroken {
print("Este dispositivo está jailbroken")
print("Porque: \(jailbreakStatus.failMessage)")
} else {
print("Este dispositivo no está jailbroken")
}
El failMessage es una cadena que contiene indicadores separados por comas, como se muestra en el siguiente ejemplo:
sileo:// Esquema de URL detectado, Archivo sospechoso existe: /Library/MobileSubstrate/MobileSubstrate.dylib, Fork pudo crear un nuevo proceso
- Detallado y filtrable, si también quieres, por ejemplo, identificar dispositivos que estuvieron jailbroken en el pasado pero ahora no lo están
let jailbreakStatus = IOSSecuritySuite.amIJailbrokenWithFailedChecks()
if jailbreakStatus.jailbroken {
if (jailbreakStatus.failedChecks.contains { $0.check == .existenceOfSuspiciousFiles }) && (jailbreakStatus.failedChecks.contains { $0.check == .suspiciousFilesCanBeOpened }) {
print("Este es un dispositivo realmente jailbroken")
}
}
Módulo detector de depurador
let amIDebugged: Bool = IOSSecuritySuite.amIDebugged()
Denegar depurador por completo
IOSSecuritySuite.denyDebugger()
Módulo detector de emulador
let runInEmulator: Bool = IOSSecuritySuite.amIRunInEmulator()
Módulo detector de herramientas de ingeniería inversa
- El método más simple devuelve Verdadero/Falso si solo quieres saber si el dispositivo tiene evidencia de ingeniería inversa
if IOSSecuritySuite.amIReverseEngineered() {
print("Este dispositivo tiene evidencia de ingeniería inversa")
} else {
print("Este dispositivo no tiene evidencia de ingeniería inversa")
}
- Detallado y filtrable, si también quieres la lista de verificaciones realizadas
let reverseStatus = IOSSecuritySuite.amIReverseEngineeredWithFailedChecks()
if reverseStatus.reverseEngineered {
// consulta reverseStatus.failedChecks para más detalles
}
Módulo detector de proxy del sistema
Ahora también puedes detectar si una aplicación está conectada a una VPN
let amIProxied: Bool = IOSSecuritySuite.amIProxied(considerVPNConnectionAsProxy: true)
Módulo detector de modo de bloqueo
let amIInLockdownMode: Bool = IOSSecuritySuite.amIInLockdownMode()
Funcionalidades experimentales
Módulo detector de hooks en tiempo de ejecución
let amIRuntimeHooked: Bool = amIRuntimeHook(dyldWhiteList: dylds, detectionClass: SomeClass.self, selector: #selector(SomeClass.someFunction), isClassMethod: false)
Módulo de denegación de hooks de símbolos
// Si queremos denegar el hook de símbolo de una función Swift, tenemos que pasar el nombre mangled de esa función
denySymbolHook("$s10Foundation5NSLogyySS_s7CVarArg_pdtF") // denegando el hook de la función NSLog
NSLog("Hello Symbol Hook")
denySymbolHook("abort")
abort()
Módulo detector de MSHook
// Declaración de función
func someFunction(takes: Int) -> Bool {
return false
}
// Definiendo FunctionType : @convention(thin) indica una referencia de función "thin", que usa la convención de llamada de Swift sin parámetros especiales "self" o "context".
typealias FunctionType = @convention(thin) (Int) -> (Bool)
// Obteniendo la dirección del puntero de la función que queremos verificar
func getSwiftFunctionAddr(_ function: @escaping FunctionType) -> UnsafeMutableRawPointer {
return unsafeBitCast(function, to: UnsafeMutableRawPointer.self)
}
let funcAddr = getSwiftFunctionAddr(someFunction)
let amIMSHooked = IOSSecuritySuite.amIMSHooked(funcAddr)
Módulo de denegación de MSHook
// Declaración de función
func denyDebugger(value: Int) {
}
// Definiendo FunctionType : @convention(thin) indica una referencia de función "thin", que usa la convención de llamada de Swift sin parámetros especiales "self" o "context".
typealias FunctionType = @convention(thin) (Int)->()
// Obteniendo la dirección de la función original
let funcDenyDebugger: FunctionType = denyDebugger
let funcAddr = unsafeBitCast(funcDenyDebugger, to: UnsafeMutableRawPointer.self)
if let originalDenyDebugger = denyMSHook(funcAddr) {
// Llama a la función original con 1337 como argumento Int
unsafeBitCast(originalDenyDebugger, to: FunctionType.self)(1337)
} else {
denyDebugger()
}
Módulo verificador de integridad de archivos
// Determina si la aplicación ha sido manipulada
if IOSSecuritySuite.amITampered([.bundleID("biz.securing.FrameworkClientApp"),
.mobileProvision("2976c70b56e9ae1e2c8e8b231bf6b0cff12bbbd0a593f21846d9a004dd181be3"),
.machO("IOSSecuritySuite", "6d8d460b9a4ee6c0f378e30f137cebaf2ce12bf31a2eef3729c36889158aa7fc")]).result {
print("He sido manipulado.")
}
else {
print("No he sido manipulado.")
}
// Verificar manualmente el valor hash SHA256 de un dylib cargado
if let hashValue = IOSSecuritySuite.getMachOFileHashValue(.custom("IOSSecuritySuite")), hashValue == "6d8d460b9a4ee6c0f378e30f137cebaf2ce12bf31a2eef3729c36889158aa7fc" {
print("No he sido manipulado.")
}
else {
print("He sido manipulado.")
}
// Verificar el valor hash SHA256 del ejecutable principal
// Consejo: Tu aplicación puede recuperar este valor del servidor
if let hashValue = IOSSecuritySuite.getMachOFileHashValue(.default), hashValue == "tu-valor-hash-del-ejecutable-de-la-aplicación" {
print("No he sido manipulado.")
}
else {
print("He sido manipulado.")
}
Módulo de detección de puntos de interrupción
func denyDebugger() {
// Establece un punto de interrupción aquí
}
typealias FunctionType = @convention(thin) ()->()
let func_denyDebugger: FunctionType = denyDebugger // `: FunctionType` es obligatorio
let func_addr = unsafeBitCast(func_denyDebugger, to: UnsafeMutableRawPointer.self)
let hasBreakpoint = IOSSecuritySuite.hasBreakpointAt(func_addr, functionSize: nil)
if hasBreakpoint {
print("Se encontró un punto de interrupción en la función especificada")
} else {
print("No se encontró un punto de interrupción en la función especificada")
}
Módulo de detección de puntos de vigilancia
// Establece un punto de interrupción en la función testWatchpoint
func testWatchpoint() -> Bool{
// lldb: watchpoint set expression ptr
var ptr = malloc(9)
// lldb: watchpoint set variable count
var count = 3
return IOSSecuritySuite.hasWatchpoint()
}
Consideraciones de seguridad
Antes de usar este y otros verificadores de seguridad de plataforma, debes entender que:
- ¡Incluir esta herramienta en tu proyecto no es lo único que debes hacer para mejorar la seguridad de tu aplicación! Puedes leer un documento técnico general de seguridad móvil aquí.
- Detectar si un dispositivo está jailbroken se realiza localmente en el dispositivo. ¡Esto significa que cualquier detector de jailbreak puede ser omitido (¡incluso este)!
- Se considera que el código Swift es más difícil de manipular dinámicamente que Objective-C. Dado que esta librería está escrita en Swift puro, los métodos de IOSSecuritySuite no deberían estar expuestos al runtime de Objective-C (lo que hace más difícil sortearlos ✅). Debes saber que un atacante aún puede usar MSHookFunction/MSFindSymbol en símbolos de Swift y cambiar dinámicamente el flujo de ejecución del código Swift.
Contribución ❤️
¡Sí, por favor! Si tienes una mejor idea o simplemente quieres mejorar este proyecto, contáctame en Twitter o LinkedIn. ¡Las pull requests son más que bienvenidas!
Agradecimientos especiales: 👏🏻
- kubajakowski por señalar el problema con el método
canOpenURL(_:) - olbartek por la revisión de código y pull request
- benbahrenburg por varias mejoras en ISS
- fotiDim por agregar nuevas rutas de archivos a verificar
- gcharita por agregar soporte para Swift Package Manager
- rynaardb por crear el método
amIJailbrokenWithFailedChecks() - undeaDD por varias mejoras en ISS
- fnxpt por agregar múltiples detecciones de JB
- TannerJin por los módulos de detección MSHook, RuntimeHook, SymbolHook y Watchpoint
- NikoXu por agregar el módulo de integridad de archivos
- hellpf por corregir un problema de socket colgante
- Ant-tree por mejorar la resistencia a hooks
- izmcm por implementar el método
amIReverseEngineeredWithFailedChecks() - sanu por proporcionar nuevas verificaciones de archivos
- marsepu por una PR bien hecha con nuevas mejoras
- mkj-is por una PR que mejora el rendimiento de ISS 🚄
- LongXiangGuo por una PR que agrega el manifiesto de privacidad
- Coeur por mejoras y correcciones de errores en ISS
- Adobels por ajustar ISS a los nuevos requisitos de Apple
TODO
- Investigar la detección de Installer5 y Zebra Package Manager (alternativas a Cydia)
- Detector de hidejb de Dopamine
Licencia
Consulta el archivo LICENSE.
Referencias
Al crear esta herramienta utilicé:
- 🔗 https://github.com/TheSwiftyCoder/JailBreak-Detection
- 🔗 https://github.com/abhinashjain/jailbreakdetection
- 🔗 https://gist.github.com/ddrccw/8412847
- 🔗 https://gist.github.com/bugaevc/4307eaf045e4b4264d8e395b5878a63b
- 📚 "iOS Application Security" de David Thiel