今天上線測試發現了一個只有前端驗證的修改密碼邏輯漏洞,但是該應用根本沒有對驗證碼進行驗證。
訪問測試地址http://xxx.xxx.xxx.xxx:xxx/dss,查看頁面功能,發現存在找回密碼功能。

登陸頁面
點擊找回密碼功能,輸入內容后發現前端驗證,未向后端發送數據包

找回密碼
從驗證碼入手,看看發送驗證碼的情況

獲取驗證碼
發現點擊發送沒有時間限制,但是不能指定電話號碼,所以不知道是否真的有短信發送
點擊確定,向服務器發起獲取驗證碼請求
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相同的值,點擊更新密碼,然后發起修改請求

修改密碼數據包
放過攔截的數據包

密碼更新成功,驗證可登陸。