SÅ‚awomir Jasek

12 minute read

Okidokeys does not work any more

One of my smart locks, Okidokeys, unexpectedly just turned into a brick, and this time for a change I had nothing to do with it ;) The mobile application barked at me: “Login request has failed. Please try again”. And the more I tried again, the more the login request failed. I finally discovered the vendor’s application server was shut down. And suddenly recalled shutting down their official website, Twitter and Facebook accounts a while before, but did not consider it important back then. Now as it turns out, also the phone number and e-mail server is dead. Following a quick investigation I found out they have been acquired in the meantime. By translating French forum I also realized some locks are undergoing a migration procedure to a new system, and the users are supposedly being notified. I did not get any notification - maybe because based on the serial number my lock was apparently destined for ‘American market’. That market was not covered by the acquisition, and therefore my device is not eligible for migration, as many others also just found out. I guess we can’t count on support any more. I wonder how many of the > 5000 customers (approximation based only on Android mobile application installs) have the same problem. And as of today there is still plenty of offers on US Amazon and Ebay.

You can imagine the level of frustration for a smart lock owner - suddenly being cut off her/his own door - by a “smart” device, that did not come cheap by the way. Feels like installing it in a first place was not the smartest move, the least to say.

Luckily that was not the case for me - not that I didn’t like the device, I just didn’t actually mount any of my extensive smart locks collection ;) But I must admit that putting this one away into non-existence of my huge “broken hardware” stack, was far away from my plans. I really got accustomed to this guy. Not only does it feature a wonderful set of vulnerabilities perfect for my “smart lockpicking” workshops and trainings, but also makes the most distinguishing “whirr” sounds out of its complex internals during operation. And it’s actually a nice piece of hardware, despite disputable external appearance. No, definitely I can’t just leave it to die!

Do you have the same problem already? If not yet - do you think such a scenario would be possible for your own devices? In any way - follow on for solutions.

The newbie’s way

For starters, we will just need some basic investigative skills.

Interestingly, simple Google Play search for Okidokeys reveals few more applications besides the original one:

You may also notice that some of the applications are published by the same developer. Following this trail, we can also find another applications. A quick glimpse at all these app’s screenshots makes an irresistible impression that they kind of resemble themselves:

It looks like we have just encountered a very common practice among device manufacturers: “white labeling” or “virtual manufacturing”. You can have basically the same device, with identical functionality and internals, but a different label, and/or sometimes external casing. Now if that’s actually the case with our lock, why not try to just use other brand’s application with our lock? Let’s take the German one. The mobile application does not have a registration option. In order to use it, one has first to register in a separate web portal. We will need our google search skills again:

The portal is in German only, but if you are already familiar with original Okidokeys one, this works exactly the same. Follow the registration (konto erstellen) and setup the new lock (Smart Gerate -> Smart-lock registrieren). Next, add your user to the new lock, by somewhat counter-intuitive drag&drop of the user icon (on the right) to the lock box (on the left):

Now we will need to reset the lock hardware to initialize it with new keys, by long-pressing hidden button using a screwdriver:

Next, log in to the mobile application with your new account, and initialize the “sync” function:

Aaaaaand it works! Now you have your lock back again! It happily whirrs back and forth on your command. You saved the lock and made the world a better place. Congratulations!

Unfortunatelly, the application is in German only. Also, judging by the very low number of its installs, one can expect it will share the fate of the original one any day now. The support documentation and videos are already pulled off.

So, if you are brave enough to become an ‘amateur hacker’, follow on for a better solution :)

The amateur hacker’s way

We will analyse the data exchanged between mobile application and the server, and based on this - build our own, independent API server!

Analyse the requests

First, we need to intercept and record communication between the mobile application and original API. My tool of choice is Burp proxy, configured to intercept traffic from the smartphone. The free version will be good enough for our needs. But you can also use any other intercepting proxy, for example open-source OWASP ZAP.

The HTTP requests are quite straightforward and self-explanatory. For example, authentication (“smartphone/login”):

GET /index.php?page=smartphone/login&lang=english&[email protected]&PASSWORD=SuperSecret&nb_keys=0&_=1506333432890 HTTP/1.1

Device initialization (“smartphone/sync”) request:

GET /index.php?page=smartphone/sync&lang=english&[email protected]&PASSWORD=SuperSecret&DEVICE_UID=_25256524230164894&type=BIN&_=1506333432901 HTTP/1.1

the server responds with base64-encoded cryptographic “seed” to initialize the device:

