Decrypting the .ASPXAUTH Cookie WITH protection=validation
Asked Answered
W

3

12

For quite sometime I've been trying to decipher the ASP .ASPXAUTH cookie and decrypt it using PHP. My reasons are huge and I need to do this, there is no alternative. In PHP so far I have successfully managed to read the data from this cookie, but I cannot seem to do it while it is encrypted. Anyway, here it goes...

First you need to alter your servers Web.config file (protection needs to be set to Validation):

    <authentication mode="None">
        <forms name=".ASPXAUTH" protection="Validation" cookieless="UseCookies" timeout="10080" enableCrossAppRedirects="true"/>
    </authentication>

Then in a PHP script on the same domain, you can do the following to read the data, this is a very basic example, but is proof:

$authCookie = $_COOKIE['_ASPXAUTH'];
echo 'ASPXAUTH: '.$authCookie.'<br />'."\n";//This outputs your plaintext hex cookie
$packed = pack("H*",$authCookie);
$packed_exp = explode("\0",$packed);//This will separate your data using NULL
$random_bytes = array_shift($packed_exp);//This will shift off the random bytes
echo print_r($packed_exp,TRUE); //This will return your cookies data without the random bytes

This breaks down the cookie, or at least the unencrypted data:

https://static.mcmap.net/file/mcmap/ZG-AbGLDKwfpKnMxcF_AZVLQamyA/stisu.jpg

Now that I know I can get the data, I removed the 'protection="validation"' string from my Web.config and I tried to decrypt it using PHP mcrypt. I have tried countless methods, but here is a promising example (which fails)...

define('ASP_DECRYPT_KEY','0BC95D748C57F6162519C165E0C5DEB69EA1145676F453AB93DA9645B067DFB8');//This is a decryption key found in my Machine.config file (please note this is forged for example)
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_RAND);
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, ASP_DECRYPT_KEY, $authCookie, MCRYPT_MODE_CBC, $iv);//$authCookie is the pack()'d cookie data

This however fails. I've tried variations of IV with all zeros @ 16 bytes. I've tried different Rijndael sizes (128 vs 256). I've tried base64_decode()ing, nothing seems to work. I've found this stackoverflow post here and started using variations of the key/iv that are made using sha256, but that isn't really working either.

Anybody have a clue what I should do?

Weldonwelfare answered 28/8, 2012 at 18:53 Comment(3)
You say that "My reasons are huge and I need to do this, there is no alternative.". Could you elaborate more on this? There are always alternatives, SSO is not an exception. Looking under the hood of the cookie encryption sounds like a bad idea - what if the encryption changes between minor framework releases because security bugs are removed/optimizations are introduced? Your decryption would just blow up suddenly.Restless
I didn't mean there is no technical alternative to doing this, I meant there is no alternative that I can/want to use due to my reasons. And no, the framework releases wouldn't be a problem.Weldonwelfare
have you tried the other way around? is it possible to get the unencrypted data and a crypted version from the same data and then try to encrypt the unencrypted data to match the encrypted string? maybe this way you find the correct parameters.Elegancy
V
5

I don't know how encryption is made in .NET AuthCookies, but I can try to answer.

Assuming the encryption occurs in AES CBC-IV mode, with randomly generated IVs, you need to first find out where the IV is.

The code snippet you show cannot work, as you are generating a random IV (which will be incorrect). That being said, even if you get the IV wrong, in CBC mode you will only have the first 16 bytes of your decrypted ciphertext "garbled" and the rest will decrypt properly - you can use this as a test to know if you're doing the rest correctly. In practice when using random IVs, it's very likely that it's prepended to the ciphertext. To check if this correct, you can try to check if len(ciphertext) = len(plaintext) + 16. This would mean that most likely the first 16 bytes are your IV (and therefore it should be removed from the ciphertext before attempting to decrypt it).

Also on your code snippet, it seems you are using the key as an ascii-string, whereas it should be a byte array. Try:

define('ASP_DECRYPT_KEY',hex2bin('0BC95D748C57F6162519C165E0C5DEB69EA1145676F453AB93DA9645B067DFB8'));

Also, this seems to be a 32 byte key, so you need to use AES-256. I don't know how the authcookie looks like, but if it's base64 encoded, you also need to decode it first obviously.

Hope this helps!

Note: I don't recomment doing this for important production code, however - because there are many things that can go wrong if you try to implement even your own decryption routine as you are doing here. In particular, I would guess there should be a MAC tag somewhere that you have to check before attempting decryption, but there are many other things that can go wrong implementing your own crypto.

Vibrato answered 12/9, 2012 at 9:57 Comment(2)
OMG You my friend just made my week.Weldonwelfare
You pointed out a flaw that I overlooked for a month, not packing the hex into binary! I did that and success, decrypted it via one of the many methods in my test script.Weldonwelfare
P
1

I understand this may not have been possible for the OP but for other people heading down this route here is a simple alternative.

  1. Create a .net web service with a method like:

    public FormsAuthenticationTicket DecryptFormsAuthCookie(string ticket)
    {
    return FormsAuthentication.Decrypt(ticket);
    }

  2. Pass cookie to web service from PHP:

    $authCookie = $_COOKIE['.ASPXAUTH'];
    $soapClient = new SoapClient("http://localhost/Service1.svc?wsdl");
    $params= array(
    "ticket" => $authCookie
    );
    $result = $soapClient->DecryptFormsAuthCookie($params);

Petroglyph answered 11/6, 2013 at 16:15 Comment(1)
That's a much better solution IMO than doing the decryption in PHP.Jorgenson
J
-1

I know what a pain is to decrypt in PHP something encrypted in .NET and vice versa.

I had to end up coding myself the Rijndael algorithm ( translated it from another language ).

Here is the link to the source code of the algorithm: http://pastebin.com/EnCJBLSY

At the end of the source code there is some usage example.

But on .NET, you should use zero padding when encrypting. Also test it with ECB mode, I'm not sure if CBC works.

Good luck and hope it helps

edit: the algorithm returns the hexadecimal string when encrypts, and also expects hexadecimal string when decrypting.

Joell answered 11/9, 2012 at 18:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.