用户密码重置找回 10 种常见姿势
本篇文章是参考大神
carry_your
讲师(360补天排名第一)的任意用户密码重置的10种常见姿势
总结的笔记。原视频地址:任意用户密码重置的10种常见姿势
介绍
本次课程主要针对挖掘逻辑漏洞中的任意用户密码重置方法和原理从 10 种常见情况进行了讲述,并结合漏洞挖掘中的真实案例场景与数据包演示了重置密码漏洞的检测方法,让大家对这一类逻辑漏洞有从浅入深,逐步深奥的见解。
验证码不失效
造成原因
找回密码的时候获取的验证码缺少时间限制仅值判断了验证码是够正确未判断验证码是否过期
测试方法
通过枚举找到真正的验证码输入验证码完成验证
案例
输入目标手机号,获取验证码随意输入验证码1234
点击下一步,拦截数据包:
数据包
POST /Account/CheckYQCode HTTP/1.1
Host: www.xxxx.cn
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0
Accept: */*Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Referer:
http://www.xxxx.cn/userCenter/toForgetPsdPage.html?mobile=
Content-Length: 11
Cookie: ASP.NET_SessionId=30jfruwn22h2xng3ahhzo2jxConnection: close
YQCode=1234
这种验证码不失效
而且验证码是4
位数的情况下,直接爆破 看包的返回长度或者内容来找到正确的验证码。
得到正确的验证码是1059
然后到网站上输入验证码跳转到输入新密码的页面完成重置密码
总结
这种验证码不失效的情况现在已经是非常少见的了,而且验证码的位数也很少有简单的4
位验证码了。现在绝大多数是这样的:6
位数的验证码而且15
分钟内有效,这样子的话爆破的可能性就非常的低了。
验证码直接返回
造成原因
输入手机号后点击获取验证码,验证码在客户端
生成,并直接返回在Response
以方便
对接下来的验证码进行比对。
测试方法
直接输入目标手机号,点击获取验证码,并观察返回包即可。在返回包中得到目标手机号获取的验证码,进而完成验证,重置密码成功。
案例
总结
这种情况上次狗哥也拿出来了这样一个类似的案例,记得他那个情况是在找回密码返回包中,直接返回了旧密码的md5
值,然后修改返回包可以直接重置管理员的密码。
验证码未绑定用户
造成原因
输入手机号和验证码进行重置密码的时候,仅对验证码是够正确进行了判断,未对该验证码是否与手机号匹配做验证。
测试方法
在提交手机号和验证码的时候,替换手机号为他人手机号进行测试,成功通过验证并重置他人密码。
案例一
首先使用自己的手机号接收验证码,
然后输入自己的手机号接收到的验证码,点击下一步并拦截数据包。
最后替换数据包里的目标手机号,然后发包
数据包
POST /tofindPasswordByPhone3.do HTTP/1.1
Host: www.xxxx.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://www.xxxx.com/tofindPasswordByPhone2.do?mobile=131234xxxxx&captcha=qkan&checkbox=on
Cookie: JSESSIONID=D4DB3147DBF941799B9CA74E4364F2F9; CNZZDATA1257851838=1754906772-1467355802-%7C1467355802; Hm_lvt_203f11422b4fcc8e2be8c54b036c5ff9=1467357432; Hm_lpvt_203f11422b4fcc8e2be8c54b036c5ff9=1467357978; smsRand="d9[x]1gSjADrs[d]"; td_cookie=699947232;
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 33
mobile=13888888888&smsCode=561768
mobile
的值改为我们想要重置的用户手机号点击下一步,跳转到设置密码的页面输入新密码,提交就成功重置了13888888888
的密码。
案例二
这个案例是验证码未绑定用户延伸一下,有时候测试会遇到这种,我们发现用户名被加密了,有无法得到具体的加密算法,怎么办?
其实大部分这种情况我们都不需要知道加密算法,比如这里例子,得到liuyy
的加密后的值是80e688602c4b11e66320c421e3b71ef2
,那么我们就可以直接利用这个keyCode
参数了。
步骤是一样的,输入我们的用户名和收到的验证码,然后把我们的keycode
替换为liuyy
的那个keycode
,这样就可以重置liuyy
的密码了。(漏洞原因还是是判断了验证码是否正确,而没有判断该验证码是否跟该用户匹配。)
总结
这种情况没有遇到过,学习了,以后在找回密码的时候会这么测试的。现在看来对于白帽子来说有2个手机号是多么的方便了。
案例二中如何获取到其他用户的keyCode
呢?这里的话正常走一遍找回密码的流程,然后抓包就会在数据包中找到加密后的keyCode
了,这样就可以重置任意用户的密码了。
修改接受验证码的手机或邮箱
造成原因
用户名、手机号、验证码三者没有统一
进行验证,仅判断了三者中的手机号和验证是否匹配和正确,如果正确则判断成功并进入下一流程。
测试方法
输入用户名获取验证码,修改接收验证码的手机号为自己的号码,自己手机成功接收验证码,提交到网站进行验证,验证成功并进入下一流程。
案例
点击找回密码,首先我们输入zhangwei
,然后点击获取验证码,这个时候把手机号
改为我们自己的号码,(一般情况下这里是在数据包中进行修改的),然后输入我们自己
的号码和验证码,成功跳到重置密码的页面,密码重置成功。
总结
carry_your
大神说这种情况下还是比较常见的,这里不是很能理解,为什么程序员开发的时候不做用户名和手机号的匹配呢?我平时测试的时候,很少遇到这种不做用户名和手机号匹配的情况 ⊙﹏⊙|||
本地验证绕过
造成原因
客户端在本地进行
验证码是否正确的判断
,而该判断结果
也可以在本地修改
,最终导致欺骗客户端
,误以为我们已经输入了正确的验证码。
测试方法
重置目标用户,输入错误验证码,修改返回包,把错误改为正确,即可绕过验证步骤,最终重置用户密码。
案例
输入手机号13888888888
,输入验证码123456
,验证码错误的时候,返回包返回的是0
这里我们所做的就是把0
修改为1
,可以借工具修改返回包,我们把0
改为1
,然后查看页面,成功跳转到修改密码的页面,输入新密码即可修改用户13888888888
的密码
总结
who_jeff
大神曾经分享给过这样一个类似的案例,当时他是在一个安卓app
上进行抓包测试的,当时就直接修改返回包 来欺骗本地的app
客户端的,成功重置任意用户的密码。
跳过验证步骤
造成原因
对修改密码的步骤,没有做校验,导致可以直接输入最终修改密码的网址,直接跳转到该页面,然后输入新密码达到重置密码的目的。
测试方法
首先使用自己
的账号走一次流程
,获取
每个步骤的页面链接
,然后记录页面3
对应的输入新密码的链接,重置他人用户时,获取验证码后,直接输入页面3
链接到新密码的界面,输入密码重置成功。
案例
首先我们走一下所有的步骤,页面1、页面2、页面3,然后记录下页面3的链接
然后尝试重置他人的用户。(ps:页面3
是在我们的邮箱里接收到的链接)
是某集团系统,所以用户wangshuai
,邮箱对应wangshuai@xxx.com.cn
使用账户wangshuai
,点击获取验证码,然后补齐下面的链接 https://xxx/page/login/veifyAccess.html?username=wangshuai&email=wangshuai@xxx.com.cn
,访问
后即可直接重置
该用户的密码
总结
这个漏洞不用按照正常的流程来走,这里的话直接补齐设置新密码的链接,然后利用这里链接可以直接重置任意用户的密码。
未校验用户字段的值
造成原因
在整个重置密码的流程中,只对验证码
和手机号
做了校验,未对
后面设置新密码
的用户身份做判断
,导致在最后一步
通过修改用户身份来重置他人的密码。
测试方法
使用自己
的手机号走流程
,在走到最后一个
设置密码的流程
时,修改数据包
里的用户信息。
案例
使用自己的手机号走流程,最后一步的数据包:
数据包
POST /yw_xxx/regist/saveNewPwd.action HTTP/1.1
Host: www.xxx.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://www.xxx.com/yw_xxx/regist/toSetPwd.action
Cookie: td_cookie=2080441838; JSESSIONID=530DD2516536F63131A1C098089CF2FB; JSESSIONID=5F3E182FAE378C1E799342C059F923B9Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 57
upassword=qwer1111&upassword1=qwer1111&mphone=131234xxxxx
我们可以看到密码找回成功
而且参数中只有密码
和用户名
,cookie
值无效,只需要修改指定用户名的值,就可以重置他人的用户密码。
修改用户为13888888888
,在发送数据包,我们就成功的把138
的密码修改为qwer111
总结
这里的话关键是在最后一步重置密码的时候替换目标手机号,这种其实也是比较暴力的,拿到这个链接的话 可以无条件批量重置任意用户的密码,这里面利用burp
可以批量枚举手机号码的mphone
参数。
修改密码处id可替换
造成原因
修改密码的时候,没有对原密码
进行判断,且根据id
的值来修改用户的密码,类似的SQL
语句:
update user set password="qwer1234" where id = ‘1’
修改数据包里的id
的值,即可修改他人密码。
测试方法
修改自己用户密码,抓取数据包,替换数据包中用户对应的id
值,即可修改他人的密码。
案例
点击立即提交
,得到右边的数据包,测试发现修改id为5
,就可以把对应的用户密码修改为123456
,没有对用户的原始密码判断,也没有判断id
是否属于该用户。
数据包
POST /Index/user/userinfo.html HTTP/1.1
Host: 192.168.8.31:8088Content-Length: 63Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Origin: http://192.168.8.31:8088
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 UBrowser/6.1.2107.202 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Referer: http://192.168.8.31:8088/Index/user/userinfo.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8
Cookie: PHPSESSID=28af1649bcbcb0e0dd83afa017691a03; __sticket=hKdyp310daeBfKWqgnimZoB2zrKwespkfaaVm4KKpN-Fp3tokWJ-YJeQqWOXe9mpf5-br8dox6SUlX_Rgn2t05GVpZ6Jqoaqg3zMoY-rnnM.6.a.
id=6&user_name=kefu1&password=123456&name=kefu123&email=&phone=
这里的id
和kefu1
的所在参数user_name
并没有去判断是否为用一个用户,这里修改id
是可以任意修改其他用户的密码的。
这里在不修改user_name
的情况下,只修改id
值就成功重置了用户的密码。
总结
这种也比较暴力流氓,可以通过枚举id
的值 ,来大批量重置任意用户密码的漏洞,因为不需要用户名了,只需要知道id
值即可,危害比较大。
cookie值的替换
造成原因
重置密码走到最后一步的时候仅判断唯一的用户标识cookie
是否存在,并没有判断该cookie
有没有通过之前重置密码过程的验证,导致可替换cookie
重置他人用户密码。(cookie
可指定用户获取。)
测试方法
重置自己用户密码到达最后阶段,抓到数据包,并在第一阶段
重新获取目标用户cookie
,替换cookie
到我们抓取的数据包中,发包测试。
案例
首先我们重置自己的用户wang111
的密码到最后一步,成功重置密码,抓到如下数据包。
数据包
POST /ppc/valid/resetPassword.do HTTP/1.1
Host: www.xxx.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Referer: http://www.xxx.com/ppc/valid/showResetPassword.do
Content-Length: 37
Cookie: JSESSIONID=E1AC27A7302C03C9432DE2254B99311A
Connection: close
password=qwer1111&rePassword=qwer1111
这里的数据包中并没有出现用用户的参数信息,所以这里面的话,可以判断这里应该是用cookie
作为身份的判断的。
到第一步去获取验证码的时候,点击下一页,可以获取到该用户wangshuai
对应的内容
Cookie: JSESSIONID=E1AC27A7302C03C9432DE2254B99311A
拿到这个cookie
就意味着可以利用这个身份判断标识去重置这个用户的密码了。
替换得到的cookie
值,即把cookie
对应的用户wangshuai
的密码修改为qwer1234
总结
关键点:cookie
可指定用户获取,尝试用他人账号来找回密码的时候,抓取数据包,可以从中提取出cookie
值,然后就可以利用这个cookie
值,就可以重置指定用户的密码了。
修改信息时替换字段值
造成原因
在执行修改信息的sql
语句的时候,用户的密码也当作字段执行了,而且是根据隐藏
参数loginid
来执行的,这样就导致修改隐藏
参数loginid
的值,就可以修改他人的用户密码。
测试方法
修改个人资料的时候,抓取数据包,然后来修改数据包的参数和对应的值,参数名一般可以在其他地方
找到,替换
隐藏参数
即可修改他人的密码等信息。
案例
点击 保存信息 抓取数据包
数据包
POST /xxxxx/employee_updateEmployeeInf.action HTTP/1.1
Host: www.xxxxx.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br
Referer: https://www.xxxxx.com/xxxxx/employee_forUpdate.action
Cookie: JSESSIONID=A115648DB5F49215078E583ABB6A665A; FLGSID=FLGSRV1; loginUrl=""Connection: close
Content-Type: multipart/form-data;boundary=---------------------------222991508618208
Content-Length: 709
-----------------------------222991508618208
Content-Disposition: form-data; name="mobileNo"
177XXXXXXXX
-----------------------------222991508618208
Content-Disposition: form-data; name="departId"
49
-----------------------------222991508618208
Content-Disposition: form-data; name="minority"
-----------------------------222991508618208
Content-Disposition: form-data; name="sex"
1
-----------------------------222991508618208
Content-Disposition: form-data; name="birthday"
19920829
-----------------------------222991508618208
Content-Disposition: form-data; name="photo"; filename=""
Content-Type: application/octet-stream
-----------------------------222991508618208--
可以看到数据包里只有这几个参数mobileNo、departId、minority、sex、birthdaymobileNo
是用户对应的手机号我们尝试修改mobileNo
的值,所获得的效果就是我们的手机号修改了,而这个手机号本身就是可以修改的。这个数据包中并没有找到我们标识用户身份的参数信息,唯一可以修改的手机号也只是表单中直接修改可以改变的。接下来我们去找一下隐藏参数。。。
view-source:https://www.xxx.com/ua/employee/forUpdate.do
查看下这个页面的源代码,找到了一个参数loginId
,这个参数是对应用户身份的而我们发现 上面的数据包里没有这个参数,那么我们是否可以自己添加上去呢?
这里修改数据包,添加字段loginId
,并且把值修改为他人的用户,发包返回修改成功,这样就成功的把用户871xxxx
的密码改为跟我们密码相同的值。
总结
最后一种要稍微复杂一点,得去找到隐藏参数:loginId
然后再修改数据包,以后挖洞的时候,多留意这些。
点评
从这篇文章开始,后面的文章貌似慢慢有了体系结构,这样整体看上去不会显得很凌乱了。
本文可能实际上也没有啥技术含量,但是写起来还是比较浪费时间的,在这个喧嚣浮躁的时代,个人博客越来越没有人看了,写博客感觉一直是用爱发电的状态。如果你恰巧财力雄厚,感觉本文对你有所帮助的话,可以考虑打赏一下本文,用以维持高昂的服务器运营费用(域名费用、服务器费用、CDN费用等)
微信
![]() |
支付宝
![]() |
没想到文章加入打赏列表没几天 就有热心网友打赏了 于是国光我用 Bootstrap 重写了一个页面 用以感谢 支持我的朋友,详情请看 打赏列表 | 国光