Hello, I’m Vinicius (big0us), this is a write-up of a machine that was the challenge for one of UHC’s qualifiers. (translate to english by 0day) Happy reading :) g00d_h4ck1ng
The first page you’re greeted with a login page, taking a look at the HTML of the page, apparently there’s nothing hidden, I’ll fuzz first, then we can test some credentials.
Apparently our fuzzing only showed a /class, where there is a directory listing pointing to a “.php” file.
Okay, let’s test some default credentials in the login form:
admin:admin guest:guest administrator:admin root:root
By testing “guest:guest” we were able to enter:
Looking around apparently, we only have a welcome page. Let’s check our cookies.
Using cyberchef to decode the cookie, we can see that it’s JSON with three values: hmac (probably something that validates the values), username, and a time for the cookie to expire.
I’m going to try to change the username value in the cookie to “admin” with base64 & URL encoding, and then send back to the application.
This page showed an error saying that we’re trying to do “cookie tampering”, and returned a flag! The first flag. After some tests, sending cookies with other random values, I realized that the application validates the cookie by the value of hmac, and not by the entire content of json. A well-known vulnerability about PHP validations is type-juggling, which consists of bypassing authentications by making any if($ == $) that will always return “true”.
Basically when a programmer uses “==” in a php comparison, first it makes the two values the same type, ignoring the type (int, str…) of the variables. And in this situation we can use some techniques for the comparison to return “true”.
After trying for quite a while, I tried changing the value of “hmac” to “true” and luckily it worked!
Okay :( I was sad that there are no flags here. I’ll try to change the username again, to understand what’s going on.
Changing to “test”, php gives us an error, it seems it’s running a “require_once” on the value we put & appending “.php” at the end. require_once is normally used to include pages and php files in websites, and when the user has control over the value that require_once uses, the application is vulnerable to LFI or RFI (Local/Remote File Inclusion).
As the application already puts the .php at the end, I will do the following. Upload a file with a webshell on a server using ngrok, then tell the application to include my file and get an RCE.
And I will send the payload:
(The application now puts the .php)
We have RCE!!
Now I’m going to try to get a reverse shell. After a few attempts I realized that there is a firewall in the application that blocks any communication on ports other than 80 or 443, since I don’t have a VPS, I’ll do it differently, instead of a reverse shell (where the victim connects back to me) I’m going to use a bind shell (opening a port on the machine and connecting to it). For this I will use “socat”.
First I got the socat binary in their github (socat binary) and passed it to the machine using the web-server that I created to get RCE, and curling it. I ran the commands that are in the image and got a bind shell! (I used port 6969)
In “/” have our next flag:
Doing the basic privesc checklist, we can see that we are the apache user and we can run a script as root on the machine:
Apparently we can’t read the script or change it.
What’s left for us to do, is to simply RUN IT!:
The file prints an IP with option 2 (List Blocked IP’s), taking a look at /var/www/html the web application path, we can see that there is a file with the same IP that was printed, so it’s printing the IP that is in the file.
I opened the file with nano (before running ‘export TERM=xterm’ !!) and started editing it, to try and provoke some type of error in python that would show me something from the program.
Interestingly, there is a different (not used often) format string running. Searching about this type of format string + vulnerabilites, I ended up stumbling on this article.
Basically it explains everything we need to do, so I won’t explain it again, but the way this format string works, allows us to inject more strings to be formatted, and if this is printed we can print all the global variables that the file uses, usually giving us some key or password.
Okay here is my final payload.
This worked and we got the value of a variable called root_secret, it’s probably the root password.
Worked!! Thanks to you who’ve read this far, I hope you enjoyed this challenge / writeup!