web 安全事件中,账号,通常是呈现给攻击者的第一接触点,与账号相关的功能若存在缺陷,攻击者可以此获取关键信息和重要功能,如,登录失败的报错信息可判断出是否因账号不存在所致,可被利用枚举有效账号,比如,登录试错无次数限制,可导致暴破密码,又如,注册流程各步骤未严格关联,导致批量注册任意账号,再如,密码找回功能各步骤未严格关联,导致任意账号密码重置。
我在日常渗透时遇到个同时存在这几类问题的网站 https://www.xxxx.com/,该网站为某电商平台,合理结合几类问题,当时已拿到管理员权限,漏洞现已提交并确认修复,思路分享给大家。
开始之前,说个习惯,很多网站分了 PC 版本和手机版本,手机版常为功能裁减,相应安全防御也较弱,“柿子专挑软的捏”,所以,我会先尽可能找出该网站的手机版。具体而言,我习惯先用手机直接访问,服务端自动将跳转至手机版,提取手机版的访问地址;如果觉得手机上输入 URL 麻烦,你可以安装 firefox 的 useragent-switcher(https://mybrowseraddon.com/useragent-switcher.html)扩展,模拟手机终端进行访问;当然,其他手段也可考虑,你可以通过子域名枚举工具 Sublist3r(https://github.com/aboul3la/Sublist3r)找到类似 https://m.xxxx.com/ 的手机版本,也可以通过路径枚举工具 dirsearch(https://github.com/maurosoria/dirsearch)找到类似 https://www.xxxx.com/wap 的手机版本,还可以通过 google hacking (inurl:xxxx.com 移动端)找到类似 https://www.xxxx.com/mobile。
账号可枚举
在登录页面 https://www.xxxx.com/Wap/User/login 输入账号、密码:
提交后拦截请求,若账号不存在则服务端应答为:
若账号存在则服务端应答为:
分析发现,虽然应答很类似,但还是有区别,有效账号比无效账号多了个“您”,或者,从应答体的长度也能判断出该账号是否有效。同时,服务端未限制高频访问,所以,可枚举有效账号。
将 mobile 参数值定为枚举变量、以常见国人姓名拼音 top500 和常见后台账号作为字典,在枚举结果中用,应答包长度为 561 的均为有效账号:
其中,既有 chenying、chenyun 这类普通账号,也有 admin、ceshi 这类后台账号,结果存为 username.txt:
密码可暴破
服务端有密码试错上限的机制,错误 5 次则一小时内禁止登录:
查看登录请求:
logintime 参数名和参数值引起我注意,刚好也是试错上限 5,尝试将值其改为 4 后,服务器又正常响应,或者,删除整改 logintime 后,也可绕过试错限制。
现在,用删除 logintime 后的请求包,将 mobile 定义为枚举变量 1、以前面生成的 username.txt 为字典,将 password 定义为枚举变量 2、以常见弱口令 top1000 为字典,进行密码暴破:
其中,应答包长度为 380 的均为有效密码,存为 logined.txt:
任意账号注册
在注册页面 https://www.xxxx.com/Wap/User/register 输入未注册过的手机号点击“获取验证码”后、输入收到的短信验证码后提交,进入密码设置页面:
输入密码后拦截请求:
简单分析发现,register_mobile 为注册的用户名,只要该参数值未注册过,通过这个请求包可绕过短信验证成功创建任意账号。
比如,系统本来只允许用手机号当用户名进行注册,利用该漏洞,可以创建账号 yangyangwithgnu/abcd1234,登录确认:
任意账号密码找回
密码找回页面 https://www.xxxx.com/Wap/User/forgetpass 用攻击者账号 13908080808 进入密码找回全流程,输入短信验证码后提交:
进入新密码页面,输入后提交,拦截请求如下:
其中,PHPSESSID=p6nujg7itekpau6p1e9ibbpe86、register_mobile=13908080808 这两个参数引起了我的注意。这个请求,用于重置账号 13908080808 密码,那么服务端如何知道该重置 13908080808 而不是 13908080807、13908080809 呢?刚才说的几个参数中肯定有一个用于该目的。逐一尝试发现,PHPSESSID 就是它,另外,boss_language 和 register_mobile 可删除,不影响结果。
这让我闻到浓郁的 cookie 混淆的味道。大致攻击思路:首先,用攻击者账号 13908080808 进入密码找回流程,查收重置验证码、通过校验;然后,输入新密码后提交,拦截中断该请求,暂不发至服务端,这时,PHPSESSID 关联的是 13908080808 账号;接着,关闭浏览器的 burp 代理,新开重置流程的首页,在页面中输入普通账号 13908090133 后获取短信验证码,这时,PHPSESSID 已关联成 13908090133 了;最后,放行之前中断的请求,放至服务端,逻辑上,可以成功重置 13908090133 的密码。
用上述思路尝试将 13908090133 密码重置为 PenTest1024,前端显示重置成功。尝试用 13908090133/PenTest1024 登录,成功进入系统:
同理可重置管理员账号,为避免影响业务,不再实际操作。
防御措施
通常来说,密码找回逻辑中含有用户标识(用户名、用户 ID、cookie)、接收端(手机、邮箱)、凭证(验证码、token)、当前步骤等四个要素,这四个要素必须完整关联,否则可能导致任意账号密码找回漏洞。另外,服务端应限制枚举等恶意请求。
本文原创作者:yangyangwithgnu 转自 www.freebuf.com