Showing posts with label Collegiate Cyber Defense Competition. Show all posts
Showing posts with label Collegiate Cyber Defense Competition. Show all posts

Thursday, May 5, 2016

PCDC 2016 RE Challenge Solutions - Part 2

This is a continuation off of my previous post detailing the solutions to the 2016 PCDC reverse engineering challenges 1 and 2. This post will go over the solutions for challenges 3 and 4. If you were a competitor in this year's PCDC competition, you may not have seen all of the RE challenges. Challenges 1 and 2 were made for high school students, challenge 3 was added for college students, and challenge 4 was added for professional day. As a result, only the professionals saw all 4 challenges. This was designed to help balance expected work load during the competition and provide increasing level so difficulty for increasing levels of skill. So let's look at the remaining two challenge solutions.

Challenge 3 - exclusive

Like with all the other challenges, let's run this one and get an idea of what it does.


So this looks a little bit like our previous challenges where we have to give it a valid input and it well tell us if that input is correct and print out the key. Let's open the challenge up in Immunity and take a look. 


After loading the binary and analyzing the modules just like the we did in the previous challenge, we can scroll down and see the instructions responsible for printing out the initial user prompt. We can also see how our input gets read into the program via the call to fgets(). The important thing to note how fgets() gets its parameters. In x86-32 bit assembly on Windows, which is what we are looking at, these parameters are passed on the stack in a standard called CDECL (C declaration). What this means is the PUSH instructions are actually setting up the parameters to the fgets() function. To understand what these parameters are, let's look at this function.

Using MSDN as a resource, we can see that fgets() has the following signature:

char *fgets(char *str, int n, FILE *stream);

What this function is doing is reading in an n byte string, storing it in a memory buffer pointed to by str, and reading the input from the file stream stream. If you look at Immunity, it even tells you which PUSH instruction is responsible for setting up which parameter to the fgets() call and in this case, it tells you it is reading a string of length 0x16 (n = 16 (22.)). Now for our purposes, the important parameter to consider is the address where this user defined input gets stored. If you looked at the link specifying the CDECL calling convention, you'll see that the first parameter listed in the function (char *str) is the last one pushed onto that stack before the call to fgets(). We don't need to understand all the instructions, we just need to see the use of DWORD PTR SS:[EBP-34]. This is going to be a pointer to where our input will be stored. If we look through the disassembly a little more, we should see this address show up again. Specifically in the 0x00401397 - 0x004013CE address range. Before we go any further, lets recap what we know:

- The program expects to get a 'serial number' which it then validates
- The program uses a call to fgets() to read in our input
- Our input is stored at DWORD PTR SS:[EBP-34]
- We see our stored address used within the assembly address range 0x00401397 0x004013CE

Now it's time to verify these. The best way to do this with a debugger is to set break points. At this point, right-click on the address 0x00401397, go down to breakpoints and select toggle. Alternatively, click on the address and press F2 to toggle the breakpoint. This is after we have entered the string to the program and before it looks like it's getting used.  With the breakpoint turned on, our program will halt at that address when execution has gotten there. So with our breakpoint set, let's run the program. This can be done 3 different ways: 1. Press F9, 2. To to the top menu and press the red play button, 3. Go to Debug -> Run. The first thing that will happen is that the program will break at what is called the program entry point. This is basically the API the program exposes to the OS so that the program can start up. There are a lot of steps that go into getting from this point to the break point we set, but we don't care about those at this time. Just press F9 again to continue. Now at this point, you should see the Windows command window. It should be waiting for you to enter in your input. Go ahead and enter is some string into this window like you did the first time you ran this challenge program.



At this point it will look like your program hangs, but this is Immunity pausing it so you can being to dive deeper into the details of what's going on. Let's analyze the following snippet of code:



If we look at the first instruction, we see a CMP to 0x16. Remember from the first post that CMP is used to make comparisons and remember from earlier in this post, that this challenge reads in a 0x16 byte string. Now look at the second instruction, JNB SHORT exclusiv.004013D0. It is a jump instruction to the address 0x004013D0. That target address is interesting, but not as interesting as the instruction before it at address 0x004013CE, a JMP SHORT exclusive.00401397. That's the same address we set our breakpoint at! This is a loop! We compare some counter to 0x22, if it is less than 0x22, continue execution, otherwise, jump. It kind of looks like:

int x = 0;
while (x < 0x16) {
    loop_body();
}

