每天都有各种各样的API密钥、密码和客户数据被发布到Github上。黑客使用这些密钥登录服务器,并收取费用,Github泄密可能会给公司造成数千甚至数百万美元的损失。在Github上收集源码的情报已经成为每个网安工作人员的必备手段,有研究人员还针对该主题写了一篇学术论文。
本文是为bug赏金猎人以及其安全团队编写的,演示了用户发布到Github公共存储库的常见敏感信息类型,以及查找这些秘密的启发性方法。本文中的技术也可以应用到GitHub Gist片段中。
在过去的一年里,我在没有访问程序网站的情况下,通过HackerOne上的漏洞奖赏获得了近1万美元的收益。向不同公司提交了30多份协同披露报告,其中包括8家财富500强公司。
我还发布了GitHound,这是一个开源工具,用于在GitHub上自动查找密钥。GitHound并不局限于单个用户或组织,它会筛选整个Github仓库,使用代码搜索查询作为进入存储库的入口点,然后使用上下文、正则表达式和其他一些巧妙的技巧快速查找密钥。
Github代码搜索
在我们进入自动化工具和漏洞奖赏策略之前,我们先说一说代码搜索。Github提供了丰富的代码搜索,可以扫描GitHub公共存储库(这里忽略一些内容,比如fork和非默认分支),像uberinternal.com那样简单,也可以包含多个字符串,也可以包含类似"Authorization: Bearer"这样的多单词字符串,甚至可以针对特定的文件进行搜索,(如文件名:vim_settings.xml)或特定的语言(如SQL)。还可以搜索vim_settings.xml。
了解了Github代码搜索的规则,我们就可以设计出搜索dork,用它来查询敏感信息,dork可以在网上找到,但最好的Dork都是自己创造的。
例如,filename: vim_settings.xml针对的是IntelliJ设置文件。有趣的是,vim_settings.xml文件包含最近用Base64编码的复制粘贴字符串。我也因为发现了这个问题而赚了2400美元,SaaS API密钥和客户信息在vim_settings.xml中被暴露。
xml只包含最近复制粘贴的字符串,但是我们可以利用存储库的提交历史来查找整个复制粘贴历史。只需要克隆代码库并运行这个14行脚本,用户的活动就掌握在你手中,GitHound还可以查找并扫描base64编码的字符串以查找密钥,甚至在提交历史中也是如此。
值得一提的是,通过Github提交搜索,我们可以用GitHound快速扫描查找base64编码的字符串以查找密钥,甚至在提交历史中也是如此。
给Bug赏金猎人的一些启发
Github的dork通常能找到敏感的密钥,但如果我们想要寻找某个特定公司的信息呢?GitHub有数百万个存储库和更多的文件,因此我们需要一些启手段来缩小搜索空间。
想要寻找敏感信息,首先要确定一个目标,最好的办法就是先从目标公司基础架构中的域或子域下手。
用company.com搜索可能不会提供有用的结果,大多公司发布的开源项目都是经过审核的,不太可能包含密钥,较少使用的域和子域机会还大一些,其中包含主机,如jira.company.com,以及更一般的二级和低级域名。查找模式比查找单个域更有效:corp.somecompany.com、somecompany.net或companycorp.com更有可能只出现在员工的配置文件中。
以下常见的开源情报与域侦查工具可能会对你有所帮助:
- Subbrute - 用于蛮力破解子域的Python dork
- ThreatCrowd - 给定一个域,通过多种OSINT技术查找相关域
- Censys.io- 给定一个域,找到使用它的SSL证书
GitHound还可以帮助进行子域发现:添加一个自定义regex \.company\.com并使用——regex文件标志运行GitHound。
在找到要搜索的主机或模式后,可以使用GitHub搜索(在使用自动化工具之前,我总是这样做)。这里要注意以下几个问题:
- 搜索出来的结果有多少?如果有超过100个页面,我可能需要找到一个更好的查询重新开始(Github将代码搜索结果限制为100页)。
- 结果是什么?如果搜索结果主要是开源项目和使用公共api的人,那么我可能可以改进搜索把这些去掉。
- 如果改变语言会发生什么?language:Shell 与 language:SQL可能会产生有趣的结果。
- 这些结果是否揭示了其他域名或主机?前几页的搜索结果通常会包含对另一个域名的引用(比如搜索jira.uber.com可能会显示另一个域名的存在,比如uberinternal.com)。
我在这一方面花了大量的时间,搜索空间的定义和它的准确性是至关重要的,自动工具和手动搜索将更快和更准确的查询。
一旦我根据上面的标准发现了有趣的结果,我就会使用带有 --dig-files 及 --dig-commits 参数在GitHound中运行,查看整个存储库的历史。
- echo "uberinternal.com" | ./git-hound --dig-files --dig-commits
- echo "uber.com" | ./git-hound --dig-files --language-file languages.txt --dig-commits
- echo "uber.box.net" | ./git-hound --dig-files --dig-commits
GitHound还可以找到简单搜索无法找到的有趣文件,比如.zip或.xlsx文件。重要的是,我还手动查看结果,因为自动化工具经常会漏掉客户信息、敏感代码和用户名/密码组合。通常,这将会让你发现更多的子域名或其他有趣的东西,给我更多搜索查询的想法,最重要的是要记住,开源情报是一个递归的过程。
这个过程几乎都能让你有所得,泄露通常分为以下几类(从影响最大到影响最小):
- SaaS API密钥——公司很少对API施加IP限制。AWS、Slack、谷歌和其他API密钥都是机会。这些通常可以在配置文件、bash历史文件和脚本中找到。
- 服务器/数据库凭证——这些通常在防火墙后面,所以它们的影响较小。通常可以在配置文件、bash历史文件和脚本中找到。
- 客户/员工信息——这些信息隐藏在XLSX、CSV和XML文件中,范围从电子邮件一直到账单信息和员工绩效评估。
- 数据科学脚本 - SQL 查询、R 脚本以及 Jupyter 项目等都有可能暴露敏感信息。这些库中也往往带有“测试数据”文件。
- 主机名/元数据——最常见的结果,大多数公司不认为这是一个漏洞,但他们可以帮助改进未来的搜索。
针对特定 API 提供程序的入侵流程
还可以特定的API提供者及其端口创建Dork,这对于为用户的API密钥创建自动检查的公司尤其有用。通过了解API键的上下文和语法,可以明显减少搜索空间。
通过了解特定的API提供者,我们可以获得与API提供程序正则表达式相匹配的密钥,然后我们可以使用内部数据库或API端点检查它们的有效性。
例如,假设一家公司(HalCorp)为用户提供了一个API来读写他们的帐户。通过创建我们自己的HalCorp帐户,我们发现API键的形式是[a-f]{4}-[a-f]{4}-[a-f]{4}。
- # Python
- import halapi
- api = halapi.API()
- api.authenticate_by_key('REDACTED')
- # REST API with curl
- curl -X POST -H "HALCorp-Key: REDACTED" https://api.halcorp.biz/userinfo
有了这些信息,我们可以为HalCorp API响应编写自己的GitHub程序:
- # Python
- "authenticate_by_key" "halapi" language:python
- # REST API
- "HALCorp-Key"
使用GitHound这样的工具,我们可以使用正则表达式匹配来找到匹配API键的正则表达式的字符串,并将它们输出到文件中:
- echo "HALCorp-Key" | git-hound --dig-files --dig-commits --many-results --regex-file halcorp-api-keys.txt --results-only > api_tokens.txt
现在我们有了一个包含潜在API令牌的文件,我们可以根据数据库检查这些令牌的有效性(如果没有API提供者的书面许可,请不要这样做)。
对于HalCorp,我们可以编写一个bash脚本来读取stdin,检查api.halcorp.biz/userinfo端点,并输出结果。
最后的启发
尽管人们对GitHub上的敏感信息曝光的意识有所增强,但每天被曝光的敏感数据依然很多,如果用户的API密钥被发布到网上,Amazon Web服务已经开始通知用户。GitHub增加了一些安全功能,可以扫描公共存储库以获取通用密钥。然而这些措施治标不治本,为了遏制源代码的秘密泄露,我们必须更新API框架和DevOps方法,以防止API密钥完全存储在Git/SVN存储库中。像Vault这样的软件可以安全地存储产品密钥,而一些API提供商,像谷歌云平台,已经更新了他们的库,强制API密钥默认存储在一个文件中。
彻底根除敏感信息的暴露是一个比较困难的问题,如何才能完全检测到用户信息?如果是Word、Excel或编译文件呢?我们还需要在这个领域进行更多的研究,才有可能找出解决方法。