16 Apr 2017
The Collegiate Cyber Defense Competition (CCDC) is often mentioned in discussions about security education. Specifically, there’s been a good amount of debate on the value of the competition and what students learn by participating. After competing at NCCDC this past weekend and wrapping up my final CCDC season, I’d like to share some thoughts I have about the competition and its value in education and the security community. Please note that this post represents my thoughts and opinions as an individual, and not necessarily those of my team or institution.
At the beginning of my Junior year in the CSEC program at RIT, I had gotten my feet wet learning about information security, and I wanted to dive into the forefront of the security community and quickly climb the learning curve of security education. I was learning about web and systems security through various online resources, and wanted to exercise those skills in a competitive environment to test myself and learn from others.
My school competes in CCDC and is a regular contender at the national competition, so when tryouts came around, I applied for a web security role within the team. Soon after, I joined the team specializing in web security and took on the additional role of managing injects (business tasks assigned to teams during the competition). This allowed me to leverage and build upon my soft skills as well as my technical skills.
Practicing for and competing in CCDC over the coming months taught me a great deal about OS internals and how systems interact with one another. I became comfortable operating in both Windows and Linux environments, and learned to dig deep into either system to hunt for red team malware and rootkits. I also learned to backtrace red team attacks to identify and remediate the root causes of compromise.
Competing in CCDC allowed me the opportunity to meet tons of great people in the security space who are involved in the competition – everyone from red teamers to white teamers to other students. After each competition, the red teamers do an individual debrief with each team to address what the team did well and what they could improve on. This is paramount for learning from the competition and improving for future iterations.
Many internships and full-time jobs are found from CCDC competitions. Participating in CCDC is a great way to demonstrate your interest and dedication in security, which is noticed by sponsors and red teamers looking to expand their teams and hire passionate students.
Many of the complaints raised against CCDC address how the competition is run in a vacuum of sorts. By this, I mean that competitors often need to ‘game the game’ and do things you would never see or do in practice. Winning teams usually end up employing crazy strategies or tactics that are hardly viable in the real world. For example, I’ve heard of teams using embedded devices such as phones or printers as firewalls, and scripting snapshot restores on virtualized systems to avoid red team persistence but just barely pass scoring checks. Teams may also resort to disabling core components or functionality of the operating system in order to reduce attack surface. These strategies are creative and clever, but where do these skills transfer to real-world scenarios and environments?
Historically, the networks that competitors are tasked to defend can contain systems or technologies that are woefully out of date – sometimes being EOL’d more than a decade ago. While these may be present in some networks in reality, it would be more beneficial to learn to use and defend modern systems and technologies rather than legacy systems of yesteryear.
The North Eastern region (NECCDC) is doing a great job at changing this. This year’s regional competition featured a modern network (including development and production clouds complete with load balancers) as well as modern technologies (GitLab, Foreman, and Jenkins). These types of topologies are much more likely to be encountered in the real world, and training and competing within updated infrastructures will better prepare students for things they’ll see on the job.
Is it worth it?
After my first year, I continued to participate in CCDC. This was largely to continue improving my technical skills (OS internals, malware hunting) and my soft skills (teamwork, management, writing). However, I believe there’s a point of diminishing returns for participating in CCDC. After reaching this point, students will only get better at competing in CCDC with little transfer of skills or expertise to the real world. The length of time it takes to reach this point will differ between students, but I do believe it exists whether it takes 4 years or a single season.
CCDC has taught me a lot, and I’m thankful for the opportunities it’s provided me over the years. Overall, I can conclude that participating in CCDC yields a lot of learning and experience, but there’s a point of diminishing returns where these rewards lessen year by year. Students should evaluate whether the competition is worth it for them with respect to the nature of the competition and their prospective career path.
17 Nov 2016
I had a chance to test my reverse engineering skills in FireEye’s Flare-On challenge this year. While I didn’t get very far, I was still able to learn a ton and sharpen my skills for next year. All of the challenges are available on the Flare-On website, so feel free to follow along. With that said, let’s jump
over that function call into the solutions!
Starting off, we’re given a challenge1.exe binary. Running the binary will prompt the user for a password:
Let’s take a closer look at the binary. Loading the challenge into Binary Ninja, we can quickly locate the strings used when comparing the passwords:
Looking at the cross-references to the “Enter password” string, we can jump to the password comparison function. Near the comparison itself, the string “x2dtJEOmyjacxDemx2eczT5cVS9fVUGvWTuZWjuexjRqy24rV29q” is pushed to the stack.
This looks fruitful! Let’s try entering this as the password:
Dang, no dice! Let’s use a debugger to see what’s actually being compared. By setting a breakpoint on the function called just before the comparison, then entering the password “test”, we see the string “aDSwaZ==” is passed to the function instead of our original input.
The double equals sign on the end of the string is a dead giveaway for a base64-encoded string. It looks like the program is base64-encoding our input, then comparing it to the comparison string (x2dtJEOmyjacxDemx2eczT5cVS9fVUGvWTuZWjuexjRqy24rV29q). If we base64-decode the comparision string, we’ll know the correct input to enter. Using a base64 decoder, let’s see what our comparison value decodes to:
Huh, that doesn’t look right. There’s a lot of bytes outside the ASCII byte range. It looks like there’s something fishy going on here…
To understand what’s going on, I needed to do a bit of research about base64. I was looking at an example implementation of a base64 algorithm when I saw the following line of code:
private static final String CODES = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
This looks like an alphabet that’s designed to be easily changed. Curious, I scrolled up on the page and found the following information:
The particular set of 64 characters chosen to represent the 64 place-values for the base varies between implementations. The general strategy is to choose 64 characters that are both members of a subset common to most encodings, and also printable.
So it looks like this alphabet is changeable! Going back to the strings in the binary, we can quickly identify a 64-character value that looks like another alphabet:
A quick Google search reveals a tool that can perform base64 encodings with alternative alphabets for us. Entering the custom alphabet we just found and our comparison string returns [email protected] as output. This looks like our flag! Let’s give it a try:
Sweet! Entering the password on the Flare-On website moves us on to the next challenge.
The next challenge is aptly named DudeLocker.exe, with an included BusinessPapers.doc that appears to be encrypted. Upon inspecting the binary in Binja, we can see there are several initial checks that must be passed.
The first of which involves a call to SHGetFolderPath, which retrieves the paths of special system folders and returns 0 if the operation was successful.
The 2nd parameter being passed to SHGetFolderPath (the 4th value pushed to the stack), 0x10, is a CSIDL value identifying the folder being retrieved. A quick lookup reveals CSIDL 0x10 corresponds to the user’s desktop directory. So, this function attempt will grab the path of the desktop, and the program will continue if the operation was successful.
The next block checks if the length of our retrieved desktop path is less than or equal to 0xf8, or 248 in decimal. If so, the program continues; otherwise, it returns.
Afterwards, we see a block with a call to CreateFile at the end. CreateFile, according to MSDN, “creates or opens a file or I/O device”. Despite its name, the I/O devices it works with are not limited to files; it also works with file streams, directories, physical disks, volumes, etc. The function takes the name of the I/O device as a parameter (the last value pushed to the stack), followed by 6 additional parameters describing the device’s attributes.
The filename parameter (var_244) is constructed earlier in the block. We see it’s being passed to sub_401000 along with var_44c, which contains our desktop path from earlier, and var_3c, which contains the string “Briefcase”. The subroutine will concatenate “\Briefcase” to our desktop path, which is then used in the CreateFile call.
So CreateFile will attempt to open an I/O device located on our desktop named Briefcase. For more information, let’s take a look at the additional parameters. dwDesiredAccess is set to 0x80000000 (GENERIC_READ), dwShareMode is set to 0x1 (FILE_SHARE_READ), lpSecurityAttributes is set to 0, dwCreationDisposition is set to 0x3 (OPEN_EXISTING), and dwFlagsAndAttributes is set to 0x02000000 (FILE_FLAG_BACKUP_SEMANTICS). There’s an important note alongside FILE_FLAG_BACKUP_SEMANTICS: “You must set this flag to obtain a handle to a directory.”
It looks like CreateFile is attempting to open an existing directory named Briefcase located on our desktop. If this operation fails, an error code of 0xffffffff is returned (INVALID_HANDLE_VALUE), which will print a taunting message and exit the program. Otherwise, we proceed onwards.
The next check lands us in a subroutine that calls GetVolumeInformation to retrieve the serial number of our root (C:) volume. This was deduced by tracing the parameters as we just did above, which is left as an exercise to the reader. The serial number is compared to the value 0x7dab1d35 (“The Dude Abides”) – if they aren’t equal, eax is cleared; otherwise, eax remains.
We need eax != 0 to pass this check, so we’ll have to either change our C volume’s serial number or bypass this check with a debugger. I opted to use the handy VolumeID from Sysinternals to change the volume’s serial. (Did I mention it’s important to work on these in a VM?)
Let’s try running the binary at this point. We’re greeted with a ransom note in the briefcase that rudely replaced my desktop background:
Looks like they want a million Bitcoins. Maybe those business papers will suffice? Let’s drop BusinessPapers.doc in the Briefcase aaaaand…
Dang, still encrypted. However, the Last Modified date on the file changed, so DudeLocker must have done something with it. Taking another look at the binary reveals calls to CryptEncrypt in the program’s Import Address Table:
This makes sense, since our modified BusinessPapers.doc still appears to be encrypted. However, the IAT doesn’t seem to have any entries for a decryption function. Taking a look at CryptEncrypt quickly points us to CryptDecrypt, which uses the same arguments sans dwBufLen at the end. If we could patch the call to CryptEncrypt with a call to CryptDecrypt, we might be able to decrypt the contents of the BusinessPapers!
Let’s take another look at the IAT. The entry for CryptEncrypt is 0x24fa, which refers to an offset in the DudeLocker binary. If we add that to the image base of 0x400000, we get 0x4024fa. Inspecting the binary at 0x04024fa reveals the following:
Hmm, looks like there’s another offset (0x00ba) followed by “CryptEncrypt” in ASCII. To make sense of what we’re looking at, I loaded the Windows DLL containing CryptEncrypt (advapi32.dll) in Dependency Walker and found the exported CryptEncrypt function:
Aha! It looks like 0x00ba was referring to the function’s hint, which contains the index for that function in the DLL’s export table. The hint for CryptDecrypt is 0x00b4. Are you thinking what I’m thinking??
Well, you are now. Patching the IAT allowed us to decrypt the file instead of encrypting it! The file still doesn’t look like a DOC file, but if we open it in a hex editor, we see the initial bytes FF D8 FF E0. A quick Google search reveals that’s the file signature for a JPEG image. Changing the file type from .doc to .jpg reveals our flag:
19 Jun 2016
When I was switching my blog to Jekyll, I needed to convert a few long Word docs to Markdown; one of which being the Web Application Cheat Sheet. Being about web security, the document contained many XSS payloads and other nastiness. It also had a lot of nested bullet points, which would have made conversion by hand a pain. So, I found a promising conversion app called word-to-markdown, dropped in the Word doc, and lo and behold..
Great, should have seen this coming.
It turned out the site was treating the document’s contents as HTML, and thus rendering the content on the right side of the page without HTML-encoding it. This opened up a Reflected XSS vulnerability – albeit not very practical, but still bad nonetheless. Thankfully, the source code was available on GitHub and the developer was very receptive to contributions. I made some quick changes, and after a simple fork and pull request the updated version went live.
The fix was pretty simple – since most people wouldn’t write HTML in a Word doc and expect it to be rendered as such, I HTML-encoded the Markdown after conversion so the document’s contents would show up as regular text and not HTML. Here’s how XSS payloads are rendered now:
05 Jun 2016
Binary Ninja is a new reverse engineering platform with a number of useful tools and features to make the reversing process quicker and easier. I did some experimenting with the beta version this weekend, and got acquainted with its Python API by working through Phase 1 of CMU’s Binary Bomb Lab. The lab has several ‘phases’ that are ‘defused’ by entering the correct input on stdin. If the program receives the wrong input, the bomb explodes and the program terminates. The bomb is defused once all phases have been solved.
This post goes over the steps I took to solve Phase 1 of the lab using the Binary Ninja API. The code is available on GitHub. For reference, here’s how the phase looks in Binary Ninja’s GUI:
Starting out, the binary is loaded and analyzed:
(The sleep function is due to Binary Ninja’s threaded analysis, which currently does not have a way to alert when the analysis is completed)
import sys, time
bv = binaryninja.BinaryViewType["ELF"].open("bomb")
Next, we iterate through the functions to find Phase 1:
# find phase_1
for fn in bv.functions:
if fn.symbol.name == "phase_1":
phase_1 = fn
We then go to the main block in Phase 1. This phase calls a string comparison function that compares the input from stdin to a string stored in memory. We’ll loop through each instruction to find the call to this function (the first and only call instruction in the block) and grab its address:
# loop through instructions in phase_1's main block
for instr in phase_1.low_level_il.basic_blocks:
# get address of string comparison function
if instr.operation == binaryninja.core.LLIL_CALL:
callAddr = instr.address
Now that we have the address of the call, we can grab the parameters being passed to the function. The address of the comparison string is the second parameter being passed.
# get address of comparison string
strAddr = phase_1.get_parameter_at(bv.arch, callAddr, None, 1).value
We now need to find the string length, so we know how far to read into memory to retrieve the comparison string. The string comparison function compares the strings byte-by-byte and does not use a string length parameter, so we’ll find the string length in a similar fashion – reading byte-by-byte until an ending character is reached:
# get the length of comparison string
strLen = 0
curr = bv.read(strAddr, 1).encode('hex')
while (curr != "2e") and (curr != "00"):
strLen += 1
curr = bv.read(strAddr + strLen, 1).encode('hex')
Now that we have the location of the string in memory and know how far to read, we can use a simple call to read the comparison string:
# get the comparison string
cmpStr = bv.read(strAddr, strLen)
Running this program on the bomb lab linked above, the string “Border relations with Canada have never been better” will defuse Phase 1 and take us to the next phase.
01 May 2016
Just a few weeks after red-teaming at Lockdown v0, I had the opportunity to follow up with my second red team experience at IRSeC this weekend! IRSeC (Incident Response Security Competition) is an annual cyber defense competition hosted by RIT’s Competitive Cybersecurity Club. The competition is geared towards beginners, with a focus on the incident response process. Emphasis is placed on how teams react to an intrusion and their ability to identify and report malicious activity.
Red/blue team interaction is crucial during IRSeC, and I was able internalize what I learned at Lockdown to improve as a red-teamer and facilitate a better learning environment overall. Talking things over with blue teams proved once again to be very helpful and important for learning. I picked up some new attacking and persistence techniques in preparation for the event as well.
In reflection, there are some important points to note for future competitions:
- Having a wide variety of persistence mechanisms is important.
When persisting on boxes during the competition, I wanted to use persistence mechanisms that teams would be able to discover due to the beginner nature of the competition. These included creating scheduled tasks, registry items, users, and services. However, some teams were more advanced than others, and were eventually able to detect and remove both the basic and advanced persistence mechanisms I used. It would have been advantageous to include several persistence techniques that are very difficult to discover in order to ensure access to teams after they think they’ve kicked me out.
- Get persistence accomplished right away.
In hindsight, I would have benefited from having a more prepared method of persisting. When teams started to discover my more basic methods of persistence, I was still fighting to establish a foothold on several boxes well into the competition. At that point, I wanted to be focusing on taking down services, exfiltrating PII, and messing with teams a bit. By establishing a wide range of persistence early on, I would have been in a more comfortable position to focus on other red team objectives.
- Be sure to take the entire infrastructure into account.
IRSeC’s network this year included several IP cameras that many red-teamers overlooked until later in the competition. These had really interesting attack vectors, and it would have been cool to get a foothold in them early on to pivot into the rest of the blue teams’ networks.
Overall, IRSeC was an awesome time, and it was great to be able to use what I learned from my previous red team experience just a few weeks later. A huge shout out goes to everyone who helped organize the event and stayed up overnight to make it happen. Looking forward to next year!