JonLuca's Blog

08 Feb 2020

Reverse engineering Blind's API and client side encryption

Blind is an app that provides an anonymous forum and community for verified employees to discuss issues, interact with people of similar professions and lifestyles, and discuss normally taboo topics like compensation, company policies, or political issues du jour. Users on Blind are grouped by topics, company and their broader industry.

Around a year ago they introduced their webapp - before this, they were just a mobile app.

blind homepage

Blinds current web homepage (teamblind.com)

I decided to poke around and see how they decided to implement their routing and webpage.

Loading into their homepage I was happy to see infinite scrolling and inline comments - this usually means they aren’t server side rendering everything, and have pure API routes setup just to fetch these things. It’s trivial to find and reverse these client side requests - no HTML scraping is needed.

As a side note, this is probably one of the main redeeming factors for people that still use PHP to generate their HTML. It’s significantly more work to scrape HTML than to use client side routes that (usually) return JSON.

Looking into the requests we see POST requests to https://www.teamblind.com/api/article/list.

blind network

POST requests to retrieve additional posts on the homepage

The response, however, wasn’t what I was hoping for.

{
  "payload": "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"
}

The request was also formatted this way, but we’ll get to it later.

blind request blob

Blinds API request format

It was a JSON object with a single key - payload. It had the telltale signs of base64, though (any string ending with = should set off your base64 detector).

{
  "payload": "A3gsuMXojEEY...<omitted for brevity>...HWGAKB7O+U8Q=="
}

I was hoping this was a custom text format encoded in base64, but unfortunately decrypting it lead to garbage.

blind encrypted blob

Decoding the base64 lead to garbled text

It was clearly decrypting this into legible content, though, so I wanted to figure out how it was formatted and how easy it would be reverse.

Decryption

The javascript that was making the request was minified through webpack, and chunked.

blind minified js

Stepping through the minified javascript

Stepping through wasn’t particularly useful, though, as it seemed like a custom HTTP library that was just a thin wrapper around fetch and XMLHttpRequest.

I assumed that they were probably using an open source library for their encryption - they are still a startup, afterall, and I doubt they’d roll their own encryption library.

I started looking for strings in the code that would be helpful - a lot of minification can’t know what a string contains, and as such won’t strip things like library version numbers and names, URLs, and other things that would give a hint of how it’s being done.

blind git

References to GitHub in the minified codebase

There were quite a few references to GitHub (Always a good keyword to search for - package authors will often link to the open source code for issues in strings that are included in the minified library).

blind encryption library

The open source library they were using for their encryption

Bingo.

    throw new Error(["sorry, createCredentials is not implemented yet", "we accept pull requests", "https://github.com/crypto-browserify/crypto-browserify"].join("\n"))

This library had a function called createCredentials that hadn’t been implemented yet, and had the helpful comment saying “We accept pull requests!”

This section of the code was clearly the minified version of the open source library.

    var p = n(342);
    t.pbkdf2 = p.pbkdf2,
    t.pbkdf2Sync = p.pbkdf2Sync;
    var d = n(519);
    t.Cipher = d.Cipher,
    t.createCipher = d.createCipher,
    t.Cipheriv = d.Cipheriv,
    t.createCipheriv = d.createCipheriv,
    t.Decipher = d.Decipher,
    t.createDecipher = d.createDecipher,
    t.Decipheriv = d.Decipheriv,
    t.createDecipheriv = d.createDecipheriv,
    t.getCiphers = d.getCiphers,
    t.listCiphers = d.listCiphers;
    var f = n(534);
    t.DiffieHellmanGroup = f.DiffieHellmanGroup,
    t.createDiffieHellmanGroup = f.createDiffieHellmanGroup,
    t.getDiffieHellman = f.getDiffieHellman,
    t.createDiffieHellman = f.createDiffieHellman,
    t.DiffieHellman = f.DiffieHellman;
    var l = n(539);
    t.createSign = l.createSign,
    t.Sign = l.Sign,
    t.createVerify = l.createVerify,
    t.Verify = l.Verify,
    t.createECDH = n(573);
    var h = n(574);
    t.publicEncrypt = h.publicEncrypt,
    t.privateEncrypt = h.privateEncrypt,
    t.publicDecrypt = h.publicDecrypt,
    t.privateDecrypt = h.privateDecrypt;
    var M = n(577);
    t.randomFill = M.randomFill,
    t.randomFillSync = M.randomFillSync,
    ...

