Beyond
┌──(kali㉿kali)-[~/archive/htb/labs/forge]
└─$ curl -s http://forge.htb/uploads/D5QHeBGiZSgYIDkVA2GD
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCdkg75DLB+Cd+2qjlqz6isdb/DVZusbqLoHtO/Y91DT02LE6a0dHeufEei6/j+XWk7aeM9/kZuNUcCwzAkNeYM2Nqpl8705gLsruGvsVXrGVRZOHBwqjSEg5W4TsmHV36N+kNhheo43mvoPM4MjlYzAsqX2fmtu0WSjfFot7CQdhMTZhje69WmnGycK8n/q6SvqntvNxHKBitPIQBaDmA5F+yqELcdqg7FeJeAbNNbJe1/ajjOY2Gy192BZYGkR9uAWBncNYn67bP9U5unQggoR+yBf5xZdBS3xEkCcqBNSMYCZ81Ev2cnGiZgeXJJDPbEvhRhdfNevwaYvpfT6cqtGCVo0V0LTKQtMayIazX5tzqMmIPURKJ5sBL9ksBNOxofjogT++/1c4nTmoRdEZTP5qmXMMbjBa+JI256sPL09MbEHqRHmkZsJoRahE8tUhv0SqdaHbv2Ze7RvjNiESD6fIMrq6L+euZFhQ5p2AIpdHvOUSbeaCPiG7hwVqwf8qU= user@forge
The authorized_keys
file was also available inside the SSH directory
I could have fetched it and figured out the exact user
Default LIST
command?
An SSRF attack via the url
method, pointing to a virtual host located at admin.forge.htb
, which could only be access through localhost
From admin.forge.htb/announcements
, I learned:
- There was an internal FTP server running.
- The
/upload
endpoint is also present with supports to upload from ftp servers with theu
parameter. - That’s precisely how I managed to send a GET request to
http://admin.forge.htb/upload?u=ftp://user:heightofsecurity123!@localhost:21
- That resulted the following unexpected output
$ curl -s http://forge.htb/uploads/zpyh0ipEENsYBY0NQqXl
drwxr-xr-x 3 1000 1000 4096 Aug 04 2021 snap
-rw-r----- 1 0 1000 33 Apr 12 16:32 user.txt
- The output looks much like that of both
ls
ordir
command inside the FTP session
how is this possible? My expected output was a form of errors because the web application would NOT know what to upload as the FTP connection string never specified any resource. just pointing to the FTP server itself.
So I tried connecting to the FTP server once I gained foothold. The result is shocking.
user@forge:~$ curl -v 'ftp://user:heightofsecurity123!@localhost:21/'
* Trying 127.0.0.1:21...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 21 (#0)
< 220 Forge's internal ftp server
> USER user
< 331 Please specify the password.
> PASS heightofsecurity123!
< 230 Login successful.
> PWD
< 257 "/home/user" is the current directory
* Entry path is '/home/user'
* Request has same path as previous transfer
> EPSV
* Connect data stream passively
* ftp_perform ends with SECONDARY: 0
< 229 Entering Extended Passive Mode (|||60807|)
* Trying 127.0.0.1:60807...
* TCP_NODELAY set
* Connecting to 127.0.0.1 (127.0.0.1) port 60807
* Connected to localhost (127.0.0.1) port 21 (#0)
> TYPE A
< 200 Switching to ASCII mode.
> LIST
< 150 Here comes the directory listing.
* Maxdownload = -1
drwxr-xr-x 3 1000 1000 4096 Aug 04 2021 snap
-rw-r----- 1 0 1000 33 Apr 12 16:32 user.txt
* Remembering we are in dir ""
< 226 Directory send OK.
* Connection #0 to host localhost left intact
As soon as I connect to the internal FTP server from the target system using curl, it goes through a series of FTP commands including, LIST
Those are NOT my inputs, it went through all that by itself.
The fact that this happened without any interaction from the web application confirms that this is not related to the web application. It’s likely an external influence from either a service or cronjob.
vsftpd
user@forge:~$ ps -auxwww | grep -i ftp
root 955 0.0 0.1 6808 3204 ? ss 16:31 0:00 /usr/sbin/vsftpd /etc/vsftpd.conf
The running FTP service is vsftpd
, loaded with a configuration file at /etc/vsftpd.conf
config
user@forge:~$ grep -v '^#' /etc/vsftpd.conf
listen=YES
listen_ipv6=NO
anonymous_enable=NO
local_enable=YES
dirmessage_enable=YES
use_localtime=YES
xferlog_enable=YES
connect_from_port_20=YES
ftpd_banner=Forge's internal ftp server
secure_chroot_dir=/var/run/vsftpd/empty
pam_service_name=vsftpd
rsa_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
rsa_private_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
ssl_enable=NO
The configuration file itself doesn’t have anything going on with the strange behavior
I had to exclude all the lines starting with the #
character to get rid of comments
So what could it be?
No more localhost
root@forge:/# service iptables restart
After compromising the system, I drop the firewall rule for port 21
, and restarted the iptables
service
┌──(kali㉿kali)-[~/archive/htb/labs/forge]
└─$ nmap -p21 $IP
starting nmap 7.93 ( https://nmap.org ) at 2023-04-13 03:54 CEST
Nmap scan report for forge.htb (10.10.11.111)
Host is up (0.094s latency).
PORT STATE SERVICE
21/tcp open ftp
nmap done: 1 IP address (1 host up) scanned in 0.22 seconds
While the target FTP server is now accessible, I will test it directly from Kali
external
┌──(kali㉿kali)-[~/archive/htb/labs/forge]
└─$ curl -v 'ftp://user:heightofsecurity123!@10.10.11.111:21'
* Trying 10.10.11.111:21...
* Connected to 10.10.11.111 (10.10.11.111) port 21 (#0)
< 220 Forge's internal ftp server
> USER user
< 331 Please specify the password.
> PASS heightofsecurity123!
< 230 Login successful.
> PWD
< 257 "/home/user" is the current directory
* Entry path is '/home/user'
* Request has same path as previous transfer
> EPSV
* Connect data stream passively
* ftp_perform ends with SECONDARY: 0
< 229 Entering Extended Passive Mode (|||10069|)
* Trying 10.10.11.111:10069...
* Connecting to 10.10.11.111 (10.10.11.111) port 10069
* Connected to 10.10.11.111 (10.10.11.111) port 21 (#0)
> TYPE A
< 200 Switching to ASCII mode.
> LIST
< 150 Here comes the directory listing.
* Maxdownload = -1
-rwxr-xr-x 1 1000 1000 3104768 Apr 12 23:11 pspy64
drwxr-xr-x 3 1000 1000 4096 Aug 04 2021 snap
-rw-r----- 1 0 1000 33 Apr 12 16:32 user.txt
* Remembering we are in dir ""
< 226 Directory send OK.
* Connection #0 to host 10.10.11.111 left intact
It STILL does that.
BUSTED
After many trials and researches, I think I finally found out what was going on curl, by default, seems to get directory listing if the remote resource is a FTP server and not specified.
┌──(kali㉿kali)-[~/archive/htb/labs/forge]
└─$ wget -v 'ftp://user:heightofsecurity123!@10.10.11.111:21'
--2023-04-13 03:56:57-- ftp://user:*password*@10.10.11.111/
=> ‘.listing’
connecting to 10.10.11.111:21... connected.
Logging in as user ... Logged in!
==> SYST ... done. ==> PWD ... done.
==> TYPE I ... done. ==> CWD not needed.
==> PASV ... done. ==> LIST ... done.
.listing [ <=> ] 786 --.-KB/s in 0s
2023-04-13 03:56:58 (110 MB/s) - ‘.listing’ saved [786]
Removed ‘.listing’.
Wrote HTML-ized index to ‘index.html’ [1410].
and wget does that too by saving it to the .listing
file first and re-naming to index.html
for better reviewing
┌──(kali㉿kali)-[~/archive/htb/labs/forge]
└─$ cat index.html
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title>index of / on 10.10.11.111:21</title>
</head>
<body>
<h1>index of / on 10.10.11.111:21</h1>
<hr>
<pre>
2021 may 19 link <a href="ftp://user:heightofsecurity123!@10.10.11.111:21/.bash_history">.bash_history</a> -> /dev/null
2020 feb 25 file <a href="ftp://user:heightofsecurity123!@10.10.11.111:21/.bash_logout">.bash_logout</a> (220 bytes)
2020 feb 25 file <a href="ftp://user:heightofsecurity123!@10.10.11.111:21/.bashrc">.bashrc</a> (3771 bytes)
2021 aug 04 directory <a href="ftp://user:heightofsecurity123!@10.10.11.111:21/.cache/">.cache/</a>
2023 apr 12 23:15 Directory <a href="ftp://user:heightofsecurity123!@10.10.11.111:21/.gnupg/">.gnupg/</a>
2020 feb 25 file <a href="ftp://user:heightofsecurity123!@10.10.11.111:21/.profile">.profile</a> (807 bytes)
2021 aug 04 directory <a href="ftp://user:heightofsecurity123!@10.10.11.111:21/.ssh/">.ssh/</a>
2023 apr 12 23:11 File <a href="ftp://user:heightofsecurity123!@10.10.11.111:21/pspy64">pspy64</a> (3104768 bytes)
2021 aug 04 directory <a href="ftp://user:heightofsecurity123!@10.10.11.111:21/snap/">snap/</a>
2023 apr 12 16:32 File <a href="ftp://user:heightofsecurity123!@10.10.11.111:21/user.txt">user.txt</a> (33 bytes)
</pre>
</body>
</html>
yeap.