November 5, 2026
Whiterose-THM
https://tryhackme.com/room/whiterose

By N30n
4 min read
adding the to /etc/hosts and saved as whiterose.thm
Recon and Port(s) Scanning:
I was given a username and maybe password. lets wait for nmap scanning to finish to know where our next step would be. after waiting minutes for the scanning, I only found 2, nothing interesting here. lets access our website
Navigating to the default domain (whiterose.thm) resulted in a client-side JavaScript redirect to cyprusbank.thm(add this to the host also), which served a static "Under Maintenance" page.
I tried Directory fuzzing against the root domain (whiterose.thm) but yielded no actionable results. same as second domain
VHost Discovery
Because standard directory fuzzing failed, I fuzzed the HTTP Host header to check for Virtual Host routing using the below commands
ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -u http://cyprusbank.thm -H "Host: FUZZ.cyprusbank.thm" -fs 57ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -u http://cyprusbank.thm -H "Host: FUZZ.cyprusbank.thm" -fs 57
I discovered admin.cyprusbank.thm(add to host also) returned a 302 redirect, indicating a login portal. I think I have now where those credentials(username&password) are useful
using the credentials above, we could check the authentication mechanism with burp intercept before sending to the server.
Web Attacks:
The challenge provided low-level credentials for Olivia Cortez (olivia:olivi8). Upon logging in, I noticed the application featured a messaging system with the URL structure /messages/?c=5.
By manipulating the c parameter (Conversation ID), I accessed conversation _c=0. How do you know olivia is low-privilege user??? try and answer 1st thm question. you now know you cant view another customer phone number, So we need another high privilege user. I exploited this through insecure direct object reference(IDOR) by changing the c values. Also try and access the settings.php, _you dont have the right perm to do that!
I can now do what olivia which is the low privilge user cant.
Remote Code Execution (EJS SSTI)
Standard Injection Testing
- I changed the body to:
name=test&password=<%= 7*7 %> - I highlighted the entire body, pressed
Ctrl+Uto URL-encode it, and clicked Send. - The response said:
Password updated to '<%= 7*7 %>'. - My Observation: It did not evaluate to
49. Standard SSTI was blocked
Breaking the App
- I changed the body to:
name=test&password[toString]=test - I highlighted the entire body, pressed
Ctrl+U, and clicked Send. - The server crashed and dumped a massive stack trace:
TypeError: Cannot convert object to primitive value. - My Observation: The error revealed
/home/web/app/views/settings.ejs. I now knew the exact template engine and file path.
The Exploit (RCE)
- The Framework: The
X-Powered-By: Expressheader proves the app uses Express.js, which relies onbody-parserto handle nested URL parameters (likesettings[view options]). - The Template Engine: The leaked stack trace explicitly mentions
/home/web/app/views/settings.ejs, confirming the use of the EJS rendering engine. - The Vulnerable Parameter: CVE-2022โ29078 is specifically triggered by the
settings[view options][escapeFunction]parameter. Because the Express parser merges this input directly into the EJS options object, we were able to overwrite theescapeFunctionwith Node.js code.
I crafted this to gain RCE
PRIV-ESC
root flag,
I achieved root access by running sudo -l to find a vulnerable sudoedit permission and exploiting CVE-2023โ22809 to read the root flag as a privileged file editor.
EDITOR="vim -- /root/root.txt" sudoedit /etc/nginx/sites-available/admin.cyprusbank.thmEDITOR="vim -- /root/root.txt" sudoedit /etc/nginx/sites-available/admin.cyprusbank.thm
Conclusion
I successfully achieved full system compromise of the Cyprus Bank environment through a chained series of vulnerabilities, demonstrating how a single unpatched dependency and a lack of strict access controls can result in complete infrastructure takeover. My initial access was obtained by identifying a hidden Virtual Host and exploiting an Insecure Direct Object Reference in the messaging system. By manipulating the conversation ID parameter, I accessed private developer chats and harvested plaintext administrative credentials. This privilege escalation provided access to the settings endpoint, where the application technology stack was identified as Node.js with the Express framework.
After intentionally crashing the application with an object injection to leak a stack trace, I confirmed the use of the EJS template engine. I bypassed the application input validation by exploiting an outdated version of EJS known as CVE-2022โ29078. By injecting a custom payload into the escape function and selectively URL-encoding only the JavaScript while leaving the name parameter raw, I achieved unauthenticated Remote Code Execution as the web user, which yielded the user flag. Finally, I enumerated the system sudo permissions and discovered that the web user was permitted to run sudoedit on a specific Nginx configuration file. The system was running a vulnerable version of sudo, allowing me to exploit CVE-2023โ22809 Argument Injection. By manipulating the editor environment variable, I forced vim to open the root flag file with root privileges, capturing the final root flag.
This challenge serves as a perfect example of the Defense in Depth principle failing. While the developers secured the login page, they left an IDOR in the chat feature. While they validated the name parameter, they failed to update their EJS dependency. And while they restricted the web user sudo privileges, they failed to patch sudo itself. The root flag perfectly summarizes the lesson: always update your dependencies and your system packages.
Happy hacking!!!