mardi 14 août 2012

Unlocking features on an iPhone application

Hi kids! Do you like dating?

Well I do, and last week I installed a new application on my iPhone 3g running iOS 4.2.1 (jailbroken).

That app (I will call it ZeApp) is a client - server app, based on a well known business model:
- users can create a profile
- they can publish advertisements (selling something, looking for something to buy, to rent, or someone to date...)
- they can view other users' profiles and ads
... for FREE

... BUT they need to pay to be able to communicate with eachother.

So there are some packages you can buy (classic, premium, 1 week, 1 year...) and depending on the package you bought, the features you can access change.

A lot of applications for selling things, auctioning, flat renting or selling, room sharing, couch surfing, dating and so on are based on this business model, and a lot of big companies make a lot of money with that.

Obviously, an application based on this business model will pay attention on the access control to the features, because if it can be circumvented, the company doesn't make money.

Surprisingly, it is not always the case...



Setting up the lab

For iOS application analysis, I use:
- a jailbroken device with ssh installed
- a wireless access point
- my laptop (ubuntu) with some tools (in this case a ssh client and burp suite)



Analyzing the app's environment

The first thing I do when I want to play with an app, is to inspect its environment: configuration files, databases, filesystem structure ...

Connect to the iDevice and look for the application directory:

jo@dp:~$ ssh root@192.168.55.11
root@192.168.55.11's password:


iPhone-de:~ root# find /var/mobile/Applications/ -name "*ZeApp*"

/var/mobile/Applications/1EF11D0A-69D4-4389-A13C-9FF73BC51FD1/Documents/ZeApp.sqlite
/var/mobile/Applications/1EF11D0A-69D4-4389-A13C-9FF73BC51FD1/Library/Preferences/com.ZeApp.iphone.plist
[...]

Then cd to the app's directory, which should be an ugly long hexa sequence.
At that time I usually look for plist files, which are configuration files. Once found, I use plutil to whether view the files or convert them to text for scp'ing them to my laptop.



iPhone-de:/var/mobile/Applications/1EF11D0A-69D4-4389-A13C-9FF73BC51FD1 root# ls
Documents/  Library/  ZeApp.app/  iTunesArtwork  iTunesMetadata.plist  tmp/
iPhone-de:/var/mobile/Applications/1EF11D0A-69D4-4389-A13C-9FF73BC51FD1 root# find . -name "*.plist"
./Documents/userdata.plist
./Library/Preferences/.GlobalPreferences.plist
./Library/Preferences/com.apple.PeoplePicker.plist
./Library/Preferences/com.ZeApp.iphone.plist
./ZeApp.app/Info.plist
[...]


One plist file is particularly interesting: com.ZeApp.iphone.plist, let's take a look!


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>APNSLastDeviceToken</key>
<string>(...)cb9f22e369c50940be4</string>
<key>AlreadyConnectedOnce</key>
<true/>
<key>AuthIsOn</key>
<true/>
<key>AuthenticationFirstLogin</key>
<date>2012-07-10T08:46:36.285761Z</date>
<key>AuthenticationLogin</key>
<string>myLogin</string>
<key>AuthenticationLoginCount</key>
<integer>1</integer>
<key>AuthenticationPassword</key>
<string>myPassword</string>
<key>AuthenticationRemember</key>
<true/>
[...]


My credentials are stored in cleartext in this plist file! First fail...

The are some other plist files that contain interesting data such as a list of action-permission pairs for client side access control. But unfortunately, those settings are overwritten everytime the app restarts.

OK, now that we know what settings are stored in plist files, let's see if there are some databases around...


iPhone-de:/var/mobile/Applications/1EF11D0A-69D4-4389-A13C-9FF73BC51FD1 root# find . -name "*.sqlite"
./Documents/ZeApp.sqlite

Let's copy it to the laptop and open it with sqlitebrowser...

jo@dp:~$ scp root@192.168.55.11:/var/mobile/Applications/1EF11D0A-69D4-4389-A13C-9FF73BC51FD1/Documents/ZeApp.sqlite ./myAnalysisDir

jo@dp:~$ sqlitebrowser myAnalysisDir/ZeApp.sqlite

In fact I'm not gonna show you the DB.
But I can tell you what's in it: it contains much more information than you can have by just using the app in a regular way (unless you subscribe). And no data in the database is encrypted...

