HubSpot 账户接管全流程

admin 2025年1月11日13:22:33评论7 views字数 7791阅读25分58秒阅读模式

 

今天我们将分享一个关于在 HubSpot 公共漏洞赏金计划中实现账户接管的故事。

正文

我们测试的子域为 https://growanz.hubspot.com。其认证功能中有一个 “忘记注册号” 功能。

HubSpot 账户接管全流程

这个功能会要求我们输入电子邮件地址,接着系统将发送一条一次性链接,用于无需注册号(密码)直接登录:

HubSpot 账户接管全流程

SQL 注入

由于存在 email 参数,后台必然有某种类型的数据库来处理这些电子邮件地址。因此,email 参数成为测试SQL注入的最佳位置。

HubSpot 账户接管全流程

经过一番测试,未发现问题。

主机头污染

开发人员通常会在重置密码的 URI 中使用 HOST Header 值,例如:

$ForgotPassURI = "https://{$_SERVER['HTTP_HOST']}/dream-auth/forgot?registration=$token&email=$email";
因此,我们尝试将 Host Header 更改为一个由我们控制的域名:

HubSpot 账户接管全流程

并未发现问题。

负载均衡器主机头覆盖

有时候,用户与服务器之间可能会存在负载均衡器或反向代理服务器。如果开发人员使用了 HOST Header,他们可能会获得负载均衡器的主机值。因此,开发人员通常会改用 X-Forwarded-Host Header,因为负载均衡器会将原始 HOST Header 值保存到 X-Forwarded-Host Header 中。

原则上,这个 Header 不应该被用户修改,但某些弱配置的负载均衡器或反向代理服务器可能会允许用户输入来重写这个 Header,这使得这个 Header 成为测试的理想目标。

测试结果如图:

HubSpot 账户接管全流程

尽管测试后邮件发送成功,但在检查邮件时,我发现“忘记注册号”的链接依然包含 growanz.hubspot.com,并未指向受控域名。

Referer Header 测试

一些开发人员可能会认为,访问“忘记密码”端点时,必须从主子域名发起请求,因此他们会在重置密码的逻辑中依赖 Referer Header 的值:

$ForgotPassURI = "https://{$_SERVER['HTTP_REFERER']}/dream-auth-forgot?registration=$token&email=$email";
HubSpot 账户接管全流程

并未发现任何问题。

ORIGIN Header 测试

接下来,我尝试测试 Origin Header。

一些开发人员可能会将 Origin Header 的值用作“忘记密码”链接的构建依据。代码可能如下所示:

$ForgotPassURI = "https://{$_SERVER['HTTP_ORIGIN']}/dream-auth-forgot?registration=$token&email=$email";
于是,我将 Origin Header 修改为指向我的 Burp Collaborator 域名进行测试。

HubSpot 账户接管全流程

测试未成功,链接仍未指向我的受控域名。

绕过正则表达式验证

开发者可能在之前的技术中使用了正则表达式来验证用户输入。如果输入匹配正则表达式,他们会发送到我们的自定义域;如果不匹配,则会发送到配置文件中的默认子域。因此,我尝试通过以下方式绕过验证。

尝试1: 绕过主机名包含域名的匹配

growanz.hubspot.com.mydomain.com

尝试2: 使用弱正则表达式匹配

假设系统可能用到的正则表达式类似于:

^growanz.hubspot.com$|^example.virtual.host$
通过插入字符 X 测试弱匹配:

growanzXhubspot.com

尝试3: 绕过匹配以域名结尾的限制

mydomain.com/growanz.hubspot.com

尝试4: 绕过白名单验证

使用 # 和 URL 编码:

mydomain.com%[email protected]mydomain.com%25%32%[email protected]

上述绕过方法在之前提到的各个 Header(如 Host Header、X-Forwarded-Host Header 等)测试中均未奏效。

因此,我决定转而测试 email 参数。

HTTP参数污染(HPP)

现如今,应用程序的开发中会使用不同类型的架构,如单体架构、事件驱动架构(EDA)、面向服务架构(SOA)和微服务架构。

