Exposing Your "Privates!"

  1. Find Application Binary Location - Use cda
  2. dumpdecrypted
  3. IDA analysis
    • Jailbreak Bypass
    • Connected Device Bypass
  4. Common Flaw Vulnerabilities
    • Base64 Authorization
    • Confirmation Bypass
    • ViewTime Bypass
    • Security Option Bypass

1. dumpdecrypted

Ref: https://github.com/stefanesser/dumpdecrypted/

Upload

scp -P 3333 dumpdecrypted.dylib root@localhost:/var/root/

Decrypt

iPhone5c:~ root# DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /var/mobile/Containers/Bundle/Application/764E86DA-730A-4452-9C67-626B0D6FD3B5/Privates.app/Privates

Download

scp -P 3333 root@localhost:/var/root/Privates.decrypted .
➜  ✗ otool -l Privates.decrypted | grep crypt
Privates.decrypted:
     cryptoff 16384
    cryptsize 2195456
      cryptid 0

Class dump (optional)

➜  Privates class-dump --arch armv7 Privates.decrypted -H -o armv7-headers
➜  Privates class-dump -S -s -H Privates.decrypted -o ./headers

NIN: 建议用jTool和class-dump一起用.

JCOLOR=1 jtool -v -d objc Privates.decrypted > privates-class.txt

2. Jailbreak Bypass

IDA Analysis

打开Privates!, 发现有 JB 检测. 拖Privates.decrypted 进 IDA.

搜索cydia, Search - Text

得到 -[BMDevice files].

查找 BMDevice files], 我们会来到 -[BMDevice isValid].

View - Open Subviews - Generate Pseudocodes.

笔者IDA生成的psudo code, 并非如作者所说的 - bool __cdecl -[BMDevice isValid](BMDevice *self, SEL), 而是

char __cdecl -[BMDevice isValid](BMDevice *self, SEL a2)

利用 frida, 测试一下该方法.

if(ObjC.available){
   var auth = ObjC.classes.BMDevice["- isValid"];
     Interceptor.attach(auth.implementation, {
       onLeave: function onLeave(retval) {
       console.log("\t[-] Type of return value: " + typeof retval);
       console.log("\t[-] Original Return Value: " + retval);
      }
   });
 }
➜  Privates frida -U -l private.js -f com.rxn.Boomerang
     ____
    / _  |   Frida 10.6.10 - A world-class dynamic instrumentation framework
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at http://www.frida.re/docs/home/
Spawned `com.rxn.Boomerang`. Use %resume to let the main thread start executing!
[iPhone::com.rxn.Boomerang]-> %resume
[iPhone::com.rxn.Boomerang]-> 	[-] Type of return value: object
	[-] Original Return Value: 0x0

可以知道返回的类型是 object, 0x0.

只要替换最终的 value, 就可 bypass JB Dectection.

if(ObjC.available){
   var auth = ObjC.classes.BMDevice["- isValid"];
     Interceptor.attach(auth.implementation, {
       onLeave: function onLeave(retval) {
       console.log("\t[-] Type of return value: " + typeof retval);
       console.log("\t[-] Original Return Value: " + retval);
       newretval = ptr("0x1")
       retval.replace(newretval)
       console.log("\t[-] New Return Value: " + newretval)
      }
   });
}

注意, 这里有个问题, 不能像以下方式调用, 因为此时 isValid已经运行完了.

➜  Privates frida -U Privates -l private.js

利用以下命令获取App Identifier.

frida -Uai

利用-f调起 App.

➜  Privates frida -U -l private-jb-bypass.js -f com.rxn.Boomerang
     ____
    / _  |   Frida 10.6.10 - A world-class dynamic instrumentation framework
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at http://www.frida.re/docs/home/
Spawned `com.rxn.Boomerang`. Use %resume to let the main thread start executing!
[iPhone::com.rxn.Boomerang]-> %resume
[iPhone::com.rxn.Boomerang]-> 	[-] Type of return value: object
	[-] Original Return Value: 0x0
	[-] New Return Value: 0x1

cycript

NIN: 尝试使用 cycript bypass, 但是失败了.

Class-Dump

