Anatomy of a Hack: SQLi via Crypto

Cryptography has various advantages including confidentiality of information. However overzealous reliance on cryptography for securing applications is a bad idea. In this blog Sunil Yadav our lead trainer for "Appsec for Developers" training class, will discuss a case study where a SQL injection vulnerability was identified and exploited via an encrypted payload.

Note: We are not going to discuss cryptographic issues (i.e. how to break cryptos) but rather an application flaw, an oversight by developers, which allowed us to generate an encrypted payload (i.e. a ciphertext for any given plaintext) which was then used to identify and exploit the SQL injection.

The actual issue was found in a real world pentest. We recreated a similar vulnerability in our hack lab for this demonstration and this is explained in detail below:

During a recent e-commerce application pentest, we observed that most of the request parameter values were encrypted.  When the request parameters are encrypted, it’s difficult to test/fuzz the application unless you can break the encryption (which requires knowledge of the secret key and the encryption algorithm). Obtaining these in time-boxed black box pentest is very unlikely. That said, check out our last blog on hacking cryptos for some insight into that matter.

Here is an example of the order details page wherein the id (orderid) parameter is sent in an encrypted format.

Note: The parameter value (BDKfx3xNKsc=) is encrypted and NOT simply base64 encoded. The encrypted value of the ID parameter is represented in base64 encoded format.

We also noted that if we log out of the application and then log back in as the same user and navigate to the exact same page, the value of the encrypted parameter (nPBri1km2ic=) is now different as shown below:

 

This provides a good indication that either a random key is used for encryption on every successful login or session ID (part of cookie) is used in some way as part of the key. Looks secure, Aye?. We tried playing around with some cryptographic flaws, but with no luck.

At first, we tried injecting a single quote (') in several locations to test input validation. The request parameters were rejected as these needed to be in the encrypted format (i.e. a valid ciphertext) and thus we sort of hit a brick wall.

Then we stumbled upon a cart sharing feature. This feature allows users to share the cart items with others. When a user saves the cart for sharing, a link is generated with a random looking token. By accessing this link (URL) users can access each other’s cart. Before the cart can be saved, the users are asked to put a name to the cart.

 

As this was one of the rare input fields that accepted cleartext input, we fuzzed it for SQLi, XSS and what not! but again with no luck.

We then realised, we have actually stumbled upon something rather interesting. On deeper inspection, it turns out that that the token in the URL generated to share the cart is actually the cipher text of the cart name we have chosen for our cart.

Note: Share cart feature was not vulnerable to any attack but it can be used to generate the encrypted payload (ciphertext) for the given input (plaintext). Now an encrypted attack payload can be generated to check the application’s behaviour for vulnerabilities like SQL Injection, Authorization Bypass, etc. To test for SQL Injection, an encrypted value of single quote (‘) was generated as shown below:

 

The encrypted payload was used to fuzz various application parameters which only accepted ciphertext values as input. It took us some while to hit the right spot, but eventually, the ID parameter of the orderitem page returned a SQL error message confirming the vulnerability as shown below:

The error message prove that the application generates dynamic queries and may be vulnerable to a SQL injection attack. It was then time to extract information from the database. UNION based SQL queries were used to extract the data from the database. The union operator is used to combine the result of two or more select statements.

The first task was to identify the number of columns returned as part of the SQL query. Using trial and error, we got a number of columns (30) returned in the query. Now, it’s time to extract information from the database. We created an encrypted payload to extract database version information as shown below:

The cipher text generated by the output of the above payload was then used as input to the vulnerable ID parameter which revealed DB version on the page.

We then used this vulnerability to pwn the database system and eventually got a shell!.

Conclusion

Encrypting parameters to implement security in the application is an example of security by obscurity. It does not make software secure. Data encrypted with strong encryption algorithms remains secret until the time keys are protected or a malicious actor identifies a way to generate an encrypted payload.  Encryption and cryptography have been considered as the de facto mechanism to protect data from tampering or spoofing. However, owing to poor implementations and lack of clarity on how “NOT” to use cryptos could result in quite devastating security breaches as we saw in this post.