Blog: Vulnerability Advisory

Slok API

David Lodge 03 Jul 2019

You may have read my previous post where I had a look at the SLOK padlock and found it had an interesting BLE interface which I couldn’t find a vulnerability for and a physical design that took seconds to work around.

Anyway, I alluded to some weirdness from the API and an actual vulnerability in it that could cause private information to be leaked. Now we had a wee bit of a delay in this post because we’ve been trying to disclose to Slok.

Note the word trying. Let me just highlight the appropriate disclosure bingo entry:

That’s right, Radio Silence.

So, it’s time for that joyful thing: full disclosure.

The API and its weirdness

There are many ways of writing an API nowadays, from a simple REST API to some really massive overblown ones with hundreds of different calls. Slok does it differently, it’s, well, unique.

Let’s have a wee peek at a Slok API call:

POST /index.php HTTP/1.1
Content-Length: 68
Content-Type: application/x-www-form-urlencoded
Host: www.you-lock.com
Connection: close
User-Agent: Apache-HttpClient/UNAVAILABLE (java 1.4)

vkey=1ea446cc945706a1447ba8340e9b50c0&user_id=XXXX&code=270&keyword=

That’s a whole call, post authentication. Those of you who are used to looking at APIs are now mouthing the letters “W”, “T” and “F”. So, what’s weird about this:

  1. There’s no authorisation header to indicate that the user’s authenticated
  2. There’s nothing in the URL to tell it what to do

Well, there is, and this is where it gets strange.

Everything is in the POST parameter, let me add some highlighting (I’ve censored my user ID, in case someone feels like messing around):

vkey=1ea446cc945706a1447ba8340e9b50c0&user_id=XXXX&code=270&keyword=

The parameter, code, highlighted in yellow is the actual API method. It’s defined by a three digit code, which maps to a method, in this case 270 which is the friend search method. There’s a load of these and you need to reverse the app to work out what they do, fortunately the app isn’t obfuscated and all these can be found in the class com.supude.slok.network.NetInterface

Code Method
100 Net_Interface_Init
181 Net_Accout_WXLogin
210 Net_Accout_Login
211 Net_Get_Locks
213 Net_Share_LockList
216 Net_Delete_Share
217 Net_Submit_Pushid
218 Net_GET_News
219 Net_GET_regist
220 Net_Email_Register
221 Net_GET_Email_code
223 Change_Password
225 Net_GET_Phone_code
226 Net_GET_Voice_code
228 Net_Avatar_upload
229 Bind_Mailbox
231 Net_Add_Lock
233 Net_Delete_Lock
235 Net_Submit_Activate
241 Net_Share_Lock
242 Net_Add_Code_Lock
243 Net_Share_Email
251 Net_Submit_Record
252 Net_GET_Record
270 Net_isearch_friend
271 Net_add_friend
272 Net_receiveinvite_friend
273 Net_share_friend
274 Net_invite_friend
275 Net_friends_list
276 Net_Contacts
277 Net_delete_friend
278 Net_Submit_opinions
281 Net_modify_lockname
283 Net_remote_login_password
285 Net_facetoface
286 Net_Set_solkcode
287 Net_scan_addlock
288 Net_addfriend_addlock
444 Net_WEIXINUserMesg_token

 

Why they couldn’t have just used a REST style interface and had a sensible path in the URL I don’t know.

Authentication and authorisation

So how does authentication work? The API does implement some authentication and it’s not vulnerable to IDOR, but how? If you look up, you’ll see a parameter passed with every request, called vkey, this is a sample:

vkey=1ea446cc945706a1447ba8340e9b50c0

This is an authentication, integrity and anti-CSRF token rolled into one. Some of you may have noticed that it consists of 32 hexadecimal digits, i.e. 16 bytes, which is exactly the right length for an MD5 hash.

A bit of digging in the source revealed how this parameter is created, in the NetInterface.getPostVerify method.

The above method takes the parameters as a map of Strings, sorts them in order and adds them to a temporary string as if they were parameters to a POST request.

It then concatenates the configuration value AccessToken.USER_ID_KEY and MD5s the whole lot. Further digging reveals that USER_ID_KEY is the user’s password. This was so strange I had to use a simple Frida script to dump the value of this this method, so I knew what it was:

Running this whilst performing any API call to the server dumped the goods:

So we can see that the MD5 is called twice:

  1. Once to hash the password (“956939”)
  2. Once to hash the sorted parameters prepended by the password hash

In terms of pseudocode it would be something like:

MD5(sort(parameters) + MD5(password))

So, we have this insanely complex authorisation token which contains a hash of the user’s password and the parameters acting as a dual authentication and integrity step. This has problems:

  1. The password is stored using the MD5 algorithms, which is quick to calculate, so easy to crack if the database is compromised
  2. Accounts with the same password could easily be compromised
  3. The token can’t be timed out
  4. It’s replayable
  5. You could brute force the password if you intercept it

One thing that makes a lot of the above attacks important, can be shown in one image:

Yes, in this world of free and easy TLS certificates, the app sends everything in the clear, allowing anybody on the wireless network to just sniff the hash, mitm-tastic.

And, we’ve still not got to the vulnerability.

The vulnerability

As I mentioned earlier, there’s no IDOR and in my previous blog posted that once a device has been registered, you can’t take ownership of it.

But, there was one call, Net_isearch_friend (call 270) which had an interesting side effect… This call takes a parameter, keyword, which acts as a search string. But it’s rather friendly about what it searches for, let’s do a simple search for the keyword mailinator, a popular throwaway mailbox domain:

vkey=2d50a07278afd469c9318be5116e7c5e&user_id=XXXX&code=270&keyword=mailinator

And look at what it returns:

Oh look, it returns a list of users, including their email address and phone number. Interesting and full of GDPR-type fail.

Can we improve this? Trying a search for a letter in the app failed as the app had a minimum search length. But, we know how the API requests are formed, so why don’t we just request this manually:

And what does this return? In short, a record for every account:

That’s only an extract, and, yes there were a lot of valid phone numbers and email addresses in there. We didn’t find any password hashes.

Whilst finishing this up an gathering information we also noticed that there may be a few more vulnerabilities in their backend as we could easily get an error message that implies SQL injection, as shown in the below screenshot. We haven’t looked into this further so as to keep on the right side of the Computer Misuse Act.

Conclusion

Taking all things about the Slok lock in consideration, I was mostly happy with the Slok lock’s BLE implementation, although it wasn’t perfect it was not possible to trivially be able to unlock; although there were a few things they could improve.

Its physical security is, quite frankly, laughable: it could be opened with a cheap screwdriver set and the motor spiked or the device taken apart. The shackle could be cut through with a pair of dirt-cheap bolt cutters.

On the API side, there is a lot of weirdness in the design with makes the tester’s vulnerability sense go off; but it does at least check for authorisation. That said you could extract enough information from the database to gather email address and phone numbers from its users. There were indications that secure coding hadn’t been applied and that there could be further vulnerabilities.

The company itself did not respond to several message whilst trying to disclose these vulnerabilities; this does not instil confidence.

So, in essence, I would not use this device to protect anything; I would not trust the company to protect information I provided to it (and this includes GPS co-ordinates) and I’m not particularly enamoured of its software design processes.

Avoid.