Saturday, June 11, 2016

Solving Crackmes: A Beginner's Guide Using LuCiFeR's Crackme 2 and Hopper Disassembler

Intro

So as some of you guys may know, I now work for NCC Group as a Security Consultant doing web and infrastructure pentesting. This normally means that I don't tend to do very much security work outside of that. Lately however, I have gotten the oppertunity to do some more research, specifically with reverse engineering. One afternoon I wanted to do something interesting, and remembered about the idea of crackme's, or small programs that people create to be reverse engineered.

Crackme's usually have some sort of goal in mind. For example, they may ask you to find a working serial for the program, or to remove an annoying popup that appears every time the program starts. Additionally they may have some restrictions on a proper solution. For example they may also state that you can't patch the program's assembly so that it jumps over the function that displays the nag screen and that instead you must find another way to solve the problem.

After looking around at a few crackme's I eventually found one that I thought would be a good, very easy challenge to start off with: LuCiFeR's Crackme #2. You can find the file at http://crackmes.de/users/lucifer/first_c_crackme/. Alternatively, you can download it here if you don't want to sign up for an account at crackmes.de: https://drive.google.com/file/d/0B5pT4hU_yYUWeXFvS2RLeDhoTWc/view


Tools Used

To solve this crackme, I originally used OllyDBG and BinaryNinja. That being said however, BinaryNinja is currently in beta and after testing it for a while I found I really don't like it's limitations, such as not being able to search for cross references to a string. Because of that, for this tutorial I will be using Hopper Disassembler. You can use the demo version or the paid version for this tutorial, though I will be using the paid version as I have a personal license. To download Hopper Disassembler, simply visit  as well if you want, which is available from http://hopperapp.com/download.html.

Keep in mind the demo version of the application has a 30 minute limitation on sessions and you cannot save your session. This is similar to the free version of IDA Pro with the exception that with IDA Pro's free version does not limit the session's length. If you don't want to pay the £70 for the full version of Hopper and you want longer sessions, but don't mind not being able to save your work, then you can also do this in IDA Pro's free version.


Initial Analysis

To begin our analysis of the crackme, lets first read what the readme.txt file contains:
  • Rules:
  • 1. Do not Patch
  • 2. Sniff a serial for your name
  • 3. write a keygen
Okay, so looks like this is a serial crackme where we have to find the serial to make the program work. Additionally we have also been told that we cannot patch the program to disable any checks, and that we need to write a keygen. For those of you that are not aware, a keygen is a small program, written in whatever language you fancy, that will take in some input, such as a name, or some other input, and generate the correct corresponding output, such as a serial, for a given crackme.

With that in mind, lets run the crackme and see what we have:

 

Okay so we have a few things to note here. The first thing is that the program displays a menu. We should note this down as we may want to look through the program's strings in a disassembler and see if we can find any cross references to these strings in memory. This will then allow us to determine the corresponding function that prints the program's menu, which will help us start to analyse the program's execution flow.

The other thing to note is that the program seems to be taking in a name and a serial as input. Based on the fact that the error message that is returned says that we have not entered the correct serial, it seems reasonable to make a guess that the program could be taking in the name as input into some sort of serial generation function. The serial that the user enters is then checked against the output from this function, and if the serials do not match, the program displays an error message and terminates.

Now that we have done an initial analysis of the program and it's functionality, lets load it up into Hopper and examine it. Drag the executable into Hopper and accept the defaults to load it as a Windows PE file. Once Hopper has finished it's analysis, you should see something like the following:

 

You may not be able to see it above, but Hopper has dumped us at the program's entry point, which it has helpfully denoted as the function EntryPoint. On the left we can see a whole bunch of functions, however none of them seem to have any helpful names.

There's a few ways to solve this issue, but the way I like to do it is by looking at the program's strings. To do this, click on the button on the upper left next to the Labels button labeled Strings:

 

Hey, would you look at that! There's several strings which appear to be from the program's menu. Lets see if we can find which function they are being used in. To do this, first double click on one of the strings that were printed within the menu. You should see something like the following:



If you look to the left here, you can see hopper has helpfully provided several XREFs for each of the strings to let us know where they are being used. As you can see in the screenshot above, it seems like function sub_4014e2 is using all of these strings. Lets see if we can't examine this further. To examine the cross references for a particular string, single click on the string from the listing shown above (any one will do :) ), and then hit the x button on your keyboard:

 

Ok, now in addition to the location of the cross reference, we can also see the specific instruction that references the particular string we chose to examine. To go to the corresponding function, simply hit the Go To button. This should give us the following:



