漏洞成因:
由于前端BindUpdateUserClickEvent()函数代码段存在问题,导致二次函数绕过,
默认的AntiForgery也许存在隐患。
我们在分析JS函数的时候,需要注重全文通读,因为你只要通读了他的整个过程,代码事件
才知道如何去利用薄弱环节,漏洞点,完成漏洞复现。
案例1:间接跳过函数强校检
首先打开目标
打开源代码进行分析,首先分析了一下函数
我们简单分析了一下
var regex = new RegExp('(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9]).{8,30}');
可以看到,这里取了一个正则
if (regex.test(Pwd) != true) {
// alert("你设置密码太简单,至少要包括大小写字母、数字、特殊字符,需要重新设置密码!");
var temp = data.substring(3);
//alert(temp);
$("#ID").val(temp);
这里有有一个输入的判断。
我们先来梳理一下登陆流程:
首先是SmsSubmitLogin登陆函数,接着判断密码的复杂度,如果密码简单,则触发到BindGroupSelectButtonClickEvent函数,强制修改密码,才能够登陆,然后这里有一个函数BindUpdateUserClickEvent()这个函数,相当于第二层验证,他这里
//首先判断前台的验证是否通过
var valid = $('#UpdateUserInfo').form('validate');
if (valid == false) {
return false;
有一个前台的验证,验证通过的UpdateUserInfo才能生效跳到下一步。
也就是说不能通过前台的验证,则不能通过这一步
而/UName1,Pwd1,PwdOK1,Phone1,Mail1
则是构造的所需参数:
//设置CSRF的AntiForgery的验证
if (postData != null) {
postData.__RequestVerificationToken = $("input[name='__RequestVerificationToken']").val();
} else {
postData = new Object;
postData.__RequestVerificationToken = $("input[name='__RequestVerificationToken']").val();
}
这里有CSRF的AntiForgery验证,最后通过异步修改用户的密码
我们来到这里,前后对比一下
这里就是前台取验证的,那么我们继续看
第一个函数是
BindGroupSelectButtonClickEvent
点击后,则触发修改密码,那么这个函数在
BindGroupSelectButtonClickEvent
在这里意义是什么呢
很明显了,他调用了这个函数,后面这个是具体调用的功能验证
可以看到这里 window.location.href = "/Home/Index";
他调到home/index,就是验证通过的意思了
那么在这里,
else {
alert(data);
window.location.href = "/Login/Index/";
}
否则跳转到首页。
我们先来尝试一遍
触发了登陆函数,随便提交一个错误数据。
验证码没对,重新填入,这里提示用户密码错误,点击,就不能继续了。
那么我们先来尝试一下修改密码的函数,我们是否能通过函数直接绕过他
按照思路,应该是直接选调这个函数,把void改成修改的函数
注意,这是登陆的函数,那么修改的函数,点击确定后
关键他这个函数调用,执行一次,这时候需要截取数据包,因为他是强验证,所以他会跳转到首页。
这时候我们发点击确定的时候,自动跳出来一个窗口,证明函数调用成功,现ID是没有给值的,因为这里没有取到。
//var val = sessionStorage.getItem("UserInfo");
所以ID是空,我们就简单填入50asddzssda*)&密码:50asddzssda*)&50asddzssda*)18
这里我们说了不能直接调用BindUpdateUserClickEvent()函数,因为有前台验证
那我们来尝试调用修改函数之后,再调用BindUpdateUserClickEvent()函数,来试试
我们可以发现这里,我们需要再次把BindUpdateUserClickEvent()写入
点击确定就会flase,flase是调到哪里呢?
那么没过前台验证嘛,所以直接flase,流程我们清楚了,那么我们回到前台验证代码段,注意这里:
这是前台的验证阶段
那么这个函数我们能否调用呢BindGroupSelectButtonClickEvent(),那么这个函数,可以理解成什么呢,他间接了逃过了这个函数BindUpdateUserClickEvent()的校检,我们来试试,通过修改函数,换成BindUpdateUserClickEvent()看是否能逃到这一步
我们首先还是触发修改函数
接着把密码填入,这里需要注意,修改成 BindGroupSelectButtonClickEvent()函数,而不是BindUpdateUserClickEvent(),我们这样做的目的,就是要看一看,是否真的能够通过BindGroupSelectButtonClickEvent()函数间接逃过BindUpdateUserClickEvent()的强校检,如果能逃过,那么就会直接带入到
当我们点了两次,第一次,触发错误的登陆函数信息,也就是这里,接着触发了BindGroupSelectButtonClickEvent()函数,点击确定之后发现是过了
这里,那证明我们利用函数逃过了BindUpdateUserClickEvent(),函数强校检
案例2:二次函数绕过使用功能
我们来看看其他的函数
注意这里,有一个函数ShowSmsPhoneDialog()这里提示输入手机号码,还有一个函数ShowSmsVerifyDialog()这里提示手机号码输入判断,我们先看看能不能直接调用ShowSmsVerifyDialog()函数
可以调用,那么我们就把用户名写成手机号码,1358888888,我们注意。默认是用户密码错误,我们现在做的就是函数调用他的原始功能。怎么调呢,首先我们把用户名换成手机号了,换成13188888888
默认是用户密码错误,我们现在做的就是函数调用他的原始功能,怎么调呢,首先
我们把用户名换成手机号了,换成13188888888,我们发现直接调是有误区的,为啥呢,直接调的话,手机号码参数就不对啊,怎么输入都是手机号码错误,弹回flase,虽然调了函数,但是用户名参数始终还是uname没有变成Phone_NO嘛,所以他才会报错,也就证明不能直接调用,因为我们不可能让uname变成Phone_NO,那么我们先看看流程。
我们发现其实ShowSmsVerifyDialog()函数和ShowSmsPhoneDialog(),是有依赖的,什么依赖呢,它们两个函数代表了一个流程。怎么走比如说ShowSmsPhoneDialog(),可以理解成输入用户的手机号码:1388888888,接着,触发到ShowSmsVerifyDialog(),进行发送验证码,是这么一个流程
那么我们既然知道了流程,就先调用ShowSmsPhoneDialog()
当我们点击确定的时候,发现直接把ShowSmsPhoneDialog()
函数的功能成功调取出来了,接着我们看看验证码这里,我们发现是void
这里是走不了下一步的,所以,我们得二次再去填入一个ShowSmsPhoneDialog()
让他走下去
这里我们试试,修改函数
我们这样做的目的就是让ShowSmsVerifyDialog()函数生效
重放一下,再重放一次
我们到这里可以发现&Phone_NO起作用了,成功带入了Phone_NO参数,也就是说流程是触发到ShowSmsVerifyDialog()函数,我们注意这里
__RequestVerificationToken=ywC7UQ3uABD6IG0NJBlu66AHA0xmoOEqIZPDzOcCQjE2hG1YzJOi3IV6bFPhweS3bxmGAAF7oxoGpVsiSc_K2_9tiuPzeyFSiGnaH3p5fxs1
这里是一个验证token,我们把它去掉后看看效果
变成302状态了,原因是啥呢,这是一个重定向,代表对象被移动。所以还是需要__RequestVerificationToken我们加入它,点击执行
我们发现功能就可以使用了,正确判断了,二次函数利用成功。