ASP.NET Padding Oracle Detector

UPDATE: Patch available, forget the workarounds, install it now: http://weblogs.asp.net/scottgu/archive/2010/09/28/asp-net-security-update-now-available.aspx

If you develop or run an ASP.NET based site you need to be aware of a potential attack that has been reported widely, known as the padding oracle exploit whereby encrypted values can be systematically decrypted or encrypted ultimately allowing an attacker to log into a forms authenticated site as a user of their choosing or download arbitrary files. Troy Hunt has an excellent write-up of the crypto stuff at the core of the attack.

There are some immediate things you can do that ScottGu outlines which involve updating <customErrors> in your web.config. But I felt that there are plenty of ASP.NET sites out that have their own way of dealing with errors which may be vulnerable due to the way they report errors.

One example is Exchange Outlook Web Access (Exchange 2007 at least), which by default exposes the underlying error details (helpfully including a stacktrace no less!) in its default error page and therefore can be potentially used as a padding oracle.

E.g. https://exchange.example.com/owa/auth/webresource.axd?d=foo:

image

This error page is served up as a 200 OK so it can’t be mitigated by a load balancer easily.

Whether an attack can actually be escalated against OWA from this is unknown to me at this time, nor which versions would be affected. OWA might not be using standard Forms Auth etc, but I haven’t heard the definitive word on this. Some kind soul has published steps on how to mitigate this apparent OWA vulnerability on the ASP.NET forums.

Anyway, I looked the attack against ASP.NET general and came up with what I thought was some useful information and posted this on the ASP.NET forums:

I’ve done some digging and come up with what I think is useful information for you if you have a custom error handling solution in place instead of or as well as the usual ASP.NET <customErrors> stuff.

From comments on ScottGu’s post it seem to be that the main suspect to be the actual padding oracle is WebResource.axd (possibly other axd’s).

  • If you look in .NET Reflector at the IHttpHandler.ProcessRequest method in  System.Web.Handlers.AssemblyResourceLoader there’s a call to Page.DecryptString early on.
  • This is the thing that will cause a HTTP 500 status to be returned if it fails, e.g. if the padding, etc in Request.QueryString["d"] is invalid
  • If the attacker manages to get the padding right, then it continues on, ultimately to call throw new HttpException(404…)
    It’s this differentiation: is the padding correct (404) or not (500) that is at the root of the exploit: the padding oracle.

If your error handling returns exactly the same response for both – it masks the oracle. To test if you’re vulnerable externally, a simple test is to request both:

  • webresource.axd?d=foo
  • webresource.axd with no parameters

and check using FiddlerTool, or FireBug that the entire response is identical for both including the status and all the headers (except for the Date header I guess!).

Of course I may have missed something, but I hope this information helps you until the official fix comes out.

Using the script

To automate the above simple test I’ve written a little Windows Script Host script in JavaScript that can be used in a couple of ways:

  • double-click it and you will be prompted for a site URL
  • or invoke from a Command Prompt passing the site URL as the first argument. e.g.:
    cscript AspNetPaddingOracleDetector.js http://mysite.example.com

Here’s what it looks like if you point it at a site that may be vulnerable:

C:\>cscript //nologo AspNetPaddingOracleDetector.js http://mysite1.example.com
Testing site: http://mysite1.example.com/
MIGHT BE VULNERABLE: HTTP status mismatch

=== Response 1 ===
404 Not Found

=== Response 2 ===
500 Internal Server Error

And here’s what it look like if the site does not appear to be exposing an obvious padding oracle:

C:\>cscript //nologo AspNetPaddingOracleDetector.js http://mysite2.example.com/blah
Testing site: https://mysite2.example.com/blah/
Site might be OK: WebResource.axd is not acting as a padding oracle

Please use your judgement in interpreting the output and do not assume that you are safe/vulnerable based solely on its output.

To test Exchange Outlook Web Access typically you will want to run the script against the /owa/auth virtual directory, e.g. https://msexchange.example.com/owa/auth.

What about ScottGu’s script?

The difference between this script and the one mentioned by ScottGu is that this one actually does a simple test of your site from the outside to see if the mitigations you have put in place are likely to have helped you. For example you may have put an iRule on your F5 BigIP to mitigate the issue: this will help you test if that has been effective.

Plz send me teh codez

Download the script (right-click, save as) and just double-click it to try it out. Or view the script source on Google Code.

Hope that helps!

Follow @duncansmart on Twitter

Solving SMTP “554 Permanent scan failure” non-delivery errors

Recently some users started getting non-delivery reports (NDRs) from our Exchange server with messages like the following:

