使用mitmproxy破解双向加密

第一弹

加解密分析与实现

本次测试为代码审计+渗透,所以可以直接分析加密方法。

抓包后发现请求响应均加密

img经分析目标系统使用AES+RSA进行加密。

  1. 客户端使用RSA公钥加密随机生成的AES秘钥,通过header里的encrypted-key字段进行发送。

img

  1. 使用随机生成的AES秘钥加密请求与响应

img所以解密时需要先用RSA私钥解密encrypted-key字段拿到AES秘钥,再使用AES秘钥解密请求与响应即可。

img首先是加解密代码实现,代码如下:

rsa_decrypt()函数用RSA私钥解密。

aes_encrypt()aes_decrypt()函数实现AES加解密。

import base64
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5 as PKCS1_cipher
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad


def rsa_decrypt(encrypt_msg):
    pri_s="MIIExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=="
    private_key = RSA.import_key(base64.b64decode(pri_s))
    cipher = PKCS1_cipher.new(private_key)
    back_text = cipher.decrypt(base64.b64decode(encrypt_msg), 0)
    return back_text.decode('utf-8')

def aes_encrypt(plaintext, key):
    cipher = AES.new(key.encode(), AES.MODE_ECB)
    padded_plaintext = pad(plaintext.encode(), AES.block_size)
    ciphertext = cipher.encrypt(padded_plaintext)
    b64_ciphertext = base64.b64encode(ciphertext).decode()
    return b64_ciphertext

def aes_decrypt(ciphertext, key):
    cipher = AES.new(key.encode(), AES.MODE_ECB)
    plaintext = cipher.decrypt(base64.b64decode(ciphertext))
    unpadded_plaintext = unpad(plaintext, AES.block_size)
    return unpadded_plaintext.decode()


if __name__ == '__main__':
    encrypt_text = "oJfxAkwLXgEQubahEx+sQQz58fXrcFm3PTwBbt7b51cz6Q2onz8Zf5hEyGsuaNaG6D+d/814cHU7y/ASMzf7bYt4XieJNTRxrc1bIGloZ6xjbJOjWvi+QLLueuaI37NWJZnnFgNjZVai5pFzUoKEpVptBixsBnytEQoOlhbxPrvDmcgqMzjD4mL0/3Jy/IWGw+lq3KTo8AATxaxHFbOOe9od1Uf9fTHpKxy5FcvPMSC9AlgfB4N/dDrHP/I1cWXGm3tct8j6t1pSiLh1lOZiAZkA4LDUCU0/tfqKBf4DUyHCs6PyvJX7nBmdrT46xocVb72dRpRJxOQ3c/iToJnV5Q=="
    aes_key = rsa_decrypt(encrypt_text)
    print("AESKEY:", aes_key)

    # aes
    encrypt_text = "uzdGewzerdgrUjoP7BCYeiZt5o3bXp9g5dCE0X+VrS16iWfc8uXRxLjtFpFJj4O2+gqjKqlFpI8Ofy51tOdhc5belXH/s1YxaMVuCLg9V5X6V3Xeu11S0e9XCUJ8y1vJJvWk21bSguJFBfhBe4QhBxUw9Qn6T2a096LWj0JAmkLtj2itLVxQAJW+R49J61Vw39WVCEr1BDufT1DfcQcwWw=="
    decrypted_text = aes_decrypt(encrypt_text, aes_key)
    print("\nDecrypted text:", decrypted_text)

    encrypted_text = aes_encrypt(decrypted_text, aes_key)
    print("\nEncrypted text:", encrypted_text)

运行脚本成功解密AESKEY并且解密请求。

img

注:这里如果没有私钥我们也可以通过hook或者调试拿到aeskey以及其对应的encrypted-key,然后固定aeskey和encrypted-key即可,像第二弹一样,客户端生成aeskey的时候我们就固定它的值(不过这里是pc应用不会搞…)。

mitmproxy实现自动加解密

