Or an example Padding Oracle attack in 100 lines of C# code.
This post has been in my outbox for weeks, since I did not want to make it generally available before the patches were released. Now that the patches are being pushed on Windows Update, and I also see that there are a couple of blog entries already providing the same details, I hope that making the source available would help developers understand how the exploit worked.
There’s been several web postings citing the vulnerability of ASP.NET, but few have tried to explain it. Here’s my attempt to simplify it for you, dear reader, complete with C# code to perform the exploit on a padding oracle. There are two kinds of attacks that I’ll be describing – the easier one is a decrypting attack, where the plaintext for encrypted data is obtained, and the more difficult one is an encrypting attack (where a forged encrypted request is sent).
None of the information I present here is secret, and all the steps can be obtained by thoroughly understanding the public documents describing how an exploit is performed. None of the documents I’ve read specifically exploits ASP.NET, but coupled with knowledge on how ASP.NET works (Reflector helps a lot), an exploit program can easily be crafted. The first and second documents are practically the same. The third document describes the attack in more practical terms.
Contrary to what’s inferred in several blog posts, none of the papers successfully describe an encryption attack on ASP.NET. Rizzo’s paper offers hints to how we can perform an encryption attack (not easy), but given enough time and HTTP requests by the attacker, it can be done. I’ll describe the special case where the attacker can download any file from certain ASP.NET web sites using an encryption attack. Update 10/13/2010: The PadBuster application in the third site above has been updated to use an encryption attack.
There are two padding oracles that I’m aware of in ASP.NET, there may be more. The first oracle is the WebResource.axd handler. It throws an HTTP 500 error if a padding error is encountered and either HTTP 200 or HTTP 404 if there isn’t a padding error. The other one is ViewState decryption, but I did not investigate further on the second one, and most sites do not encrypt view state – that is, they just don’t place sensitive information in the view state and avoid the encryption/decryption. Contrary to what’s been mentioned out in the net, the ScriptResource.axd handler is not a padding oracle. The code for ScriptResource catches a padding error and returns an HTTP 404 in its place. The ScriptResource handler, however, is what’s exploited in attempting to download any file from the web site.
The first fix has to be on the WebResource handler, to make it behave the same way as the ScriptResource handler (that is, catching the padding exception and returning an HTTP 404). The processing code for ViewState may need to be fixed as well (like I mentioned, I didn’t explore the ViewState attack vector). I will also make the assumption that the encrypting method is known (and the attacker knows what the cipher block size is). This is typically 3DES or AES, but it’s just an additional step to check if the attack works for one or the other.
Finding The WebResource Padding Oracle.
First is to find an existing ciphertext for a request to the WebResource handler. Inspection of the generated HTML page from an ASP.NET application can easily find this. Even the simplest ASP.NET application will include a WebResource request to the embedded “WebForms.js” resource. The decrypted form of that request parameter is “s|WebForms.js”. It doesn’t have to be that specific request – any WebResource request will do, because we know that it’s a valid request to the ASP.NET application.
Performing The Decryption Attack.
With a known valid ciphertext, we use that ciphertext as the prefix blocks for a padding oracle exploit. I won’t go into detail into the mathematical aspects of this (it’s all described in the papers). Suffice to say that we perform a padding oracle decryption attack by sending several “known ciphertext” + “garbled block” + “ciphertext block” to the server. Decrypting a single ciphertext block will take at most n*256 requests, where n is the number of bytes in a block. For 3DES-based encryption, that’s a small 2000 requests per block.
Performing The Encryption Attack.
The papers and the “padBuster” utility available for download around the net assumes that the initialization vector (IV) is controllable by the attacker. It may be true on some systems, but not on the other flaw with ASP.NET (described next).
There is this big vulnerability in one of the HTTP handlers that came out with ASP.NET 3.5. Specifically, the ScriptResource.axd handler allows download of any file within your application directory. But only if an attacker can figure out what the encryption key to use in encrypting the download request. Assuming an attacker can find what the encryption key is, what would the plaintext look like? A plaintext request for a file in the application directory looks like one of these:
The different prefixes indicate different variations of the request (whether the downloaded stream should be gzip’ed and such). The path could also be an absolute path instead of an application-relative path.
If the attacker does not have the encryption key, and the IV is the prefix of a request to ScriptResource, then it’s easy for an attacker to craft such a request by first performing a decrypting padding oracle attack for the last block of the request against an existing ciphertext block. Given the intermediary bytes for the last block, the ciphertext block for the second-to-the-last block is derived, and another decrypting attack is made on it. The chain is followed until the first block, where the IV is derived and the IV sent as a prefix. This would only involve about 4000 requests to the padding oracle since the length of the desired attack request is only two 3DES blocks (or one AES block).
That’s only if the IV were sent as the prefix to the encrypted block. It isn’t. Not for the ScriptResource handler.
Specifically, the attack request will be composed of: “prefix” + “garbled block” + “||~/Web.config”.
Because of how the ScriptResource handler processes the request, the garbled block could be ignored and the subsequent part of the request for the file download is honored. This causes the attack to append the contents of the requested file into the rest of the results.
If the attacker can not find an existing ScriptResource usage that has the “Q|” prefix, then it comes down to being able to craft a ciphertext block that would correspond to having a 2-character prefix of “r#”, “R#”, “Q#”, or “q#”. This is not trivial, but still boils down to only being able to forge a single block. Because of the nature of block cryptography, a block with the correct prefix could be forged in at most 256*256/4 (~16000) attempts. Once that single block is forged, then it can be used as the prefix to the attack request where there is still a garbled block in the middle and a file download at the tail end of the attack. The attack request will be composed of: “prefix” + “garbled block” + “|||~/Web.config”.
16000 HTTP requests. 8000 requests on average. It’s not a big number and can be done in a matter of minutes.
The provided code has more inline comments on it. The constants in the code should be substituted with what’s obtained from visual inspection of the generated HTML file for a page.
Great write up and accompanying code.
In a lab test the retrieval of web.config using the method: “prefix” + “garbled block” + “|||~/Web.config” was successful.
Just trying to retrieve other files from the web application and not having any success.
For example, “|||~/App_Data/test.txt” where the test.txt does exist but cannot retrieve. Is there a different format for accessing files in sub-directories?