Looking at the assembly, we can see there are several strings which appear to be loaded into the variables var_424 and var_428 before the function sub_431fe0 is called, presumably to print the string out to the screen. Lets rename these variables and the function to make it easier to read the disassembly.

For starters, lets rename sub_431fe0 to print_buffer_to_screen. To do this, click on the function sub_431fe0 within the disassembly, then hit the n button to rename the function:

 

If we look at sub_432880, we notice that it seems to be being called every time that the program expects input. We can assume that this function grabs the user's input and saves it to a buffer, so lets rename this function to grab_input_into_buffer. When we are done we should get something like the following:



The next thing we want to do is analyse what is being done with our input. To do this we need to focus on the calls to grab_input_into_buffer. Lets take a look at them:

 

What we can see here is that EAX appears to be loaded with the location of a variable in memory (this is done via the LEA instruction). In the first call, this is var_108, whilst in the second call this is var_208. This address is then placed into var_424, which appears to serve as a pointer to the buffer in memory where our input should be stored. Following this we see that for both calls, var_428 is passed the parameter 0x437510 prior to the call to grab_input_to_buffer. Combining this all together and using Hopper's helpful comments in green on the side, we can determine that var_428 is the first argument to grab_input_to_buffer, which contains the stream number to grab the user's input from. The second parameter is var_424, which contains a pointer to the buffer in memory where the user's input is to be stored. This allows grab_input_to_buffer to effectively grab the user's input and store it in memory.

Finally, if we look just after the second call to grab_input_to_buffer, we can see a call to j_strlen along with the parameter EAX, which appears to be loaded with the address of var_108, or the buffer where our name was stored earlier. Lets see what the program does once it has calculated the length of the name that we inputted into the program:

 

First, the program loads the result of the strlen call from EAX into EDX at 0x00401676. We then go ahead and multiply EDX by 0x875cd, storing the result in EDX (the first parameter to IMUL is where to store the result, the second one is what to multiply 0x875cd by :)  ). Once that is done, we move 0x51eb851f to EAX, and then execute mul edx.

What is important to note at this point is that the mul instruction multiplies EAX by the parameter provided and stores the result in EDX:EAX. That is, the higher 32 bits of the result are stored in EDX, whilst the lower 32 bits of the result are stored in EAX.

With this in mind, the next instruction, MOV EAX, EDX stores the higher 32 bits of the result into EAX. The instruction SHR EAX, 0x5 then shifts EAX right 5, which is equivalent to dividing by 2 ^ 5, or 32.

Once this is done we multiply the result by 0xfffffc90 and store it in EAX. Keep in mind that any result over 32 bits will be dropped at this point. In other words if we end up getting a 42 bit number as the result of the multiplication, the first 10 bits would be dropped and only the last 32 bits would be saved in EAX.

Next we move 0x0 into EDX and push the values of EDX and EAX onto the stack. I do not know why this occurs as it does not impact anything and the values are not POP'd off the stack at any point.

Following this, the instructions at 0x00401697 to 0x004016aa do some instructions with floating point numbers. We'll get into this with OllyDBG in a bit but for now just now that there is a seperate stack which is used for floating point numbers and these instructions use that stack to adjust our calculated serial somewhat.

If we look at 0x004016ae to 0x004016bf we can see that we load the string "%i-x019871" into var_42C and the address of var_308 into var_430. These are then used as the first and second arguments respectively for the call to j_sprintf, which seems to save the serial that we should have entered into var_308.

Finally, we have a call to j_strcmp which compares two pointers to string buffers to see if their contents are the same or not. The first argument points to var_208, which holds the serial that we entered into the program. The second argument points to var_308, which holds the serial that we should have entered. The program then jumps to a goodboy or badboy message according to whether or not these two buffers matched or not.


Initial Overview of Crackme Algorithum

At this point we can determine the algorithum works as follows:
  1. The program calculates the length of the user's name.
  2. This is then multiplied by 0x875cd.
  3. The result of this operation is then multiplied by 0x51eb851f and the higher 32 bits of the result are saved.
  4. Bit-shift this number right 5 bits, effectively dividing by 32.
  5. Multiply this value by 0xfffffc90
To figure out the final part of the algorithum (so we can generate a working solution) we need to turn to OllyDBG.


Using OllyDBG to Solve the Floating Point Instructions Issue

With a understanding of most of the crackme's algorithum, we now turn to OllyDBG to understand the floating point instructions and how they change the final serial that is generated.

