Tuesday, September 28, 2010

Investigating .NET Padding Oracle Exploitation with padBusterdotnet

Everyone in the security industry has crashed into the amazing research of T. Duong and J. Rizzo of Netifera Security named Padding Oracle Attacks. This research hit the media again some days ago because also Microsoft .NET Framework was found extremely vulnerable to it.

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 16
Where:
./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:
{
string strx;
string str = queryString["d"];
...
try
{
str2 = DecryptString(str);
}
catch(CryptographicException exception)
{
    throw 404(exception);
}
return strx;
}
As you can see from the previous code Crypto errors are handled as 404 errors; application errors will be spawn as 500 error codes. . 

In framework 3.5 sp1 and above ScriptResource.axd has an even different error handling routine. Pseudo code is:
{
string strx;
string str = queryString["d"];
...
try
{
str2 = DecryptString(str);
}
catch(exception)
{
    throw 404(exception);
}
return strx;
}
All errors are 404 exception and the Padding Oracle is turned off if you do not use a "T" block as prefix.


How to check if my site is vulnerable?

To check if your site is vulnerable make the following requests:
  1. http://www.mysite.co/notexistentpage.aspx - if you have verbose messages you are vulnerable since "customerrors" are not enabled
  2. Check 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
  3. 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!
  4. Update... Try the following script (thanks to Bernardo Damele for testing it accurately!): Check Patch
How to download Web.config from the virtual path?

 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

23 comments :

  1. Hi Georgio,

    Thank 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?

    ReplyDelete
  2. Hi Georgio,

    one 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

    ReplyDelete
  3. kudos Man, for releasing this 0day exploit!

    ReplyDelete
  4. @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.

    In 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).

    ReplyDelete
  5. @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.

    ReplyDelete
  6. When encrypting using the padding oracle, you have to start from the last block.
    As 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

    ReplyDelete
  7. Hum, blocksize should be 8 for 3DES and 16 for AES
    Depends on what you configured in web.config :)

    ReplyDelete
  8. The block size is 16 for AES encryption, but remains as 8 for 3DES encryption.

    ReplyDelete
  9. @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.

    For making it easier to use, I have added a IV with fixed number of nullbytes. It will be soon up again.

    ReplyDelete
  10. @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.

    # 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;

    ReplyDelete
  11. OK, slight misunderstanding, I'm not speaking about decryption which is trivial
    I'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)

    ReplyDelete
  12. the -plaintext encryption not working well with 3DES nor AES.
    encryption "q|~/web.config" gives "=�� � `z��f�x��q|~/web.config"

    ReplyDelete
  13. @freesrvs: yes, this is the output at the moment you get from our tool. This is also the problem that was mentioning @anonymous.

    We will release some patches to get rid of that.

    ReplyDelete
  14. ok another question, can this apply also to viewstate to determine the intermediate value?

    ReplyDelete
  15. @freesrvs, @Anonymous:

    Assuming 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...

    ReplyDelete
  16. 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.

    1) 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

    ReplyDelete
  17. 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.

    ReplyDelete
  18. when i use padbuster i always get status 301 responses. the target shows a costum error page when loadin site.com/webresource.axd

    so it might be a false positive and the site is not volnerable to the padding oracle , am i right ?

    ReplyDelete
  19. 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?
    Can you decrypt the ViewState? or what?

    Thank

    ReplyDelete
  20. @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.

    It's important to say that viewstate cannot be replayed if MAC is enable (default)

    ReplyDelete
  21. 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
  22. @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.

    ReplyDelete
  23. What 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