随着微服务架构的流行,它带来了许多单体架构所不具备的优势,这些优势有助于扩展我们的攻击面。那么,如果我们的目标依赖于微服务架构,并且微服务之间使用RESTful API进行通信,我们该如何进行挖掘呢?

HubSpot 账户接管全流程

我制作了这个图表作为我们场景的简单示例。

假设我们的重置密码请求首先传递给一个依赖JSP的微服务,该微服务处理与数据库相关的请求(例如,重置密码邮件)。如果该邮箱存在,微服务会响应业务路由逻辑,然后将原始请求再次路由到处理SMTP服务的PHP微服务,负责发送重置密码邮件。

因此,如果我们的目标使用了微服务架构,我们需要测试其他攻击方式,例如HTTP参数污染(HPP)。

HubSpot 账户接管全流程

根据这个表格,如果我们将两个参数传递给PHP,它将使用第二个参数,而像JSP这样的其他技术会使用第一个参数。

// HTTP 参数污染(HPP){"email":"victim@mail.com","email":"attacker@mail.com"}

因此,如果我们的请求传递给处理数据库的JSP微服务,它会根据第一个邮箱创建重置密码的URI,但当请求再次路由到PHP时,它会将重置密码邮件发送到第二个邮箱。

HubSpot 账户接管全流程

在检查邮件后,我并未发现问题。

攻击链(SMTP注入和HTTP参数污染)

在这里,我将使用PHP作为示例来说明。实际上这些攻击适用于其他依赖SMTP解析器和服务的技术。

假设你的邮件地址是这样处理的:

<?php// 这是使用mail函数的简单示例if(isset($_POST['email'])) {  $to = $_POST['email'];    $subject = "忘记注册号";  $message = "  <html>  <body>  <h1>示例:登录你的账户</h1>   点击此一次性链接  <a>https://growanz.hubspot.com/login?registration=$RegesNum&email=$to</a>  <html>  <body>";  $subject = '重置密码';  // 设置SMTP头  $additional_headers = "From: [email protected]" . "Content-type: text/html;";  $additional_params = "";  mail($to, $subject, $message, $additional_headers, $additional_params); }?>
mail函数中的所有字段都是必需的,除了$additional_headers和$additional_params这两个是可选的。

所以接下来让我们攻击$to参数。

攻击$to参数

一些开发者使用$to参数来输入用户的邮件地址,但没有进行验证,因为他们预期邮件只会发送给该用户。然而,他们忽略了用户可以使用分隔符添加另一个邮箱来发送忘记密码邮件。

根据官方文档,我们可以使用“,”作为分隔符,但我们需要通过HTTP参数污染来链式攻击,方法是将受害者的邮箱作为另一个参数传入。因为当应用程序处理数据库来重置密码时,它会找到有效的邮箱并执行查询。

因此,当处理数据库的微服务找到正确的邮箱并执行数据库查询时,另一个处理SMTP服务的微服务如果实现了错误的验证,将会发现受害者的邮箱。

// 使用逗号作为分隔符结合 HPP 链{"email":"Victim@gmail.com,Attacker@gmail.com","email":"[email protected]"}{"email":"[email protected]","email":"[email protected],[email protected]"}
HubSpot 账户接管全流程

让我们交换参数的值:

HubSpot 账户接管全流程

返回success,但是在检查我的邮件后,我仍然没发现问题。

经过测试,我发现PHP接受其他未在官方文档中列出的分隔符,例如空格和“;”,这为我们提供了一个新的思路,因为开发人员可能只对“,”进行验证以防止添加另一个邮件地址,但他们可能忽略了空格或“;”的验证。

示例如下:

//分号分隔符与HPP链式攻击{"email":"[email protected];[email protected]","email":"[email protected]"}{"email":"[email protected]","email":"[email protected];[email protected]"}
//空格分隔符与HPP链式攻击{"email":"[email protected]%[email protected]","email":"[email protected]"}{"email":"[email protected]","email":"[email protected]%[email protected]"}
结果如下,均返回success,因此不存在针对SMTP的保护措施:

