漏洞名称:从一个逻辑漏洞浅谈某集团整体代码缺陷
影响网站:某集团旗下的4个网站
自评等级:严重
漏洞类型:逻辑漏洞
发现方式
某集团旗下的4个网站,均存在此通过邮箱或手机找回任意用户的密码逻辑漏洞。
以旗下的某一个网站为演示,先使用手机验证找回密码,为了不影响网站正常用户这里我用自己的账号测试,我的第一个账号手机号码是17130000030,这是我要重置的目标。
我先使用第二个账号手机号码17131000031,正常走一遍找回密码的流程,在最后输入新密码点击下一步的时候抓包。
在通过手机验证找回密码,这个最终提交给后端修改密码的数据包中的 GET 参数如下:
jsonpCallback=jsonp1576491645000&memberId=m8031_29788&uid=74305025&mobilePhone=17131948031&password=test888&newPassword=test888&_=1576491489817
经过测试,只需要提交 5 个参数就可以修改密码,这 5 个参数分别是:
memberId(用户名称)
uid(用户ID)
mobilePhone(用户手机号码)
password(新密码)
newPassword(确认新密码)
后端并没有一个关键凭证的验证,我们只需要把这些用户信息参数换成目标账号的,就可以修改任意账号的密码。
经过测试,在个人中心修改手机号码的时候可以获取目标手机号码的用户信息。
输入手机号码点击获取短信验证码的时候会先发给后端查询该手机号码相关的信息,再根据后端返回的用户信息,前端判断是否是null再发送短信验证码。(null代表该手机号码没有用户绑定)
点击获取短信验证码,抓取发给后端查询该手机号码的数据包。
可以看到后端返回该手机号码的用户信息。
{"msg":"user exist","uid":"74304975","code":"-2","location":"userbind","userbind":"17131000030","username":"m8030_8388"}
我们需要的信息有二个:
"uid":"74304975"(用户ID)
"username":"m8030_8388"(用户名称)
我们在最终提交给后端修改用户密码的数据包中替换这些信息,并且删除掉无关的参数。
/uc/findPassword/saveNewPassword?memberId=m8030_8388&uid=74304975&mobilePhone=17131000030&password=test888&newPassword=test888
"success":true
可以看到成功了。
接下来使用邮箱验证找回任意用户密码,我的第一个邮箱账号是:[email protected]qq.com
点击下一步的时候抓包,测试发现发送该数据包服务端会返回绑定该邮箱的用户信息。
"userInfo":{"uid":74305795,"memberId":"m7253_4666 ","password":null,"newPassword":null,"mobilePhone":null,"email":"[email protected]","randCode":null,"photoRandCodeSign":null,"ifbind":0,"ucToken":null,"signstr":null,"sign":null,"signFlag":false}
服务端返回的用户信息,我们需要的有这二个。
"uid":74305795(用户UID)
"memberId":"m7253_4666"(用户名称)
在这里发现另外一个问题,删除其他所有参数,只向后端传递email参数也是可以直接发送,说明后端是判断有参数才去检验参数值是否正确,并没有思考如果这个参数前端不传递怎么处理,导致可以绕过验证码和token的检验。
我用我的另一个账号正常走找回密码流程,邮箱是[email protected]。
邮箱中获得的url链接地址是:
点击邮箱收到的链接地址,并输入新密码:
点击确定的时候抓包
在通过邮箱找回密码,这个最终提交给后端修改密码的数据包中的GET参数如下:
jsonpCallback=jsonp1576499345000&memberId=m8031_29788&uid=74305025&email=2556654352%40qq.com&newPassword=test123&signstr=9e9f1cfe735993076fc69e679a65248e&_=1576499210154
可以看到有signstr参数,这个参数就是邮箱url地址中的参数,说明程序员是会检验这个参数值是否正确的,但是最后发现后端程序员并没有检验这个参数,把这个参数改成任意值或者直接删除都是可以通过的。
我们把这些参数值替换成我们之前获得的要修改的目标的信息,并删除其他参数。
memberId=m7253_4666&uid=74305795&email=2226356220%40qq.com&newPassword=test123
可以看到返回1
漏洞证明
我们来到网站登录这里输入刚刚重置的账号和密码
先输入通过手机验证重置任意用户的密码
17131948030
test888
再输入通过邮箱验证重置任意用户的密码
m7253_4666
test123
均登录成功。
修复方案
可以看到整体的代码缺陷存在3个问题:
第一个问题:只判断参数值有的时候检验参数值是否正确,并未考虑参数值没传递怎么处理。(案例:删除验证码和token还能继续发送邮件)
第二个问题:用户重要信息修改,代码应该验证一个身份的关键凭证,关键凭证通过后才能修改。(案例:手机验证找回密码)
第三个问题:压根没验证关键凭证参数值是否正确。(案例:邮箱验证找回密码)