The description of the library is “The goal of this module is to reimplement node’s crypto module, in pure javascript so that it can run in the browser.”

It looks like they’re using Node on their backend with the crypto module, and want to use the same features on their front end in exactly the same way.

Nice way to reuse code, but it also means that they have to pass their shared secret key to the client.

I assumed that they wouldn’t include the secret key in the client - they’d create one adhoc per session, and renew it every X minutes, through a websocket perhaps.

I assumed wrong.

blind encryption key

Blinds shared AES secret key

They kept the static shared key as a string in the minified JS. They also helpfully named these functions dataDec and dataEnc.

At this point it looked like we have everything we need to decrypt their data.

We don’t even need to download the library they used, since it’s just a reimplementation of the crypto module.

30 seconds in an editor later and we have the following:

const text = `<blob from above>`;
const crypto = require('crypto');

const t = crypto.createDecipher("aes-256-cbc", "5d860d3eb8e4a271309c0e4c001fafcc7cc80277e5238d9796a810a93ffa27d3")
let e = t.update(text, "base64", "utf8");
e += t.final("utf8")


console.log(JSON.parse(e))

I just copy and pasted their minified implementation and swapped out the crypto module.

blind decrypted

The API decrypted API response

This worked out of the box - no additional required. The most interesting part of the response was the article_list. These were formatted as follows:

{
    "alias": "b6WJEDTp",
    "member_nickname": "faRw33",
    "created_at": "4d",
    "is_auth": "Y",
    "board_id": 114961,
    "member_company_id": 109330,
    "images": [],
    "group_name": null,
    "channel_name": "Misc.",
    "board_name": "Misc.",
    "title": "Is an extreme work ethic required to reach the absolute top of your potential?",
    "content": "I was never a huge basketball fan, but after Kobe's death I spent more time into his background. He was an absolute machine in how hard/how long he worked and the results showed. It's seems like its like that with so many great people who are just so passionate about one thing they will work their b",
    "content_length": 300,
    "like_cnt": 2,
    "comment_cnt": 22,
    "view_cnt": 1337,
    "is_liked": false,
    "is_bookmarked": false,
    "is_multi_poll": false,
    "is_multi": false,
    "is_poll": true,
    "is_mine": false,
    "last_comment_cnt": null,
    "has_comment_update": false,
    "is_hot": false,
    "is_now": false,
    "is_company_tagged": false,
    "is_wormhole": false,
    "job_title": null,
    "is_read": false,
    "report_msg": null,
    "is_top_contributor": false,
    "is_show_holic": false,
    "mention": null,
    "was_companies": null,
    "bio": null,
    "tags": [],
    "article_tags": null,
    "is_hidden_company": false,
    "is_show_company": true,
    "member_company_name": "Greenhouse Software",
    "is_best_company": false,
    "poll": {
        "id": 47176,
        "article_id": 553156,
        "is_multi": false,
        "cnt": 108,
        "polled": 0
    },
    "link": null,
    "label": null
}

We get the users alias as well as their nickname, which isn’t shown on the actual posts, as well as some other information about the post.

We can now successfully decrypt every response from Blind. But how about making these requests adhoc in the first place?

Encryption

Back to making the requests that we alluded to earlier - it looks like the request also follows the same format, with a payload.

blind request blob

Blinds API request

The natural assumption would be that they follow the exact same format as above - use that same AES key to encrypt the request payload.

First we need to figure out what the non-encrypted request looks like.

Looking back above at the decryption process, there was another function called dataEnc. This is probably how they encrypt their requests. Putting a breakpoint there before the function is executed shows us the format.

blind request

Blinds API request format

The encryption is different this time, though - it’s using an asymmetrical public key instead of the AES key from earlier. I’m not entirely sure why they do this - if someone is sniffing traffic, and they’re able to see the encrypted request object, they would’ve been able to see the minified JS and do the same thing I’m doing right now. It does prevent an attacker from decrypting the request, since they don’t have the private key, but it doesn’t prevent them from just recreating the request in the first place.

