Скачать PDF: 2022_C00C00R00CON_jailbreak.pdf
Без побега из тюрьмы
С ptrace (lldb / frida) → приложению требуется право get-task-allow.
Внедряя код Frida → приложение необходимо переупаковать.
В обоих случаях вам необходимо подать заявку на отказ.
но у него много побочных эффектов:
Другой идентификатор команды
Файлы изменены
С побегом из тюрьмы
Механизмы обнаружения взлома добавлены в защиту обратного проектирования, чтобы затруднить запуск приложения на взломанном устройстве. Это блокирует некоторые инструменты и методы, которые любят использовать реверс-инженеры. Как и большинство других типов защиты, обнаружение джейлбрейка само по себе не очень эффективно, но разбросанные проверки по исходному коду приложения могут повысить эффективность общей схемы защиты от взлома.
Риски корпоративной безопасности, создаваемые составами для взлома, в сочетании с инструментами, которые могут помочь пользователям легко обойти распространенные методы обнаружения взлома. Пользователь может загрузить любую настройку приложения, например Spotify++, непосредственно из стороннего магазина приложений Cydia. Многие приложения обеспечивают обнаружение джейлбрейка, как и многие приложения для СМИ и финансовых услуг, которые хотят ограничить пиратство контента и взлом учетных записей соответственно. К сожалению, обнаружение джейлбрейка основано на сочетании относительно простых и легко обходимых тестов, таких как:
Фундаментальное ограничение этих и аналогичных тестов обнаружения заключается в том, что злоумышленники могут получить доступ к ним, провести реверс-инжиниринг и обойти их как тесты на стороне клиента. Кроме того, приложения, выполняющие эти тесты на обнаружение джейлбрейка (например, приложение MDM), должны пройти процедуру проверки приложений Apple, что ограничивает объем данных, которые они могут собирать для анализа статуса джейлбрейка устройства. Давайте кратко рассмотрим их:
Проверьте файлы и каталоги, которые обычно связаны с джейлбрейком, например:
//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 "
]
}
Чаще всего их проверяют с помощью
-(BOOL)fileExistsAtPath:(NSString*)
метод пути в NSFileManager или FileManager.default.fileExists(atPath: path)
. Однако существуют также приложения, использующие функции C более низкого уровня, такие как fopen(), stat() или access().
Другой способ проверить наличие механизмов взлома — попытаться выполнить запись в место, находящееся за пределами «песочницы» приложения. Это можно сделать, заставив приложение попытаться создать файл, например, в каталоге /private
. Если файл создан успешно, устройство взломано.
Этот метод заключается в проверке разрешений определенных файлов и каталогов в системе. На взломанном устройстве больше каталогов имеют доступ на запись, чем на нескомпрометированном. Одним из примеров этого является корневой раздел, который изначально имеет разрешение только на чтение. Если обнаружено, что у него есть разрешения на чтение и запись, это означает, что устройство взломано. Существуют разные способы выполнения этих проверок, например использование NSFileManager и функций C, таких как statfs().
Быстрый:
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
}
Цель-С:
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 ];
}
Существуют различные способы выполнения этих проверок, например использование NSFileManager и функций C, таких как statfs(), open(), utimes(), stat(), pathconf(), stat64(), fopen().
Вы можете проверить обработчики протокола, попытавшись открыть URL-адрес Cydia. Магазин приложений Cydia, который по умолчанию устанавливается практически в каждом инструменте для взлома, устанавливает обработчик протокола cydia://.
Быстрый:
if let url = URL ( string : " cydia://package/com.example.package " ) , UIApplication . shared . canOpenURL ( url ) {
// Device is jailbroken
}
Цель-С:
if ([[UIApplication sharedApplication ] canOpenURL: [ NSURL URLWithString: @" cydia://package/com.example.package " ]]){
// Device is jailbroken
}
Злоумышленники могут получить доступ к этим простым проверкам, перепроектировать их и обойти.
ptrace ( PT_DENY_ATTACH );
void try_kill () {
const int pid = getpid ();
int ret = kill (pid, 0 );
}
Согласно man-странице kill ( man 2 kill
), сигнал 0
используется для проверки того, что pid
, указанный в первом параметре, действительно существует.
[…] Однако значение 0 приведет к выполнению проверки ошибок (без отправки сигнала). Это можно использовать для проверки достоверности pid.
За этой операцией уничтожения следует проверка PTRACE
:
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)
Мы можем проверить целостность подписи нашего двоичного файла. Эта проверка начинается с открытия основного двоичного файла приложения с диска, поиска до последовательности kSecCodeMagicEmbeddedSignature 0xfade0cc0
, чтения прав и вычисления контрольной суммы.
Сегмент подписи кода содержит структуру superblob, которая сама содержит другие BLOB-объекты разных типов. Структура обоих определена в еще одном коде Apple с открытым исходным кодом:
/*
* 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;
Суперблоб просто содержит некоторую магию, длину всей секции подписи кода, количество больших двоичных объектов и массив индексов этих больших двоичных объектов. В этом файле определены различные идентифицирующие магические объекты BLOB-объектов:
/*
* 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 */
};
Например, двоичный файл iOS ps
содержит четыре больших объекта контента, следующих за начальным суперобъектом:
Это соответственно:
0xfade0c02
), который вы можете заметить, поскольку он имеет квалифицированное двоичное имя com.apple.ps
.0xfade0c01
).0xfade7171
).0xfade0b01
).Постарайтесь остановить приложение после большого таймаута и не выходить сразу из места обнаружения джейлбрейка.
fork()
Форкирование процесса. Sandboxd не запрещает приложениям использовать fork(), popen() или любые другие функции C для создания дочерних процессов на взломанных устройствах. Однако Sandboxd явно запрещает разветвление процессов на устройствах без джейлбрейка. Таким образом, проверив возвращенный pid функцией fork(), приложение может определить, скомпрометировано ли устройство. Если форк пройдет успешно, приложение сможет сделать вывод, что оно работает на взломанном устройстве.
system()
Вызов функции system() с аргументом NULL на устройстве без джейлбрейка вернет 0. Выполнение того же самого на устройстве с джейлбрейком вернет 1. Это связано с тем, что функция будет проверять, существует ли /bin/sh, и он существует только на взломанные устройства.
Петлевые соединения SSH. Из-за очень большого количества взломанных устройств, на которых установлен OpenSSH, некоторые приложения пытаются подключиться к 127.0.0.1 через порт 22. Если соединение установлено успешно, это означает, что OpenSSH установлен и работает, что доказывает, что устройство взломано.
Проверьте петлю для 22 (OpenSSH) и 44 (checkra1n) открытых портов.
Этот метод обнаружения начинается с вызова таких функций, как _dyld_image_count()
и _dyld_get_image_name()
чтобы узнать, какие библиотеки dylib в данный момент загружены. Этот метод очень сложно динамически патчить из-за того, что сами патчи являются частью dylibs.
/usr/lib/substitute-inserter.dylib
например
Можно использовать внутренние структуры dlopen/сканирование памяти/dyld и т. д.
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
}
Проверьте целостность кода
Попробуй обнаружить Фриду
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
}
В целом, чем сложнее обнаружение джейлбрейка, тем труднее его обнаружить и обойти. Самая распространенная ошибка при реализации обнаружения джейлбрейка часто кроется в самой реализации.
Мы часто сталкиваемся с приложениями, которые хорошо обнаруживают джейлбрейк, но реализация заключается в одной функции, которая возвращает true или false в зависимости от того, взломано ли устройство. В этих случаях мы обходим обнаружение джейлбрейка, используя Cycript или аналогичный инструмент для инвертирования возвращаемого значения функции обнаружения.
На практике лучший метод обнаружения джейлбрейка объединяет несколько методов и интегрирует их в другие функции, чтобы их нельзя было легко обойти.
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/