为什么 TOTP 秘密每秒都在变化?

逆向工程 艾达 拆卸
2021-06-25 03:37:16

最近我一直在检查 IDA Pro 中的一个密钥生成器程序。我相信这里的线程讨论了一个类似的密钥生成器。因此,某些细节可以参考。密钥生成器将设备序列号作为输入,并生成一个 32 字节(字符)的主密钥以及上述链接中形式OTPAUTH URI

  • 主密钥只是当前时间的函数(从纪元开始以秒为单位)。因此,无论序列号如何,每秒都会发生变化。

由于密钥每秒都在变化,因此 OTPAUTH URI 也是如此。我想知道在这种情况下,一旦客户端进入 TOTP,服务器应该如何验证 TOTP?

编辑: 所以现在有一些新问题:

  • 我如何使用此密钥生成器向服务器进行身份验证,知道该密钥生成器正在srand(time(NULL))用于种子,同时rand()连续调用8 次以生成 32 字节的随机序列。
  • 说 OTP 代码的时间步长仍然是 30 秒是否合乎逻辑,而我们知道密钥和因此的秘密每秒都在变化?这是否转化为 OTP 有效期现在为 1 秒的事实?

漏洞:服务器是否容易创建未来的 TOTP 并将其保存在存储库中?当我写这个部分时,自纪元以来已经过去了 1476946414 秒。假设创建一个 TOTP 的时间相当于从 epoch 过去的 1476947000 秒。可以修改密钥生成器,以便将 1476947000 传递给srand()而不是time(NULL)大概也有足够的时间从 OTPAUTH URI 派生 TOTP。

使用 IDA Pro 6.8 打补丁:

所以我认为最好继续接触时尚。滚动反汇编,我将调用更改time(NULL)mov指令,将我最喜欢的时间分配给eax为了检查我的补丁,我在最喜欢的时间运行了原始的注册机。结果是相同的。三件事仍然困扰着我:

  1. 服务器执行的验证过程是否可以隐藏在密钥生成器中,或者密钥生成器是它唯一期望的密钥生成器?!
  2. 反汇编有一堆类似于我假设的 openssl 子例程的字符串。例如digest.cpmeth_gn.cpmeth_lib.c等。代码可以在网上找到。但是,我没有找到适合外行的清晰文档。我怀疑这里是否定义了服务器的验证参数。我还能够使用findcrypt2在反汇编中检测 SHA256 和 SHA512 加密常量
  3. 我被警告说密钥是使用 Linux 生成的。这可能会产生什么影响?我仍然在 Windows 轨道上!

切换到 Linux:

  1. 所以我安装了 Ubuntu 16.04 并运行了打补丁的 linux 二进制密钥生成器。密钥文件和秘密与Windows同时生成的完全不同。在到达指定时间之前,我创建了 HMAC 并导出了该特定时间的 TOTP 代码,并在特定时间准确输入它们。但是,我无法进行身份验证。服务器当前似乎并不期待 TOTP。我不知道我应该在什么时间向服务器提供 TOTP!

  2. 虽然findcrypt2在 Windows 密钥生成二进制文件中没有发现任何 AES 迹象,但它确实注意到Linux 密钥生成二进制文件中有多个Rijndael的(只是作为附加信息添加)。

  3. 我已经能够接收服务器二进制文件。我认为必须在那里概述身份验证程序。但是我应该在哪里看?

这是最后的问题: 密钥生成器程序用于生成设备特定的密钥。这些密钥的生成方式存在一个弱点,应该利用这些弱点为任何设备生成有效的一次性代码。

  1. 序列号可以是任何 9 位数字。我个人一直在与 381151134 合作。

  2. 用法:keygen [-g OR -m master_key_file] -k serial -o master_output_file

  3. 要下载 keygen Linux 二进制文件,请单击此处可以在此处找到 Windows 二进制文件

1个回答

由于密钥每秒都在变化,因此 OTPAUTH URI 也是如此。我想知道在这种情况下,一旦客户端进入 TOTP,服务器应该如何验证 TOTP?