首先使用mitmproxy解密请求,代码如下:

# mitmproxy --mode upstream:http://127.0.0.1:8080 -s .\de_proxy.py --listen-port 8989 --ssl-insecure
from mitmproxy import http, ctx
import json
from RSAde import *

class DecryptPassword:
    # 解密请求包
    def request(self, flow: http.HTTPFlow) -> None:
        if "xxx.cn" in flow.request.headers["Host"] and flow.request.method=="POST":
            # 解析请求体中的数据
            req_data = flow.request.text
            # 获取encrypted-key,解密获得aeskey
            encrypted_key = flow.request.headers["encrypted-key"]
            aes_key = rsa_decrypt(encrypted_key)
            print("\n\n\n\n\n\n\n"+aes_key)
            print(req_data)
            # 使用aeskey解密消息
            decrypted_text = aes_decrypt(req_data, aes_key)
            print(decrypted_text)
            flow.request.text = decrypted_text



addons = [
    DecryptPassword()
]

使用如下命令跑上面的解密脚本。

mitmproxy --mode upstream:http://127.0.0.1:8080 -s .\de_proxy.py --listen-port 8989 --ssl-insecure
# --mode upstream:http://127.0.0.1:8080表示将流量转发到指定的上游代理服务器
# --listen-port 8989表示监听端口号为8989
# --ssl-insecure表示忽略SSL证书验证,即接受所有SSL连接而不校验证书的有效性。

目标为PC端应用,使用Proxifer转发流量至mitmproxy监听的8989端口,mitmproxy解密后再将请求发给burp。

img此时,请求包已经是明文了

img接下来需要第二个mitmproxy实现加密请求发给服务器,同时解密响应包内容。

# mitmproxy -s .\en_proxy.py --listen-port 8990 --ssl-insecure
from mitmproxy import http, ctx
import json
from RSAde import *


class EncryptPassword:
    # 加密请求包
    def request(self, flow: http.HTTPFlow) -> None:
        if "xxx.cn" in flow.request.headers["Host"] and flow.request.method=="POST":
            # 解析请求体中的数据
            req_data = flow.request.text
            # 获取encrypted-key,解密获得aeskey
            encrypted_key = flow.request.headers["encrypted-key"]
            aes_key = rsa_decrypt(encrypted_key)
            # 使用aeskey加密消息
            encrypted_text = aes_encrypt(req_data, aes_key)
            flow.request.text = encrypted_text

    def response(self, flow: http.HTTPFlow):
        if flow.request.method == 'POST':
            req_data = flow.request.text
            # 获取encrypted-key,解密获得aeskey
            encrypted_key = flow.request.headers["encrypted-key"]
            aes_key = rsa_decrypt(encrypted_key)
            # 处理响应
            datas = flow.response.get_content()
            #print("\n\n\n\n\n\n\n"+aes_key)
            try:
                datas = json.loads(datas.decode())
            except:
                pass
            decrypted_text = aes_decrypt(datas, aes_key)
            flow.response.raw_content = decrypted_text


addons = [
    EncryptPassword()
]

运行命令为,监听的端口为8990

mitmproxy -s .\en_proxy.py --listen-port 8990 --ssl-insecure

burp设置下一级代理为8990,此时mitmproxy接收到burp发来的明文请求,将其再次AES加密发给服务器,同时将服务器发过来的数据进行解密。

img再次抓包,此时请求响应均是解密的

img下面就可以愉快的测试了,运气不错,直接扫出来个SQL注入和Fastjson的RCE

img

第二弹

加解密分析与实现

请求响应均为加密的

img一看这个就知道是RSA+AES,param是真正的参数,使用AES加密,key是用RSA公钥加密的AES秘钥。

加密代码在common.js,下面是生成随机AES加密key的js代码。

img

利用burp固定aes加密的秘钥为return '0123456789123456';

img

固定aes秘钥后,key也固定了,后端用私钥解密出来永远都是0123456789123456

