Web前端参数加密分析破解与测试
Posted Tr0e
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Web前端参数加密分析破解与测试相关的知识,希望对你有一定的参考价值。
前言
在渗透测试过程中,许多系统会直接明文传输账户密码等敏感信息,存在被嗅探的风险。有的开发人员则会对相应的敏感信息在前端借助JS代码进行加密后再传输,使攻击者看到的是“一堆乱码”,从而无法正常进行篡改和其他渗透测试操作……如下图所示。
但是前端加密只能提高攻击者进行攻击的难度,并无法对敏感信息进行有效的保护。因为前端JS加密的代码是公开的(虽然可能会经过混淆和压缩),攻击者可以通过对加密函数的审计,来达到根据自身需要构造测试语句并加密后替换初始密文的目的,从而可以像明文传输的系统一样进行正常的渗透测试。本文将记录对某网站登录页面的前端加密函数的破解过程。
初级解密
首先来看看该站点的登录页面:
输入账号密码,开启代理和BurpSuite,点击登录,抓包如下:
可见,用户名和密码在传输时均经过前端加密。
点击事件
接下来进行加密函数的查找,此例借助火狐浏览器F12开发者工具。
前端很多操作都是基于事件绑定的,我们选取“登录”按钮,并查看其绑定的事件。
点击event,可快速定位到这个button点击后的事件逻辑块代码,如下图所示。
在调试器中进一步跟进、查看登录按钮的事件逻辑块代码:
此处附上validateLoginForm()
函数及其关联函数的具体代码:
function validateLoginForm()
var userName = document.getElementById("userName");
var userPwd = document.getElementById("userPassword");
var inputCode = document.getElementById("validateCode");
if (userName.value.replace(/(^\\s*)|(\\s*$)/g, "")=='')
$("#login_info").html("请输入用户名");
userName.focus();
return false;
else if (userPwd.value.replace(/(^\\s*)|(\\s*$)/g, "")=='')
$("#login_info").html("请输入密码");
userPwd.focus();
return false;
else if (inputCode!=undefined && inputCode.value.replace(/(^\\s*)|(\\s*$)/g, "")=='')
$("#login_info").html("请输入验证码");
inputCode.focus();
return false;
else
userLogin();
function userLogin()
var userName = document.getElementById("userName").value;
var userPwd = document.getElementById("userPassword").value;
var inputCode = document.getElementById("validateCode").value;
var actionName = "";
var submitUserId = document.getElementById("submitUserId").value;
var loginUrl = "/wt/dayeewt/web/index/webUserLogin!userLoginForNormalByCode?operational=260496f91c732845b3918ece535b9c378edde02b7918fe1ab4aefb88debf685012f581ab741e69cc9c3a73bbbf91490a61806b4ea38059f1f30106fd947bf04c67635eb5443d0c163cbaf45030dacf5a3d8fada7db3731a2";
var dataStr = "needDefaultKey=true&submitUserId="+submitUserId+"&userName="+encrypt(userName)+"&password="+encrypt(userPwd)+"&validateCode="+inputCode+"&actionName="+actionName;
$.ajax(
type:"POST",
dataType:"text",
url:loginUrl,
data:dataStr,
success:callBack
);
function callBack(data)
var result = eval("("+data+")");
var retCode = result.retCode;
if(retCode=="0")
var brandCode = '1';
if(brandCode == '')
brandCode = 1;
var url;
url = "/wt/dayeewt/web/index/primaryResume210!listResume?operational=260496f91c732845b3918ece535b9c37b9663b3aaba1be538a89b51cf8e70839552308a0211a4dd69fd52a40c23d85bba51758a03efc5dd80ab70edad5576c64c39cecf29e406ff9"+"&brandCode="+brandCode;
window.location.href=url;
else
genNewCode();
document.getElementById("validateCode").value="";
$("#login_info").html(result.retMsg);
……………………
从以上代码可以看出,userLogin()
函数中调用encrypt()
函数对用户名和密码进行了加密,"&userName="+encrypt(userName)+"&password="+encrypt(userPwd)
。
加密函数
显然,接下来的任务是继续追踪并查看encrypt()
函数。
直接使用Ctrl+Shift+F
全局搜索encrypt
:
双击查看encrypt()
函数的具体代码:
从代码中可以看到使用了AES加密(ECB模式),密钥key=“1234567887654321”。
具体的加密逻辑代码放在上图所示的crypto-js.js
中,此处不再展开分析了。
结果验证
打开AES在线加解密站点,如下图所示:
选择加密模式ECB、填充模式pkcs7padding、数据块128位、密码1234567887654321、输出hex,然后输入a123456并进行加密,如下图所示:
得到的加密结果5ec7551fa86d8c8cf5fbe8f153c96dd8
和文章前面拦截获取的登录请求包的密文进行比较:
可见,与password的密文值完全一致。
同时可验证下是否能正常解密,咱们输入数据包中username参数的密文4bc8c4cf302a2615278bdd630ba541bcaa7d6d07dac4c6b68bec23f5fd1d3126
,尝试进行解密,成功。如下图所示:
断点调试
此案例中整体代码并不复杂,encrypt()
加密函数的查找相对简单,如果遇到复杂的加密情况(经过代码混淆和压缩),我们可能需要借助断点调试确定程序的加密函数的位置(还可以跟踪加密过程中各变量数值的变化)。下面简述下前端JS代码的断点调试过程。
如下图所示,在代码行前面单击即可在改行设置断点:
重新点击“登录”,如果该button的逻辑处理代码调用了断点处的函数,则程序会被暂停到断点处(可初步确定encrypt()
函数就是加密了登录账号信息的函数):
继续逐步往下执行JS代码(可跨步、逐步、回跳),并观察相关变量的数值变化:
一直往下逐行执行代码,最后返回账号(1425553230@qq.com)的密文值:
得到的加密结果4bc8c4cf302a2615278bdd630ba541bcaa7d6d07dac4c6b68bec23f5fd1d3126
和文章前面拦截获取的登录请求包的密文进行比较:
可见,与userName参数的密文值完全一致,故断定该函数即为我们要找的加密函数。
密文绕过
对经过前端加密的数据包的修改,有两种思路:
- 从网站的前端JS代码中查找加密函数,有些站点的加密方式较为简单,通过审计前端JS逻辑代码可以直接破解,从而对密文进行解密后做修改,最后再重新加密并发送;
- 中断程序的执行,直接在前端JS代码对明文数据进行加密前,对明文数据进行更改。
第一种方法上面已经展示完毕,但是该方法局限于前端加密算法很简单(Base64、MD5、密码存储在前端的DES等),如果加密算法特别复杂(如非对称加密RSA算法),无法直接破解(如下图所示),我们就只能通过第二种方法来绕过密文了。
断点拦截
1、来看看本次测试的站点和功能,为某支付平台的交易记录查询功能:
2、首先,从前端JS代码找到该站点的加密函数所在的位置,如下图所示:
3、接着,在该语句设置断点,然后执行程序,如果加密函数寻找正确,那么程序将暂定在该行代码处:
4、程序跳转到执行下一行代码,发现查询请求包的明文数据k,如下图所示:
5、切换到控制台,输入k,控制台将打印k的值,如下图所示:
6、接着关键操作!直接在控制台输入“k=XXXXX”的命令替换掉k的值(此处替换掉查询的卡号,尝试进行越权查询测试),如下图所示:
7、最后,取消断点,放行程序,发现查询的卡号成功被篡改,同时越权查询失败,如下图所示:
【小结】至此,借助F12开发者工具的断点调试功能,我们成功实现了对采用前端加密的站点的数据包篡改。
JS脚本替换
下面介绍第二种方法,借助Fiddler抓包工具,实现对前端加密站点的JS脚本替换,从而达到任意篡改数据包的目的。
1、首先,将包含加密函数的在线JS脚本文件通过点击鼠标右键,下载保存到本地,如下图所示:
2、在加密函数encryptstring: function (k, g) 中添加JS代码,替换查询请求包中的卡号,如下图所示:
3、接下来打开Fiddler,捕获加密函数所在的JS文件的请求,并将其拖入到右侧AutoResponder模块里,如下图所示:
4、进入AutoResponder模块,勾选以下选项并添加自动替换规则,将本地编辑的JS代码替换用于在线加密的JS代码,如下图所示:
5、刷新该站点,点击该功能模块,其前端JS代码将被我们本地编辑过的JS代码替换,来看下效果:
【小结】至此,我们借助Fiddler的AutoResponder模块模块实现了对采用了前端加密的站点的请求包的篡改。
总结
至此,我们已经可以自由地篡改和替换该网站相应数据包的密文,从而进行正常的渗透测试。另外补充一句,断点调试虽然比JS脚本代码替换简便,但是JS脚本代码替换的方法可以实现的功能更为强大,测试人员可根据实际的需求,选择合适的测试方法。
最后,附上几篇大佬们关于前端加密的文章:
以上是关于Web前端参数加密分析破解与测试的主要内容,如果未能解决你的问题,请参考以下文章