【JS 逆向学习】【笔记】01-HN某政务login协议

声明

本文章内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除!

工具&环境

pycharm:开放工具 2019.2
chrome:浏览器
python:3.7.4
node:v12.14.1

逆向目标

#index 主页-获取session:aHR0cHM6Ly9sb2dpbi5obnp3ZncuZ292LmNuL3RhY3MtdWMvbG9naW4vaW5kZXg=

#login 登陆接口 :aHR0cHM6Ly9sb2dpbi5obnp3ZncuZ292LmNuL3RhY3MtdWMvbmF0dXJhbE1hbi9sb2dpbk5v

#csrfSave 辅助接口-或其MD5码 :aHR0cHM6Ly9sb2dpbi5obnp3ZncuZ292LmNuL3RhY3MtdWMvbmF0dXJhbE1hbi9jc3JmU2F2ZQ==

#uploadIdentifier 辅助接口-获取uuid :aHR0cHM6Ly9sb2dpbi5obnp3ZncuZ292LmNuL3RhY3MtdWMvbmF0dXJhbE1hbi91cGxvYWRJZGVudGlmaWVy

# verCode 辅助接口-获取校验码(滑块):aHR0cHM6Ly9sb2dpbi5obnp3ZncuZ292LmNuL3RhY3MtdWMvbG9naW4vdmVyQ29kZQ==

逆向参数:
Form data : loginNo、loginPwd、code、requestUUID
request headers: token

登陆涉及的form data
ajax统一设置的headers-token

操作完整流程

1:chrome访问主页


#主页:aHR0cHM6Ly9sb2dpbi5obnp3ZncuZ292LmNuL3RhY3MtdWMvbG9naW4vaW5kZXg=
主页登陆界面

chrome打开无痕窗口,按F12,输入主页地址回车。观察网络请求

image.png
2:输入密码后,滑动滑块:

触发请求verCode

第6步:过滑块触发verCode接口
SESSION=ZDFjMDY4ZmMtZGYyNy00MDRmLWI5ZjEtNjE4NDcyZTRhYTMx
3:输入密码,并登陆
第7步:loginNo登陆  --header需要token
SESSION=ZDFjMDY4ZmMtZGYyNy00MDRmLWI5ZjEtNjE4NDcyZTRhYTMx

payload --form data

backUrl: 
loginNo: 
IIAesumzZ+GIKAYY5YJF32PBLMlLl+j2kUW5R7q/2WJGFUB8jziuwDFTeSpIdfIsrr/wbP9i2C2wNY9v386Ykkf2mNG9DGWBn9vA/TYl4lXrklgI+A7rvHzk9rh3bJ5ZKcBLC4RCE7eHfWxDUGdFgwdOCEcqFgbcErr02+RsIQaBdli9cV85JYTSpoR44nBTqOro5hX+bkQCpit20BbXeHwQeo4MAMzlpWarYPOGNuKusttWqNqzdhkM/Gl4AcKKzykGNsTR1P6wwL4Ba+ajmLUDsLrprtw9BA4k/22EEVQKHKsvA6+yRuCAbm8INjfp7yh5P8Lres4qv34Kj/bsFw==
loginPwd: 
SKZuAq/nxYRAekdeUApamQCNdqKaeHh6KSje7zSGRjScoe2o8giKKqP7wNMcAEIF2y8xGxp7Jfq/jkK5xoOBkjyP+ov0r80guTAEGbe1JCughEBeHr/SJql2ZA8OZtNCyza66kv6SvyPkOu2HcfpAkpwzNMl8QQzoBo+68tnoPE4YriJaYaGt0RJe2Fdp+DJL3pK3K3Tg3q6O2Cpp6kM3tMfXGS3MJahoNa3JzGF2egVM8pytZDBjk7HFGoiXFbh72FZIhORW19Zu+9TWTHkm1d6ukvIY9rlHtHU6UFhjYjNOKn3i35XkIf8y0SSQlAdFcKl3yUEasAYDsXE9ZD9eg==
code: 
11604ae4-21dc-4109-943f-adc25209c9e9
requestUUID: 
19b9951f-786c-4d68-ab1c-7ba65b457589
guoBanAuthCode:

分析步骤

先描述分析大概步骤, 并再后面说明如何分析
1:进入页面--获取session,
2:自动调用uploadIdentifier,返回data.data是 requestUUID
3:并过滑块拦截到的https请求verCode,返回data.data是验证码
4:登陆触发loginNO,返回登陆是否成功的信息

拦截到的请求、form data数据

搜索"requestUUID" 在登陆方法personLoginSubmit中可以看到如下代码

