[100 ejemplos de JS Reverse] WebSocket Protocol Crawler, Wisdom Tree Scan Code Scaning Case Analysis

Preste atención a la cuenta pública de WeChat: rastreador Brother K, continúe compartiendo productos técnicos secos como rastreador avanzado, JS / Android inverso.

declaración

Todo el contenido de este artículo es solo para el aprendizaje y la comunicación. El contenido capturado, las URL confidenciales y las interfaces de datos se han insensibilizado. Los usos comerciales e ilegales están estrictamente prohibidos. De lo contrario, todas las consecuencias que surjan no tienen nada que ver con el autor. Si hay alguna infracción, por favor póngase en contacto conmigo para eliminar inmediatamente!

objetivo inverso

  • Objetivo: inicio de sesión de código de escaneo de árbol inteligente, la interfaz utiliza el protocolo de comunicación WebSocket
  • Página principal:aHR0cHM6Ly9wYXNzcG9ydC56aGlodWlzaHUuY29tL2xvZ2luI3FyQ29kZUxvZ2lu

Introducción a WebSockets

WebSocket es un protocolo para la comunicación full-duplex sobre una única conexión TCP. WebSocket hace que el intercambio de datos entre clientes y servidores sea mucho más simple. En la API de WebSocket, el navegador y el servidor solo necesitan completar un protocolo de enlace, y se puede crear una conexión persistente directamente entre los dos, y se puede realizar una transmisión de datos bidireccional.

El protocolo WebSocket se abrevia como WS o WSS (WebSocket Secure), y la URL para enviar una solicitud comienza con ws://o wss://WSS es una versión cifrada de WS, similar a HTTP y HTTPS.

La característica más importante del protocolo WebSocket es que el servidor puede enviar información de forma activa al cliente, y el cliente también puede enviar información de forma activa al servidor. Es un verdadero diálogo de dos vías y pertenece a un tipo de tecnología de envío de servidor. La comparación con HTTP se muestra en la siguiente figura:

01.png

Análisis de captura de paquetes

Vaya a la página de inicio de sesión del código de escaneo de Wisdom Tree, capture paquetes y seleccione WS para filtrar las solicitudes de WebSocket, como se muestra en la siguiente figura:

02.png

Hay algunos parámetros especiales que no están disponibles en las solicitudes HTTP/HTTPS:

  • Upgrade: websocket: Indica que se trata de una solicitud de tipo WebSocket;
  • Sec-WebSocket-Version: Indica el Websocket Draft (versión del protocolo) utilizado por el servidor, que debe ser 13;
  • Sec-WebSocket-Extensions: Extensión de protocolo, un cierto tipo de protocolo puede admitir múltiples extensiones, a través de las cuales se puede lograr la mejora del protocolo;
  • Sec-WebSocket-Key: es un texto cifrado codificado en base64 enviado por el cliente WebSocket, que es generado aleatoriamente por el navegador. Se requiere que el servidor devuelva una Sec-WebSocket-Acceptrespuesta cliente arrojará Error during WebSocket handshakeun error y cerrará la conexión.

Primero escaneamos el código para iniciar sesión y luego seleccionamos la pestaña Mensajes. Puede ver que hay alguna interacción de datos. La flecha verde son los datos enviados por el cliente al servidor, y la flecha roja son los datos devueltos por el respuesta del servidor al cliente, como se muestra en la siguiente figura:

03.png

Observemos todo el proceso de interacción. Cuando abrimos la página del código QR, es decir, cuando se carga el código QR, se establece la conexión WebSocket. Cada 8 segundos más o menos, el cliente envía activamente una cadena de cadenas y el servidor. también devuelve la misma cadena, pero en formato de diccionario. Cuando escaneamos el código con éxito, el servidor devolverá la información de éxito del código de escaneo. Cuando hacemos clic para iniciar sesión, el cliente devolverá el resultado del código de escaneo. Si tiene éxito, hay será una contraseña de un solo uso oncePasswordy una uuid, estos dos parámetros definitivamente se utilizarán en solicitudes posteriores. Si no escanea el código durante mucho tiempo, el mensaje de que el código QR ha caducado se devolverá después de un período de tiempo y se enviará un mensaje cada 8 segundos, solo para mantener la conexión y obtener el estado del código QR. mensaje.

