I Hacked An Android App To Get A Free Haircut | Hacker Noon

June 23rd 2020

Author profile picture

@pedro.costaPedro Costa

Passionate Software Engineer by day, Greedy crypto enthusiast by night

Android apps are mainly composed of a bunch of binaries bundled together, built from compiled Kotlin or Java code. The original source code can be easily reconstructed by several light-weight tools, found on the top of a google search page.

If you’re a happy Android developer and you’re not careful enough to apply the best security practices on your projects, you won’t stay happy for long. All the precious secrets you think are safely hidden in your code, can and will be used against you in the wild by someone with the right motivations. That’s precisely what happened to the Android app of this chain of barber shops.

The developers’ disregard of every kind of security best practices resulted in something that, in just a matter of a couple of hours, I was able to decompile, reverse-engineer and identify several vulnerabilities that anyone can exploit to achieve what would be every hacker’s life-pursuit dream: free haircuts for life!

Here, I’ll walk you through the whole hacking process, show you how important it is to follow the security best practices and how simple decisions can greatly increase the difficulty for reverse-engineering and exploitation of your Android app.

The app of this chain of barber shops has a very simple purpose: Users can book haircuts on the available shops and per each 10 haircuts, the user gets

one for free

.

So far so good, they all look like pretty good tasks for an app to do. However, after installing the app and looking at my profile page, there was a very explicit and somehow intriguing message: the freebies could only be generated via app – not by any other platform – and they could also be used whenever the user wants: just need to present the app when it’s paying time.

This message definitely got my attention.

So I downloaded and decompiled the apk to satisfy my curiosity.
Maybe if I looked at the code, I could, hypothetically, use the app in some creative ways.

And I was right: what I found was a complete mess.

After decompiling the app and reverse-engineering the code, I identified several vulnerabilities. Later on, I’ll go one by one and discuss what the original developer could have done to prevent it:

  1. No code obfuscation, making it really easy to reverse-engineer
  2. No certificate or any kind of app integrity checks, making it impossible for the backend to spot tampered client apps
  3. Important business logic implemented on client app without further confirmation checks on backend side
  4. Hardcoded secrets on the code making backend’s private api exposed and easily exploitable

The APK file

Kotlin and Java sources are first compiled to 

.class

 files, which consist of

bytecode

instructions. Traditionally, these bytecode instructions would be executed directly on the JVM. However, Android apps are executed on the 

Android Runtime

, which uses incompatible instructions, and therefore an additional

Dexing

step is required, where 

.class

 files are converted into a single 

.dex

 file.

Here’s the compilation process:

Decompile the APK

There are several tools online that decompile

apks

and convert the

.dex

file into readable Kotlin or Java code. The resulting decompiled code is the entry point for understanding the functionality of the targeted app, but will likely not be 100% usable code. In other words, you can read the source, but you can’t really modify, recompile and build the original app with it.

The apk

decompilation

steps:

However, as I was really motivated on snooping into the code, I used

apktool

to decompile the apk along with its

.dex

file contents anyway (steps 1 and 2 above)

$ apktool d target_app.apk
I as stated before, the

.dex

file is the format that the platform actually understands. However, it’s not easy to read or modify binary code, so there are some other tools out there to convert it to and from a human readable representation. The most common human readable format is an assembly language known as

Smali

. This is the format

apktool

outputs and stores on a

/smali

folder.

This is what a

smali

file looks like:

Smali

files are the ones we’ll be editing later, but not clearly the ones we’d want to be looking at for reverse engineering the whole application. Not unless we’re forced to.

To look at more friendly code that could help me on the reverse engineering process, I converted the these smali files into standard

.class

files using

dex2jar

(step 3 above):

$ dex2jar decompiled_app/build/apk/classes.dex

and booom! I have now access to the full app source code in a very familiar format, as the original developer wrote it.

Now, let us have a look at what I found

Vulnerability 1: No code obfuscation!

Obfuscation and minification are strategies used to reduce unused code and shorten the names of your app’s classes and members – usually by replacing them by something meaningless – not only making it very hard to read but also further reducing the size of your app.

If you don’t apply any kind of code obfuscation, you’re pretty much giving access to your private repo to the hacker.

In this particular case, It was straightforward to understand and follow the code, identify third party technologies, but also the secrets used to authenticate them.

This could be all easily avoided by using some kind of obfuscation tool, like

ProGuard

, that would at least make the hackers life much harder, and forcing them to invest the much more significant effort to reverse engineer the code. 

