目录
一、JS逆向进阶一:破解AES加密
(一)AES对称加密算法原理
(二)破解AES加密
(三)实战:发现报告网
二、JS逆向进阶二:破解RSA加密
(一)RSA非对称加密算法原理
(二)破解RSA加密
(三)实战:36氪:破解RSA加密,逆向解析36氪登陆参数
三、JS逆向进阶三:解决多个请求使用相同加密算法的情况
四、JS逆向进阶四:破解参数混合加密
五、JS逆向进阶五:解决密钥需要额外获取的情况
六、JS逆向进阶六:基础JS混淆加密破解
安装一个模块:pip install pycryptodome
# 把明文拆分成 128bits 的部分,如果最后的部分不足128bits,就需要进行 padding(填充)
# 密钥的长度 128bits, 192bits, 256bits
# 长度不固定
# CBC 是最常用的模式,还需要一个128bits 的iv(随机向量)
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
# 加密
def encrypt(plaintext, key, iv):
# 三个值均转为二进制形式
plaintext = plaintext.encode()
key = key.encode()
iv = iv.encode()
cipher =AES.new(key=key, mode=AES.MODE_CBC, iv=iv)
# 密文(加密后的文字)(pad:进行填充)
ciphertext = cipher.encrypt(pad(plaintext, AES.block_size))
# 变为base64的形式
ciphertext = base64.b64encode(ciphertext).decode()
return ciphertext
# 解密
def decrypt(ciphertext, key, iv):
ciphertext = base64.b64decode(ciphertext)
key = key.encode()
iv = iv.encode()
cipher =AES.new(key=key, mode=AES.MODE_CBC, iv=iv)
plaintext = unpad(cipher.decrypt(ciphertext), AES.block_size)
plaintext = plaintext.decode()
return plaintext
plaintext = "apple"
key = "0123456789abcdef"
iv = "abcdef0123456789"
ciphertext = encrypt(plaintext, key, iv)
print(ciphertext)
plaintext = decrypt(ciphertext, key, iv)
print(plaintext)
以下为加密数据
添加xhr断点,以下为加密部分的js函数
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
def encrypt(plaintext, key, iv):
plaintext = plaintext.encode()
key = key.encode()
iv = iv.encode()
cipher =AES.new(key=key, mode=AES.MODE_CBC, iv=iv)
ciphertext = cipher.encrypt(pad(plaintext, AES.block_size))
# 变为base64的形式
ciphertext = base64.b64encode(ciphertext).decode()
return ciphertext
def decrypt(ciphertext, key, iv):
ciphertext = base64.b64decode(ciphertext)
key = key.encode()
iv = iv.encode()
cipher =AES.new(key=key, mode=AES.MODE_CBC, iv=iv)
plaintext = unpad(cipher.decrypt(ciphertext), AES.block_size)
plaintext = plaintext.decode()
return plaintext
plaintext = "abcd"
key = "0123456789abcdef"
iv = "abcdef0123456789"
code = encrypt(plaintext, key, iv)
url = "http://127.0.0.1:5000/api/C14L02"
headers = {
"User-Agent": "xxxx",
"Refer": "http://127.0.0.1:5000/api/C14L02"
}
data = {
"code":code
}
res = requests.post(url, headers= headers, data=data)
print(res.json())
发现密码区域为加密数据
添加xhr断点,找到书写加密函数的区域并添加debug断点,放开url的xhr断点,可看到具体的值
在控制台中可看到的时间戳为13位,比要求数据少3位。但是在python中的时间戳time.time()函数刚好为整数部分
data参数中加密函数中:
在控制台查看分析数据
_()函数:md5加密字符串长度不变,经过验证为md5加密。D().ne()函数:因AES加密前后不一致,猜测,现在点进去这个函数
注意:
(1)iv此网站只截取字符串的后16位
(2)在requests发送请求时,此网站data要求转为json格式数据,请求头添加content-type参数不然会报错
(3)python中最终转为了base64格式,网站中的AES加密后为16进制的格式,需要修改一下
import time
import hashlib
import requests
import json
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
def encrypt(plaintext, key, iv):
plaintext = plaintext.encode()
key = key.encode()
iv = iv.encode()
cipher =AES.new(key=key, mode=AES.MODE_CBC, iv=iv)
ciphertext = cipher.encrypt(pad(plaintext, AES.block_size))
ciphertext = ciphertext.hex()
return ciphertext
mobile = "19244359876"
password = "WAJ23Aww"
ts = int(time.time())
# D().ne("".concat(a).concat(o), _()("".concat(s.slice(3)).concat(a)))
plaintext = str(ts) + password
key = mobile[3:] + str(ts)
key = hashlib.md5(key.encode()).hexdigest()
iv = key[-16:]
ciphertext = encrypt(plaintext, key, iv)
url = "https://api.fxbaogao.com/mofoun/user/login/byPhoneNumber"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
"Refer": "https://www.fxbaogao.com/"
}
data = {
"data" : ciphertext,
"mobile": mobile,
"time": str(ts)
}
data = json.dunmps(data)
res = requests.post(url=url, headers= headers, data=data)
print(res.text)
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5 as PKCS1_signature
from Crypto.Cipher import PKCS1_v1_5 as PKCS1_cipher
from Crypto import Random
import base64
# 生成key
def genKeys():
random_generator = Random.new().read
rsa = RSA.generate(2048, random_generator)
private_key = rsa.exportKey()
public_key = rsa.public_key().exportKey()
with open("./C14/rsa_private_key.pem", "wb") as f:
f.write(private_key)
with open("./C14/rsa_public_key.pem", "wb") as f:
f.write(public_key)
def get_key(key_file):
with open(key_file, "r") as f:
data = f.read()
key = RSA.importKey(data)
return key
def encrypt(plaintext, public_key):
plaintext = plaintext.encode()
cipher = PKCS1_cipher.new(public_key)
ciphertext = cipher.encrypt(plaintext)
ciphertext = base64.b64encode(ciphertext).decode()
return ciphertext
def decrypt(ciphertext, private_key):
cipher = PKCS1_cipher.new(private_key)
ciphertext = base64.b64decode(ciphertext)
plaintext = cipher.decrypt(ciphertext, 0).decode()
return plaintext
public_key = get_key("./C14/rsa_public_key.pem")
private_key = get_key("./C14/rsa_private_key.pem")
plaintext = "hello"
ciphertext = encrypt(plaintext, public_key)
print(ciphertext)
plaintext = decrypt(ciphertext, private_key)
print(plaintext)
此处为加密数据部分
xhr断点
import time
import requests
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5 as PKCS1_signature
from Crypto.Cipher import PKCS1_v1_5 as PKCS1_cipher
from Crypto import Random
import base64
def encrypt(plaintext, public_key):
plaintext = plaintext.encode()
cipher = PKCS1_cipher.new(public_key)
ciphertext = cipher.encrypt(plaintext)
ciphertext = base64.b64encode(ciphertext).decode()
return ciphertext
public_key = """xxxxxx"""
public_key = RSA.importKey(public_key)
ts = int(time.time()*1000)
ciphertext = encrypt(str(ts), public_key)
print(ciphertext)
url = "http://127.0.0.1:5000/api/C14L05"
headers = {
"User-Agent":"xxx",
"referer":"http://127.0.0.1:5000/C14L05"
}
data = {
"code":ciphertext
}
res = requests.post(url, headers=headers, data=data)
print(res.json())
此处为加密形式
全局搜索"mobileNo",并打断点查看数据内容
控制台可知,后面部分即为电话号和密码
点击进入,前面的函数的js
由函数可知上方的i即为publickey
import time
import requests
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5 as PKCS1_signature
from Crypto.Cipher import PKCS1_v1_5 as PKCS1_cipher
from Crypto import Random
import base64
def encrypt(plaintext, public_key):
plaintext = plaintext.encode()
cipher = PKCS1_cipher.new(public_key)
ciphertext = cipher.encrypt(plaintext)
ciphertext = base64.b64encode(ciphertext).decode()
return ciphertext
# 需要带上---部分
public_key = """-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCeiLxP4ZavN8qhI+x+whAiFpGWpY9y1AHSQC86qEMBVnmqC8vdZAfxxuQWeQaeMWG07lXhXegTjZ5wn9pHnjg15wbjRGSTfwuZxSFW6sS3GYlrg40ckqAagzIjkE+5OLPsdjVYQyhLfKxj/79oOfjl/lV3rQnk/SSczHW0PEyUbQIDAQAB-----END PUBLIC KEY-----"""
public_key = RSA.importKey(public_key)
ts = int(time.time() * 1000)
mobile = encrypt("19833679937", public_key)
password = encrypt("ssddef", public_key)
url = "https://gateway.36kr.com/api/mus/login/byMobilePassword"
headers = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
"referer":"https://36kr.com/",
"Content-Type": "application/json"
}
data = {
"krtoken" : "",
"param" : {
"countryCode": "86",
"mobileNo": mobile,
"password" : password
},
"partner_id": "web",
"timestamp": ts
}
data = json.dumps(data)
res = requests.post(url, headers=headers, data=data)
print(res.json())
JS函数如下
书写代码:
如下图可知,多个请求使用相同加密算法
以下为加密数据,全局搜索”acode"
import base64
import hashlib
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
def encrypt(plaintext, key, iv):
plaintext = plaintext.encode()
key = key.encode()
iv = iv.encode()
cipher =AES.new(key=key, mode=AES.MODE_CBC, iv=iv)
ciphertext = cipher.encrypt(pad(plaintext, AES.block_size))
ciphertext = ciphertext.b64encode(ciphertext).decode()
return ciphertext
key1 = "0123456789abcdef"
key2 = "987654321abcdef"
iv = "abcdef0123456789"
ts = int(time.time()*1000)
code = encrypt(str(ts), key1, iv)
acode = hashlib.md5(code.encode()).hexdigest()
bcode = encrypt(code, key2, iv)
url = "https://127.0.0.1:5000/api/C14L09"
headers = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
"referer":"https://127.0.0.1:5000/api/C14L09"
"Content-Type": "application/json"
}
data = {
"timestamp":ts,
"acode":acode,
"bcode":bcode
}
data = json.dumps(data)
res = requests.post(url, headers=headers, data=data)
print(res.json())
以下位置为加密数据部分
以下为函数部分
如上述函数知,需要获取public_key
import requests
import base64
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5 as PKCS1_signature
from Crypto.Cipher import PKCS1_v1_5 as PKCS1_cipher
url = "https://127.0.0.1:5000/api/C14L11/get_key"
headers = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
"referer":"https://127.0.0.1:5000/api/C14L11"
}
res = requests.post(url, headers=headers)
def encrypt(plaintext, public_key):
plaintext = plaintext.encode()
cipher = PKCS1_cipher.new(public_key)
ciphertext = cipher.encrypt(plaintext)
ciphertext = base64.b64encode(ciphertext).decode()
return ciphertext
public_key = RSA.importKey(res.text)
code = encrypt("abc123", public_key)
url = "https://127.0.0.1:5000/api/C14L11/get_data"
data = {
"code": code
}
res = requests.post(url, headers=headers, data=data)
print(res.json())
以下为加密函数
在控制台中查看各个函数代表的含义
import time
import random
import requests
timestamp = int(time.time() * 1000)
rand = int(random.random() * 500 + 100)
mySign = str(timestamp) + '-' + str(rand)
print(mySign)
url = "https://127.0.0.1:5000/api/C14L12"
headers = {
"sign": mySign,
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
"referer":"https://127.0.0.1:5000/api/C14L12"
}
res = requests.get(url, headers=headers)
print(res.json())