码存储:数学、概率与复杂性

238 阅读20分钟

密码破解已经成为信息安全测试中一个充满故事的元素,从最早期的工具如Cain and Abel到现代的工具如hashcat。尽管多年来工具和技术有所变化,密码破解背后的原理却基本未变。

密码破解可以应用于多种场景,从用户离职后恢复系统访问权限,到渗透测试和红队测试,通过密码破解来证明(或否定)我们的访问控制机制的安全性。

在本章中,我们将涵盖以下主要主题:

  1. 什么是密码破解?
  2. 密码是如何存储和使用的?
  3. 为什么有些密码更容易被破解?

什么是密码破解?

密码破解是从混淆(通常是加密或哈希)文本中恢复秘密的过程。这个非常广泛的术语涵盖了许多类型的密码存储和混淆。因此,并非所有的密码破解操作都是相同的——一些密码以及密码存储的方法比其他的更容易破解。在本书中,我们将详细讨论这一点。

密码破解可以分为多种方法来尝试恢复秘密:

  1. 基于字典的方法
  2. 组合方法
  3. 暴力破解
  4. 混合方法
  5. 部分已知(也称为掩码攻击)

让我们逐一讨论这些方法。

基于字典的攻击

顾名思义,基于字典的攻击使用一系列单词或短语作为密码候选——我们将测试这些潜在密码,看它们是否是正确的密码。尽管这个列表被非正式地称为字典,但它可能并不包含字典中的单词。事实上,这个术语更多的是对早期时代的延续,当时许多密码都是基于字典单词的,而不是如今要求增加大写字母、数字和符号的复杂密码。

谈到复杂性要求,传统的字典单词似乎在密码破解操作中作为密码候选的效果不会那么好,因为复杂性要求变得越来越普遍。我们将在后续部分解决这个问题。

构建用于字典攻击的词列表可能很简单,也可能耗费时间。然而,在许多情况下,提前花时间为你的目标定制一个好的词列表在破解时会有很大的收益。这里的权衡是,你的词列表可能在其他密码破解情况下的重用性较差。我们将在第二章《为什么在OSINT能解决问题时还要破解密码?》中讨论如何使用开源情报(OSINT)来帮助构建词列表。

