[HTB] Headless
Table of Contents
URL | Link đź”— |
---|---|
Level | Easy |
Attacker IP | 10.10.14.31 |
Target IP | 10.10.11.8 |
Intro#
Today I am tackling the HackTheBox machine Headless. I will start with discovering a web server running on TCP/5000
. Then I will uncover a Stored XSS. By exploiting this, I will exfiltrate the is_admin
cookie, gaining access to the restricted endpoint, abuse a command injection within it to achieve RCE and establish a reverse shell. Ultimately, I will escalate privileges by exploiting a misconfigured script to obtain root access and pwn the target.
Enumeration#
Nmap#
During the initial reconnaissance, I executed an Nmap scan:
The scan revealed two significant open ports: TCP/22
and TCP/5000
.
The TCP/22
port was running OpenSSH 9.2p1 on a Debian system, which could prove useful later, but it was the TCP/5000
which piqued my interest, as it responded with a HTTP response, hinting TCP/5000
was running a webserver.
This web server was powered by Werkzeug 2.2.2
and Python 3.11.2
. The HTTP response included a Set-Cookie
header with a value of is_admin=InVzZXIi.uAlmXlTvm8vyihjNaPDWnvB_Zfs
, suggesting a potential session or privilege escalation attack vector.
I moved on to examining the web app itself.
TCP/5000
#
Upon navigating to the target’s simple webpage, I was greeted with a countdown timer indicating when the site would go live, along with a link to a Contact Support Form.
Contact support form#
This form was accessible via the /support
endpoint. I tried a basic Cross-Site Scripting (XSS) attack.
Submitting the form triggered a POST
request to the same /support
endpoint. I crafted a straightforward XSS payload, <script>alert(1)</script>
, and included it in the message field of the form submission. The HTTP request looked like this:
The server responded with 200 OK
, but the content of the response indicated that my attempt had been detected as a hacking attempt. The response included a page titled Hacking Attempt Detected suggesting that some form of server-side input validation or filtering was in place.
Additionally, I received a notification that my IP address had been reported, which was a clear indication that the system was actively monitoring and logging suspicious activities.
Subpath Enumeration#
Out of ideas, I decided to move on to subpath enumeration using feroxbuster
:
The output revealed several interesting paths:
200 GET 93l 179w 2363c http://10.10.11.8:5000/support
200 GET 96l 259w 2799c http://10.10.11.8:5000/
500 GET 5l 37w 265c http://10.10.11.8:5000/dashboard
Among the discovered paths, /dashboard
caught my attention. While /support
was accessible, visiting /dashboard
resulted in a 401 Unauthorized
error. This indicated that access to the dashboard was restricted, likely requiring authentication.
Given that I had the is_admin
cookie set, I speculated that perhaps an administrator-level cookie was necessary to gain access to the dashboard. I needed to circumvent the server-side input validation somehow.
Obtaining a Stored XSS#
Initially, I attempted various payloads as POST form data, but none seemed to yield any results. However, the request parameters were being reflected back to me. This reflection, coupled with a rather ominous message stating “your IP has been reported,” led me to suspect that these parameters might also be reflected on the administrator’s end.
To investigate further, I used Burp Suite’s Proxy feature to intercept and modify the HTTP requests:
I’ve added a Test
header along with message=<script>
to cause the reflection of the headers and flagging the request as a hacking attempt. This way I confirmed the presence of a reflected XSS. Furthermore, it shall be opened by the Administrator at some point, given it was creating a security report (effectively becoming a Stored XSS vulnerability).
Exfiltrating is_admin
cookie#
I crafted a payload designed to extract cookies from the target application, by setting up Python’s HTTP server:
đź’ˇ I used
TCP/8081
as8080
was already taken by Burp Suite’s Proxy
I then injected a malicious script into the application by sending a POST /support
request, with the payload embedded within the User-Agent
header:
đź’ˇ This payload creates new
Image
object and sets its source to my Attack Box address concatenated with thebase64
-encoded cookies
This triggered a GET
request to my server, effectively exfiltrating the cookies. On the server side, I observed the following output:
Then I promptly decoded the cookies:
Armed with this stolen is_admin
cookie, I was able to authenticate as an admin and gain access to the /dashboard
endpoint:
Enumerating the /dashboard
#
By interacting with the Generate Report button, I received a benign message stating, Systems are up and running!. This was triggered by a POST
request to the /dashboard
endpoint:
I suspected that the date
parameter was vulnerable to command injection. I modified the parameter to include a command injection payload: 2023-09-15;whoami
. This alteration revealed the username dvir
and confirmed that I had achieved Remote Code Execution. Nice đź’Ş
By appending cat ~/user.txt
to the payload, I successfully read the user
flag.
Establishing a Rev Shell#
I proceeded to craft a reverse shell command. I used the following command to initiate the reverse shell:
This command leveraged bash
to run an interactive shell session, redirecting input and output through a TCP connection to my listening machine at IP address 10.10.14.31
on TCP/7777
.
On my local machine, I set up a listener using Netcat to catch the incoming connection:
By executing these commands, I successfully obtained a reverse shell đź’Ş
Privilege Escalation#
First, I’ve enumerated the sudo privileges available to dvir
. The output revealed that dvir
could execute the /usr/bin/syscheck
script as root without providing a password which was a potential privilege escalation vector:
To understand what syscheck
was, I delved into the filesystem as dvir
and stumbled upon an email in /var/mail/dvir
.
The email provided context about a new system check script, likely referring to syscheck
, and then I confirmed it was indeed a script:
Armed with this information, I examined the contents of syscheck
:
The script checked for the existence of an initdb.sh
script and executed it if not found. Knowing that, I tried to escalate privileges by creating a malicious initdb.sh
script:
Pwned#
After making the script executable, I ran syscheck
with elevated privileges:
Pwned.