views:

668

answers:

4

I need to undo the following ASP.Net processes in PHP so I can get at the username and expiration date in a ticket. I've decrypted the 3DES encryption (step 3 below) but I'm not sure what I need to do next. Is the string that results from decryption a byte array? Should I be able to convert it to ascii? (Because it doesn't).

What ASP.Net does to create ticket: 1. Serialize username, expiration, other data (which I don't care about). Create a byte array. 2. Sign the ticket using SHA1 (the sig is the last 20 bytes) 3. Encrypt the ticket with 3DES (which I've unencrypted). I get back something that looks like this:

6E 85 A4 39 71 31 46 BB A3 F6 BE 1A 07 EE A4 CE 5F 03 C8 D1 4C 97 5D 6A 52 D1 C4 82 75 5E 53 06 7B 1D D2 4D BF 22 40 F7 F4 B8 8D B0 C3 EC E5 BE F7 52 C2 DF 00 7A D1 CB BC 76 4B 10 33 2D 1A B4 15 A7 BB D6 9D BF 41 69 D2 C4 43 4A 26 95 01 F2 06 AA 46 2C 96 CC AD DC 08 59 C0 64 B6 EE 2C 5F CA ED 8B 92 1C 80 FD FF DC 61 67 28 59 CB E6 71 C6 C3 72 0E D0 32 69 22 57 4E 40 2B DA 67 BA 7F F1 C5 78 BC DF 80 8C D8 F2 8B 19 E2 A4 4F 7C 8C D9 97 37 BD B5 5B 0A 66 9B DD E7 DC 7B 78 F4 F8

It doesn't map to ascii, what do I do next? I have the SHA1 validation key. Thanks for any help!

+1  A: 

I don't think this is possible...

A few pre-requisite questions:

  • Are you sure you have decrypted the string correctly, with the correct MachineKey value and decryption algorithm? I know ASP.NET 1.0 used 3DES but newer versions generally use AES by default.
  • Why are you accessing this data in the first place? The FormsAuthenticationTicket was not intended to be "broken", and if you were going to access these values from a different language you may consider rolling your own scheme.

Some noteworthy observations:

Buried in FormsAuthentication.Decrypt() is a call to UnsafeNativeMethods.CookieAuthParseTicket(...). Here is the signature:

[DllImport("webengine.dll", CharSet=CharSet.Unicode)]
internal static extern int CookieAuthParseTicket(byte[] pData, int iDataLen, StringBuilder szName, int iNameLen, StringBuilder szData, int iUserDataLen, StringBuilder szPath, int iPathLen, byte[] pBytes, long[] pDates);

This parses what looks to be a byte array returned from MachineKeySection.HexStringToByteArray() (apparently a function that appears to decode the string using UTF-8) into the individual members of the FormsAuthenticationTicket.

I can only assume that no matter which decoding method you use (ASCII, UTF-16, etc.) you're not going to get the data back unless you know Microsoft's implementation hidden in this native method.

MSDN may also offer some help.

John Rasch
+2  A: 

I've been working it out, and I have managed to get the forms authentication ticket contents in PHP.

  1. Decrypt the ticket with the same key used to encrypt it on the .Net side. For this, I'm using http://www.navioo.com/php/docs/function.mcrypt-encrypt.php.

  2. The decryption adds padding to the end of the string, I remove that.

  3. I'm left with a string with a 20 byte SHA1 hash at the end. Those last 20 bytes (should) match the SHA1 hash of the first part of the string (string length - 20 bytes). I'm still working on this part, trying to figure out how .NET converts a byte array into a single clump of data that can be SHA1 hashed (so I can do the same on the PHP side).

That's really all there is to it.

lynn
A: 

I've got to do the exact same thing, decrypt an ASP.NET forms authentication ticket, but in Perl. I've tried a whole set of decryptions but I can't get it to work (the result is far from a readable string).

Since you've apparently solved it, do you think you could help out by providing some more details about your solution? (Perhaps even some code?)

Thanks in advance.

JW
A: 

For anyone else wanting to do this, please note that the AES encryption used by ASP.NET is always of 16-byte block size, i.e. MCRYPT_RIJNDAEL_128 in PHP mcrypt terminology, and uses CBC mode. The key length (32 bytes / 256 bits by ASP.NET default) is determined by PHP from the actual key supplied. Also, the beginning of the decrypted data seems to become corrupted unless the IV is all zeros (i.e. "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0").

For more information on decoding the data, see: http://www.codeproject.com/KB/aspnet/Forms_Auth_Internals.aspx

OttoG