بِسْمِ اللَّـهِ الرَّحْمَـٰنِ الرَّحِيمِ
Hi geeks,
A few months ago, I worked on a VDP on the HackerOne platform. I usually start my testing with passive and active recon to discover subdomains. Following this, I proceed to test such as SQL injection, XSS , and SSTI in various parameters when navigating the websites.
I noticed that the website reflected {7*7} as 49. My first instinct was to attempt exploiting SSTI, which led to achieving RCE :))
After spending amount of time attempting to exploit SSTI, I discovered that the website was built with the Vue.js framework, which utilizes a Client-Side Template Engine. As a result, all avenues to exploit SSTI were closed :))
What are Client-Side Template Engines?
Client-Side Template Engines such as AngularJS and Vue.js , as their name suggests, will render the data on the client-side. These engines can only access data that is accessible and presented to the client and will process the data locally. Their impact will be limited mostly to the user
So now, we can easily exploit that and escalate it to DOM XSS..
Exploiting the vulnerability:
Now, all that’s left is to attempt triggering an alert using the template injection {{alert(document.cookie)}} .
Another Exploitation method :
- If the initial payload fails to trigger an alert, it provides a valuable insight into whether JavaScript execution is possible. In such cases, an error is thrown, typically indicating ‘Uncaught TypeError: alert is not a function’. This error originates from Vue.js, often at a specific line (e.g., line 12345).
- Analyzing this line reveals a newly constructed function, utilizing the parameter ‘code’ as its content. To gain a deeper understanding of the process, a breakpoint is set at this line.
- Leveraging the browser’s debugger offers further insights into intriguing functions. Given that JavaScript functions are objects, we exploit the ‘constructor’ property to reference the constructor function responsible for creating the instance object. This is achieved using the payload: {{$emit.constructor}}.
- With access to the function’s constructor, we can craft our own function. For instance, we utilize the payload: {{$emit.constructor`alert(document.cookie)`()}} to create a function that pop up an alert box.
I found the same bug in two different subdomains within that company.
If you’ve made it this far, I hope you found this write-up helpful. My apologies if there were any issues along the way…HAVE A NICE DAY!