服务器必须知道以前生成的密钥以提供可用性。要么通过动态生成以前的键(我可以想象一种算法,它会尝试t-0,如果失败t-1,如果t-2在预定义的范围内失败,则允许用户在移动到下一个后的某个时间输入一个值。

否则,整个生成-插入-发送-验证过程仅限于一个短窗口。一次接受多个有效密钥是可以接受的,因为范围仍然很短,值仍然难以预测,暴力破解仍然不可能(这可以通过在多次错误尝试后限制接受密钥的范围来进一步缓解)。

我如何使用此密钥生成器向服务器进行身份验证,知道该密钥生成器正在使用 srand(time(NULL)) 作为种子,同时连续 8 次调用 rand() 以生成 32 字节的随机序列。

没有对整个密钥生成算法和实际生成过程进行逆向工程是不可能知道的。您需要对函数调用进行逆向工程,rand()并为密钥生成过程构建模拟器。

如果您描述的是整个过程,那么您将需要弄清楚这些rand()值是如何连接在一起的(它们是连接在一起的吗?彼此异或?最终值是如何编码的?)

编辑:回答“漏洞”下提出的其他问题

服务器是否容易创建未来的 TOTP 并将它们保存在存储库中?

确实如此,但正如我在回答您的第一个问题时提到的,这不一定会发生。验证代码可以在每次需要执行验证时生成它认为合理/潜在的 TOTP 密钥。

此外,这需要攻击者破解该安全存储的访问权限,但是如果攻击者获得该安全存储的访问权限以窃取 TOTP 密钥,他也可能窃取用于生成这些密钥的主密钥并获得生成 TOTP 的能力钥匙如他所愿。因此,将密钥存储在存储主密钥的同一位置不会增加风险。

显然,服务器有能力生成密钥以验证它们,并且必须确保该机制值得信赖才能安全运行。这是大多数加密协议的共同要求,即某些点是可信的。毕竟,为了让服务器验证用户,假设服务器受到保护是合理的。

人们可以考虑使用某种非对称密钥协议而不是对称密钥。但是,由于该协议旨在通过服务器验证用户,因此只要服务器变得不受信任,它就会变得毫无意义。

如果攻击者侵入服务器以生成未来的密钥,一旦检测到这种情况,就需要更换主密钥(以及相应的所有未来 TOTP 密钥)。

服务器执行的验证过程是否可以隐藏在密钥生成器中,或者密钥生成器是它唯一期望的密钥生成器?!

密钥生成器和服务器执行相同的基本过程。曾经作为提供知识证明(密钥生成器)的一种方式,以及一种对其进行验证的方式(服务器)。

密钥生成器能够执行验证,服务器能够具体证明,但这不应该发生(尽管它可能会发生,并且可能会带来风险并使协议暴露于漏洞中)。

反汇编有一堆类似于我假设的 openssl 子例程的字符串。例如digest.c、pmeth_gn.c、pmeth_lib.c等。代码可以在网上找到。但是,我没有找到适合外行的清晰文档。我怀疑这里是否定义了服务器的验证参数。我还能够使用 findcrypt2 在反汇编中检测 SHA256 和 SHA512 加密常量。

我不太确定这里的问题是什么。我不认为任何 SSH 功能与密钥生成直接相关,但我可能是错的。

我被警告说密钥是使用 Linux 生成的。这可能会产生什么影响?我仍然在 Windows 轨道上!

Windows和Linux的实现srandrand不同。具体来说,他们使用不同的常量或不同数量的迭代和迭代之间的组合。常见的 rand 函数的基本块是这样的:

int myrand(void) {
    next = next * 1103515245 + 12345;
    return((unsigned)(next/65536) % 32768);
}

其中 1103515245 和 12345 是两个常量值,在实现之间经常发生变化。

是 glibc 的版本。你可以看到它更复杂。对具体实现进行逆向工程可能是最安全的方式。