Desvendando Dados Cifrados de API com JavaScript e Python

A análise de dados retornados por requisições web frequentemente revela que a informação pode estar cifrada. Este artigo detalha o processo de decifração de respostas de uma API específica, utilizando tanto Python quanto a execução direta de código JavaScript.

Ao inspecionar o tráfego de rede para o endpoint https://www.swguancha.com/home/city-detail?code=310100, observa-se que os dados de resposta são strings cifradas. Em cenários onde os dados de retorno são criptografados, é comum que a lógica de decifragem esteja implementada através de interceptadores (interceptors) no lado do cliente.

A investigação do código JavaScript revela a presença de interceptadores de resposta. Após análise, um dos interceptadores exibe palavras-chave como decrypt e AES, indicando que a lógica de decifragem reside ali.

Definindo um ponto de interrupção (breakpoint) e recarregando a página, podemos examinar as variáveis relevantes. t.data contém a resposta cifrada, enquanto key e iv (se aplicável) são utilizados para o processo de decifragem. A chave (key) é obtida a partir de uma constante definida no código (l) e convertida para UTF-8. O modo de operação, identificado como u.mode.ECB, confirma o uso do modo ECB (Electronic Codebook). Neste caso específico, o vetor de inicialização (iv) não é necessário devido ao modo ECB.

Implementação em Python

A decifragem pode ser realizada diretamente em Python utilizando a biblioteca pycryptodome.

import requests
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import base64

# O URL da API pode variar dependendo do endpoint específico
api_url = "https://app.swguancha.com/client/v1/cPublic/consumer/property/type/search?level=2"

# Cabeçalhos necessários para a requisição
request_headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
    "Referer": "https://www.swguancha.com/"
}

# Realiza a requisição GET
response = requests.get(api_url, headers=request_headers)

# A resposta bruta pode conter espaços que precisam ser removidos
encrypted_data_raw = response.text.replace(" ", "")

# Chave de decifragem obtida da análise do JavaScript
decryption_key_str = "QV1f3nHn2qm7i3xrj3Y9K9imDdGTjTu9"
decryption_key_bytes = decryption_key_str.encode("utf-8")

# Configuração do cifrador AES em modo ECB
cipher_aes = AES.new(key=decryption_key_bytes, mode=AES.MODE_ECB)

# Decifra os dados: primeiro decodifica de Base64, depois aplica AES
decrypted_data_bytes = cipher_aes.decrypt(base64.b64decode(encrypted_data_raw))

# Remove o padding PKCS7
decrypted_data_unpadded = unpad(decrypted_data_bytes, 16)

# Converte os bytes decifrados para string UTF-8
original_data = decrypted_data_unpadded.decode("utf-8")

print(original_data)

Execução de Código JavaScript com Python

Alternativamente, é possível executar o código JavaScript original que realiza a decifragem, utilziando a biblioteca PyExecJS.

Primeiro, crie um arquivo decryptor.js com o seguinte contteúdo:

var CryptoJS = require("crypto-js");

var encryptionKey = "QV1f3nHn2qm7i3xrj3Y9K9imDdGTjTu9";

function decryptResponse(encryptedText) {
    var keyParsed = CryptoJS.enc.Utf8.parse(encryptionKey);
    var decrypted = CryptoJS.AES.decrypt(encryptedText, keyParsed, {
        mode: CryptoJS.mode.ECB,
        padding: CryptoJS.pad.Pkcs7
    });
    var decryptedString = decrypted.toString(CryptoJS.enc.Utf8);
    var jsonData = JSON.parse(decryptedString);
    return jsonData;
}

Em seguida, utilize o seguinte script Python para chamar a função JavaScript:

from functools import partial
import subprocess
import requests
import base64
import execjs

# Necessário para garantir que subprocess.Popen use encoding UTF-8
subprocess.Popen = partial(subprocess.Popen, encoding="utf-8")

api_url = "https://app.swguancha.com/client/v1/cPublic/consumer/property/type/search?level=2"
request_headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
    "Referer": "https://www.swguancha.com/"
}

response = requests.get(api_url, headers=request_headers)
encrypted_data_raw = response.text.replace(" ", "")

# Carrega o código JavaScript do arquivo
with open("decryptor.js", "r", encoding="utf-8") as f:
    js_code = f.read()

# Compila o código JavaScript
js_runtime = execjs.compile(js_code)

# Chama a função JavaScript com os dados cifrados
decrypted_result = js_runtime.call("decryptResponse", encrypted_data_raw)

print(decrypted_result)

Ambos os métodos permitem obter os dados originais da API, demonstrando a flexibilidade ao lidar com diferentes requisitos de implementação.

Tags: Python javascript AES ECB API

Publicado em 9-18 12:33