September 8, 2018

Hunting for Angular Based Bugs With the Browser Console

One of the least appreciated tools that are available to pentesters is the browser console. Every browser has it, allowing you to not only read comments that developers forgot to remove (as often features get pushed to production faster that they can be tested), but also manipulate the behavior of the application at runtime by making use of functions and variables written by the frontend programmers of the application. This is one of my favorite tools to use when testing AngularJS applications. The reason why is that, among other things, the console allows you to manipulate:

  • Angular Factories: Angular factories are singletons that encapsulate most of the logic of the application. Most of the times when developers talk about Angular services they are actually referring to Factories. The difference is that a new instance of a service is created every time it is used by a controller; whereas Factories are passed by reference and initialized once in the Angular application lifecycle. Angular controllers use services for things such as authentication logic, calls to APIs, and other complex frontend logic. Think of Factories as “front end business logic” and controllers as the Controller classes in MVC architectures.
  • Angular controllers: As stated above, controllers encapsulate DOM logic and make use of services for more complex operations.

Now, bear in mind that this is not a “how to exploit X with browser consoles” tutorial. Rather, this technique simply allows you to explore the application at a deeper level by giving you the ability to manipulate the code in an interactive manner. Granted, you may not always want to explore the application through the browser console when you have say, 2 days to complete a web application pentest assessment. Nevertheless, this technique is particularly useful when you want to research an application in depth, as it may allows you to find logic based vulnerabilities rather than, for instance, XSS or CSRF bugs that can often be found using automated tools.

Ok, before continuing let me first clarify that this technique only works for Angular 1.X applications. I plan to write another post in the future that focuses on how to play with the code of an Angular 2-6 application from the broser console.

Hands-on research time! Assuming that you have an Angular 1.X application opened in the browser, the first thing you’d want to do is of course to open the browser developer console. If you are using Chrome, just press F12 or right click any element on the page and select inspect element. Now click on Sources tab to start exploring the application code:

This application has a number of interesting services. In this case we are going to play with the Auth service. You may not always be able to see readable code like the one above, as in many cases the code will be minified. If that is case you can either use a Javascript beautifier tool to make it readable, or click on the {} icon at the bottom of the Sources tab in the browser, right below the code window.

After you have explored the code further you may want to start modifying the behavior of the application. The first thing you need to do is get an Angular injector reference, so go ahead and click on the Console tab of the browser and type

var injector = angular.element(document.body).injector();

This injector will allow us to obtain references to any services or controllers used by the page. Now let’s get a reference to the Auth service:

var authService = injector.get('Auth');

Now if we type authService in the console and press enter we can see a list of all functions exposed by that service:

Now let’s go ahead and modify the behavior of the isLoggedIn function by typing the following:

authService.isLoggedIn = function(){ return true; }

Great, we have modified the behavior of the isLoggedIn function so that it always returns true. But the browser does not know about this change yet, as Angular has not yet bound the new definition of the function to the isLoggedIn variable. We can force that by writing the following in the console:

angular.element(document.body).scope().$apply();

The above code simply forces Angular to start a new $digest cycle and update any bindings and values that may have changed since the last $digest (you can read more about this here). After doing that, all elements of the page and all JavaScript variables and functions that make use of the isLoggedIn variable will use our new function definition, which in this case returns true every time. In this case, additional menu items may show up on the page as angular thnks that you are logged in. With enough patience, you may be able to do some very interesting things. Note however that when you reload the page by pressing Ctrl-r the function will not remain modified.

Ok, that was interesting, but how useful is it? The answer is, it depends. For instance, in some cases this may only be useful if for instance, you want to display content not rendered at page load time by modifying variables that affect ng-if behavior. Unlike hidden HTML elements, elements controller by ng-if attributes completely remove or hide elements of the page on page load, so you cannot simply find them by inspecting the HTML code and removing hidden attributes using the HTML inspector tool. In other cases, I have seen serverless applications that rely on services like Firebase for data operations, and manipulating the code in this manner allows you to essentially enumerate an entire database. Remember, this is not necessarily an exploit technique, but yet another tool that allows you to gain a deeper understanding of the application you are testing. While you can do a lot with tools like Burp, it helps to think like a developer when you are on the hunt for bugs. Good luck in your bug hunting endeavors!

© hex0punk 2023