声明:本文只作学习研究,禁止用于非法用途,否则后果自负,如有侵权,请告知删除,谢谢!(手动狗头)
url: aHR0cHM6Ly93d3cuMDk5YzUwMC52aXAvbG9naW4=
1.抓包分析
多次抓包后发现咱请求头没啥加密,就负载这里搞个random和password加密,我们先试试random固定|不带random,看看能不能请求成功
1.1 不带random请求
1.2 带固定的random请求
发现请求的random根本不影响msg,不必管他,咱去搞pwd加密
2.分析加密参数位置
来到调用堆栈,一眼看出这login不同寻常,咱先来到第二个login这,看看参数有没有生成。
进来断点断住,发现还没加密,咱们看看o.b.Login()是不是动了手脚,执行一下看看
发现此时就已经开始加密了,咱跟进去这函数看看,到底是什么牛马干的,给pwd加密了
发现是这么个函数
var t = "dafacloud_" + Math.random()//首先t是一个字符串加上随机的数,不用管
, a = {
random: o.encode(t)//random跟咱想的一样,随机的给它固定就好,不用带都可以,不用管
}
, i = c(e.userName, e.password);//通过c函数对pwd和username进行处理(估计是进行了加密)
return localStorage.setItem("temporaryPass", i),//返回了i,储存在local Storage里
e.password = s()(i + t),//这里就是i 和一个随机字符串相加然后再加密了
e.random = a.random,
n.a.post(l, e)
}
为了追求细节,咱也搞个random过来(可能人家后端就专门比较random和pwd)话不多说,直接全部copy过来
折叠起来发现是webpack,同时最开头的(window.webpackJsonp = window.webpackJsonp || []).push可以简化成a()
我们来到a函数
function a(a) {
for (var f, b, r = a[0], n = a[1], o = a[2], u = 0, l = []; u < r.length; u++)
b = r[u],
d[b] && l.push(d[b][0]),
d[b] = 0;
for (f in n)
Object.prototype.hasOwnProperty.call(n, f) && (e[f] = n[f]);
for (i && i(a); l.length; )
l.shift()();
return t.push.apply(t, o || []),
c()
}
//可以看到调用了c函数
//咱省的事多,全copy下来
!function (e) {
function r(a) {
if (f[a])
return f[a].exports;
var c = f[a] = {
i: a,
l: !1,
exports: {}
};
return e[a].call(c.exports, c, c.exports, r),
c.l = !0,
c.exports
}
function a(a) {
for (var f, b, r = a[0], n = a[1], o = a[2], u = 0, l = []; u < r.length; u++)
b = r[u],
d[b] && l.push(d[b][0]),
d[b] = 0;
for (f in n)
Object.prototype.hasOwnProperty.call(n, f) && (e[f] = n[f]);
for (t.push(a); l.length;)
l.shift()();
return t.push.apply(t, o || []),
c()
}
window.xxx = a//给a放到全局变量中
function c() {
for (var e, a = 0; a < t.length; a++) {
for (var c = t[a], f = !0, b = 1; b < c.length; b++) {
var n = c[b];
0 !== d[n] && (f = !1)
}
f && (t.splice(a--, 1),
e = r(r.s = c[0]))
}
return e
}
var f = {}
, b = {
85: 0
}
, d = {
85: 0
}
, t = [];
}([]);
下面我们再重新来到加密函数的位置
//咱先 扣一层代码
JhLU: function (e, t, a) {
"use strict";
//关键在于怎么调用这个代码,得到Login
t.b = {
Login: function (e) {
var t = "dafacloud_" + Math.random()
, a = {
random: encode(t)
}
, i = c(e.userName, e.password);
window.yufan = [s()(i + t).toString(), a.random]//只有调用了才能赋值给window
},
}
window.dog = t.b;//再给t.b赋值到全局对象里
}
通过以上分析,咱需要先通过调用JhLU,拿到里面的函数,获得t.b,接着调用t.b里的Login,将我们要的结果变量,赋值到全局变量中,开整
3.扣代码&python模拟
打印发现JhLU里面的参数,前两个随便给个{},而最后一个则是要r函数,而定位到r函数中,正是和咱a函数处在一起,巧巧巧(七巧板)
!function (e) {
//这个函数正是第三个参数
function r(a) {
if (f[a])
return f[a].exports;
var c = f[a] = {
i: a,
l: !1,
exports: {}
};
return e[a].call(c.exports, c, c.exports, r),
c.l = !0,
c.exports
}
function a(a) {
//观察发现,传过来的a = [6], {}, [["Vtdi", 85, 0]],所以a[1]刚好包含咱要的参数,锁定n
for (var f, b, r = a[0], n = a[1], o = a[2], u = 0, l = []; u < r.length; u++)
b = r[u],
d[b] && l.push(d[b][0]),
d[b] = 0;
for (f in n)
Object.prototype.hasOwnProperty.call(n, f) && (e[f] = n[f]);
for (t.push(a); l.length;)
l.shift()();
n.JhLU({}, {}, r)//在a函数调用时,我们去执行n.JhLU,拿的window.dog(t.b)
return t.push.apply(t, o || []),
c()
}
window.xxx = a
function c() {
for (var e, a = 0; a < t.length; a++) {
for (var c = t[a], f = !0, b = 1; b < c.length; b++) {
var n = c[b];
0 !== d[n] && (f = !1)
}
f && (t.splice(a--, 1),
e = r(r.s = c[0]))
}
return e
}
var f = {}
, b = {
85: 0
}
, d = {
85: 0
}
, t = [];
}([]);
//通过调用window.xxx(a),乘机把咱的JhLU搞过去
window.xxx([6], {
//这里正是咱的JhLU,简化一下,只要核心的Login
JhLU: function (e, t, a) {
"use strict";
t.b = {
Login: function (e) {
var t = "dafacloud_" + Math.random()
, a = {
random: encode(t)
}
, i = c(e.userName, e.password);
window.yufan = [s()(i + t).toString(), a.random]
},
}
window.dog = t.b;
}
}, [["Vtdi", 85, 0]])
//最后咱对window.dog里的Login进行调用,传进去咱的账号和密码
window.dog.Login({
'password': "123456",
'userName': "123456"
}
)
console.log(window.yufan)//打印出结果
话不多说,开始运行
发现咱的o.encode没有,去网站上看看
发现就是encode函数,还是个三目运算符,很明显,我们的e是undefined。什么?不信,你看看
信了吧,直接简化成_encode(String(t)) , _encode又在哪呢,诶,您别急,往上看看
可不就在上面吗?那我全扣?太麻烦了,搞的代码又臭又长,鼠标悬浮在_encode,您才怎么找,直接定位
到这来很明显的btoa、atob,base64啊
var cb_utob = function (t) {
if (t.length < 2)
return (e = t.charCodeAt(0)) < 128 ? t : e < 2048 ? fromCharCode(192 | e >>> 6) + fromCharCode(128 | 63 & e) : fromCharCode(224 | e >>> 12 & 15) + fromCharCode(128 | e >>> 6 & 63) + fromCharCode(128 | 63 & e);
var e = 65536 + 1024 * (t.charCodeAt(0) - 55296) + (t.charCodeAt(1) - 56320);
return fromCharCode(240 | e >>> 18 & 7) + fromCharCode(128 | e >>> 12 & 63) + fromCharCode(128 | e >>> 6 & 63) + fromCharCode(128 | 63 & e)
}
, re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g
, utob = function (t) {
return t.replace(re_utob, cb_utob)
}
var encode = function (t, e) {
return btoa(utob(String(t)))
}
encode搞定,继续运行
发现c没有定义,去网站上看看
s()又是哪里来的呢?
发现是出来的乱七八糟的玩意,new t(!0).update,在网站是打印看看是啥
这又是啥?相信熟悉MD5的已经能够猜出来了,什么?猜不出来,没事,咱往前看看
哈哈,这是啥,看人家煞费苦心,生怕咱认不出来是Md5,那很好办了走起
//npm install crypto-js
var CryptoJS = require('crypto-js')
var s = function (){
return function(n) {
return CryptoJS.MD5(n)
}
}
function c(e, t) {
return s()(e.toLowerCase() + s()(t))
}
好,咱都分析完了,去第四步
4.代码整合
window = this
window = {};
var CryptoJS = require('crypto-js')
!function (e) {
function r(a) {
if (f[a])
return f[a].exports;
var c = f[a] = {
i: a,
l: !1,
exports: {}
};
return e[a].call(c.exports, c, c.exports, r),
c.l = !0,
c.exports
}
function a(a) {
for (var f, b, r = a[0], n = a[1], o = a[2], u = 0, l = []; u < r.length; u++)
b = r[u],
d[b] && l.push(d[b][0]),
d[b] = 0;
for (f in n)
Object.prototype.hasOwnProperty.call(n, f) && (e[f] = n[f]);
for (t.push(a); l.length;)
l.shift()();
n.JhLU({}, {}, r)
return t.push.apply(t, o || []),
c()
}
window.xxx = a
function c() {
for (var e, a = 0; a < t.length; a++) {
for (var c = t[a], f = !0, b = 1; b < c.length; b++) {
var n = c[b];
0 !== d[n] && (f = !1)
}
f && (t.splice(a--, 1),
e = r(r.s = c[0]))
}
return e
}
var f = {}
, b = {
85: 0
}
, d = {
85: 0
}
, t = [];
}([]);
//通过调用window.xxx(a),乘机把咱的JhLU搞过去
window.xxx([[6], {
JhLU: function (e, t, a) {
"use strict";
//JS_md5
var s = function (){
return function(n) {
return CryptoJS.MD5(n)
}
}
function c(e, t) {
return s()(e.toLowerCase() + s()(t))
}
var cb_utob = function (t) {
if (t.length < 2)
return (e = t.charCodeAt(0)) < 128 ? t : e < 2048 ? fromCharCode(192 | e >>> 6) + fromCharCode(128 | 63 & e) : fromCharCode(224 | e >>> 12 & 15) + fromCharCode(128 | e >>> 6 & 63) + fromCharCode(128 | 63 & e);
var e = 65536 + 1024 * (t.charCodeAt(0) - 55296) + (t.charCodeAt(1) - 56320);
return fromCharCode(240 | e >>> 18 & 7) + fromCharCode(128 | e >>> 12 & 63) + fromCharCode(128 | e >>> 6 & 63) + fromCharCode(128 | 63 & e)
}
, re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g
, utob = function (t) {
return t.replace(re_utob, cb_utob)
}
var encode = function (t, e) {
return btoa(utob(String(t)))
}
t.b = {
Login: function (e) {
var t = "dafacloud_" + Math.random()
, a = {
random: encode(t)
}
, i = c(e.userName, e.password);
window.yufan = [s()(i + t).toString(), a.random]
}
}
window.dog = t.b;
},
}, [["Vtdi", 85, 0]]]);
window.dog.Login({
'password': "123456",
'userName': "123456"
}
)
console.log(window.yufan)
运行结果
出来了,咱们成热打铁,换到python中去试试
# -*- coding: utf-8 -*-
'''
@IDE : PyCharm
@version : 3.9
@Auth : gouzi
@time : 2023/9/30 12:17
@Description:
'''
import requests
import execjs
headers = {
'authority': 'www.099c500.vip',
'accept': 'application/json, text/plain, */*',
'accept-language': 'zh-CN,zh;q=0.9',
'cache-control': 'no-cache',
'content-type': 'application/x-www-form-urlencoded;charset=UTF-8',
'cookie': '_uab_collina=168994263384070692985472',
'origin': 'https://www.099c500.vip',
'pragma': 'no-cache',
'publish-version': '2023/07/14_10:52:50 pc-v1.187.0',
'referer': 'https://www.099c500.vip/login',
'sec-ch-ua': '"Not/A)Brand";v="99", "Google Chrome";v="115", "Chromium";v="115"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-origin',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36',
'x-token': '',
}
with open('login.js',encoding='utf-8') as f:
js_code = f.read()
code = execjs.compile(js_code)
data_ = code.call('get_data','123456','123456')
print(data_)
data = {
'userName': '123456',
'password': data_[0],
'random': data_[1]
}
response = requests.post('https://www.099c500.vip/v1/users/login', headers=headers, data=data)
print(response.json())
运行成功
5.总结:
这东西嵌套真™多,想要调用这复杂,同时它本身的md5方法也看不懂,不晓得咋扣,就只能自己搞md5进行加密了,总体来说
难度:适中(对我这种萌新小白来说,大佬肯定轻而易举的~~,好吧,大佬也不会看我这文章)
学会了如何去找到调用的对象,又熟悉了js呢