How To Write Code
That Doesn't Suck

wry observations from the deep end of the software cesspool


Stripe CTF, minimalist solution edition

I'd heard of the previous rounds of Stripe's Capture The Flag coding competition but hadn't actually looked into them in detail, but a friend of mine was giving this round a go and so I decided to play along. I had no vision of winning, so to keep the effort time-boxed I went for the minimalist solution that I could envision to each problem. I only made it to level 3 then stalled out, mostly because I'm unfamiliar with Scala and thus implementing my envisioned solution would have required a significant amount of time. I also wasted a significant chunk of time on level 1 (probably more than equal to the time spent coding all the other levels) trying to pull off what I assumed was an invited hack before trying a straightforward solution. Overall I found it a lot of fun and would encourage anyone interested in software to give it a go next time.

level 0

In this level we're given a short ruby script that "highlights" (by adding angle brackets) all of the words in an input text which aren't found in a dictionary. The script works but is slow, as it simply reads the dictionary into an array and does a naive search of that array for each word in the input. My solution was trivial, simply read the dictionary into a hash, and check for a key. Could have just been two changed lines if I bothered to try to remember a terser array to hash technique.

 path = ARGV.length > 0 ? ARGV[0] : '/usr/share/dict/words'
-entries ="\n")
+entries = {}
+File.readlines(path).each do |entry|
+  entries[entry.chomp] = true
 contents = $
 output = contents.gsub(/[^ \n]+/) do |word|
-  if entries.include?(word.downcase)
+  if entries.has_key? word.downcase
 print output

Result scored 117/50 required points.

level 1

On this level I wasted a bunch of time trying a hack rather than coding a solution. The task is to submit a git commit with a hash "lexicographically less than the value contained in the repository's difficulty.txt file". The fact that difficulty.txt was a local file rather than some constant or stored on a server seemed to me to be asking for a hack like submitting a difficulty.txt file with a value like "ffffff" in it. Could not make that work, but would be interested to hear from anyone who did. After giving up on the hack it took about 5 minutes on Google and Stack Overflow to find this utility:

beautify_git_hash: Beautify the Git commit hash! This is a little useless toy inspired by BitCoin's "proof of work" concept. It enables you to modify your Git commit to enforce a certain prefix on the Git commit hash.

I cloned this into my project and tested it by hand to see that it worked. Since this beautifies un-pushed commits via an amend, I changed prepare_index() in miner to do a commit instead of an add, then simply replaced default implementations solve routine with a call to beautify_git_hash. High level loop didn't change at all, so here's the guts of my code:

prepare_index() {
     perl -i -pe 's/($ENV{public_username}: )(\d+)/$1 . ($2+1)/e' LEDGER.txt
     grep -q "$public_username" LEDGER.txt || echo "$public_username: 1" >> LEDG
     git commit LEDGER.txt -m 'Give me a Gitcoin'
 solve() {
     fix=`../ 000000`
     bash -c "$fix"

I fired up the miner and in a couple minutes I'd mined a gitcoin, which gave me a result of 50/50. Didn't have to improve performance of the beautify_git_hash script at all so credit for this win goes to the original author, Volker Grabcsch.

level 2

Hey, finally a node level, how exciting! Well, not really, this turned out to be just a rehash of the level 0. In this level we have to create a proxy that can blacklist attackers based on ip. A full implementation is provided with one key function missing: currently_blacklisted(ip). The obvious implementation proved good enough, with a couple quick tests to figure out the right constant to use to detect a "bad" number of requests.

var blacklist = {};
function currently_blacklisted(ip)
  if (!(ip in blacklist)) blacklist[ip] = 0;
  blacklist[ip] += 1;
  return blacklist[ip] > 4;

This got me a result of 95/85. I actually spent a little more time on this later and was able to get higher scores during local testing, but never got a positive score on submitting them, so I suspect something was borked in the test environment.


Post a Comment