Friday, August 21, 2015 At 9:57AM
When performing security code reviews of .NET web applications, one of the first goals for the reviewer should be to enumerate the external facing attack surface. For ASPX based applications this is achieved by enumerating all files with an aspx or ascx extension. Additionally, the ‘web.config’ file should be parsed for any exposed HttpModules, HttpHandlers and configured web services. Over the years, more and more applications have been transitioning to .NET MVC. With this transition the process for enumerating endpoints becomes a bit trickier.
When encountering a .NET MVC web application, Controllers handle the processing of incoming requests and are tied to exposed URL endpoints in the application. To successfully enumerate an application’s web attack surface, finding all classes that inherit from Controller base classes and enumerating their public methods is required. Additionally, .NET MVC introduces Filter Attributes that can be set at a Global, Controller (class) or Action (method) level.
For example, the DataController class in the code snippet below exposes an action named Index() that returns the current time. This action is decorated with the OutputCache action filter.
Therefore, prior to executing the code within the method, the logic of the ‘OutputCache’ action attribute will be executed first. There are out of the box Filter Attributes provided by .NET, or you can create your own. The ‘HttpGet’ attribute set on the method scopes the request to accepting only ‘GET’ requests. The ‘Route’ method defines the URL endpoint a user would need to hit in order to be routed to run the ‘Index()’ method.
Snippet 1 – Controllers\DataController.cs
public class DataController : Controller { [OutputCache(Duration=10)] [HttpGet] [Route(“index”)] public string Index(){ return DateTime.Now.ToString("T"); } }
It is very common for applications to use Filter Attributes to handle security related tasks. Some frequently observed examples of security related logic are:
-
Authentication enforcement
-
User/role based access control
-
CSRF token validation
-
Cache control headers
-
Setting of HTTP security headers
Having the ability to enumerate all exposed application endpoints and their associated Filter Attributes becomes very powerful during a manual security code review. The code reviewer will have the ability to quickly identify the application’s attack surface and identify gaps in security coverage based on the Filter Attributes assigned.
Using the Rosyin API
In order to perform our enumeration we used the .NET Compiler Platform (Roslyn) which provides open-source C# and Visual Basic compilers with powerful code analysis APIs. It enables building code analysis tools with the same APIs used by Visual Studio. It is a workable ‘compiler as a service’ API – that is to say that it exposes the C# compiler as an API for developers to call and work with the syntax tree. The APIs allow us to automate the enumeration process very accurately compared to simply using regex based ‘grepping’.
The Roslyn APIs are available by default within Visual Studio 2015. Alternatively, it can be installed through NuGet by installing the ‘Microsoft.CodeAnalysis’ package.
Using the APIs, we can iterate through all ‘*.cs’ files within a given directory and parse each file using the ‘CSharpSyntaxTree.ParseText’ method. This method turns the parsed file into a syntax tree that can then be analyzed.
using (var stream = File.OpenRead(path)) { var tree = CSharpSyntaxTree.ParseText( SourceText.From(stream), path: path); SyntaxNode root = tree.GetRoot();
In order to identify the classes that inherit from a Controller class, you can traverse the syntax tree and check the base type of the class.
public bool inheritsFromController(SyntaxNode root, String args) { bool isValid = false; try { isValid = root.DescendantNodes() .OfType<BaseTypeSyntax>().First().ToString() .Equals("ApiController") || root.DescendantNodes() .OfType<BaseTypeSyntax>().First().ToString() .Equals("Controller"); }
Retrieving the class declaration for the Controller and all of its public methods can be performed using the following code.
ClassDeclarationSyntax controller = root.DescendantNodes().OfType<ClassDeclarationSyntax>() .First(); //Get all the public methods in this class IEnumerable<MethodDeclarationSyntax> methods = from m in root.DescendantNodes() .OfType<MethodDeclarationSyntax>() where m.Modifiers.ToString().Contains("public") select m;
Now that the Controller and its public methods are enumerated we can extract the attribute assigned at both the class and method levels. The attributes can be retrieved by reading the ‘AttributeLists’ value of the ClassDeclarationSyntax and/or MethodDeclarationSyntax objects.
Public methods with a route defined are potential entry points to the application and can be invoked through HTTP requests. Before invoking the code within the method, the request will be processed by the filter attributes defined globally, at the controller level and at the method level.
.NET MVC Enumeration tool
We are releasing a tool that utilizes the Roslyn API to automate the enumeration of .NET MVC controller entry points. The tool runs against a given directory and identifies:
-
All classes that inherit from a Controller class
-
All public methods within Controller class
-
Attributes assigned to a method including the ones set at the class level
The basic usage of the script is as follows:
> DotNetMVCEnumerator.exe -h Usage: DotNetMVCEnumerator.exe [-d Directory To Scan *Required] [-a Attribute Name to Search] [-n Attribute Name To Perform Negative Search] [-o File Name to Output Results as CSV] [-h Display Usage Help Text]
Sample Usage 1 – Scan code within a directory and write output to the ‘results.csv’ file.
> DotNetMVCEnumerator.exe -d “C:\Code” -o results.csv
Sample Usage 2 – Scan code and only include results of methods containing the ‘CSRFTokenValidate’ attribute filter. The output is written to the console and to the ‘results.csv’ file.
> DotNetMVCEnumerator.exe -d “C:\Code” -o results.csv -a CSRFTokenValidate
The tool is very useful to quickly identify any methods that may be missing authorization controls enforced through filter attributes. The CSV output is very helpful during manual code reviews in order to:
-
Quickly identify test/debug or administrative functionality that is accidentally exposed based on the name of the Controller or method name or URL route path.
-
Identify classes that are missing filter attributes and therefore may be missing the enforcement of security controls.
-
Keep track of your manual code review progress by leaving comments in the spreadsheets as each external entry point is reviewed.
Excel can be used to perform column based filtering based on your needs.
The source code and binary for the tool can be found on our Github repository:
https://github.com/GDSSecurity/DotNET-MVC-Enumerator
Author: Pryank Nigam
©Aon plc 2023