Remember view state? This was the massive kludge of hidden input data in an ASP.NET web forms page which tried to create quasi-persistence between requests in what is otherwise the stateless world of HTTP. Actually saying “was” isn’t that fair as indeed web forms apps make up the vast majority of ASP.NET sites out there today, but Microsoft’s implementation of MVC tends to be viewed as the new shiny thing that many of us have gravitated towards in recent years. That said, when I created my recent Pluralsight course on ASP.NET Security Secrets Revealed, I must admit to marvelling just a little at some of the tricks view state has up its sleeves.
Moving on, last year I wrote about Understanding (and testing for) view state MAC in ASP.NET web forms which explained how data in the view state was verified by the server when the browser posts it back using a “Message Authentication Code” or MAC. Incidentally, the context of that post was about not disabling MAC and indeed as I prophesised in that post, Microsoft have just disabled the ability to disable it in .NET 4.5.2. But the real story in that post with relevance to what I’m about to share here is this: by default, view state is not encrypted and can be read by anyone.
That's why this view state is such a problem:
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUJODA1MTI0Mzk4D2QWAmYPZBYCAgMPZBYEAgMPZBYCAgEPZBYCAgEPEGQQFQUNUGxlYXNlIFNlbGVjdCxUZWFjaGVycyBvZiBzdHVkZW50cyByZWNlaXZpbmcgaG9tZXdvcmsgaGVscC1TdHVkZW50IGludGVyZXN0ZWQgaW4gcmVjZWl2aW5nIGhvbWV3b3JrIGhlbHAPVm9sdW50ZWVyIHR1dG9yGlRlYWNoZXIgb2Ygdm9sdW50ZWVyIHR1dG9yFQUBMANQTlQDUE5TBFBOVFQFUE5UVFQUKwMFZ2dnZ2dkZAIFD2QWAgIBDzwrAAsBAA8WCB4IRGF0YUtleXMWAB4LXyFJdGVtQ291bnQCAh4JUGFnZUNvdW50AgEeFV8hRGF0YVNvdXJjZUl0ZW1Db3VudAICZBYCZg9kFgQCAQ9kFgRmD2QWAgIBDw8WAh4EVGV4dAUFU2NfSWRkZAIBD2QWAgIBDw8WAh8EBQg1MDAwMDA5NmRkAgIPZBYEZg9kFgICAQ8PFgIfBAUPZGJDb25uZWN0U3RyaW5nZGQCAQ9kFgICAQ8PFgIfBAVDVXNlciBJRD1nY207cHdkPWwwY2tlZHVwO0luaXRpYWwgQ2F0YWxvZz1uU3RlcDI7RGF0YSBTb3VyY2U9U1FMTUFJTmRkZNCELsk5YxBaWJIoYpQ8Bqz9Ip2QyhSnfXcau1LNtd5w" />
Let's come back to that in a moment, first I’d like to walk you through where this has come from and why it’s a problem.
Discovery
Near on any page with a .aspx extension is going to have a big whack of view state in the HTML source which looks just like the one above. Now remember, this is sent to your browser by the site so it sits there on your machine. You have access to it simply by loading a web page, this is not about going and probing away at vulnerabilities.
A page just like this has view state, in fact it has the view state you see above:
This is the registration page for Study Buddy. Now because the view state is simply Base64 encoded data, it means you can use a tool like the View State Decoder to get this:
And then the data from the controls on the page that have the default view state behaviour:
There’s nothing wrong with this, it’s just a means of persisting data between requests and there’s an HMAC to ensure it hasn’t been tampered with (assuming that it hasn’t been disabled). This, however, is not such a good idea:
Yes, that is what it looks like – a connection string in plain text. This has been programmatically set by code, that is someone has consciously said “You know what’d be a good idea? We should send the database connection string down to the client”. This is not just simply a matter of a control automatically persisting data via view state, rather it’s a deliberately coded decision. In theory, this would be enough to get you directly into the database behind the app and do… well pretty much anything. That’s a very serious risk – potentially.
The fix
There are two really, really easy fixes for this:
- Enable encryption on the view state. This is dead simple and puts an immediate stop to this risk as the view state is no longer remotely decipherable. It’s just a configuration setting in the web.config and it’s job done.
- Don’t store sensitive data in view state! Why anyone would want to put a connection string in view state is beyond me, but here’s a simple trick: if it’s not there, if can’t be grabbed just by copying it out of the source code! Seriously, if you’re putting anything sensitive in view state you’re almost certainly doing it wrong.
Easy, isn’t it?
Disclosure (and why nobody wants to listen)
Working out what to disclose, when to do it to whom and for what reason can be dicey. I’ve written about The responsibility of public disclosure before and shared stories of how frankly, very little gets done until stuff goes public. That said, each situation is unique and in this case I really wanted to get through to Study Buddy privately. Before I explain what happened (or didn't happen), it’s worth noting that the connection above refers to an internal data source name and that the URL it’s on doesn’t have port 1433 open to the public. In many cases you could just directly connect via the exposed connection string but fortunately that’s not the case here, at least not on that domain name using the default SQL Server port.
Moving on, this risk was privately disclosed to me last month and it was prefaced with this note:
I don't think they will be fixing it any time soon as the following was sent to exgenex on 12/3/2011
Now I’m not sure whether that was in March or December 2011 but either way, that’s a hell of a lot of water under the bridge. Regardless, I emailed Study Buddy over three weeks ago on the address on their website and… nothing. So I tweeted them a couple of weeks ago too and… nothing.
But of course I’m interchangeably referring to two separate organisations here: Study Buddy who are the ones you’re registering with and then there’s Exgenex who appears to be standing up the service on a separate domain. So let’s get in touch with them and exgenex.com goes off to thepulsenetwork.com so we’ll give them a go via their contact form. I get an immediate response:
Thank you for contacting The Pulse Network. If this is a customer service request, someone will respond to your request within 24 hours. All other requests will be answered within 48 hours.
And then I get… nothing. Time comes, time goes, so I tweet them as well and many days and many contact attempts by different people to different organisations via different means later, here we are.
Where there’s smoke…
Problem I often find with security is that such a glaring vulnerability is often a sign of other risks as well. At the very least, the practice of using view state in this way has probably been repeated in other resources on that register03.exgenex.com domain. It quite likely also exists in other assets The Pulse Network has created (assuming it’s them, I don’t know, they never got back to me!) But of course that’s all the same risk, the concern I would have is that if they don’t understand the serious ramifications of using view state in this way, what else don’t they understand? It might sound like a stretch, but time and time again I repeatedly see the pattern of one low-hanging risk suggesting there are more ripe for exploit.