// Dumping class 70 (BMStartNavigationController)
@interface BMStartNavigationController : UIKit::_OBJC_METACLASS_$_UINavigationController
// No properties..
// Adjusting num elems: 2
// 2 instance variables
/* 0 */  char _signupWorkflow; // c
/* 1 */  BMStartModalTransition _modalTransition; // @"BMStartModalTransition"
// 21 instance methods
/* 0 - 0x34901 */ + initWithCoder:;  // Protocol @12@0:4@8
/* 1 - 0x34947 */ + modalTransition;  // Protocol @8@0:4
/* 2 - 0x349a1 */ + startPresentationViewController;  // Protocol @8@0:4
/* 3 - 0x34a23 */ + flipToViewController:options:;  // Protocol v16@0:4@8I12
/* 4 - 0x34a93 */ + showStartScreen;  // Protocol v8@0:4
/* 5 - 0x34ab9 */ + showSignupScreen;  // Protocol v8@0:4
/* 6 - 0x34ddd */ + showLoginScreen;  // Protocol v8@0:4
/* 7 - 0x35101 */ + showTourScreen;  // Protocol v8@0:4
/* 8 - 0x35411 */ + showForgotPasswordScreen;  // Protocol v8@0:4
/* 9 - 0x35769 */ + showResetPasswordScreenWithUsername:;  // Protocol v12@0:4@8
/* 10 - 0x35ae3 */ + showWelcomeScreen;  // Protocol v8@0:4
/* 11 - 0x35b29 */ + showTermsOfUse;  // Protocol v8@0:4
/* 12 - 0x35dc1 */ + showPrivacyPolicy;  // Protocol v8@0:4
/* 13 - 0x36059 */ + showConfirmDeviceScreen;  // Protocol v8@0:4
/* 14 - 0x36283 */ + showFindFriendsIntroductionScreenAnimated:;  // Protocol v12@0:4c8
/* 15 - 0x3635f */ + showFindFriendsScreenAnimated:;  // Protocol v12@0:4c8
/* 16 - 0x3643b */ + navigationController:animationControllerForOperation:fromViewController:toViewController:;  // Protocol @24@0:4@8i12@16@20
/* 17 - 0x36731 */ + .cxx_destruct;  // Protocol v8@0:4
/* 18 - 0x366eb */ + (null);  // Protocol c8@0:4
/* 19 - 0x366fb */ + setSignupWorkflow:;  // Protocol v12@0:4c8
/* 20 - 0x3670b */ + setModalTransition:;  // Protocol v12@0:4@8
@end
cy# ?expand

// 记得加 toString()
cy# [[UIApp keyWindow] recursiveDescription].toString()
`<UIWindow: 0x124e97430; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x124ea3c60>; layer = <UIWindowLayer: 0x124ea5bc0>>
   | <UIView: 0x124ec1870; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x124ec15c0>>
   |    | <BMBackgroundView: 0x124ec1ef0; frame = (0 0; 375 667); autoresize = RM+BM; layer = <CALayer: 0x124ec16b0>>
   |    |    | <CAGradientLayer: 0x124e94dd0> (layer)
   |    | <UIImageView: 0x124ec2c80; frame = (20 32; 335 615); autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x124ec1620>>
   |    | <UIView: 0x124dbc540; frame = (40 203; 295 261); autoresize = RM+BM; layer = <CALayer: 0x124db30f0>>
   |    |    | <UIImageView: 0x124dbc6b0; frame = (90.5 0; 114 114); autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x124db6510>>
   |    |    | <UILabel: 0x124ec0950; frame = (0 134; 295 26); text = 'Jailbroken Device Detecte...'; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x124ec0b50>>
   |    |    | <UILabel: 0x124ebe070; frame = (0 168; 295 93); text = 'This appears to be a modi...'; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x124ebe5f0>>`

cy# [#0x124ec1870 nextResponder]
#"<BMStubViewController: 0x124dbb1b0>"
// 获取当前Controller

cy# function currentVC() {
    var app = [UIApplication sharedApplication]  
    var keyWindow = app.keyWindow  
    var rootController = keyWindow.rootViewController  
    var visibleController = rootController.visibleViewController  
    if (!visibleController){
       return rootController
    }
    return visibleController.childViewControllers[0]
}
cy# var vc = currentVC()

