PDF herunterladen: 2022_C00C00R00CON_jailbreak.pdf
Ohne JailBreak
Mit ptrace (lldb / frida) → benötigt die App die Berechtigung get-task-allow
Durch das Einfügen von Frida-Code muss die App neu verpackt werden
In beiden Fällen müssen Sie von der Bewerbung zurücktreten
aber es hat viele Nebenwirkungen:
Andere Team-ID
Dateien werden geändert
Mit einem JailBreak
Dem Reverse-Engineering-Schutz werden Mechanismen zur Jailbreak-Erkennung hinzugefügt, um die Ausführung der App auf einem Gerät mit Jailbreak zu erschweren. Dies blockiert einige der Tools und Techniken, die Reverse Engineers gerne verwenden. Wie die meisten anderen Verteidigungsarten ist die Jailbreak-Erkennung an sich nicht sehr effektiv, aber verstreute Überprüfungen im gesamten Quellcode der App können die Wirksamkeit des gesamten Anti-Manipulation-Systems verbessern.
Die Sicherheitsrisiken für Unternehmen, die durch Jailbreaking entstehen, verschärfen sich angesichts der Tools, mit denen Benutzer gängige Jailbreak-Erkennungsmethoden einfach umgehen können. Ein Benutzer kann jede App-Optimierung wie Spotify++ direkt aus dem Drittanbieter-App-Store Cydia herunterladen. Viele Anwendungen bieten eine Jailbreak-Erkennung, ebenso wie viele Medien- und Finanzdienstleistungs-Apps, die die Piraterie von Inhalten bzw. die Kompromittierung von Konten begrenzen möchten. Leider basieren diese Jailbreak-Erkennungen auf einer Kombination aus relativ einfachen und vermeidbaren Tests, wie zum Beispiel:
Die grundlegende Einschränkung bei diesen und vergleichbaren Erkennungstests besteht darin, dass sie als clientseitige Tests von Angreifern abgerufen, rückentwickelt und umgangen werden können. Darüber hinaus müssen die Apps, die diese Jailbreak-Erkennungstests durchführen (z. B. die MDM-App), den App-Überprüfungsprozess von Apple durchlaufen, wodurch der Umfang der Daten begrenzt ist, die sie zur Analyse des Jailbreak-Status eines Geräts sammeln können. Werfen wir einen kurzen Blick darauf:
Suchen Sie nach Dateien und Verzeichnissen, die typischerweise mit Jailbreaks in Zusammenhang stehen, wie zum Beispiel:
//suspicious system and app paths to check
private static var suspicousAppandSystemPaths : [ String ] {
return [
" /usr/sbin/frida-server " ,
" /etc/apt/sources.list.d/electra.list " ,
" /etc/apt/sources.list.d/sileo.sources " ,
" /.bootstrapped_electra " ,
" /usr/lib/libjailbreak.dylib " ,
" /jb/lzma " ,
" /.cydia_no_stash " ,
" /.installed_unc0ver " ,
" /jb/offsets.plist " ,
" /usr/share/jailbreak/injectme.plist " ,
" /etc/apt/undecimus/undecimus.list " ,
" /var/lib/dpkg/info/mobilesubstrate.md5sums " ,
" /Library/MobileSubstrate/MobileSubstrate.dylib " ,
" /jb/jailbreakd.plist " ,
" /jb/amfid_payload.dylib " ,
" /jb/libjailbreak.dylib " ,
" /usr/libexec/cydia/firmware.sh " ,
" /var/lib/cydia " ,
" /etc/apt " ,
" /private/var/lib/apt " ,
" /private/var/Users/ " ,
" /var/log/apt " ,
" /Applications/Cydia.app " ,
" /private/var/stash " ,
" /private/var/lib/apt/ " ,
" /private/var/lib/cydia " ,
" /private/var/cache/apt/ " ,
" /private/var/log/syslog " ,
" /private/var/tmp/cydia.log " ,
" /Applications/Icy.app " ,
" /Applications/MxTube.app " ,
" /Applications/RockApp.app " ,
" /Applications/blackra1n.app " ,
" /Applications/SBSettings.app " ,
" /Applications/FakeCarrier.app " ,
" /Applications/WinterBoard.app " ,
" /Applications/IntelliScreen.app " ,
" /private/var/mobile/Library/SBSettings/Themes " ,
" /Library/MobileSubstrate/CydiaSubstrate.dylib " ,
" /System/Library/LaunchDaemons/com.ikey.bbot.plist " ,
" /Library/MobileSubstrate/DynamicLibraries/Veency.plist " ,
" /Library/MobileSubstrate/DynamicLibraries/LiveClock.plist " ,
" /System/Library/LaunchDaemons/com.saurik.Cydia.Startup.plist " ,
" /Applications/Cydia.app " ,
" /Applications/blackra1n.app " ,
" /Applications/FakeCarrier.app " ,
" /Applications/Icy.app " ,
" /Applications/IntelliScreen.app " ,
" /Applications/MxTube.app " ,
" /Applications/RockApp.app " ,
" /Applications/SBSettings.app " ,
" /Applications/WinterBoard.app "
]
}
Am häufigsten werden diese mithilfe des überprüft
-(BOOL)fileExistsAtPath:(NSString*)
Pfadmethode in NSFileManager oder FileManager.default.fileExists(atPath: path)
. Es gibt jedoch auch Anwendungen, die untergeordnete C-Funktionen wie fopen(), stat() oder access() verwenden.
Eine andere Möglichkeit, nach Jailbreaking-Mechanismen zu suchen, besteht darin, zu versuchen, an einen Speicherort zu schreiben, der sich außerhalb der Sandbox der Anwendung befindet. Sie können dies erreichen, indem Sie die Anwendung versuchen lassen, eine Datei beispielsweise im Verzeichnis /private
zu erstellen. Wenn die Datei erfolgreich erstellt wurde, wurde das Gerät gejailbreakt.
Bei dieser Methode werden die Berechtigungen bestimmter Dateien und Verzeichnisse im System überprüft. Auf einem Gerät mit Jailbreak haben mehr Verzeichnisse Schreibzugriff als auf einem nicht kompromittierten Gerät. Ein Beispiel hierfür ist die Root-Partition, die ursprünglich nur über Leserechte verfügt. Wenn festgestellt wird, dass es über Lese- und Schreibberechtigungen verfügt, bedeutet dies, dass das Gerät einen Jailbreak aufweist. Es gibt verschiedene Möglichkeiten, diese Prüfungen durchzuführen, z. B. die Verwendung von NSFileManager und C-Funktionen wie statfs().
Schnell:
do {
let pathToFileInRestrictedDirectory = " /private/jailbreak.txt "
try " This is a test. " . write ( toFile : pathToFileInRestrictedDirectory , atomically : true , encoding : String . Encoding . utf8 )
try FileManager . default . removeItem ( atPath : pathToFileInRestrictedDirectory )
// Device is jailbroken
} catch {
// Device is not jailbroken
}
Ziel-C:
NSError *error;
NSString *stringToBeWritten = @" This is a test. " ;
[stringToBeWritten writeToFile: @" /private/jailbreak.txt " atomically: YES
encoding: NSUTF8StringEncoding error: &error];
if (error == nil ) {
// Device is jailbroken
return YES ;
} else {
// Device is not jailbroken
[[ NSFileManager defaultManager ] removeItemAtPath: @" /private/jailbreak.txt " error: nil ];
}
Es gibt verschiedene Möglichkeiten, diese Prüfungen durchzuführen, z. B. die Verwendung von NSFileManager und C-Funktionen wie statfs(), open(), utimes(), stat(), pathconf(), stat64(), fopen().
Sie können Protokollhandler überprüfen, indem Sie versuchen, eine Cydia-URL zu öffnen. Der Cydia App Store, den praktisch jedes Jailbreaking-Tool standardmäßig installiert, installiert den Protokollhandler cydia://.
Schnell:
if let url = URL ( string : " cydia://package/com.example.package " ) , UIApplication . shared . canOpenURL ( url ) {
// Device is jailbroken
}
Ziel-C:
if ([[UIApplication sharedApplication ] canOpenURL: [ NSURL URLWithString: @" cydia://package/com.example.package " ]]){
// Device is jailbroken
}
Diese einfachen Prüfungen können von Angreifern abgerufen, rückentwickelt und umgangen werden.
ptrace ( PT_DENY_ATTACH );
void try_kill () {
const int pid = getpid ();
int ret = kill (pid, 0 );
}
Laut der Manpage von kill ( man 2 kill
) wird das Signal 0
verwendet, um zu überprüfen, ob die im ersten Parameter angegebene pid
wirklich existiert.
[…] Ein Wert von 0 führt jedoch dazu, dass eine Fehlerprüfung durchgeführt wird (ohne dass ein Signal gesendet wird). Dies kann verwendet werden, um die Gültigkeit der PID zu überprüfen.
Auf diesen Kill -Vorgang folgt PTRACE
Prüfung:
inline bool ptrace_detect () {
int32_t opt[ 4 ] = {
CTL_KERN,
KERN_PROC,
KERN_PROC_PID,
getpid (),
};
kinfo_proc info;
sysctl (opt, 4 , &info, sizeof (kinfo_proc), nullptr , 0 );
return info. kp_proc . p_flag & P_TRACED;
}
getppid() == 1
getfsstat64(), statvfs()
fcntl(F_ADDSIGS)
csops(CS_OPS_MARKKILL)
Wir können die Integrität der Signatur unserer Binärdatei überprüfen. Diese Prüfung beginnt mit dem Öffnen der Haupt-App-Binärdatei von der Festplatte, der Suche nach der kSecCodeMagicEmbeddedSignature-Sequenz 0xfade0cc0
, dem Lesen der Berechtigungen und der Berechnung der Prüfsumme.
Das Codesignatursegment enthält eine Superlob-Struktur, die wiederum andere Blobs unterschiedlicher Art enthält. Die Struktur beider ist in einem weiteren Open-Source-Apple-Code definiert:
/*
* Structure of an embedded-signature SuperBlob
*/
typedef struct __BlobIndex {
uint32_t type; /* type of entry */
uint32_t offset; /* offset of entry */
} CS_BlobIndex;
typedef struct __SuperBlob {
uint32_t magic; /* magic number */
uint32_t length; /* total length of SuperBlob */
uint32_t count; /* number of index entries following */
CS_BlobIndex index[]; /* (count) entries */
/* followed by Blobs in no particular order as indicated by offsets in index */
} CS_SuperBlob;
Der Super-Blob enthält lediglich etwas Magie, die Länge des gesamten Code-Signatur-Abschnitts, eine Anzahl der Blobs und eine Reihe von Indizes für diese Blobs. Die verschiedenen identifizierenden Blob-Magies sind in dieser Datei definiert:
/*
* Magic numbers used by Code Signing
*/
enum {
kSecCodeMagicRequirement = 0xfade0c00 , /* single requirement */
kSecCodeMagicRequirementSet = 0xfade0c01 , /* requirement set */
kSecCodeMagicCodeDirectory = 0xfade0c02 , /* CodeDirectory */
kSecCodeMagicEmbeddedSignature = 0xfade0cc0 , /* single-architecture embedded signature */
kSecCodeMagicDetachedSignature = 0xfade0cc1 , /* detached multi-architecture signature */
kSecCodeMagicEntitlement = 0xfade7171 , /* entitlement blob */
};
Beispielsweise verfügt die iOS- ps
Binärdatei über vier Inhaltsblobs, die auf den anfänglichen Superlob folgen:
Dies sind jeweils:
0xfade0c02
), das Sie daran erkennen können, dass es den qualifizierten Binärnamen com.apple.ps
enthält.0xfade0c01
).0xfade7171
).0xfade0b01
).Versuchen Sie, die App nach einer großen Zeitüberschreitung anzuhalten und verlassen Sie den Ort der Jailbreak-Erkennung nicht direkt.
fork()
Prozessgabelung. Sandboxd verweigert Anwendungen nicht die Möglichkeit, fork(), popen() oder andere C-Funktionen zu verwenden, um untergeordnete Prozesse auf Geräten mit Jailbreak zu erstellen. Sandboxd verweigert jedoch explizit die Prozessverzweigung auf Geräten ohne Jailbreak. Daher kann eine Anwendung durch Überprüfen der zurückgegebenen PID bei fork() erkennen, ob ein Gerät kompromittiert ist. Wenn der Fork erfolgreich ist, kann die App daraus schließen, dass sie auf einem Gerät mit Jailbreak läuft.
system()
Der Aufruf der system()-Funktion mit einem NULL-Argument auf einem Gerät ohne Jailbreak gibt 0 zurück. Wenn Sie dasselbe auf einem Gerät mit Jailbreak tun, wird 1 zurückgegeben. Dies liegt daran, dass die Funktion prüft, ob /bin/sh existiert, und zwar nur auf Geräte mit Jailbreak.
SSH-Loopback-Verbindungen. Aufgrund der sehr großen Anzahl von Geräten mit Jailbreak, auf denen OpenSSH installiert ist, versuchen einige Anwendungen, eine Verbindung zu 127.0.0.1 auf Port 22 herzustellen. Wenn die Verbindung erfolgreich ist, bedeutet dies, dass OpenSSH installiert ist und ausgeführt wird, was beweist, dass das Gerät einen Jailbreak hat.
Überprüfen Sie den Loopback auf 22 (OpenSSH) und 44 (checkra1n) geöffnete Ports.
Diese Erkennungsmethode beginnt mit dem Aufruf von Funktionen wie _dyld_image_count()
und _dyld_get_image_name()
um zu sehen, welche Dylibs derzeit geladen sind. Es ist sehr schwierig, diese Methode dynamisch zu patchen, da die Patches selbst Teil von Dylibs sind.
/usr/lib/substitute-inserter.dylib
zum Beispiel
Kann dlopen/Speicherscan/dyld interne Strukturen usw. verwenden.
private static func checkDYLD ( ) -> Bool {
let suspiciousLibraries = [
" FridaGadget " ,
" frida " ,
" cynject " ,
" libcycript "
]
for libraryIndex in 0 ..< _dyld_image_count ( ) {
guard let loadedLibrary = String ( validatingUTF8 : _dyld_get_image_name ( libraryIndex ) ) else { continue }
for suspiciousLibrary in suspiciousLibraries {
if loadedLibrary . lowercased ( ) . contains ( suspiciousLibrary . lowercased ( ) ) {
return true
}
}
}
return false
}
Überprüfen Sie die Codeintegrität
Versuchen Sie, Frida zu entdecken
private static func isFridaRunning ( ) -> Bool {
func swapBytesIfNeeded ( port : in_port_t ) -> in_port_t {
let littleEndian = Int ( OSHostByteOrder ( ) ) == OSLittleEndian
return littleEndian ? _OSSwapInt16 ( port ) : port
}
var serverAddress = sockaddr_in ( )
serverAddress . sin_family = sa_family_t ( AF_INET )
serverAddress . sin_addr . s_addr = inet_addr ( " 127.0.0.1 " )
serverAddress . sin_port = swapBytesIfNeeded ( port : in_port_t ( 27042 ) )
let sock = socket ( AF_INET , SOCK_STREAM , 0 )
let result = withUnsafePointer ( to : & serverAddress ) {
$0 . withMemoryRebound ( to : sockaddr . self , capacity : 1 ) {
connect ( sock , $0 , socklen_t ( MemoryLayout < sockaddr_in > . stride ) )
}
}
if result != - 1 {
return true
}
return false
}
Generell gilt: Je komplizierter die Jailbreak-Erkennung ist, desto schwieriger ist sie zu erkennen und zu umgehen. Der häufigste Fehler bei der Implementierung der Jailbreak-Erkennung liegt häufig in der Implementierung selbst.
Wir stoßen häufig auf Apps, die über eine hervorragende Jailbreak-Erkennung verfügen, deren Implementierung jedoch in einer Funktion erfolgt, die je nachdem, ob das Gerät einen Jailbreak aufweist, „true“ oder „false“ zurückgibt. In diesen Fällen umgehen wir die Jailbreak-Erkennung, indem wir Cycript oder ein ähnliches Tool verwenden, um den Rückgabewert der Erkennungsfunktion umzukehren.
In der Praxis besteht die beste Jailbreak-Erkennung darin, mehrere Techniken zu kombinieren und sie in andere Funktionen zu integrieren, sodass sie nicht einfach umgangen werden können.
https://github.com/mehrankmlf/SecurityKit
https://www.synacktiv.com/sites/default/files/2021-10/2021_sthack_jailbreak.pdf
https://www.romainthomas.fr/post/21-07-pokemongo-anti-frida-jailbreak-bypass/
https://aeonlucid.com/Snapchat-detection-on-iOS/
https://github.com/AeonLucid/SnapHide
https://redmaple.tech/blogs/macho-files/