SterKinekor vulnerability to download millions of user accounts

Tweet about this on TwitterShare on FacebookShare on RedditShare on Google+Email this to someonePin on Pinterest

I just finished my DevConf 2017 talk entitled All your data are belong to us: Reverse-engineering API’s, web scraping, and the details of how I gained access to 7 million Ster-Kinekor accounts.

This blog post is a rough summary of the Ster-Kinekor part of that.

MyBroadband has done a piece on this: Massive flaw in old Ster-Kinekor website leaked clients’ private data 

It’s worth noting that nothing here is particularly advanced, and neither is my security knowledge – which is sort of what makes this scary.

If you don’t want to read the details, here is a summary:

Ster-Kinekor had a vulnerability in their site/api that allowed anyone to get the profile details of every single user in their system. Those details included names, addresses, phone numbers, and plain text passwords (amongst a lot of other fields that you can see below).

To be clear, this wasn’t a hard thing to find at all, and from Ster-Kinekors side, it was just pure negligence. Not only did the API hand off details to anyone, they were also storing password in their database in plaintext (and returning those to the client!).

Some important points

  • I disclosed the details of this directly to SK last year, following the guidelines of Responsible Disclosure.
  • As of a couple months ago, this has been fixed and is no longer an issue, and that is why I can now talk about it.
  • I do not know if anyone else pulled this data. And I doubt SK knows either. But I would say it is safe to assume that someone dodgy has your data. If you’ve used your SK password anywhere else, stop reading this and go change it to something unique right now.
  • The ID’s went up to about 6.7 million. But there were some deleted accounts.
  • A bunch of accounts had password that followed a certain format. I’m going to assume that those were people that signed up in-person instead of on the site.

The new site

The site recently got redone, with a fancy new app and web front-end that doesn’t use Flash (yay). From the comments I see, it seems like it doesn’t always actually work, but at least it [probably] isn’t leaking your data. From the image below, which I took from the Android app, it looks like their new system runs on something called Vista. It also looks like they either didn’t license the app, or forgot to change the about page.

The old site

The old site was a bunch of Flash, connected to a PHP backend.
When logging into the site with your SK account, the call looked something along the lines of

That’s the entire request. So basically we can assume that the credentials you’re logging in with are in params.
So let’s try see how that params value is actually generated.
It’s safe to assume that this is being done locally, and since this is a Flash app, it’ll be done inside there somewhere.

So, I downloaded the site, which was a bunch of HTML, and some Flash bits. The flash bits are what we’re interested in.


I should note at this point that I had no idea how flash worked – I still don’t – or if it is possible to pull it apart.

So I Googled “Flash decompiler”. The first result was JPEXS Free Flash Decompiler, so I installed that.
It actually worked! Although it needed me to install Java :-/
Out of the three .swf files, side_panel was probably the place to start, as the login is in a side panel.
Searching for “login” gets a few results:




There were a few button results, but the interesting one looked like the third one (SidePanel).
That file had a bunch of code relating to registration and logging in.

Midway through the file there was the login function, which presumably does the login.

Looking at that code there is firstly some bulletproof email validity checking (they consider an email address valid if it contains an @). And below it is the call that works out what to put in the query string. Specifically, it looks like we need to find what ENCRYPT_DATA is.




Globals is just a string definition, and SidePanel is where we just came from. But maybe it is in one of the other swf’s.

Doing the same search for “ENCRYPT_DATA” in sk_main_040313.swf gives some better results





You can tell which is the interesting file there…

Opening up the Encryption file, we find a bunch of keys

Plus a bunch of methods for doing encryption and decryption.

Since I don’t know ActionScript, my first though was to try convert it to C#, but decided it would be better to just get it working in a standalone Actionscript app.

After a bit of Googling I found a free Actionscript editor called FlashDevelop.

I downloaded that, pasted the whole encryption file, and got it working in a little app to encrypt and decrypt these strings.

So back to the first login call we looked at, if we decrypt that, it shows that params is:

Calling the API with that returns a user ID.

Next, it does another call to the API, which looks the same as the first login call (obviously with a different value for params. This call returns the users profile.

Decrypting this one we can see the parameter is

3 points if you can see what is wrong here…

Yup, there is no session key, or auth, or anything checking that the person getting the profile is that same person.

So after we know an ID, all we need to do is call with a query string of the encrypted version of: method=login_profile&id=1234

And yes, ID’s were sequential.

Calling login_profile returns all the usual details of an account, like the person’s name, surname, email. Oh…and their plaintext password.

Here is an example of an account response. Obviously I’ve replaced identifying information with ***:

Not all profiles had every field (like addresses for instance). Here is a list of all the fields:

As a side note, it’s interesting that there is a PHP session key in the headers and response body. They just never use it.

Next I wanted to see if I could pull all of the accounts. I already had the encryption code working in my FlashDevelop project, so I wrote some crappy ActionScript that went through all the ID’s, encrypted a call for that ID to get the profile, and then saved that out to a bunch of text files (I say a bunch because when you’re dealing with this many items, things get big).

These files looked like this:

Next I needed to do 6.7 million calls to their API. I tried a whole bunch of scraping and data dumping software, and they were all just too slow.

So eventually I gave up and just wrote a little C# app that spun up about 200 concurrent requests at a time and pulled the data nice and quickly.

I did hit something interesting at this point though. From my single home internet connection, after doing a few hundred calls the API would just start breaking and return an error that it couldn’t contact the database. Obviously I didn’t want to break their whole system, so I artificially slowed down the requests to the point where it didn’t cause any slow down for them.

A few quick points of stuff they did wrong

  • No HTTPS, so everything is sent insecurely over the wire
  • Using their own magical encryption
  • No authentication on profile requests
  • They were returning what looks to be the entire user record out of the database – including plaintext password
  • Storing passwords in the database in plaintext
  • The API couldn’t handle the load from a single home-internet connection. This is kind of bizarre for a company of this size.
  • As far as I can tell, they had no monitoring of their service. After doing all the above, I got through to the person who I was told was in charge of the platform, and they sounded surprised that I had done this.
    A) If their service was getting hit with downtime, they should probably have some automated warnings
    B) An API as big as this should probably notify the admins when it gets hit with 6.7million queries in a day – when it likely only got tens of thousands in previous days.
Tweet about this on TwitterShare on FacebookShare on RedditShare on Google+Email this to someonePin on Pinterest