头图
Pay attention to WeChat public account: K brother crawler, QQ exchange group: 808574309, continue to share advanced crawler, JS/Android reverse engineering and other technical dry goods!

statement

All the content in this article is for learning and communication only. The captured content, sensitive URLs, and data interfaces have been desensitized, and it is strictly forbidden to use them for commercial or illegal purposes. Otherwise, all the consequences arising therefrom will have nothing to do with the author. Infringement, please contact me to delete it immediately!

Reverse target

  • Target: an e Netcom login interface
  • Homepage: aHR0cHM6Ly93ZWIuZXd0MzYwLmNvbS9yZWdpc3Rlci8jL2xvZ2lu
  • Interface: aHR0cHM6Ly9nYXRld2F5LmV3dDM2MC5jb20vYXBpL2F1dGhjZW50ZXIvdjIvb2F1dGgvbG9naW4vYWNjb3VudA==
  • Reverse parameters:

    • Request Headers:sign: 3976F10977FC65F9CB967AEF79E508BD
    • Request Payload:password: "A7428361DEF118911783F446A129FFCE"

Reverse process

Packet capture analysis

Came to the login page of a certain e Netcom, just enter an account and password to log in, capture the packet and locate the login interface as aHR0cHM6Ly9nYXRld2F5LmV3dDM2MC5jb20vYXBpL2F1dGhjZW50ZXIvdjIvb2F1dGgvbG9=naW3Vudload in the password, and the password is processed in the header of the request.

01.png

Parameter reverse

sign

First look at the sign of the request header, try to search directly, and find that it is not the data returned by some requests. If you observe other requests, you can find that there is the same sign, and the value of each request is different:

02.png

It can be preliminarily judged that this value should be generated by JS, the global search keyword 0615125b1d2cb9, you can see the suspected sign assignment in the request.js and request.ts files respectively, sign: Next, the principle is also very simple, add a string of fixed characters to the timestamp, and then convert to uppercase after MD5 encryption.

03.png

Use Python to achieve:

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 is the value obtained after the plaintext password is encrypted. If you try to search directly, you will find a lot of values. It is very difficult to find an accurate value:

04.png

You can see that this request is an XHR request. This time we use the XHR breakpoint method to locate the specific encryption location. Through this case, we will learn how to follow up the call stack and how to locate the specific location through the context. Encryption location.

Switch to the Network tab, find the login request, move the mouse to the JS under the Initiator tab, you can see its call stack, if the site encryption method is relatively simple, there is not much confusion, you can see login in the call stack Key words such as, send, post, encrypt, etc., in this case, you can click directly in, it is easier to find the encrypted place, but most sites have confused function names and variable names, just like this case , The functions displayed in the call stack are some single or multiple irregular letter functions, which cannot be directly located. At this time, we need to look forward from the last function slowly.

05.png

Click to enter the last function, the Y function, which is at the top of the call stack, which means that after this function, the browser will send a login request, and the password encryption process has been processed. Put a breakpoint in this function, and you can see the call stack on the Call Stack on the right. From bottom to top, it means the execution process of the functions that are called successively after you click to log in:

06.png

To find the specific encryption location, we have to look forward one by one and analyze each function one by one. For example, move forward to the penultimate call stack, namely the o function. You can see that the passed params parameter contains the Encrypted password information, which means that the encryption operation must be before this function:

07.png

According to this idea, follow up the call stack step by step, and you can see that an anonymous function is executed in utils.ts, which calls a passwordEncrypt function. You can see from the function name that it is basically a function of password encryption. :

08.png

Bury a breakpoint here to debug, the plaintext password is passed in, and passwordEncrypt is actually the O function in encode.ts that is called:

09.png

Follow up with the O function and quote the crypto-js encryption module. Obviously, AES encryption, just rewrite it locally.

10.png

The encryption of this case is relatively simple, but the encryption function is better hidden, and you need to follow up the call stack patiently. If you search directly, there are too many results, and it is not easy to locate the encryption function. In this case, follow up to one After the function, you can clearly see the encrypted place, then some sites may be more confusing, and it is impossible to see that there is an encrypted function. In this case, we need to pay attention to the change of parameters. If in this call stack What you see is the encrypted parameters, and what you see in the previous call stack is the plaintext parameters, then the encrypted operation must be between the two call stacks, and you can bury a breakpoint and analyze it carefully.

Complete code

GitHub pays attention to K brother crawler, and continues to share crawler-related code! Welcome star! https://github.com/kgepachong/

only part of the key code is demonstrated and cannot be run directly! complete code warehouse address: https://github.com/kgepachong/crawler/

JavaScript encryption code

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 login code

#!/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()


K哥爬虫
166 声望143 粉丝

Python网络爬虫、JS 逆向等相关技术研究与分享。