This is what the code looks like before and after applying obfuscation [2]:

Vulnerability 2: Hardcoded secrets

The first class I looked at, had literally an hardcoded variable called

CLIENT_SECRET

, that would later on be used to authenticate each Http call to the backend.

And suddenly, I have now access to the entire app’s private api to mess around and look for new attacking vectors.

If you really need to store secrets on your client applications to provide some kind of authentication, this can be avoided in many ways without compromising these secrets by hardcoding them on your code.
There are several well-known methods like using symmetric key derivation strategies or password-based key derivation functions.

Vulnerability 3: Important business logic on client app without confirmation checks on backend

This is where things get interesting… Continuing my quest to get the best haircut – the one I don’t have to pay for – I still had to find some vulnerability that would get the app to generate me a free haircut booking.

After spending roughly one hour looking at the code, this is what I’ve learned:

  • The backend stores all the
    Shops

    and

    User

    info

  • The backend stores the
    Bookings

    for each user

  • The client app retrieves all the
    Bookings

    for each user via

    REST

    calls

  • Each
    REST

    call to backend is identified by a hardcoded

    client_secret

    and user-specific

    basic_auth

    creds

And now, the cherry on top of the cake:

  • The client app determines – not the backend – when is time to grant a
    freebie

    , by counting how many successful bookings a

    User

    has made

  • The
    freebie

    was just a standard

    booking

    REST call with an additional

    flag

    stating the booking is for a

    free haircut
At this point, you can guess what was the backend response when I promptly issued a

POST

to the booking api with that

flag

set to true:

After looking at so many mistakes here, I confess I wasn’t surprised.

What we can learn from this is that by letting your

client app

to call such important decisions like: when it’s time to grant a free booking, you’re literally placing your precious business rules on the most vulnerable end of the whole user-journey.

Even worse, is to not validate the REST calls on the backend when you still have the chance. It would be obviously mandatory to validate if a user has made and payed for enough bookings to get a free one, before accepting and storing on the backend anything incoming from the client’s app.

And this leads me to the last but not least vulnerability:

Vulnerability 4: No client app integrity checks

If you’re going to code important business logic decisions on the client app – which is totally wrong by the way – the least you can do is to have some mechanism in place to verify the app’s authenticity.

A lot of the vulnerabilities above could have been mitigated with some kind of client app integrity check, making it possible for the backend server to verify when the api calls are coming from legit applications and discard the ones incoming from compromised apps. This can be easily achieved by signing the requests with the app’s release certificate.

Each Android apk is signed with a release certificate. If the apk is decompiled and recompiled again with code changes, by some process similar to what I describe here, the new recompiled apk must be signed with a different certificate, as the hacker won’t have access to the original one used to sign the legit app that only the original developer would have.

Change the Smali assembly files and Recompile the APK

So, now that we’re happy with our hacking and we know what and where we should place our malicious code, it’s time to edit some assembly files and recompile the whole thing. Remember

smali

?

apktool

outputs one

.smali

file per each

.class

so it would be easy, at least, to navigate and identify where the changes should be made. However, from now on, you’re on your own: if you’re not familiar with some kind of assembly language, this can be a quite painful process.

I’m glad I didn’t have to change too much for my tampered booking requests to work. Just adding couple of

flags

and removing a couple of

:gotos

proved to be enough.

When your done editing, just use the

apktool

again to recompile everything:

$ apktool b -f decompiled_app -o hacked_app.apk

Generate a random key pair to sign the recompiled app like this:

$ keytool -genkey -v -keystore some_ks.keystore -alias some_alias -keyalg RSA -keysize 2048 -validity 1000
$ jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore some_ks.keystore hacked_app.apk some_alias

And you’re good to go!

This is it. This is the rejoice moment. I’ve done what no hacker has done before. I could sit back and install my tampered app, call the barbers shop private api with my tampered requests, and finally, I could book free haircuts!

And it was worth it! (hypothetically)

In Conclusion

This was an attempt to show how easy it is to steal your secrets and how generally vulnerable your code is if you don’t take the necessary precautions to preserve both your intellectual property and your business logic. Several exploiting tools and general knowledge on how to use them properly are widely available online, meaning it’s not just a matter of luck if your app gets hacked, no, It’s just a matter of time.

So you better start investing some time learning the best practices; otherwise, you’re just leaving the door open for someone to really take advantage of your code and potentially cause significant losses to your business. Not just displaying it for didactic purposes like I did here.

Tags

The Noonification banner

Subscribe to get your daily round-up of top tech stories!

read original article here