Summary

A vulnerable code snippet is used in many .NET applications and is even incorporated in a book on .NET "best practices". The vulnerability allows for remote code execution via unsafe deserialization.

Vulnerability discovery

Last week I was doing a security assessment for one of my clients and I found the vulnerability in an internal application. I sat down with the developer to check how the vulnerable code got in the codebase, and we found the code snippet to exists throughout the internet.

Vulnerability origins

Back in March 2005, a programmer and Microsoft employee Scott Hanselman released a blog post on overriding the LoadPageStateFromPersistenceMedium function to implement a custom compressed viewstate.

Note that the normal .NET viewstate is called __VIEWSTATE and this code names its parameter __VSTATE, which makes it easy to spot vulnerable websites.

In 2007, the code snippet was incorporated in a book with 5 listed authors: The ASP.NET 2.0 Anthology: 101 Essential Tips, Tricks & Hacks. It seems to have sold pretty well over the years. The vulnerable code can be read in chapter 15. The LosFormatter is used to serialize data. The code uses the format Deserialize(decompress(base64decode(__VSTATE))).

The code was created in a time when the normal .NET viewstate was also vulnerable to deserialization. This awesome write-up on .NET deserialization issues shows that .NET before 4.5 contained this vulnerability. Version 4.5 of the framework was published on 10/9/2012.

To sum up: the vulnerable code was created in a time when the normal .NET viewstate was also vulnerable. In 2012, the .NET framework automatically protected against this type of vulnerability in the normal viewstate, but this custom snippet for creating a compressed viewstate still had the vulnerability in it and was continued to be passed around on the internet to this day.

Exploitability

During the assessment, I simply used the tool YSoSerial.NET with the TypeConfuseDelegate gadget and of course the LosFormatter to gain administrative access to one of my client's servers. Creating a payload is as simple as a command like the following:

ysoserial.exe -g TypeConfuseDelegate -p LosFormatter -o base64 -c "echo spip"

And then one can just compress that payload and send it to the server as the VSTATE parameter.

The spread

Many websites only show a (compressed) viewstate after authentication, so it can be difficult to identify vulnerable websites. However, doing a simple code search with PublicWWW shows 1620 websites that use the VSTATE variable on their home page alone. NerdyData shows 388 pages, including some fairly high-ranking ones (<100k).

The much-used site codeproject.com copied the code from Scott Hanselman in 2006. The article has 72 5-star votes and the forum contains many questions on proper implementation. It's advertised on Sitepoint to "speed up your website!". It can also be found on experts-exchange and on StackOverFlow. It can also be found in some public code repos.

Recommendation

Check your codebase for this piece of code if you have a .NET application:

Request.Form["__VSTATE"]

Remove the code for compressing a custom ViewState and just use the default .NET ViewState options, which protect against deserialization attacks by default.

Impact

It's only a matter of time before someone starts indexing all websites that use the vulnerable compressed viewstate code. All their webservers can then be hijacked via straight-up code execution using standard tools like YSoSerial.

It's hard to automate this issues for arbitrary websites, since one would need to log in for most websites before they start saving a (compressed) viewstate in your browser. However, with a combination of manual work and high-end website indexing this should still allows for a fast-growing botnet for anyone who puts a little effort into it.