554 Permanent scan failure. Email Session ID: {4C209A7E-0-3A6A8C0-1FFFF}

Looking at the SMTP logs (C:\Program Files\Microsoft\Exchange Server\TransportRoles\Logs\ProtocolLog\SmtpSend) showed the offending sessions looking something like this:

* attempting to connect
+
< 220 mail.example.com ESMTP
> EHLO smtp.example.com
< 250-mail.example.com
< 250-8BITMIME
< 250-SIZE 10485760
< 250 STARTTLS
* 1600 sending message
> MAIL FROM:<Jo.User@example.com> SIZE=1061757
< 250 sender <Jo.User@example.com> ok
> RCPT TO:<A.N.Other@example.com>
< 250 recipient <A.N.Other@example.com> ok
> DATA
< 354 go ahead
< 554 Permanent scan failure. Email Session ID: {4C209928-2-3A6A8C0-1FFFF}
> QUIT
- Remote

Very odd as I couldn’t find any information about this “Permanent scan failure”.

Then looking at the SMTP message headers of messages that did get through (Outlook hides them away in the message properties as “Internet headers”) on the receiving side offered up a clue:

Received: from mail.example.com (4.3.2.1) by blah.example.com
(5.6.7.8) with Microsoft SMTP Server (TLS) id 8.1.340.0; Thu, 18 Mar
2010 10:17:49 -0400
Received: from smtp.example.com (HELO smtp.example.com) ([1.2.3.4]) by
mail.example.com with SMTP; 18 Mar 2010 10:19:34 -0400
X-CheckPoint: {4BA23672-7-3A6A8C0-7B6}
Message-ID: <CAC3AC395FD04CB1BB7DCEC764E7816E@example.com>
From: fred <fred@example.com>
To: <johndoe@example.com>
...

The CheckPoint firewall was injecting an ID into the headers which had exactly the same format as the “Session ID” from the ones that were failing with “Permanent scan failure”.

So unbeknownst to us CheckPoint was proxying/filtering the SMTP traffic and barfing on it for some reason.  When we switched off the SMTP checks that CheckPoint was doing (they weren’t required as we have another mail gateways in place) the problem went away.

Macro to Restart Visual Studio Elevated

Kevin Dente ponders on Twitter:

Wonder if it would be possible to create a Visual Studio add-in or macro that re-launches VS elevated, with the current project, then exits

This is something I’ve been meaning to do for a while, as often I’ll open a Web Application in Visual Studio configured to run under IIS and be met with the following:

The Web Application Project is configured to use IIS. To access local IIS Web sites, you must run Visual Studio in the context of an administrator account..

Running anything elevated is easy, you just need to call ShellExecute (the .NET equivalent is System.Diagnostics.Process.Start) with the “RunAs” verb, so it’s simply a matter of starting Visual Studio’s devenv.exe passing the path to the current solution.

So here goes: copy and paste this into a Macro Module (ALT+F11) then wire up to a toolbar button as appropriate:

Sub ElevateVisualStudio()

    Dim slnPath As String = DTE.Solution.FullName
    DTE.Solution.Close(True)

    Dim startInfo As New System.Diagnostics.ProcessStartInfo(DTE.FullName, slnPath)
    startInfo.Verb = "RUNAS"
    System.Diagnostics.Process.Start(startInfo)

    DTE.Quit()

End Sub

Works On My Machine™, etc and only tested on Visual Studio 2008.

Using Windows 7’s “XP Mode” to run IE 6, IE 7 and IE8 side-by-side

Windows 7’s XP Mode is essentially a Windows XP virtual machine that runs in the new Windows 7 version of Virtual PC. This new edition of Virtual PC includes cool features such as seamless windows. The main reason I’m interested in this is to run older versions of Internet Explorer for testing purposes. IE8’s compatibility mode does a pretty good job of emulating IE7 but there are differences, so I investigated how to get “real” IE7 running under Windows 7’s XP Mode, without losing IE6.

Out of the box, the Virtual PC image is Windows XP SP3 with IE6. The trick to getting IE6 to appear as a seamless window like this is to launch the Virtual Windows XP virtual machine and in the VM, create a shortcut in the “All Users” Start Menu or desktop:

image

After a short delay, the shortcut will be duplicated into the Windows 7 host’s start menu:

image

When you launch this shortcut in Windows 7, the main Virtual PC window will close and the application will be launched and projected onto your desktop.

Creating a VM for IE7

