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 输入账号、密码:

image.png

提交后拦截请求,若账号不存在则服务端应答为:

image.png

若账号存在则服务端应答为:

image.png

分析发现,虽然应答很类似,但还是有区别,有效账号比无效账号多了个“您”,或者,从应答体的长度也能判断出该账号是否有效。同时,服务端未限制高频访问,所以,可枚举有效账号。

将 mobile 参数值定为枚举变量、以常见国人姓名拼音 top500 和常见后台账号作为字典,在枚举结果中用,应答包长度为 561 的均为有效账号:

image.png

其中,既有 chenying、chenyun 这类普通账号,也有 admin、ceshi 这类后台账号,结果存为 username.txt:

image.png


密码可暴破

服务端有密码试错上限的机制,错误 5 次则一小时内禁止登录:

image.png

查看登录请求:

image.png

logintime 参数名和参数值引起我注意,刚好也是试错上限 5,尝试将值其改为 4 后,服务器又正常响应,或者,删除整改 logintime 后,也可绕过试错限制。

现在,用删除 logintime 后的请求包,将 mobile 定义为枚举变量 1、以前面生成的 username.txt 为字典,将 password 定义为枚举变量 2、以常见弱口令 top1000 为字典,进行密码暴破:

image.png

其中,应答包长度为 380 的均为有效密码,存为 logined.txt:

image.png


任意账号注册

在注册页面 https://www.xxxx.com/Wap/User/register 输入未注册过的手机号点击“获取验证码”后、输入收到的短信验证码后提交,进入密码设置页面:

image.png

输入密码后拦截请求:

image.png

简单分析发现,register_mobile 为注册的用户名,只要该参数值未注册过,通过这个请求包可绕过短信验证成功创建任意账号。

比如,系统本来只允许用手机号当用户名进行注册,利用该漏洞,可以创建账号 yangyangwithgnu/abcd1234,登录确认:

image.png


任意账号密码找回

密码找回页面 https://www.xxxx.com/Wap/User/forgetpass 用攻击者账号 13908080808 进入密码找回全流程,输入短信验证码后提交:

image.png

进入新密码页面,输入后提交,拦截请求如下:

image.png

其中,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 登录,成功进入系统:

image.png

同理可重置管理员账号,为避免影响业务,不再实际操作。


防御措施

通常来说,密码找回逻辑中含有用户标识(用户名、用户 ID、cookie)、接收端(手机、邮箱)、凭证(验证码、token)、当前步骤等四个要素,这四个要素必须完整关联,否则可能导致任意账号密码找回漏洞。另外,服务端应限制枚举等恶意请求。

*本文原创作者:yangyangwithgnu