Sunday, November 26, 2017

Exposing Your "Privates!"

The following tweet popped up in my feed recently and for some reason it piqued my interest. Hey don't judge me :)

Tweet Behind This Post
The article basically provides a guide to sexting securely. If you are so inclined then you should check it out. The article suggests several apps for this type of activity including Privates! which is the focus of this post. Up until this article I had not heard of this app and so I decided to check it out. Note I didn't spend a lot of time of on it. I had some spare time and decided to give it a quick look. I really should be working on finishing up the AMFI series, but I digress. Let's get on with it then....

My environment was as follows:
- Jailbroken iPhone 5S running iOS 9.3.3
- IDA Pro
- BurpSuite
- Frida

Jailbreak Detection
I installed the app and launched it on my jailbroken device at which point I was presented with the following screen:

Jailbreak Detection
I guess that's that done, right? Far from it. I first tried bypassing the detection using the usual suspects like tsProtector 8+ and xCon, both of which failed. I don't usually use these tweaks by the way I just decided to give them a quick run. The next step then was to obtain the binary, and as discussed in the "BLIND" Reversing - A Look At The Blind iOS  post I use dumpdecrypted for this:
Obtaining The Binary via Dumpdecrypted
With binary in hand I fired up IDA Pro to see what was up. The first thing I searched for was occurrences of the strings shown in the jailbreak detection notification. When that came up short I looked for references to common jailbreak artifacts like "Cydia", "/usr/bin/ssh","/usr/bin/sshd" etc. This led to the -[BMDevice files] method:

Jailbreak artefacts
And this method was referenced by the -[BMDevice isValid]  method as shown:

isValid Snippet
The method also checks for things like whether or not the call to fork was successful - this call should fail on a non-jailbroken device. So essentially this detection is your typical run of the mill routine. I only went into this level of detail to explain the approach and give you some tips on what to look for.

Jailbreak Bypass
Bypassing the check is trivial. The function returns a boolean value - bool __cdecl -[BMDevice isValid](BMDevice *self, SEL) - so whatever it returns we just need to flip it. For this we turn to Frida. The next step is to determine the app identifier and for that you issue frida-ps -Uai

Process List via Frida
We then hook the -[BMDevice isValid] method and check it's return value:

Determining Return Value
Where the private.js script is defined as:

   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);  

The bypass then is simply to flip the return value from 0 to 1:

   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")  
       console.log("\t[-] New Return Value: " + newretval)  

And with that the jailbreak detection is bypassed.

With the jailbreak detection bypassed the next step was to examine the traffic. The app presents the following login screen:

And upon successful login, sends requests similar to the following:

Sample Requests
Now this is where things get interesting. Let's take a look at the request to the retrieve messages endpoint - /messages:

Basic Authorization
You are indeed seeing correctly, Privates! is using Basic Authorization. For those that may not be aware this is just a base64 encoded value usually consisting of a username:password pair. In the case of Privates! the value is the user's phonenumber:password. Generally this approach is not recommended.

This brings up an interesting observation, apart from redirecting you to the login screen, the logout functionality shown below really doesn't do much, does it?

Confirmation Bypass
Another interesting thing was that if the app didn't recognize the device you were logging in from you would be sent a confirmation a code. Fair enough. Now let's say I somehow captured someone's credentials and attempted to log in from my own device. The victim would receive an SMS message with the code and since I as the attacker don't have access to their device, the victim would simply ignore it and carry on, because after all whoever is trying to access their account doesn't have the 6 digit pin.

Confirm Flow
An incorrect confirmation attempt results in a 400 Bad Request response from the server:
Server Response Incorrect Code
Can you see where this is going yet? All the attacker has to do is forge a successful response from the server and they have bypassed the confirmation check. Figuring out a successful response is easy. Simply copy the response from a successful request to the /login endpoint.

Forged Success

Connected Device Bypass
Another feature of Privates! is that it doesn't allow you to view messages if the device is connected(read connected via usb). If the device is connected, trying to read a message results in the following message:

Device Connected Error
Incidentally, take note of the Viewing Period as we will get back to it. Ok, so to track this down I again searched for the displayed message and found it in the -[BMMessageConnectionViewController updateWithUSBMessage] method.

updateWithUSBMessage Responsible For Displaying Message
I then searched for occurrences of updateWithUSBMessage which led to the [BMMessageConnectionViewController handleConnectionChange] method:

handleConnectionChange Method
This method then called the isDeviceDiconnected(yes without the s, I guess as an anti-debugging feature right....) method at offset 0x00000001000C3E40. As it turns out this method returns a boolean value. If you are wondering how it determines if the device is connected it simply checks the battery state(using UIDevice) after all if the device is connected the battery will be charging right:

Checking Battery State
Bypassing this check is therefore similar to the jailbreak detection bypass in that we determine the original return value and then flip it. We end up with the following:

 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")  
       console.log("\t[-] DeviceConnected New Return Value: " + newretval)  

And with that the check is bypassed and we can carry on. One thing to note here is that the isDeviceDiconnected method is a class method(+ class method, - instance method).

Viewing Timer Bypass
So I hinted at this earlier. The sender of the message has the option of specifying the Viewing Period of the message:
Setting Viewing Period
From the above settings you only get a maximum of 30s. In fact there are three settings you can choose from mild, wild and insane with Viewing Periods being 30, 15 and 10 seconds respectively. But let's suppose I want to errrrrmmmmm how do I say this....."enjoy the image" a bit longer. Well the astute reader would have noticed that communication between the app and the server have the following Content-Type: application/json. Do you see where this going? No way what I am about to do should work right? Well, when you retrieve a message one of the parameters included in the response is duration - highlighted in red:

Setting Viewing Duration
To bypass the check just change this to a value of your choosing and enjoy those images...Here I changed it to 60 seconds:
Extended Viewing
Security Options Bypass
Even more interesting is that the sender can specify the actions the recipient has to take before being able to view the message. These actions are defined as Security Options - security_options": ["touch", "motion", "camera"]. Camera means a picture is taken, motion means you have to hold the device a particular way and touch is exactly that - you have to tap the screen. Again you can edit this list and remove the actions you don't want to perform and the sender would be none the wiser.

Unhandled Exceptions
In some instances, the app returned some rather, dare I say "helpful" error messages:

Verbose Errors
This is kind of information is often useful to attackers as it can be used to plan further attacks. At the very least, it shows that some "conditions" were not being properly handled. Let me hasten to point out that I didn't hack the server. The above error message was generated when I attempted to retrieve a message that had been recalled by the sender.

In the end you use these apps at your own risk. The app definitely has areas that it needs to improve on. I didn't even bother getting into the crypto because this was just some weekend fun(the real reason is crypto is hard). I am sure there are other areas to look at - as I said earlier this was by no means an in-depth review - and if you are so inclined this post should have provided enough information for you to go further. At the very least it should have provided some food for thought.

Until next time....Happy Hacking!!!

Disclaimer: This blog is intended for educational purposes only. Any actions and or activities related to the material contained within this Website is solely your responsibility.The misuse of the information in this website can result in criminal charges brought against the persons in question. This author will not be held responsible in the event any criminal charges be brought against any individuals misusing the information in this website to break the law.

No comments:

Post a Comment