ASP.NET Web API
Newtonsoft.Json (11.0.2)
Microsoft.AspNet.WebApi.Client (5.2.6)
Microsoft.AspNet.WebApi.Core (5.2.6 )
ASP.NET Web API is Mircosoft’s recommended framework for building REST services on the .NET Framework.
A weakness in this framework might expose applications that use it to DOS attacks.
ASP.NET Web API framework takes care of de-serializing the input to the application and of serializing the output that is returned by it. The serialization of the output is done by the library Json.NET which fails to handle serialization of highly nested objects (ALEPH-2018004).
If a highly nested object is being returned by the application, a StackOverflowException will be thrown and the hosting process will be terminated immediately (see our blog post).
If an attacker can build a highly nested object in the system and then use the API to get this object, s/he can remotely crashes the application.
For example, if the API provides a way to build a tree structure by adding nodes iteratively and it also provides a way to retrieve the entire tree, an attacker can build a deep tree and then crash the application by requesting the entire tree.
Applications that contain such a pattern, will be vulnerable to a DOS attack due to poor implementation of the serializer that is used by the framework.
I reported this issue to Microsoft on July 30th 2018. A case was opened, but Microsoft closed it as “by design”.
I was surprised by this response. How can you design a framework that crashes the process by design when handling a highly nested object? I would expect it to return an appropriate error message.
Here is an example of API controller that crashes the application when being called with big depth (~2000):
using System.Web.Http;
namespace TestApp
{
public class TreeNode
{
public TreeNode[] Suns { get; set; }
}
public class TreeController : ApiController
{
public TreeNode GetTree(int depth)
{
TreeNode root = new TreeNode();
TreeNode iNode = root;
for (int i = 0; i < depth; i++)
{
iNode.Suns = new TreeNode[] { new TreeNode() };
iNode = iNode.Suns[0];
}
return root;
}
}
}