An eager group of us met up Saturday at 1 pm — Alex, Colin, Jay, Jeremy, Mak, Richard, and I (Ron). Armed with junk food and piles of computer gear, we set out on our quest: to capture all the flags!
The clock ticked. It hit 1:00. Nothing yet. 1:01, 1:02, and finally at 1:03 the first challenges were up! Mak started decrypting them while the rest of us waited. Slowly, we started getting the puzzles. A PCAP of a SSH session for Forensics, a C program that said "U MAD?" for Bin-Pwn, a bunch of encrypted data for Crypto, and an obscure Hackers reference for Grab-Bag.
An hour of derping later, and all we could wonder is what we had gotten ourselves into. As we were working, other teams were completing challenges, and we were falling behind. What's going on? Are we that derpy!? New challenges were unlocking — a bitmap with faded text for Forensics, a network service for Bin-Pwn that was a calculator, and a photo of a crazy breadboard for Grab-Bag. And there we sat, still derping.
Grab-Bag 100: Hackers
Eventually, Richard realized that the obscure Hackers reference meant we had to watch the movie and find the scene where they showed the Garbage File. So he and Mak fired up Netflix, and spent a half-hour jumping around looking for the two frames in which the hex dump of the file showed the address we needed. First flag: DEFEATED! 100 points! w00t! High fives all around!
Things were looking good! Let's get our hopes up so we can really feel it good when we fail!
Forensics 100: Beep beeeeeep beep
Next up, the SSH session. After a bunch of screwing around looking for any kind of data leakage, we started looking at the SSH traffic. Nothing jumped out, and we didn't even have the handshake so we didn't know how it was encrypted. WAT DO?
Eventually, the challenge coordinators released a hint: "This challenge could just as easily be RSH". Wait, what? SSH is encrypted, RSH is not. Hmm! That led me to start thinking of covert channels. We started looking at the packets' metadata, but didn't see anything interesting. Alex points out that there are large and odd gaps in the ssh traffic, like eight second gaps once in awhile. We opened a timing graph, and I said, "This is modulated.", and we were right. A horrified look crossed Mak's face as we all came to the realization: it's Morse code. With SSH packets. Wow.
So, we decoded it, and sure enough, it was a flag. FLAG 2! There was much rejoicing, and the best high five I've ever had with Mak. I swear we were breaking atomic bonds between our hands... [Editor's Note: I still have flashbacks and phantom pains as a result.]
By that time, it was 8 or 9 pm. We were in the middle of the pack and going strong. But I'm not gonna lie, the rest of the night/morning is a bit of a blur, fuelled by junk food and sugar, so I'm just going to hit on the high points, to the best of my recollection, in vaguely chronological order.
Bin-Pwn 300: Please don't ask me about Bin-Pwn 300
Bin-Pwn 300. Oh God, Bin-Pwn 300. It was a Linux binary that was running on their server. It became quickly obvious that you had to exploit it, but despite reversing the whole damn thing, I couldn't find the issue. I'm supposed to be good at that stuff! Sadly, I'm not so good at Linux debugging/hacking, so it slipped through the cracks despite spending all night on it. Sadfaec. :(
Luckily, I'm not the only one with a nemesis! Forensics 200. You can see the look of horror on Mak's face just by mentioning it. When I brought it up in the SkullSpace meeting, he publicly threatened to stab me in the face. It's just that good!
Forensics 200: Please ask Mak about Forensics 200
Forensics 200 was a BMP image.The hint noted "This file is big 54 + PixelArraySize." That's it. We already knew from the previous level, the Morse code, that there would be something hidden in some insane manner. Looking closely, we could see that there was some text somewhat superimposed on the image. Mak wrote a Ruby script that would take the original BMP as input and output a directory full of mangled BMPs with the same pixel data, but with a different height and width declared. Alex ran the script and eventually identified the text as "BITCHES BITCHES EVERYWHERE". Surprisingly quickly, Mak, in the supercomputer he calls a brain, realized that the bytes were encoded funny, and that there was likely some stenography on the pixel data in there, causing the strange colouring. He threw together another Ruby script, and before long had pulled out the least-significant nibble (4-bit value) from each byte of pixel data to form a new file. And guess what? IT WAS ANOTHER IMAGE!
That image, Mak eventually realized after some nudging from Mark, had extra data after the pixel data. It was a 7zip archive! By midnight, we had the 7zip archive. By 1pm the next day, we still had the 7zip archive. It turns out, the password was stego-encoded in the second BMP in a way that we never did figure out. We still don't understand it now that another team has explained it to us. It was a sad time...
At some point pizza showed up. I don't eat pizza, but I also had a box of oranges, triscuits, bunny-shaped graham crackers, chips, dip, guacamole, bagels, ... well, let's just say I had a lot of food. Also a couple bottles of Kambucha. I love that stuff!
Anyway, on to other flags. Did I mention I worked on Bin-Pwn 300 all night? I'm still upset with that.
Bin-Pwn 100: U MAD?
Other flags... oh yeah, Bin-Pwn 100. Jay, poor Jay, spent far too much time chasing a white rabbit on that one. See, they had a weird combination of whitespace in each line: tabs and spaces. We tried all sorts of stego techniques, but no luck.Let me back up. The level was a simple .c file that used a copy of libjpeg.a to generate an image saying "U MAD?" — the answer was, of course, "Yes, fuck off." At least, it was by the end of the night.
So anyway, Jay was playing with the whitespace in various ways and getting nowhere. He also tried to compile it against a system version of libjpeg.a and hash the output images... they were identical. So no hidden features in libjpeg.a. WAT DO?
That's when Alex took a look. Or maybe it was later, things are kinda hazy. Alex opened up libjpeg.a as an archive (and that night, I learned that .a files are just collections of .o files — who knew?) and discovered a .jpeg file embedded. That's not right! The jpeg file, however, had a corrupted header. But, once he took the header from the original "U MAD?" .jpeg file and stuck it on the new one, it displayed a key above the text. We no longer mad, bro!
At some point that night, Ian and Marcella showed up and took some pictures. They are here. It was cool to see some friendly faces in the middle of the night. Actually, a lot of people stopped by here and there to help and cheer us on.
Bin-Pwn 200: 1 + 1 = 2
Bin-Pwn 200 was, basically, a calculator. You netcat to their server on a given port and it lets you enter two numbers and an operator. Those values are combined and the result is printed. That's it. What the fuzzle!?This is where Jay saved us. He discovered that whitespace was handled wrong. If you added spaces, multiple numbers were used. For example, "1 1 1", "+", "2 2" would wind up as "7". How do? He quickly realized that he was looking at a Lisp-based evaluator. At that point, he had to leave.
Mak and Nick, a remote teammate, took over and started looking at this puzzle. They eventually figured out which Lisp dialect it is, and used these things they called "lambdas" to do all the magic: listing files, reading them, etc. With that, they managed to read "flag.txt" in the calculator's working directory and get the flag. BOOM!
I remember the sun coming up. Sunday was a beautiful day, I think. I pulled my car around without putting on a jacket. The sun felt nice after 24 hours in a chair...
Bin-Pwn 400: Hutlh ghItlh pIqaD
If we couldn't get Bin-Pwn 300, how the heck were we supposed to get Bin-Pwn 400!? Who knows, but we tried anyway!Once again, we were given a server and a port. But this time, we also had a username. The server was called "alien-server" or something. It was a SSH server, and we didn't have a password. Okay... so we need to break SSH? LAME!
After poking around a bit, Alex remembered that he had to send a SSH public key to the organizers to register our team for the contest. Aha! Sure enough, we logged in, expecting a shell. As the famous Chuck Testa would say, nope!
We logged in, and the server starts saying weird things. It starts by saying "loS", then waiting ten seconds, followed by other gibberish. I love me some ciphers, so I thought this might be fun! For fun, Alex Googled one of the phrases. We found an English-Klingon dictionary. Yup, it's Klingon. We bashed our heads trying to figure out what to type, but all it would respond with is "bad message" or something.
Nick discovered that the Klingon letter 'ch' could be used to read a file. But only a couple files were available, specifically, the files that were the source of the shell itself.
Once we had access to the files, Nick and I started working on how to exploit the system. Eventually we realized that we could get the system to interpret (or JIT compile, more likely) arbitrary C++ code by using a bunch of weird Klingon commands. I managed to write a file-reader to read flag.txt, and boom! We had another flag! I woke up Mak to high five him. It was a good time.
Shortly after that, I realized I couldn't stay vertical anymore so I laid down. I remember the voices fading out, the coldness, and then waking up with an arm covered in drool. An hour or two of sleep will do that. I woke up to cheering and high fives...
Grab-Bag 300: Duckrolled
I, probably fortunately, slept through this level. It was JavaScript code that, through a combination of nested packing, syntax errors, obfuscation, and duckrolling — was very annoying to decode.Here's how I understand it happening: I went to sleep, Mark and Mak starting typing and pointing excitedly at the screen, then I was being woken up for high fives. It was a great level, at least for me. I wish they'd solve more like that. [Editor's Note: I wish you'd snore less. (-:|3]
By the time I woke up, I realized I was mostly useless and instead of continuing to bash my head, I started cleaning up and taking out the garbage. That way, when the clock ran out, I could go straight home and get some more, much needed, sleep...
Grab-Bag 200: Blinkenlights
Now, if there's one thing I don't know — and believe me, there are a ton of one things I don't know — it's circuit diagrams. And, worse yet, pictures of breadboards with unknown ICs.Once this level unlocked, we had a bunch of people looking at it. Andrew, Ben, Justin, Richard, and more. There were LEDs and wires and chips and resisters and stuff, and they had to figure out which LEDs would go on, I assume. What else do LEDs do, really?
After a couple hints from the organizers, including an extra image of the contraption from a new angle so that the wiring was actually visible, and working on it for the entire night, Richard figured it out, and we captured our sixth flag. This put us into tenth place overall, but unfortunately we lost a position in the last forty-five minutes of the contest.
And that's a wrap!
And that was the end. Six flags, eleventh place, and maybe six hours of sleep between the four of us who stayed the night (Alex, Mak, Richard, and I). It was intense!Personally, I had a great time, and based on feedback from the others, so did they. As I said, we derped the hell outta the contest, but considering we got eleventh place with only four consistently present members on our team, that's darn good.
If I did it again, what would I do differently?
- I'd get more sleep. I realize I burnt myself out. I bet I could have done better with a proper sleep.
- Next, I'd try to get together a bigger group, and sleep/work in shifts.
- I'd also like more space to work, and scratch paper.
- I'd also like to suck less at debugging Linux applications.
If you're interested in helping out with other CTF challenges, email me, ron at skullsecurity.net, and let me know! I'll add you to our mailing list and we'll let you know when we plan to do our next time.