Así que aquí hay dos problemas:

  1. ¿Cómo conseguiste que la cadena de cadenas se enviara de un lado a otro de forma interactiva?

  2. ¿Cómo se deben implementar las solicitudes de WebSocket en Python?

  3. ¿Cómo puede el cliente recibir información del servidor en tiempo real mientras envía datos cada 8 segundos? (Observe que el resultado del código de escaneo de la solicitud se devuelve en tiempo real, por lo que no se puede recibir cada 8 segundos)

adquisición de parámetros

Primero resuelva el primer problema, ¿de dónde proviene la cadena enviada por el cliente? La forma de encontrar la cadena cifrada aquí es la misma que la solicitud HTTP/HTTPS. En este ejemplo, podemos buscar directamente esta cadena y encontrar que se pasa a través de una interfaz, donde img es el valor base64 de la imagen del código QR y qrToken es la cadena enviada por el cliente, como se muestra en la siguiente figura:

04.png

Cabe señalar aquí que no todas las solicitudes de WebSocket son tan simples. Los datos enviados por algunos clientes son mensajes binarios (datos binarios) o parámetros de cifrado más complejos, que no se pueden obtener mediante la búsqueda directa. Para esta situación, también tenemos una solución alternativa. :

  1. La declaración conocida para crear un objeto WebSocket es: var Socket = new WebSocket(url, [protocol] );, por lo que podemos buscar y new WebSocketubicar la ubicación donde se creó la solicitud.

  2. Sabiendo que un objeto WebSocket tiene los siguientes eventos relacionados, podemos buscar el código del controlador de eventos correspondiente para ubicar:

evento controlador de eventos describir
abierto Zócalo.onopen Se activa cuando se establece una conexión
mensaje Socket.en mensaje Activado cuando el cliente recibe datos del servidor
error Socket.onerror Activado cuando ocurre un error de comunicación
Cerrar Zócalo.onclose Disparado cuando la conexión está cerrada
  1. Sabiendo que un objeto WebSocket tiene los siguientes métodos relacionados, podemos buscar el método correspondiente para localizar:
método describir
Socket.enviar() enviar datos usando la conexión
Zócalo.cerrar() cerrar la conexión

Python implementa la solicitud WebSocket

A continuación, la segunda pregunta, ¿cómo se debe implementar una solicitud de WebSocket en Python? Hay muchas bibliotecas de Python que se usan para conectarse a WebSocket, las más estables y de uso común son websocket-client (no asíncrono), websockets (asíncrono) y aiowebsocket (asíncrono). En este caso se utiliza websocket-client, y aquí se debe prestar atención al tercer problema, para el cliente se deben enviar datos cada 8 segundos, para el servidor se necesita recibir la información del servidor en tiempo real. Puede observar la solicitud, escanear el El resultado del código se devuelve en tiempo real.Si también recibimos datos cada 8 segundos, los datos pueden perderse y la respuesta de todo el programa no será oportuna y la eficiencia será menor. .

En la documentación oficial de websocket-client, proporcionamos una demostración de una conexión larga, que realiza el envío de datos tres veces seguidas y monitorea los datos devueltos por el servidor en tiempo real, en el que websocket.enableTrace(True)indica si mostrar los detalles de la conexión:

import websocket
import _thread
import time


def on_message(ws, message):
    print(message)


def on_error(ws, error):
    print(error)


def on_close(ws, close_status_code, close_msg):
    print("### closed ###")


def on_open(ws):
    def run(*args):
        for i in range(3):
            time.sleep(1)
            ws.send("Hello %d" % i)
        time.sleep(1)
        ws.close()
        print("thread terminating...")
    _thread.start_new_thread(run, ())


if __name__ == "__main__":
    websocket.enableTrace(True)
    ws = websocket.WebSocketApp(
        "ws://echo.websocket.org/", on_open=on_open,
        on_message=on_message, on_error=on_error, on_close=on_close
    )

    ws.run_forever()

