In the second part, we’ll take a look at the requests we intercepted thanks to Fiddler, and see if Aks.fm implemented some sort of security (tokens, checksums, etc)
Understanding the request headers and parameters
Here is the request we’ll analyze :
POST /authorize HTTP/1.1
Accept: application/json; charset=utf-8
Authorization: HMAC a9f98b69f649e0c96240cc6e36980da96f308cea
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
User-Agent: Dalvik/2.1.0 (Linux; U; Android 6.0.1; GT-N7100 Build/MOB30R)
As we can see , there are lots of interesting headers here. I’ll not make you wait and explain directly what I deducted from my tests :
- X-Client-Type: This header indicates the version number of the Ask.fm application used. Let’s just use the same as the one we captured.
- X-Api-Version: This is the… API version, you guessed it. It is important because the parameters we need to send to the API change with each version and they are NOT retro-compatible ! This must be a nightmare to maintain for the developers.
- X-Access-Token: Before you make any requests, you need to make a GET request to the address https://ask.fm/token, with a few get parameters (the device id, the current timestamp and a third parameter we’ll explain later). Then you use this token in your authorization POST request. The token you get back from this request will be the token that identify you and keeps trace of your “session”.
- Authorization: Aaaaah, this header is the one who gave me a headache. We can see it sends an HMAC, which is just a glorified checksum, used to verify the request. The application basically generates this checksum (HMAC) from the URL and the parameters of the request. Then, when the server receive your request, it will compute the HMAC and compare it to the one you sent. If it’s the same, the request is valid. Otherwise, the server will send you a nasty “Invalid request” error message.
- Other headers are simple and classical HTTP headers
So… the three first headers are simple to reproduce. But this HMAC Authorization header is a barrier : we need to find how this HMAC is generated. And for this, we’ll have to dwelve into the AskFM source code. We’ll look at it later. For now, let’s look at the request parameters.
Every POST request has only one parameter, called “json”, containing an URL-encoded version of all the parameters in JSON. What is funny, is that I discovered you must format this JSON parameter exactly like the application does, or else the request will be considered invalid (I’m really wondering how they parse it). The correct formatting is : the keys must be alphabetically sorted, and there must be no spaces or new lines. Everything must be on a single line. OK, why not…
Also, besides the parameters specific to each request, there are four parameters that will always be present :
- “did”: The Android device ID, in hexadecimal
- “guid”: The same ID (can it be different ? I’m not an Android expert)
- “rt”: I discovered this is a counter that is incremented at each request made. Maybe they use it for rate analytics ? Or for an ugly rate limiting ?
- “ts”: This is just the current timestamp (in seconds)
Decompiling the apk to find the HMAC generation routine
So now we only need one last thing : to know how this HMAC is generated. For this we’ll need to decompile the apk. You can do it with tools like APKTool, but there are websites like https://www.apkdecompilers.com/ that allows you to send an APK and download the decompiled code. I used a software with a GUI but I don’t remember its name.
Anyway, now we have the decompiled “human readable”, somewhat-Java-ish code, we just need to go through the different packages name and find the ones that sounds useful. I did it months ago so I don’t exactly remember how I proceeded and how I ended up finding the code that was interesting. All I know is that the code we’re interested in is the package com.askfm.network.utils and the class is called Signature.
Here is the decompiled Java code : https://gist.github.com/Hexalyse/fe31295ba1ff6685397e3bee955350b0
As we can see, the code uses a private key (the HMAC secret key), which is stored somewhere else in the source code. I won’t tell you where since… I don’t remember. But it’s pretty easy to find.
UPDATE : I’ve been informed by a reader that the developers changed the way the HMAC secret key is generated in the newer versions of the app. It is no longer stored as plain-text in the code. It is instead generated via another Java class. If you want it, you can extract this class, import it in your own Android app project, compile it, run it, and you’ll have the key without spending too much time reversing the code.
From there, we can just replace this function call with the secret key and we have a Java class we can use to generate a valid HMAC 😀
Conclusion and source code
I will stop this article here, since all that is left is clean up the Java code or re-implement it in any language we want. Then we just have to spend a LOT of time analyzing the requests to each of the API endpoints we’re interested in, and implement it.
I chose to make a very basic implementation of the API with only the functions I needed for a few projects I had which needed some sort of automation (posting answer, sending questions, etc.), but I was too lazy to port the Java code to Python so I kept it in Java.
If you want to get the source code, you can get it on Github : Hexalyse/pyAskFm – Basic python implementation of the Ask.fm API