This past weekend my fellow coworkers/friends and myself had the opportunity and the privilege to partake in Michigan State's Collegiate Cyber Defense Competition (CCDC). Specifically, we were asked to act as the 'Red Team', which essentially translates into making the student teams' lives as miserable as possible.
I have no idea who this guy is, but he's my hero.
For those that have never heard of CCDC, it is a national competition between teams of students in various colleges around the country, where students spend a day or more acting as network and security administrators of a small, fictional company. Student teams are asked to take a previously created network of systems and secure them against the threats of the world (in this case those threats come in the form of the Red Team), all the while being asked to handle the needs of the business and demands from their fictional users.
Ok, so we're being asked to come in and hack student network essentially. I realized that persistence tends to be half the battle with these competitions. Getting in is easy, but staying on the system while students are actively looking for any hair out of place is not. About two or so weeks before the competition, I resolved to create some custom malware that our team could utilize after compromising a Windows system. This is that story.
For those of you that don't know me, which I suspect is something like 99.9% of the people reading this blog post, I work on the Malware Analysis Team within the SpiderLabs Research group. We typically spend a lot of our time assisting our Forensics counterpart when they discovered malware on a compromised host. As such, I wanted to bring real-world flavor to the malware that I wrote. I've seen a lot of malware used by real criminals, and I wanted the students to get a taste for what that was like. As such, I opted to write a Remote Access Trojan (RAT), which utilized some techniques that I saw in real-world samples. The RAT boiled down to a few components—Delivery, Communication, and Control.
In my mind this is one of the toughest parts. How do we ensure that our malware is going to run continually, even in an environment where the administrators are keeping any eye out for anything suspicious? I decided to split my malware into three distinct parts. The first part would be the 'installer', which would create a new service on the victim host, drop and execute an EXE, and drop and inject a DLL into every running process on the system. This new service would act as a nanny, making sure that the DLL was always injected and that the EXE would always be running. This brings me to the EXE and the DLL. Both of these PE files would be twins, performing the same tasks. I'll get into specifics about what those tasks are in just a minute. Before I get ahead of myself, let's take a look at what this installer is doing in a way that is hopefully easier to understand.
As mentioned previously, the installer follows the following flow:
The installer is configured to run from anywhere, but as a personal preference, I like to drop it in the %WINDOWS%\system32 directory. I did my best to make the service look legitimate by configuring version information in the executable, and populating the necessary fields when creating the service. I attempted to make it look like a Microsoft .NET 4.0 component, as seen by the following screenshots:
Dropping the EXE and DLL is as simply as placing both binaries inside of the installer as resources. This is a pretty common method that we see fairly regularly in malware that drops other files. CFF Explorer does a good job of showing you what I mean.
So how does that DLL injection actually work? Well, there's many options when it comes to DLL injection, but as I wanted to mimic real-world attackers, I decided to go with a method that we see all the time by criminals targeting track data. It's actually a pretty simple process. First, we write the DLL file name that we wish to inject into some process. In the real world, we see attackers overwrite the kernel32 MZ header (specifically the string that tells the user the program cannot be run in DOS mode). Then we find the location of the LoadLibraryA Windows API call inside of that process. At this point it's a simple matter of calling LoadLibraryA with an argument of our DLL filename in the process we're injecting into. A call to CreateRemoteThread accomplishes this for us. This loads our malicious DLL into a remote process in the context of a new thread. And voila!, we're in business. If I've confused you, or you're starting to realize that this post is a tad long and would like a change of scenery for a few minutes, I suggest you go check out SkullSecurity.org, where Ron Bowes does a great job of further explaining this technique. He's even gracious enough to provide some code should you feel like playing with it yourself. You can check it out here: http://www.skullsecurity.org/wiki/index.php/.dll_Injection_and_Patching
Let's take a moment to take a look at the actual RAT that gets dropped on the system. I utilized a global mutex that I aptly named 'thisisnotthedroidyourelookingfor'. This mutex allows me to see if any other RAT instances are running. As my malware is running inside of any process I can get my hands on, as well as the separate EXE that I dropped on the system, you can imagine that this can be a recipe for disaster. Using this mutex, I'm able to ensure that only one instance of my malware is running at once. The beauty of this is that if the students discover, say, my executable, and take steps to clean their system, some other RAT code that is still running will take its place.
Knowing that I've actually got some code running, and that only one instance is running it, I begin my infinite loop where I periodically hit a remote server and process commands. I allowed my RAT to execute the following commands:
- Execute GUI Application
- Execute CLI Application and Exfiltrate Response
- Modify Sleep Interval for RAT
- Upload File Contents
- Create Message Box on Victim
So how does this RAT get commands? How does it upload information? Well I'm glad you asked, because that's what we're going to talk about next.
So I didn't want to be a total jerk to the students. Iwanted them to have a fighting chance should they try and figure out what'sgoing on. This is a learning experience for them (and everyone involvedreally), so I decided to simply stick to good ol' HTTP communication. Nowbefore you start shouting, "But that's too easy!", I did make things a bit moreinteresting.
Every 'X' seconds, the RAT agent hits a webserver that Ispecified. Specifically, the agent attempts to hit http://something/header.png.They use a specially crafted User-Agent, that is formatted like so:
If a person attempts to access this URL without thisformatted User-Agent, or attempts to access any page other than '/login' or'/admin', they are redirected to http://nedry.ytmnd.com (screenshot below forthose that don't feel like enjoying it at this time).
If you do have the correct User-Agent when you try to hit'/header.png', however, you get something different. Specifically, you get apicture of me. I know what you're thinking… both of these options areincredible!
But let's take a look at this PNG a bit more closely. If welook at the actual binary, we'll notice what appears to be a comment towardsthe bottom of the file.
This certainly looks suspicious, and it's clearly got some Base64-encoded text inside of it. If we quickly decode the text, we see the following:
Now, in case you haven't figured it out yet, the first character is used as the command, following by a colon, followed by some argument. Remember those commands the RAT parsed earlier? They translate to the following:
- 'd' - Download/Execute
- 'e' - Execute GUI Application
- 'c' - Execute CLI Application and Exfiltrate Response
- 's' - Modify Sleep Interval for RAT
- 'u' - Upload File Contents
- 'm' - Create Message Box on Victim
The RAT simply looks for the '<!--' and '--!>" delimiters, base64-decodes anything inside, and parses any commands found. Overall pretty simple, yet hopefully some fun for any students that were taking a look at the network traffic. So how am I actually sending out commands to these agents? Doing this stuff by hand would be tedious to say the least. I don't like tedious. So I went ahead and tried to automate the process.
I wrote the RAT code in C++, and while this language is awesome, it's nice to take a break and mix it up. I opted to code my HTTP server in Ruby/Sinatra with a little DataMapper sprinkled in for persistent storage. Being a visual creature, I also threw in a little JQuery to make it look presentable. After having a few beers and deciding I wanted to call my little piece of malware 'Bro RAT', or 'brat' for short, I came up with the following:
I blurred the face so a certain mouse doesn't sue me—Let's call him wreck-it Alph. As mentioned earlier, the User-Agent acts as a sort of identity for every victim. When a command is received, a new 'Victim' is created in the back-end Postgres database, and an 'initial communication received' log is, well, logged. Using this interface, I'm able to send commands that will be parsed one-time, or persist until I tell it otherwise. So if I wanted to, say, spawn an instance of notepad every second, I'd change the sleep value to '1', and then simple send the command 'Download GUI' with an argument of 'notepad.exe' and the persist checkbox checked. Any responses are uploaded via a POST request to '/footer.png', and are both stored in a file as well as displayed to the admin in the Logs section.
Overall the actual competition was a blast. There were a few glitches along the way, but honestly, nothing ever really goes exactly as planned. We started the competition by gaining access to, basically every team's Windows 2003 box and installing my malware on the machines. Of course, being the genius that I am, I forgot to statically compile the DLL that got dropped on the victim boxes. This led to a lovely error message popping up on the machines which notifies the end-user that we're trying to find the Microsoft Visual C++ Runtime, but can't. Woops. This led to me frantically trying to install the necessary DLL that was needed and registering it on the systems. I discovered later on that a couple teams were actually nice enough to install the runtime on their own. Certainly appreciated on my end. Ok, so the malware works (eventually), but I still didn't see any hits from my Internet-based servers. Bit of a head-scratcher. Turns out there was an issue on the network-side of things where the students didn't have Internet access. Eventually it got sorted out, but by then most teams had reverted to a snapshot and cleaned their systems. Not all hope was lost, however, as I ended up getting a couple hits when Internet access was restored.
At this point I was totally ecstatic that all my hard work had paid off, and proceeded to cause some serious havoc on these boxes.
In all seriousness though, it was a great competition, and we had a great time both hacking through the day, but especially talking with the student teams when everything was said and done. I'd like to think that everyone left for their homes that Sunday having learned at least a few things that they'll be able to use throughout their careers.
Ferris State University
, who took first, second, and third place respectively.
Also a big thanks to the organizers (both in Michigan and everywhere this competition is held), as putting the competition together is difficult to say the least. We certainly had a blast helping out, and look forward to next year. Now that I've given away my secrets, I suppose I'll have to come up with something even better next time.