【JS 逆向百例】如何跟栈调试?某 e 网通 AES 加密分析
关注微信公众号:K哥爬虫,QQ交流群:808574309,持续分享爬虫进阶、JS/安卓逆向等技术干货!
声明
本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除!
逆向目标
- 目标:某 e 网通登录接口
- 主页:aHR0cHM6Ly93ZWIuZXd0MzYwLmNvbS9yZWdpc3Rlci8jL2xvZ2lu
- 接口:aHR0cHM6Ly9nYXRld2F5LmV3dDM2MC5jb20vYXBpL2F1dGhjZW50ZXIvdjIvb2F1dGgvbG9naW4vYWNjb3VudA==
- 逆向参数:
- Request Headers:
sign: 3976F10977FC65F9CB967AEF79E508BD
- Request Payload:
password: "A7428361DEF118911783F446A129FFCE"
- Request Headers:
逆向过程
抓包分析
来到某 e 网通的登录页面,随便输入一个账号密码登陆,抓包定位到登录接口为 aHR0cHM6Ly9nYXRld2F5LmV3dDM2MC5jb20vYXBpL2F1dGhjZW50ZXIvdjIvb2F1dGgvbG9naW4vYWNjb3VudA==,请求头里,有一个 sign,Payload 里,密码 password 被加密处理了。
参数逆向
sign
首先来看一下请求头的 sign,尝试直接搜索一下,发现并不是经过某些请求返回的数据,观察一下其他请求,可以发现同样有 sign,而且每次请求的值都不一样:
由此可以初步判断这个值应该是通过 JS 生成的,全局搜索关键字 sign:
,可以分别在 request.js、request.ts 两个文件里面看到疑似 sign 赋值的地方,埋下断点调试,成功断下,原理也很简单,时间戳加上一串固定的字符,经过 MD5 加密后再转大写即可。
使用 Python 实现:
import time
import hashlib
timestamp = str(int(time.time() * 1000))
sign = hashlib.md5((timestamp + 'bdc739ff2dcf').encode(encoding='utf-8')).hexdigest().upper()
print(sign)
password
password 是明文密码经过加密后得到的值,如果尝试直接去搜索的话,会发现出来的值非常非常多,要想找到准确的值难度巨大:
可以看到这条请求是 XHR 请求,本次我们使用 XHR 断点的方法来定位具体的加密位置,通过本次案例,我们来学习一下具体是如何跟进调用栈、如何通过上下文来定位具体的加密位置。
切换到 Network 选项卡,找到登陆请求,鼠标移动到 Initiator 选项卡下的 JS 上,可以看到其调用栈,如果站点的加密方式比较简单,没有太多混淆的话,调用栈里面就可以看到 login、send、post、encrypt 等等之类的关键词,这种情况下就可以直接点进去,比较容易找到加密的地方,但是大多数站点对于函数名、变量名都做了混淆,和本案例一样,调用栈里面显示的都是一些单个或者多个无规则的字母的函数,无法直接定位,此时就需要我们从最后一个函数往前慢慢找。
点击进入最后一个函数,即 Y 函数,它位于调用栈的最顶层,表示经过此函数后,浏览器就会发送登录的请求,密码的加密过程已经处理完毕。在此函数埋下断点,可以在右侧的 Call Stack 看到调用栈,从下到上,表示的是点击登陆后,先后调用的函数的执行过程:
想要找到具体的加密位置,我们就要依次往前找,挨个函数进行分析,例如往前定位到倒数第二个调用栈,即 o 函数,可以看到传进来的 params 参数里面就包含了已加密的密码信息,这说明加密操作肯定在此函数之前:
根据这种思路,一步一步往下跟进调用栈,可以看到在 utils.ts 里面执行了一个匿名函数,其中调用了一个 passwordEncrypt 函数,通过函数名就可以看出基本上就是密码加密的函数了:
在此处埋下断点进行调试,传进来的是明文密码,passwordEncrypt 实际上是调用的 encode.ts 中的 O 函数:
跟进 O 函数,引用了 crypto-js 加密模块,很明显的 AES 加密,本地改写一下就行了。
本次的案列加密比较简单,但是加密函数隐藏得比较好,需要耐心跟进调用栈,通过直接搜索的话,结果太多,是不太容易定位加密函数的,本次案例中跟进到一个函数后,可以很清楚的看到加密的地方,那么有的站点可能混淆得更加厉害,是看不出来有加密函数的,这种情况下就需要我们注意参数的变化情况,如果在这个调用栈看到的是加密后的参数,在上一个调用栈里面看到的是明文的参数,那么加密的操作必定在这两个调用栈之间,埋下断点,仔细分析即可。
完整代码
GitHub 关注 K 哥爬虫,持续分享爬虫相关代码!欢迎 star !https://github.com/kgepachong/
以下只演示部分关键代码,不能直接运行!完整代码仓库地址:https://github.com/kgepachong/crawler/
JavaScript 加密代码
CryptoJS = require("crypto-js")
const key = CryptoJS.enc.Utf8.parse("20171109124536982017110912453698");
const iv = CryptoJS.enc.Utf8.parse('2017110912453698'); //十六位十六进制数作为密钥偏移量
function getEncryptedPassword(word) {
let srcs = CryptoJS.enc.Utf8.parse(word);
let encrypted = CryptoJS.AES.encrypt(srcs, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.ciphertext.toString().toUpperCase();
}
// 测试样例
// console.log(getEncryptedPassword("123457"))
Python 登录代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import time
import hashlib
import execjs
import requests
login_url = '脱敏处理,完整代码关注 GitHub:https://github.com/kgepachong/crawler'
session = requests.session()
def get_sign():
timestamp = str(int(time.time()*1000))
sign = hashlib.md5((timestamp + 'bdc739ff2dcf').encode(encoding='utf-8')).hexdigest().upper()
return sign
def get_encrypted_parameter(password):
with open('ewt360_encrypt.js', 'r', encoding='utf-8') as f:
ewt360_js = f.read()
encrypted_password = execjs.compile(ewt360_js).call('getEncryptedPassword', password)
return encrypted_password
def login(sign, username, encrypted_password):
headers = {
'sign': sign,
'timestamp': str(int(time.time()*1000)),
'sec-ch-ua': '" Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}
data = {
'autoLogin': True,
'password': encrypted_password,
'platform': 1,
'userName': username
}
response = session.post(url=login_url, headers=headers, json=data)
print(response.json())
def main():
username = input('请输入登录账号: ')
password = input('请输入登录密码: ')
sign = get_sign()
encrypted_password = get_encrypted_parameter(password)
login(sign, username, encrypted_password)
if __name__ == '__main__':
main()
【JS 逆向百例】如何跟栈调试?某 e 网通 AES 加密分析的更多相关文章
- 通过JS逆向ProtoBuf 反反爬思路分享
前言 本文意在记录,在爬虫过程中,我首次遇到Protobuf时的一系列问题和解决问题的思路. 文章编写遵循当时工作的思路,优点:非常详细,缺点:文字冗长,描述不准确 protobuf用在前后端传输,在 ...
- JS逆向之补环境过瑞数详解
JS逆向之补环境过瑞数详解 "瑞数" 是逆向路上的一座大山,是许多JS逆向者绕不开的一堵围墙,也是跳槽简历上的一个亮点,我们必须得在下次跳槽前攻克它!! 好在现在网上有很多讲解瑞数 ...
- 网络爬虫之记一次js逆向解密经历
1 引言 数月前写过某网站(请原谅我的掩耳盗铃)的爬虫,这两天需要重新采集一次,用的是scrapy-redis框架,本以为二次爬取可以轻松完成的,可没想到爬虫启动没几秒,出现了大堆的重试提示,心里顿时 ...
- 这个爬虫JS逆向加密任务,你还不来试试?逆向入门级,适合一定爬虫基础的人
友情提示:在博客园更新比较慢,有兴趣的关注知识图谱与大数据公众号吧.这次选择苏宁易购登录密码加密,如能调试出来代表你具备了一定的JS逆向能力,初学者建议跟着内容调试一波,尽量独自将JS代码抠出来,实在 ...
- 爬虫必看,每日JS逆向之爱奇艺密码加密,今天你练了吗?
友情提示:优先在公众号更新,在博客园更新较慢,有兴趣的关注一下知识图谱与大数据公众号,本次目标是抠出爱奇艺passwd加密JS代码,如果你看到了这一篇,说明你对JS逆向感兴趣,如果是初学者,那不妨再看 ...
- JS逆向之浏览器补环境详解
JS逆向之浏览器补环境详解 "补浏览器环境"是JS逆向者升职加薪的必备技能,也是工作中不可避免的操作. 为了让大家彻底搞懂 "补浏览器环境"的缘由及原理,本文将 ...
- 兄弟,你爬虫基础这么好,需要研究js逆向了,一起吧(有完整JS代码)
这几天的确有空了,看更新多快,专门研究了一下几个网站登录中密码加密方法,比起滑块验证码来说都相对简单,适合新手js逆向入门,大家可以自己试一下,试不出来了再参考我的js代码.篇幅有限,完整的js代码在 ...
- 兄弟,别再爬妹子图了整点JS逆向吧--陆金所密码加密破解
好久没有写爬虫文章了,今晚上得空看了一下陆金所登录密码加密,这个网站js加密代码不难,适合练手,篇幅有限,完整js代码我放在了这里从今天开始种树,不废话,直接开整. 前戏热身 打开陆金所网站,点击到登 ...
- JS逆向-抠代码的第一天【手把手学会抠代码】
首先声明,本人经过无数次摸爬滚打及翻阅各类资料,理论知识极其丰富,但是抠代码怎么都抠不会. 无奈之下,只能承认:这个活,需要熟练度. 本文仅对部分参数进行解析,有需要调用,请自行根据现实情况调整. 第 ...
- 我去!爬虫遇到JS逆向AES加密反爬,哭了
今天准备爬取网页时,遇到『JS逆向AES加密』反爬.比如这样的: 在发送请求获取数据时,需要用到参数params和encSecKey,但是这两个参数经过JS逆向AES加密而来. 既然遇到了这个情况,那 ...
随机推荐
- ServiceWorker工作机制与生命周期:资源缓存与协作通信处理
在 <web messaging与Woker分类:漫谈postMessage跨线程跨页面通信>介绍过ServiceWorker,这里摘抄跟多的内容,补全 Service Worker 理解 ...
- 开心档之CSS 测验
目录 CSS 测验 编辑 CSS 测验 CSS测验是一种衡量前端开发人员对CSS的熟练程度的测试.通过CSS测验,可以评估一个人对CSS语言的掌握程度和应用能力,帮助公司或招聘方挑选合适的人才. ...
- Exception in thread "main" java.lang.UnsatisfiedLinkError: xxx()V
Exception in thread "main" java.lang.UnsatisfiedLinkError: com.vipsoft.demo.JNIDemo.testHe ...
- Linux day4:查看文件属性信息 inode和block 硬链接和软链接 inux系统时间 虚拟机克隆 linux定时任务 paramiko模块 公钥私钥
目录 文件属性信息 存储数据相关 inode block 访问文件原理 链接信息 硬链接 软链接 linux系统时间 虚拟机克隆 链接克隆和完整克隆 克隆之后的配置 linux定时任务 定时任务软件 ...
- 记录一次Java内存泄露分析过程
版权说明: 本文章版权归本人及博客园共同所有,转载请在文章前标明原文出处( https://www.cnblogs.com/mikevictor07/p/13032635.html ),以下内容为个人 ...
- k8s-部署 Kubernetes 集群(kubeadm方式)
一 机器准备 IP 主机名 角色 配置 安装组件 192.168.198.150 master-1 master 2U2G master组件 etcd kubectl 192.168.198.151 ...
- C223 生产版本BAPI
1.事务代码:C223 2.调用函数CM_FV_PROD_VERS_DB_UPDATE "-----------------------------@斌将军----------------- ...
- 通过部署流行 Web 框架掌握 Serverless 技术
大家好,我是霍大侠,本篇我们通过学习部署流行 Web 框架,如 Spring Boot,Express,Web IDE,让你掌握 Serverless 函数计算架构和技术,领略弹性并发.高可用的好处. ...
- docker 镜像管理之 overlay2 最佳实践
1. Docker 镜像 Docker 镜像是个只读的容器模板,它组成了 Docker 容器的静态文件系统运行环境 rootfs,是启动 Docker 容器的基础. Docker 镜像是容器的静态视角 ...
- 13个构建RESTful API的最佳实践
前言 Facebook.GitHub.Google和其他许多巨头都需要一种方法来服务和消费数据.在今天的开发环境中,RESTful API仍然是服务和消费数据的最佳选择之一. 但你是否考虑过学习行业标 ...