Now we haven't figured out the loop body yet. But let's step through this an instruction at a time by pressing the F7 key and stop when we get to address 0x004013A5, the first XOR instruction. If you're following along with my example and entered in abcd1234 as your string to test, you should see something like this:


Now I've added some circles to draw your attention to a few places. So the instruction we stopped at is XOR EAX, 9C. This means we are performing the XOR operations on whatever value is in the EAX register with the hex value 0x9C. I've circled the EAX register, and we can see the value of 0x61. If you recall, our input string was abcd1234, the hexadecimal value for the ASCII character 'a' is 0x61. Interesting. Let's continue to the next XOR instruction at 0x004013B9.


Again, I've highlighted the value in the EAX register, 0x62 (ASCII value for 'b'), and the other value in the XOR operation is 0xDC. If you continue to step through, you'll see that we jump back to address 0x00401397, and loop through these series of instructions again. When you inspect the EAX register, you'll see the values 0x63 and 0x64 (ASCII 'c' and 'd' respectively). It is indeed our input string. Now, we know we are in a loop. In fact, we wrote out some pseudo-code for it. So let's update it a little:

int x = 0;
while (x < 0x16) {
   input[i] ^ 0x9C;
   input[i+1] ^ 0xDC;
   x++;
}

Hmmm this doesn't seem quite right. So how is our loop being incremented and how to we know our index for our input? Let's looks at the following details:

What we're looking at is how the input string is indexed using the EDX register, and how that register is incremented by 2 every loop iteration. So let's refine our code a little more:

int x = 0;
while (x < 0x16) {
   input[i] ^ 0x9C;
   input[i+1] ^ 0xDC;
   x += 2;
}

Great. Now when we exit our loop, our input has been XOR'ed with the key 0x9CDC. A little further down we see a call to the function memcmp(). Here is the MSDN documentation for that function. What it does is look to see if 2 memory regions contain the same data for a given number of bytes. Again, Immunity has done some work for us and shows us that this memcmp() is using 2 pointers, s1 and s2, and comparing them up to 0x15 (21) bytes. Le't set a breakpoint at address 0x004013DA where memcmp() gets called. So, by looking at the previous instructions and what we learned from the loop we reverse engineered, we see that s2 is the string we entered after it has been XOR'ed. A good way to confirm this is we see that the address of this string got loaded into the EAX register with the instruction at address 0x004013D2. So what we can do is right-click on the EAX register and click Follow in Dump. This will show a hex dump of our data:


And indeed, those are our input bytes after being XOR'ed. Check the first 2 bytes; 0x6162 XOR 0x9CDC = 0xFDBE. So what we are really interested in is the memory contents of the second pointer, s1, being used in the memcmp(). We can find that by doing the same thing we did in the previous step, but with the ECX register. So let's get the contents of that dump.


This this is ultimately our goal. The 0x15 (21) bytes of this memory segment. This is what our input string gets compared to after being XOR'ed against the key 0x9CDC. So now let's update our pseudo-code:

char serial[0x15] = "\xff\xbd\xfa\xb9\xb1\xec\xad\xee\xaf\xe8\xb1\xe9\xaa\xeb\xa4\xe5\xb1\xbe\xf9\xb9\xfa"
char *input = (char *)malloc(0x16);
fgets(input, 0x16, STDIN);

int x = 0;
while (x < 0x16) {
 input[i] ^ 0x9C;
   input[i+1] ^ 0xDC;
   x += 2;
}

if (memcmp(key, input, 0x15) == 0) {
    win();
} else {
    fail();
}

Now, we know this is what happens with the memcmp() function by reading the documentation and seeing the TEST EAX, EAX instruction and seeing successful jumps over the failure messages. So the only thing left to do is solve what the input string is. If you read the documentation on XOR, you know that it is reversible. So all we have to do is XOR our serial we dumped out of memory with the key of 0x9CDC. There are plenty of online tools to do this for you. Once you do it, you'll find that the input should be: cafe-01234-56789-beef. Let's give this a try.



Success!

Password: cafe-01234-56789-beef
Flag: FLAG{XOR_Encryption_Is_Super_Safe!!!}

Challenge 4 - hashbrowns

This challenge was made specifically for the competition on professional day. As such, I'm going to assume a slightly more advanced level of readership. The last challenge solution really went in depth by stepping through the explanation. This solution write-up isn't going to go into as much detail describing how a particular section of code does something. Instead, it will be left up to the reader to figure out all the details.

