In a previous article, we reviewed the most critical and widespread vulnerability in web applications according to the OWASP Top 10: broken access control. Today, we tackle the common vulnerabilities and exploits related to the lack or absence of encryption in applications.
Data encryption is crucial to ensuring application security. In this article, we will explore the vulnerabilities related to the lack or absence of encryption through the prism of the OWASP Top 10. Using attack scenarios from penetration tests, we will detail common exploits as well as best practices, fixes and measures to implement to properly encrypt data in order to prevent the risk of compromise.
What is data encryption?
Encryption is a process that consists of converting all types of data into an encrypted code that cannot be decrypted without a specific key (encryption key). It is a central element of any cybersecurity strategy, as it not only ensures the confidentiality and integrity of exchanged and stored data, but also verifies the authenticity of an authentication or controls access to a resource or a service.
What are the different types of encryption?
Encryption mechanisms are usually configured with keys. The security of these mechanisms relies almost entirely on the confidentiality and/or integrity of these keys. In practice, encryption can be symmetric or asymmetric:
Symmetric encryption
Symmetric encryption is an encryption method in which the same key is used for both encryption and decryption. This key is called the secret key and must be kept confidential for security reasons.
In practice, symmetric encryption allows a clear message to be transformed into an encrypted message, using this key. In the same way, only this key will allow the communication to be decrypted.
Asymmetric encryption
Asymmetric encryption is an encryption method that uses two different keys: a public key, which can be publicly distributed, and a private key, which must remain confidential.
For example, in an electronic signature mechanism, an entity has a private signing key, and the verification key can be published.
The public encryption operation uses the public key to transform a clear message into an encrypted message. At the same time, decryption will allow the communication to be re-transcribed in clear text from the encrypted message and the private key.
What are the common exploitations of lack of encryption?
Insufficient encryption of passwords in a database
The compromise of a database is obviously catastrophic in itself. However, insufficient or no encryption of the passwords stored in the database can make the difference between a “simple” data leak and the total compromise of the platform.
We have encountered this several times: a vulnerability allows us to retrieve, in one way or another, insufficiently hashed or clear text passwords, which then allows us to log in, usually with administrator accounts on the platform.
Let’s take a closer look at one particular case:
Exploiting an SQL injection to retrieve a password database
The scenario is as follows: we perform a web application penetration test in black box.
An SQL injection on the login form has allowed us to retrieve the database. The platform is already heavily compromised. However, the SQL injection only allows us to read data when we would like to insert it.
Furthermore, our ultimate goal is to gain access to the administration panel in order to further compromise our target.
Discovering MD5 hashed passwords
The data in the user table that we have retrieved through the SQL injection is as follows (for this example, the data has obviously been replaced by mock-ups):
Passwords are hashed, but their hash algorithm is easily recognisable: MD5.
MD5 is an algorithm invented in 1991 that has since (first partially in 1996, then completely in 2004) been compromised. Today, it is considered unsuitable for security and should no longer be used for storing passwords.
Its obsolescence allows us to easily and quickly break most MD5 hashed passwords.
Brute force attack on the hashed passwords
There are several ways to crack an MD5 password. Here, we opted for a simple dictionary attack. However, this method does not allow us to collect all of the users’ passwords but we only need to obtain a few passwords, ideally an administrator account.
The best known tool for cracking passwords is John the ripper. In our case, we will use it in wordlist mode with a password dictionary: rockyou.txt.
First, we put all the hashes in a text file hashes.txt.
Then we run John:
The operation takes only a few seconds and finds several passwords. And when you look at the counter in the last line of the above screenshot “1.084g/s”, it means that the software tests more than a billion possible passwords per second.
This is one of the main reasons why MD5 is obsolete: flaws in the cryptographic algorithm allow for mathematical “shortcuts”, which greatly reduce the effort needed to calculate a hash and allow for so many attempts per second.
After obtaining the passwords, we found that one of them corresponds to an administrator account, which allowed us to compromise a large part of the application.
Use a robust hash function to secure password storage
Passwords should be hashed with strong cryptographic algorithms such as Argon2, scrypt, bcrypt or PBKDF2.
And to add an extra layer of security, hashes can be salted, with a unique random string for each password (stored in the same database table as the password) and peppered, via a random string shared by all passwords (not stored on the database but usually on the application server instead).
With salt and pepper, an attacker must compromise the database AND the application server to have any chance of attacking the passwords. Even then, it will take considerable resources and time.
In addition, a strong password policy should be put in place to reduce the possibility of dictionary attacks.
Finally, it should be noted that, from a legal point of view, the storage of passwords in clear text or with algorithms clearly identified as obsolete are considered a breach of the security obligation of organisations towards their users with regard to the RGPD in particular and can lead to legal sanctions.
For more information on the secure storage of passwords, you can consult the articles below:
How to securely store passwords in a database?
How to update passwords in database to secure their storage with Argon2?
Weakness of HMAC keys and modification of a JWT token signature
A JWT is a token, often a session token, which has the particularity of being able to contain data (in JSON format) allowing a user to be identified and to fill in metadata concerning him or her: name, email, role, access rights, etc.
The integrity of this token is guaranteed by an algorithmic signature system which ensures that the token has not been modified or forged.
Grey box penetration test of a web application
This time, we test a very classical web application, with a system of rights by stratum:
- “Users” have the most basic rights.
- “Managers” have control over a company space and all users attached to it
- The administrator role is reserved for employees of the company that manages the web application and is used to set up and manage the different areas.
“Users” and “managers” accounts were provided for testing.
Structure of the JWT token
The session system works through a JWT token, generated by the server during authentication and then passed on to the client.
This token looks like this:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjY0MSIsIm5hbWUiOiJ2YWFkYXRhIHRlc3QgdXNlciAxIiwicm9sZSI6Mn0.yo5wq8EOs96H5IHo3RGGMdaQjknLsRqNfwvneICyF14
When decoded from base 64, we get this:
{"alg":"HS256","typ":"JWT"}
{"id":"641","name":"vaadata test user 1","role":2}
+ signature
We can see that the JWT is signed with HS256 and that it contains the id and role of the user in question. It is very likely that if we manage to modify it, we can steal other accounts by changing the id or escalate our privileges by changing the role.
Brute force of the secret
First of all, let’s test the simplest attack: change the signature algorithm to “None” and see if the server accepts the token anyway. If it does, it means that the signature is not verified at all and we can forge any JWT. Several ways can be used to generate a JWT token. Here we will use the cyberchef site and its “JWT sign” function.
We use the generated token instead of our own and… the server returns a 401 “unauthorized” error.
So the signature is verified, but is it solid?
Let’s test another attack technique: cracking the secret (the password) used to sign the JWT.
We know that the signature is created with the HASH-MAC256 (HS256) algorithm. So let’s try to crack it with, once again, John the ripper.
We put the JWT in a file (jwt.txt) and try to crack it, first with a dictionary and then, if that doesn’t work, we’ll try a pure brute force attack.
It was quick. The key appears to be “secret”, presumably a default key that has not been changed.
To check that we have the right key, we just need to generate a JWT token with it.
After verification, the token is accepted by the server.
This effectively gives us full control of the session system. Thus, we can forge JWTs to log in with any user, or even as an administrator, giving us almost total control of the application.
Fixing the vulnerability
To ensure the security of the JWT token, two parameters must be taken into account:
- The algorithm. Make sure you not only use an algorithm that is suitable for your purpose, but also that it is verified with the same algorithm! We regularly find servers that rely entirely on the token’s metadata to define its signature type, which can be abused by changing the algorithm to “none” and thus bypassing the signature system completely.
- The secret. Make sure you choose a strong password as your secret. It should be as long as possible and randomly generated.