HackTheBox - OpenSource Writeup
Summary
This machine’s theme is that it is an opensource file transfer app, where one user can upload a file and they would get a URL they can share with others to download. Vulnrabilites in the code made it possible for an attacker to upload a backdoor and get command execution on a Docker container. Where the attacker could then pivot to a filtered Gitea service and log in to one of the users using found credentials in a previous commit in the git repository. Privilage escaltion revolves around a custom script ran as root to commit and push the home directory of the comprised user, that can be exploited by adding a malicious pre-commit hook.
Enumration
Port scanning
|
|
Port 80
and port 22
are open which are just ssh
and http
, but there is another port 3000
that is filtered by a firewall.
Website running in development mode with python debugger Werkzeug/2.1.2
That means we could access /console for code execution if we knew the pincode.. or generated it.
Werkzeug Pin code generation is possible but we are gonna need access to files on the machine.
Website
Web page promoting their open source file sharing app.
We have the option to download the source code and another option to go to the running app in /upcloud
App has upload functionality. possible LFI?
Git commits
Since this is a git repo we can check for any sensitive files or secrets that were commited previously. A good tool for this is gitkraken.
Found creds in a previous commit in the dev branch
dev01:Soulless_Developer#2022
|
|
Found in .vscode/settings.json commit: a76f8f75f7a4a12b706b0cf9c983796fa1985820 In the dev branch.
Testing for local file inclusion (LFI)
- Uploading a file stores it in
/uploads/{FILE}
- Tried navigating to
/uploads/../../../../etc/passwd
but it gets filtered
Since we have the source code we can see how it is being filtered.
|
|
This function sanitizes the file name from the users post request (uploading a file).
We can see that it only filters ../
And if we check out how the path is constructed in views.py
. We see that it just uses os.path.join()
|
|
And that is vulnerable because, if we looked at how os.path.join()
works
We can see that if we add a /
to any argument it will ignore all the arguments that came before and start from the argument that starts with /
.
So that means we could control the file path and bypass the LFI filter by just adding a /
making it an absolute path.
|
|
This does return /etc/passwd
from the target machine.
Using this LFI I have tried generating the werkzueg pin code but I could not get that to work.
Foothold
Found some cronjob, but there are no executable scripts to modify.
We have file read and file upload so what is stopping us from changing the source code on the server to add our own vulnerable code to get RCE
|
|
added this function to views.py
which will take any data we send with as POST
request and process it as a command and send it back. Basically making ourselves a backdoor.
Now we need to upload views.py
but uploading it normally will place it in /uploads
and that would be useless.
We can intercept the upload request with burpsuite
and use the same method we used to bypass LFI filter to navigate to /app/app/views.py
Testing RCE
Sending a POST
request to /vymvn
using curl:
|
|
- We have RCE!
as root?
Getting a reverse shell
Setting up listener:
|
|
Sending reverse shell command:
|
|
/bin/ash
from the /etc/passwd
file we got previously.
After exploring the machine we can quickly realize that we are in a Docker
container.
Network enumration
The docker instance runs on its own interface (probably
docker0
)The docker interface has the network ip
172.17.0
Wrote a quick shell script to ping sweep the network and see who is up.
|
|
We can see hosts from .1
to .9
are up.
Wrote another script to scan the ports on these hosts.
|
|
The output:
|
|
Since 172.17.0.1
is the network gateway and the ports open on it match the ports in the nmap scan we can confirm that it is the host machine.
Port 3000 is running an HTTP server and we can connect to it from the docker container because it is inside the network and not filtered by a firewall.
Now we can port forward/tunnel port 3000 to our machine and access it with the browser.
Tunneling in
Found tunneling tool chisel which allowed me to create a tunnel to 172.17.0.1:3000
with reverse port forwarding.
This was done by:
- Starting a chisel server on attack machine:
|
|
- Connecting from victim machine
|
|
And now I could access port 3000 on the box by simply going to localhost:3000
on my attacker machine!
172.17.0.1:3000
to 10.10.14.57:3000
which is my machine.Navigating to it we find that it is running gitea
which is like github but hosted locally.
Signing in with the creds found before. We find a backup folder with a private ssh key.
Stole that key and connected to user dev01
|
|
User pwned!
Privilege Escalation
Checking procceses
Dropped pspy and ran for a while to check what proccess are being ran.
We can notice that there is a custom script ran by root that is commiting and pushing the home directory of dev01
. We can’t modify this script becuase we don’t have write permissions on it.
Since the commiting is done by root we can add a pre-commit hook in .git/hooks/pre-commit
. We enable this hook by renaming .git/hooks/pre-commit.sample
and removing the .sample
from the end.
The pre-commit script will be executed by root before commiting.
Injected chmod +s /bin/bash
into .git/hooks/pre-commit
which made bash an SUID
means it will run bash as root and maintain the UID and GID of root, effectively making us the root user.
|
|
- Root pwned!