The Multibillion Dollar Industry That's Ignored

This past fall at Derbycon 4.0 Ryan and I presented our research on video game cheats, anti-cheats and a bit about how the gaming industry doesn't really appear to care. We put some of our new Machine Learning knowledge we'd gained over the past year or so to the test and came out with some surprising results.

Here's the presentation on youtube:

Goodbye forever

Around 4 years ago (2010) failed to notify me that this domain was expiring and I lost it to some squatters who clearly had pre-paid to yank the domain from me. Recently they finally decided it was a waste of their money to keep my old domain name and now it's finally back under my control.

Sorry GoDaddy - you lost my business for good.

ASP.NET and the Padding Oracle Attack: Wrap-up

I'm no crypto expert (I do know the basics) and it's been a challenge to wrap my head around the nuances of this Padding Oracle vulnerability in ASP.NET.

Initially, based on the news that was released it sounded like an issue with AES since they never mentioned 3DES. It turns out that this was false and that this attack works against ANY BLOCK CIPHER meaning 3DES was also vulnerable. I suspected it was premature to suggest this as a valid mitigation technique at the time and said so, and it turns out I was correct at least about that part.

Microsoft posted that the work-around was to turn custom errors On because the attack needs to know "which error code was returned by the server" - from all of my discussions, research, and reading on this attack, it's clear to me that this is not going to completely solve the issue. All an attacker needs to do is INFER if encryption was successful or unsuccessful.

Now on Scott Guthrie's blog a series of 'mitigation' techniques have been released that will help, but still none of the actually get to the heart of properly solving the issue - which is fine since Microsoft should move to fix this in the Framework. The combination of techniques recommended will do a good job both slowing attackers down and not providing good information about successful/unsuccessful decryption - slowing down or stopping the oracle. So definitely take steps in this direction.

One thing we always stress in Software Security is Input Validation - systems need to be programmed to securely handle untrusted input that come from clients. The Forms Authentication Ticket is pushed down to the client and then get's submitted back to ASP.NET without checking to see if it's been modified or if it can be considered trusted. The problem with symmetric encryption, which is used to encrypt the Forms Auth Ticket, is that there's no way to know if the cipher-text can be trusted since it's just data blob - so ASP.NET happily accepts any data and starts crunching on that data before verifying that it can actually trust the data.