Vamos a modificarlo correctamente. En el método de ejecución, el cliente todavía envía qr_token cada 8 segundos y recibe el mensaje del servidor en tiempo real. Cuando aparece la palabra "escanear código con éxito" en el mensaje, los resultados obtenidos oncePasswordy uuidalmacenados. cierre la conexión, el código lógico es el siguiente, y luego solo necesita conectar la lógica de adquisición del código QR. (Se ha insensibilizado y no se puede ejecutar directamente)

import json
import time
import _thread
import websocket


web_socket_url = "wss://appcomm-user.脱敏处理.com/app-commserv-user/websocket?qrToken=%s"
qr_token = "ca6e6cfb70de4f2f915b968aefcad404"
once_password = ""
uuid = ""


def wss_on_message(ws, message):
    print("=============== [message] ===============")
    message = json.loads(message)
    print(message)
    if "扫码成功" in message["msg"]:
        global once_password, uuid
        once_password = message["oncePassword"]
        uuid = message["uuid"]
        ws.close()


def wss_on_error(ws, error):
    print("=============== [error] ===============")
    print(error)
    ws.close()


def wss_on_close(ws, close_status_code, close_msg):
    print("=============== [closed] ===============")
    print(close_status_code)
    print(close_msg)


def wss_on_open(ws):
    def run(*args):
        while True:
            ws.send(qr_token)
            time.sleep(8)
    _thread.start_new_thread(run, (qr_token,))


def wss():
    # websocket.enableTrace(True)  # 是否显示连接详细信息
    ws = websocket.WebSocketApp(
        web_socket_url % qr_token, on_open=wss_on_open,
        on_message=wss_on_message, on_error=wss_on_error,
        on_close=wss_on_close
    )
    ws.run_forever()

Realizar escaneo de código de inicio de sesión

La parte más importante de la solicitud de WebSocket ha sido resuelta. Después de escanear el código para obtener oncePasswordy uuid, los pasos de procesamiento posteriores son relativamente simples. Ahora echemos un vistazo a los pasos completos:

  1. Solicite la página de inicio, obtenga la cookie por primera vez, que incluye: INGRESSCOOKIE, JSESSIONID, SERVERID, acw_tc;
  2. Solicite la interfaz del código QR para obtener el valor base64 y qrToken del código QR;
  3. Establezca una conexión WebSocket, escanee el código QR y obtenga la contraseña de un solo uso una vez Contraseña y uuid (parece inútil);
  4. Solicite una interfaz de inicio de sesión, redirección 302, debe llevar una contraseña de un solo uso, obtener la cookie por segunda vez, que incluye: CASLOGC, CASTGC y actualizar SERVERID al mismo tiempo;
  5. Solicite la dirección de redireccionamiento 302 en el paso 4 y obtenga la cookie por tercera vez, que incluye: SESIÓN;
  6. Lleve la cookie completa, solicite la interfaz de información del usuario y obtenga el nombre de usuario real y otra información.

De hecho, después de que finaliza la conexión WebSocket, hay muchas solicitudes, que parecen estar bien, pero después de la prueba de Brother K, solo son útiles dos redireccionamientos.La captura de paquetes es la siguiente:

05.png

código completo

¡GitHub presta atención al rastreador de Brother K y continúa compartiendo código relacionado con el rastreador! ¡Bienvenida estrella! https://github.com/kgepachong/

¡Lo siguiente solo muestra algunos códigos clave y no se puede ejecutar directamente! Dirección completa del repositorio de código: https://github.com/kgepachong/crawler/

Código de inicio de sesión de Python

import time
import json
import base64
import _thread
import requests
import websocket
from PIL import Image


web_socket_url = "脱敏处理,完整代码关注 GitHub:https://github.com/kgepachong/crawler"
get_login_qr_img_url = "脱敏处理,完整代码关注 GitHub:https://github.com/kgepachong/crawler"
login_url = "脱敏处理,完整代码关注 GitHub:https://github.com/kgepachong/crawler"
user_info_url = "脱敏处理,完整代码关注 GitHub:https://github.com/kgepachong/crawler"