HubSpot 账户接管全流程

HubSpot 账户接管全流程

CRLF注入

注意:在Unix系统中,我们只能添加n作为换行符来进行SMTP头注入,但在Windows系统中,需要添加rn来进行SMTP头注入攻击。

Unix系统(n URL编码)

//抄送(CC:)与HPP链式攻击{"email":"[email protected]%0Acc:[email protected]","email":"[email protected]"}{"email":"[email protected]","email":"[email protected]%0Acc:[email protected]"}
//密送(BCC:)与HPP链式攻击{"email""[email protected]%0Abcc:[email protected]","email":"[email protected]"}{"email":"[email protected]","email":"[email protected]%0Abcc:[email protected]"}

Windows系统(rn URL编码)

//抄送(CC:)与HPP链式攻击{"email":"[email protected]%0D%0Acc:[email protected]","email":"[email protected]"}{"email":"[email protected]","email":"[email protected]%0D%0Acc:[email protected]"}
//密送(BCC:)与HPP链式攻击{"email""[email protected]%0D%0Abcc:[email protected]","email":"[email protected]"}{"email":"[email protected]","email""[email protected]%0D%0Abcc:[email protected]"}

结果如图:

HubSpot 账户接管全流程

仍然没有奏效。

那么,如果版本稍微更新了一些,并且在$to参数中对CRLF注入或SMTP头注入进行了保护,如何处理呢?

作为保护,mail()函数开始将像换行符或回车符这样的控制字符在$subject和$to参数中转换为空格。

但幸运的是,这个保护有一个绕过方法。这里我们不再深入讨论绕过的细节,我们直接在email参数中使用这个绕过,它将被注入到$to参数中:

//绕过mail()函数进行HPP链式攻击{"email":"[email protected] ncc: [email protected]","email":"[email protected]"}{"email":"[email protected]","email":"[email protected] ncc: [email protected]"}
然而,似乎系统使用的mail()函数是最新的,并且没有受到之前攻击的影响。

那么,如果用户输入的电子邮件值被注入到开发者用于某些逻辑的头部,并且这个值被传递到$additional_headers参数中怎么办?

攻击$additional_headers参数

$additional_headers参数用于添加开发者需要的其他头部,例如,如果邮件包含HTML数据,开发者可能需要设置Content-type: text/html头部,以便在用户的浏览器中解析数据为HTML,或者添加From: [email protected]头部。

那么,如果出于某种开发逻辑,开发者将用户输入的电子邮件添加到$additional_headers参数中,这时我们应该通过SMTP头注入(CRLF注入)攻击它,因为根据官方文档,防止在$additional_headers参数中进行CRLF注入是开发者的责任。

但我们之前已经尝试了这些攻击。

甚至像SMTP头注入这样的攻击,通常出现在“联系我们”表单中,而不是在重置密码功能中,但有时候开发者会犯一些低级错误,这也是值得一试的原因。

操作系统命令注入

由于PHP依赖于/usr/sbin/sendmail命令来发送邮件,一些开发者可能更喜欢使用命令行来发送电子邮件,而不是内置函数。

简单示例:

$json = file_get_contents('php://input');$json = json_decode($jsontrue);$to = $json['email'];$command = "echo 'Example: to login into your account click on this magic link https://growanz.hubspot.com/login?registration=$token&email=$to | mail -s 'Forgot Password Mail' $to";exec($command);
在尝试了不同的payload来执行命令后,我并没有得到任何结果。

email数组

使用SMTP发送邮件不仅限于发送重置密码邮件,它也用于发送一些内部邮件或像大多数应用程序中常见的功能,如“订阅我们的新闻源”等。

发送邮件给所有用户的一种常见方式是将它们放入数组中,例如$emails,然后使用像implode(",", $emails)这样的函数,以“,”作为分隔符,一次性发送邮件给所有的邮箱,这样可以提供高性能的操作,其时间复杂度为O(1),而不是迭代方式的O(n)。

但有时,开发者大多数时候不会一次又一次地从头编写代码,而是复制代码并根据需要进行修改。

示例如下:

