Web页面验证码机制漏洞的检测
每个用户都在部分网站上注册过一些账号,当这些账号涉及到金钱或者利益时,账号的安全就成为一个非常重要的问题。因此,账号安全是各个厂商非常关注的焦点。然而,仍然存在一些厂商在身份验证方面存在漏洞。并不是因为厂商不重视这个问题,而是在代码层面的验证过程中存在一些差异,往往这些逻辑漏洞容易被利用。
一、不可靠的前端校验
在现实环境中,有许多网站没有严格进行身份校验,他们通常通过依靠账号密码发送后回传的状态码来判断用户身份是否正确。这暴露了很大的漏洞,利用这种漏洞相当容易。只需要使用安全工具BURP就可以绕过身份验证,在登录时输入正确的账户和任意密码,拦截报文并捕捉返回的状态码。
将返回包中的状态码修改为正常登录的状态码。当然,这里的状态码不一定是0和1,各种状态码都有可能存在。那么,我们如何判断正确的状态码是什么呢?这里我们需要手动注册一个用户,然后进行正常登录并抓取返回的状态码。当你发现返回的报文中只存在状态码,没有其他set-cookie或者token等信息时,那么这个登录界面很有可能存在这种漏洞。这是一种比较致命的漏洞,但即使存在这种漏洞,我们也不太可能拥有其他大量的账号,因此这个漏洞的危害性就不是很大了。
二、遍历手机号
现在大多数网站都允许使用手机号进行注册,一般来说,同一个手机号只能注册一个账号。因此,手机号可以作为账号使用,这是一个可以利用的点。当我们知道手机号可以用作登录账号时,如何获取这些手机号呢?这其实是一个非常好的问题。对于手机号来说,一共有11位数,要想随机猜测一个手机号是否在某个平台上注册过,一次性猜中的概率微乎其微。但是有些网站的忘记密码功能存在利用的方法(尽管大多数厂商忽略了这种漏洞),但我认为它仍然具有危害性。在我们忘记密码时输入手机号码并发送手机验证码时,部分网站会先查询该手机号是否在该网站上注册过。如果不存在,则会提示号码不存在;如果存在,则发送短信。因此,可以利用这个逻辑来进行用户手机号的遍历。顺便提一下,可以使用手机号码字典生成器来生成手机号码字典,然后用于遍历。
如图所示,如果用户不存在,则会显示其他信息。我们只需根据长度来判断,也可以编写Python脚本来遍历并保存注册用户。这一点可以获取大量用户手机号。
三、可爆破的手机验证码
前面介绍了绕过前端校验的方法和获取用户手机号的方式,接下来讲解一下手机验证码的问题。手机验证码存在于登录、注册和密码找回这三个环节。其中,注册环节的危害相对较小,除非找到一个可以批量注册账号的漏洞。
那么危害较大的就剩下登录和密码找回了,实际上这两个环节的原理是一样的,只是利用的环境有所不同。目前,使用手机验证码登录的网站数量并不占很大的比例,本文以找回密码为例进行说明。
在测试之前,我们首先要判断手机短信验证码的长度、有效期以及页面是否存在难以识别的图片验证码(识别率低于50%)。这是我们首先要注意的。其次,提交一次表单并抓包观察,是否存在前端加密或者sign等。我将验证码长度分为4位和6位两类进行分类。
1) 4位手机验证码
当我们发现手机验证码长度为4位,有效期约为5分钟,并且没有复杂的前端加密、sign和图片验证码时,恭喜你,你可能找到了一个可以爆破验证码的漏洞。虽然这种漏洞需要爆破,但实际上花费的时间非常短,通常可以在很短的时间内重置或登录一个手机号。对于厂商来说,这是一个高危漏洞,相信他们会给你不错的报酬。在最近的测试中,我发现了带有sign标记的4位验证码,这增加了爆破的难度。它的sign是根据当前的时间戳和手机号验证码等信息加密生成的,要想破解这个加密算法是不太现实的。因此,我使用了一种巧妙的思路,可能其他安全领域的专家也使用过,那就是使用Python的Selenium库来模拟浏览器自动化点击测试,但需要根据网站的实际情况和窗口位置编写脚本。关于Selenium,提供一个学习链接。
2) 6位手机验证码
通常来说,6位验证码和30分钟的有效期是相对安全的设计,因为在30分钟内想要完成100万条数据的爆破难度很大,并且网站通常会根据发送速率进行限制。一旦发送速率超过设定值,你的IP将会被封禁一段时间,这些设置使验证码相对安全。但如果有效期达到1小时甚至更长,并且不限制IP的发送速率,那么仍然可以利用,只是利用成本较高,所以基本上不考虑。因此,在思维导图中我写到基本不去考虑。
四、现实环境下的漏洞案例思路和分析
接下来给大家带来一个真实的漏洞案例,也是我本人挖掘到的一个高危漏洞。
在登录界面,由于图片验证码长期有效,所以猜测可以爆破。通过两次提交发现图片验证码在一定时间内不会发生变化,尽管已经经过了一次校验。通过查看JavaScript代码,发现验证码是由手机验证码经过SHA256加密后从第六位开始取4位验证码。在测试时输入的验证码为1602。
证实了这个加密算法,于是利用脚本生成了0000-9999的加密后的字典用于爆破。在爆破过程中发现,验证码的有效期约为1分钟,不足以完成爆破。因此,换了另外一种思路,既然通过爆破无法突破验证码的限制,那么想到了程序员在编写代码时是否会犯一种错误,即将过期的验证码重置为一串特定的字符。既然有了这种猜想,就需要进行验证。首先根据加密算法发现它是SHA256,也就是每一位验证码数据只会在0-f之间生成。因此,生成了一个0000-ffff的字典,进行了一轮爆破。正如猜想的那样,爆破出了一个意外的数值。当然,并不是在第一次爆破过程中发现的,第一次可能是一个偶然。于是,我借用了别人的手机进行了几次尝试后,发现这个数值是固定的,证明了这个漏洞的存在。
这样就挖掘出了一个任意登录账号的漏洞。刚好这个网站又存在如之前所说的手机号遍历的问题,因此结合这两个点就可以登录任意用户。当然,关于挖掘到这方面的漏洞不止一个,但由于厂商修复尚未完成,不宜公开其他漏洞。
分析:对于这个漏洞点的发现其实是因为当时测试时的突发奇想。这个漏洞的前端SHA256加密截取4位的算法不容易发现,单单这一个点就能阻止许多想要爆破的人。验证码本身是由0000-9999的纯数字组成,很难联想到它是从SHA256中截取的字符串。但是当你绕过这个问题时,验证码的有效期又成为你的下一个问题。在挖掘出这个特殊字符串时,也感到有些惊讶。毕竟,这个想法是我在挖掘过程中突发奇想的结果,是一个热血沸腾的想法。因此,当你在挖掘过程中被一个点困住时,不要死磕,可以放松思维,也许能够想到设计者在设计时可能犯下的错误。挖掘漏洞本身是三分实力七分运气的事情,保持常心肯定会有所收获。因此,提升自己的能力和改善自己的心态将成为你挖掘漏洞时的利器。