Cross site scripting is a technique that allows a malicious party to interact with a user within a website, performing actions on the users behalf, stealing data all without the users knowledge.

XSS

XSS allows us to bypass the same origin policy, where the data stealing or actions on the behalf of the user come in, and can be quite devistating in their efficiency. There are three types of XSS: reflected, stored and DOM based.

Stored XSS is when we are able to save data to a database or any data store that is then reloaded each time. An example is the anonymous post to a blog and the <script>alert.. popup.

Reflect XSS is where the query is returned to the user like the example below. This attack must be delivered to a user not through visiting of the site, but say, a successful phishing campaign. The user can be sent a link like http://localhost/Blog?search=<script>/*do bad things*/</script>

DOM XSS occurs where an element in the Document Object Model is used for input to allow code to be executed in the browser.

public IActionResult Blog(CommentViewModel comment)
{
    Comment newComment = new Comment();
    newComment.Text = comment.Text;
    commentsRepository.Save(newComment);

    return RedirectToAction("BlogView");
}

Here we see c# code to take the comment and save. Notice comment.Text is saved regardless of what is there. No sanitization takes place. The following is the view, where equally bad we use the razor helper @Html.Raw().

<div class="col-sm-11">
    <div class="clearfix">
        <b>@Html.Raw(item.Username)</b> <span>made a post</span>
    </div>
    <div class="clearfix">
        at <small>@Html.Raw(item.CreatedAt)</small>
    </div>     
    <div class="clearfix" style="padding: 0.5em">
        @Html.Raw(item.Text)
    </div>
</div>

Here we can simply use @Html.Raw(HTML.Encode(item.Text)) or even the less secure @item.Text which is partially encoded but bypassable as it uses blacklisting. A full set of actions must be put in place to ensure we do not allow this vulnerability on the server, in the app and within the view (browser).

The big idea here is Defense in Depth. That is a multi-layered approach, that allows one area to fail, while still protecting the data. What should be most clear in any of the attacks observed thus far, is we can never trust user input. More on this later.

Within the application, or on the server in the website config or farther, at the web server level, some policies must be set.

<customHeaders> // in web.config  
            <add name="Content-Security-Policy" value="'self' URL" /> 

</customHeaders> 

Within C# we can ensure our string fields are protected by adding, as an example, regular expressions to a model.

public class PersonModel  
{  
   [RegularExpression(@"^\d{9}|\d{3}-\d{2}-\d{4}$", ErrorMessage = "Please enter a valid SSN")]  
   public string SSN { get; set; }  
} 
// We can also specify the content type and character set used in a number of ways. In C#
[HttpGet]  
public HttpResponseMessage GetData(string fileName)  
{  
   var dataResponse = Load();  
   var response = Request.CreateResponse(HttpStatusCode.OK);  
   response.Content = new StringContent(dataResponse .ToString(), Encoding.UTF8, "text/csv");  
   return response;  
} 
//encode URL parameters in the case of reflected xss
var example = "\"Quoted Value with spaces and &\"";
var encodedValue = _urlEncoder.Encode(example);

Finally, the antiXSS package on nuGet is an excellent option to help mitigate this issue.

SSTI

Server side template injection (SSTI) is often mistaken for XSS, but SSTI is far worse as the code is executed on the server, almost always leading to remote code execution. Thus a potential pivot point into a network. Many web frameworks use templates, as they help in the display of dynamic content.

  [HttpPost]
  [ValidateInput(false)]
  public ActionResult Index(string razorTpl)
  {
      ViewBag.RenderedTemplate = Razor.Parse(razorTpl);
      ViewBag.Template = razorTpl;
      return View();
  }

// display using the following code

<form action="" method="post">
    <textarea name="razorTpl" cols="75" rows="10">@ViewBag.Template</textarea>
    <br />
    <input type="submit" value="Preview" />
</form>
<hr />
@if (ViewBag.RenderedTemplate != null)
{ 
    <p>
        @Html.Raw(ViewBag.RenderedTemplate)
    </p>
}

Our controller takes a string, parses the string and then returned back a view. That view is used as the template and we can achieve code execution because of this.

It is worth recalling that asp to asp.net winforms to asp.net mvc has slowly changed the web view engine, now using the simple @C# code reference. In this example, we could really do anything here, as the code is fully under our control. While this example is somewhat contrived and finding real world examples is much harder, it is worth noting in its simplest form.

Insecure Deserialization

Insecure Deserialization involves XML, or JSON being deserialized and in the process, referencing code that can provide code execution.

Back in the day of WinForms apps, desktop development at an engineering firm I worked for, we often had a program and needed to store it’s inputs and outputs.

[Serializable]
class MyProgramData {

public string ImportantData {get; set; }

}

Now this could be saved and deserialized and put right into a model. The program continues working and the user completes his or her tasks. Along this same example, let’s say we have some JSON data for a website in a model.

public class DeserModel
{
   [JsonProperty(PropertyName = "body")]
   public dynamic Body { get; set; }
}

//Next we have a controller
[HttpPost]
public void Post(DeserModel body)
{
   Console.WriteLine(body.Body);
}

There is a tool called ysoserial that can generate payloads for this type of situation.

Let’s break this down, first we can see we are in fact using a JSON format. Next we can see references to three types (ObjectDataProvider, ArrayList, and Process). We can see at the bottom the command and what is called, so here the command prompt should be called and pop up on the server.

Now we must use Burp Suite to Post to the server.

And on the server, we now have the command prompt.

In order to understand this, go back to the engineering example. When the file is deserialized, if a type is included instead of string, is that constructors code executed for the type? Here is a perfect example of using only primitive datatypes when serial/deserializing an object. Farther, ensure the user is authenticated, use the lowest privilege’s possible and use cryptographically strong library that can ensure the data is trusted.

These last two examples use an API. Let’s look at how to audit an API.

APIs

The API offers us a whole host of advantages for devs and users alike. To ensure they are secure, not only should we audit the code, we must also audit the endpoint via a tool like ZAP. Zap has a marketplace that can use add-ins like other tools, and can help us with GraphQL to WSDLS.

Once we have these Add-ins, we can scan a site as we did before. Check out all the add-in, besides the specific one you may need at a time, I highly recommend the Collection: Pen Testers Pack and Collection: Scan Rules Pack.