Hacking Stripe’s Capture the Flag
Posted by Tom on November 1st, 2012Note: I wrote this at the end of August, but never posted it. There are some excellent walkthroughs of the levels online.
I finished the “Capture the Flag” hacking event put on by Stripe, an online credit card processor. (It’s not a hugely impressive ranking, but finishing was not a trivial task! About seven thousand people started, I was 549 of 978 finishers.)
It was neat, and I learned a handful of things along the way, most notably a vulnerability in SHA (also, here), and I built a web server in Python. I hadn’t previously done for more than a few lines in Python, so using a new language was a pleasant challenge. (@Stripe: Maybe some Clojure next time? I haven’t used that before either, but I’d like to!) The first levels were pretty easy, and I made it through the first five pretty quickly—it would have been even faster if not for family obligations like dinner and putting the kids in bed. For level 6, the chat rooms really helped out (I started lurking the chat rooms around level 4), and had it not been for the chat rooms pointing to an article on SHA vulnerability and suggesting a look at the level’s log files (which led me to notice another vulnerabilty that had to be leveraged as well), I wouldn’t have made it.
I ended up on the final level before anyone had captured the flag, as one of just over 100 people to get there (at the time). I ended up staying awake all night, somewhat to the detriment of my other projects. By the early morning, around the time there were about 10 people completing the last level, someone was kind enough to connect the dots of what I’d deduced from the code and inferred from the chat room. I knew from the chat room, for example, that I’d need SSH access on a server belonging to the “company”, and had been able to leverage previous hacks to depost my SSH key and gain access, but wasn’t sure yet how to use it.
I finished my code a little while later, and did a first run, and was able to pare down the password space by about 1/3. I was tired though, and not particularly interested in the leaderboard, so I took a long (and much deserved) break. When I came back the next afternoon, there were so many users hammering the server that the port-counting method I used became ineffective. I kept tweaking my code, and eventually switched part of my code to Ruby to make it easier for me to edit/tweak. Ruby’s not my primary langauge either, but I’ve played in it enough—and used Prototype.js, which uses Ruby idioms—that I’m comfortable with basic tasks. Things would have moved faster if the final server had accepted PHP. It was frustrating that it didn’t; the hacked Level 2 didn’t expose the PHP binary to the command line but it executed PHP in the webserver as part of my exploit. (At least, PHP wasn’t in $PATH. As I wrote this, I figured out a way to find the path to the binary, but the servers are now closed so I can’t go back and attempt it.)
Switching to Ruby was, in the long run, I think, a mistake on an over-loaded server. Someone in the chat suggested they were able to significantly improve their success rate by implmeneting a particular piece in C instead of using an interpreted language. I spent some time in XCode and mostly completed the part I needed. At the same time, I was still running my Ruby code in the background, and went through several runs not making any progress because there was so much noise on the server (which was not helped by several users that thought they’d achieve success by port scanning as many servers as they could). I had other things to take care of, and dropped the project for a time, as I wasn’t making any progress.
I tried again the following morning, and there was still a great deal of jitter in the results, and again, I didn’t have time to finish up my C solution. I didn’t touch it at all over the weekend, which turned out to be enough time for the completion list to jump from the dozen or so it had been when I started to more than five hundred. When I checked Monday night, nearly every request was went through fast enough with the Ruby solution that there was no need to switch. (By way of comparision, my first effort was successful in excluding a test only about 2 out of ten tries, while the test run on Monday succeeded more on than 9 out of 10, which made checking the 4,000 tests I needed to run—four sets of 1,000, with each set dependent on the previous one—super easy, and my program runs were completed in a couple of hours of running in the background.)
Update (1 Nov): One of the prizes (the only prize, actually, apart from recognition) was a free T-shirt from Stripe. Mine arrived yesterday. It’s a lightweight, navy shirt, 50/50 cotton from American Apparel, with what seems to be excellent build quality.