But at this point nothing very surprising, using cryptography seems to be a mess for a lot of developers, so they often just don't.

Ok that's it for the application's environment. We located the configuration files, the databases, and we now know what data the application manipulates and stores, and where it gets it's settings from.

Now let's see how it communicates with the server.






Network traffic analysis


To analyse the network traffic you have several aproaches, and my favourite is the active one: you MITM so that you can both monitor and tamper with the transmitted data.

To do  that, I use ssh port forwarding to redirect the traffic to my laptop's port Burp is listening on. (thanks to @AndrivetSeb for the trick!)

Let's do it:

jo@dp:~$ burp &
jo@dp:~$ ssh root@192.168.55.11 -R 8080:localhost:8080
root@192.168.55.11's password:

Then you need to configure your phone to use a proxy on your wifi AP:
- go to Settings > Wifi > YourNetworkName > HTTP Proxy
- set your local proxy to the port you specified (so Server:127.0.0.1, Port: 8080)

And activate interception on burp. Done. You are in the middle.


When the app is launched, it sends my credentials to the server to log me in:



We can see here that the credentials are sent over HTTP in cleartext. Second fail....
The server's response sets a bunch of cookies and contains a session id which will be used to identify me in the following requests. If someone intercepts the request or the response, he can use my session and date the girls I'm supposed to date...

The next stages are funny:

The application asks the server for my account state.

The response contains the type of offer I subscribed, and the date my subscription expires, my account number, my email address, my login and my (obfuscated) password.

If I know the identifiers of premium subscriptions, I can trick the app so that it thinks I'm a premium member.
If someone intercepts this he has access to useful information such as my password length or my email address (which is a threat for my anonymity, and can be used for spam or phishing).




After that, the app asks the server for the acces control rules. The server returns a list of action-permission pairs. This list looks like this:

{"resultset":{"result":{"method":"rights","response":{"rights":{"id":{"LIST_EVENTS":{"type_pass":null},"MAIL_SEND":{"type_pass":["PASS_PREMIUM","PASS_PREMIUM"]}}}}}}}


This clearly means that the action "LIST_EVENTS" is available for all users, and the action "MAIL_SEND" requires a premium subscription.

And now you start to see what can be tried to trick the application: change the server response to allow any action to any subscription type!

To automate that, burp has a very useful feature. In the proxy tab, we can define find and replace rules.  We only need to replace ["PASS_PREMIUM","PASS_PREMIUM"] by 'null'.


And it worked! In the application, all the buttons are active now. I'm able to send a message to the girl of my dreams:



The server should deny the action, if it is designed correctly. But it is not!

I tried the other 'paid' features and it worked too. I fully unlocked the application and am able to enjoy all features for free.

It means that the server does not perform access control for the requests coming from the mobile application. The access control is only done by the mobile application according to the access control rules received from the server!

This is very bad. It is a very common mistake in web applications and webservices.

And thanks to that mistake, I no longer spend money to meet girls. However I still have to pay for drinks and dinner, but it's another problem...



How could it be better?


Obviously, the problem here is that the server trusts the mobile application too much. And the trick presented here is harmless, but I bet it is possible to attack the server by sending unexpected data (could lead to SQL injections for instance).

As recomanded by OWASP, the server shall never trust the client application. It should perform its own access control, and validate data received from the user. And the same stands for the client application regarding the server.


A few thoughts about this


I was very surprised of this weak access control mistake. The web version of the service performs the access control correctly on the server side. I expected the mobile application to use the same server side logic.

Another funny aspect of that app is that the executable code is obfuscated in a way that IDA hangs when I try to open it for further analysis. I don't really understand the point: why hardening the binary, when the application security is so weak? All config files are cleartext, the network data is cleartext, and the access control is  a big fail.

I certainly will analyse the obfuscation technique, and I may post about it later.


Finally, something bothers me. When you look at the method parameters for sending a mail, you can see that the destination is a user id. The user id is just a number. So we can imagine how easy it can be to spam all the users once a session (or credentials) is owned. This can be a quite interesting vector for spamming, phishing and social engineering.

dimanche 12 août 2012

Beatbox for free - Abusing a cheap authorization on Android

Hi kids, do you like human beatboxing?


