
Week 12. Corporate
TL;DR
This is an network resembling a corporate environment. The web site offers a support chat that is vulnerable to XSS and after exploitation we are able to get an access cookie. Once we have access to an employee dashboard we are able to move laterally by exploiting an IDOR vulnerability on the shared files feature. This allows to get a list of valid usernames and dates of birth, that can be used to craft a list of initial passwords that will be used to bruteforce access to an SSH machine in the internal network and get the user flag. Regarding escalation, first we crack a Bitwarden PIN to get access to an internal Gitea server. Here we find a JWT secret that will allow us to create token to move laterally to another user from the "Engineer" group. This allows to escalate privileges and move laterally to another host, where finally we have to exploit Proxmon's CVE-2022-35508 to escalate to root.
KEYWORDS
XSS, IDOR, Hydra SSH bruteforce, Bitwarden, Gitea, Proxmon 7.4, CVE-2022-35508.
REFERENCES
ENUMERATION
Port scan.
> nmap $target -p- -T4 -Pn --open --reason
Starting Nmap 7.93 ( https://nmap.org ) at 2024-02-14 14:10 EST
Stats: 0:00:57 elapsed; 0 hosts completed (1 up), 1 undergoing Connect Scan
Connect Scan Timing: About 38.10% done; ETC: 14:13 (0:01:34 remaining)
Nmap scan report for corporate.htb (10.10.11.246)
Host is up, received user-set (0.073s latency).
Not shown: 65534 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE REASON
80/tcp open http syn-ack
Nmap done: 1 IP address (1 host up) scanned in 133.43 secondsEnumerate the open ports.
Fuzz for subdomains.
Add to hosts file and enumerate the web site with Firefox. In the "Contact" section we can start a chat session with support team.
USER
The support chat is vulnerable to XSS, so start a new discussion and insert the payload.

Start a Python HTTP server on port 80 and click on "Send Message", a CorporateSSO cookie is received.
Repeat the process a couple of times to collect more cookies.
Then decode the JWTs to find some usernames. This is for the first token.
This is for the second.
And this is the last one.
Now login in http://people.corporate.htb or http://people.corporate.htb/dashboard with any of these tokens. To do this, just add the cookie in Firefox console or configure Burpsuite proxy settings to automatically add the cookie in the headers.

Reload the site, you are logged as Dangelo Koch.

Start enumerating the employee dashboard.
First, in the chat we can see several employees posts, clicking on the employee name we see the URL address format is like this: http://people.corporate.htb/employee/<employeeID>
It seems employee IDs are within the range 5000 – 5100, and by clicking on each employee we get access to the employee personal data, such as email and date of birth.

Our first step will be to get a list of valid employee IDs. For this, prepare a wordlist of sequential numbers from 5000 to 5100.
Then capture a request and edit with vim to prepare for ffuf
Fuzz with ffuf, we find a list of 78 employee IDs.
Next, click on the "Sharing" tab, here you can share your files with any other employee. Just click on the icon and add the email of the user you want to share the file with. Use the email of any of the employees whose cookies we have dumped before, for example Margarette Baumbach.

Click on "Share File" and then log in as Margarette using the previously captured JWT token. Add the token in Burpsuite headers configuration, then reload http://people.corporate.htb/dashboard. Margarette's profile comes into view.

Verify in the "Sharing" tab Margarette has access to Dangelo's shared file, and notice the file URL is formed: http://people.corporate.htb/sharing/file/222

There is a possibility file IDs are granted sequentially, like in IDOR vulnerability, so we can make all files shared with Margarette from Dangelo's profile.
Go back to Dangelo's dashboard (edit the cookie in Burpsuite headers configuration and reload the dashboard). Move to his "Sharing" tab, intercept a sharing request and copy to a file. Then edit the file to fuzz the fileid field. Your request file should look like this.
Generate a wordlist of 300 files and fire the process with ffuf. Since this is a POST request, all hypothetical files with ID from 1 to 300 will be shared with Margarette after each request is completed.
No answer is received but it does not matter, the POST requests have been successfully processed.
Move back to Margarette's profile, verify a huge amount of files are now shared with her. We are interested in fileid=122, a PDF file shared by Callie Goldner called welcome_to_corporate_2023_draft.pdf

Open it, it looks like a template for newcomers welcome document. You can see the password policy for new accounts.
If you remember, we had retrieved an employee ID list before. Using these IDs we can extract the date of brith from all employees.
Prepare a list of possible credential pair username-password for a credential stuffing attack.
Save the list as we will use it later.
Go back to your dashboard "Sharing" section and download the .ovpn. Use it to connect to the VPN.
In the openvpn output we notice 2 new routes have been added to 2 subnets 10.8.0.xxx and 10.9.0.xxx.
Verify the new IP address assigned.
And use your favorite host discovery script or method to scan the subnet, taking note of the alive hosts.
For example, this is a custom .sh script that pings all IPs in the subnet with nmap and saves the results in the file pingscan
And also use it in the 10.9.0.xxx subnet, since this new route has also been added.
We will start by enumerating the discovered hosts. First the IP 10.8.0.1 and then the other 2 hosts in the 10.9.0.xxx subnet.
The three hosts have port 22 open.
We will launch a credential stuffing attack with hydra and the list of credentials we crafted before. In a credential stuffing attack not all usernames are tested against all passwords, only the username-password pair.
Trim the credentials.txt file in the format username:password and use the option –C with hydra
Trying the attack in the 3 boxes, finally we find credentials for machine 10.9.0.4.
Four valid credentials have been found.
Log in the host 10.9.0.4 using the credential elwin.jones:CorporateStarter04041987
And use this shell to collect the user flag.

ROOT
Start from a low-priv SSH shell as user elwin.jones in host 10.9.0.4 and take the opportunity to enumerate the user and the system.
Enumerate the home folder, there is a Firefox profile in /home/guests/elwin.jones/.mozilla/firefox/profiles.ini
In order to browse this profile you just need to copy all files into Firefox path /.mozilla/firefox/ tr2cgmb6.default-release. And modify your local profiles.ini to add the new profile.
Then start Firefox, list the profiles with about:profiles and launch the profile in a new browser.

In the new window open the browser history, there are some references to a password manager called Bitwarden. Someone has been investigating if 4 digits are strong enough for a Bitwarden PIN.

Follow the history links and add Bitwarden to Firefox add-ons.
The user has searched for 4-digit Bitwarden PINs. To bruteforce it, first we need to dump the Bitwarden vault content. Install the tool moz-idb-edit.git (https://gitlab.com/ntninja/moz-idb-edit) as explained here: https://ambiso.github.io/bitwarden-pin/
There is an SQLite database inside the profile file system in the path storage/default/moz-extension+++c8dd0025-9c20-49fb-a398-307c74e6f8b7^userContextId=4294967295/idb/3647222921wleabcEoxlt-eengsairo.sqlite
Dump the database using the tool and save it in the file data.json
In order to bruteforce the PIN, download this rust script: https://github.com/ambiso/bitwarden-pin
Install Rust and run the script.
Several notes on the bruteforcing process:
The
data.jsonfile needs to be trimmed in order to be correctly parsed by the script. Replace the word "untitled" by "null" invimwith%s/untitled/null/gInspecting the source code (
main.rs), you see you need to define the variableXDG_CONFIG_HOMEbefore running the script.Also, you need to hardcode the path to the
data.jsonin the source code.
In summary: set XDG_CONFIG_HOME, hardcode the path as /htb/corporate/data.jsonand save your file in ~/kali/htb/corporate/data.json
Finally, I also changed the rounds variable to 600000 in the file main.rs to match the variable kdfIterations in the data.json. I cannot confirm if this is necessary since the script takes hours to finish and did not have time to test other values.
All in all, the working script used was this.
Use the pin 0239 to unlock the Bitwarden vault and disclose secrets (login credentials and OTP for http://git.corporate.htb).

Update the hosts file and navigate to http://git.corporate.htb
Login using the Bitwarden vault, right-click on the username filed and select "bitwarden-auto-fill". Same for the "totp" field. The corporate repos come into view.

Enumerate the private repos, read the code and analyze it.
Important things to notice:
JWT secret is taken from an
envvariable.A recent commit has been made to prevent sysdamin password to be changed.
Password resets may still be done by means of an API running at http://sso.corporate.htb/reset-password
The API source code is available at
corporateIT/corporate-sso/app.ts

Where you see passwords can be reset by sending a POST request with parameter currentPasword

We cannot see the JWT secret in the code; however, it can be disclosed by looking at the commits.
Move to the repo corporateit/ourpeople and browse the commits. Open the commit "Added prisma and dashboard" on the file package.json made by Tanner Kuvalis 11 months ago. This is the URL: http://git.corporate.htb/CorporateIT/ourpeople/commit/54bc5ff1f96ff9c3dda92ad92f05b110e43ba26e

The JWT secret is JWT_SECRET=09cb527651c4bd385483815627e6241bdf40042a
Now you can forge JWT tokens for any user but we need to think which user is more interesting to impersonate. According to Gitea, password reset for sysadmins has been disabled, so maybe they are not the best choice.
If we continue to enumerate the corporate-workstation-04 host at 10.9.0.4 from the elwin.jones SSH shell we find out there is a Docker daemon listening; however, we do not have acces to it, only people from "Engineer" group.
So it is more convenient to impersonate an engineer and escalate privileges with Docker.
Let's find a suitable engineer to impersonate such as her.

Email is dylan.schumm@corporate.htb, birthday 26/02/1967 and ID 5026.
Let's forge a JWT for Dylan Schumm using the previously disclosed JWT secret.

And verify it works by logging into the dashboard.

Although we have the JWT token, we need the SSH password to perform the Docker escalation. With the token we can get to the SSO portal where we can reset Dylan's password; however, to use the password reset feature we need to know the current password.
To understand how passwords are reset, read and analyze the reset-password endpoint in the application source code file app.js
Current passwords are requested during a password reset only if requireCurrentPassword flag is set to True
So we just need to forge a new JWT token with this flag set to False

Use it to log in and navigate to http://sso.corporate.htb for a password reset. Now it can be done without entering the current password.

And with the new password we can open an SSH session as Dylan Schumm.

In order to perform a Docker escalation we need an image but there are no images loaded in the machine. So we need to download an image and import it into the host.
In your Kali machine, pull an Alpine image.
Save it as TAR.
Now move the TAR file to the host with scp, and load the image.
Now it is possible to perform an escalation running a docker container that will mount host root file system on container's /mnt

Now that we are root we can enumerate further the system files and security configurations, such as the file sssd.conf
Here we see LDAP credentials for a user autobind that we can use to dump the entire directory.
First we chroot to /mnt so the ldapsearch binary installed in the machine works.
Then query all the directory.
The output is too large, so let's grep for admins.
It seems there is a group called sysadmin, let's proceed to extract the group members.
We see two members Stevie Rosenbaum and Amie Torphy. Let's see if we can dump more details about Amie.
And now Stevie.
We can just su to Amie's account and dump her private key in the home .ssh directory.

The private key does not work for connecting with SSH as amie.torphy at 10.9.0.1. But if you check the /etc/passwd file for alternative usernames, you'll find there is another user called sysadmin
And this username works to connect to the 10.9.0.1 host with the private key found.

Enumerating the file system, we see Proxmon is installed (/etc/pve directory), and the version installed is 7.4.
There is a CVE affecting this version: https://www.cvedetails.com/cve/CVE-2022-35508/.
And a PoC available here: https://starlabs.sg/blog/2022/12-multiple-vulnerabilites-in-proxmox-ve--proxmox-mail-gateway/
Basically, you can forge tickets to allow administrator rights to interact with the Proxmon API.
First we have a look at Proxmox configuration file.
It seems there is a backup directory in /var/backups
Inside it there are 2 backup files.
Download them with scp and extract the contents. We are looking for a file authkey.key to exploit the CVE. It is in fact inside the pve-host-2023_04_15-16_09_46.tar.gz package, in the path etc/pve/priv/authkey.key
We can use this key to generate a ticket for the Proxmox API. Just use the PoC described in the blog URL indicated before. After some modifications, the PoC final code is this.
Run it to get a ticket.

Now forward the Proxmox web service running on port 8006 to your Kali machine.
In the Proxmox API documentation it says how we can test our tickets (https://pve.proxmox.com/wiki/Proxmox_VE_API). Just use curl with your newly generated ticket.

Additionally, according to documentation we need a CSRF token for any API interaction. It can be we extracted from a server response to any generic curl request.

Now we need to find a way to escalate privileges leveraging our API access. According to documentation (https://pve.proxmox.com/pve-docs/api-viewer/index.html#/access/password) we can change any user password in the /api2/json/access/password endpoint, so let's change root password.
Don't forget your ticket and the CSRF token.

The only thing that's left is to su to root in the Amie Torphy session.

You are root.
Last updated