To speed things up a bit, first set a breakpoint at the address 0x00401623, which is hit after the first part of the menu is printed out. If we scroll down we should see the same disassembly as in Hopper, with the first floating point instruction occuring at 0x00401697 after the PUSH EDX and PUSH EAX instructions. Let's put a breakpoint here so we can examine things further, and press F9 to continue the program. We enter in our name, and our serial, pressing F9 to continue the program as needed before eventually we hit the breakpoint:

 

The next instruction, FILD QWORD PTR SS:[ESP] loads a QWORD, or a 64 bit number, from the location pointed at by ESP, and puts it onto the FPU (Floating Point Unit) stack. This can be seen in the following screenshot. Notice that ESP holds the value 0xFE8BC1A0 while ESP+4 holds the value 0x00000000. As we are reading a 64 bit value into the FPU stack, we read both of these values (a 32 bit, or DWORD read would just read the value at ESP, 16 bit, or WORD read, the SP register, etc etc):



An important point to note here is that the value 0xFE8BC1A0 is the value calculated from the first 5 steps of the algorithum that we have examined so far. Moving on though, we can see that the MM7 register of the FPU stack has now been changed to hold the value 0x000000000FE8BC1A.

The next instruction, LEA ESP, [ESP+8] loads the address of ESP+8, which holds the name that I entered into the program (in this case "Grant"), into ESP. This effectively moves the stack pointer so that it now points at our name on the stack.

The instruction FSTP QWORD PTR SS:[LOCAL.260] pops the QWORD value 0x000000000FE8BC1A off of the FPU stack and writes it to the local variable LOCAL.260. If we look closer at the information provided by OllyDBG, we can see that LOCAL.260 is the address 0x0063FB30. Following this in the dump (right click on the address in the information display and click Follow in Dump) shows that the memory is currently empty:

 

We can also see that OllyDBG tells us that the float value 4270571936.0000000000 will be written into memory at this address. Pressing F7 to do a single step in OllyDBG, we can see that the memory has been adjusted, though not quite in the way we expected:

 

Whats happened here? Well, this took me a bit of research and I had to look at some previous answers to understand what happened here, but apparently the FSTP instruction, when converting the number 0x000000000FE8BC1A to floating point number, or 4270571936.0, also packed the number into binary format before storing it in memory. Reversing the bytes, this means that the number is now stored as 0x41EFD17834000000 at 0x0063FB30 in memory.

The next two instructions FLD QWORD PTR SS:[LOCAL.260] and FSTP QWORD PTR SS:[ESP+8] first load the value of LOCAL.260, which is now 0x41EFD17834000000, onto the FPU stack, and then POP that value off of the FPU stack and write it to ESP+8.

MOV DWORD PTR SS:[ESP+4],00401469 moves the string "%i-x019871" into ESP+4, and the following two instructions LEA EAX,[LOCAL.194] and MOV DWORD PTR SS:[ESP],EAX load the address of LOCAL.194 into EAX and push it as the first argument. We then see a call to sprintf with these three parameters. From this we can conclude that we are sprinting the resulting serial into memory at LOCAL.194, and that the string "%i-x019871" is the format string to print into memory, whilst LOCAL.260 is the value that will replace the "%i" part of the format string before it is placed into memory.


Final Crackme Algorithum

From this, we now have our crackme algorithum. We also know that the generated number is appended with the string "-x019871". Our new algorithum now looks as follows:
  1. Calculates the length of the user's name.
  2. Multiply this number by 0x875cd.
  3. Take the result of this operation, multiply it by 0x51eb851f and take the higher 32 bits of the result.
  4. Bit-shift this number right 5 bits, effectively dividing by 32.
  5. Multiply the resulting value by 0xfffffc90, and store only the lower 32 bits as the result.
  6. Take this value in hex and convert it to a floating point decimal number, then pack the result in binary format.
  7. Convert the number back to an integer, and append the string "-x019871" to it.

The Keygen

The last part of the challenge asked one to generate a keygen for the program. This is a small program which takes the algorithum mentioned above and generates a serial based on the name entered. I will leave this as an exercise for you to complete, however if you would like to see my poorly annotated, hacky solution, you can find it here: https://drive.google.com/file/d/0B5pT4hU_yYUWMnBfVTllaHNrMWc/view?usp=sharing

Conclusion

I hope you enjoyed this tutorial and it inspired you to get into crackmes more :) I appologise if it was overly detailed in places but I wanted to make as many people could follow along as possible. Let me know if you have any comments or feedback!

-tekwizz123







Saturday, February 20, 2016

An Update and Some Tips and Tricks I Picked Up

Intro

Quick note before I start this, but I am writing this at 12:36 am my time so please excuse any spelling mistakes etc you may find :)

