No Escape - Mobile Hacking Lab
Introduction
Welcome to the iOS Application Security Lab: Jailbreak Detection Evasion Challenge. The challenge centers around a fictitious app called No Escape, designed with robust jailbreak detection mechanisms. Your mission is to bypass these mechanisms and gain full access to the app’s functionalities using Frida.
Objective
Bypass Jailbreak Detection: Your task is to evade the jailbreak detection implemented in the No Escape app to execute arbitrary code and access all app features.
On launch, the app instantly flags the device as jailbroken and terminates.
I attempted to use Objection and several jailbreak detection bypass scripts from Frida Codeshare, but none of them worked
Objection
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
objection -g com.mobilehackinglab.No-Escape explore
Using USB device `iOS Device`
Agent injected and responds ok!
_ _ _ _
___| |_|_|___ ___| |_|_|___ ___
| . | . | | -_| _| _| | . | |
|___|___| |___|___|_| |_|___|_|_|
|___|(object)inject(ion) v1.11.0
Runtime Mobile Exploration
by: @leonjza from @sensepost
[tab] for command suggestions
com.mobilehackinglab.No-Escape on (iPhone: 14.4) [usb] # ios jailbreak disable
frida CodeShare
- https://codeshare.frida.re/@incogbyte/ios-jailbreak-bypass/
- https://codeshare.frida.re/@sdcampbell/ios-jailbreak-bypass/
- https://codeshare.frida.re/@patali09/ios-jailbreak-detection-bypass/
Extracting the .ipa
File
The provided app came in an .ipa
file essentially a ZIP archive containing the application bundle.
1
unzip No_Escape.ipa -d No_Escape
Inside the extracted folder, the binary was located in:
1
Payload/No_Escape.app/No_Escape
Reverse Engineering with Ghidra
I began reverse engineering the application binary and discovered a function named isJailbroken
. This function is invoked by two other functions and internally calls four additional functions to perform multiple jailbreak checks. The application relies on the return value of isJailbroken
to decide whether it is running on a jailbroken device. If the return value is true
, the app concludes that the device is jailbroken, displays an alert message, and then exits. If the return value is false
, the app assumes the device is not jailbroken and proceeds to retrieve the flag.
Method 1: Frida
A Frida script that enumerates all symbols in the main module and searches for any symbol whose name contains the word jailbroken
.
1
2
3
4
5
6
7
8
9
10
11
var targetModule = Process.enumerateModules()[0].name;
console.log("[*] Scanning module: " + targetModule);
var symbols = Module.enumerateSymbols(targetModule);
symbols.forEach(function(s) {
if (s.name.toLowerCase().indexOf("jailbroken") !== -1) {
console.log("[+] Found function: " + s.name + " at " + s.address);
}
});
output
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
└─# frida -U -f com.mobilehackinglab.No-Escape -l hook.js
____
/ _ | Frida 16.0.0 - 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=00008020-00032D801E32002E)
Spawning `com.mobilehackinglab.No-Escape`...
[*] Scanning module: No Escape
[+] Found function: $s9No_Escape12isJailbrokenSbyF at 0x1005a2068
[+] Found function: $s9No_Escape12isJailbrokenSbyF at 0x1005a2068
A Frida script that enumerates all symbols in the main module, hooks any symbol whose name contains jailbroken
, and forces its return value to 0
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Handle non-Objective-C functions (C/Swift exports)
var mainModule = Process.enumerateModules()[0];
console.log("[*] Scanning symbols in " + mainModule.name);
var symbols = Module.enumerateSymbols(mainModule.name);
symbols.forEach(function(s) {
if (s.name.toLowerCase().indexOf("jailbroken") !== -1) {
console.log("[+] Hooking exported function: " + s.name + " @ " + s.address);
Interceptor.attach(s.address, {
onEnter: function (args) {
console.log(" [*] Called function: " + s.name);
},
onLeave: function (retval) {
console.log(" [*] Original return: " + retval);
retval.replace(ptr("0")); // Return false/0
console.log(" [*] Modified return: " + retval);
}
});
}
});
output
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
└─# frida -U -f com.mobilehackinglab.No-Escape -l hook.js
____
/ _ | Frida 16.0.0 - 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=00008020-00032D801E32002E)
Spawning `com.mobilehackinglab.No-Escape`...
[*] Scanning symbols in No Escape
[+] Hooking exported function: $s9No_Escape12isJailbrokenSbyF @ 0x1026e2068
[+] Hooking exported function: $s9No_Escape12isJailbrokenSbyF @ 0x1026e2068
Spawned `com.mobilehackinglab.No-Escape`. Resuming main thread!
[iOS Device::com.mobilehackinglab.No-Escape ]-> [*] Called function: $s9No_Escape12isJailbrokenSbyF
[*] Called function: $s9No_Escape12isJailbrokenSbyF
[*] Original return: 0x1
[*] Modified return: 0x0
[*] Original return: 0x0
[*] Modified return: 0x0
[*] Called function: $s9No_Escape12isJailbrokenSbyF
[*] Called function: $s9No_Escape12isJailbrokenSbyF
[*] Original return: 0x1
[*] Modified return: 0x0
[*] Original return: 0x0
[*] Modified return: 0x0
Another Frida script that hooks a function by its name.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var myMethod = Module.findExportByName(null, "$s9No_Escape12isJailbrokenSbyF");
if (myMethod) {
Interceptor.attach(myMethod, {
onEnter: function (args) {
console.log("Hooked Swift method!");
},
onLeave: function (retval) {
console.log("Original return value:", retval.toInt32()); // Log the original return value
retval.replace(0); // Replace with false
console.log("Modified return value:", retval.toInt32()); // Log the modified return value
}
});
} else {
console.log("Hooking Swift method failed!");
}
Method 2: Application Patching
Right Click » Patch Instruction
1
mov w0, #0x0
This function’s return value has been forced to always be false.
File » Export Program » Format: Original File
push the patched binary to the iphone
1
└─# scp No\ Escape root@192.168.1.6:"/private/var/containers/Bundle/Application/1D3C5998-C8FB-42D6-B2DD-95057797D843/No Escape.app/"