Monday, May 15, 2017

DBIR Puzzle 2017 Writeup

"I wan-na be the ve-ry best..."

This was my second year playing the DBIR puzzle. I almost didn't notice the DBIR's release this year, because I had been in a company hackathon all week and wasn't paying attention to the news. I caught wind of the game on Thursday afternoon and played it late into the night. Luckily I had Friday off  (thanks Manny!), so I had plenty of time to attack the puzzle without distractions from work, which gave me a definite advantage.

Trailheads, False Starts, and Lucky Numbers

The cover art for this year's DBIR was tarot-themed. I immediately spotted something out of place - the "Il Papa" (The Pope) card had the string "OFXPB" on it in tiny letters. This had to be the trailhead.

I Googled "OFXPB" and ended up in a very deep rabbit hole of Twitter accounts, Wix sites and Soundcloud pages that turned out to be completely unrelated to the DBIR puzzle. At first I was really impressed; the DBIR puzzle team had written a really detailed ARG for us this year! But the deeper I dug in, the more I came to realize that the people and stories involved were way too real, and the content got more and more inappropriate for a Verizon-sponsored puzzle game. After about 2 hours without finding anything that looked like the puzzles I've come to expect from the DBIR cover puzzle, I decided to start again from square one. I'm fairly sure I wasn't the only person to fall down this rabbit hole, based on what I saw on Twitter.

So, back to square one. "OFXPB" is the Atbash cipher transform of "LUCKY", which I determined by feeding it to the cipher tools. Also hidden in the cover is two lines of text:


It looked like base64-encoded text. It WAS base64-encoded text! Some of it was unprintable, but the start was readable: "Salted__". It turns out that this is the start of an OpenSSL-encrypted file where a salt has been used. In order to decode it, I would need to determine which encryption algorithm and which key were used. The obvious first guess would be that one of LUCKY, lucky, OFXPB, or ofxpb are our key. None of them worked. I would have to actually read the DBIR (gasp) in order to find what I was looking for.
I found it on page 38 of the DBIR:

Of course, this report can only inform the reader of the trends
we observe and not actually foretell your entire future.
However, our data does indicate that 7, 29 and 60 are your
lucky numbers, and you will find love and riches on Flag Day.

Since the cover of the report showed a fortune teller using tarot cards to predict the future, and "LUCKY" was enciphered on the cover... maybe the key was made up of our lucky numbers? I spent some wasted minutes trying to include all the bits of that hint - numbers for love and riches in different numerology systems, and the day and month of Flag Day, but those were dead ends. Eventually I figured out it was just the digits, and that aes-256-cbc was the correct algorithm (lucky guess on the first try!):

> openssl aes-256-cbc -d -base64 -salt -k 72960 -in file.enc -out file.dec


This led me to, which was the main page for this year's DBIR puzzle.

Breachemon Training and Map Hacking

So what was our theme for this year?

You have found the preeminent SEIM for training and battling breachemon. Analysts, pen testers, and CISSPs alike battle it out to capture enough breachemon to be named the breachemon champion trainer!
Our chief breachemon necrologist, Ulga, have identified 10 types of breachemon:
  • Espionage
  • Crimeware
  • DoS (Denial of Service)
  • Misuse
  • Errors
  • Skimmers
  • PoS (Point of Sale)
  • Physical
  • Web App
  • EE