// 也可以将上面的 function 保存到 myfunc.cy
// cycript -p WeChat myfunc.cy ; cycript -p WeChat
// 获取当前Controller
cy# UIApp.keyWindow.rootViewController
#"<BMStartNavigationController: 0x15f078400>"
cy# UIApp.keyWindow.rootViewController = [[BMStartNavigationController alloc] init]
#"<BMStartNavigationController: 0x13e02e000>"
cy# [#0x13e02e000 showLoginScreen]

虽然能成功 bypass 掉 JB Screen, 但是 Login 界面还是少了一块. 如果输入用户名与密码的时候, 无法登陆, 提示缺少 key.

Connected Device Bypass

Privates! 不允许当手机用 USB 连接电脑时使用.

搜索iPad, Search - Text, 得到 [BMMessageConnectionViewController updateWithUSBMessage].

搜索updateWithUSBMessage, Search - Text, 得到 [BMMessageConnectionViewController handleConnectionChange] .

双击打开[BMMessageConnectionViewController handleConnectionChange], View - Open Subviews - Generate Pseudocodes.

isDeviceDiconnected这个方法, 引起了我们的注意. 类似jb bypass

var device = ObjC.classes.BMMessageConnectionViewController["isDeviceDiconnected"];  
Interceptor.attach(device.implementation, {  
	onLeave: function onLeave(retval) {  
		console.log("\t[-] DeviceConnected Type of return value: " + typeof retval);  
		console.log("\t[-] DeviceConnected Original Return Value: " + retval);  
		newretval = ptr("0x1")  
		retval.replace(newretval)  
		console.log("\t[-] DeviceConnected New Return Value: " + newretval)  
	}  
});

NIN: 这里有一个需要注意的. 上面ObjC.classes.BMDevice["- isValid"];ObjC.classes.BMMessageConnectionViewController["isDeviceDiconnected"]调用方法时的不同. 一个有-, 另一个无. (+ class method, - instance method).


jTool 并没有打印出方法 - isDeviceDiconnected. class-dump 有.

@interface BMDevice : NSObject
{
}

@property(readonly, nonatomic) NSArray *files;
@property(readonly, nonatomic, getter=isValid) BOOL valid;
@property(readonly, nonatomic) NSArray *links;

@end
@interface BMMessageConnectionViewController : UIViewController
{
    UILabel *_titleLabel;
    UILabel *_subtitleLabel;
    CDUnknownBlockType _completion;
}

+ (id)controllerWithCompletion:(CDUnknownBlockType)arg1;
+ (BOOL)hasExternalConnections;
+ (BOOL)hasSingleDefaultScreen;
+ (BOOL)isDeviceDiconnected;
- (void).cxx_destruct;
- (void)batteryStateDidChange:(id)arg1;

Common Flaw Vulnerabilities

Basic Authorization

发现Authentication使用的是 basic authentication. 因此, 也没有任何 session timeout.

Confirmation Bypass

又是一例Business Logic Flaw 的问题. 当发送的OTP 不正确, server 返回400, 但是只要替换 response, 就可以 bypass 了.

ViewTime Bypass

同样, 只要替换 response 的 time, 就可以令到 client 按此 time, 限制 message 的可读时间.

Security Option Bypass

同样, 只要替换 response 的 security_option, 就可以令到 client 做某动作才能看 message 的限制解除.

Bonus


Bonus - Restart SpringBoard

iPhone5c:~ root# killall -HUP SpringBoard

Bonus - Generate Pseudo code

View - Open Subviews - Generate Pseudocodes

Short Cut: F5

Bonus - ssh_exchange_identification: Connection closed by remote host iphone

检查 ssh 错误的原因.

➜  ~ ssh -vvv -p 3333 root@localhost

解决方法: Reinstall openssh

Ref: submanifold

加号方法 & 减号方法

前置加号(+)的方法为类方法,这类方法是可以直接用类名来调用的,它的作用主要是创建一个实例。有人把它称为创建实例的工厂方法。

前置减号(-)的方法为实例方法,必须使用类的实例才可以调用的。

Ref: iOS中的加号和减号方法 - CSDN博客

Ref

Show Comments