My fellow colleague Bernhard developed two iOS Crackme and here is the writeup.
Uncrackable Level 1
From the main view, it hints that the flag can be found in the hidden label.
Well if that is not a red herring like every crackme challenge, lets try to unhidden the hidden label using cycript. Lets print the view hierarchy and locate the address for the hidden label.
The command [[UIApp keyWindow] recursiveDescription].toString() returns the view hierarchy of keyWindow. The description of every subview and sub-subview of keyWindow will be shown and the indentation space reflects the relationships of each views. For an example UILabel, UITextField and UIButton are subviews of UIView.
VP:~ root# ps aux | grep Crack
root 730 0.0 0.0 535232 432 s000 R+ 5:04PM 0:00.01 grep Crack
mobile 728 0.0 0.8 586328 8368 ?? Ss 5:04PM 0:00.35 /var/mobile/Containers/Bundle/Application/A8BD91A9-3C81-4674-A790-AF8CDCA8A2F1/UnCrackable Level 1.app/UnCrackable Level 1
VP:~ root# ./cycript -p 728
cy# UIApp.keyWindow.recursiveDescription().toString()
`<UIWindow: 0x155b8420; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x155a0080>; layer = <UIWindowLayer: 0x155acd40>>
| <UIView: 0x156a7300; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x156a74a0>>
| | <UILabel: 0x156a3b10; frame = (0 40; 82 20.5); text = 'i am groot!'; hidden = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x156a3bf0>>
| | <UILabel: 0x156a22f0; frame = (0 110.5; 320 20.5); text = 'A Secret Is Found In The ...'; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x156a2550>>
| | <UITextField: 0x156a3e70; frame = (8 141; 304 30); text = ''; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x155c2ce0>; layer = <CALayer: 0x156a4140>>
| | | <_UITextFieldRoundedRectBackgroundViewNeue: 0x156a65e0; frame = (0 0; 304 30); opaque = NO; autoresize = W+H; userInteractionEnabled = NO; layer = <CALayer: 0x156a6800>>
| | <UIButton: 0x155ba6d0; frame = (8 191; 304 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x155ba980>>
| | | <UIButtonLabel: 0x155b2ac0; frame = (133 6; 38 18); text = 'Verify'; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x155b3680>>
| | <_UILayoutGuide: 0x156a7500; frame = (0 0; 0 20); hidden = YES; layer = <CALayer: 0x156a7700>>
| | <_UILayoutGuide: 0x155c0a00; frame = (0 568; 0 0); hidden = YES; layer = <CALayer: 0x155c0fe0>>`
We can see that the UILabel 0x156a3b10 is hidden.
<UILabel: 0x156a3b10; frame = (0 40; 82 20.5); text = 'i am groot!'; hidden = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x156a3bf0>>
We can unhidden it by running the following command
cy# [#0x16e8f840 setHidden:NO]
And we have our flag :), lets move onto level 2.
Crackme Level 2
The second app has a number of security implementations, to identify those I did some minor reverse engineering. Let's start off with class-dump to identify what header class are used to get a glimpse of the application internal.
$ class-dump -S -s -H uncrackable2_32 -o uncrackable2.dump
$ ~/tools/ios/hackme/uncrackable2.dump|
⇒ ls -laR
.:
total 64
drwxr-xr-x 17 tnayr staff 578 Apr 20 16:58 .
drwxr-xr-x 16 tnayr staff 544 Apr 20 16:58 ..
-rw-r--r-- 1 tnayr staff 288 Apr 20 16:58 AESCrypt.h
-rw-r--r-- 1 tnayr staff 929 Apr 20 16:58 AppDelegate.h
-rw-r--r-- 1 tnayr staff 362 Apr 20 16:58 CDStructures.h
-rw-r--r-- 1 tnayr staff 238 Apr 20 16:58 NSData-Base64Additions.h
-rw-r--r-- 1 tnayr staff 555 Apr 20 16:58 NSData-CommonCryptor.h
-rw-r--r-- 1 tnayr staff 328 Apr 20 16:58 NSData-CommonDigest.h
-rw-r--r-- 1 tnayr staff 297 Apr 20 16:58 NSData-CommonHMAC.h
-rw-r--r-- 1 tnayr staff 949 Apr 20 16:58 NSData-LowLevelCommonCryptor.h
-rw-r--r-- 1 tnayr staff 253 Apr 20 16:58 NSError-CommonCryptoErrorDomain.h
-rw-r--r-- 1 tnayr staff 880 Apr 20 16:58 NSObject-Protocol.h
-rw-r--r-- 1 tnayr staff 268 Apr 20 16:58 NSString-Base64Additions.h
-rw-r--r-- 1 tnayr staff 5237 Apr 20 16:58 UIApplicationDelegate-Protocol.h
-rw-r--r-- 1 tnayr staff 779 Apr 20 16:58 ViewController.h
-rw-r--r-- 1 tnayr staff 303 Apr 20 16:58 __ARCLiteIndexedSubscripting__-Protocol.h
-rw-r--r-- 1 tnayr staff 279 Apr 20 16:58 __ARCLiteKeyedSubscripting__-Protocol.h
AESCrypt.h #import "NSObject.h" @interface AESCrypt : NSObject { }
+ (id)decrypt:(id)arg1 password:(id)arg2;
+ (id)encrypt:(id)arg1 password:(id)arg2;
@end
After viewing AESCrypt.h, I suspect that the flag encrypts and decrypt with AESCrypt. but we should make no assumption and analyze it with a dissembler and see how do things work.
viewDidLoad
We will first look at the viewDidLoad since it is to load functions and checks before the view controller and a common place to implement security checks.
There are a few things that tingle ma spider sense. Our Objective here is to identify security implementation that can possibly be anti-debugging, anti-jailbreak, memory integrity, application integrity and so on. I have identified that anti-debugging, anti-jailbreak were implemented.
Anti-debugging
Ptrace System Call
It is using ptrace system call to prevent process from being traced.
protectAgainstDebugger functions
It is using sysctl call to detect whether if the process is being debugged.
Jailbreak protection
Now onto jailbreak protection, it is obvious that it uses a list of file to determine if the phone is jailbroken.
/Applications/Cydia.app
/Library/MobileSubstrate/MobileSubstrate.dylib
/bin/bash
/usr/sbin/sshd
/etc/apt
Remote debugging
When I try to submit the flag on the app, there will be a jailbreak alert which again verified our observation about jailbreak protection. Now how are we going to test if there is actually debugging protection? We are going to use lldb and there is a fantastic write up on how to set up debugging on ios. link link After setting the environment up, let's see what happen if we try to attach a debugger onto the process.
$debugserver *:6666 -x backboard "/var/mobile/Containers/Bundle/Application/C5DC5006-8D20-4C88-BE41-E44B570A49B0/UnCrackable Level 2.app/UnCrackable Level 2"
⇒ lldb
Process 2548 stopped
* thread #1, stop reason = signal SIGSTOP
frame #0: 0x1febe000 dyld`_dyld_start
dyld`_dyld_start:
-> 0x1febe000 <+0>: mov r8, sp
0x1febe004 <+4>: sub sp, sp, #16
0x1febe008 <+8>: bic sp, sp, #7
0x1febe00c <+12>: ldr r3, [pc, #0x70] ; <+132>
(lldb) c
Process 2548 resuming
2017-04-20 21:24:53.456 UnCrackable Level 2[2548:131476] === SSL Kill Switch 2: Preference set to 0.
2017-04-20 21:24:53.457 UnCrackable Level 2[2548:131476] === SSL Kill Switch 2: Subtrate hook disabled.
2017-04-20 21:24:53.546 UnCrackable Level 2[2548:131476] Introspy - Profiling disabled for sg.vp.UnCrackable-2
Process 2548 exited with status = 45 (0x0000002d)
Aha!!! Exit status 45 and that may suggest that ptrace was used to prevent debugging which was identified earlier on our static analysis.
Bypass anti-debugging
Now we have identified there is anti-debugging (ptrace and sysctl) and jailbreak detection (list of files and Cydia uri) from static analysis and we will bypass them :)
Ptrace
We can easily bypass ptrace method by modifying the request argument that is passed into the ptrace function. If ptrace is set to 31 - PT_DENY_ATTACH as shows as the list below will deny any traces made to the process.
define PT_TRACE_ME 0 /* child declares it’s being traced */
define PT_READ_I 1 /* read word in child’s I space */
define PT_READ_D 2 /* read word in child’s D space */
define PT_READ_U 3 /* read word in child’s user structure */
define PT_WRITE_I 4 /* write word in child’s I space */
define PT_WRITE_D 5 /* write word in child’s D space */
define PT_WRITE_U 6 /* write word in child’s user structure */
define PT_CONTINUE 7 /* continue the child */
define PT_KILL 8 /* kill the child process */
define PT_STEP 9 /* single step the child */
define PT_ATTACH 10 /* trace some running process */
define PT_DETACH 11 /* stop tracing a process */
define PT_SIGEXC 12 /* signals as exceptions for current_proc */
define PT_THUPDATE 13 /* signal for thread# */
define PT_ATTACHEXC 14 /* attach to running process with signal exception */
define PT_FORCEQUOTA 30 /* Enforce quota for root */
define PT_DENY_ATTACH 31
define PT_FIRSTMACH 32 /* for machine-specific requests *
We identified earlier that ptrace functions is set to 31 which is PT_DENY_ATTACH and we can bypass it by replacing the request argument from 31 to -1. We will write a tweaks to hook the functions.
static int (*oldptrace)(int request, pid_t pid, caddr_t addr, int data);
static int newptrace(int request, pid_t pid, caddr_t addr, int data){
if (request == 31) {
request = -1;
}
printf("newptrace:%d\n\n",request);
return oldptrace(request,pid,addr,data);
}
MSHookFunction ((void *)MSFindSymbol(NULL,"_ptrace"), (void *)newptrace, (void **)&oldptrace);
Bypass Sysctl debugging protection
Note that unlike the ptrace technique this method doesn’t prevent a debugger from attaching to a process. Instead, it uses the sysctl function to retrieve information about the process and determine whether it is being debugged. Apple has an article in their Mac Technical Q&As with sample code that uses this method: Detecting the Debugger
int (*oldsysctl) (int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
int newsysctl (int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen)
{
printf("sysctl");
return 0;
};
MSHookFunction ((void *)MSFindSymbol(NULL,"_sysctl"), (void *)newsysctl, (void **)&oldsysctl);
Bypass jailbreak protection
I used xcon to bypass jailbreak protection and they have precompiled list of files that uses to detect jailbreak devices.
/.fseventsd
/.cydia_no_stash
/etc/clutch.conf
/usr/bin/codesign_allocate
/var/apt
/var/log/syslog
/var/stash
/var/run/syslog
/var/run/syslog.pid
/var/tmp/cydia.log
/var/tmp/pgloader
/evasi0n7
/evasi0n7-installed
/usr/lib/pangu_xpcd.dylib
/usr/lib/pangu_xpcd.ipod.dylib
/xuanyuansword
/tmp/cydia.log
/tmp/FlipSwitchCache
/tmp/.pange93loaded
/tmp/pgloader
/tmp/pgii
Bypass all security implementations
If you have combined both tweaks and have xcon running, you should be able to attach a debugger to the process and no longer see the jailbreak alert.
Hook AESCrypt decrypt functions
As we have mentioned earlier, the flag is encrypted and can be decrypted with AESCrypt. So let's hook the function and have it log the cleartext password. P.S: I also found out that there is no memory integrity check, so you can hook the AESCrypt function without bypass any security implementation.
%hook AESCrypt
+ (id)decrypt:(id)arg1 password:(id)arg2 { %log; id r = %orig; NSLog(@" = %@", r); return r; }
%end
and we have our password from /var/log/syslog :)
Apr 20 21:15:12 VP UnCrackable Level 2[2438]: [hookaescrypt] Tweak.xm:2 DEBUG: +[<AESCrypt: 0x9f0c4> decrypt:VaoQcPb6CChCzVmU45BGEKcNMXAYXoZvegJHYO2zqJg= password:cb17927cc23e2757aadb8d8dc7594c32]
Apr 20 21:15:12 VP UnCrackable Level 2[2438]: = shakennotstirred
Final Tweaks
%hook AESCrypt
+ (id)decrypt:(id)arg1 password:(id)arg2 { %log; id r = %orig; NSLog(@" = %@", r); return r; }
%end
static int (*oldptrace)(int request, pid_t pid, caddr_t addr, int data);
static int newptrace(int request, pid_t pid, caddr_t addr, int data){
if (request == 31) {
request = -1;
}
printf("newptrace:%d\n\n",request);
return oldptrace(request,pid,addr,data);
}
int (*orig_sysctl) (int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
int replaced_sysctl (int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen)
{
printf("sysctl");
return 0;
};
%ctor {
@autoreleasepool
{
printf("Tweak to bypass anti-debugging with ptrace and sysctl Start!\n\n");
MSHookFunction ((void *)MSFindSymbol(NULL,"_sysctl"), (void *)replaced_sysctl, (void **)&orig_sysctl);
MSHookFunction ((void *)MSFindSymbol(NULL,"_ptrace"), (void *)newptrace, (void **)&oldptrace);
}
}
I will try to write up on how to prevent the bypass method hopefully next week if i have some time.
Reference
https://blog.cydia.so/iosdev/2016-01-07/154.html
http://www.iosre.com/t/7-2-0-ios/770/4
http://www.blogfshare.com/ali-ios-game.html
http://www.isoft365.com/rainyx.com/?p=358
Comments
comments powered by Disqus