SlackEnum:绕过速率限制的Slack用户枚举工具

本文介绍了SlackEnum工具的开发过程,该工具通过多账户轮询机制绕过Slack的速率限制,实现大规模用户枚举,可收集用户名和邮箱地址用于安全评估。

介绍SlackEnum:Slack用户枚举工具

最近,作为我们ANTISOC持续渗透测试(CPT)服务的一部分,我有机会研究攻击者如何利用Slack进行网络攻击,类似于我们在红队演练中经常使用Microsoft Teams识别用户和执行攻击的方式(Slack显然在努力防止这种情况)。

针对Slack特别有趣,因为即使组织没有Slack订阅,组织内的个别用户也可能拥有与其工作电子邮件地址关联的Slack账户。他们可能还在工作设备上使用Slack应用或Web界面。实际上,在针对我们的持续渗透测试客户运行本文描述的枚举攻击后,一些客户惊讶地发现,尽管组织没有Slack订阅或以任何官方身份使用Slack,但数百名员工拥有与其工作电子邮件地址关联的活跃Slack账户。

在今天的博客文章中,我将分享开发SlackEnum的过程——这是一个新工具,可以枚举大量用户并收集他们的姓名和电子邮件地址以供进一步操作,同时绕过Slack旨在防止此滥用的速率限制控制。

注意:为避免暴露任何真实Slack用户,我已将本文中的未编辑电子邮件地址替换为域“example.com”上的虚构电子邮件地址。

Slack的用户枚举“功能”

用户枚举基于一个简单前提:如果网站在输入无效用户ID时的行为与输入有效用户ID时不同,则通过观察网站的响应可以确定给定用户ID是否有效。在Slack的情况下,电子邮件地址就是该用户ID——用于登录用户账户,并用于识别其他Slack用户。

登录Slack后,用户可以通过单击主屏幕上的“更多”按钮,然后单击菜单中的“外部连接”项来搜索其他用户。

在结果页面的顶部有一个搜索框,允许通过电子邮件地址搜索其他用户。

如果您搜索没有Slack账户的电子邮件地址,Slack会告诉您该账户不存在。

但当您搜索有效Slack用户的电子邮件地址时,用户的电子邮件将显示在屏幕上,并带有一个可以单击以开始与他们对话的按钮。在某些情况下,用户的显示名称(通常是他们的名字和姓氏)也会显示在屏幕上。

在Slack上,这种用户枚举方法似乎是预期功能,而不是意外副作用。这进一步由以下事实证明:用户和企业订阅者可以通过禁用其账户上的“Slack Connect可发现性”设置来防止他人使用此方法找到他们。然而,在这两种情况下,可发现性默认启用,我尚未遇到在整个用户群中禁用可发现性的组织。

尽管Slack上的用户枚举似乎是预期的,但攻击者不在乎用户枚举是错误还是功能的结果。对攻击者的好处是一样的。我们可以确认电子邮件地址存在,确认所有者拥有Slack账户,有时还可以获取账户所有者的全名。

Slack似乎意识到了这一点,因为从免费账户枚举超过约10个用户会导致速率限制。发生这种情况时,账户在冷却期过去之前不允许查找任何其他用户。

用加特林机枪绕过速率限制

尽管有速率限制,我仍然想滥用此功能来枚举Slack账户,并想批量进行,以便为所有CPT客户识别组织范围内的Slack用户。

由于此用户枚举方法仅在我登录时可能,仅更改IP地址无法绕过速率限制,因为是我的用户账户而不是我的IP地址被速率限制。

但这给了我一个想法:

如果我将请求分散到多个Slack账户,每个账户的请求速率可能足够慢以避免触发速率限制。这类似于加特林机枪可以以非常高的速率发射一连串子弹,但枪管不会过热,因为子弹是从多个循环枪管发射的。第一个枪管发射后,其他枪管继续发射,给第一个枪管时间冷却,然后再次发射子弹。通过以这种方式将工作负载分散到多个枪管,没有枪管变得足够热以致过热。

有了这个概念,我开始自动化用户枚举过程。

自动化规划

使用Burp Suite,我捕获了通过Web界面与用户搜索功能交互时观察到的三种场景的浏览器请求和服务器响应:

首先,是当前搜索查询,其响应表明我的账户被速率限制。检查此请求为我提供了路径“/api/connectableContacts.lookup”,我的搜索正在其中提交;响应中的“error”:”ratelimited”文本提供了速率限制已触发的明确指示。