The first trainer to email proof of capturing at least eight of the ten breachemon to SEIM Leader will be crowned breachemon champion! Don't stop though. It's ok to not be the very best. (And frankly you'll never be the best there ever was.) Battle it out for second and third place as well!

The game asked us to pick a Trainer name, then directed us to a Google Map with the locations of the Breachemon to be caught. Scrolling through the map, we could click on each Breachemon and get a description with a hint on how to catch it by solving the puzzle. This would give us a Breachemon Key to enter for credit. There were only the 10 Breachemon types listed on the page, and a handful of Breachemon names in each type.
As I solved more of the puzzles, I found that some Breachemon seemed harder to locate on the map than others; in other words, some were "rare" Breachemon. I wanted a faster way to get all the puzzles, and luckily it wasn't hard to do so. Viewing the source of gave me all the puzzles in one place and saved me a lot of hunting and zooming in and out on the map. The companion files /js/breachemon_to_puzzle.json and /js/breachemon.js would come in handy for determining which of the puzzle categories I'd solved.

"Who's That Breachemon?" (The puzzles)


Espionage breachemon commonly invovled credentials. The key to capturing them is knowing just how many attack with credentials (either by brute force or through theft). It is said an online corpus of breaches exists where this could be looked up.

Since this is Verizon's puzzle, "an online corpus of breaches" is obviously the VERIS dataset, at I downloaded the whole thing. The answer to the puzzle is the number of cases in VERIS where the "motive" field is "Espionage" and the "variety" field is either "Brute force" or "Use of stolen creds". Reviewing the verisc-labels.json file on the VERIS Github helped make the determination of which values to look for. I wrote a VERY hacky Python script to parse the JSON files and count the matching cases:

import os
import json


for filename in os.listdir(filepath):
                if filename.endswith('.json'):

                                if j['actor']['external']['motive'] and 'Espionage'in j['actor']['external']['motive']:                             if j['action']['hacking']['variety'] and 'Brute force' in j['action']['hacking']['variety']or 'Use of stolen creds' in j['action']['hacking']['variety']:

print count

This gave me the answer 106.

Crimeware  (Unsolved)

If it were our call, (and it is), we'd recommended you read up on how to catch this water breachemon.

The link points to a pic of a Samsung Gusto 2 flip phone. The background shows the scene from Caddyshack where Judge Elihu Smails waves off Al Czervik's boat before it slows and drops an anchor on his. The file name, 132-5235776773.jpg, and the "call" hint made me think I needed to either call a phone number (not out of the question since last year's puzzles had us do this) or use the number pad on the phone to spell out an answer.  Sadly, I wasn't able to complete it. Of the two I didn't complete,  I feel I was closer to solving this one.

Denial of Service

We have collected statistics on a wide range of breachemon. They can be found here.
The key to catching this breachemon is identifying the median weight (to the hundredth, rounded up), of female specimens with a weight to height ratio greater than 20 and KQS and PZB tags, but not PAO.

This provided file at is a huge zipped .csv file. Instead of trying to work with it in Excel, I decided to use some python-fu to parse through it.

specimen_id gender weight height tags
0 male 43.49855484 3.34362631 SBZPNBDUF


Most of the fields were comma-separated as you'd expect. The tags, it turned out, were all in the same string. I initially thought that the presence of a given tag in the string was independent of position, but through trial and error I realized that each tag took up three letters, and were meant to be cut apart and checked independently.

import numpy
while True:
  if not l:
  num, gender,weight, height, tags=l.split(',')
  #assuming the tags are in groups of 3 letters sequentially and not in arbitrary locations in the tags string...
  taglist=[l[i:i+n] for i in range(0, len(l), n)]
  if "KQS" in taglist and "PZB" in taglist and not "PAO" in taglist:
    ratio=numpy.float64(weight)/(numpy.float64(height)) #note - many sites want you to square the height, but this was wrong
    if ratio>20:
print median

The raw answer from the calculation was 47.4374246138. Rounding this up to the hundreds place gave the answer 47.44.

Privilege Misuse

The key to catching this breachemon is the shortest distance from specimen 65 to specimen 840, (to the nearest hundredth, rounded down). The map of where the specimens are can be found here.

The link,, contained a sizable Excel file with two sheets - one with the location of each specimen, and one with the links between them. I recognized this immediately as a graph theory "shortest path" problem. I downloaded the NetworkX module for Python, which I'd read about but never used, and set to work hacking together some code. Since the puzzle asked for the "shortest distance", I assumed correctly that I needed to calculate the distance for each edge of the graph and use that as the weight of the edge when calculating the shortest path.
I split the pages of the xlsx into two csv files so I could import them into NetworkX, and threw together MORE hacky code. I had some trouble with the csv files and had to jump through some encoding hoops to read them; I'm sure there was a "right" way to get the data from .xlsx to .csv but I was in a hurry:

