TL;DR: Week 6 of the #MagnetWeeklyCTF was the beginning of what I can only hope is a good reverse engineering side quest.
Review
Check out the week 1 blog post for how to get started on the Magnet Weekly CTF.
Get the first challenge
The weekly challenge for week 6 was two parts, both lengthy. The first was:
Hadoop is a complex framework from Apache used to perform distributed processing of large data sets. Like most frameworks, it relies on many dependencies to run smoothly. Fortunately, it’s designed to install all of these dependencies automatically. On the secondary nodes (not the MAIN node) your colleague recollects seeing one particular dependency failed to install correctly. Your task is to find the specific error code that led to this failed dependency installation. [Flag is numeric]
This is getting back into things you learn running Linux as your daily driver for over 15 years, unlike Hadoop questions. The host is running Ubuntu, so we would expect to see the user running apt to install and manage dependencies.
Open the target file(s)
The log files relating to apt can be found in /var/log/apt. In /var/log/apt/history.log you can see the commands run to manage packages, so this was the first stop to find a dependency which did not install. Comparing the three disks, HDFS-Slave2 had errors worth digging in to.
The first error in that file came with a command started at 01:17:04 on November 8, 2017, but we can’t immediately see the error. However, we can examine term.log to see what the user was actually presented with at that time.
Here we can see the error came from trying to install a Java 7 package and that the error was specifically a 404 HTTP error which prevented its download, probably because that is an ancient package. Since the answer wants the numeric code, “404” is the answer for the first part.
Get the second challenge
The second part was:
Don’t panic about the failed dependency installation. A very closely related dependency was installed successfully at some point, which should do the trick. Where did it land? In that folder, compared to its binary neighbors nearby, this particular file seems rather an ELFant. Using the error code from your first task, search for symbols beginning with the same number (HINT: leading 0’s don’t count). There are three in particular whose name share a common word between them. What is the word?
If “ELF” wasn’t a dead giveaway to you, we can translate it into Windows by saying “EXEant” although the impact isn’t the same. ELF stands for “Executable and Linkable Format” and is the standard format for executables on your normal Linux workstation, similar to EXE on Windows. Right away I was hopeful we would be doing some reverse engineering.
Find the wrong place
The first part of the question forces you to find the dependency that was installed. We already saw in the history.log file that oracle-java8-installer was attempted immediately after the failed dependency and term.log shows that jdk-8u151-linux-x64.tar.gz was downloaded to install. This is the first place I went down the wrong rabbit hole, because that file is found in /home/hadoop/temp/, so I thought that was the location they were talking about.
Find the wrong binary
In the same folder as the zip file is an ELF binary named master on the main node, this is the second place I went wrong because the question clearly states that you did not want the main node. But feel free to join me on my journey down the rabbit hole. This binary, however was stripped, meaning you can’t find the names of its symbols, so it can’t be the right answer, but seems funky since it has netcat in it. Immediately above this folder is a binary named 45010 which also looks fairly suspicious. Running strings on it has phrases such as “credentials patched, launching shell…”, so this has to be the binary we are digging in to, right? We will use objdump to take a look at the symbol table, specically with the -t switch.
If you’ve never looked at this output before, the column on the left is the symbol value and the far right column is the symbol name. The problem here is that none of these have 404 in them… anywhere. After much wasted time, I finally convinced myself this wasn’t the right binary, even though it looked shady as all get out and I’d be willing to bet it shows up again later.
Attempt to brute force the answer
You should know by this point that my answer to being in the wrong place would be to brute force the answer. I knew I was looking for an ELF binary, I suspected it should be somewhere near this Java download or the Java installation in usr/local/jdk1.8.0_151 where it ended up, and that it should have symbols which had 404 in it. I strongly suspect the 404 would be in the value, not the name, because of the hint that “leading 0’s don’t count”.
My approach was to chain together a few commands you should be used to and a few new ones. I had all three disk images mounted in /mnt so I went to that directory and ran a find command to list all the files benath it1. Because I wanted to limit what I was looking for, I used grep to limit my search to usr/local. I then piped the output to file and specified that it should read from standard input (-f -). From that, another grep would give us only ELF binaries and then we get to learn a new command.
The output of file has the filename at the start of the line, so I used awk to just print the first field ('{print $1}'), using “:” as the delimiter (-d ':'). This isn’t the best use of awk, cut probably would handle this just fine, but if you don’t know awk, this is a great place to learn as it is very powerful. For example, in other iterations I had awk displaying both the value and the name with '{print $1, $6}'. We then use a while loop to loop over each file, spit out the name, and then use objdump to flag anything with 000404 in it. The result is a nice long output that lets you quickly see which files have potential values and which words are shared by three of them in the same file.
I found the same files I had found earlier and couldn’t find an appropriate word to submit (despite trying many).
Find the right place
Since we’ve exhausted brute force, I re-read the question for the 98th time. I was sure that the reference to binaries nearby was a reference to a bin folder at that point, so I looked in the java installation and checked for large fiiles (“elephants”). The largest binary was easy to find using ls with the sort argument (-S): /usr/local/jdk1.8.0_151/bin/unpack200. Specifically looking at that file showed three symbols which had 404 in the value, all sharing one word.
The common word in all three of those is “deflate” and when you submit that as the answer, it works!
Find my problem
You’ll notice in my brute force above, this file did not show up, nor did these symbols. Why? Because I typo’d -T instead of -t. This came about from jumping between objdump and another tool (readelf) in which you need to use -T to view the entire symbol name. sigh Brute force didn’t let me down, I let brute force down.
Alternatives
Working brute force
If you fix the typo in my brute force, and add in use of sed to split apart the symbol names and uniq with the count (-c) option, you can have the same wall of text but have it tell you which words appear exactly 3 times in the fuile. This would have worked nicely, had I paid attention to my arguments.
In the output, you have a file I spent a lot of time on (test-container-executor) and the right file. There are not that many words to try, so this in theory should have worked nicely.
Following the directions
Assuming you were able to follow the question better than I did, you could also run a more targeted version that relies on ln to identify the largest file and head to only select that one file. This would be my preferred “solution in a Tweet” answer.
Conclusion
This week was a lot more comfortable for me and fairly uplifting, compared to last week’s struggle with Hadoop. The command line is still a great place to be to solve these questions, all the more so if you actually provide the right input to it. If you’ve never used awk before, I’d definitely recommend you play with it this coming week.
Footnotes
Because I had an eye towards making this fit into a Tweet later, I used find ... | grep instead of find -ipath... as it ends up being slightly shorter. ↩