Front end development has rapidly changed over the past decade. Most modern day web applications are built using frameworks like AngularJS, React, Vue, and more. According to google "AngularJS is a JavaScript-based open-source front-end web framework mainly maintained by Google and by a community of individuals and corporations to address many of the challenges encountered in developing single-page applications". Most people think these frameworks are immune to vulnerabilities like XSS but that is not the case, its just a little different to exploit.
There are a few things you need to understand when dealing with Angular applications. I will briefly go over a few topics such as templates, expressions, and scopes which is vital for understanding client side template injection in Angular.
When you are looking at an Angular application in your browser your actually looking at a template. A template is an HTML snippet that tells Angular how to render the component in angular application. The main advantage of templates is that you can pass in data allowing you to dynamically generate HTML code based on the arguments passed to it. An example template can be found below
<h1>Welcome {{Username}}!</h1>
As you can see the following template creates an "h1" tag which welcomes the current user. The "{{Username}}" is an expression and changes based on your username. If my username is "ghostlulz" then the application would display "Welcome ghostlulz!". This allows Angular to dynamically generate HTML pages instead of using static pages as shown below:
<h1> Welcome ghostlulz!</h1>
Expressions are Javascript like code snippets . Like Javascript expressions Angular expressions can contain literals, operators, and variables as shown below:
Unlike Javascript expressions which are evaluated against the global window, Angular expressions are evaluated against the Scope object. Basically what this means is if you try to evaluate "alert(1)" it will fail because the scope does not have an "alert" function (unless you define one). The scope is just an object and you can define variables and functions in it as shown below:
$scope.username = "Ghostlulz";
$scope.greetings = function(){ return 'Welcome ' + $scope.username + '!';};
According to Google "Client-side template injection vulnerabilities arise when applications using a client-side template framework dynamically embed user input in web pages". As you know Angular is a client side template framework and you can embed user input into these templates. This makes Angular the perfect target for this type of vulnerability.
Note in this demonstration ill be using the following application provided by liveoverflow:
https://old.liveoverflow.com/angularjs/
If you don't know better and you'r testing for XSS on an Angular site you might try something like this:
Ass you can see I didn't get an alert box and thats because the server is encoding our input before passing it to the template as shown below.
<?php // GET parameter ?q= mit sicherem escaping
$q = $_GET['q'];
echo htmlspecialchars($q,ENT_QUOTES);
?>
This is a very popular method of preventing XSS and in sufficient enough for most application but Angular is different. In Angular we can use expressions which does not have to use special characters which get encoded by the "htmlspecialchars" PHP function as shown below:
As you can see above I am using the expression "{{1+1}}" which gets evaluated to "2". This is a very strong indicator that the application is vulnerable to client side template injection.
Forcing an application to add two numbers together isn't all that exciting, but what if we could inject javascript code. We know we cant simply insert an "alert(1)" function because that function isnt defined in the scope object. Behind the scenes "alert(1)" turns into "$scope.alert(1)"
By default the scope object contains another object called "constructor" which contains a function also called "constructor". This function can be used to dynamically generate and execute code. This is exactly what we need to execute our XSS payload as shown below:
{{constructor.constructor('alert(1)')()}}
Notice the following payload does not contain any special characters. This means any attempt to encode our payload will fail to prevent XSS. This is huge as thats how most people prevent XSS.
As you can see above our malicious Angular expression was injected into the page causing the application to dynamically generate and execute our payload.
To help prevent this type of attack Angular 1.2 - 1.5 contains a sandbox. This was latter removed in version 1.6 and above as it provided no real security as there were numerous sandbox bypasses. If the application your testing is between versions 1.2 - 1.5 you will need to lookup the sandbox bypass for that version to get your XSS payload to execute.
With new technologies comes new vulnerabilities. Any client side template framework that accepts user input can be vulnerable to client side template injection. This vulnerability is mostly used to trigger XSS payloads. Since angular uses expressions we can often bypass traditional XSS preventions such as encoding the users input. Most developers rely heavily on this prevention method which works fine in most applications just not ones that make use of client side templates and expressions.