Some tools have been released to perform this particular attack, but no public tools at the moment work with .NET Ajax Framework as shown in the original .NET exploit video at Ekoparty conference.
To better clarify how this exploit originally worked, we spent some days in our labs studying the .NET Ajax libraries. We also started from the beautiful Padbuster tool coded by Brian Holyfield of Gotham Digital Science and we added some features in order to work with WebResource.axd and ScriptResource.axd .NET Handlers. We have created a tool called PadBusterdotnet.
Important Update: I'm happy that the publication of our mods, which were the first this morning, speeded up the publication of different private tools. Now Gotham Digital Science security has just released the new version of Padbuster (v0.2) which supports Net UrlToken Encoder/Decoder check it here.
Update 04/10/2010: Today Padbuster v0.3 now supports attacks against .NET applications to download files from the webroot. The attack for downloading Web.config is similar to the first attack we published two days ago, but it adds several important features to it. We suggest to read it!
How does Padbusterdotnet work
Padbusterdotnet is very similar to the original Padbuster. The main difference is that it uses a re-implemented version of Microsoft UrlTokenEncoder() and UrlTokenDecoder() functions. It also does not Urlescape() parameters by deafult.
How does Padbusterdotnet applies to .NET Ajax Handlers
Microsoft Ajax Handlers are publicly exposed by default and accept encrypted strings of data which are NOT signed. This means that could be possible to perform byte by byte substitutions from an original string and check response errors for guessing intermediate values.
The following is a command line practical example:
n0def@holycow:~/n0def$ ./padBusterdotnet.pl http://127.0.0.1:8083/HacmeBank_v2_WebSite/ScriptResource.axd?d=qMO75zQ9ISgn3xx5rRdJSy7gggYrjYwjnIPlXPs84bc1 qMO75zQ9ISgn3xx5rRdJSy7gggYrjYwjnIPlXPs84bc1 16Where:
./padBusterdotnet.pl ScriptResourceUrl EncryptedSample BlockSize
Which handler should I use? Webresource.axd vs Scriptresource.axd
Webresource.axd and Scriptresource.axd are very similar, except the fact that they have a different error handling code. So, if "customerrors = off" both handlers are practically the same.
Update 2/10/10: If "customerrors = ON" and 404 pages are handled differently from 500 pages, you should use WebResource.axd (Note: This is good for both Framework 2.0 - With Ajax 1.0 and for framework 3.5 Sp1). To abuse the padding Oracle with "Customerrors = ON" you need to use WebResource.axd with valid "d" encrypted data as prefix. "d" parameter to be valid for WebResource handler must contain at least a single pipe char "|" after decryption. In short terms use the tool with "-prefix" option. This was the approach used initially in the original attack video (POET vs .NET).
Update 3/10/2010: if you use the "T exploit" and remote site is running framework 3.5 Sp1 or above, you just need to bruteforce the first block with average 150 requests to decrypt any message. And you need to check just for 200 status codes. More info on the "T" block exploit.
Update 4/10/2010 More info on 200 vs 404 Status codes: Padbuster v0.3 and .NET attacks. This approach is more efficient because it uses the infamous "T" block for abusing the Padding Oracle.
To make things more complex (:D) the code of ScriptResource.axd was heavily modified during years. That's why we suggest to use all the approaches described above in this section to have the Padding Oracle speaking.
In framework 2.0 with Ajax 1.0 extensions the pseudo error handling routine in ScriptResource.axd is:
{As you can see from the previous code Crypto errors are handled as 404 errors; application errors will be spawn as 500 error codes. .
string strx;
string str = queryString["d"];
...
try
{
str2 = DecryptString(str);
}
catch(CryptographicException exception)
{
throw 404(exception);
}
return strx;
}
In framework 3.5 sp1 and above ScriptResource.axd has an even different error handling routine. Pseudo code is:
{All errors are 404 exception and the Padding Oracle is turned off if you do not use a "T" block as prefix.
string strx;
string str = queryString["d"];
...
try
{
str2 = DecryptString(str);
}
catch(exception)
{
throw 404(exception);
}
return strx;
}
How to check if my site is vulnerable?
To check if your site is vulnerable make the following requests:
http://www.mysite.co/notexistentpage.aspx - if you have verbose messages you are vulnerable since "customerrors" are not enabledCheck if the response to "http://www.mysite.co/notexistentpage.aspx" vs the response to "http://www.mysite.co/WebResource.axd?d=wrongstring" do match. If these 2 responses are different you are potentially vulnerable- Update... Patches are now available: Official Microsoft Patches ! Now workarounds can be easily bypassed1 or easily bypassed2. Check if patches are installed as Juliano Rizzo suggests here: check if MAC signature is present, if not, you are still vulnerable!
- Update... Try the following script (thanks to Bernardo Damele for testing it accurately!): Check Patch
This feature is available through ScriptResource.axd only in .NET Framework 3.5 Sp1 and above (Framework 2.0 cannot be abused in this way). You should issue a particular string - "R|~/Web.config" - correctly encrypted using Padbusterdotnet tool.
If you are interested in how to download Web.config remotely with Padbuster or Padbusterdotnet, read:
Breaking dot.net encryption With or Without a Padding Oracle
P.s. : Let me know if you find any bug, I'll try to improve it during next days :D
Hi Georgio,
ReplyDeleteThank you for the proof of concept. I was trying to figuring out if I was vulnerable or not. it seems so, and the tool may prove it.
The tool can also be used to forge custom encrypted payloads?
Hi Georgio,
ReplyDeleteone thing's not clear to me:
on JSF, IV is passed as 8 first bytes of the encrypted payload, so it's "easy" to forge a message
on ASP.NET, IV is not passed in the message and is actually 8 0x0 bytes
I tried encrypting the "magic string" to download a file, and in the resulting encrypted payload, the first 8 bytes were indeed garbage and the processing of this request failed on the server
decrypted request :
\x98_\x00\xc5H\xdb'.XXXXXXXXXXXXXXXXXXXYYYY
(replace X by magic string and Y by padding)
didn't have much time to work on this problem and, AFAIK, tihs problem's not solved here neither
kudos Man, for releasing this 0day exploit!
ReplyDelete@Anonymous: Thank you for your comment. I'm working on it. Since the IV is not passed, you should manipulate the first encrypted block, since the values are passed as the IV of the second block. You should have a message of at least 2 encrypted blocks.
ReplyDeleteIn this way you should be able to bruteforce the padding values. If you can brute successfully the last byte of the first block, you can presume that you have the encrypted value for 0x01. Now you can XOR it with the value you have obtained and you get the intermediate value. If you XOR the intermediate value with the original LAST byte of the first block, you should get a number that indicates the number of padded values (like 0x06).
@Anonymous: You should be able to continue like this. Another thing is about the blocksize of .NET CBC encryption. It should be 16 and not 8.
ReplyDeleteWhen encrypting using the padding oracle, you have to start from the last block.
ReplyDeleteAs the IV for block N is the encrypted value of block N-1, you don't have control over N-1.
If you could pass the IV, it wouldn't be a problem, but here, you end up with a block with IV 8*0x0 and I don't see how you can modify this
Or I didn't understand what you meant
Hum, blocksize should be 8 for 3DES and 16 for AES
ReplyDeleteDepends on what you configured in web.config :)
The block size is 16 for AES encryption, but remains as 8 for 3DES encryption.
ReplyDelete@Anonymous: Yes, you are right. I was trying the tool against a Target with AES enabled. The tool works correctly I just made a bug in the decoder section. As I explained previously if you know the value of the IV vector that should be enough.
ReplyDeleteFor making it easier to use, I have added a IV with fixed number of nullbytes. It will be soon up again.
@Anonymous: Try the tool, it decrypts also the first block. You do not manipulate the IV, but you manipulate the first encrypted block. Each encrypted block is the IV of the next block.
ReplyDelete# Create an null pad IV
my $ivBytes = "\x00" x $blockSize;
# Assume the first block is the IV this is a patch for .NET
$encryptedBytes = $ivBytes . $encryptedBytes;
OK, slight misunderstanding, I'm not speaking about decryption which is trivial
ReplyDeleteI'm speaking about encryption ;) (as you cannot provide the IV to ASP.NET, the first "newly encrypted block" normaly uses the IV 0x0*8 but the decryption only gives garbage)
the -plaintext encryption not working well with 3DES nor AES.
ReplyDeleteencryption "q|~/web.config" gives "=�� � `z��f�x��q|~/web.config"
@freesrvs: yes, this is the output at the moment you get from our tool. This is also the problem that was mentioning @anonymous.
ReplyDeleteWe will release some patches to get rid of that.
ok another question, can this apply also to viewstate to determine the intermediate value?
ReplyDelete@freesrvs, @Anonymous:
ReplyDeleteAssuming that you have 8 blocks:
1) You encrypt this payload with Padbuster "|||~/web.config". You will end with 2 blocks of |IV|block1|0padblock|
2) What is missing is that now you need to bruteforce the first block until you download Web.config.
Since we know that:
1) r#garbage|||~/web.config
2) R#garbage|||~/web.config
3) q#garbage|||~/web.config
4) Q#garbage|||~/web.config
You'll endup with: brutedblock|IV|block1|0padblock|
Are all valid blocks and anything that follows # gets ignored even if they are non UTF8 bytes. You need some thousand requests...
As the above example is the most generic, but very hard to solve, there are different easier ways that depends on what you already get from the application.
ReplyDelete1) You find a decrypted block with Padbuster that ends with a “#” comment and starts with “r”, “R”, “q” or “Q”. What comes after the “#” is a comment and is ignored.
first = q|~/myse
second = nesitvef
third = ile.js|#
fourth = comment|
so on….
So if you find an encrypted block as a whole that decrypted is like that. You can use one of the attacks I showed without the use of bruteforcing.
You can put garbage after the third block. The final string will decrypt to:
q|~/mysenesitvefile.js|#ajshgarbagehahsa|||~/web.config
2) The block ends with a “|” pipe. You need to bruteforce the garbage block until it decrypts to a “#” as the first character and you get the Web.config
Thanks for the great blog. After reading the blogs I have cleared all my queries about Padbusterdotnet, Webresource.axd and Scriptresource.axd. But I also read about the difference between PadBuster and PadBusterdotnet where it uses a re-implemented edition of Microsoft UrlTokenEncoder () and UrlTokenDecoder () functions. It also does not Urlescape () parameters by default.
ReplyDeletewhen i use padbuster i always get status 301 responses. the target shows a costum error page when loadin site.com/webresource.axd
ReplyDeleteso it might be a false positive and the site is not volnerable to the padding oracle , am i right ?
Hi, I have only a simple question I cannot find anywhere. What does this attack allow you to do if X-AspNet-Version is 2.0.50727 so minor than 3?
ReplyDeleteCan you decrypt the ViewState? or what?
Thank
@Anonymous: Yes you can decrypt the Viewstate or other information crypted with the MachineKey. Encrypted Viewstate String should be partially modified for this to work.
ReplyDeleteIt's important to say that viewstate cannot be replayed if MAC is enable (default)
Hi, So based on this blog post, is it suggesting it is not possible to retrieve the web.config file with padding oracle attack under .net 2.0?
ReplyDelete@Anonymous: exactly, it's not possible to retrieve the "Web.config" file in .NET 2.0. There are no available features that permit do download files. That features are available from .NET 3.5 sp1 onward.
ReplyDeleteWhat would be the format to retrieve a file in a sub-directory within the web application? e.g. |||~/site/sub-directory/site.config doesn't seem to work even though |||~/web.config works OK and the site.config file is known to exist.
ReplyDelete