key=8a65c9b957a9f5c75bec431aa3c94b30c5a9fda6f89515c4552c00d0a4f4d69e011435a33deebe92bb2725860ed40a534f458bae0f86f9242ec5675da594d571cf1e121c8ab8b86f13a53a9c6c6622557a2644407822b9d75658a7bb48ef887d904883948578055136c391e1cdc1e4cdf75d23a354a96fcfa87683aaeab8a819

加密函数调试过程:

打断点在aes加密函数处

img调用堆栈处找到调用加密的上一个函数

img加密解密均能正常调用

img这里实现aes加解密使用crypto-js实现的

var CryptoJS = require('crypto-js')

// crypto-js加密
function cryptoEncryption(aseKey,message){ //aseKey为密钥(必须为:8/16/32位),message为要加密的密文
  var encrypt = CryptoJS.AES.encrypt(message,CryptoJS.enc.Utf8.parse(aseKey), {
    mode:CryptoJS.mode.ECB,
    padding:CryptoJS.pad.Pkcs7
  }).toString();
  return encrypt
}
// crypto-js解密
function cryptoDecrypt(aseKey,message){
  var decrypt = CryptoJS.AES.decrypt(message, CryptoJS.enc.Utf8.parse(aseKey), {
    mode: CryptoJS.mode.ECB,
    padding: CryptoJS.pad.Pkcs7
  }).toString(CryptoJS.enc.Utf8);
  return decrypt
}

var aseKey = "12345678" //密钥一致才能进行解密
var encrpytText = "abc12345";
var decryptText = 'KLqoT18E3l+OoDFLwS8DsA=='
console.log(cryptoEncryption(aseKey,encrpytText)); //调用加密方法
console.log(cryptoDecrypt(aseKey,decryptText));//调用解密方法

img

使用python的execjs调用js里的加解密函数

import execjs

js = open('aes.js', encoding='utf-8')
com = execjs.compile(js.read(), cwd="./")

def aes_encrypt(aes_key, data):
    return com.call("cryptoEncryption", aes_key, data)

def aes_decrypt(aes_key, data):
    return com.call("cryptoDecrypt", aes_key, data)

print(aes_encrypt("12345678", "123"))
print(aes_decrypt("12345678", "+ahiJogQTpDxQ8yIGrMGlw=="))

img

后面直接使用mitmproxy解密数据包即可

mitmproxy实现自动加解密

解密请求包的代码:

# mitmproxy --mode upstream:http://127.0.0.1:8080 -s .\aes_dproxy.py --listen-port 8989 --ssl-insecure
from mitmproxy import http, ctx
import urllib
import base64
from aes import *


class DecryptPassword:
    # 解密请求包
    def request(self, flow: http.HTTPFlow) -> None:
        if "192.18.101.76" in flow.request.headers["Host"] and flow.request.method=="POST":
            # 解析请求体中的post数据
            req_data = flow.request.text
            print("\n\n\n\n\n"+req_data)
            print(flow.request.content)
            # 判断是否包含password参数
            if 'param' in req_data:
                req_data=urllib.parse.unquote(req_data)
                # print(req_data)
                # 进行解密操作
                password = req_data.split("&")[0]
                password = password.replace("param=","")
                print(password)
                # 对参数进行解密
                decrypted_password = aes_decrypt("0123456789123456", password)
                decrypted_password = base64.b64decode(decrypted_password)
                print(decrypted_password)
                # print(decrypted_password)
                # 修改JSON数据中的password参数值
                req_data = "param="+decrypted_password.decode()+"&key=8a65c9b957a9f5c75bec431aa3c94b30c5a9fda6f89515c4552c00d0a4f4d69e011435a33deebe92bb2725860ed40a534f458bae0f86f9242ec5675da594d571cf1e121c8ab8b86f13a53a9c6c6622557a2644407822b9d75658a7bb48ef887d904883948578055136c391e1cdc1e4cdf75d23a354a96fcfa87683aaeab8a819"
                print(req_data)
                # 将修改后的JSON数据转换成字符串形式
                # 更新请求体中的数据
                flow.request.text = req_data


