关于python:JS-逆向百例HN某服务网登录逆向验证码形同虚设

2次阅读

共计 4558 个字符,预计需要花费 12 分钟才能阅读完成。

申明

本文章中所有内容仅供学习交换,抓包内容、敏感网址、数据接口均已做脱敏解决,严禁用于商业用途和非法用处,否则由此产生的所有结果均与作者无关,若有侵权,请分割我立刻删除!

逆向指标

  • 指标:某政务服务网登录接口
  • 主页:aHR0cHM6Ly9sb2dpbi5obnp3ZncuZ292LmNuL3RhY3MtdWMvbG9naW4vaW5kZXg=
  • 接口:aHR0cHM6Ly9sb2dpbi5obnp3ZncuZ292LmNuL3RhY3MtdWMvbmF0dXJhbE1hbi9sb2dpbk5v
  • 逆向参数:

    Form Data:loginNo、loginPwd、code、requestUUID

    Request Headers:token

抓包剖析

本次逆向指标来源于某位粉丝的求助:

轻易输出账号密码点击登陆,抓包发现接口的 Request Headers 有个加密参数 token,Form Data 里 loginNo、loginPwd、code、requestUUID 都是通过加密解决了的,loginNo 和 loginPwd 应该就是用户名明码了,因为登录前须要过一下滑动验证码,因而能够猜想另外两个参数与验证码无关,不过仅从抓包来看,另外两个参数相似于 uuid 的格局,不太像验证码的参数。

另外能够留神到登陆前,有两次 csrfSave 和一次 verCode 的申请,失常申请胜利就会返回一个 JSON,外面有个 data 参数,前面应该是会用到的。

参数逆向

Form Data

先看 Form Data,搜寻任意一个参数,比方 loginNo,很容易在 login.js 里找到加密的中央,用户名和明码都通过了 encrypt 这个函数进行加密,backUrl 这个值,是利用 localStorage 属性,从浏览器贮存的键值对的数据里取的,为空也不影响。

跟进 encrypt,能够看到用到了 JSEncrypt,规范的 RSA 加密:

再看看 loginCode,间接搜寻这个值,能够看到是 verCode 这个申请返回的:

而后再看看 requestUUID,其值就是个 UUID,间接在以后文件(login.js)里搜寻,能够看到定义的中央,有个 uploadUUID() 办法,就是在设置 UUID 的值,办法外面是向一个 uploadIdentifier 的接口发送了 post 申请:

这里留神,如果你间接全局搜寻 UUID 的话,还能够在 common.js 里搜寻到一个办法,通过测试,间接应用这个办法生成一个 uuid 也是能够申请通过的,这网站可能不谨严,不会严格检测这个值。

Request Headers

Form Data 解决了,再来看看 Request Headers 里的 token 参数,因为它存在于申请头里,所以咱们能够通过 Hook 的形式来查找其生成的中央:

(function () {
    var org = window.XMLHttpRequest.prototype.setRequestHeader;
    window.XMLHttpRequest.prototype.setRequestHeader = function (key, value) {if (key == 'token') {debugger;}
        return org.apply(this, arguments);
    };
})();

这里咱们也能够间接搜寻 token、setRequestHeader 之类的关键字,很容易在 common.js 里找到,当咱们点击登陆,会有一个 csrfSave 的申请,返回的 data 值,通过 encrypt 办法加密后就是登陆申请头的 token 了。

这个 token 参数在很多申请中都会用到,生成办法是一样的,都是拿 csrfSave 申请返回的 data 通过 RSA 加密后失去的:

另外留神一点的就是,以上所有波及到网络申请的,Cookie 都须要一个 SESSION 值,这个能够在首次拜访页面获取到:

登陆流程

这里咱们理一下登陆的流程:

  1. 拜访首页拿 Cookie 中的 SESSION 值;
  2. 拜访 csrfSave,拿到一个 data 值,通过 RSA 加密失去 token,携带 token 拜访 uploadIdentifier,拿到 uuid;
  3. 拜访 csrfSave,拿到一个 data 值,通过 RSA 加密失去 token,携带 token 拜访 verCode,拿到 code;
  4. 拜访 csrfSave,拿到一个 data 值,通过 RSA 加密失去 token,携带 token、uuid、code 和加密后的账号密码,拜访 loginNo 登录。

这里第 2 步,也能够间接用 Python 或者 JS 生成一个 uuid,网站校验不严格,也能够通过,另外能够看出这个滑块是假的,通过代码能够忽视滑块进行登录。

残缺代码

GitHub 关注 K 哥爬虫,继续分享爬虫相干代码!欢送 star!https://github.com/kgepachong/

以下只演示局部要害代码,不能间接运行! 残缺代码仓库地址:https://github.com/kgepachong…

JavaScript 加密代码

/* ==================================
# @Time    : 2022-01-11
# @Author  : 微信公众号:K 哥爬虫
# @FileName: encrypt.js
# @Software: PyCharm
# ================================== */

JSEncrypt = require("jsencrypt")

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;
}

// 测试样例
// console.log(encrypt("15555555555"))

Python 登录代码

# ==================================
# @Time    : 2022-01-11
# @Author  : 微信公众号:K 哥爬虫
# @FileName: hnzww_login.py
# @Software: PyCharm
# ==================================


import execjs
import requests


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("encrypt.js", encoding="utf-8") as f:
    js = execjs.compile(f.read())


def csrf_save():
    url = "脱敏解决,残缺代码关注 GitHub:https://github.com/kgepachong/crawler"
    headers = {"User-Agent": UA}
    response = requests.post(url=url, headers=headers, cookies=cookies).json()
    data = response["data"]
    return data


def get_session():
    url = "脱敏解决,残缺代码关注 GitHub:https://github.com/kgepachong/crawler"
    headers = {"User-Agent": UA}
    response = requests.get(url=url, headers=headers)
    cookies.update(response.cookies.get_dict())


def get_uuid():
    url = "脱敏解决,残缺代码关注 GitHub:https://github.com/kgepachong/crawler"
    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 = "脱敏解决,残缺代码关注 GitHub:https://github.com/kgepachong/crawler"
    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 = "脱敏解决,残缺代码关注 GitHub:https://github.com/kgepachong/crawler"
    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()
    code = ver_code()
    login(phone, pwd, code, uuid)


if __name__ == '__main__':
    main()

正文完
 0