冷却期过后,我的用户账户不再被速率限制,我使用Burp Repeater重放相同的请求。我搜索了相同的电子邮件地址,该地址没有匹配的Slack账户。这让我捕获了不存在账户的响应。

然后我修改了请求中的电子邮件地址,并通过Burp Repeater再次发出。这次我搜索了我知道存在的账户的电子邮件地址,这让我看到了服务器对有效账户的响应以及响应数据的格式,以便在存在时提取用户的名称。

我重复了几次修改电子邮件地址和重新发出请求的过程,以确认响应继续匹配相同的JSON数据结构。手动修改和重放相同请求几次也确认了不需要单次使用令牌(例如CSRF令牌)来进行成功的搜索请求。

分析搜索API的最后一步是确定执行搜索时是否需要任何其他参数。首先,我从请求中删除了所有cookie并再次重放,以确保不允许未经身份验证的搜索查询。正如预期,此请求失败,我收到了“invalid_auth”错误。

我恢复了cookie,使请求再次正常工作,然后查看了POST参数。唯一看起来可能对我的用户账户唯一的POST参数是“token”参数,其值以“xoxc-”开头。

我修改了令牌值的最后几个字节,并重新发出相同的请求。再次,我得到了与之前删除cookie时相同的“invalid_auth”错误,这确认需要有效的令牌值来进行搜索请求。

我使用Burp Proxy在Web浏览器中使用Slack时生成的所有先前请求和响应中搜索令牌值。首次提到令牌值是在“/ssb/redirect”的响应中,Slack API将令牌值连同键名“api_token”发布到我的浏览器。

我在Burp Repeater中重放了几次“/ssb/redirect”请求,以确认每次发出请求时“api_token”值都出现在响应中,确实如此。

此时,我相当确定我有制作基本Slack用户枚举脚本所需的一切。我只需要自动化我刚走过的用户枚举过程的每个单独步骤,然后将整个东西包装在一个循环中,该循环将按顺序从多个Slack账户发射请求,就像加特林机枪的枪管一样。此外,我需要一大堆用户账户来充当这些枪管。

如何创建100个Slack账户

因为我只能在大约10次搜索请求后短时间内使一个用户账户被速率限制,所以我需要创建更多用户账户,以便同一账户重复请求之间的时间尽可能长。

因此,我创建了一百个Slack用户账户,全部加入同一工作区。

这无疑是整个项目中最长、最繁琐的部分。😅

这让我想起有一次在现场红队演练中,我从地面爬楼梯到50楼闯入CEO办公室。大楼里的保安在每层巡逻时乘坐电梯,因为显然没有人笨到爬楼梯到50层楼的顶部。有时获胜的不是任何技术或 fancy 的东西。有时只是做一些不舒服的事情,比对手认为任何理性的人会做的时间更长。

老实说,我宁愿再次爬楼梯,也不愿坐在这里在电脑上制作100个账户。幸运的是,至少Slack账户的创建比许多其他服务的用户账户快得多,我在几个小时内完成了。

如果您想使用SlackEnum,不幸的是您必须付出类似的代价,因为需要多个用户账户来绕过速率限制。因此,以下是我用于创建一堆Slack账户并将它们加入同一工作区的过程,尽可能减少点击和按键:

  1. 在NameCheap.com上购买一个域,并设置从该域到您的电子邮件地址的电子邮件转发。这将让您接收发送到该域上任何地址的所有电子邮件。

  2. 使用您域上的任何虚构电子邮件创建新的Slack账户和工作区。

  3. 生成您想要创建账户的任意数量的电子邮件地址列表。以下是在Linux上可用于生成99个电子邮件地址的命令示例(当然,将“your-domain.com”替换为您自己的域):

    1
    
    for n in {01..99} ; do echo user$n@your-domain.com ; done
    
  4. 在您的Slack账户中,单击“邀请同事”并粘贴您刚生成的所有电子邮件地址列表。

现在,在您的电子邮件中,您将为每个电子邮件地址收到一个Slack邀请。

打开其中一封电子邮件,单击邀请链接,输入名称,您将自动登录并加入您的Slack工作区。

登录后,使用CookieBro浏览器扩展将浏览器的cookie导出到文件。然后按CTRL+Shift+Del清除所有浏览器的cookie并重复。

Slack身份——加特林机枪的枪管