$.ajax({
            url: uri + "/naturalMan/loginNo",
            xhrFields: {withCredentials: true},
            dataType: "json",
            type: "post",
            crossDomain: true == !(document.all),
            data: {
                "backUrl": localStorage.getItem("backUrl"),// 可为null
                "loginNo": encrypt(personName), //手机号
                "loginPwd": encrypt(apsswordTestCorrect),//密码
                "code": loginCode, //verCode接口返回data.data
                "requestUUID": UUID,//uploadIdentifier接口返回data.data
                "guoBanAuthCode": guoBanAuthCode //可为null
            },
            success: function (data) {
                var result = data.code;
                var msg = data.msg;
                if (result != successCode) {
                    $('#verCode').click();
                    $("#loginError").html(errorImgLabel + msg);
                    $("#loginbtn").attr("disabled", false);
                    $("#loginbtn").css("background", "#567fe6");
                } else {
                    。。。

                }
            }
        });
抠出encrypt.js代码

点击encrypt 函数在encrypt.js进入查看

//add by wangp at 2018-01-23 密码加密方法 start
function encrypt(pwd){
    var key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsgDq4OqxuEisnk2F0EJFmw4xKa5IrcqEYHvqxPs2CHEg2kolhfWA2SjNuGAHxyDDE5MLtOvzuXjBx/5YJtc9zj2xR/0moesS+Vi/xtG1tkVaTCba+TV+Y5C61iyr3FGqr+KOD4/XECu0Xky1W9ZmmaFADmZi7+6gO9wjgVpU9aLcBcw/loHOeJrCqjp7pA98hRJRY+MML8MK15mnC4ebooOva+mJlstW6t/1lghR8WNV8cocxgcHHuXBxgns2MlACQbSdJ8c6Z3RQeRZBzyjfey6JCCfbEKouVrWIUuPphBL3OANfgp0B+QG31bapvePTfXU48TYK0M5kE+8LgbbWQIDAQAB";
    var encrypt = new JSEncrypt();
    encrypt.setPublicKey(key);
    var encrypted = encrypt.encrypt(pwd);
    return encrypted;
}
//add by wangp at 2018-01-23 密码加密方法 end

里面使用到JSEncrypt对象进行RSA加密,代码在jsencrypt.min.js中,点击进去,并格式化代码,copy出来保存为jsencrypt.min.js(也可以直接下载该文件)


image.png

格式前的代码,我们看不是很清楚


格式化代码

按“{}”格式化后,后其实JSEncrypt 就是 var ze = function(t)


image.png

新打开一个chrome无痕窗口,在chrome中新建snippet,并把jsencrypt.min.js+encrypt.js; (主页如果要在python+nodejs环境中运行,需要做些更改,后面会进一步描述。主页原因是浏览器环境会自动补全部分功能)

右键运行该代码片段

snippet代码快运行结果
loginCode是如何生成的
var loginCode = $("#verCode").val();

搜索 loginCode


搜索 loginCode

搜索 $("#verCode")


搜索verCode

UUID是如何生成的

UUID定义再login.js中,是uploadIdentifier接口返回的data.data

var UUID = "";

搜索UUID赋值


搜索UUID

最终代码

hnzwfw_encrypt.js
//add by czg at 2022-05-11 start  for run in pythin

global.navigator={
userAgent: 'node.js',
};
var window = global;

var JSEncrypt ;

//add by czg at 2022-05-11 end  for run in pythin

.....
jsencrypt.min.js部分代码
.....
//add by czg at 2022-05-11 start
function encrypt(pwd){
    var key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsgDq4OqxuEisnk2F0EJFmw4xKa5IrcqEYHvqxPs2CHEg2kolhfWA2SjNuGAHxyDDE5MLtOvzuXjBx/5YJtc9zj2xR/0moesS+Vi/xtG1tkVaTCba+TV+Y5C61iyr3FGqr+KOD4/XECu0Xky1W9ZmmaFADmZi7+6gO9wjgVpU9aLcBcw/loHOeJrCqjp7pA98hRJRY+MML8MK15mnC4ebooOva+mJlstW6t/1lghR8WNV8cocxgcHHuXBxgns2MlACQbSdJ8c6Z3RQeRZBzyjfey6JCCfbEKouVrWIUuPphBL3OANfgp0B+QG31bapvePTfXU48TYK0M5kE+8LgbbWQIDAQAB";
    var encrypt = new JSEncrypt();  
    encrypt.setPublicKey(key);
    var encrypted = encrypt.encrypt(pwd);
    return encrypted;
}
//add by czg at 2022-05-11  end


定义全局变量

image.png

需要copy进来的jsencrypt.min.js,部分添加对全局变量的赋值 JSEncrypt = ze

