Ghost in the Shellcode

We ran Ghost in the Shellcode (GitS) from 2010 to 2015. It was one of the earlier Capture the Flag (CTF) hacking competitions. When we launched it, there really were only four other CTFs: DEFCON CTF and Codegate CTF were open to everyone and CSAW CTF and iCTF were academic-oriented.  There may have been others, but this is how I remember it.

Ghost in the Shellcode

Most of us had just won the DEFCON 17 CTF finals as VedaGodz and decided that we too should run a CTF and we'd do it at a conference for a little added prestige. ShmooCon was coming up soon and was the next largest US conference and they didn't have a CTF. Jordan knew Bruce, the founder of the Shmoo Group and the conference. He reached out around Thanksgiving and we were in, they were going to give us a room to host our very own CTF!

(Don't) Panic

ShmooCon happens in January in most years but was in February that year (2010). Which meant we only had about 8 weeks to design and put together a CTF, but we still took a few weeks to start.

First, we had to pick a name. Someone – Jordan? Brandon? Greg? – on the team was watching Ghost in the Shell during the meeting and it was suggested we do a Ghost in the Shell themed game and use the name Ghost in the Shellcode. We didn't have a better name, so we went with it and decided we'd change the theme and name every year.

Next, we had to figure out game dynamics. Were we going to do an attack-defense CTF like the DEFCON CTF finals or are we going to do an attack-only CTF – aka Jeopardy board? We really wanted to do an attack-defense game but time constraints made us go with the Jeopardy board.

Someone volunteered to write the scoring server. Remember, it was 2009, CTFd wouldn't be written or released for another 6 or so years. At the time CSAW CTF handled submissions by having competitors email flags to the organizers.

The rest of us then went and tried to write as many challenges as we could.

However, that person dropped the ball and we didn't have a scoring server with only two days left. Greg and Jay picked up the task – writing the majority of it on the plane and in the hotel room the night before. They decided to write it in Python, which was fairly new to us – most of us only wrote C and maybe a bit of Perl.

class AJAXHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
        def do_GET(self):
                print "GET in thread: %s\n" % (threading.currenThread().getName(),)
                """Serve a GET request."""
                self.encoder = json.JSONEncoder()
                parsed_path = urlparse.urlparse(self.path)
                #parsed_path: (scheme,netloc,path,params,query,fragment)
                #print parsed_path[2]
                if parsed_path[2] == "/ajax/":
                        f = self.send_head()
                        if f:
                                self.copyfile(f, self.wfile)
A small sample of our first score server. This was before flask existed but also we didn't know what we were doing.

I was definitely unhelpful that night. I was sleep-deprived and kept suggesting we go buy golf pencils ✏️ and golf score sheets to let competitors submit flags. Dustin and Andrew were late flying in and were panicked about the lack of scoring server. I definitely got on their nerves with this suggestion.

Sphere Grid

For our scoreboard interface, we went with a "sphere grid" design. We weren't great about sticking to the theme of "Ghost in the Shell" – to this day 12 years later I've never seen an episode. The sphere grid was inspired by one of the Final Fantasy game's tech trees.

The "Sphere Grid" scoreboard

This was another concession we made due to lack of time. We didn't have enough challenges to fill a normal scoreboard. We had too many pwnables and not enough crypto or web challenges – which is an evergreen statement about GitS. We devised this complicated scoreboard where we started in the center of the grid and you could only unlock one or two other challenges – giving us some extra time to write more challenges as the game went on.

We strategically placed harder challenges on junction points to slow the game down. We were terrified of someone unlocking half the game board in the first few hours. Notice in the screenshot above that only about half of the nodes are glowing, we only had 12 challenges for the 21 spots. At the time we lied and said we'd release those "unopened" challenges next year.

Running the game itself was interesting since we were new to ShmooCon – none of us had attended it prior – we didn't know what the conference network situation would be. The game was going to be in person only which made it a little easier. We decided to bring our own network equipment to put up a wireless network and two small Dell Optiplex 960s as our servers. All of us lived in Florida so we had to carry these servers as personal items on the flights. I've brought a few small form factor PCs through TSA and it's always a struggle explaining it's a computer even without a monitor.

Our server infrastructure

There was a problem though. WiFi at the time was 802.11b/g and WEP was the widely supported encryption protocol and deauthorization attacks to sniff everyone's traffic were easily achieved. The Shmoo Group itself published AirSnort, a tool for doing exactly that. Shortly after we made it to the hotel we realized it would be a problem and had to set up our own self-signed CA and cut TLS certs for all the services.

We launched the game on time and had about 15 people playing! The scoreboard broke immediately after the first solution – we had failed to properly map the sphere grid connections. After the first few hours, we were pretty confident the board wouldn't be cleared so we were able to enjoy the conference and socialize with the competitors.

A Historic Mess

Then the snow came. They called it Snowmageddon and it was historic amounts of snow for the DC region. Most of the team grew up in Florida, so it was their first time seeing snow – definitely the first to see so much snow. We stole serving trays from the hotel and used them as (very poor) saucer snow sleds and chucked them into the bushes for the hotel to find them in the spring. Jordan found a couple of people who decided they were going to leave the conference early and drive home to Florida. The rest of us stayed, for what turned out to be an extra week longer as every flight was canceled consistently for that week.

The first year was in the bag and we could switch focus to preparing for DEFCON CTF. We now had two CTF seasons: competing in DEFCON CTF and hosting Ghost in the Shellcode.

Year Two

Most of the 2011 Ghost in the Shellcode organizing team. Not pictured: me.

As you probably guessed, we never changed the name with a new theme. This year the conference was moving to the wonderful Washington Hilton. Heidi, who is the main point of contact for all things ShmooCon, gave us a larger room and even gave us a free ticket to the conference to give away.

We were trying to build a little hype but also wanted to get tickets out to people who wanted to play. ShmooCon is notorious for being difficult to get tickets to – they generally sell out in less than 20 seconds. We thought, "Hey, we can do a mini-competition and host it online to give out the ticket."

We called it the "CTF Warm-up" but in later years changed the name to the teaser. The first teaser was won by awesie, one of the original members of PPP.

For the challenges that year, I had spent a bit of time reversing ddtek's and kenshoto's standard pwnable library and reimplementing it for our own use. It was fun having Visi and Eagle claiming we stole it, but Eagle himself stole it from Visi!

// Service setup functions
int socketListen(unsigned short);
void loop(int fd, int (*childHandler)(int));
int drop_privs_user(const char *user);
int drop_privs(struct passwd *user);
void alarm_handler(int);

// main child handler
int handleConnection(int);

// socket read and write functions
ssize_t sendAll(int, char *, size_t);
ssize_t sendMsg(int, char *);
ssize_t sendMsgf(int, const char *, ...);
ssize_t readAll(int sock, char *buf, size_t len);
ssize_t readUntil(int sock, char *buf, size_t len, char sentinal);
"Our" standard library header

The biggest concern was screwing up process privileges and having a standard wrapper made that far less likely.

I also decided I'd rewrite the score server and introduce a ton of leader board sorting bugs. We fixed them live every year we used that software and then promptly forgot to commit the changes to our SVN server (remember, it was 2011 and git was difficult).

I think 2011 was the year that Jordan and I flew up a little early for some work-related reason and got stuck on the DC Metro under the Potomac for an hour when the metro system lost power. It should have been a sign.

In 2011 they called it "Snowpocalypse"

The competition went off without any issues. It was still an in-person-only CTF. I remember giving away points to a team who brought us donuts.

But the snow started again and it was somehow worse than the year before. Several of our friends got stranded overnight in their cars on the interstates. It was decided that I would rent a car since I had seen snow before in my life – being from the scary northern US. It was less joyous this year as we remembered the prior year. Greg and I ended up driving back to Florida because our flights kept getting canceled again.

Having to create 30 challenges a year can be daunting, so we'd have brainstorming sessions. I found these old challenge ideas from our trac from around this time. Only a few are winners:

  • Something called buffalo overrun.
  • An animated gif where the timeout between frames spells out another
    hint/key. It would have to be an archer gif - is there an archer quote about
  • Something like the ashdoc2.png where they cat'd a wav on the end of a png
    and you could play it by cat'ing it to /dev/dsp
  • I really like the idea of using the Compton lyrics and mac say. say has a
    an option that allows network play, maybe a forensics challenge or something?
    Could use Rick Astley instead.
  • Opcode trivia, six bytes to jump to eax+0x100. (use a different reg?)
  • Dustin's SHA*FUN
  • A bonus points question that gives you complete stack control and requires
    you to ROP. Libc will be moved so they can't ret-to-libc.
  • A challenge that executes the shellcode in a QR code and prints out
    debugging info
  • Wub (dubstep) encoded data - from Dillon
  • pascal strings
  • one's complement
  • The embarrass Jordan contest (get a picture with Jordan where he's super
  • ddtekd, all format strings, ipv6
  • dwarf byte-code

The ROP one is funny in retrospect. ROP was new and exciting at the time.

I had liked the idea of giving people large, unwieldy prizes for winning. Surfboards seemed appropriate, but were logistically difficult. We ended up ordering custom skateboards.

The picture above says we ordered four, but I only remember ordering three. Maybe one fell off a truck? 👀

We had planned to give the winning team three boards, but managed to destroy two of them before we gave them away. The boards were shipped without grip tape on the top side, but the grip tape was included – so we figured we'd afix it. I left them in my office on my office couch. Later, a coworker came in and stacked and moved them so he could sit and ask a question. Stacking them put the Ghost in the Shellcode logos in direct contact with the super coarse grip tape, scratching the decks – only the outer one survived and we awarded it to awesie for winning that year.

Year Three

After two years of flying up with all our infrastructure and having to spend the night before frantically setting it up, we decided to try hosting the competition on Amazon AWS. No one else had tried it yet and we had no idea what it would cost us.

Around this time, I decided I was going to be the treasurer of the team and I started charging yearly membership dues of $100. We had a lot of people who wanted to be part of the team but never actually contributed anything. I thought the dues would make them more serious but in the end, we just had more spending money. The larger budget helped us buy nicer prizes, swag, and pay for the unknown AWS bill.

This was the first big Ghost in the Shellcode as it was the first one where we allowed remote teams to compete. All the biggest teams of the day played: PPP, Eindbazen, EuroNOP, pwningyeti, TracerTea, More Smoked Leet Chicken, 0ld Europe, and others.

We switched the scoreboard away from the sphere grid and had a custom monopoly game commissioned for both the scoreboard and had one printed for the prize.


This year we released one of our best challenges: Khazâd. Khazâd was a 600-point pwnable written in C++ and used exceptions pretty extensively. Khazâd was sneaky, it was only exploitable due to a bug in the DWARF exception handling functions. 0xff did a fantastic write-up that I was able to dig out of the Wayback Machine. 0xff's impression of the competition as a whole was poor but also he's German.

PPP won for the second year in a row – at the time PPP was actually notorious for coming in 2nd place in most of their competitions. They used to joke that they could never win. They probably don't make that joke anymore. I hope they still have the monopoly game somewhere in Pittsburgh.

No massive snowstorms that year – the weather was pretty nice. The AWS bill ended up being somewhere around $100 and that's with a ton of overprovisioning.

Year Four

For 2013, ShmooCon went with a snow theme. I stole this banner and other the ones from other years too – presumably, it's still hanging in Florida.

2012 was an election year so the conference had to move hotels, as the Washington Hilton was unavailable – booked by the Romney transition team for if he had won. We moved to the Hyatt Regency Capitol Hill. The hotel was smaller and we had to share a room – but don't worry, we managed to take over most of the room.

We ran it from the back corner. We also all had matching embroidered GitS hoodies with thumbholes (boo hiss)

For this year's game, we introduced shellcode.tv, a streaming site we used to play distracting videos and some CTF-appropriate music. I wanted to make the scoreboard only accessible via the video stream but was overruled. Not everyone had the connection required to stream our HD distraction. We played all the CTF room classics such as Benny Benassi (1) (2), Die Antwoord (1), deadmau5 (1), and probably an embarrassing amount of dubstep.

The warning we ran at the bottom of shellcode.tv. We were so hip.

A challenge I particularly liked was folly, which I wrote. Folly was a shellcoding challenge with several stages. When you connected you were prompted with a choose your own adventure prompt. Apparently, I was reading Don Quixote at the time because I made it Don Quixote-themed.

$ nc folly.2013.ghostintheshellcode.com 5679
Hola! I am Sancho, who are you?
Don Quixote de la Mancha
Hello! Are you ready for your adventure?
Sire, what should we do?
  (S)earch for your lady love, Dulcinea del Toboso
  (A)ttack Giants
  (M)ount Rocinante

Sire! Let me help you onto your steed.
Sire, what should we do?
  (S)earch for your lady love, Dulcinea del Toboso
  (A)ttack Giants
  (M)ount Rocinante

Just then they came in sight of thirty or forty windmills that rise from that plain.And no sooner did Don Quixote see them that he said to his squire, "Fortune is guiding our affairsbetter than we ourselves could have wished. Do you see over yonder, friend Sancho, thirty or fortyhulking giants? I intend to do battle with them and slay them. With their spoils we shall begin tobe rich for this is a righteous war and the removal of so foul a brood from off the face of the earth is a service God will bless."

"What giants?" asked Sancho Panza.

"Those you see over there," replied his master, "with their long arms. Some of them have arms well nigh two leagues in length."

"Take care, sir," cried Sancho. "Those over there are not giants but windmills. Those things that seem to be their arms are sails which, when they are whirled around by the wind, turn the millstone."

What will you shout as you attack the giants?
Sire, what should we do?
  (S)earch for your lady love, Dulcinea del Toboso
  (A)ttack Giants
  (M)ount Rocinante


The "(A)ttack Giants" option allowed you to send up to 1024 bytes of shellcode that it would execute. The flag was:

There is no book so bad...that it does not have something good in it.

However, our adventure still awaits!


The first flag linked you to the next stage. It was a "the princess is in another castle" challenge. The challenge was 7 stages in total with each being a different architecture: x86, ARM, MIPS, PPC, 68k, ALPHA, and HPPA. Since I'm a miserable bastard I put them all on consecutive ports and added a few repeats at the end so if you scanned them you'd think there were 20 stages.

Year Five

For 2014 we updated the teaser to be a little slicker and made it Grand Theft Auto 5 themed. By 2014 there were a bunch of other CTFs and we were starting to riff on each other's challenges. That year it was hip to make QR code challenges. Codegate did a bunch and PlaidCTF even more in response – in hopes that it would kill QR codes as a challenge. It backfired because we ended up doing our own QR code challenge and naming it after them: Plaid Parliament of Codegate.

I haven't mentioned him yet, but Rusty was a part of Ghost in the Shellcode from the beginning, always producing really solid challenges. Rusty is an annoyingly talented person – he's seemingly good at everything. At the time, Rusty would spend 8 hours at work implementing (still) cutting-edge emulators for software analysis and then go home and spend 8 more hours working on his video game. In 2014, he built Choose your Pwn Adventure 2, a fully hackable 3D FPS.

Choose your Pwn Adventure 2

Pwn Adventure 2 was a 3D FPS built on the Unity engine. It was filled with challenges that were impossible if you played the game straight-up. You had to find and exploit vulnerabilities in the game to complete the challenges. Challenges required you to figure out infinite health hacks, how to fly, speed hacks, and more.

Unbearable: Open the chest before the bears kill you. Also, in the last few minutes, they have had assault rifles.

The Unity engine is written in C#, so you could solve these challenges by decompiling it and patching it. You could also solve it purely with network attacks. For each of the challenges, the server trusted the client a little too much and you had to figure out what you could manipulate to unlock the required superpowers.

Doge was in vogue then

The scoreboard was updated to remove any form of challenge unlocking controls. Half the game board was available only in the context of Pwn Adventure 2, but we had plenty of other challenges.

One notable challenge from that year was ByteSexual. Somehow, we discovered that on Linux you can far call with 0x23 as your CS segment selector value to switch between 32bit and 64bit execution modes. We used this trick to constantly switch between the two execution modes and abusing how the differing instruction decoders to confuse IDA and GDB's disassemblers.

We also updated our shellcode.tv setup to have a slick GitS-themed test card.

Frequency in Megacycles

Year Six

Our sixth year was our biggest year. Rusty had spent much of the previous year working on Choose your Pwn Adventure 3, a completely new iteration of the game. This time it was written in C++ and used the Unreal engine.

PA3: Pwnie Island

Pwn Adventure 3 was a much larger part of the game that year. The bears were back too.

I mentioned previously that we started to make challenges that riffed on the challenges of other competitions – normally PlaidCTF. Plaid had a series of great challenges called "ECE's Revenge", where they would force us to decode some discrete logic circuit to get the flag. For PA3, we had our own version of that called "Blocky's Revenge". In Blocky's Revenge, you had to decode a Minecraft-esc discrete logic circuit to get the flag. LiveOverflow did a video on analyzing it, jump to 66 seconds to see the circuit.

LiveOverflow: Analyzing the Blocky Logic Puzzle

I actually don't remember much about the competition that year. It was really the PA3 show. I was more interested in distracting the competitors who were in the room – I remember playing full episodes of Archer on the projector which would totally DoS half the teams.

Year Seven (Postponed since 2015)

Ghost in the Shellcode never made it to its 7th year. We had intended to continue hosting it but by December 2015 it was pretty clear that we had lost all momentum and we decided to postpone the competition. You can still see the postponement message on the website. There wasn't a single reason why we called it quits, life just moved on. Jay and I had both moved to NYC and it felt kinda odd running a competition associated so strongly with our former employer. Jordan, Peter, and Rusty left to found Vector35 and work on Binary Ninja. I should say, most of us wanted to keep hosting it but we weren't putting in the effort and it would not have been able to maintain the quality we had held ourselves prior.

When I talk about Ghost in the Shellcode these days, I sound like a horrible old man. When we started, CTF was still in its infancy. When we started, the flag files were actually called key, because keys were the secrets we wanted to steal. We also didn't have a standard flag format until much later, it was even slightly controversial internally to suggest we use one.

The biggest change has been CTFs gaining respect. When we started, all the old-school hackers looked down on CTFs as not being real or just being toys. Now, those old-school hackers are still around and grumpy but most of them have begrudgingly admitted that CTFs are a good thing for our industry and develop very real skills.

The CTF industry has evolved a lot in the 12 years since we started Ghost in the Shellcode. I wonder where it goes next.