页面图片验证码测试思路
本文首发i春秋,未经允许禁止转载
前言
网站在进行登录时,一般都存在验证码,用来防止机器大规模注册,机器暴力破解数据密码等危害。但是验证码也并不是绝对安全的,这与验证码的自身复杂度、生成机制、验证机制、传输流程等都有关系。验证码一旦被绕过,那么就完全失去了他的作用,下面总结一下对于验证码测试的思路,其中涉及的示例有的是实际遇到的,有的是自己搭建的环境
一般验证码的流程
客户端发起请求->服务端响应并创建一个新的SessionID同时生成随机验证码,将验证码和SessionID一并返回给客户端->客户端提交验证码连同SessionID给服务端->服务端验证验证码同时销毁当前会话,返回给客户端结果。
一种前后端分离的验证码实现方案
- js生成一个随机数保存在localstorage里。
- 带上随机数请求服务器
- 服务器根据客户端信息加密随机数。 verify_code = f(rand)
- 根据加密结果生成验证码,返回base64图片
- 当用户提交验证码的时候,随机数一起带过来
- 服务器通过之前的加密规则验证是否正确
根据上面验证码的流程,可以把每个流程分离出来,分别分析各个流程中可能会出现的问题,例如客户端、服务端、验证码自身、传输流程、验证流程。
客户端
前端验证
这种验证码是在前端由JS生成并验证,所以生成和验证过程中不会和服务器进行交互
测试方法
一般这样的验证码不会特别复杂,进行验证时,查看浏览器审查元素中的网络,或者查看抓包软件记录,若其中不存在和服务器交互的数据包,则可以猜测是前端验证,这时候,只需要把JS禁用就可以绕过验证,或者直接在Burp中进行提交数据(因为验证码不是服务端生成,所以前端不会向后端发送验证码)
验证码直接输出在前端
这类验证码生成的不是图片,而是直接生成的HTML代码,这就导致了可以直接查看前端代码查看验证码内容,同样可以直接写脚本进行提取,如图(图片来自Wooyun)
服务端
验证码无效
在一些新开发的系统或者不成熟的系统中,开发人员可能为了测试方便,没有配置随机验证码,或者是直接没有写完这个功能,此时输入特定验证码或者任何验证码都可以验证成功。
测试方法
如果在输入验证码时,任意验证都可以验证成功就说明存在验证码无效的问题,另外如果输入了正确验证码却验证失败,可以尝试Fuzz简单的数组或者字母,如8888、1111、123456,这可能是为了方便测试,设置的固定验证码。
验证码存在固定有效期
系统在生成一个验证码后,在一段时间内,这个验证码都是有效的,导致可以在一段时间内使用该验证码进行爆破或者其他测试。
测试方法
在输入验证码提价后,验证码没有立即刷新,再次使用相同验证码进行提交时,验证正确。这样的验证码一般会设置5分钟或者其他时间的有效期,过期后验证码失效
验证码存在固定验证次数
系统生成验证码后,设定一个最大的验证次数,每使用该验证码验证一次,就减1,到0时,重新生成验证码。
测试方法
与上一个类似,在验证后验证码没有立即刷新,验证密码失败固定次数后验证码失效,放在Burp的爆破模块里跑几次就无法验证了
验证码生成结果可控
另外有的系统在请求验证码的字段中,存在验证码字符的范围,例如?range=0123456789,如果存在类似的参数,可以将它设为单个字符或者重复的字符,以此来达到生成固定字符的目的;或者有的流程就像前面前后端分离的验证码实现方案中一样,前端生成随机数,服务端根据随机数生成验证码,如果服务端生成函数存在问题,传入相同随机数时,生成的验证码相同,或者生成的验证码是可被预测的。
验证码自身
验证码易于识别
验证码自身问题主要还是生成的验证码过于简单,导致可以借助OCR软件进行识别,在Burp中也有一些插件可以对这种简单的 二维码进行识别,例如PKAV HTTP Fuzzer、reCAPTCHA。这些插件的实现原理一般都是获取返回的验证码图片,然后调用验证码识别接口或者本地进行识别,所以识别的准确度与验证码自身、训练模型都有关系。
传输流程
生成的验证码使用Cookie传输
服务端会将生成的验证码传输到客户端,其中传输过程中有的系统会直接将验证码放在Cookie中
获取验证码的响应包存在验证码
这个也是之前经常存在的漏洞,在重新获取验证码时,会发送一个请求包,在响应包中会直接发回验证码,这个时候就可以写一个脚本获取验证码来绕过,或者是同Burp中的Macros功能,自动提取并替换验证码。
返回的验证码图片中存在验证码文本
在返回验证码的时候,会将生成的验证码文本内容放在图片后面返回
验证流程
没有进行非空判断
这种根据不同的系统可能会有很多种测试方法,例如当后台对验证码的参数没有进行严格校验时候,可以将验证码参数值置为空、将参数改为数组或者直接删除这个参数,这些都是有可能绕过验证码的
验证后没有销毁会话
这个问题是验证逻辑的错误,属于验证流程的问题,但是存在于服务端,它是在校验验证码后没有将会话销毁,这样会导致一个验证码能够反复利用,这也是存在最多的一种验证码漏洞,直接的后果就是验证码完全失去了它的作用。
测试方法
直接一直使用同样的包进行发送,查看返回结果,另外可以删除请求包中的某些字段来进行测试,例如Cookie、Session或者请求的其他参数
Burp中Morse的使用
这里是自己写的一个示例,其中存在的问题是在请求验证码时,服务端会将验证码的内容返回回来,因此可以直接将返回包中的验证码输入进行验证
那么这时候可以自己编写脚本将得到的验证码拿到下一步进行验证,或者使用Burp中的Macros,下面是使用方法
设置宏
首先设置宏,在图示位置点击添加
添加后会自动弹出历史包,这里选择这两个我们要用到的包,一个是请求验证码,一个是验证验证码的包
然后选择第一个获取验证码的包(因为是先获取验证码在验证),点击Configure item 进行设置
之后设置获取字段的名字,这里的名字设置成与验证包里的变量相同的名字,然后下面用鼠标选择,它会自动识别前后的内容
然后回到刚才的地方,设置第二个包,这里它会自动识别提交的参数,只需要选择对应的参数,然后选择数据来源为获取验证码的包,这里第一个包。
设置会话处理规则
接下来设置会话处理规则,刚才设置的只是一个动作,这里的设置是设置在什么时候启用这个宏
这里选择图示的选项,在后面选择修改包中captcha的内容,之后选择OK
下面设置Scope,其中可以设置动作生效的模块,例如可以只选择爆破模块,中间是URL的范围,最下面是参数的范围,这些都可以根据具体情况进行设定,设定好后OK
然后就可以到Repeater或者爆破模块中进行测试了,这里再爆破模块进行了测试
可以看到所有的都是验证码正确,注意使用爆破的时候要设置单线程
总结
对于上述的验证码问题,单从验证码方面来说,造成的影响并不是很大,但是验证码一旦失效,可用的地方还是很多的,例如有的后台验证码可重复使用,那么就可以直接对后台的用户或者密码进行爆破,以此来步步深入,或者有的接口验证码失效,那么就可以利用这个接口来遍历或者爆破一些信息。这样的例子还有很多,结合实际情况进行利用,就能加大这个漏洞的影响。
https://blog.csdn.net/weixin_39190897/article/details/86539542
本文作者 : W4rnIn9
原文链接 : http://joner11234.github.io/article/5d927c8d.html
版权声明 : 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!