{"ERRORS":[],"SYNC":{"BIN":"REIX+RT3BIBCcaYl\/f3aaDJ9S\/gDD984wMrGMLIUhF3RRJFLyTrkPHHJQvTkyK0vdhgTQoxd\/2fzrCqW3rD11iloIUGjM6lvY3lcauCbVb8CEK03ZAW3xDLbqPa4jl8jrdhqHfo="}}

Other requests, and example response containing lock keys generated by portal, as visible in Burp proxy:

For those of you having a pro version of Burp, with possibility to restore saved state, I have uploaded a full session dump, including all the HTTP requests here on Github.

Create our own API

We will create our own API in the easiest way possible: just save the above responses JSON content from Burp proxy to static files, and then serve the same content from these static files. My example files and instruction are here on Github. You can create your ones - by intercepting your requests as explained above. Or - you can use my ready files. Just change the device serial number "DEVICE_OCSN" in my actuator_list and smartphone_login JSON files. You can also change the lock name, PIN and other values according to your needs. Of course, if you decide to use my files, be aware that keys to your lock are now public on Github :)

You will need to upload the files to a web server of your choice. I have used my own laptop running Apache http server, which was in the same local network as my smartphone. But of course you can use for example a hosting service, just remember to secure it (e.g. add access control to .htaccess, implement HTTPS). Beside the content files, we will also need to configure rewrite engine - so that specific static files match the above HTTP requests from mobile application. I have prepared for that a very simple .htaccess file, with basic syntax like this:

# login
RewriteCond %{QUERY_STRING} ^page=smartphone\/login
RewriteRule ^$ smartphone_login.html    [NC,L]

# initialize crypto seed (sync)
RewriteCond %{QUERY_STRING} ^page=smartphone\/sync
RewriteRule ^$ smartphone_sync.html    [NC,L]

(...)

(whole htaccess here). For simplicity, I removed the index.php of original requests (we will remove it from URL hardcoded in mobile app in a few moments also). From now on, every time your mobile application will request URL like:

http://your_server/?page=smartphone/login<anything_here>

the server will respond with static file content smartphone_login.html.

Patch the mobile application

OK, so we have the server part ready, now we just need to redirect the mobile application to our own server instead the dead one. This can be done among others by using DNS tricks - e.g. static DNS entry on your router or smartphone, redirecting the URL hardcoded in mobile application to your own API address. But we will follow different approach: patch the mobile application binary and replace its URL. If you haven’t done such things before - don’t worry, it’s much simpler than it sounds.

You will easily find plenty of good resources on how to reverse-engineer and patch Android applications, so I will not explain all the details here. We will just follow a few simple steps - obtain APK binary, unpack it, edit the text configuration file, pack it back, and self-sign the binary.

First, download Okidokeys original apk file - using online service, or from your phone (with developer options on):

$ adb pull /data/app/com.okidokeys.smartapp-1/base.apk

Next, unpack it using apktool:

$ apktool d <your_file.apk>

Now, to find where the URL is hardcoded - just grep the uncompressed folder for ‘portal.okidokeys.com’. You will find configuration file: assets/www/js/openways/tools/constant.js. In this file you will find various endpoint addresses (some of them still operating by the way):

DevBaseURL:"https://devportal.okidokeys.com/index.php",
ProdBaseURL:"https://portal.okidokeys.com/index.php",
MaxBaseURL: "http://192.168.0.113/index.php",
PostaccessDevBaseURL : "https://ps.okidokeys.com/index.php",
PostaccessProdBaseURL : "https://moncompte.postaccess.fr/index.php",
CTCAMDevBaseURL :"https://www.cle.ctcam.fr/index.php",
CTCAMProdBaseURL : "https://www.cle.ctcam.fr/index.php",
TOXDevBaseURL :"https://devportal.okidokeys.com/index.php",
TOXProdBaseURL : "https://portal.tox-smartlock.de/index.php",
OWSDevBaseURL :"https://devportal.okidokeys.com/index.php",
OWSProdBaseURL : "https://mykey.openways.com/index.php",
DOMDevBaseURL :"https://devportal.okidokeys.com/index.php",
DOMProdBaseURL : "https://portal.okidokeys.com/index.php",
PushwooshBaseURL : "https://cp.pushwoosh.com/json/1.3/",

Just switch the ProdBaseURL to your server root (without index.php, to match our rewrite rules). For example:

ProdBaseURL:"http://192.168.0.5/"

Oh, and if you can’t have your own server, of course you can use other API endpoint with the original, English language Okidokeys mobile application. You know what to do :)

Now, pack the application binary again:

$ apktool b <your_path>

And the last but not least step - sign the re-packaged apk, using for example apksigner or any other tool.