addons = [
    DecryptPassword()
]

加密请求包发给服务器,解密响应包的代码(由于用内网客户机器,实现太麻烦,解密响应包的没搞了):

# mitmproxy -s .\aes_eproxy.py --listen-port 8990 --ssl-insecure
from mitmproxy import http, ctx
import urllib
import base64
import mitmproxy
from aes import *


class EncryptPassword:
    # 加密请求包
    def request(self, flow: http.HTTPFlow) -> None:
        if "192.18.101.76" in flow.request.headers["Host"]:
            # 解析请求体中的JSON数据
            req_data = flow.request.text
            print("\n\n\n\n\n"+req_data)
            # 判断是否包含password参数
            if 'param' in req_data:
                req_data=urllib.parse.unquote(req_data)
                print(req_data)
                password = req_data.split("&")[0]
                password = password.replace("param=","")
                print(password)
                # 对参数进行解密
                encrypted_password = base64.b64encode(password.encode()).decode()
                print(encrypted_password)
                encrypted_password = aes_encrypt("0123456789123456", encrypted_password)
                print(encrypted_password)
                # 修改JSON数据中的password参数值
                req_data = "param="+encrypted_password+"&key=8a65c9b957a9f5c75bec431aa3c94b30c5a9fda6f89515c4552c00d0a4f4d69e011435a33deebe92bb2725860ed40a534f458bae0f86f9242ec5675da594d571cf1e121c8ab8b86f13a53a9c6c6622557a2644407822b9d75658a7bb48ef887d904883948578055136c391e1cdc1e4cdf75d23a354a96fcfa87683aaeab8a819"
                print(req_data)
                # 将修改后的JSON数据转换成字符串形式
                # 更新请求体中的数据
                flow.request.text = req_data

    # 解密请求包
    # def response(self, flow:HTTPFlow):
    #     # 解析请求体中的post数据
    #     req_data = json.loads(flow.response.text)
    #     flow.response.set_text('success')
    #     print("\n\n\n\n\n\n\n"+req_data)
        # if 'result' in req_data.keys():
        #     password=req_data["result"]["data"]
        #     print(password)
        #     decrypted_password = aes_decrypt("0123456789123456", password)
        #     print(decrypted_password)
        #     req_data["result"]["data"] = decrypted_password
        #     flow.response.text = req_data

addons = [
    EncryptPassword()
]

如下图所示,实现了自动解密,然后加密请求包给服务器。

img可对账号密码进行爆破枚举等其他操作

img

对于破解JavaScript加密,需要具体了解所使用加密算法和密钥管理方式。在引用的内容中,提到了RSA加密和AES加密两种常见的加密算法。 对于RSA加密,它是一种公钥加密算法,使用公钥进行加密,私钥进行解密。破解RSA加密需要获取私钥,但私钥通常是由加密方保管的,因此破解RSA加密是非常困难的。 对于AES加密,它是一种对称加密算法,使用相同的密钥进行加密和解密。破解AES加密需要获取密钥,但在JavaScript中,密钥通常是在客户端存储的,因此可能存在一些安全问题。然而,要破解AES加密,需要获取存储在客户端的密钥,这通常需要对客户端进行攻击或者获取密钥的访问权限。 总的来说,破解JavaScript加密是一项复杂的任务,需要具备相关的技术和知识。同时,破解加密算法是非法的行为,违反了隐私和安全的原则。因此,建议在合法和合理的情况下使用加密算法,保护数据的安全性。 #### 引用[.reference_title] - *1* *3* [常规 JavaScript 加密大全](https://blog.csdn.net/mxd01848/article/details/130109000)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [常见JavaScript加密算法、JS加密算法](https://blog.csdn.net/qq_43762932/article/details/131042614)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值