You can’t install IE7 side-by-side with IE6 on the same machine, so to run IE7 at the same time as IE6 we will need to create a new VM. Unfortunately, if you run the VirtualWindowsXP.msi setup again you’ll get a message saying “Setup has detected that Virtual Windows XP is already installed”:

image

The workaround is to create a new instance of the VM manually using the supplied VHD as the base disk image. To do this do the following:

Open the Virtual Machines folder from the Start Menu and click Create virtual machine:

image

Specify a name and location for the virtual machine:

image

For memory I specified 256MB, which should me more than enough for just running IE7:

image

Here’s the important bit. Choose “Create a virtual hard disk using advanced options”

image

…and then choose a Differencing disk. This is the same way that the default Virtual Windows XP VM is set up:

image

If you want, you can change the default name and location (I didn’t bother):

For the parent virtual hard disk choose the original Virtual Windows XP virtual disk, which on my machine was at C:\Program Files\Virtual Windows XP\Virtual Windows XP.vhd:

image

Now start the new Virtual PC you just created from the Virtual Machines folder and complete Windows Setup as appropriate, choosing a computer name unique for your network and an Administrator password:

image

When that’s done:

  • Enable Integration Features from the Tools menu of the Virtual PC window
    • For credentials enter Administrator and the password you entered during setup.
    • I chose to Remember my credentials for convenience
  • download and install IE7 in the VM,

When IE7 has installed and rebooted, create a shortcut to IE7 in the “All Users” start menu which, after a short delay, will create a corresponding shortcut in the Windows 7 start menu of the host.

image

So here’s the end result, IE6, IE7 and IE8 all running on Windows 7:

image

Ahhh, 3 generations, all together – don’t they look adorable?

Fixing WebSVN “Unable to call svn command” error

WebSVN is a great PHP web-based interface to Subversion that we run on our IIS build server. But, after updating to a more recent build we started getting errors like the following when viewing diffs:

Unable to call svn command "svn --non-interactive --config-dir /tmp"

The source of the error is in the getFileContents function in svnlook.php, where it’s piping the output of svn cat to GNU Enscript (for syntax highlighting) and then parsing the output of that using sed. I guessed that maybe the regex that sed is using isn’t being escaped properly for the Windows command line and therefore failing.

But I noticed that all of this code was in an if($config->useEnscript) block. Just before that is an if($config->useGeshi) block that looks a lot simpler. Simpler because GeSHi is PHP-based syntax highlighter, rather than an external command whose output requires special parsing. So I went to our include/config.php and added the $config->useGeshi(); call (as detailed in the distconfig.php template config file), and it all started working happily again!

Unzipping/extracting MSI files

If, like me, you are constantly wanting to just extract the files from a Windows Installer MSI file quickly, then this is for you.

My ZIP utility of choice 7-Zip appears to support extracting MSI files but in fact extracts all the various weird and wonderful binary streams in the MSI rather than simply just the actual files. Thankfully I stumbled across a Windows Installer switch today after typing msiexec /? that does the job perfectly: the /a “administrative install” switch, e.g.:

msiexec /a foo.msi /qb TARGETDIR="C:\TEMP\Foo"

So, what I’ve done is packaged this up as a little registry tweak that conveniently lets you do this by simply right clicking a file like so:

image

Copy and paste the following into a *.reg file and double-click it:

Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Classes\Msi.Package\shell\Extract MSI\command]
@="msiexec.exe /a \"%1\" /qb TARGETDIR=\"%1 Extracted\""

Hope that helps!

Fixing “Provider: Unspecified error” when querying LDAP with the ADsDSOObject OLEDB Provider

As part of our logon script we have a Windows Script Host script that was failing with “Provider: Unspecified error” (mmn, helpful) but only on some Windows XP machines.

The offending line of code looked like this:

rs = con.Execute("<LDAP://DC=example,DC=com>; (sAMAccountName="+ username +"); ADsPath; subTree")

After some trial and error the fix was this (see if you can spot the difference):

rs = con.Execute("<LDAP://DC=example,DC=com>;(sAMAccountName="+ username +");ADsPath;subTree")

Can you see what it is? No spaces after the semicolons!

Alternatively the SQL-like syntax also seems to be a bit more forgiving:

rs = con.Execute("SELECT ADsPath FROM 'LDAP://DC=example,DC=com' WHERE sAMAccountName='"+ username +"'")

It appears that with some later version of ADSI ADsDSOObject (or to give it its full title, the “OLE DB Provider for Microsoft Directory Services”) the query syntax strictness has been relaxed. In any case “Unspecifed error” appears to mean “Syntax error” in this case.

Follow

Get every new post delivered to your Inbox.

Join 35 other followers