Regardless, their implementation looks like this:

return new Jt("-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhRvQEkqodGnJ9ap47FiF\nNwMTpdqUbfWyzecgJBxjWwWYwMYxpnde0WNjpzpdz9PMKLdFAg0UH1u32Y2xK/Bq\n/L8F2f+djLwGxszjTZwGGPiQxNWyDRI/In8T3S3dVqfr0QPirKsoy2OxgnbC7+BE\nH0ZN6Y4Sax588Uq+9M1Wz7ct60EZjLO9RLS/qH+t1ZBpQ/p3Ddkm/yCDvixyctvd\nGTbWUVFxtsqdTQjy8OcnQo2y1v6NUeZRqoKsk7LVmkYk3HjggDkBOZk8h1xRuCch\nkY1ix5jjArG645y863N6R+EQ9ShHZnwbVpsy47Vo8zigfk2RKl8ksxvstLrtABfW\nDQIDAQAB\n-----END PUBLIC KEY-----").encrypt(t, "base64")

Looking at the function signature (.encrypt(t, "base64")) and code it wasn’t immediately obvious what library they were using (they weren’t using the same library as earlier).

Actually stepping into the code this time helped.

blind stepping into code

Stepping into the minified third party library for public key encryption

Googling around for the this.$options had a nearly perfect match on the node-rsa module.

blind googling for options

Google results for the JSON options object of the library

Minification will often not rewrite variable names for certain classes due to potential issues with string based references (options['mystring'] needs to work, so you can’t rewrite certain variables. Thanks compilers class!). Because of this you can pretty easily find 3rd party libraries even without a source map or any understanding of what the code is doing (which is fairly frequent when dealing with minified JS).

I do the same as we did above and create a simple wrapper for this library:

const NodeRSA = require('node-rsa');
const key = new NodeRSA(`-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhRvQEkqodGnJ9ap47FiF
NwMTpdqUbfWyzecgJBxjWwWYwMYxpnde0WNjpzpdz9PMKLdFAg0UH1u32Y2xK/Bq
/L8F2f+djLwGxszjTZwGGPiQxNWyDRI/In8T3S3dVqfr0QPirKsoy2OxgnbC7+BE
H0ZN6Y4Sax588Uq+9M1Wz7ct60EZjLO9RLS/qH+t1ZBpQ/p3Ddkm/yCDvixyctvd
GTbWUVFxtsqdTQjy8OcnQo2y1v6NUeZRqoKsk7LVmkYk3HjggDkBOZk8h1xRuCch
kY1ix5jjArG645y863N6R+EQ9ShHZnwbVpsy47Vo8zigfk2RKl8ksxvstLrtABfW
DQIDAQAB
-----END PUBLIC KEY-----`);

const toenc = {
  "channelId": "Careers",
  "childchannelIds": [
    120565
  ],
  "offset": 0,
  "limit": 50,
  "orderBy": "pop"
}

const encrypted = key.encrypt(toenc, 'base64');
console.log('encrypted: ', encrypted);

I was a little thrown off at first because what I got didn’t match what my browser was saying, but then I realized that this library actually produces a different output on every decryption.

blind different outputs for the same input

Different results on every encryption

I took my request and replaced the encrypted blob from their version of the library and replaced it with mine, and got back a valid response.

We are now able to generate requests and decrypt the responses.

The offset and limit are also interesting, but I’ll leave that as an exercise for the reader 😉.

Conclusion

Blind is encrypting their requests and responses locally. While not a good solution to network sniffing and interception by any means, this isn’t as dumb as it initially looks - it prevents anyone who is only looking at their API route from being able to decrypt it.

It also prevents any automated tools from harvesting the data; you’d need to do a fairly deep analysis of their libraries and keys to figure out how it was encrypted. Additionally, by encrypting the requests with the public key, you couldn’t decrypt them unless you had the corresponding private key. This is less true for the AES key (but probably makes sense based on relative sizes of the requests - public/private key encryption is much more computationally expensive than AES, and the requests seem to be a few orders of magnitude smaller than the responses).

Overall a pretty fun weekend afternoon!

JonLuca at 12:54

Follow @jonluca
Share on: