Hey everyone, thanks for checking out this post. For those unable to tell from the title, this post is targeted towards my USB Security Application, and hacking it.
Details of activities
Goal: To extract the Encryption/Decryption key from the application.
It should be noted that as this application is for educational purposes, the key itself has been hard-coded into the code. Meaning, extracting it is a goal that will lead to thinking of ways to try and further improve the security of these keys.
- Sysinternals Suite (strings.exe): Used to extract strings and study what contents were taken out. The reason for doing this is to see how much of it is bare to someone looking to see the inner workings of the application.
- netshrink: A .net packer for executables that obfuscates strings and makes the string extraction mostly pointless as it becomes unreadable at that point. There are some things that can still be determined from an obfuscated executable however.
- hiew (Demo version): Used to study the hex dump of the strings and see how different they are from the packed version to the normal one.
- ILSpy: A free .net disassembler that is able to disassemble the executable and compile it into C# code for reading. This can help to determine the flow of the program, but also give valuable information about it.
Step 1: Strings and Hex Dump
Using both strings.exe and Hiew, I was able to extract the strings, dump them to a text file as well as view a hex dump of the two executables. One was the normal version, while the other was the packed version. The following photos show the difference.
The various functions used by the program can be observed on the right of the screenshot above. The content to the left just after the colons are the hex values of the individual ascii characters defining the strings of various function names, and messages within the program. The values to the left of the colons are virtual memory addresses. The main point here is that the strings can be read in clear text. When using strings.exe, this can be saved to an external text file for an even easier viewing of the strings.
It should be noted, that the actual encryption and decryption key (composed of IV (Initialization Vector) and the key itself), are not found in there.
The difference should stick out as the text from the above screenshot seems nothing more than gurgled nonsense here. The virtual memory addresses are also different from what we see in the original executable. From my understanding, what packing the executable does is that it compresses the original file, but adds in decompression code on top of it while the strings are scrambled in the compression process. What we see as strings in the packed executable are simply what’s read from the file, rather than first it being decompressed and then reading.
The decompression should occur when the file is actually executed, however as we will see later on, that did not exactly happen.
What did doing all of this exactly achieve?
The point was to answer my curiosity of what will be seen between a packed and a non-packed executable file. It was also to determine if I could see the encryption/decryption key.
Step 2: Disassembling the Executables
Normally software like IDA Pro is considered an industry standard. However, I opted to use something more specifically built for .net. This led me to ILSpy. It’s streamlined interface was also very helpful in being able to see how much is exactly extracted from the executables.
First, lets see what happens when I try the packed version:
The PEFile properties themselves are not supported. This leads me to believe that the disassembler is not able to decompress it and look into the actual code. It could be that, or it could also ultimately be the fact that it simply was not packed properly, potentially corrupting the PEFile properties.
Lets see what happens when I try the normal version:
As evidenced by the picture, we can see all the functions in the program. These are also accessible, and as I had expected, the code is readable clear as day. In fact, to get the encryption/decryption key, all one would have to do is attach this disassembler to the executable, and they will get all the information they want about the program.
That’s how simple it really was. Just take the original executable, and hook it up to the disassembler to see the C# code inside. Now this would be a different story had the packed version been actually disassembled, I doubt we would have seen much information of use. As I mentioned, I did not try IDA Pro on this, it is possible that we could still get some form of assembly out of the packed version, as with the original to, which could help make some sense of what is happening under the hood of the application.
But with this, the goal was accomplished, and quite easily so. This leaves serious concerns for the practices I have employed with the key storage if this were to be an actual production application. However, I do have an idea on how to resolve this which will be covered in the conclusion section.
Executing the Two Files
Before I said in the step 1 section that the packed file did not execute as expected. The following screenshots should shed some light on the matter.
When I try to execute the packed version, an error would pop up as shown in the screenshot below. But when I execute the original file, the program works just fine.
In this error, we are told that we are missing a .dll file. It is very well possible that the packed file is looking for a different run-time version than what is currently available on the machine at the moment.
Doing further research would indicate that to be the case as the dll file “msvcr71d” itself is a C Run-time library. It is also the debug version of msvcr71.dll (the added d to the end after 71 indicates debugging). Downloading and moving this file into the proper location should theoretically resolve this issue. I will make an update to this post should I get the chance to test this idea.
This happens for both the 32 bit and 64 bit versions of the file.
The goal was to figure out the encryption/decryption key as someone without any knowledge about the program. Some techniques that were tried were to see a hex dump and strings extraction of the various executables. One was the original .exe file, while the second was a packed version to see what difference it would make.
While the difference was obvious in the hex dump and the strings, it created for issues when it came to executing the packed version. But the most interesting bit was the disassembler as it was able to extract every bit of code in-tact from the original file. Where as it struggle with the packed version, possibly because it could not decompress it and then peer inside to the C# code, or perhaps the compression was not done well, potentially corrupting the file’s PE properties.
Now, since I was able to get the encryption/decryption key out, it meant that I met the end goal of this particular exercise. The important bit is how can we exactly secure this, so that even if someone were to get a hold of the code, they can’t easily figure out the encryption/decryption key.
Change the way encryption/decryption is handled. Rather than having a preset hard-coded key, a key is dynamically generated every time the user asks for one. The key will then be requested of the user any time they want to encrypt or decrypt the contents. Keeping the key safe will be the responsibility of the user.
What this does is that it ensures that even if someone manages to get the password, or brute-force their way into the application, they won’t have access to the key itself which is integral to the whole operation. The only way to obtain the key would be to either social engineer the key holder, obtain any physical or logical file that may store such data, or in a more complicated method, install a keylogger onto the victim’s system and send data to the attacking machine either through a back door or through other means. This dramatically decreases the chances of someone figuring out the possibility of decrypting a user’s data.
The flow of events for this proposed solution would be as follows:
- User wants to create an encryption/decryption key.
- The user inputs in a password that they selected at the beginning when they first ran the program.
- The program then randomly generates an encryption/decryption key that is composed of:
- Lower/Upper letters
- Special Characters
- The user will then be asked to input that key in every time they wish to encrypt or decrypt the data. Should they want to change keys periodically, they are free to generate more. BUT, the right keys must be used when decrypting the data. The key that encrypted it must be used to decrypt it as well, otherwise it won’t work as you will have the wrong key to the lock.
How the key is kept safe is up to the user at that point. They can either memorize it, write it down or type it out into a file.
So I suppose the next step would be to actually figure out an algorithm behind the random key generator and implement this process. Then also refine the application further, but at the same time, see how else it can be broken through either the use of process injection, potentially creating/using rootkits (if I’m feeling adventurous) or as I had mentioned before, keyloggers. We can build one in python, and see the type of data come to us through either the creation of a backdoor or sending it over the network via email.
If there are any updates to be made in the future to this post, they will come down here…