So let's start by running this program like we did the ones before it.



Ok. So we are given a hash and we have to find the input that matches this hash. So the way we do this is we need to find the hashing algorithm. Opening up the executable in Immunity, we should see the following:


So with this challenge, we see that there are a couple of internal functions with the CALL instructions to addresses within the hashbrowns executable image. Notably, these can be seen at 0x00401442 and 0x00401471. Let's look at the first function starting at address 0x00401310 by right-clicking on the address and choosing the follow option.



I've gone ahead and annotated the interested aspects of this function. The first is that this is a loop and we see a call to strlen() in the loop. This leads us to believe that we are looping through a string for the length of a string. The other interesting pieces of information about this loop are the CMP instructions. We see each of them circled in the above picture and each comparison is to a hex value. The four values, 0x41, 0x5A, 0x61, and 0x7A correspond to the ASCII characters 'A', 'Z', 'a', and 'z' respectively. This loop looks like it is looking for upper and lowercase alphabetical characters. We can further confirm this by analyzing the string argument to the printf() call at 0x00401453, "Found a character I can't hash." This clue would indicate that the program only accepts alphabetical characters. Let's test this hypothesis.


We have confirmed our hypothesis. Let's move onto the next internal function at 0x00401390. Here is a picture of that function.



So again we can see can see we are looping through the length of the string character by character. This is in-fact the function that performs the hashing function. Now, there were a few ways to solve this. The difficult way was to manually reverse engineer the actual algorithm represented by the instructions at addresses 0x004013C3 - 0x004013D7, or, look at the value 0x1505 and do some research on hashing algorithms. If you convert 0x1505 to decimal, you get 5381. A Google search with the keywords hash and 5381 should lead you directly to the DJB2 hashing algorithm. Here is what that algorithm looks like.
unsigned long djb2(unsigned char *str){
        unsigned long hash = 5381;
        int c;
        while (c = *str++)
            hash = ((hash << 5) + hash) + c; 

        return hash;
}

When looking at this algorithm, we see the constant 0x1505 and the shift left 5 (SHL EDX, 5). Now we need to make sure this is actually what were after. Going back to the main part of our challenge, we see the following section of code.


What we see here is a call to our hashing function at 0x00401390 then a series of CMP instructions. Interestingly we see a CMP  to a value of 0x28C7FAE4 which is the hash value the challenge asked us to match. If we look at it a little further, we can see that this CMP instruction calls a JMP to a unique address not jumped to by any other CMP instruction. So these are the pieces we have so far:

  • The input expects a string input that will be hashed
  • That string gets hashed through the DJB2 hashing algorithm
  • The result of the hash must match 0x28C7FAE4
The way to solve this is to write a brute force script that enumerates through alphabetical strings and hashes them using the DJB2 hashing algorithm until a match is found with the value 0x28C7FAE4

This is what the DJB2 algorithm looks like in Python.

def djb2(string):
    hash = 5381
    for x in string:
        hash = (( hash << 5) + hash) + ord(x)
    return hash & 0xFFFFFFFF

The best way to solve this is to actually use a password list. Using the rock-you password list and a python script based on the previous snippet of code, you would have found that the hash value matches the input string of cyberdragoon. Here is the proof.



So here is the summary for RE challenge 4:
Password: cyberdragoon
Flag: FLAG{alls_good_when_the_hashing_is_easy}


Conclusion

I hope this year introduced an interesting new twist on the PCDC injects. If you're interested in working through the challenges on your own, I've put the executables on my GitHub account here. As always, I'm always interested in hearing feedback, so if you have anything you'd like to see improved for next year, don't hesitate to let me know. See you in 2017!





Wednesday, April 15, 2015

South East Regional CCDC 2015 - Red Team

This time last week I wrapped up Red Teaming for the South East regional Collegiate Cyber Defense Competition (SECCDC) for 2015. The SECCDC is special for me for a few reasons. It was my first exposure to the whole CCDC arena, many of my close friends form the Red Team, and the CCDC national champs from last year are from this region.

This year's scenario was similar to last year's. The Blue Teams were responsible for maintaining the operational status of the HAL business network while completing a series of business related injects. The network layout changed a bit from last year, however. This year all the Blue Teams had a few machines that were public facing, and a group of privately networked workstations. The public facing images were comprised of a pfSense software firewall, 2 SuSe Linux boxes, and a Windows 2012 R2 server. The SuSe boxes were used for backup DNS, MySQL database, and the e-commerce web server while the Windows box was primarily performing the normal functions of Domain Controller and primary DNS.

