Link Search Menu Expand Document

Server-Side Request Forgery in .NET

Vulnerable Example

In this example, the /avatar API is used to update the user’s avatar with a user-supplied URL. The reasoning is that the JavaScript web front end will always fill in the field, choosing among some possibilities (such as gravatar, tumblr, twitter, google).

https://www.vulnerableapp.com/avatar?url=https%253A%252F%252Fapi.twitter.com%252F1.1%252Fusers%252Fshow.json%253Fscreen_name%253Dusername

The value of the url parameter is the following Twitter API value: https://api.twitter.com/1.1/users/show.json?screen_name=username url-encoded two times; this accounts for the first URL-decode, which will take place inside our web server, and the second URL-decode, which will take place in Twitter’s server. Here’s the piece of code that retrieves the external URL.

WebRequest request = WebRequest.Create(inputURL);
WebResponse response = request.GetResponse();

The code is vulnerable as it trusts the attacker input of the full URL; an attack vector such as the following url=file:///etc/passwd will return the content of the file to the attacker (in Windows, the equivalent syntax is url=file:///C:/path/to/file)

Prevention

If the list of permitted URLs is known, implement an allow list. In the same example above, the new API will be invoked in this way:

http://vulnerableapp.com/api/avatar/update?external=true&url=1&user=screen_name%3Dusername

In the above URL, the user parameter contains both the name and the value of the parameters to be sent to the Twitter API; the %3D is the URL-encoded version of the = character. If the actual = character has to be sent to the third party URL, it must be encoded twice inside the value of user.

enum AvatarURL
{
    Twitter = 0,
    Gravatar = 1,
    Google = 2,
    Facebook = 3
}

Dictionary allowedURLsForAvatar = new Dictionary();
allowedURLsForAvatar.Add(AvatarURL.Twitter,"https://api.twitter.com/1.1/users/show.json");


AvatarURL avatarURLEnum;
Enum.TryParse("0", out avatarURLEnum);
string safeURL = "";
allowedURLsForAvatar.TryGetValue(avatarURLEnum, out safeURL);

if (safeURL == null){
	// Return an error message
} else {
	...
	// build and use the final URL
	string finalURL=safeURL;
	if (user != null) {
		// account for encoding
		string paramName = System.Web.HttpUtility.UrlEncode(user.Split("=").First());
		string paramValue = System.Web.HttpUtility.UrlEncode(user.Split("=").Last());
		finalURL += '?' + paramName + '=' + paramValue;
	}
	...
}

References

OWASP - Server Side Request Forgery Acunetix - What is Server Side Request Forgery Dzone: The Server Side Request Forgery Vulnerability and How to Prevent It