Defeating Encryption

Navneet
6 min readAug 3, 2022
Photo by Markus Spiske on Unsplash

Introduction

I came across an application where I had to validate the security fix implemented by the development team. The first assessment had findings like Vertical Privilege Escalation and Horizontal Privilege Escalation through Insecure Direct Object Reference. An attacker could simply capture a request in Burp Suite and modify ‘dashboardID’ parameter to get read and write access to another user’s dashboard.

To fix these issues application team implemented AES encryption. Now all the form parameters and URL parameters were encrypted before being sent to the server and it was no longer possible to modify the request through Burp Suite.

Description

The application has the functionality to view and manage dashboards. It is available for admin and non-admin users. But non-admin users cannot see and modify the dashboard of admin users and vice versa. To avoid tampering in Burp Suite application uses the following JS library for encrypting form and URL parameters at the client-side.

  • pbkdf2.js
  • securityUtil.js
  • crypto-js.js

securityUtil.js has the following 3 important functions for encryption.

  • queryParamEncryption(): calls getEncriptionUsingAES() to encrypt query parameters.
  • formParamEncryption(): calls getEncriptionUsingAES() to encrypt form parameters.
  • getEncriptionUsingAES(): performs the actual encryption.

All the above 3 functions take 4 arguments.

  • Arg1: The parameter to be encrypted
  • Arg2: Initialization Vector (IV)
  • Arg3: Salt
  • Arg4: Token

IV, Salt and Token are dynamically generated for every request. There is no hard-coded secret key in the source code. Along with encrypted parameters the application also sends IV, Salt and Token with every request to facilitate the server to decrypted form and URL parameters. After decrypting the necessary parameters application performs various operations. Tampering any parameter in the request resulted in an error.

Impact

The consequences of bypassing client-side encryption led to the following issues —

  • A non-admin user was able to view, modify and steal an entire dashboard from ‘admin’ users.
  • A similar fix was implemented for other reported issues. Hence this finding was applicable to all other issues with a similar fix.
  • This had organization-wide repercussions as it (encryption) was treated as a standard way to fix issues in several other applications.

Proof of Concepts

As usual, I started by tampering with the encrypted request parameters to observe the application behaviour. The application responded with ‘ENCInvalid input’ or ‘Content-Length: 0’ if any of the request params were tampered with or completely removed from the request. This led to the conclusion that encryption/decryption is properly implemented and validated at the server-side. At this stage, I felt there is no point in further analyzing the issue.

Figure 1: Encrypted parameters in the request and successful response.
Figure 2: Tampered parameter and unsuccessful response.
Figure 3: Encryption-related parameters completely removed from the request.

I got curious to understand how the application encrypted form and URL parameters. I opened up Chrome Dev Tools (F12) and searched (ctrl+shift+s to search in JavaScript) for ‘encryption’.

Figure 4: Search result for ‘encryption’.

I ‘Pretty-printed’ the JS files and checked both crypto-js.js and securityUtil.js. SecurityUtil.js looked particularly interesting as it had various functions like queryParamEncryption, formParamEncryption, getEncriptionUsingAES. But to my dismay, the code was a bit cryptic and it was difficult to figure out what was going on inside these functions. But the ‘function name’ gave me some hints and I assumed the following things.

  • queryParamEncryption: is used for encrypting query params
  • formParamEncryption: is used for encrypting form params
  • getEncriptionUsingAES: returns AES encrypted string
Figure 5: Un-minified securityUtil.js

With that assumption, I thought of playing around with these functions. I went to the ‘console’ tab and called these functions one by one to see if I can encrypt my random string with a randomly chosen value of IV, Salt and Token.

Figure 6: Different encryption functions called directly from the console.

I could successfully encrypt 1 with randomly chosen values 2, 3, 4 (which is IV, Salt and Token respectively). The result looked promising. :) :)

Next, I tried to check what are the actual arguments for these functions, and for that, I added a breakpoint in ‘formParamEncryption()’.

Figure 7: Breakpoint in formParamEncryption function.

I logged in as ‘admin’ to get the ‘dashboardID’ of one of my dashboards which was not available to non-admin users. Now if I performed any operation in the application the execution stopped at the breakpoint and I could see precisely what arguments were passed to the function. ‘F10’ shortcut can be used to go to the next line of code.

Figure 8: Arguments passed to formParamEncryption revealed through the breakpoint.

I got an interesting parameter ‘dashboardId’ which was otherwise encrypted and invisible when I captured the request in Burp Suite. At this point, things got more interesting and I thought what if I modified the ‘dashboardId’ parameter and called the same function from ‘console’ to get the encrypted form parameters? The other parameters for calling the function were already revealed in this process.

Another thing to note is that both the functions queryParamEncryption and formParamEncryption call getEncryptionUsingAES (line number 124 and 141 respectively) to get the encrypted values. At this point, I had already got the ‘dashboardId’ of the admin user. Now I logged in as a non-admin user, noted down all the parameters from Dev Tool required to call the getEncriptionUsingAES function (as described above). I went back to the console tab and called the getEncryptionUsingAES function with appropriate parameters. Note that I have tampered the value of ‘currentDashboardId’ and ‘dashboardname’ parameter which was otherwise impossible to do in Burp.

Figure 9: getEncriptionUsingAES called directly from the console to get encrypted form params after modifying the arguments.

I got the encrypted form parameters. I used the same ‘Dashboard modification’ request in Repeater which I had used in the previous step to collect all the arguments necessary to call the getEncryptionUsingAES function. Please note if you use any other request the attack fails because IV, Salt and Token are unique for every request. I went to Burp Suite Repeater and replaced the value of the encrypted form parameter with the one I had obtained in ‘console’.

Figure 10: Tampered and encrypted form parameters replaced in the request.
Figure 11: Dashboard is missing from ‘My Dashboard’ of the admin user.
Figure 12: Dashboard stolen by a non-admin user.

Remediation

Authorization should always be explicitly checked server-side to verify that the user requesting to view data or perform an action is authorized to do so.

This may be as simple as checking that a user is authorized to view a page in the application or checking that the user is authorized to perform an action overall. Many other more fine-grained situations may exist depending on the application context and the complexity of the business functionality. The following are some common situations where a more fine-grained authorization check is necessary -

A user may be authorized to perform an action, but only against certain entities involved in the transaction. For example, a user may be authorized to perform a funds transfer from one account to another, but they may only be authorized to access certain accounts. Authorization checks must be performed to verify that the user is authorized to make a funds transfer as well as verify that the user is authorized to perform that transaction using the supplied accounts.

A user may be authorized to only view data tied to their account. For example, a retail banking customer may be authorized to view the details of each of their accounts at a particular bank but may not be authorized to view the details of other users’ accounts. Authorization checks must be performed to verify that the user is authorized to view account details as well as verify that the user is authorized to view the details of the account, they have requested information for.

Likelihood: High

Impact: Critical

Severity: Critical

References

  • https://medium.com/@imayankraheja/tampering-encrypted-parameter-to-account-takeovera5fec7dde360

--

--