一个好的、相当大的初始词列表通常是RockYou词列表。这个词列表因2009年RockYou公司的数据泄露事件而得名,当时超过3200万个用户凭证被曝光。尽管这个词列表可以在互联网上的多个地方找到,但一个常见的下载地址是:github.com/brannondors…。该列表包含超过1400万个唯一的密码候选,并且也包含在许多常见的渗透测试发行版中,如Kali Linux(可在www.kali.org/get-kali/#k…)下载 和Slingshot Linux(可在www.sans.org/tools/sling…下载。

组合攻击

组合攻击使用两个词列表作为输入,并将每个列表中的一个密码候选连接(拼接)在一起,以创建用于测试的密码候选。例如,一个词列表可能包含单词word1和word2,而第二个词列表可能包含单词word3和word4。

在这种情况下,组合攻击会使用来自两个列表的单词来创建潜在的密码候选,例如word1word3、word1word4、word2word3和word2word4。

国家标准与技术研究院(NIST)的当前指导建议密码长度优于复杂性,以最好地抵御密码破解。这有助于鼓励用户创建易于记忆但难以破解的密码,并反映NIST的当前指导。这可以通过将几个字典单词串在一起并添加一个助记符来帮助用户记住密码来实现。这只是一个方法,但这个例子指出——结合当前NIST指导——随着更多用户按照建议转向密码短语,组合方法的密码破解可能更有效。

尽管如此,一些标准可能会减缓较长但不太复杂的密码短语的采用。例如,支付卡行业数据安全标准(PCI-DSS)要求处理信用卡数据的商户使用12个字符的密码,并且这些密码必须包含字母和数字,用于与持卡人数据相关的账户。

暴力破解

暴力破解正如其名称所示——每个密码候选的每个位置都用所有可能的候选填充。例如,如果密码只能是八个字符长,暴力破解方法可能首先尝试aaaaaaa作为密码候选,然后尝试aaaaaaab,以此类推,直到尝试完所有可能的密码。这种方法的问题在于,一旦密码长度达到任何合理的长度,执行这种攻击所需的时间就变得难以承受。此外,可用于密码的字符集(小写、大写、数字和符号)的数量也会大大增加完成这种攻击所需的猜测次数。

密码破解的好消息是,用这种方法可以破解任何密码。然而,以现今的计算能力来看,对于较长的密码或更复杂的(对每次密码猜测都更耗时的)算法,这种方法实际上是不可行的。

混合攻击

混合攻击融合了组合攻击和暴力破解的一些特征。混合攻击以一个词列表为基础,然后通过在词后添加一个或多个字符并对这些字符空间进行暴力破解来修改词列表中的单词。例如,假设我的词列表中有以下单词:

banana

然而,我知道我的目标密码政策要求每个密码中包含一个数字。我可能会尝试一种混合攻击,将词列表中的单词后面添加一个数字。所以,现在我的密码候选如下:

banana1 banana2 banana3 banana4

这使我们能够更有效地测试那些用户经常在其密码中添加(在末尾)或前置(在开头)一些基础字典单词的环境。

部分已知(也称为掩码攻击)

掩码攻击利用了我们对密码构建格式的部分了解,创建一种类似暴力破解的方法,但由于我们对密码格式的假设而加快了速度。

一个例子会很有帮助。假设我们正在测试一个要求密码必须包含一个大写字符、一个小写字符和一个数字的公司的密码。这是许多公司中常见的密码复杂性要求,许多用户会通过选取一个单词(字典中的或其他),将单词的第一个字母大写,然后在单词后面添加一两个数字来满足这一要求。

顺便提一下,这种类型的密码要求,加上90天密码轮换周期,可能会导致可怕的季节-年份密码,用户会将其密码设置为当前季节的名称(春季、夏季等)并在密码后面添加两位或四位数的年份(Spring22/Spring2022,Summer22/Summer2022等)。

这些复杂性要求可能会引导我们构建一个假设用户会选择以大写字母开头、然后是五到六个小写字母、最后以两位数(0-9)的密码的掩码。这个掩码会尝试暴力破解任何满足这些长度和条件的密码。虽然这不会检索到给定列表中的每个密码,但这种方法历史上会产生高比例的破解密码,因为这种方法是用户构建密码时常用的方法之一。

重要提示

我们将在第11章中建议更好的密码构建方法和缓解措施。

密码是如何存储和使用的?

虽然这看似简单,但密码在系统中的存储方式对其能否通过密码破解操作恢复以及所需时间有着巨大的影响。

你不一定需要破解密码!

大多数密码通过某种过程存储在身份验证系统中,使密码难以恢复。然而,遇到不适当保护用户凭证的系统也并非闻所未闻。你可能记得我们在本章前面讨论过的RockYou泄露事件。在RockYou的情况下,公司以明文(无哈希或加密)存储用户密码,这使得恢复用户密码变得非常简单。这意味着一旦用户密码公开,它们就完全暴露了——不需要密码破解或其他复杂操作,它们就直接可以被获取。

让我们谈谈我们通常看到的两种负责的密码存储方式:哈希和加密。

哈希

密码哈希的想法是存储用户的密码,使得任何人都无法检索密码。这种方法有几个优点:

  • 对存储密码的公司来说,这代表了一种强有力的尽职调查,并且可能在法律上提供一些保护。
  • 密码不能从哈希值中还原为明文(原始密码),这意味着具有密码存储访问权限的恶意内部人员无法检索密码。
  • 许多应用框架中存在执行这种哈希的标准函数,这意味着很容易实现。

其核心是,哈希将一串明文(密码)转换为固定长度的不可读数据字符串。这个值不能还原为明文,这是哈希与加密的核心区别之一。此外,对于相同的输入,这个哈希过程将始终返回相同的值;这被称为确定性。一些类型的哈希还可以添加一个盐值,增加生成哈希值的熵(随机性)。每个密码的盐值都不同,可以抵消预计算攻击的效果——这种攻击在破解操作之前生成所有可能的哈希值(你可能听说过彩虹表,它是一种预计算攻击)。哈希算法在用于创建存储的哈希的轮次(哈希操作)、输出长度以及其他几个因素方面有所不同。当我们深入讨论不同类型的密码检索时,我们将讨论各种哈希算法。

在哈希的情况下,通过获取用户的密码、对其进行哈希并将其与存储的哈希进行比较来验证密码。如果它们匹配,则密码是正确的;如果不匹配,则输入的密码不正确。在这个过程中,哈希通过确保系统在哈希后从不处理明文密码来进一步保护明文密码。

加密

加密与哈希不同,加密文本(加密算法的产物)可以还原回原始明文(密码)。为此,必须生成一个或多个加密密钥,并用于加密和解密操作。

加密在用作密码存储时有一些缺点。最突出的一个是加密文本是可逆的,这意味着如果恶意内部人员或外部方能够获取加密文本和加密密钥,他们可以检索明文密码。此外,由于加密和解密操作需要使用密钥,因此密钥必须是可检索的,这进一步增加了误用和/或泄露密钥的可能性。

加密作为密码哈希(或更差)的简单检查

你是否曾经忘记密码并在应用中使用了“忘记密码”链接或工作流?你可能有。如果你曾使用“忘记密码”功能,并通过电子邮件或其他明文方法(而不是被提示设置新密码)接收到密码,这意味着你的密码是以加密格式存储在那个系统中的。如果使用了密码哈希,他们将无法检索你的明文密码。还有另一种可能——系统将你的密码以明文存储,类似于RockYou的做法。我们已经看到这是一个非常糟糕的主意,但不幸的是,有时会这样做。

在使用加密密码进行身份验证的情况下,可以比较加密文本(类似于使用哈希的身份验证),或者可以解密密码并将其与用户提供的密码进行比较以验证密码。

虽然这里提到加密是为了完整性,但使用加密存储密码并不理想,也不推荐在NIST 800-53标准中使用。

为什么有些密码比其他密码更容易被破解?

有几个原因,但归根结底是一个问题:系统猜对密码所需的时间。如果我们能创建需要更长时间才能被破解的密码,那么我们就创造了一个更难破解的密码。反之,如果我们创建的密码需要更短的时间猜中,那么这个密码就更容易被破解。

那么,哪些因素使密码更容易(或更难)被破解呢?以下是一些最重要的因素:

  • 密码长度
  • 密码复杂性
  • 哈希/加密密码的时间

让我们逐一讨论这些因素。

密码长度

用户通常会以最低标准来考虑密码长度。换句话说,如果系统要求至少八个字符的密码,许多用户会选择一个八个字符长的密码。

在撰写本文时,NIST(美国国家标准与技术研究院)在其密码建议中保持最低八个字符的标准。这在NIST特别出版物(SP)800-53B中有提到,并会不时更新。然而,NIST也指出,系统应接受用户输入至少64个字符的密码。

让我们思考一下八个字符的密码。要猜测一个人的八字符密码需要多少次尝试呢?答案是,像信息安全中的许多事情一样,这取决于情况。让我们从一个简单的字符集开始,该字符集由26个小写字母组成。成功确定此密码所需的猜测次数表示为x的y次幂,即xy,其中x是密码每个位置的可能字符,y是密码的总字符数。对于我们的26字符小写密码,它的长度为8个字符,需要268次猜测,即208,827,064,576次猜测。请注意,这是最大猜测次数——这表示有人猜测了所有可能的密码并仅在最后一次猜测中成功。这是一个很大的猜测数量!但这是否意味着这个密码是安全的呢?再一次,这取决于情况。我们每次尝试猜测并验证是否正确需要多长时间?即使每次猜测多或少几毫秒也会对遍历所有可能性所需的总时间产生巨大影响。

如果我们选择一个比NIST最低建议长度更长的密码呢?比如九个字符的同样的小写英文字母密码呢?那就是269或5,429,503,678,976次猜测。正如你所预料的,这比八字符密码多了26倍的猜测次数。

当我们用同样的26字符集达到12字符密码时,我们看的是2612,即95,428,956,661,682,176次猜测(约95千万亿次)。这是八字符密码所需猜测次数的456,976倍!

在图表中可视化这一点(见图1.1),我们可以看到每增加一个密码字符所需的猜测次数呈指数增长:

【图1.1 密码长度与猜测次数的关系图表】

image.png

对于那些构建安全系统的人来说,这很好,这意味着每个字符在密码长度方面都很重要。密码越长,破解所需的时间就越长,安全性(抗破解能力)就越高。

密码复杂性

密码复杂性的理念与密码长度类似,都是为了使密码更具抗破解能力。然而,复杂性采取了不同的方法——对于密码中的每个字符,我们增加了可能用来填充该位置的字符种类。让我们通过回顾上一节的数学计算,看看这在实践中是如何运作的。

如果我们将大写英文字母添加到我们的小写英文字母字符集中,我们将有52个可能的字符。所以,现在,我们的8字符密码将需要52^8次猜测,即53,459,728,531,456次猜测。在这里,增加额外的26个字符显著增加了猜测次数。此外,由于这是一个指数运算,随着密码长度的增加,每个字符的猜测次数的增加可以以与26字符密码相同的方式可视化(见图1.2):

image.png

如图1.1所示,增加密码长度会增加识别密码所需的总猜测次数。同样,在图1.2中,我们可以看到增加密码的复杂性会增加所需的猜测次数,而同时增加长度和复杂性则会更快地增加所需的猜测次数!那么,哪种方法更好?或者我们是否应该两者都使用?要回答这个问题,我们需要先看看数学,然后再结合心理学。

一个包含大小写字母的八字符密码最多需要53,459,728,531,456(53万亿)次猜测。而一个仅包含小写字母的十字符密码则需要几乎三倍的猜测次数——141万亿次。现在,让我们谈谈心理学。对于人类来说,哪种密码更容易记住——一串全小写字符,还是一串包含大小写字母的字符?可能会出现以下两种情况之一:

  1. 用户会通过将密码的第一个字母大写而其余保持小写来创建一个易于记住的密码。这在破解过程中很容易处理,并且违背了增加额外字符集的初衷。如果密码的第一个字母大写,那么有26种可能选择,这与使用小写字符时的选择数量相同。如果用户接下来将密码的其余部分保持小写,那么每个字符也只有26种可能选择。在这种情况下,八字符密码有26^8种可能性,而不是52^8种可能性——这与密码一开始就是小写时的可能性数量相同!
  2. 第二种可能性是用户创建了一个难以记住的密码,并将其写在纸上或存储在密码管理器中。虽然使用密码管理器通常是理想的行为,但将密码写在可能被发现的地方则不然。

那么,这让我们得出什么结论呢?人类的大脑会发现全小写密码比一串大小写字母、一串大小写字母和数字或一串大小写字母、数字和符号更容易记住。我们可以增加全小写密码的长度,并且仍然创建一个抗破解的密码。这是NIST的当前建议——SP 800-53B的当前修订版建议在创建密码时不需要使用密码组合规则(第5.1.1.2节)。

哈希/加密密码的时间

创建抗破解密码的第三个主要因素不是密码本身的选择,而是生成哈希所需的计算操作及其耗时。想想我们之前讨论的各种类型密码所需的猜测次数。每次猜测都需要非零时间来执行。我们必须计算该密码候选的哈希值,然后将其与已知的哈希值进行比较,看看它们是否匹配(意味着我们的密码候选即为密码)。

如果这个操作需要一整秒而不是半秒,那么破解过程的总时间将加倍。实际上,猜测会发生得更快,但为了说明问题,你可以看到这对我们在这些情况下处理的猜测次数有多大影响。

哈希算法设计得很快。哈希是一种常见的计算操作用于比较,我们希望它们快。然而,我们希望密码哈希特别慢——我们希望它尽可能慢。密码哈希操作越慢,实现抗破解的能力就越强,因为每次尝试的计算成本更高。像PBKDF2这样的密码哈希算法使用常见的哈希算法如SHA-512,但运行许多轮次的哈希算法以增加生成密码哈希的时间。

虽然每次哈希的时间增加会导致破解操作变慢,但破解者可以通过增加每秒执行的哈希次数来抵消这一点,要么通过增加用于破解过程的计算能力,要么通过将破解操作的负载分布到多个计算引擎上。在第二部分《密码破解类型和方法》中,我们将根据我们要破解的哈希类型来看各种破解操作的整体速度。

关于“伦理”密码破解

无论采用哪种方法,本书的目标是帮助你掌握恢复密码所需的工具和技术,无论你是在进行渗透测试/红队行动,还是为不幸去世的用户恢复备份密码,或是在其他类似的情境中。

这里需要强调的重要警告是,本书专注于伦理密码破解。本书的目的是帮助你在渗透测试任务中发现漏洞,或通过其他合法手段支持你的业务,而不是帮助你规避法律或从事非法活动。

在对公司密码使用这些技术之前,请务必咨询你的法律顾问和/或公司法律顾问。

总结

在本章中,我们介绍了密码破解的概念、各种破解攻击类型、密码的存储和使用方式,以及如何创建更强密码的一些理由。通过这些内容,你已经为开始各种类型的密码破解奠定了基础。

然而,如果我们能完全不需要破解密码,那岂不是更简单?在某些情况下,我们可以做到这一点,因为可以利用诸如之前的数据泄露和密码重用等信息。在下一章中,我们将探讨如何使用开放源代码情报(OSINT)来查找先前泄露的信息或为特定目标构建自定义词典。