挖洞经验 | 利用周六休息日狂赚两万欧的漏洞发现
作者:admin | 时间:2019-6-30 14:30:57 | 分类:黑客技术 隐藏侧边栏展开侧边栏
*本文中涉及到的相关漏洞已报送厂商并得到修复,本文仅限技术研究与讨论,严禁用于非法用途,否则产生的一切后果自行承担。**近期,众测平台Intigriti组织了一场漏洞测试比赛,作者和朋友共同努力在周六休息日,发现了目标系统的两个IDOR防护机制绕过漏洞,收获了€20,000的漏洞赏金。本文中作者分享了整个漏洞发现的思路和过程,仅当学习借鉴。*
目标系统的加密参数
目标系统具备多层防护和加固机制,除通常的IDOR防护措施之外,还使用了“加密参数”手段,如以下的请求响应示例中’E'参数的加密方式:
Request:
POST /changeUsername HTTP/1.1Host: target.io{"userId":{"T":"text","V":"123456789","E":"VGhpcyBpcyBteSB1c2VyIGlkLCBvYnZpb3VzbHkgdGhpcyBpcyBub3QgYmFzZTY0Cg"},"userName":{"T":"text","V":"Matti Bijnens"}}
Reponse:
HTTP/1.1 200 OK{"adjustedUserName":{"T":"text","V":"Matti Bijnens","E":"SXQgd2FzIG5vdCBiYXNlNjQgYnV0IGl0IGxvb2tlZCBsaWtlIGl0Cg\u003d"}}
刚开始我就注意到了这个点,想把它作为切口进行破解突破,我具体的尝试思路如下:
(1)‘E’ 参数值可以被忽略吗?能不能把‘V’参数值进行替换,尝试实现IDOR攻击?
(2)如果‘E’ 参数值是在Web前端生成的,这样我们就可以逆向破解其加密算法来校验我们任意的设定的参数值了?
(3)能不能更改请求类型?或是删除‘E’ 参数值?这样服务端的处理是否会回退到不需要加密参数的过程?
按思路测试
想到就开始做吧。在第一种思路中,我尝试对‘V’参数值进行了编辑修改,但却没有收获,而且无任何错误响应消息显示。最后我弄明白了,服务端对几乎大部份Web路径提交的‘V’参数值都直接选择了忽略,只会检查校验其中的加密参数‘E’值,而对于某些极少Web路径中,服务端确实会选择检查‘V’参数值,忽略加密参数‘E’值。
在只检查‘V’参数值的Web路径中,我们遇到了深入的下一层IDOR防护机制,在针对‘V’参数值的IDOR攻击尝试中,只会返回一个提示消息:运行出错,请重新尝试或与管理员联系(This doesn’t seem to be working, try again or contact us.)。
现在我们转为第二种思路,来看看‘E’ 参数值是否为Web前端加密生成的。但经过测试我发现,‘E’ 参数值总是随用户即时请求而相应生成,因此我放弃了之前的猜想。尽管我努力去尝试是否能猜测出‘E’ 参数值的加密方式,但最终也不了了之,没有头绪。但有一点是确定的:同样的‘V’参数值进行不同时间的发送,却可以生成不同的‘E’ 参数加密值,而且,服务端只接受最近生成的‘E’ 参数加密值。这里,我们猜想其加密方法可能引入了时间戳,这就没法了。
进入第三种思路中,我们更改请求类型(none, hidden, number, …),或是修改‘E’ 参数值,最终得到的也是同样的错误消息提示:运行出错,请重新尝试或与管理员联系(This doesn’t seem to be working, try again or contact us.)。
百思不得其解时,朋友Arne提示我可考虑用Oracle的签名方法来尝试破解这个‘E’ 参数值,也就是说,这个‘E’ 参数值可能是Oracle机制的加密签名值,我们只要在服务端系统中看看它是否使用了Oracle签名方法,然后给它一个‘V’参数值明文,之后观察它会不会返回响应一个类似的‘E’ 参数加密值。比如说,目标系统中存在这么一个Web路径/encryptValue ,它负责接收‘V’参数然后响应回‘E’ 参数,那么,我们给它一个明文V,如id=6548116,看它是否会返回上述类似的‘E’ 参数加密值E=bm90YWN0dWFsbHliYXNlNjQ。
不管其中的‘E’ 参数如何加密如何签名,是不是 trailing/prepended(尾随/预置式)数据哈希,这些暂且不重要,只要服务端可以接受这个经 Oracle机制加密的‘E’ 参数,那么事情就成了。
于是,我马上在目标系统中寻找上述分析的“Oracle机制加密签名路径”,刚好,在用户名修改功能处,我发现服务端也会返回一个加密的‘E’ 参数。也就是说,只要更改用户名(这里以用户ID12341代替),服务端就会响应返回一个与用户名对应的‘E’ 参数加密值SSBsb3z1rHBpZQo。那这个路径会不会是我们分析的“Oracle机制加密签名路径”呢?
不管它,先来想办法利用利用这个’E'参数值。有了这个服务端生成了‘E’ 参数加密值,我要看看其它Web路径下是否能用到它。经过半天的测试寻找,我发现了用户ID12340的票据获取路径( “/getInvoice”),其中也包含了’E'参数值。在这个用户ID为12340的请求中,为了利用上述’E'参数值,我们把用户ID变为我们测试的12341,然后把其中的也换为对应的SSBsb3z1rHBpZQo,看看会有什么反应。
遗憾的是我未能得到任何票据信息,但服务端却返回了另一个错误提示:该实体与客户身份不符(Entity does not belong to client),至少后端已经接收了这个’E'值,这明显说明,我们之前猜测的‘E’ 参数值是Oracle加密签名完全正确。
虽然这又是另外一个错误消息提示,但明显是一个突破,我们弄清楚了目标系统其中的某个点的加密方式,可以继续想办法绕过其深入的IDOR防护机制。
转化切入点实现IDOR
在与朋友Arne和Jeroen商量过后,我们决定深挖目标系统中的一些与用户ID相关的’敏感’路径,希望这些路径的校验检查存在逻辑缺陷或不足,但不幸的是,我们面对的是一个非常安全的目标,要想找到一个缺乏二次校验检查的Web路径是一件非常痛苦的事情。
我们最终把焦点放到了 /getArchive 路径上,该路径可以返回用户所有的账单/收入( bills/earnings)数据,与其它通常路径下用户ID区域属性为“text”不同的是,由于上下文关系,该路径的用户标识区域属性为“hidden”,也即隐藏,如下:
Request:
POST /getArchive HTTP/1.1Host: target.io{"T":"Hidden", "E":"Q2xlYXJseSBhIHZlcnkgd2VsbCBoaWRkZW4gc29tZXRoaW5nCg"}}
Response:
HTTP/1.1 200 OKRedirecting to archive-mattibijnens.pdf
由于这个隐藏属性,所以在请求中也无相应的参数值,但我隐约感觉,这个隐藏属性可能是用户ID的相关信息,除此之外,也没什么可是的了。
于是,在路径服务中,我马上把我初始请求的用户名更改为用户ID,并结合前述用户名生成的‘E’加密参数值,进行了请求提交。一开始是不行的,服务端返回了错误:不能找到与该ID匹配的用户(Could not find client with this ID)。但经对之前大量的路径测试,我发现有时服务端只会选取用户ID的最后一部份,于是,我把我用户ID的前一部份删除了,然后再提交请求,这一次,服务端竟然能有效接收并响应了,返回了与我账户对应的所有文档资料。
也就是说,那个隐藏区域确实是我的用户ID,而且我要了朋友Jeroen的用户ID,按照以上方法进行了测试,同样,请求能有效提交,而且服务端返回了Jeroen的所有账单/收入资料。
漏洞上报和复现
之后,我们及时向厂商进行了漏洞通报,最后得到了CVSS 7.7(高危)的评分。由于是实时的漏洞测试比赛,厂商很快就注意到了我们的报告,但由于报告没讲清细节,他们希望看到详细的漏洞复现过程。
于是,我被邀请进入了厂商办公室,对方将近20个人都围了过来,这种压力让我紧张,而且刚好我笔记本的HDMI接口又坏了,连接不了投影仪。尴尬之余,Intigriti老总Stijn让我拿他的MacBook做演示,之前我从没用过Mac本啊,在甚至不知道在Mac系统中如何切换Burp和Firefox,那个时候我就像傻瓜一样慌了手脚。好在我试着镇定下来,按照以下步骤复现了漏洞:
(1)把当前登录的用户名更改为其它用户对应的用户ID;
(2)在/getArchive 路径下代入用户名生成的‘E’加密参数值;
(3)成功返回响应后,以此判断出其中的隐藏属性为用户ID。
我用朋友Jeroen的账户进行了漏洞复现,但其中一个厂商参会人员提出希望用他的用户ID进行复现,最终我成功获取到了他所有的资料信息,此举一出,大家都对该漏洞的影响和威胁有了清楚认识。演示完毕,我坐回了椅子,Intigriti员工告知我,厂商对该漏洞的定级由高危更改为特别严重,按照其奖励政策,这会有€10.000的赏金。
与此同时,我们的三人团队继续利用前述的“Oracle加密签名Bug”深入测试其它路径中的IDOR漏洞,Arne发现了只要提交用户姓名即能获得用户所有收入信息的一种方式,同样,该漏洞也被厂商评定为特别严重,也是€10.000的赏金标准。其请求Payload如下:
Request:
POST /getEarnings HTTP/1.1Host: target.io{"name":{"T":"text","V":"John Doe","E":"T2J2aW91c2x5IG5vdCBiYXNlNjQgYWdhaW4sIGJ1dCBhbiBlbmNyeXB0ZWQgdXNlciBJRAo"}}
Response:
HTTP/1.1 200 OK{"totalEarnings":{"T":"text","V":"€4560000"}}
另外,Jeroen针对某些特定用户,发现了一个可以获取这些特定用户非公开资料头像的漏洞,也得到了相应的漏洞赏金。
总结
后续,我和厂商开发团队进行了一些交流,其实目标系统架构中就根本没采用什么加密方法,也不是什么“Oracle加密签名”,其中的‘E’参数加密值也仅只是不同路径服务下针对不同用户某些明文信息的随机生成串而已,如下映射关系:
开发者简单的认为由于不知道其他用户的ID,所以也就能用这种方式防御IDOR攻击了,但其实他们错了,这里的逻辑缺陷是攻击者可以通过弄清其中的’E'参数生成方式后,就可以通过替换它来实现IDOR攻击了。以下是我的一些观点总结:
没有任何一个系统是安全的,任何人都可能犯错;
发现一些“高级的防护措施”后千万别灰心放弃;
如果可行,尝试和其他白帽朋友们共同进行头脑风暴;
好好详细写漏洞报告,否则你可能会在20多个人面前复现漏洞。
*参考来源:medium,clouds编译,转自FreeBuf