[Python crawler advanced learning] - JS reverse hundred examples - nested layer by layer, RSA encryption in an accelerated mall

 

statement

All contents in this article are for learning and communication only. Sensitive websites and data interfaces have been desensitized. It is strictly prohibited to use them for commercial and illegal purposes. Otherwise, all consequences arising therefrom have nothing to do with the author. If there is infringement, please contact me and delete them immediately!

Reverse target

  • Target: login interface of an acceleration mall

  • Home page: ahr0cdovl3dy4xnxl1bm1hbgwuy29tl3bjl2xvz2lul2luzgv4

  • Interface: ahr0cdovl3dy4xnxl1bm1hbgwuy29tl3bjl2xvz2lul2nozwnr

  • Reverse parameters:
    Cookie:

    PHPSESSID=g9jp7sfpukg99v03gj69nr9r56
    

    Form Data:

    u[password]: 7aad70a547b016a07f2e20bee7b4936111e650aa5c419fafdfb28322......
    _csrfToken: 4bea63330c5ccdd37588321d027f4c40129687b0
    

Reverse process

Packet capture analysis

Click log in on the home page to log in, enter an account and password randomly, and locate the login interface as aHR0cDovL3d3dy4xNXl1bm1hbGwuY29tL3BjL2xvZ2luL2NoZWNr. In the POST request and Form Data, the password {u[password] is encrypted, and there is another one_ csrfToken also needs to be solved. There is a PHPSESSID in the cookie. After testing, if this parameter is not taken, the final request will fail.

Parameter inversion #

First look_ csrfToken, first try to search its value directly, and you can find it in the source code of the home page. Just take it directly:

Take another look at the PHPSESSID in the cookie. The first thing you think of may be the set cookie returned by Response Headers when you visit the page for the first time. Check the first request. It is true. If not, you need to clear the cache before accessing (developer tools - > Application - > storage - > clear site data).

The last password parameter {u[password] must be obtained through JS encryption. Direct Ctrl+Shift+F global search. You can directly find the place encrypted by RSA on the index home page and bury breakpoints for debugging. The last res is the encrypted password:

We rewrite this key code and encapsulate it into a function:

function getEncryptedPassword(password) {
    var public_key = "00bdf3db924714b9c4ddd144910071c282e235ac51371037cf89fa08f28b9105b6326338ed211280154c645bf81bae4184c2b52e2b02b0953e7aa8b25a8e212a0b";
    var public_length = "10001";
    var rsa = new RSAKey();
    rsa.setPublic(public_key, public_length);
    return rsa.encrypt(password);
}

The three main functions used here are RSAKey(), setPublic(), and encrypt(). In the developer tool, mouse over the function and you can see that RSA is called here JS, we directly peel off the entire file for local debugging:

During local debugging, you will find that the prompt "BigInteger" is undefined. Move the mouse over this function and you can find that JSBN has been called The methods in jsbn.js, similarly, directly integrate the whole JSBN JS file for local debugging.

It's actually in RSA JS file has a comment on the first line: / / depends on JSBN js and rng.js, we can guess RSA JS may depend on JSBN JS and RNG JS of these two files.

With JSBN JS code. After debugging again, you will find that {navigator} and {SecureRandom} are not defined. Navigator} is very familiar to us. It is the relevant information of the browser. Generally, it can be directly defined as empty (navigator = {};); Move the mouse over the secure random function, and you can find that RNG is called JS, similarly, directly integrate the entire RNG JS file for local debugging. This confirms our conjecture, RSA JS really depends on JSBN JS and RNG JS.

We note that here in RNG JS file, there is also a comment: / / random number generator - requires a PRNG backend, e.g. prng4 JS, indicating RNG JS is a random number generator and requires a PRNG backend, such as prng4 JS, in cryptography, the full name of PRNG is pseudorandom number generator, that is, pseudo-random number generator. It refers to generating a series of numbers through a specific algorithm, so that this series of numbers look random, but they are actually determined, so it is called pseudo-random number. Interested friends can study it in depth. Here we know RNG JS may also rely on prng4 JS, which needs further debugging.

rsa.js,jsbn.js,rng.js are complete. If you debug locally again, you will find RNG RNG in JS_ Psize , undefined, mouse over to see , rng_psize , is a constant value of 256. You can also see the value of 256 in the Global variable on the right. Try searching , rng_psize can be found in prng4 JS defines var rng_psize = 256;, Sure enough, it's the same as the notes, RNG JS is dependent on prng4 JS, but it seems to define RNG directly here_ Just psize.

Define var RNG directly in the local code_ psize = 256;, Debug again, and you will be prompted with RNG Missing PRNG in JS_ The newstate () object. When you return to the developer tool again, you can see {prng_newstate() is prng4 JS inside the method, sure enough RNG JS and prng4 JS is not a simple relationship. Similarly, we directly integrate the whole prng4 JS file for local debugging.

After debugging again and running correctly, you can successfully get the encrypted password:

Logical summary

  1. The encryption portal can be found on the index home page, using RSA The three encryption functions in JS are RSAKey(), setPublic(), and encrypt();

  2. rsa. The BigInteger() function in JS depends on JSBN JS, the SecureRandom() function depends on RNG js;

  3. rng.js variable rng_psize , in prng4 JS, PRNG_ The newstate () function also relies on prng4 js;

To add RSA js,jsbn.js,rng.js,prng4.js these four JS encrypted files can be completely stripped down to restore the whole encryption process.

Complete code

The following shows only some key codes, and the complete code warehouse address: https://github.com/kuaidaili/crawler/

Parameter JS encryption key code

navigator = {};

// ================== prng4.js begin ================== //

function Arcfour() {}

function ARC4init(key) {}

function ARC4next() {}

// N functions are omitted here

var rng_psize = 256;

// ================== prng4.js end ================== //

// ================== rng.js begin ================== //

var rng_state;
var rng_pool;
var rng_pptr;

function rng_seed_int(x) {}

function rng_seed_time() {}

// N functions are omitted here

function SecureRandom() {}

SecureRandom.prototype.nextBytes = rng_get_bytes;

// ================== rng.js end ================== //

// ================== jsbn.js begin ================== //

var dbits;

var canary = 0xdeadbeefcafe;
var j_lm = ((canary & 0xffffff) == 0xefcafe);

function BigInteger(a, b, c) {}

function nbi() {}

// N functions are omitted here

// protected
BigInteger.prototype.copyTo = bnpCopyTo;
BigInteger.prototype.fromInt = bnpFromInt;
BigInteger.prototype.fromString = bnpFromString;
BigInteger.prototype.clamp = bnpClamp;
BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
BigInteger.prototype.drShiftTo = bnpDRShiftTo;
BigInteger.prototype.lShiftTo = bnpLShiftTo;
BigInteger.prototype.rShiftTo = bnpRShiftTo;
BigInteger.prototype.subTo = bnpSubTo;
BigInteger.prototype.multiplyTo = bnpMultiplyTo;
BigInteger.prototype.squareTo = bnpSquareTo;
BigInteger.prototype.divRemTo = bnpDivRemTo;
BigInteger.prototype.invDigit = bnpInvDigit;
BigInteger.prototype.isEven = bnpIsEven;
BigInteger.prototype.exp = bnpExp;

// public
BigInteger.prototype.toString = bnToString;
BigInteger.prototype.negate = bnNegate;
BigInteger.prototype.abs = bnAbs;
BigInteger.prototype.compareTo = bnCompareTo;
BigInteger.prototype.bitLength = bnBitLength;
BigInteger.prototype.mod = bnMod;
BigInteger.prototype.modPowInt = bnModPowInt;

// "constants"
BigInteger.ZERO = nbv(0);
BigInteger.ONE = nbv(1);

// ================== jsbn.js end ================== //

// ================== rsa.js begin ================== //

function parseBigInt(str, r) {}

function linebrk(s, n) {}

function byte2Hex(b) {}

function pkcs1pad2(s, n) {}

function RSAKey() {}

function RSASetPublic(N, E) {}

function RSADoPublic(x) {}

function RSAEncrypt(text) {}

// protected
RSAKey.prototype.doPublic = RSADoPublic;

// public
RSAKey.prototype.setPublic = RSASetPublic;
RSAKey.prototype.encrypt = RSAEncrypt;
//RSAKey.prototype.encrypt_b64 = RSAEncryptB64;

// ================== rsa.js end ================== //

function getEncryptedPassword(password) {
    var public_key = "00bdf3db924714b9c4ddd144910071c282e235ac51371037cf89fa08f28b9105b6326338ed211280154c645bf81bae4184c2b52e2b02b0953e7aa8b25a8e212a0b";
    var public_length = "10001";
    var rsa = new RSAKey();
    rsa.setPublic(public_key, public_length);
    return rsa.encrypt(password);
}

// Test sample
console.log(getEncryptedPassword("123456"))

Python login key code

#!/usr/bin/env python3
# -*- coding: utf-8 -*-


import execjs
import requests

from lxml import etree
from PIL import Image


index_url = 'Desensitization, complete code attention GitHub: https://github.com/kuaidaili/crawler/'
login_url = 'Desensitization treatment, complete code attention GitHub: https://github.com/kuaidaili/crawler/'
code_url = 'Desensitization, complete code attention GitHub: https://github.com/kuaidaili/crawler/'

headers = {
    'Host': 'Desensitization, complete code attention GitHub: https://github.com/kuaidaili/crawler/',
    'Referer': 'Desensitization, complete code attention GitHub: https://github.com/kuaidaili/crawler/',
    'Origin': 'Desensitization, complete code attention GitHub: https://github.com/kuaidaili/crawler/',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36'
}
session = requests.session()


def get_encrypted_password(password):
    with open('encrypt.js', 'r', encoding='utf-8') as f:
        yunmall_js = f.read()
    encrypted_password = execjs.compile(yunmall_js).call('getEncryptedPassword', password)
    return encrypted_password


def get_csrf_token_cookie():
    response = session.get(url=index_url, headers=headers)
    tree = etree.HTML(response.text)
    csrf_token = tree.xpath("//input[@name='_csrfToken']/@value")[0]
    cookies = response.cookies.get_dict()
    # print(csrf_token, cookies)
    return csrf_token, cookies


def get_very_code(cookies):
    response = session.get(url=code_url, cookies=cookies, headers=headers)
    with open('code.png', 'wb') as f:
        f.write(response.content)
    image = Image.open('code.png')
    image.show()
    very_code = input('Please enter the verification code: ')
    return very_code


def login(csrf_token, very_code, cookies, username, encrypted_password):
    data = {
        'u[loginType]': 'name',
        'u[phone]': username,
        'u[password]': encrypted_password,
        'u[veryCode]': very_code,
        'u[token]': '',
        '_csrfToken': csrf_token
    }
    header_info = {
        'X-Requested-With': 'XMLHttpRequest',
    }
    headers.update(header_info)
    response = session.post(url=login_url, data=data, cookies=cookies, headers=headers)
    response.encoding = 'utf-8-sig'
    response_code = response.text
    # print(response_code)
    status_code = {
        '31': 'Congratulations, successful login.',
        '32': 'Login failed.',
        '33': 'Wrong user name or password.',
        '35': 'The user has been locked by the administrator.',
        '311': 'The account has been bound to the device. Please log in to the bound device.',
        '20001': 'Incorrect verification code!'
    }
    try:
        print(status_code[response_code])
    except KeyError:
        print('Request timed out!')


def main():
    username = input('Please enter login account: ')
    password = input('Please enter the login password: ')
    if len(password) > 32:
        raise Exception('Please enter the correct password!')
    encrypted_password = get_encrypted_password(password)
    csrf_token, cookies = get_csrf_token_cookie()
    very_code = get_very_code(cookies)
    login(csrf_token, very_code, cookies, username, encrypted_password)


if __name__ == '__main__':
    main()

Finally, there is a surprise (don't miss it)

It is the dream of every programmer to become a big manufacturer. He also hopes to have the opportunity to shine and make great achievements. However, the distance between ideal and reality needs to be shortened.

So here I have prepared some gift bags, hoping to help you.


★ gift bag 1

If you have no self-control or motivation to learn and communicate together, welcome to leave a message in the private letter or comment area. I will pull you into the learning and exchange group. We will communicate and study together, report to the group and punch in. There are many benefits in the group, waiting for you to unlock. Join us quickly!
★ gift bag 2

❶ a complete set of Python e-books, 200, a total of 6 G e-book materials, covering all major fields of Python.

❷ Python hands-on projects, including crawler, data analysis, machine learning, artificial intelligence and small game development.

Keywords: Python Javascript crawler

Added by jmanfffreak on Sun, 23 Jan 2022 17:46:59 +0200