对全局变量JSEncrypt赋值
hnzwfw_login.py
import execjs  #需要下载库 pip install pyExecJs
import requests  #pip install requests
# 特别注意如果pc开始代理会报错误 ProxyError(e, request=request)
#   UnicodeEncodeError: ‘gbk‘ codec can‘ https://www.10qianwan.com/articledetail/733782.html
# 原因 :场景为在 Windows 电脑下使用 Python execjs 运行指定的 JS 文件,但 JS 文件中包含中文 python 运行 execjs 出现错误
# 修改subprocess.py
# execjs._exceptions.ProgramError: ReferenceError: navigator is not defined  https://blog.csdn.net/qq_36853469/article/details/105075131
# 这是因为execjs除了nodejs,还需要浏览器环境,浏览器上还需要document以及window对象,所以我们要还要安装环境

# execjs._exceptions.ProgramError: ReferenceError: window is not defined
cookies = {}
UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"

with open("hnzwfw_encrypt.js", encoding="utf-8") as f:
    js = execjs.compile(f.read())


def csrf_save():
    url = "加密后:aHR0cHM6Ly9sb2dpbi5obnp3ZncuZ292LmNuL3RhY3MtdWMvbmF0dXJhbE1hbi9jc3JmU2F2ZQ=="
    headers = {"User-Agent": UA}
    response = requests.post(url=url, headers=headers, cookies=cookies).json()
    data = response["data"]
    return data

# 获取session
def get_session():
    url = "加密后:aHR0cHM6Ly9sb2dpbi5obnp3ZncuZ292LmNuL3RhY3MtdWMvbG9naW4vaW5kZXg="
    headers = {"User-Agent": UA}
    response = requests.get(url=url, headers=headers)
    cookies.update(response.cookies.get_dict())




def get_uuid():
    url = "加密后:aHR0cHM6Ly9sb2dpbi5obnp3ZncuZ292LmNuL3RhY3MtdWMvbmF0dXJhbE1hbi91cGxvYWRJZGVudGlmaWVy"
    headers = {
        "User-Agent": UA,
        "token": js.call("encrypt", csrf_save()),

    }
    response = requests.post(url=url, headers=headers, cookies=cookies).json()
    uuid = response["data"]
    return uuid


def ver_code():
    url = "加密后:aHR0cHM6Ly9sb2dpbi5obnp3ZncuZ292LmNuL3RhY3MtdWMvbG9naW4vdmVyQ29kZQ=="
    headers = {
        "User-Agent": UA,
        "token": js.call("encrypt", csrf_save())
    }
    response = requests.post(url=url, headers=headers, cookies=cookies).json()
    data = response["data"]
    return data


def login(phone, pwd, code, uuid):
    url = "加密后:aHR0cHM6Ly9sb2dpbi5obnp3ZncuZ292LmNuL3RhY3MtdWMvbmF0dXJhbE1hbi9sb2dpbk5v"
    headers = {
        "User-Agent": UA,
        "token": js.call("encrypt", csrf_save())
    }
    data = {
        "backUrl": "",
        "loginNo": js.call("encrypt", phone),
        "loginPwd": js.call("encrypt", pwd),
        "code": code,
        "requestUUID": uuid,
        "guoBanAuthCode": ""
    }
    response = requests.post(url=url, headers=headers, cookies=cookies, data=data)
    print(response.json())


def main():
    phone = input("请输入账号:")
    pwd = input("请输入密码:")
    get_session()
    uuid = get_uuid()  #setHeader内部调用一次csrf_save
    print("uploadIdentifier 接口获得uuid =" ,uuid)
    code = ver_code() #setHeader内部调用一次csrf_save

    print("ver_code 接口获得code =" ,code)

    login(phone, pwd, code, uuid)

if __name__ == '__main__':
    main()

PyCharm中运行测试

image.png

附-在pyCharm下执行碰到的问题、及解决办法

1:错误 ProxyError(e, request=request)
这是pc使用代理造成的,关闭代理即可。
2:execjs._exceptions.ProgramError: ReferenceError: navigator is not defined

execjs._exceptions.ProgramError: ReferenceError: window is not defined

//add by czg at 2022-05-11 start  for run in pythin

global.navigator={
userAgent: 'node.js',
};
var window = global;

var JSEncrypt ;

//add by czg at 2022-05-11 end  for run in pythin

3:UnicodeEncodeError: ‘gbk‘ codec can
Python 安装目录下 lib 文件夹里面的一个文件,名字叫做 subprocess.py,修改 encoding=None 为 encoding = "utf-8" 。


知识点

自执行函数
$.ajax()方法详解

你可能感兴趣的:(【JS 逆向学习】【笔记】01-HN某政务login协议)