Now you can finally install the resulting apk file to your smartphone. You don’t need to provide proper login and password - our simple server does not check it. Aaaaaaaand it works, again! I also could not help myself but to switch the default lock image by the way (you will easily find the link in JSON file):

I was playing with it like a kid - opening and closing back and forth :) The cheer did last however only until I tried to open the lock for the 10th time… It emitted a long warning beep, flashed to me its red light, and declared “operation failure”:

Outdated?!! What do you mean outdated? We will need to dig deeper…

Generate more keys

The mobile application receives only 10 keys at a time from portal, and then another 10 after using them. In our server, the application gets again the same static file with the same keys. As the lock device checks if a given key was already used (anti-replay protection, valid security mechanism), it does not allow us to reuse them. Hence the error.

We could undergo the inconvenient reset procedure every 10 unlocks, but that would be very user-unfriendly. How about getting more keys? We can send the request to get the new keys multiple times, save the consecutive responses and then serve them one after another. But wait - there is a better solution! An observant reader may have noticed the “nb_keys” parameter in the HTTP GET request invoked from mobile application to generate keys:

GET /index.php?page=smartphone/login&lang=english&[email protected]&PASSWORD=SuperSecret&nb_keys=10&_=1506333432897 HTTP/1.1

Guess what this parameter controls? Yes, the number of keys to generate of course! How about changing its value? In Burp Proxy -> HTTP History tab right-click on the interesting request and choose “Send to Repeater”. Now you can edit this request and hit “Go”. And yes, the server happily responds with more keys:

In this case the response is massive 11Mb, and it took almost a minute to compute and transfer. But it consists mostly of base64 encoded MP3 content - apparently they had locks opened by emitting special sound(?). But that feature won’t be useful for us, so we can safely remove the MP3 part from the JSON response:

$ jq 'walk(if type == "object" and has("MP3") then del(.MP3) else . end)' 500_keys.json > smartphone_login.json

The resulting file is only 70k.

Final recipe

One more trick to go. We want the mobile application to get the keys from our server only once, store them and then just use the stored values. For that we will need 2 separate responses to smartphone/login request: with- and without the keys. The response containing keys will be used only during lock initialization. For consecutive application use, we will serve the login response without the keys. Faced that, the application will just use the previously stored values. We already took care there will be enough of them for long :) You will only need to provide PIN to use them - they are encrypted on your phone. My PIN was set to ‘1232’, but you can edit it freely in the static json files (look for PINCODE element).

So, during initial setup just use the default .htaccess file which points smartphone/login request to smartphone_login_keys.html (the one with the keys). After the device sync is done, rename .htaccess_after_setup to .htaccess - which will point to smartphone_login.html (without the keys). Otherwise, when mobile app downloads the same keys again, we would face the key reuse problem.

Now you can be proud to have made the lock finally working great again. You will just have to reset it after 500 unlocks.

Summary

Back in the old days, if you bought a piece of gear - e.g. furniture, an oven or a radio - it was undoubtedly your device. You did not have to worry much how long this specific manufacturer/craftsman will be there to help you in case of trouble. You could safely assume in such case it will be possible to repair it and use again anyway.

Nowadays, device manufacturers seem to take advantage of the contemporary device complexity, moving towards proprietary clouds, subscription services, limiting usage and unlocking features on request. Of course protecting intellectual property is a valid argument, and cloud services are very useful. But on the other hand the desire to have a full control over already sold device can easily turn against users. Who are mostly unaware that their perfectly working gadget can suddenly become an electro-waste without their consent.

Therefore we should promote open architectures and specifications. Not just “open” API - usually still controlled by vendor and impossible to replace - although that’s a good first step. Preferably easy to repair, open design hardware, which can be supplemented with open-source software of your choice. I do realize this is a utopian dream, and such devices are a rare species (I probably have most of them in my drawer already). So for now I’m afraid we’ll have to stick to reverse-engineering. Fortunately both EU and US legal systems allow for it, if this is necessary in order to achieve “interoperability”.

In our case, we just used a few simple tricks to bring our device back to life. We were lucky and did not have to reverse-engineer the proprietary key generation algorithm. That would require much more advanced skills, and significantly more time. In other cases the effort may be higher, but it’s worth a try - which can be a life-saver for your device in a future. So - do not count on vendor’s support, be smart and take the matters into your own hands. And better hurry up before it’s too late!

Stay tuned for more tutorials coming, including hacking smart locks, access control systems, home automation and other devices.

And of course you can also follow me or smartlockpicking on Twitter. Thank you!

comments powered by Disqus