JS逆向
基本了解
作用域:
相关数据值
调用堆栈:
由下到上就是代码的执行顺序
常见分析调试流程:
1、代码全局搜索
2、文件流程断点
3、代码标签断点
4、XHR提交断点
某通js逆向结合burp插件jsEncrypter
申通快递会员中心-登录
查看登录包,这里的发起程序里的请求调用堆栈可以看见依次调用了那些js文件,调用顺序为从下往上
看名字就感觉send就是发送,ajax 提交,login可能存在加密
function Login() {
var numMobile = $(“#numMobile”).val();
var numPassword = $(“#numPassword”).val();
var numCode = $(“#numCode”).val();
var chkAgreement = $(“#accountChkAgreement”).prop(“checked”);
function Login() {
var numMobile = $("#numMobile").val();
var numPassword = $("#numPassword").val();
var numCode = $("#numCode").val();
var chkAgreement=$("#accountChkAgreement").prop("checked");
//验证服务条款是否选中
if (!chkAgreement) {
layer.msg("请查看并同意服务条款");
return false;
}
//判断手机号码格式是否正确
if (!$("#numMobile").val() === "") {
layer.msg("手机号码不能为空");
return false;
}
else if (!$("#numMobile").val().length > 11) {
layer.msg("请输入有效的手机号码");
return false;
}
//判断手机号码格式是否正确
else if (!$("#numMobile").val().match(/^1(3|4|5|6|7|8|9)\d{9}$/)) {
layer.msg("手机号码格式不正确");
return false;
}
//用if语句来判断当用户名或者密码有一个为false时就弹出一个消息框,并提示:请输入正确的信息。
if (!numMobile || !numPassword) {
layer.msg("请输入正确的信息");
return false;
}
encrypt.setPublicKey(pkey);
var logindata = {};
//加密手机号
var numMobile = $("#numMobile").val();
var numPassword = $("#numPassword").val();
var numCode = $("#numCode").val();
logindata.UserName = encodeURI(encrypt.encrypt(numMobile));
logindata.Mobile = encodeURI(encrypt.encrypt(numMobile));;
//加密密码
logindata.Password = encodeURI(encrypt.encrypt(numPassword));
// logindata.ValidateCode = numCode;
//logindata.NECaptchaValidate = ret.validate;
var userId = $("#hiddenUserId").val();
//用ajax来实现不刷新网页的基础上更新数据
$.ajax({
type: "post",
url: "/Vip/LoginResult",
data: logindata,
success: function (data) {
if (data.Status) {
layer.msg("登录成功");
window.location = "/Vip/Index";
}
else {
layer.alert(data.StatusMessage);
}
}
});
}
可以看见注释//加密密码 //加密手机号 在此断点
看右边作用域发现还没进行加密,那么再往下走,将鼠标放在
encodeURI(encrypt.encrypt(numMobile)) 和encodeURI(encrypt.encrypt(numMobile))上面发现就是加密后的字符串
找到加密函数就在Login函数内,就去掉非加密的部分,扣代码
function Login() {
encrypt.setPublicKey(pkey);
var logindata = {};
//加密手机号
var numMobile = "19174007849";
var numPassword = "123456"
logindata.UserName = encodeURI(encrypt.encrypt(numMobile));
logindata.Mobile = encodeURI(encrypt.encrypt(numMobile));;
//加密密码
logindata.Password = encodeURI(encrypt.encrypt(numPassword));
console.log(logindata.Mobile)
}
放在线js执行看看
提示encrypy不存在,回到源代码找encrypy
找到var encrypt = new JSEncrypt();
ctrl+shift+f搜索function JSEncrypt找不到匹配项,证明它是js自带库
询问gpt然后确定是三方库后,获取到该库的url
<script src="https://cdn.jsdelivr.net/npm/jsencrypt/bin/jsencrypt.min.js"></script>
构造POC:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login Example</title>
<script src="https://cdn.jsdelivr.net/npm/jsencrypt/bin/jsencrypt.min.js"></script>
<script>
function Login() {
var encrypt = new JSEncrypt();
var pkey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIcxKPIWPDEg1V9kILfivIpldY"
+ "G3dZ0tdUKrqOAb3r0TXGK0RXwpdkHRIyUZv18y51g03xnYyMRz5LsEKqfHt4S7IT"
+ "gyYrk1MUSM38I46H9ifPvrsARbq1FLa/Mc67uStp6+0unnlzhmuCNpooFdv9JJYy"
+ "kVdRvyrIQeLSOoEgMQIDAQAB";
encrypt.setPublicKey(pkey);
var logindata = {};
var numMobile = "19174007849";
var numPassword = "123456";
logindata.UserName = encodeURI(encrypt.encrypt(numMobile));
logindata.Password = encodeURI(encrypt.encrypt(numPassword));
console.log(logindata.Mobile);
console.log(logindata.Password);
}
Login();
</script>
</head>
<body>
</body>
</html>
运行访问看看是否成功
成功,将三方库下载下来,这边建议搜索这个js名字,直接通过该网站下载,不然可能报错,我就是因为这一点浪费2h
使用jsEncrypter插件(安装方式网上查需要先安装好phantomjs),更改phantomjs_server.js文件内容
这里提供两个文件下载位置:
下载phantomjs并设置环境变量
https://phantomjs.org/download.html
Burp加载jsEncrypter插件
https://github.com/c0ny1/jsEncrypter/releases
更改名字导入下载好的三方js文件
var wasSuccessful = phantom.injectJs('jsencrypt.min.js');/*引入实现加密的js文件*/
var encrypt = new JSEncrypt();
var pkey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIcxKPIWPDEg1V9kILfivIpldY"
+ "G3dZ0tdUKrqOAb3r0TXGK0RXwpdkHRIyUZv18y51g03xnYyMRz5LsEKqfHt4S7IT"
+ "gyYrk1MUSM38I46H9ifPvrsARbq1FLa/Mc67uStp6+0unnlzhmuCNpooFdv9JJYy"
+ "kVdRvyrIQeLSOoEgMQIDAQAB";
encrypt.setPublicKey(pkey);
newpayload = encodeURI(encrypt.encrypt(payload));
将加密主要函数小改后放进去
命令phantomjs phantomjs_server.js启动,开启监听
在bp的jsEncrypter连接并test
左边是test的明文,右边是加密后的
在爆破模块中的payload处理处添加 通用Burp扩展,选择jsEncrypter
就可以了
某大学平台登陆点js逆向
交我算平台
这里调用的堆栈太多了,不好排查断点,费力耗时
那么就使用标签(DOM)断点或XHR断点,什么是标签断点,就是选中登录的元素代码,选择中断于子树修改和属性修改,意思就是如果登录框状态一旦变化就暂停调试
但是如下图,没看到什么有用的思路
那么就使用XHR断点
抓取到登录包的url特点是/user/login,在XHR断点处添加这个特性,一旦遇见该请求
提交数据包
断点成功,在作用域看见了username和password字段,找到入手点了
点击这个向上符号或者堆栈往上逆向
点到堆栈value的时候可以发现i变量就是我输入的用户名,a变量就是我输入的密码,s变量就是我输入的密码被加密后的样子
可以看见a是经过r.encrypt变成s的
var s = r.encrypt(a)
那么就寻找r.encrypt()
发现var r = new JSEncrypt,JSEncrypt是老朋友了,直接全局搜它
访问后先下载到本地
r.setPublicKey(o);
这里发现o的值是公钥,但是o不知道会不会变化,那么在输入其他用户名密码断点一次,提取两次的o值查看是否有变化
第一次:
305c300d06092a864886f70d0101010500034b003048024100959684a0076fd2a8fc1589469cf8c95f16ef67490c519f4d274373f29cee64cf6a0db8ad8953122c5b3664e4a48acd34d9b95c0ae62a31be612632e1c49154db0203010001
第二次:
305c300d06092a864886f70d0101010500034b003048024100959684a0076fd2a8fc1589469cf8c95f16ef67490c519f4d274373f29cee64cf6a0db8ad8953122c5b3664e4a48acd34d9b95c0ae62a31be612632e1c49154db0203010001
太好了,没有变化,那么就是说o是固定值
开始扣代码
浏览器访问该html,查看控制器
没有报错,那么再使用burp插件jsEncrypter联合爆破
修改phantomjs_server.js文件
运行插件并在burp上测试
成功
将password标记为变量
导入字典后,payload处理选择jsEncrypter插件
成功编码
反调试
实现防止他人调试、动态分析自己的代码
检测调试方法:
1、键盘监听(F12)
2、检测浏览器的高度插值
3、检测开发者人员工具变量是否为true
4、利用 console.log 调用次数-利用代码运行的时间差
5、利用 tostring
6、检测非浏览器
绕过反调试
条件断点
正在播放:【识骨寻踪第二季】part 4-- 咸鱼影视 智能解析 X4
该网站在播放视频的时候开启开发者模式就会暂停
在debug处添加断点并添加条件写入false
再刷新就ok了
此处暂停法
置空函数法
本地覆盖
例如如下网站:
PM2.5实时查询|PM2.5历史数据查询|PM2.5全国城市排名|PM2.5雾霾地图|中国空气质量在线监测分析平台|
右键 F12都被禁用
那么先开启开发者工具然后再访问该网址
成功打开调试器,但是程序依然暂停
全局搜索关键词:检测到非法调试
可以发现endebug函数就是检测函数
全局搜索使用endebug相关的代码
发现jquery.min.js?v=1.1和jquery.min.js?v=1.3两个js文件使用了endebug
那么在这两个文件右键,选择替代内容
找到endebug,将它所在的函数注释掉,并ctrl+s保存
然后再刷新,右键/F12都可以用了,也不会被反调试了
混淆加密
为了防止反调试功能被剔除,我们可以对JS代码进行混淆加密
开源代码混淆解密:
https://www.sojson.com
加密结果
执行没问题,去掉最后(‘sojson.v4’)试试
源码就出来了
aa加密
运行试试:
和上面思路一样,寻找最后一个括号删除内容
这里推荐插件Rainbow可以高亮
删除后源代码就出来了
商业代码混淆解密:
https://jsdec.js.org.
如下网站的这个js文件就是混淆加密后的代码
https://www.eisk.cn/Tides
拿出来放网站尝试解密
一个一个试就解出来了
可以发现是aes加密
模式:cbc;iv:3125674387384578;key:aaasfbbbbcccgasdeeeeffffgrwervxr
JS安全问题
配置泄露
未授权
更改返回包即可绕过前端验证
框架漏洞检测
工具推荐:
https://github.com/DenisPodgurskii/pentestkit