ZX Security


Customising Blacklist3r for OWIN OAuth Access Tokens

This post discusses how we adapted the Blacklist3r tool to achieve authentication bypass on a web application implementing OWIN (Open Web Interface for .NET) OAuth 2.0 during a client pentest.

Authored by Michael Tsai

Published on

Overview

Blacklist3r is a project that collects pre-published secret keys such as the Machine Key used by a .NET application from various locations such as public Github repositories, blog posts and tutorials. These keys are sometimes reused in the production environment or were accidentally published by the developers. Blacklist3r also provides the AspDotNetWrapper tool to brute-force encrypted material against this list of Machine Keys.

The types of encrypted data it supported are:

  • OWIN auth cookie
  • Forms authentication cookie
  • ViewState

However, as the tool did not support decrypting OWIN OAuth Access Tokens by default, we needed to modify Blacklist3r to support this feature. This led to a successful decryption of the access token, which resulted in authentication bypass on the target application.

OWIN OAuth

OWIN stands for “Open Web Interface for .NET”. It is a specification that aims to decouple the web application from the web server. For more information regarding OWIN and the Microsoft implementation Katana, please see the official documentation.

A classic implementation of OAuth 2.0 in ASP.NET 4.x is to use the OWIN OAuth middleware. This is based on the Microsoft.Owin.* libraries provided by Katana. The OAuth architecture typically includes an Authorisation Server and a Resource Server. Upon successful authentication on the Authorisation Server, the client would be issued an access token for accessing the protected resources on the Resource Server.

Example OWIN OAuth Implementation

In a since-removed article (archived on the Internet Wayback Machine), Microsoft describes an implementation to issue a Bearer Token in the context of Client Credentials Grant.

The Authentication Provider is set up as follows during start up:

Set OnGrantClientCredentials to the GrantClientCredentials method

The GrantClientCredentials method is implemented as follows:

Call the context.Validated method on the identity

The token generation happens during context.Validated(identity). This relevant code is implemented in Microsoft.Owin.Security.OAuth/Provider/BaseValidatingTicketContext.cs. The AuthenticationTicket is created at this point based on the provided identity and properties.

Microsoft.Owin.Security.OAuth/Provider/BaseValidatingTicketContext.cs

Implementation of the Validated method

As the Authentication Ticket is created, an access token is then issued to the client. This code flow is shown below:

Microsoft.Owin.Security.OAuth/OAuthAuthorizationServerHandler.cs

The access token is created and serialized

Microsoft.Owin.Security/Infrastructure/AuthenticationTokenCreateContext.cs

The SerializeTicket method calls the Protect method

Microsoft.Owin.Security/DataHandler/SecureDataFormat.cs

The implementation of the Protect method in SecureDataFormat

To understand the encryption process, we have to trace back how _serializer, _protector and _encoder were defined.

  • _serializer is a TicketSerializer object whose Serialize() function is simply performing Gzip compression
  • _protector is defined as follows:

    Microsoft.Owin.Security.OAuth/OAuthAuthorizationServerMiddleware.cs

    How the DataProtector is set up

  • _encoder is Base64Url encoding.

The encryption part is defined by the Protect() function, which eventually calls the standard MachineKey.Protect() function defined in System.Web.Security. The _purposes string is also passed in along with the user data.

For testing purpose and to summarise the operation, we have also come up with the following sample code to create an access token.

// Create new ClaimsIdentity
var identity = new ClaimsIdentity("Bearer");

// Add some claims here
identity.AddClaim(new Claim(ClaimTypes.Name, user.UserName));

// Set authentication properties
var props = new AuthenticationProperties();
props.IssuedUtc = new DateTime(2020, 12, 12);
props.ExpiresUtc = new DateTime(2222, 12, 12);

// Create a sample Authentication ticket
var sampleAuthTicket = new AuthenticationTicket(identity, props);
var newSerializer = new TicketSerializer();
var sampleTicket = newSerializer.Serialize(sampleAuthTicket);

// Encrypt the ticket
var enc = EncryptData(sampleTicket, machineKey, validationKey, "SHA1", "AES", emptyIV);
Console.WriteLine("Encrypted OAuth token: " + enc);

The EncryptData() method is taken and adapted from Blacklist3r:

public static string EncryptData(
  byte[] plaintext,
  string machineKey,
  string validationKey, 
  string validationAlgo,
  string DecryptionAlgo,
  byte[] encryptionIV
) {
  AspNetCryptoServiceProvider obj = new AspNetCryptoServiceProvider(
    validationKey, validationAlgo, machineKey, DecryptionAlgo
  );
  obj.SetEncryptionIV(encryptionIV);

  Purpose purpose = Purpose.User_MachineKey_Protect.AppendSpecificPurposes(
    new[] {
      "Microsoft.Owin.Security.OAuth",
      "Access_Token",
      "v1"
    }
  );
  ICryptoService cryptoService = obj.GetCryptoService(purpose);
  var encrypted = cryptoService.Protect(plaintext);
  return Convert.ToBase64String(encrypted).Replace('+', '-').Replace('/', '_').Replace("=", "");
}

Now knowing the context of how an access token is created and encrypted, we can customise Blacklist3r to brute force for OWIN OAuth tokens.

Customising Blacklist3r

It is relatively easy to add OWIN OAuth support to Blacklist3r since it already supports OWIN auth cookies. If we compare the two implementations during the encryption process, we notice that the only difference is the purposes string array that gets passed into the CreateDataProtector() function:

Blacklist3r OAuth v.s. Cookie Authentication

Regarding the Blacklist3r project itself, the code inside the AspDotNetWrapper/Customization directory is all we need to modify. We can see the existing purpose string for OWIN auth cookie is defined in DefinePurpose.cs:

The existing purpose string for OWIN auth cookie in DefinePurpose.cs

Instead of typeof(CookieAuthenticationMiddleware).FullName which is Microsoft.Owin.Security.Cookies.CookieAuthenticationMiddleware, we would just need typeof(OAuthBearerAuthenticationMiddleware).Namespace which evaluates to Microsoft.Owin.Security.OAuth. Similarly, instead of ApplicationCookie we would put Access_Token. In addition to this main modification, there is only slight changes required for the other pieces of code that deal with handling command line arguments and decrypted output.

After the change, we can now successfully decrypt the target Bearer Token and obtain the machine key:

decryption result

Conclusion

Blacklist3r is a highly useful tool to audit the target application for usage of pre-published machine keys. Successful brute-forcing of this information could often lead to authentication bypass or Remote Code Execution. In this post, we have shown our approach to modifying Blacklist3r to decrypt OWIN OAuth access tokens and that other encryption routines could also be added to Blacklist3r with ease.

Reference