Introduction
String data type is used quite often for storing hard-coded secrets in the code. These secrets could be general purpose literals used in applications like connection strings or business specific secrets (like coupon codes, license key, etc.). The fact that a vast majority of developers/applications have sensitive data in string data types makes it quite interesting for hackers. In this article, we will demonstrate some techniques that hackers use to discover sensitive information stored within strings.
Let's Make Couple of Things Clear Upfront
There are couple of things that I would like to make absolutely clear before we delve into any further discussion. First in this article, I will demonstrate how hackers can use tools like JustDecompile, ILDASM and Windbg to their advantage. What's important to remember is that none of these tools were built to facilitate hacker's interests. These tools are built for legitimate purposes and for good reasons. It's just that bad guys use the same tools for their own interests that can be potentially harmful for others. It is therefore quite important to learn the techniques that hacker's use so that we can be better prepared to mitigate against specific threats posed by those techniques.
Finally this article by no means is about defense mechanisms for the threats that I will demonstrate. I will briefly mention some common approaches that could be used to defend against these threats, however, it is not a comprehensive discussion about defense mechanisms & methodologies.
What Makes this Type of Attack Possible?
With CLR Execution model, you write code in your favorite .NET Language like C#, Managed C++, VB.NET, etc. This code is compiled into byte code called Microsoft Intermediate Language or IL. So your application or .NET Assembly actually contains code in the form of Intermediate Language. When you execute your application, at runtime this IL code is compiled into native CPU instructions. The process of compiling IL code into native instructions is called Just In Time compilation aka JITting.
Figure 1: CLR Execution model
This intermediate language contained in .NET assemblies is highly detailed and it preserves information about all data structures like classes, fields, properties, methods, parameters, even the method code. Presence of this highly verbose IL is what makes reverse engineering a .NET assembly quite trivial thus enabling attackers to gain valuable information without having access to the actual source code.
Let the Fun Begin
In order to find hard coded secret in an assembly, you can open the assembly in .NET code browsers like Telerik’s JustDecompile or ILSpy, etc. These code browsers provide you with the ability to open a .NET assembly and view the code in form of C#, VB.NET or Intermediate Language. Let’s take a brief look at our sample application. The code itself is very simple & straightforward but it’s good enough to demonstrate the concept. This sample application has a class called Constants
that contains some strings used to store sensitive business information as shown below:
public class Constants
{
public static string ConnectionString = "Data Source=HOMEPC;
Initial Catalog=MyDb;User Id=SpiderMan;Password=secret;";
public static string CouponCode50Pct = "AlphaBetaGamma50";
public static string CouponCode75Pct = "AlphaBetaGamma75";
public static string UserName = "SuperUser";
public static string Password = "SuperSecretPassword";
public Constants() { }
}
Now let’s open the compiled executable assembly in Telerik’s JustDecompile. Figure 2 shows the view of this assembly and as you can easily view these strings that should not be easily revealed to anyone.
Figure 2: .NET Assembly in JustDecompile
Typically in a real-life application, searching through strings by opening the assembly (or set of assemblies) in any .NET code browser (like Telerik JustDecompile) is a tedious job. Today’s hackers are smart and they have more efficient tools in their arsenal to efficiently find vulnerable pieces of code and plan their next attack accordingly. One of those tools is Intermediate Language Disassembler (a.k.a ILDASM). Just like JustDecompile, ILDASM could be used to disassemble a .NET assembly and view its code, however, with ILDASM you can only view this code in the form of Intermediate Language.
ILDASM can be operated in two modes, one using its graphical user interface; the other one using command console. ILDASM in console mode is what typically hackers prefer especially to perform an information disclosure attack. Figure 3 shows how ILDASM could be used in command mode to search for string types present in .NET Assembly code.
Figure 3: ILDASM for searching string data types in .NET Assembly
We have used ILDASM with text
switch, which basically implies to display the decompiled assembly in the console windows. This text is then piped into findstr
command. The argument to findstr is ldstr
. ldstr
is an intermediate language instruction to load a string into memory/evaluation stack. As you can see from the output of this command, it only list strings from our .NET assembly including sensitive data like connection string, user name, password, etc.
One common mechanism widely used to protect intellectual property and hard-coded secrets is by obfuscating your assembly. Most commercial obfuscation tools not only make .NET code less human-readable but they also provide options like encrypting string types. Figure 4 below demonstrates the same ILDASM command when run against an obfuscated assembly with strings been encrypted.
Figure 4: ILDASM for searching string data types in an obfuscated .NET Assembly
I would like to point out that assembly obfuscated and string encryption by no means a perfect solution. It does provide some protection against casual user, however, a determined user with reasonable skillset and enough time in hand can crack though many defense mechanisms.
Secrets Leakage during Runtime
What we have seen so far are "static" attacks performed against .NET assemblies. String data types are also vulnerable to secret leaks during runtime. What it means is that at runtime a hacker can attach a debugger and inspects data stored within these string data types. Let's take a look at how this type of attack could be performed. I will use Windbg for this demo. Windbg is a native debugger that could also be used to debug managed application with the help of extensions DLLs. Windbg is part of "Debugging Tools for Windows" and could be downloaded from here.
Let's take a look at how string secrets can be inspected at runtime. When you launch the demo application, a login screen appears. I have simplified a couple of things in this demo application to make things easy to follow. For instance, typically a password type field you don't see the characters that user is typing (rather just display a * for each character). Another simplification I did is by displaying a message box when user hits OK button. In a real-life application, typically clicking on OK button takes users to a new screen. I have used this method to simplify the process of attaching windbg to a running process. There are ways of setting breakpoint in Windbg also. You can read one way of setting breakpoint my blog here.
The figure below shows the login screen from demo.
Figure 5: Login Screen
When you hit OK, a dialog will appear showing that login has failed. At this point, launch windbg and attach it to the running process. For this, you have to choose "Attach to a Process" menu option under File as shown below:
Figure 6: Attach to a Process menu option
Next, you will get the following dialog box to select the running process that you want to attach.
Figure 7: Attach to a Process Dialog
At this point, we would like to take a peek at .NET managed heap and inspect string data type instances. There are various ways of doing it. I will simply use !strings
command to get to it.
Figure 8: Running !strings command
The output of !strings
command could be really long but the values we entered in text boxes for username and password should be visible here as shown below:
Figure 9: Secrets visible at runtime
Microsoft has provided SecureString class that could help provide some protection against these type of attacks. Keep in mind people have found ways of inspecting SecureString
class to determine the actual value of string stored within SecureString
.
Summary
In this article, we discussed why string data types is of particular interest for hackers. We demonstrated some common ways that hackers can use statically and at runtime to discover sensitive information stored in string data types. Hopefully, you will find this information useful the next time you store some secrets within your code.
History
- First version: 16 June 2012
- Second version: 17 June 2012 - Updated images