为了处理多个Slack账户,我最初写了一个函数来解析从Burp Suite保存的原始HTTP请求。由于我一直在使用Burp进行所有初始测试,当时这似乎很方便。但是,正如我在上一节中提到的,在我开始创建和登录多个Slack账户后,我发现使用CookieBro导出cookie更快。因此,结果是SlackEnum接受两种不同格式的Slack账户:从Burp复制和保存的原始HTTP请求,或包含所有用户cookie的CookieBro导出的JSON文件。

在SlackEnum中,我将这些攻击者控制的Slack账户称为“Slack身份”或“Slack ID”,以给它们一个清晰的名称,与目标枚举的账户分开。

Slack ID保存到两个用户可配置的文件夹——一个用于Burp请求,一个用于CookieBro文件——并且在启动脚本时,这些文件夹中的所有文件都会被加载和解析。由于CookieBro文件仅包含cookie,Slack工作区主机名和浏览器用户代理字符串被硬编码到SlackEnum的“slackenum.py”最顶部的“设置”部分。因此,从CookieBro文件导入的所有Slack ID必须加入同一Slack工作区,并且该工作区主机名必须在脚本顶部的“default_host”设置中配置。

整合一切

在脚本的第一部分执行以处理Slack身份后,启动加特林机枪循环以枚举用户。

SlackEnum执行的整个过程大致如下:

  1. 加载用户配置的设置,硬编码到脚本开头。这些包括CookieBro Slack ID的默认Slack工作区主机名和默认用户代理字符串,以及输出文件名、计时设置和代理设置,以便脚本可以选择通过其他工具(如Burp Suite)进行代理。
  2. 加载目标枚举的电子邮件地址列表。
  3. 从存储它们的两个文件夹中的所有文件加载和解析Slack ID。然后将Slack ID存储在字典中,该字典跟踪每个Slack ID的工作区主机名、cookie和用户代理头。还跟踪每个Slack ID的速率限制状态以及当前是否登录。
  4. 从先前步骤加载的所有信息中,生成一些非常粗略的枚举可能所需时间的估计。实际上,这些估计有时最终较低,由于一些计时选项增加的延迟,或者如果计时设置过低,由于速率限制引起的延迟。我包含了这些统计信息,因为它们可能有助于调整脚本顶部的计时配置或决定需要多少Slack ID。(我建议至少100个Slack ID以获得合理有用的速度。)

如果用户按Enter继续执行,SlackEnum在循环中运行以下步骤,加特林机枪风格,直到所有目标电子邮件地址都被查询:

  • 从池中选择一个Slack ID,并检查以确保它仍然登录且未被速率限制。
  • 从“/ssb/redirect”请求Slack ID的API令牌。
  • 如果无法检索令牌,Slack ID被标记为注销,循环从列表中的下一个Slack ID重新开始。
  • 向“/api/connectableContacts.lookup”发出POST请求以搜索列表中的下一个目标电子邮件地址。

如果响应表明请求成功接收(“ok”:true)但不存在此类账户(“contacts”数组为空),脚本创建日志文件条目并在屏幕上打印“无效账户”消息。

如果响应表明请求成功接收(“ok”:true)且用户存在(“contacts”数组包含用户详细信息),则脚本将用户的电子邮件地址和名称记录到输出文件作为有效用户账户,并在屏幕上打印“Slack账户确认”消息。

如果响应包含“ratelimited”错误,当前Slack ID被添加到速率限制的Slack ID列表中,在那里等待直到冷却期过去。同一目标电子邮件地址将在下一个循环中用列表中的下一个Slack ID进行测试。

如果发生任何其他情况,输出被视为未知错误。循环继续,同一目标电子邮件地址在循环中用下一个Slack ID进行测试。

这是此执行阶段的输出,从上次屏幕截图停止的地方继续。屏幕上左侧括号中的“00.txt”、“01.json”等文件名指示每个请求使用的Slack ID文件。

这是同一扫描的相同输出,如CSV输出文件中所示。

健全性检查

最后,由于我不想冒险启动长时间运行的枚举扫描与任何注销或有其他问题的Slack ID,我添加了一个“–sanity”标志。此标志允许用户提供单个已知有效的电子邮件地址,然后用每个可用的Slack ID枚举同一账户。这样,可以在开始长时间运行作业之前快速识别生成错误或假阴性的任何Slack ID。

结论

好了,就是这样。我希望您喜欢这篇文章。🙂

如果您想自己尝试SlackEnum,可以在GitHub上下载:https://github.com/Wh1t3Rh1n0/SlackEnum

如果您喜欢此内容,您可能想查看我的课程“红队初始访问”,我在其中教授我们今天用于通过互联网闯入现代企业环境的所有常用技术。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计