Before I begin, I would like to say that, the actual reason behind the hue and cry about this vulnerability is the fact that the Microsoft Security Advisory 2416728 quoted that this vulnerability can be "further exploited to view data, such as the View State, which was encrypted by the target server, or even read data from files on the target server, such as the web.config file".
Though, there is no available exploit code in the internet that allows us to check the legitimacy of the above statement but it is true that a vulnerability and exploit code that has been disclosed in such a professional manner would definitely not be released to the public. Although, there are tools and scripts such as POET, PadBuster, AspNetPaddingOracleDetector etc. but they fail to justify what Microsoft has quoted in their Security Advisory and it is acceptable that a public release of the actual exploit code will trigger a sudden burst of malicious activities. Seeing the issue from this perspective lets see, how even without the exploit code in place, we can still try to identify if our ASP.Net applications are vulnerable or not.
Before I move on to the steps, let me quickly give a brief idea about one of the most important factors that aid this exploitation mechanism as this will be the key to our manual judgemental skills.
- When we send a request to the ASP.Net application, it carries ciphertext (__VIEWSTATE parameter, Cookie parameter etc) with it. For some reason, if the ciphertext is invalid, an exception will be thrown, and the system may act according to one of the following scenarios:
- Returns a 500 Internal Server Error
- Returns a 404 Not Found Error
- Return the ASP.Net Yellow Screen Of Death (YSOD) Exception page with or without Stack Trace depending on customErrors settings in the web.config
- Return a page stating only the exception’s message
- Return a constant page, stating there was an error, without providing detail. This is actually the Microsoft’s workaround
- The default ASP.Net way of taking the user to the login page and swallowing the exception completely without displaying any error
Now, it is these behaviors that will help us to identify if our ASP.Net application is vulnerable or not and if the workaround proposed my Microsoft is helping our application to refrain itself from giving hints of its vulnerability to the attacker. Though, the vulnerability would still remain, but it would take the sting off by at first not letting the attacker know of its vulnerability.
The below image shows the requests made on a sample ASP.Net blog application. I would explain each of these requests and responses.
Request 1 to Request 3 is highlited in red and Request 4 to Request 8 is highlited in green. The requests highlited as red means the application's web.config was not set in the way that Microsoft recommended and the requests highlited as green means the application's web.config was set as per Microsoft's recommendation.
Explanation:
Condition 1: Web.Config doesn’t redirect to a single error page. CustomErrors section reads <customErrors mode="On"/> or <customErrors mode="RemoteOnly"/>
Request 1: When we made a request to the application with a valid ciphertext "GET /Blog/WebResource.axd?d=R7QyY48orpGSFdUDj4AslA2" the application gave the response "200 OK"
Request 2: When we made a request to the application with an invalid ciphertext "GET /Blog/WebResource.axd?d=test" the application gave the the response "500 Internal Server Error" because its an invalid ciphertext.
Request 3: When we made a request to the application with no ciphertext "GET /Blog/WebResource.axd?d=" the application gave the the response "404 Not Found" and also said that " The resource cannot be found" because our request didn’t had a resource request encrypted as a ciphertext.
So we see that the application has behaved in three different ways for three different GET requests.
Condition 2: Web.Config redirect to a single error page. CustomErrors section reads <customErrors mode="On" defaultRedirect="error.aspx"/>
Request 4: Same as Request 1. Since it’s a valid request, the application responds with the response "200 OK"
Request 5: The request is same as Request 2 and since its an invalid ciphertext, it triggers an error "500 Internal Server Error" in the server, but since we have the customErrors module in the Web.Config to handle this, it sees that there is the error.aspx that it should serve, however, for redirection to that resource, it sends the response "302 Found" and also adds the Location header "Location: /blog/error.aspx?aspxerrorpath=/Blog/WebResource.axd" to the response so that the client knows its current location. Thus, what it has done is, it has supressed the "500 Internal Server Error" error.
Request 6: The client makes a request for the new resource that came with the previous response. In our case, it’s the "GET /blog/error.aspx?aspxerrorpath=/Blog/WebResource.axd". This request is processed and the error.aspx page served resulting in a "200 OK" response from the server.
Request 7: Similar way, when we request to the application with no ciphertext, it triggers an error "404 Not Found" in the server, but again we have the customErrors module in the Web.Config to handle this, it sees that there is the error.aspx that it should serve, however, for redirection to that resource, it sends the response "302 Found" and also adds the Location header "Location: /blog/error.aspx?aspxerrorpath=/Blog/WebResource.axd" to the response so that the client knows its current location. Thus, what it has done is, it has supressed the "404 Not Found" error.
Request 8: The client makes a request for the new resource that came with the previous response. In our case, it’s the "GET /blog/error.aspx?aspxerrorpath=/Blog/WebResource.axd". This request is processed and the error.aspx page served resulting in a "200 OK" response from the server.
What we have seen is, in simple words, if the application is throwing different errors for different scenarios then it reveals the vulnerability because, on the basis of the different error code that is returned by the web server the atacker can guess if the ciphertext was decrypted properly. By making many such requests (and watching what errors are returned) the attacker can learn enough to successfully decrypt the rest of the cipher text. Thus, if the application is showing different errors like the above three requests (Request 1 to Request 3) then its revealing its vulnerability.
Furthermore, for added safety, it is recommended that the error.aspx should have a random, small sleep delay. This will obfuscate the time required to serve the error.aspx on even of an error, thus obfuscating the nature of the error further.
The code of the error.aspx with the random sleep delay can be found on the Microsoft Security Advisory 2416728 page.