- 逻辑漏洞概述
什么是逻辑漏洞
随着网络安全法的实施、企业和用户安全意识的提高,Web安全已经成为了重点关注的方向。诸如使用安全开发框架、部署安全防护设备等防护手段的使用,使得网站的常规漏洞越来越少。以SQL注入为例,由于其危害巨大,常年稳居OWASP Top 10的第一位,目前很多Web开发框架在底层就直接杜绝的SQL注入问题。
但“逻辑漏洞”一词现在却更加热门,很可能成为Web漏洞的主战场。之所以称之为“逻辑漏洞”,是因为在代码之后是人的逻辑,人更容易犯错,是编写完程序后随着人的思维理解产生的不足,所以逻辑漏洞一直都在。
相比SQL注入、XSS漏洞等传统安全漏洞,SQL注入、XSS等漏洞可以通过安全框架等避免,并且攻击流量非法,对原始程序进行了破坏,防火墙可以检测;所以现在的攻击者更倾向于利用业务逻辑层的应用安全问题,逻辑漏洞就是指攻击者利用业务的设计缺陷,获取敏感信息或破环业务的完整性。一般出现在密码修改(没有旧密码验证)越权访问、密码找回、交易支付等功能处。而且由于逻辑漏洞产生的流量多数为合法流量,传统的安全防御设备和措施收效甚微,一般的防护手段或设备无法阻止,这类问题往往危害巨大,可能造成了企业的资产损失和名誉受损,所以导致了逻辑漏洞成为了企业防护中的难题。
逻辑漏洞分类
验证机制缺陷
会话管理缺陷
权限管理缺陷
业务逻辑缺陷
- 如何挖掘逻辑漏洞
逻辑漏洞的挖掘其实也是思路拓展的过程
1.测试业务的时候,先了解清楚业务整体流程,可以利用思维导图快速理清各个业务之间的关系也可以通过查看 JS 了解(JS 中可能会存在信息泄漏)
2.重点关注的业务:个人(他人)信息、密码修改(找回)、支付流程、注册流程、需要手机(邮箱)验证的业务
3. 对每个业务模块进行抓包,分析其中各种请求,注意 特殊参数,很有可能就是这些 特殊参数 决定了业务步骤
4. 抓包重放的过程,需要多次实验,判断是否可以跳过(绕过),如何跳过(绕过),纯数字可以用 数字 + 字母 尝试绕过
5. 返回包中数据的分析,关注特殊字符串和特殊参数
6.综上所述,业务流程需同时结合 HTTP/HTTPS 请求分析,关注重点在各种可以用于区别的参数,绕过必要验证,跳过业务步骤
- 交易支付中的逻辑问题
支付类逻辑
1.商品价格修改:在购买商品的时候,通过抓包通过修改商品的价格,即可造成0.01元购买商品。这里修改商品价格的地方很多,加入购物车的时候可以修改,提交订单的时候也可以修改,这个看情况进行修改。
2.商品数量修改:有些开发会对商品的价格进行封装,我们通过修改数据包没法进行修改,但是这里的商品数量可以改为-1,然后我们再选择别的商品,即可造成价格抵扣。这里修改的地方也是加入购物车的时候可以修改,提交订单的时候也可以修改。
3.运费修改:这个跟以上同理,但是有些开发只对商品做了限制,忽略了运费这一点,通过修改运费为负数,即可抵扣商品。
4.支付金额修改:这个就是最后一步支付的时候,可以修改订单的价格,造成低价购买。
- 密码修改逻辑漏洞
登陆页面
点击找回密码功能,输入内容后发现前端验证,未向后端发送数据包
找回密码
从验证码入手,看看发送验证码的情况
获取验证码
发现点击发送没有时间限制,但是不能指定电话号码,所以不知道是否真的有短信发送
点击确定,向服务器发起获取验证码请求
POST /dss/findPwd.e HTTP/1.1
Host: xxx.xxx.xxx.xxx:xxx
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://xxx.xxx.xxx.xxx:xxx/dss/findPwd.jsp
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 7
Connection: close
Cookie: JSESSIONID=14CEE8646A9BF274394F948BE24D5ED5
id=test
放过请求找回test账号,返回200,没有数据内容
正确用户名返回数据包
再尝试请求一个错误的账号,返回内容中疑似存在验证码,但是该验证码不能成功重置密码
错误用户名返回数据包
上面数据包根据返回内容不同,也可用来爆破存在的用户名
既然是前端验证,我们通过使用开发者工具箱找到前端验证的函数
更新密码调用的js函数
查看找到的函数内容
function checkform() {
$("#checkResult").html('');
var checkResultMes = '请输入的用户账号!';
var findPwdNumber = $('#findPwdNumber').val();
if(!findPwdNumber||$.trim(findPwdNumber)=='') {
//验证手机号为11位
$("#checkResult").html(checkResultMes);
return false;
}
return true;
}
//验证输入的手机号是否存在
function getRand(){
if(checkform()){
var findPwdNumber = $('#findPwdNumber').val();
if(confirm('是否确认执行找回工号[' + findPwdNumber + ']的密码操作?')){
$.post('/dss/findPwd.e',{id:findPwdNumber},function(data){
var result = eval(data);
$("#findPwdRand_hidden").val(result[0].findPwdRand);
$("#checkResult").html(result[0].Msg);
});
}
}
}
//重置密码
function forwordcxc(){
var info = {};
info.findPwdNumber = $("#findPwdNumber").val();
info.findPwdRand = $("#findPwdRand").val();
info.findPwdRand_hidden = $("#findPwdRand_hidden").val();
info.findPwdNew = $("#findPwdNew").val();
info.findPwdNewRepeat = $("#findPwdNewRepeat").val();
if(info.findPwdNew==""||info.findPwdNewRepeat==""){
$("#checkResult").html('请输入两次新密码!');
return;
}
if(info.findPwdNew != info.findPwdNewRepeat){
$("#checkResult").html('两次输入的密码不一致,请重新输入!');
return;
}
var numExp = new RegExp(/([0-9])/);
var strExp = new RegExp(/([a-zA-Z])/);
var strnumExp = new RegExp(/([!,@,#,$,%,^,&,*,?,_,~])/);
if(!(strnumExp.test(info.findPwdNew)&& strExp.test(info.findPwdNew)&&numExp.test(info.findPwdNew)&&info.findPwdNew.length>=8)){
$("#checkResult").html('新密码必需包括特殊字符(! @ # $ % ^ & * ? _ ~), 字母, 数字且长度大于7!');
return;
}
if(info.findPwdRand==""){
$("#checkResult").html('请输入接收到的验证码!');
return;
}
if(info.findPwdRand != info.findPwdRand_hidden){
$("#checkResult").html('验证码输入错误,请重新输入!');
return;
}
info.findPwdNew = aesEncrypt(info.findPwdNew);
info.findPwdNewRepeat = aesEncrypt(info.findPwdNewRepeat);
$.post('/dss/updatePwd.e',info,function(data){
var value = eval(data);
if(value[0].result == '1'){
$("#checkResult").html("密码更新成功,此页面3秒后关闭,请用新密码登录!");
setTimeout(rollBack, 3000);
}else{
$("#checkResult").html("修改密码错误,请联系管理员!");
}
});
}
function rollBack(){
window.location.href = "/dss/index.jsp";
}
查看js代码发现验证码是否正确只通过提交字段和隐藏字段是否相等
验证码验证代码
使用开发者工具箱的控制台执行js代码
执行js代码
获取id为findPwdRand和findPwdRand_hidden的值,发现findPwdRand_hidden内容为空,为findPwdRand_hidden赋值与findPwdRand相同的值,点击更新密码,然后发起修改请求
修改密码数据包
放过拦截的数据包
修改成功
密码更新成功,验证可登陆。
- 个人项目逻辑漏洞
漏洞情景
1)登录验证码爆破
有些系统,手机获取验证码的时候,没有对验证码的验证次数进行限制,或者是没有对验证码的有限时间进行限制,就会造成验证码爆破,但是实战中4位的数字验证码还是很容易爆破的,有些6 7 位的就不是很好爆破了,一般src也不会收这些。
2)凭证返回
这个就很有意思,在一次某人才网漏洞挖掘的时候,发现在获取验证码的地方,抓包,返回的响应包set-Cookie里面直接返回了验证码,直接就可以输入验证码,可以完成任意用户登录,注册,密码找回。有一些还有在登陆或者密码找回的时候会返回密码。
- 逻辑漏洞修复
首先要设计好IP锁定的安全机制,当攻击者在尝试登陆网站用户的时候,可以设定一分钟登陆多少次,登陆多了就锁定该IP,再一个账户如果尝试一些特殊操作,比如找回密码,找回次数过多,也会封掉该IP。
验证码识别防护,增加一些语音验证码,特殊字体验证码,拼图下拉验证码,需要人手动操作的验证码,短信验证码一分钟只能获取一次验证码。验证码的生效时间安全限制,无论验证码是否正确都要一分钟后就过期,不能再用。所有的用户登录以及注册,都要与后端服务器进行交互,包括数据库服务器。