Information Gathering
Rustscan
Rustscan finds port 22 and 80 open:
rustscan --addresses 10.10.11.15 --range 1-65535
Enumeration
HTTP - TCP 80
Let’s first add comprezzor.htb to /etc/hosts
.
Accessing comprezzor.htb shows a website where we can upload txt, pdf, docx and compress using LZMA Algorithm:
Let’s see if there are more hidden subdomains:
sudo gobuster vhost --append-domain -u http://comprezzor.htb -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
Gobuster finds several more subdomains:
- auth.comprezzor.htb
- report.comprezzor.htb
- dashboard.comprezzor.htb
Let’s add all above again to /etc/hosts
.
auth.comprezzor.htb is a login portal:
http://auth.comprezzor.htb/login
Below the portal, there’s a Register link.
It seems like registration actually works:
Using the registration credentials, let’s sign-in:
Now that we are signed-in, we will first take a look at the cookies.
Go to Storage → Cookies and we can access the cookie value:
Let’s decode the vaule obtained with base64:
Web app is storing cookie in the format of user_id, username, role, and some kind of hash in the end.
We have tried cracking this hash but it wasn’t successful.
Let’s try changing the role from user to admin and see what happens.
We will base64 encode the modified following data:
{"user_id": 6, "username": "jadu", "role": "admin"}|8e8f57556ef8398f42dcbb05bc78b3f8f184f0ff7b0dde60aace0b97cd7216f2
We expected to bypass the login portal after replacing the cookie value with the base64 hash above.
Unfortunately, nothing happened. Let’s restore cookie value to mitigate issue.
XSS Cookie Stealing
Adam Cookie
Now let’s move on to enumerating report.comprezzor.htb.
/report_bug
will lead us to report submission form:
From some research, we have discovered that this form is vulnerable to XSS Cookie Stealing.
Let’s use the following payload on both fields of the form with out Python server listening:
After successful execution, we can observe cookie being stolen on our Python server:
Similarly, we can use the following payload as well to obtain the same result:
We get cookie value on our Python listener:
However, cookie value obtained from the first payload and the second payload looks different. This is because seocond payload output cookie is base64 encoded.
If we base64 decode it, it looks the exactly same as the first payload output coookie:
Base64 decoding on the user_data, we can see that this is the cookie value for user adam and he has the role as the Webdev:
Replacing user_data cookie value with the obtained cookie for adam, we can bypass login portal and access dashboard.comprezzor.htb:
Admin Cookie
Let’s see what functionality does dashboard provides.
Clicking on report ID, we are provided with the features of setting the Report to be Resolved, Set High Priority, or Delete Report:
Our guess is that if we set the report with the Cookie stealing payload as high priority, admin user will read it and will return his/her cookie value back to us.
Let’s go back to Report Submission form and create the same payload that will steal cookie value:
After submitting, we can verify it on dashboard.
However, priorty is set as 0:
Using Burp Suite, let’s the value for priority to be 1, so that the admin user will take a look at it:
Now we can see that the priority has changed to 1:
Within no time, we retrieve admin user’s cookie:
First cookie retrieval is from user adam and the second cookie retrieval should be from the admin user.
We retrieve cookie value from both adam and admin user because there is a slight time delay while we set the priority to be 1 after payload submission.
base64 deocding it, we successfully obtain the coookie value for admin:
SSRF
Let’s sign-in to dashboard using admin’s cookie value.
We can observe that some more features are provided for admin:
- Full report list
- Create a backup
- Create PDF Report
Checking on Create PDF Report, we can see that we input URL and the web app will generate a PDF Report out of it:
/create_pdf_report
Submitting URL to a web form, immediately reminded me of SSRF.
Let’s spin up a Python web server on our local machine:
Now let’s input the address of our Python web server on the web form:
We can see that the PDF is created and it shows the directory listing for the Python web server:
Taking a look at the PDF Creator using exiftool, it is identify to be wkhtmltopdf 0.12.6:
There is known SSRF vulnerability regarding wkhtmltopdf 0.12.6, but it turned out to be a dead end.
CVE-2023–24329
Instead of checking on the PDF creator, let’s see what software is being used when it is sending out the PDF back to us.
After spinning up netcat listener on our Kali machine and we will generate PDF of our netcat listener:
We get different output compared to Python web server.
User-Agent is identified and it is Python-urllib/3.11.
Searching for the known vulnerabilities regarding it, CVE-2023-24329 is found:
We would be able to bypass blocking listing methods via using blank characters in the front:
Let’s see if it actually works:
file:///etc/passwd
Generated PDF contains /etc/passwd
file, verifying the vulnerability:
Lets request on cmdline to know the current running process.
The /proc/self/cmdline
file in Linux contains the command line arguments passed to the currently running process. It provides insight into how a process was invoked, including any flags, options, or parameters supplied to it:
file:///proc/self/cmdline
The currently running application is /app/code/app.py
:
Let’s retrieve its code:
file:////app/code/app.py
Using ChatGPT, we can make the output more readable:
Above code sets up a Flask web application with multiple blueprints and specific configurations.
Based on app.py, let’s take a look at dashboard.py:
file:///app/code/blueprints/dashboard/dashboard.py
On dashboard.py, credentials for FTP login is revealed:
Shell as dev_acc
Using the FTP credentials, we can login via SSRF.
Let’s type in the following command on PDF Generation URL:
ftp://ftp_admin:u3jai8y71s2@ftp.local/
Output PDF shows the directory listing of FTP:
Let’s take a look at welcome_note.txt file:
ftp://ftp_admin:u3jai8y71s2@ftp.local/welcome_note.txt
welcome_note.txt file contains the passphrase for SSH: Y27SH19HDIWD
Let’s take a look at private-8297.key:
ftp://ftp_admin:u3jai8y71s2@ftp.local/private-8297.key
Key files is a OpenSSH Private Key:
Let’s use ssh-keygen to output the public key associated with the private key, which might include any comments that were created when the key pair was generated:
ssh-keygen -y -f id_rsa
User name dev_acc was left as a comment on SSH private key.
Now using the discovered passphrase and SSH Private Key, we can SSH-in to the system as dev_acc:
ssh -i id_rsa dev_acc@comprezzor.htb
Privesc: dev_acc to lopez
Linpeas
We will first run linpeas to see if there’s anything interesting.
There are several ports open internally. We might port forward on these ports later on.
One interesting open port is 21, meaning FTP is open internally.
We can also see what users are on the system:
Several interesting files were found, including users.db and users.sql:
sqlite database folder is also found:
Local Enumeration
Now let’s go ahead and further enumerate on what linpeas discovered.
There are two web apps running on this machine: blueprints and selenium
Let’s first check on users.db that linpeas found.
We can dump the database using sqlite3
sqlite3 users.db
We have hashes for admin and adam.
Only adam’s hash could be cracked and the password is: adam gray
FTP as adam
Since we know that FTP is open internally, let’s login to it as adam:
There lies run-tests.sh, runner1, and runner1.c files inside /backup/runner1
:
Let’s download all three to /tmp
directory:
run-tests.sh seems to be requiring a key in order to be ran but the last four digits are missing:
runner1.c seems to be making authentication by comparing the key to the stored md5 hash before granting to run the application:
Key Guessing
Let’s move on to guessing the last four digits of the key.
Here’s the missing value key: UHI75GHI****
. The hash associated with it is 0feda17076d793c2ef2870d7427ad4ed
.
We can use the Python code below to try all possible combinations:
Python script guesses the key within 7 seconds: UHI75GHINKOP
Suricata
Unfortunately, we do not have the privilege to run runner1 although we have the correct key:
After spending lot of time on enumeration, we found something interesting on /opt
:
There is a directory called runner2
but only sys_adm
group can access it, The idea is, this is the version 2 of the application we was exploiting before runner1
so it should be related somehow, after some search again I found logs directory for suricata.
There are multiple zip files inside /var/log/suricata
:
Suricata sometimes leave credentials behind so let’s look for the active usernames with zgrep.
Searching for user lopez, we can see authentication password for user lopez: Lopezz1992%123
Now we can switch in to lopez’s shell using su lopez
and the discovered password:
Privesc: lopez to root
lopez
user is one of the sys-adm
group so we can access the runner2
directory now:
It seems that runner2 application receive json file as the input:
After long enumeration, we discovered way to exploit this.
We will frist create a json file with the key on it as such:
echo ' { "auth_code": "UHI75GHINKOP", "run": { "action": "install", "role_file": "getroot.tar;bash" } }' > file.json
Let’s create archive.tar.gz file:
Now, let’s change the name of the zip file into getroot.tar;bash:
mv archive.tar.gz "getroot.tar;bash"
When we run runner2 towards file.json, we get a shell as the root:
sudo /opt/runner2/runner2 file.json