$json = file_get_contents('php://input');$to = json_decode($jsontrue);// 发送邮件mail(implode(","$to['email']), $subject$message$headers);
因此,如果像这样用于发送重置密码邮件的代码,单个邮箱时一切正常,但如果我们尝试添加包含受害者和攻击者电子邮件的多个邮箱,这个方法可能使我们得到受害者的重置密码邮件,Payload如下:

//电子邮件数组{"email":["[email protected]","[email protected]"]}

HubSpot 账户接管全流程

但是也没有成功。

查看上图的错误信息,会注意到它告诉我们“$to参数”不是有效的地址,这至少表明在所有这些攻击之后,我的后端代码预测是准确的,即使我们还没有发现任何漏洞。

参数暴力破解

无论如何,我们应该利用API的错误信息,所以我认为是时候使用Arjun了,也许会有一些隐藏的参数。

HubSpot 账户接管全流程

Arjun没有输出任何结果。

实际上,这有点奇怪,因为我们已经有了一个有效的email参数。所以现在我打算手动进行参数暴力破解。

我抓取了Arjun的参数,并将每个参数的值替换为包含所有特殊字符的参数名,目的是通过引发错误来检测API使用了哪个参数。我使用了这个简单的Python脚本:

params = open("Arjun/arjun/db/large.txt","r").readlines()params = set(params)NewParams = set()for param inparams:    NewParams.add('"'+param.strip()+'"'+":"+'"'+param.strip()+''!@#$%^&*)(?><",')NewParamsFile = open("new-params","w")for param in NewParams:    NewParamsFile.write(param+"n")
之后,我将这些参数放入请求中,看看会发生什么:

HubSpot 账户接管全流程

看来后台使用了href,而Arjun并没有检测到这个参数,这也给了我们一个宝贵的经验教训(不要依赖工具,如果你不知道工具在后台做了什么)。

Arjun没有检测到这个参数的原因是:它为每个参数值添加了4个数字,这意味着email参数的值将是无效的,从而导致服务器始终返回“Invalid value for email parameter”的错误响应。由于Arjun是通过检查响应的content-length头部来判断是否存在改变内容长度的动态参数,而由于email值始终无效,这导致Arjun未能检测到这些参数。

HubSpot 账户接管全流程

回到正文。如果你了解HTML基础知识,你肯定知道href(超链接引用)值通常是URL。所以,第一个问题出现在我脑海里:

  • 为什么他们在这里使用了href参数?
  • 他们是否在忘记注册邮件中使用了href参数?

为了回答这些问题,我在href参数中注入了Burp collaborator。

HubSpot 账户接管全流程

再看看我们的电子邮件:

HubSpot 账户接管全流程

从上图中可以看到,我们已经收到了来自 hubspot.com 域的邮件。

点击一次性链接:

HubSpot 账户接管全流程

如图,当点击这个一次性链接时,它并不会让用户登录,而是会向我控制的 Burp Collaborator 服务器发送请求,这样我就能接收到受害者的凭证。

培训咨询v

bc52013 或  linglongsec

SRC漏洞挖掘培训

玲珑安全第一期SRC漏洞挖掘培训

玲珑安全第二期SRC漏洞挖掘培训

玲珑安全第三期SRC漏洞挖掘培训

玲珑安全第四期SRC漏洞挖掘培训

玲珑安全第五期SRC漏洞挖掘培训

往期漏洞分享

某教学平台支付逻辑漏洞

通过模拟功能实现提权(Bugcrowd)

JS Review+GraphQL滥用实现管理面板访问

绕过电子邮件确认实现预账户接管

价值$3000的Google Slides IDOR漏洞

通过有趣的逻辑漏洞实现账户接管

一个漏洞让我年入数百万

从2FA绕过到账户接管

玲珑安全B站公开课

https://space.bilibili.com/602205041

玲珑安全QQ群

191400300

原文始发于微信公众号(芳华绝代安全团队):【万字详析】HubSpot 账户接管全流程

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年1月11日13:22:33
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   HubSpot 账户接管全流程https://cn-sec.com/archives/3602276.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息