import networkx as nx
import codecs
import numpy


#dealing with conversion troubles from Excel export'nodes.csv',"r", "utf-8-sig")'edges.csv',"r", "utf-8-sig")

#first build a dict of nodes and locations
for l in f.readlines():
  name, x, y=l.split(',')
  G.add_node(name, x=x, y=y )

#then build the graph, calculating the weight of each edge
for m in g.readlines():
  (x1, y1)=nodes[start]
  (x2, y2)=nodes[end]


print nx.shortest_path_length(G,source=u'65',target=u'840', weight='weight')

I spent FOREVER with a typo in the code - instead of starting point '65' I had starting point '6'. Oooops. When I fixed that, I got the right answer, 28.77

Miscellaneous Errors

The key to catching this breachemon is the counter clockwise numeric sequence, starting with 1 and ending in the middle, of the circles when placed such that all pip colors are aligned.

The link pointed to a picture of a colorful set of wheels:
It looked to me like it was a real, physical puzzle in the photo, so I started Googling to see if I could find the rules. I found one:
Since it was a real puzzle, I guessed that there would be a writeup on how to solve one, and I was correct: This version of the answer used letters instead of numbers, so I had to map the letters to the numbers in the puzzle photo:
By the rules of that solution, I got the correct answer  1637542.

Payment Card Skimmers

It is rumored this breachemon type was created by a mad scientist at Mr. Figgis's PI company.  The key to catching them is in his New York Kastle, on the wall outside his lab.

Sometimes wasting time pays off - I understood the hint immediately. "Mr. Figgis' PI company" is The Figgis Agency, which appeared in the last season of the FX TV show Archer. The mad scientist in question is Dr. Algernop Krieger, and searching for his New York Kastle gets you:
The page instructs you to telnet to When you do this, an ASCII movie starts playing.

 In one of the opening scenes, a wall hanging that says "MODERN ART!" appears before panning to the door to Krieger's lab.Therefore the answer is modernart.

Point of Sale

You just have to call this breachemon!

The hint links to . Playing it in Audacity, I heard a voice saying "You get over here right now!", but I quickly learned this wasn't the clue. I pondered taking those words and their length to spell a phone number, which wasn't right (too short) and I tried correcting the spelling of "breachymon" to "breachemon", but that didn't get me anywhere. I also cracked open the file in a hex editor, looking for hidden messages or metadata.

Finally, in Audacity, I noticed that there were two audio channels, but one appeared to be blank. On a hunch, I muted the audible channel and cranked up the sound on the "silent" one, and heard "Here, breachy breachy!" This gave me herebreachybreachy as the correct answer.

Lost and Stolen Assets (Unsolved)

We used to know the key to catching these breachemon, but someone dropped it on the floor and broke it.
The linked image,, shows a number of Tetris-like puzzle pieces with letters. The image also includes the covers two previous DBIRs, which suggested the solution was similar to previous years' puzzles.
I remembered the "fun time" I'd had when solving last year's variant on the Haberdasher's Puzzle, so I left this one for last. Luckily, I didn't have to solve it, because I solved 8 other puzzles.

Web Applications

We had to write down the instructions on how to catch this breachemon.
The puzzle pointed to, which told us:
We had to write down the key to capturing this breachemon. And we wanted keep it secure, so we encrypted it. But darnit, we forgot the how to decrypt it! If you can figure out how to open it, it's yours!
The linked PDF file at was password protected. 
The page itself showed thumbnails of four images. I loaded these into the Tineye image search engine (and failing that, Google Image Search) to get some context. It turns out they're thumbnails for music videos: - REM - "Man on the Moon" - - - Steve Earle- "Ben McCulloch" - - Talking Heads - "Road to Nowhere" - - Ryan Adams + Jello Biafra - "Moon over Marin"  - 