headers = {
    "Host": "脱敏处理,完整代码关注 GitHub:https://github.com/kgepachong/crawler",
    "Pragma": "no-cache",
    "Referer": "脱敏处理,完整代码关注 GitHub:https://github.com/kgepachong/crawler",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36"
}

qr_token = ""
once_password = ""
uuid = ""
cookie = {}


def get_cookies_first():
    response = requests.get(url=login_url, headers=headers)
    global cookie
    cookie = response.cookies.get_dict()


def get_login_qr_img():
    response = requests.get(url=get_login_qr_img_url, headers=headers, cookies=cookie).json()
    qr_img = response["img"]
    global qr_token
    qr_token = response["qrToken"]
    with open('code.png', 'wb') as f:
        f.write(base64.b64decode(qr_img))
    image = Image.open('code.png')
    image.show()
    print("请扫描验证码! ")


def wss_on_message(ws, message):
    print("=============== [message] ===============")
    message = json.loads(message)
    print(message)
    if "扫码成功" in message["msg"]:
        global once_password, uuid
        once_password = message["oncePassword"]
        uuid = message["uuid"]
        ws.close()


def wss_on_error(ws, error):
    print("=============== [error] ===============")
    print(error)
    ws.close()


def wss_on_close(ws, close_status_code, close_msg):
    print("=============== [closed] ===============")
    print(close_status_code)
    print(close_msg)


def wss_on_open(ws):
    def run(*args):
        while True:
            ws.send(qr_token)
            time.sleep(8)
    _thread.start_new_thread(run, (qr_token,))


def wss():
    # websocket.enableTrace(True)  # 是否显示连接详细信息
    ws = websocket.WebSocketApp(
        web_socket_url % qr_token, on_open=wss_on_open,
        on_message=wss_on_message, on_error=wss_on_error,
        on_close=wss_on_close
    )
    ws.run_forever()


def get_cookie_second():
    global cookie
    params = {
        "pwd": once_password,
        "service": "脱敏处理,完整代码关注 GitHub:https://github.com/kgepachong/crawler"
    }
    headers["Host"] = "脱敏处理,完整代码关注 GitHub:https://github.com/kgepachong/crawler"
    headers["Referer"] = "脱敏处理,完整代码关注 GitHub:https://github.com/kgepachong/crawler"
    response = requests.get(url=login_url, params=params, headers=headers, cookies=cookie, allow_redirects=False)
    cookie.update(response.cookies.get_dict())
    location = response.headers.get("Location")
    return location


def get_cookie_third(location):
    global cookie
    headers["Host"] = "脱敏处理,完整代码关注 GitHub:https://github.com/kgepachong/crawler"
    headers["Referer"] = "脱敏处理,完整代码关注 GitHub:https://github.com/kgepachong/crawler"
    response = requests.get(url=location, headers=headers, cookies=cookie, allow_redirects=False)
    cookie.update(response.cookies.get_dict())
    location = response.headers.get("Location")
    return location


def get_login_user_info():
    headers["Host"] = "脱敏处理,完整代码关注 GitHub:https://github.com/kgepachong/crawler"
    headers["Origin"] = "脱敏处理,完整代码关注 GitHub:https://github.com/kgepachong/crawler"
    headers["Referer"] = "脱敏处理,完整代码关注 GitHub:https://github.com/kgepachong/crawler"
    params = {"time": str(int(time.time() * 1000))}
    response = requests.get(url=user_info_url, headers=headers, cookies=cookie, params=params)
    print(response.text)


def main():
    # 第一次获取 cookie,包含 INGRESSCOOKIE、JSESSIONID、SERVERID、acw_tc
    get_cookies_first()
    # 获取二维码
    get_login_qr_img()
    # websocket 扫码登录,返回一次性密码
    wss()
    # 第二次获取 cookie,更新 SERVERID、获取 CASLOGC、CASTGC
    location1 = get_cookie_second()
    # 第三次获取 cookie,获取 SESSION
    get_cookie_third(location1)
    # 获取登录用户信息
    get_login_user_info()


if __name__ == '__main__':
    main()

{{o.nombre}}
{{m.nombre}}

Supongo que te gusta

Origin my.oschina.net/u/4585873/blog/5346839
Recomendado
Clasificación