[访客日记] 蜜罐密码与HIBP对比分析
DShield蜜罐持续暴露在互联网上,充斥着漏洞利用流量、登录尝试和其他恶意活动。分析记录的密码尝试有助于识别攻击者的目标。为了处理这些密码,我创建了一个利用HaveIBeenPwned(HIBP)API的工具,用于标记未在任何数据泄露中出现过的密码。
目的
识别在已知泄露中未出现的密码很有价值,因为这可能表明攻击者进行了额外规划,并有助于识别这些较不常见密码中的模式。任何运营蜜罐(并接收大量明文密码尝试数据)的人都可以将此项目作为调查的额外起点。
开发过程
HaveIBeenPwned维护着一个庞大的泄露密码数据库,并提供一个API来检查给定密码是否已泄露。这是通过向“https://api.pwnedpasswords.com/range/#####”发出请求来实现的,其中“#####”是被测试密码SHA1哈希值的前5个字符(前缀)。该网站将返回数据库中以前缀开头的任何密码哈希的最后35个字符(后缀)。每个条目包括相应密码在泄露中被看到的次数。这防止任何人仅基于请求就知道我们正在查找的密码的完整哈希值。
为了收集蜜罐收集的所有密码列表,我使用JQ解析位于/srv/cowrie/var/log/cowrie目录中的cowrie.json文件:
|
|
为了扩展这一点,我们可以使用sort和uniq删除重复项,并将唯一密码保存到文件中:
|
|
在撰写本文时,这将密码数量从51,601个减少到16,210个唯一密码。
现在我有了唯一密码列表,接下来的步骤是:读取创建的密码文件,获取每行的SHA1哈希值,查询API获取哈希前缀,并在结果中检查哈希后缀。
为了实现这一点,我创建了一个Python脚本,使用一个输入文件和两个输出文件。输入文件包含要检查的密码列表,每行一个条目。一个输出文件存储所有已检查的密码、SHA1哈希值以及HIBP看到该密码的次数(此文件为CSV格式,用于避免重复检查输入文件中的密码)。另一个输出文件存储HIBP从未见过的任何密码的明文。命令行用法如下:
|
|
这导致识别出1,196个HIBP未见过的密码。
代码解析
代码可在GitHub上获取[3],有详细的注释,但我们将在此检查部分内容以更深入理解其功能。
图1显示了处理读取结果文件的代码部分,该文件包含我们搜索过的所有密码。这预期格式为带有“password,sha1,count”标题的CSV文件。如上所述,这有助于避免不必要地检查密码。
代码使用csv.DictReader打开文件,检查标题中的“password”,然后使用for循环遍历所有行以提取非空密码并将它们添加到集合中。集合在函数结束时返回。
图1:用于读取所有先前检查过的密码的代码
图2显示了用于发出API请求和处理常见错误的代码。首先,建立一个循环并发出API请求。其次,我们检查429响应代码,这意味着请求过多。如果存在429错误,HIBP将添加一个“Retry-After”标头,告诉我们重试前要等待多长时间。用户代理在其他地方指定为“PasswordCheckingProject”,因为HIBP声明“缺少用户代理将导致HTTP 403响应”[4]。
图2:用于发出API请求和处理预期429错误的代码
图3显示了处理其他错误和正常功能的行为。首先,调用“resp.raise_for_status”,如果HTTP请求有错误,将引发异常。如果没有错误,我们只需遍历响应的所有行以将哈希后缀和计数保存在字典中,然后返回它。如果引发异常,我们递增一个“attempt”变量,这让我们可以限制重试次数,默认设置为三次。如果达到最大值,代码将打印错误消息指示正在检查的前缀并退出。如果还有更多重试剩余,脚本将在继续前等待5秒。图2有类似的最大重试检查,以避免潜在的429错误无限循环。
图3:用于存储和返回请求结果或处理持续/意外错误的代码
实施
要下载项目并使用一些测试数据尝试,可以运行以下命令:
|
|
当脚本运行时,它将打印出每个识别的未见密码,并在最后显示一个简短摘要,如图4所示。
图4:使用真实数据的脚本输出
自动化
为了自动化使用此工具,我创建了一个cron作业来运行JQ命令并将结果输出到文件,并创建了另一个作业来使用所需参数运行脚本。这些设置为每天运行,脚本在JQ命令运行5分钟后运行。这使用以下crontab条目:
|
|
脚本在JQ命令运行5分钟后运行,以确保有足够的时间创建输入文件。由于日志保留时间有限,无需担心这会开始花费更长时间。
我选择这种方法而不是将解析功能添加到脚本中是出于便利性。使用脚本将需要额外的逻辑,并且要么硬编码要检查日志的位置,要么处理更多参数。按照设计,任何人都可以轻松插入密码列表,而无需担心许多命令行选项或编辑脚本。
结果
脚本准确提供了关于HaveIBeenPwned在先前泄露中未见过的密码的信息。虽然未见密码比预期的要多(截至撰写时为1,196个,约占所有唯一密码的7.4%),但它提供了一些参与者可能针对的目标的有趣见解。结果还揭示了用于访问尝试的密码变异模式:
|
|
密码模式与分析
分析上面结果部分看到的密码可以为了解用于生成密码的技术提供一些见解。
考虑上面的结果样本。广义上说,这个“deploy家族”的密码很可能是通过以“deploy”为基础密码并添加常见修饰符来增加复杂性而生成的。这里看到的是最简单修饰符的好例子:添加年份(在这种情况下带有@符号)和添加顺序数字。
上面的其余条目都基于单词“password”。这些比我们在“deploy”中看到的更复杂。以下是三个条目,一个可能用于提出它的Hashcat规则的简单解释,以及规则实现的示例:
P4$$word!@#
首字母大写,将a替换为4,将s替换为$,在末尾添加!@# - c sa4 ss$ $! $@ $#
P@55W0RD2004
所有字母大写,将a替换为@,将s替换为5,将o替换为0,并在末尾添加年份 - u sa@ ss5 so0 $2 $0 $0 $4
Password!2024
首字母大写,在末尾添加!和年份 - t0 $! $2 $0 $2 $4
Hashcat和John the Ripper都可以通过使用规则来增强密码列表来进行这些修改。规则允许对输入进行各种更改,例如将某些字符替换或交换为其他字符。请注意,虽然这些工具之间的大部分规则语法相似,但存在一些差异[5]。
浏览未见密码,我们还可以看到更具体的目标,如Elasticsearch、Oracle、PostgresSQL和Ubuntu。图5显示了一些这些密码,它们使用与前面提到的相同类型的修改,并说明了频率的相对差异。
图5:与特定服务/平台相关的密码
总体收获
虽然仍然需要大量手动分析,但这些结果可以提供很多价值,并且脚本有助于减少时间。我们可以了解更多关于要避免的常见密码修改,甚至可以了解不同目标的相对兴趣。仅在图5中,我们可以看到PostgresSQL可能比Elasticsearch被针对的可能性大约高两倍,特别是针对新安装。
对于未来的工作,我将添加一个功能来重新检查已知的未见密码,以识别它们是否恰好是新泄露的。
此外,我可能会考虑添加两个功能以方便使用。第一个是重新排序未见文件,因为它是仅追加的。第二个是解析功能,以简化自动化并允许脚本为最终用户提供更多功能。
[1] https://www.sans.edu/cyber-security-programs/bachelors-degree/ [2] https://haveibeenpwned.com/API/v3#PwnedPasswords [3] https://github.com/MeepStryker/queryHIBP [4] https://haveibeenpwned.com/API/v3#UserAgent [5] https://hashcat.net/wiki/doku.php?id=rule_based_attack#compatibility_with_other_rule_engines