Some Lessons

Its been a long time since I've last done a post on this blog and I think enough has changed in my life that I aught to discuss some of the things that have occured. For those of you not already aware, since I last updated by blog I finished my studies as a Junior Security Consultant at NCC Group and have now graduated to a full time security consultant. As a result of this I've been busy bouncing back and forth between various jobs for several of NCC Group's clients, an experience that has proven to be both interesting and unexpected in a number of different ways.

In particular, one of the things that suprised me the most was how different everyone's experience is when it comes to performing professional pentration tests. Whilst my internship at MWR Infosecurity exposed me to this somewhat, its become much more apparent over the last few months that there are a wide range of skillsets within the infosec industry and that it really is quite impossible to master every single one of them, or even truely gain indepth knowledge of a few of them, without actual experience working with those products. There is simply too much to learn within a single field of security. As thus I've found that many people tend to choose one main area of study that they want to truely master and then another 2 or 3 additional areas that they try to remain knowledgeable about. This is just my experience though an in no way should act as a delimter to stop someone from trying to learn as many feilds as they feel comfortable taking on.

Another thing that I've come to realise more about is the role of certifications these days. Many people I've met have repeatly noted that they are not comfortable with the idea of certifications within the security community, and having done some jobs for NCC Group, I can honestly say that I understand why this is the case. Whilst I have done several security certifications such as OSCP and OSCE in the past, and they have no doubt help build the basics in my mind, until you are actually put on the job and have to learn things by yourself. Several concepts, tips, and tricks I've only learnt through actually getting hands on with training labs and real world client engagements where one has to come up with solutions to various problems on the fly. While most of you who probably read this blog already know this is the case, you'd be suprise to know that some of the people I've worked with still don't realise the crucial need to self learn or ask for help in these situations. If you don't know how to Google your problem, your going to have a bad time and your just wasting your time, your clients time, and the companies time.

Finally, I  found it really odd how many pentesters I've met from various companies whilst working who don't know how to program. Understandably, some pentesters may feel that they don't need to learn programming as most of their job consists of running tools that others have programmed and then interpreting the output to report to the client. Unfortunetly, without a proper understanding of programming, one will not understand the true underlying nature of a lot of security issues that he/she reports, which will hamper one's ability to explain the true impact of a bug on the client's systems.

Future Plans - Defcon, Exploit Development Stuff, Misfortune Cookie, etc

With all this aside, I wanted to say that this year I will be planning to attend Defcon 24 this year and will be self funding a trip down to Las Vegas to come see all you guys in the USA :) If your in the area or planning to attend, feel free to give me a shout; it would be great to meet up with all of you!

Some of you guys have also been asking why I haven't been updating the blog with any stuff reguarding exploit development. The thing is that while I am still working on exploit development from time to time (its not so easy doing it inbetween jobs), a lot of it is still either a work in progress, or covered by company NDA agreements, so I can't really discuss a lot of it. That being said, if you are interested in some of the work that I have done recently, feel free to take a look at https://www.nccgroup.trust/globalassets/our-research/uk/whitepapers/2015/10/porting-the-misfortune-cookie-exploit-whitepaperpdf/ for one of my whitepapers I did on porting the Misfortune Cookie exploit to support more target routers. Unfortunetly due to the company's policy on exploits, I am prohibited from releasing any of these exploits publicly or too many screenshots on the whole process, however the whitepaper tries to provide an overview of the process and the problems that I encountered as best as I could.

I've actually had a lot of thoughts about how I plan to continue to develop my skills in the future. One of my concerns is the combination of pentesting and exploit development burning me out in the long haul, however at the same time I realise theres a certain point where this thought is just dragging me down and preventing me from doing anything useful. To that extent I am planning to try go through The C Programming Language 2nd Edition by Brian W. Kernighan and the late Dennis M.Ritche to recover C programming basics and ensure that I don't have any gaps in my knowledge as I feel there are some areas that might need reinforcing. I'm hoping to then go through The Shellcoder's Handbook Second Edition as I really need to go through some of the basics in that book such as heap overflows, fuzzing and format string bugs.

Conclusion

With all that being said, I'm very happy to be working with NCC Group at the moment and I hope to try and update this blog some more in the foreseeable future if it is at all possible, however the main thing I wanted to get across here is that because of NDA's and work life, I may end up posting less on this blog than normal. Hopefully though, I will be publishing some whitepapers and technical articles though NCC Group and I'll likely be notifying you guys of any updates on that side of things through my blog or Twitter.

Until the next update, keep learning guys :)

- Grant