This is what a Digital Signature can be used for. Digital Signatures are based on both Asymmetric encryption (or Public Key Cryptography) and Hashes. Asymmetric encryption allows one party to encrypt data with their private key, a key no one else should know. Then anyone with their public key (a key that's safe to make publicly known) can validate the person in possession of the private key sent the message. This is done by decrypting the message with the public key.

A Digital Signature then is when a hash of the message to be signed is generated and then encrypted using the private key. This signature can then be included and used to check to see if the message was changed (HASH) and if it was signed (hash encrypted with private key) by the person who was in possession of this private key...

A good way to protect against the Padding Oracle attack against ASP.NET is to us a Digital Signature to sign the Forms Auth Ticket. Signing the Forms Auth Ticket with a digital signature would provide the following protections:

1. Detect if the Forms Auth Ticket was modified
2. Detect if the Forms Auth Ticket modification was unauthorized

If the Signature is invalid - throw it out -it's untrusted. This type of Input Validation could be applied to the Forms Auth Ticket as well as any other data encrypted and sent down to the clients. ASP.NET would not have to bother trying to decrypt the messages protected by the Symmetric key unless the signature could be validated, thus eliminating the oracle. This prevents anyone else from generating or attempting to generate Forms Auth Tickets except the ASP.NET web server server - so EVEN IF THE ATTACKER WAS IN POSSESSION OF THE MACHINE KEY, they still wouldn't be able to create a trusted Forms Auth Ticket without the asymmetric private Key used to encrypt the hash.

I suspect a HttpModule could be written to add signature data for Forms Auth Ticket Cookie, Role Cookies, etc. in ASP.NET and then validate them when they are submitted back to the client...

ASP.NET and the Padding Oracle Attack

UPDATE: Read my final analysis and wrap-up here:

The Padding Oracle attack affects all block ciphers that are configured to use CBC + PKCS7...and it's been demonstrated that both AES and 3DES are both vulnerable to this attack in ASP.NET. Once the machine key is recovered it appears that the Forms Auth Tickets (and any other encrypted element) can be decrypted and re-encrypted allowing a full compromise of any ASP.NET Web Site that relies on Forms Authentication. Additionally MS revealed that on Framework 3.5+, even arbitrary files could be retrieved from the web server due to this vulnerability, though I'm not clear as to why this would be possible:

"If the ASP.Net application is using ASP.Net 3.5 SP1 or above, the attacker could use this encryption vulnerability to request the contents of an arbitrary file. The public disclosure demonstrated using this technique to retrieve the contents of web.config. Any file which the worker process has access to will be returned to the attacker."

Watch this video on youtube POET vs ASP.NET: DotNetNuke to see Dot Net Nuke using 3DES getting Pwnt using 3DES with Custom Errors OFF.

It appears from the video that if Custom Errors are ON, then the Oracle isn't present and the attack may not succeed.

This is a serious vulnerability for ASP.NET web sites that have CustomErrors set to 'Off' - out of the box ASP.NET is secure, as it's default setting is 'RemoteOnly'.

More information as well as a script to detect web sites with CustomerErrors set to 'Off' here:

Vulnerability In .NET Crypto Puts ASP.NET Web Sites at Risk

UPDATE: Read my final analysis and wrap-up here:

ASP.NET web applications that leverage Forms Authentication, ASP.NET Membership Providers, ASP.NET Role Providers, and/or ViewState encryption are vulnerable to data exposure and potentially tampering. Details to be given this Friday, Sept. 17th at the ‘ekoparty Security Conference’ in Buenos Aires.

'Padding Oracle' Crypto Attack Affects Millions of ASP.NET Applications
"It's worth noting that the attack is 100% reliable, i.e. one can be sure that once they run the attack, they can exploit the target. It's just a matter of time. If the attacker is lucky, then he can own any ASP.NET website in seconds. The average time for the attack to complete is 30 minutes. The longest time it ever takes is less than 50 minutes," Duong said.”

Padding oracles everywhere
“The second part presents a previously unknown advanced attack. The most significant new discovery is an universal Padding Oracle affecting every ASP.NET web application. In short, you can decrypt cookies, view states, form authentication tickets, membership password, user data, and anything else encrypted using the framework's API!”
Presented by Rizzo and Duong

This technique allows the attacker to discover the AES Machine Key used by various ASP.NET features to encrypt and decrypt data stored on the web client.

There is a vulnerability in the AES algorithm implementation in .NET. This might be a bit premature, since the presentation details haven’t been given but a quick mitigation should be to switch over to 3DES instead of AES to protect your web sites. Hopefully a patch from Microsoft will be released that will solve this issue.

By default ASP.NET 2.0+ uses AES to protect ViewState, Forms Authentication, Roles, Membership, etc. and is vulnerable to attack. Depending on how an ASP.NET applications is architected/configured will determine if you are vulnerable.

For IIS 7 (Windows Server 2008, Win7, Vista) – the encryption settings (system wide, or application specific) can be configured directly in the IIS Manager. Under ASP.NET settings, choose “Machine Key” and make the changes through the GUI. You can do it Server Wide, or for each application.

iis MachineKey2

If on an older version of IIS, you can make the changes to the .NET config files directly. Configuration Files are located in many folders depending on the versions of the .NET Framework that are installed. On a 64-bit machine, there is a separate configuration file for 64-bit.
  • %SYSTEMROOT%\Microsoft.NET\Framework\[version number]\CONFIG\
  • %SYSTEMROOT%\Microsoft.NET\Framework64\[version number]\CONFIG\
  • The web.config in your web application folder
Ref: (.NET 4.0 docs):


    <machineKey validationKey="AutoGenerate,IsolateApps" 


        validation="3DES" decryption="3DES" />  

  • validation attribute specifies how to handle ASP.NET ViewState – when it’s been configured to encrypt…you may want to leave this to SHA1 and then change it in the local web.config instead.
  • decryption attribute handles which algo is used to encrypt/decrypt Forms Authentication Data (Forms Auth Ticket/Cookie), Membership Data (including Anonymous Identification), Role Cookies, – If it’s set to auto, that means you are using AES in .NET 2.0+ and you will be vulnerable.
Be careful, machinekey settings much match across all servers in a web farm. If a decryption key was specified (typically a web farm) then you’ll need to generate a new 3DES key and duplicate it across all servers in the web farm.

For more information on configuring Machine Keys in .NET 2.0: (depreciated, but still useful)

As always, determine if you actually have a vulnerability first, and THEN TEST ALL SETTINGS before modifying your production environment.
kick it on

Smart Card Authentication Module Update Released

I’ve finally wrapped up updating the SmartCardAuthenticationModule. The link to the download is at the end of this post.

A complete write-up of the previous version can be located here:

Changes / Improvements

  • * Added support for ASP.NET Membership which means support for Profiles and Roles as well.
  • * Removed all custom database requirements from the Module. If custom DB access is needed this can be implemented in a Global event.
  • * Removed SmartCardPrincipal class. Smart Cards only help establish identity and don’t provide any roles membership information so I opted to remove the class and instead just wrap the identity into a GenericPrincipal. If the ASP.NET Role provider is being used, the Role module will automatically wrap the SmartCardIdentity in a RolePrincipal. Implementer's can also add custom event code in the Global to use any Principal of their choice.
  • * Added ASP.NET Health Monitoring events for auditing Success and Failed logins, as well as when Membership accounts are created.
  • * Added support for custom error pages on a 401 Unauthorized.
  • * Added the following Smart Card Authentication Module events:
    •     * Authenticate
    •     * FailedMembershipAuthentication
    •     * MembershipValidating
    •     * MembershipUserCreated
    •     * MembershipUserCreating

OOTB Behavior

The out of the box behavior for the Smart Card Authentication module is as follows:
  1. 1. With ASP.NET Membership – The first time a user visits the web site, the Smart Card Authentication Module will automatically create a Membership account in a disabled state. The new MembershipUser will not have access until the account is enabled through the Membership Admin. For users who visit the site have a Membership account. the Module will call the Membership.Validate() method and will only allow them access if their Smart Card is the same as it was when they enrolled and the account is enabled.
  2. 2. With ASP.NET Membership and ASP.NET Roles – The RolePrincipal will contain the SmartCardIdentity. IsInRole() checks will work as expected and the SmartCardIdentity will also be available.
  3. 3. Without ASP.NET Membership/RoleProvider enabled – the SmartCardAuthenticationModule will authenticate the user and attach a GenericPrincipal with NO ROLES to the HttpContext.User. To provide custom roles (when not using the ASP.NET RoleProvider), subscribe to the SmartCardAuthentication_Authenticate event in Global.asax and attach an IPrincipal containing the roles appropriate for authorization.


Configure the Web project to have a reference to the SmartCardAuthenticationModule. This can be accomplished in one of two ways:.
  1. 1. Add a reference to the SmartCardAuthentication.dll to the web application project
  2. 2. To have Smart Card Authentication Module source available in the solution, add the SmartCardAuthentication Project to the Solution containing your web project and then add a project reference to the SmartCardAuthenticationModule.
In IIS, install a SSL/TLS Certificate and for Client Certificates, make sure to check either Accept or Require for the Web Site or Application. For production environments, Require SSL checked and Require Client Certificates selected is recommended:

Additionally, make sure to Enable only Anonymous Authentication in IIS:

HTTP Modules are installed differently depending on which version of IIS being used.


Launch the Internet Information Services (IIS) Manager and install the SmartCardAuthenticationModule in the Modules Feature under IIS section like so:
1. Open IIS Manager and expand the web site / application to enable the module:

2. Choose the Modules Feature under the IIS section, then click Add Managed Module… in the Right hand Actions pane.


3. The Add Managed Module dialog box will pop up. In the Name box, type in a name like SmartCardAuthenticationModule. The drop-down should contain an entry for the assembly SmartCardAuthentication.SmartCardAuthenticationModule that was detected from adding a reference to the project. When the reference is added, the SmartCardAuthentication.dll should have been put in the /bin folder of the application.


4. Click OK.
The steps above add the following XML to the web.config:
      <add name="SmartCardAuthentication"
           preCondition="" />
NOTE: Only set preCondition=”managedHandler” if you want the Smart Card Authentication Module to protect ASP.NET pages. If you want the module to protect your images and other documents on the web server, make sure to leave preCondition empty.

IIS 5.1 / 6.0

For older versions of IIS, simply add the following XML to the web.config file in the root of the web application:

<?xml version="1.0"?>
      <add name="SmartCardAuthentication"


There are several events provided in the SmartCardAuthenticationModule that will override the Smart Card Authentication Module’s default behavior. These events can be overridden in the Global.asax.
The events are:
  • * Authenticate
  • * MembershipUserCreating
  • * MembershipUserCreated
  • * MembershipValidating
  • * FailedMembershipAuthentication
For the events to be properly wired up, they must be prefixed with the Module Name followed by an underscore. For example, to subscribe to the Authenticate event, the method name would be SmartCardAuthentication_Authenticate.

SmartCardAuthentication_Authenticate Event

The Authenticate event is used to override the default authentication behavior of the Smart Card Authentication Module.
By default, the Smart Card Authentication Module will authenticate all Smart Cards / Client Certificates allowed in by IIS unless Membership is used. The Module also will not assign any roles, unless using the ASP.NET RoleProvider. Using information from the X.509 certificate, authenticated users and retrieve their corresponding roles.
When implementing this event:

  • * For Authentication to be successful, attach a IPrincipal containing the SmartCardIdentity to the AuthenticationEventArgs.User property. Make sure to set the IsAuthenticated property to true.
  • * To signal the Smart Card Authentication Module that Authentication has failed, either set the AuthenticationEventArgs.User property to null, or attach the IPrincipal to the AuthenticationEventArgs.User property and set IsAuthenticated to false.
protected void SmartCardAuthentication_Authenticate(object sender,
                SmartCardAuthentication.AuthenticationEventArgs e)

{  // NOTE: e.Identity has the Smart Card Identity extracted by
  // the SmartCardAuthenticationModule  if (e.Identity != null)
    // Write code to take SmartCard information from e.Identity
    // and:
    // 1. Authenticate: Check the user against the user data store
    // and check if they should be authenticated
    // e.g. From Active Directory, LDAP, Custom DB, etc.

    // FOR DEMO PURPOSES THIS HARD CODES IIdentity.IsAuthenticated
    // It may be acceptable to hard code in certain situations
    // where Certificate Trust Lists (CTL) are configured
    // and properly restrictive in IIS
    e.Identity.IsAuthenticated = true;

    if (e.Identity.IsAuthenticated)
      // 2. Authorize: Retrieve roles
      // e.g. From Active Directory, LDAP, Custom DB, etc.
      // string roles[]=
      //   DBAccess.GetRolesByPublicKeyhash(e.Identity.PublicKeyHash);
      // string roles[]=
      //       LDAPAccess.GetRolesByUPN(e.Identity.UserPrincipalName);
      // For Demo purposes, this uses HARD CODED ROLES
      string[] roles = new string[] { "Accounting", "Administrator" };

       // 3. Create a new Principal object using
       // retrieved roles and the Smart Card Identity (e.Identity)

       // This example will use GenericPrincipal, which works well
       // when you don't need a specific principal
       GenericPrincipal genericPrincipal =
                       new GenericPrincipal(e.Identity, roles);

       // 4. Attach the IPrincipal to the e.Context.User OR the
       // e.User to signal he SmartCardHttpModule that
       // authentication has been handled
       e.User = genericPrincipal;
      // NOT AUTHENTICATED, make sure user is null to signal
      // the SmartCardHttpModule that authentication has been
      // handled
      e.User = null;

SmartCardAuthentication_MembershipUserCreating Event

The MembershipUserCreating event is used to override the Smart Card Authentication Module’s default behavior of Membership Account creation.
This event allows control over how membership accounts are created, including information that might also need added to the user’s profile, and whether the Membership accounts are enabled or disabled when created. When using something other than the e.Identity.Name and e.Identity.PublicKeyHash as the Membership username and password, ALSO implement the SmartCardAuthentication_MembershipValidating event as well to make sure Membership.ValidateUser() is called with the correct username and password.
When implementing this event:
  • * When creating the Membership User account, take care when setting the isApproved argument in the Membership.CreateUser() method. Only set it to true if the Identity is from a valid user of the system. Remember, anyone could present a false Client Certificate and attempt to spoof a Smart Card.
  • * Likewise, exercise caution when setting the MembershipEventArgs.Identity.IsAuthenticated property to true for the same reasons outlined above.
  • * After creating the Membership User account, assign the newly created MembershipUser to the MembershipEventArgs.MembershipUser property.
protected void SmartCardAuthentication_MembershipUserCreating(
                   object sender,
                   SmartCardAuthentication.MembershipEventArgs e)
{  // Account doesn't exist, add it  MembershipCreateStatus status;   // In this example, auto-enable the user (NOT USUALLY A GOOD IDEA unless
  // there is data available in back end systems that can validate the
  // Smart Card information as authentic). This is done by setting the
  // 6th argument of Membership.CreateUser() to true.  MembershipUser user = Membership.CreateUser(
                               null, null, true, null, out status);  if (status == MembershipCreateStatus.Success)
    // Success, attach the newly created user to the Membership
    // eventArgs.
    e.MembershipUser = user;

    // Make sure to also set IsAuthenticated to true to signal the
    // Smart Card Module that this user is authenticated.
    e.Identity.IsAuthenticated = true;
  }  else  {
    // There was an error creating the account so throw the error.
    throw new MembershipCreateUserException(status);

SmartCardAuthentication_MembershipUserCreated Event

The MembershipUserCreated event allows implementers the ability to do further Membership account or Profile configuration setup after the Smart Card Authentication Module creates the MembershipUser account using the default Membership Provider.
This event is raised right after the Smart Card Module automatically creates the membership account. This allows access to the automatically created Membership User account and also provides a place to automatically enable the Membership account or to notify the administrator that a new Membership account has been created and that action is required to validate and enable it.

SmartCardAuthentication_MembershipValidating Event

The MembershipValidating event is used to override the Smart Card Authentication Module’s default Membership validation behavior.
The MembershipValidating event provides a place to override the Smart Card Authentication Module’s default Membertship validation routine. This is useful if the Membership Username and Password need to be different than the default implementation.
When implementing this event:

  • * For a successful Membership Authentication, assign the MembershipUser to the MembershipEventArgs.MembershipUser property and set the MembershipEventArgs.Identity.IsAuthenticated to true.
  • * For an unsuccessful Membership Authentication, set the MembershipEventArgs.MembershipUser to null and the MembershipEventArgs.Identity.IsAuthenticated to false.
protected void SmartCardAuthentication_MembershipValidating(object sender,
                     SmartCardAuthentication.MembershipEventArgs e)
{  // Provide new Membership Validation  bool isUserValidated = false;  // Does Smart Card User have a Membership account?  if(Membership.FindUsersByName(e.Identity.Name).Count == 1)
    // Yes, validate them
    isUserValidated = Membership.ValidateUser(e.Identity.Name,
    // account might be marked Inactive, so set the IIdentity to
    // match Membership
    e.Identity.IsAuthenticated = isUserValidated;
    e.MembershipUser = Membership.GetUser(e.Identity.Name);

    if (!isUserValidated)
      // Authentication with Membership provider failed.
      e.MembershipUser = null;
  }  else  {
    throw new ApplicationException("Membership user not found.");

SmartCardAuthentication_FailedMembershipAuthentication Event

The FailedMembershipAuthentication event is fired when an authentication failure occurs for any reason in the Smart Card Authentication Module, whether it’s Membership Auth failure or Smart Card Identity authentication failure.
This can mean one of several things:
  • * Someone provided a Client Certificate or SmartCard that is not authorized to use the site.
  • * Someone’s Smart Card / Client Certificate expired and needs renewed.
  • * The information registered in the Membership database doesn’t match the Smart Card / Client Certificate supplied data.
Since the X.509 certificates expire on Smart Cards and Client Certificates there may be a way to detect and automatically re-enroll User’s new X.509 certificate.
Additionally it may be used to do custom account lockout after several failed logins. If using a Membership Provider, use it’s account lockout mechanisms instead.
protected void SmartCardAuthentication_FailedMembershipAuthentication(
               object sender,
               SmartCardAuthentication.AuthenticationEventArgs e)
{  // Use e.Identity data retrieved from the X.509 certificate and
  // auto-enroll if able to verify the new X.509 certificate data.

  // At Minimum, log failed log-ins and perhaps incorporate it into
  // workflow for re-enrolling users with expired certificates.}

Custom Unauthorized Page

To display a custom 401 Unauthorized page, include it in the customErrors node of the web.config like so and unauthorized users will be re-directed to it.
<?xml version="1.0" encoding="UTF-8"?>
    <customErrors mode="On" >
      <error statusCode="401" redirect="Unauthorized.aspx"/>
Make sure to grant access to anonymous users to the Unauthorized page in the web.config:
<?xml version="1.0" encoding="UTF-8"?>
  <location path="Unauthorized.aspx">
        <allow users="?" />
        <deny users="*" />

Download Source

You can download the source here.

Comments, questions, feedback, and feature requests welcome. Also if you run across any bugs let me know.