After scanning the networks, we quickly determined that the Blue Teams were running all of their public facing services off of an ESXi server. Additional investigation revealed that the ESXi servers were version 5.5.0 and vulnerable to Heartbleed. This vulnerability became our primary attack vector. By leveraging Heartbleed, we could force the ESXi servers to leak the login credentials in clear-text whenever the Blue Teams logged in. Once gaining root access to the ESXi servers, my goal was to gain access to the domain controller. This is a little tricky when you want to go unnoticed. We were able to jump on a couple of domain controllers that Blue Teams logged into, but left the console open and unattended. The Linux boxes were much easier to compromise. Either they were logged into as root and we could change the password, add users, start SSH, lock the console, and log in remotely, or, we reboot the machine into single user mode, changed the root password, and rebooted. Finally, by leveraging a combination of default credentials and unattended console sessions, we leveraged the pfSense firewalls to lock the Blue Teams out of their networks by turning off the internal interface, but allowed us in via the external interface.

Throughout the course of the competition, the Blue Teams started to slowly kick us out of their networks. This forced us to start getting more creative with our access methods. The first area we looked at was the WordPress site running the e-commerce server. Although we couldn't take advantage of any vulnerable plugins, we could take advantage of the fact that the WordPress configuration let anyone register an account. Now, registering an account in and of itself isn't exciting, but what is exciting, is the fact that WordPress emails you your password. This is important because we had read/write access to the MySQL database backend of WordPress. In the database we could clearly see the administrator's hashed password. Now that we created our own user, we could also see our hashed password in the database. The next step was just receiving the password generated by WordPress. With the Blue Team's network configuration, the WordPress instance couldn't email out to a public email address. But what it could do, was pass the email along to a local Python SMTP server that we controlled. During the user account creation process, we simply specified our email address as 'user@<ipaddress>' rather than providing a public domain name. This worked like a charm. Now that we had a clear-text password and a corresponding WordPress password hash, we leveraged our read/write access to the MySQL database to overwrite the administrator's password hash. Now we could log into the WordPress administrator's account with a password that we knew.

Our other attack vector was actually found by digging through the pfSense source code. For a few of the teams we still had authentication access to the firewalls, but the web administration had been shutoff. It turns out that there is an XML RPC in pfSense. Like I said, we had the username and password, but couldn't turn on the web console and not all the routers had SSH enabled. So we created our own shell. Using the XML RPC and a little PHP voodoo, we pulled down a PHP shell and created our own web console. In most of the Red Team's opinion, this was one of our coolest finds of the event.

One of the largest differences I noticed this year was how a couple of Blue Teams were able to almost completely block out the Red Team. The teams that were quick to correctly configure their routers and whitelists on their ESXi servers removed the largest holes in their network, and their service scores showed it. As a Red Team we really took advantage of Heartbleed and default pfSense credentials. Without those footholds, we weren't able to really do much. Smaller attack surfaces seemed to be a trend for a few of the CCDC regional events this year. My previous blog post talked about how at the Pacific Rim regional, the Red Team really only had 2 targets, and the vulnerabilities were default credentials. This was definitely not the case for South East, but the Red Team definitely noticed a lack of attack surface. I've been talking to a lot of people about some of these observations and we all agree that we want modern systems and network configurations, but how do you open up the attack surface without making it unrealistic?

All in all, I had an absolute blast at SECCDC. I'm already looking forward to next year. I know all the organizers of the SECCDC work incredibly hard to put on this event every year. Their efforts have been noticed and I thank them for all the time and effort they put forth to make this event a reality. And congratulations to UCF for winning a second year and a row! Good luck at Nationals and bring keep the championship in the South East!!

Tuesday, March 31, 2015

Pacific Rim Regional CCDC 2015 - Red Team

A week and a half ago I got to participate in the 2015 Pacific Rim (Pac-Rim) Collegiate Cyber Defense Competition as a member of the Red Team. My more experienced friend Dan has already written a couple of posts about this season's CCDC events (lockboxx) including Pac-Rim. I wanted to use this post not to talk about what I did as a member of the Red Team, but my developing opinions of CCDC and these types of "cyber defense" competitions.

