Slack用户枚举工具SlackEnum:绕过速率限制实现批量用户发现

本文介绍SlackEnum工具的开发过程,该工具通过多账户轮询机制绕过Slack的速率限制,实现批量枚举用户邮箱和姓名,适用于企业安全评估和渗透测试场景。

SlackEnum:Slack用户枚举工具

近期,在ANTISOC持续渗透测试(CPT)服务中,我研究了攻击者如何利用Slack发起网络攻击,类似于红队演练中常用Microsoft Teams识别用户和执行攻击的方式(Slack显然试图防止此类行为)。针对Slack特别有趣,因为即使组织没有Slack订阅,其内部用户也可能拥有与工作邮箱关联的Slack账户,并在工作设备上使用Slack应用或网页界面。事实上,在对CPT客户运行本文所述的枚举攻击后,一些客户惊讶地发现数百名员工拥有活跃的Slack账户,尽管组织并未官方使用Slack。

Slack的用户枚举“功能”

用户枚举基于一个简单前提:如果网站在输入无效用户ID和有效用户ID时行为不同,则通过观察网站响应即可确定给定用户ID是否有效。在Slack中,邮箱地址即用户ID——用于登录账户和识别其他用户。

登录Slack后,用户可通过点击主屏幕“More”按钮,然后点击菜单中的“External connections”项来搜索其他用户。在结果页面顶部有一个搜索框,允许通过邮箱地址搜索用户。如果搜索没有Slack账户的邮箱,Slack会提示账户不存在;但搜索有效用户邮箱时,会显示用户邮箱和可点击的对话按钮,有时还会显示用户姓名(通常为全名)。

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

尽管用户枚举在Slack上似乎是预期的,但攻击者不在乎枚举是漏洞还是功能。对攻击者而言,收益相同:我们可以确认邮箱地址存在、确认所有者拥有Slack账户,有时还能获取账户所有者全名。Slack似乎意识到这一点,因为从免费账户枚举超过约10个用户会触发速率限制。此时,账户在冷却期内无法查找其他用户。

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

尽管有速率限制,我仍想滥用此功能枚举Slack账户,并批量进行以识别所有CPT客户的组织范围内Slack用户。由于此用户枚举方法仅在我登录时可行,仅更改IP地址无法绕过速率限制,因为受限的是我的用户账户而非IP地址。

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

基于此概念,我开始自动化用户枚举过程。

自动化规划

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

  1. 当前搜索查询,响应指示我的账户被速率限制。检查此请求提供了路径“/api/connectableContacts.lookup”,我的搜索在此提交;响应中的“error”:”ratelimited”文本提供了速率限制触发的明确指示。
  2. 冷却期过后,我的用户账户不再受限,我使用Burp Repeater重放相同请求。搜索同一无匹配Slack账户的邮箱,捕获了不存在的账户的响应。
  3. 修改请求中的邮箱地址,再次通过Burp Repeater发出。这次搜索我知道存在的账户邮箱,看到了服务器对有效账户的响应以及响应数据格式,以便在存在时提取用户姓名。

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

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

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

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

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

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

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

如何创建100个Slack账户

由于在短时间內只能进行约10次搜索请求 before 一个用户账户被速率限制,我需要创建更多用户账户,以便同一账户重复请求之间的时间尽可能长。

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

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

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

老实说,我宁愿再次爬楼梯也不愿坐在电脑前创建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账户中,点击“Invite Coworkers”并粘贴你刚生成的所有邮箱地址列表。

现在,在你的邮箱中,你会为每个邮箱地址收到一个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 IDs”,以给它们一个清晰的名称,与目标枚举账户分开。

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

整体组装

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

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

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

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

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

如果响应指示请求成功接收(“ok”:true)但无此类账户存在(“contacts”数组为空),脚本创建日志文件条目并在屏幕上打印“Invalid account”消息。 如果响应指示请求成功接收(“ok”:true)且用户存在(“contacts”数组包含用户详细信息),则脚本将用户的邮箱地址和姓名记录到输出文件作为有效用户账户,并在屏幕上打印“Slack account confirmed”消息。 如果响应包含“ratelimited”错误,当前Slack ID被添加到速率限制的Slack IDs列表,等待直到冷却期过去。同一目标邮箱地址将在下一个循环中用列表中的下一个Slack ID测试。 如果发生任何其他情况,输出被视为未知错误。循环继续,同一目标邮箱地址在循环中用下一个Slack ID测试。

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

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

健全性检查

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

结论

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

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

如果你喜欢此内容,你可能想查看我的课程“Red Team Initial Access”,我教授我们今天用于通过互联网闯入现代企业环境的所有常用技术。

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