Well I do, and a few months ago, I downloaded an application for my Nexus S running Android 2.3.4. I will call it Blabla.
This application was awesome, and allowed me to record and mix live loops from the microphone, exactly what I was looking for...

But I downloaded the free version of the app, and some basic features were missing, such as saving and exporting the tracks. Furthermore, a messy time limit for recording was present.

The full version of the application does not cost a lot, but just for fun I decided to take a look on the free app. Because sometimes the free app already contains the full app logic, and checks if it should authorize the use of 'paid' features...and it was the case here.

Furthermore, on the market, there is no full app. There is only an app called "Blabla unlock key". This means that the free app probably handles all the features.

In the following I will describe the main steps I went through to unlock the application.

NOTE: I'm not inviting people to hack the app. It is a good application, and the developers deserve to earn money for it. This is why I won't mention the name of the app, I won't show screenshots or anything that would lead to the identification of the application

Soft-rooting the phone


To feel comfortable and to be able to do whatever I want, I first soft root the phone.

To do that:
- enable debugging, to activate adb
- push a compiled version of zergRush on the filesystem and run it
- enjoy the root shell

Exploring the application environment


It is a classical part of the application discovery.After locating the application on file system, I take a look at the manifest to check the permissions:

Extract from AndroidManifest.xml:

    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />


So the free app is obviously able to write data on the SD card, which is exactly what is needed to save the tracks... It means that there is a chance that the free app handles the full app features... Let's digg a bit more...


Then I took a look at the configuration file, which is a simple plain text XML file called BlablaActivity.xml. I was looking for a field that tells if I paid or not. But there was nothing useful in this file...

The app doesn't use any database, so there is nothing more to see in the application environment.

I had to read the code, just to see how the application checks if I bought the unlock key.


Reversing the app


Reversing Android applications can be very easy.

To do that:
- extract the application apk to your computer using adb
- use dex2jar to get a jar archive of the application
- use jd-gui to access to the java code of the jar



Sometimes, dex2jar fails to create the exact java code. If it occurs, one can access the dex code using dedexer, and read the logic. But in this case, I didn't need to fully understand the exact code. I was just looking for the technique used to check if the unlocking key app is installed.

If we look at the class names, we can see that some are obfuscated (classes a, b, c and d). This attracts attention...




Some methods are called nativeSomething, so we can assume that some parts of the logic are embedded in a native library. Indeed, the methods for saving and loading tracks are native. There is also a native method that sets preferences.

It is used in the a() method of the class d. And we can see that this method checks if the unlockingapp is installed by using the PackageManager.getApplicationInfo() method. If the application is present, a specific key-value pair is set in the "native" preferences.



Unlocking the free app


In fact, the class d is a thread that performs that test until the unlocking key is found. It is launched at application startup and stops running when the key is found or when the application closes.

PackageManager.getApplicationInfo() returns true if an application with a specific name is installed. So to pass that test, the simplest way is to create an empty Android application and give it the right name. Then, when it is installed, the Blabla application will be unlocked.

It seems too easy to be true...
In fact the native library is essentially meant to handle the sound processing tasks. The developers decided to involve it in the unlocking key check, but the main checking logic is not native.

By the way, handling the whole key check in the native library would only make it slightly longer for an attacker to reverse it...

The developer released a few other applications that use the same process, a free app and a unlocking key you must buy to unlock the full features.



How could it be better?



I think the easiest way to perform the key check without implementing heavy cryptography would be to use the application signature features provided by Android.

Without changing anything to the application logic, I would just change the permissions. The Blabla Unlocking Key application could ask for the WRITE_EXTERNAL_STORAGE permission, instead of the Blabla application.

If the applications are defined to share their userID, they also share their permissions.
That way, the Blabla application could check if it has the WRITE_EXTERNAL_STORAGE permission and if so, it means that the key application is installed AND signed with the same developer key (because they share their UID).

Of course, it wouldn't stop from fully cracking or patching the application, but on Android, it is a general statement. The problem which I discussed here is that the phone doesn't need to be rooted for circumventing the key check. Anyone can install his own fake empty key application, just by enabling debugging and installing third party apps.

There might be some better ways to do that, but as I'm writing this post, I think the one I give would solve the problem.

Feel free to discuss everything I wrote by leaving a comment!