To give context to this post, I'll give a brief description of Pac-Rim's scenario. The Blue Teams were tasked as the IT/Security department of The Center for Disease Control (CDC) while the world experienced a zombie outbreak. While trying the manage their network, they must also address the growing scare of zombies and how that impacted their jobs at the CDC.

As far as network design, the Blue Teams were given an external/public facing network, and a couple of internal networks with varying security levels. From the Red Team perspective we saw 3 primary targets, a VyOS router (VyOS), a Windows 2012 R2 exchange server, and a Fedora 20 web server. Initial scans for vulnerabilities turned up very little. These were pretty modern systems that weren't running a lot of services. Not a lot to attack. The VyOS router did have port forwarding rules set to proxy through connections to servers on the internal network. With this we could see a couple of services beyond the router such as MySQL. For the Red Team, the only way we actually got access to any of these machines was by default credentials.

Leaving default credentials is such a silly thing for Blue Teams to pass up and it is such an easy vector for Red Teams to leverage. Default credentials are usually the very first thing Blue Teams change. That being said, once default credentials have been changed, the Red Team has to be more cunning to find another way into the Blue Team's networks. Unfortunately, for the Pac-Rim event, it seemed that more than half of the teams separated themselves because they changed their passwords quicker than the other teams. I want to focus on this point a little bit more.

When I say that a Blue Team was quicker in changing their default password, I mean they were quicker by a minute, to seconds. This year, we split the Red Team up into cells. Each cell was tasked with attacking a specific Blue Team for the duration of the event. Each cell was to stay in sync with all the other Red Team cells. This sounds like a great concept because it seems very fair. And I agree that it is fair in theory. The issue you run into is the very opening few minutes. This entire event was determined by the first five minutes. The Blue Teams that changed their passwords on the Win2012 Exchange server before their router did better than the students that changed their router's password first. The reason being that the Win2012 Exchange server could be used to pivot all around the internal domain. The router did not provide this type of access. We even had a couple of teams that changed both the router and Exchange server passwords extremely quickly. The result, the Red Team really couldn't do much to them. Now, this isn't meant to be a Red Team sob story. I love when the students lock the Red Team out. That means they are learning, and they are equipped with the skills to make our industry safer. That to me is an amazing thing. The issue I have is that changing 2 default passwords and locking the Red Team out for a day and half is not a learning experience. Further more, since all the Red Team cells are staying in-sync with each other, A Blue Team could get away with leaving a gaping whole in their systems as long as the Red Team cells weren't attacking that particular issue at that time.

The primary point of CCDC is to provide the students with a unique learning experience that they will never get in the class room. At the end of the competition, I got to sit down with the Blue Team I attacked all weekend. They were so full of questions and eager to learn from their experience. The problem was, I couldn't answer all of their questions. Due to a scheduling issue, I had to work alone as a Red Team cell so my focus was extremely stretched. My Blue Team changed their Exchange server password right away and I never got access to it. I only got access to their router and MySQL database. Since most of the Blue Teams' networks was comprised of a majority of Windows systems, I was asked a lot of questions regarding how well they did configuring the workstations, domains, and other Windows related services. Unfortunately I had to tell them that because they changed 1 default password, I wasn't able to give them an accurate perspective. They could have had a terribly configured domain. I wouldn't know. And this was the case for a lot of Blue Teams. They simply didn't get all the feed back that the Red Team could have provided had there been more access.

I go back to the point that CCDC is suppose to be a learning experience. It's hard to find the balance between giving the students unrealistically insecure systems that the Red Team can stomp all over, and modern secure systems where the Red Team still has decent access. I also want to emphasize the point of these competitions is to focus on cyber security. One of my Blue Team members told me that they spent the entire first day (more than 8 hours) dealing with customer phone calls from the Orange Team. What?! Customer service has very little to do with developing cyber security skills. I understand that the Orange Team is there to act as real world customers, but this is a competition. Blue Teams are obviously going to put their best 'people person' on the phone. They probably won't learn anything in terms of how to deal with people and they'll miss out on the actual technical education.

In the end if my Blue Team was able to learn 1 thing, than in my opinion, the experience was worth it. I love doing these types of events as a way to connect with students and provide guidance in a way that it was provided to me. Next week I'll be participating in the South East CCDC regional and my company's own cyber defense competition (PCDC) so I should have a lot more stuff to report on.