使用protection=validation解密.ASPXAUTH Cookie

12

我已经尝试了很长时间来解密ASP .ASPXAUTH cookie并且使用PHP进行解密。我的原因非常重要,我必须这样做,没有其他选择。到目前为止,在PHP中我已经成功地从该cookie中读取了数据,但是在加密时似乎无法这样做。无论如何,接下来就开始吧...

首先,您需要修改服务器的Web.config文件(protection需要设置为Validation):

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

然后,在同一域名下的 PHP 脚本中,您可以执行以下操作来读取数据。这是一个非常基本的示例,但可以证明:

$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

这个过程会分解cookie,或者至少是未加密的数据:

http://i.stack.imgur.com/stisu.jpg

现在我知道如何获取这些数据后,我从Web.config中移除了'protection="validation"'字符串,并尝试使用PHP mcrypt进行解密。我已经尝试了无数种方法,但以下是一个有希望的例子(失败了)...

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

然而,这个方法失败了。我已经尝试过各种16字节全零IV的变化形式,尝试了不同的Rijndael大小(128 vs 256),也尝试过使用base64_decode(),但似乎都没起作用。我在这里找到了一个stackoverflow帖子并开始尝试使用使用sha256生成的key/iv的变化形式,但那也没有真正起作用。

有人知道我应该做什么吗?


你说:“我的理由很充分,我必须这样做,没有其他选择。” 你能详细说明一下吗?总是有替代方案的,SSO也不例外。深入了解cookie加密的内部机制似乎不是一个好主意——如果加密方式在小型框架版本之间发生变化,因为安全漏洞被修复/优化被引入,那么你的解密将会突然失效。 - Wiktor Zychla
我的意思并不是说没有技术上的替代方法来完成这个任务,而是说基于我的原因,我没有或者不想使用其他的替代方案。至于框架版本的发布,那对我来说并不是问题。 - TheFrack
你尝试过反过来吗?是否有可能从相同的数据中获取未加密的数据和加密版本,然后尝试加密未加密的数据以匹配加密的字符串呢?也许通过这种方式你可以找到正确的参数。 - Jan Prieser
3个回答

5
我不知道.NET AuthCookies如何进行加密,但我可以试着回答。假设加密是以AES CBC-IV模式进行的,并且有随机生成的IV,您需要先找出IV所在的位置。您展示的代码片段不能工作,因为您正在生成一个随机IV(这将是不正确的)。话虽如此,即使您获取了错误的IV,在CBC模式下,仅第一个16个字节的解密密文会“损坏”,而其余部分将正确解密 - 您可以使用这个作为测试来确定您是否正在正确执行其余部分。在实际应用中,当使用随机IV时,很可能它会被添加到密文前面。要检查是否正确,您可以尝试检查len(ciphertext)= len(plaintext)+ 16。这意味着最有可能的情况是前16个字节是您的IV(因此在尝试解密之前应从密文中删除它)。
另外,在您的代码片段中,似乎您正在使用键作为ASCII字符串,而实际上它应该是一个字节数组。请尝试:
define('ASP_DECRYPT_KEY',hex2bin('0BC95D748C57F6162519C165E0C5DEB69EA1145676F453AB93DA9645B067DFB8'));

另外,这似乎是一个32字节的密钥,所以您需要使用AES-256。我不知道authcookie的样子,但如果它是base64编码的,您还需要首先解码它。希望这可以帮到您!
注意:我不建议在重要的生产代码中这样做,因为如果您尝试实现自己的解密例程,会有很多事情可能会出错。特别是,我猜想应该有一个MAC标签,在尝试解密之前,您必须检查它,但在实现自己的加密过程中还有许多其他可能出错的事情。

哇塞,你真是我的好朋友,你让我这一周都很开心。 - TheFrack
你指出了我一个月以来忽略的一个缺陷,那就是没有将十六进制打包成二进制!我做到了,并且成功地通过我的测试脚本中的其中一种方法解密了它。 - TheFrack

1

我知道这对OP可能不可行,但对于其他人来说,这里有一个简单的替代方法。

  1. 创建一个.NET Web服务,其中包含以下方法:

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

  2. 从PHP将cookie传递给Web服务:

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


在我看来,这是比在 PHP 中进行解密要好得多的解决方案。 - Stefan Born

-1

我知道在PHP中解密.NET加密的内容以及反之是多么痛苦。

最终,我不得不自己编写Rijndael算法(从另一种语言翻译过来)。

这里是算法源代码的链接:http://pastebin.com/EnCJBLSY

在源代码的末尾有一些使用示例。

但是在.NET上,加密时应该使用零填充。同时,测试ECB模式,我不确定CBC是否有效。

祝你好运,希望能帮到你。

编辑:该算法在加密时返回十六进制字符串,并且在解密时也需要十六进制字符串。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接