Inspecting the source of the page showed there was a fifth hidden image, with its display dimensions set to 0 px by 0 px: - The Beatles (song unknown)

I started noticing common threads in the song titles - Moon, Man, Nowhere, Road. Maybe the shared words in the titles suggested how to combine them to solve the puzzle.
The filenames also suggested which song I needed in each case.
For example, the Steve Earle song was named CoP.png, even though the thumbnail images was for the song  "Ben McCulloch". Steve Earle has a song called "Nowhere Road", but "Copperhead Road" fit the filename pattern much better.
Similarly, I didn't have a video to match with the Beatles, but MAN suggested "Nowhere Man", which fit the theme.

Remembering last year's DNA Puzzle (Dr. Pedro Tipton) I tried to align the titles so their shared words lines up vertically:
Copperhead Road
                     Road to Nowhere
                              Nowhere Man
                                           Man on the Moon
                                                            Moon over Marin
This gave me "Copperhead Road To Nowhere Man On The Moon Over Marin".
Then I took the image filenames in that order. CoP+RTN+MAN+OThM+MARIN

The password CoPRTNMANOThMMARIN unlocks the PDF, which gives you the answer MOOSE AND SQUIRREL. (The game also accepts the lowercase "moose and squirrel")

Everything Else

We started to puzzle out the key to catching this breachemon, but then abandoned it like yesterday's newspaper.
The link points to , which is an intimidating filename. The image shows a number of circular icons:
  They are laid out in a grid of 9 rows by 9 columns. Given the key words "puzzle" and "newspaper" from the puzzle description, and my knowledge of puzzles, I surmised that this is a Sudoku puzzle (which frequently appear in American newspapers). Typically Sudoku uses the numerals 1 through 9 for its symbols, but you can use any symbols. Here, the symbols are from the DBIR sections on incident classification patterns.

In order, they are:
1) Crimeware (orange, mask)
2) Cyber-Espionage (dark green, sleuth)
3) Denial of Service (light purple, wave)
4) Insider and Privilege Misuse (dark yellow, sheet of paper)
5) Miscellaneous errors (baby blue, letter in trash)
6) Payment Card Skimmers (light green, hand with card)
7) Point of Sale Intrusions (brown, hand with dollar signs)
8) Physical Theft and Loss (dark purple, hand)
9) Web Application Attacks (light brown, globe+arrow)
The icon for the Everything Else category is not used.

I translated these into digits, giving them the value associated with the order in which their section appears in the DBIR, and then fed them into an online Sudoku solver. In the solution, the spot which contains the text "# of incidents found here" was a 5, which mapped back to Miscellaneous Errors. On page 38 of the DBIR, the table shows that 2478 incidents happened in this category in this year. This gives us the answer 2478.
(In hindsight, I probably could have just tried all the values on page 38 for the 10 categories to solve this faster.)


I spent all of Friday working on the puzzles, forsaking everything but coffee, which the substance from which all life flows. When I'd solved 8 puzzles, I expected to unlock some kind of meta-puzzle or final round, which is how the 2016 DBIR Puzzle endgame worked. When nothing happened, I double-checked all of my answers, and then sent an email to with those answers just to see if I really was done.  I think I surprised the puzzlemasters this year, because Gabe asked me to show my work; thankfully I'd learned to do the write-ups as I solved the puzzles, so I wouldn't miss anything and have to re-solve later. :) A few minutes later, I got an email notification that I'd won, and then the glory tweet:

This year's puzzles seemed a little easier to me than last year's, and I was a little disappointed there wasn't a meta-puzzle at the end, but I all in all I really enjoyed playing this year. I hope to be back next year to defend my title, unless I get invited to the secret puzzlemasters club and get the honor of writing the puzzles for next year. It could happen!

Thanks to the whole DBIR team for putting together a challenging and fun puzzle (and, oh yes, the exceptional report as well) Congratulations to @darkstructures for coming in second place, and to the unnamed third place winner as well - best of luck to you both, and to everyone, for next year's puzzle!