[817]JS加密-DES與Base64

image.png

常用的加密有哪些?

對稱加密(加密解密密鑰相同):DES、DES3、AES
非對稱加密(分公鑰私鑰):RSA
信息摘要算法/簽名算法:MD5、HMAC、SHA

學習資源推薦

冷月大佬的博客 : https://lengyue.me/
突破前端反調試–阻止頁面不斷debugger :https://segmentfault.com/a/1190000012359015
嵐光的JavaScript反調試和混淆 :https://0x0d.im/archives/javascript-anti-debug-and-obfuscator.html

基礎流程

以下是可以參考的調試流程(面向新手):

  1. 如果網頁有跳轉,必須勾選 preservelog 防止丟包
  2. 看一下有沒有框架 右鍵查看框架源代碼
  3. 登陸的話儘量使用錯誤密碼 防止跳轉
  4. 查看關鍵登陸包 分析哪些參數是加密的
  5. 使用別的瀏覽器分析哪些參數是固定的值
  6. 初步猜測加密方法
  7. 搜索(md5,aes,des,tripedes,rsa,encrypt,setpubkey,setpublickey)
  • 直接搜索參數
  • pwd=
  • pwd =
  • pwd:
  • pwd :
  • 密碼框地方右鍵 檢查 查看 id name type
    • 原生js方法獲取
      doucumnet.getElementById[“”].value
      doucumnet.getElementByName[“”][0].value
    • jQuery獲取
      alert($(“#id”).val());
      alert($(“input[type=’password’]”).val());
  1. 找到加密的地方(重點)
  2. 調試
  3. 找出所有的加密代碼
  • 從最後一步開始寫起,缺啥找啥
  • 如果找的是函數的話 search 要帶上 function xxx
  • 如果看到加密的地方有個類,並且之後是用 prototype 把方法加在原生對象上的話,要把所有加在原生對象上的方法都找出來
  • 函數找多了沒關係,只要不報錯不會影響結果,但是不能找少了
  • 直接保存整頁JS瀏覽器調試

RSA加密

RSA中比較熟悉的東西是:

  • public key 本地用公鑰加密,服務器上用私鑰解密
  • Encrypt 這個關鍵字
  • 長度是128位或者256路

MD5加密

  • 長度 32 位

DES加密

JS調試實戰案例
  • 爲了避免被刪文,所以這裏就不說是哪個網站了,有需要可私信

  • 我們先參照上面的調試流程抓包,搜索加密參數’password’,經過測試通過’password='這關鍵字找到了加密所在的js。

image

  • 經過測試(步驟7)在文件內搜索’password:'找到加密位置,並通過斷點確認了猜測。

image

image

  • 通過點擊提示的路徑,我們找到以下代碼:

image

  • 找到這裏就可以把需要的js代碼扣出來,然後一步步調試了,通過補齊缺失的代碼,得到以下js加密代碼並運行:
var CryptoJS = CryptoJS || function(u, l) {    var d = {}        , n = d.lib = {}        , p = function() {}        , s = n.Base = {        extend: function(a) {            p.prototype = this;            var c = new p;            a && c.mixIn(a);            c.hasOwnProperty("init") || (c.init = function() {                    c.$super.init.apply(this, arguments)                }            );            c.init.prototype = c;            c.$super = this;            return c        },        create: function() {            var a = this.extend();            a.init.apply(a, arguments);================ 代碼太多了,此處省略 ================var encryptByDES = function(t) {    var e = "e9284d45-cf2a-4e46-9367-f122413ca6b0";    var a = CryptoJS.enc.Utf8.parse(e);    try {        var s = CryptoJS.DES.encrypt(String(t), a, {            mode: CryptoJS.mode.ECB,            padding: CryptoJS.pad.Pkcs7        })    } catch (t) {        console.log(t)    }    return s.toString()}console.log(encryptByDES('11111111111'))
  • 輸出運行結果’+g64648uhmWlN9eoU3Tszw==’,與我們抓包的結果相同。

image

Base64加密

JS調試實戰案例
  • 同樣參照上面的調試流程,搜索加密參數’encodePassword’,經過測試通過’encodePassword ='這關鍵字找到了加密所在的js,並通過斷點驗證

image

  • 找到關鍵加密位置後,查看加密的js文件,直接複製出來即可

image

  • base64加密比較簡單,直接複製補上我們的密碼,輸出的就是加密後的字段了
function Base64() {

    // private property
    _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

    // public method for encoding
    this.encode = function (input) {
        var output = "";
        var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
        var i = 0;
        input = _utf8_encode(input);
        while (i < input.length) {
            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);
            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);

================ 代碼太多了,此處省略 ================

var encodePassWord = new Base64().encode('11111111111')+",";
console.log(encodePassWord)

Python實現加密方法合集

其實上面的步驟不一定都要去手動扣JS, 我們的大Python已經爲我們造好了輪子,如果可以判斷js的加密沒有做其他的更改,我們就可以使用造好的輪子直接實現對應的加密。

所以這裏給大家推薦一個大佬寫的加密代碼合集(我就不獻醜了),記得給大佬來個star
GitHub地址:

https://github.com/dhfjcuff/R-A-M-D-D3-S-M-H/blob/master/RSA-AES-MD5-DES-DES3-MD5-SHA-HMAC.py

內容如下:

# -*- coding:utf-8 -*-
import base64
import rsa
from Crypto.Cipher import AES
from Crypto.PublicKey import RSA
from pyDes import des, CBC, PAD_PKCS5
from Crypto.Cipher import DES3
import hashlib
import hmac


class USE_AES:
    """
    AES
    除了MODE_SIV模式key長度爲:32, 48, or 64,
    其餘key長度爲16, 24 or 32
    詳細見AES內部文檔
    CBC模式傳入iv參數
    本例使用常用的ECB模式
    """

    def __init__(self, key):
        if len(key) > 32:
            key = key[:32]
        self.key = self.to_16(key)

    def to_16(self, key):
        """
        轉爲16倍數的bytes數據
        :param key:
        :return:
        """
        key = bytes(key, encoding="utf8")
        while len(key) % 16 != 0:
            key += b'\0'
        return key  # 返回bytes

    def aes(self):
        return AES.new(self.key, AES.MODE_ECB) # 初始化加密器

    def encrypt(self, text):
        aes = self.aes()
        return str(base64.encodebytes(aes.encrypt(self.to_16(text))),
                   encoding='utf8').replace('\n', '')  # 加密

    def decodebytes(self, text):
        aes = self.aes()
        return str(aes.decrypt(base64.decodebytes(bytes(
            text, encoding='utf8'))).rstrip(b'\0').decode("utf8"))  # 解密


class USE_RSA:
    """
    生成密鑰可保存.pem格式文件
    1024位的證書,加密時最大支持117個字節,解密時爲128;
    2048位的證書,加密時最大支持245個字節,解密時爲256。
    加密大文件時需要先用AES或者DES加密,再用RSA加密密鑰,詳細見文檔
    文檔:https://stuvel.eu/files/python-rsa-doc/usage.html#generating-keys
    """
    def __init__(self, number=1024):
        """
        :param number: 公鑰、私鑰
        """
        self.pubkey, self.privkey = rsa.newkeys(number)

    def rsaEncrypt(self, text):
        """
        :param test: str
        :return: bytes
        """
        content = text.encode('utf-8')
        crypto = rsa.encrypt(content, self.pubkey)
        return crypto

    def rsaDecrypt(self, text):
        """
        :param text:bytes
        :return: str
        """
        content = rsa.decrypt(text, self.privkey)
        con = content.decode('utf-8')
        return con

    def savePem(self, path_name, text):
        """
        :param path_name: 保存路徑
        :param text: str
        :return:bytes
        """
        if "PEM" in path_name.upper():
            path_name = path_name[:-4]
        with open('{}.pem'.format(path_name), 'bw') as f:
            f.write(text.save_pkcs1())

    def readPem(self, path_name, key_type):
        """
        :param path_name: 密鑰文件
        :param key_type:類型
        :return:
        """
        if 'pubkey' in key_type:
            self.pubkey = rsa.PublicKey.load_pkcs1(path_name)
        else:
            self.privkey = rsa.PublicKey.load_pkcs1(path_name)
        return True

    def sign(self, message, priv_key=None, hash_method='SHA-1'):
        """
        生成明文的哈希簽名以便還原後對照
        :param message: str
        :param priv_key:
        :param hash_method: 哈希的模式
        :return:
        """
        if None == priv_key:
            priv_key = self.privkey
        return rsa.sign(message.encode(), priv_key, hash_method)

    def checkSign(self, mess, result, pubkey=None):
        """
        驗證簽名:傳入解密後明文、簽名、公鑰,驗證成功返回哈希方法,失敗則報錯
        :param mess: str
        :param result: bytes
        :param pubkey:
        :return: str
        """
        if None == pubkey:
            pubkey = self.privkey
        try:
            result = rsa.verify(mess, result, pubkey)
            return result
        except:
            return False


class USE_DES:
    """
    des(key,[mode], [IV], [pad], [pad mode])
    key:必須正好8字節
    mode(模式):ECB、CBC
    iv:CBC模式中必須提供長8字節
    pad:填充字符
    padmode:加密填充模式PAD_NORMAL or PAD_PKCS5
    """
    def __init__(self, key, iv):
        if not isinstance(key, bytes):
            key = bytes(key, encoding="utf8")
        if not isinstance(iv, bytes):
            iv = bytes(iv, encoding="utf8")
        self.key = key
        self.iv = iv

    def encrypt(self, text):
        """
        DES 加密
        :param text: 原始字符串
        :return: 加密後字符串,bytes
        """
        if not isinstance(text, bytes):
            text = bytes(text, "utf-8")
        secret_key = self.key
        iv = self.iv
        k = des(secret_key, CBC, iv, pad=None, padmode=PAD_PKCS5)
        en = k.encrypt(text, padmode=PAD_PKCS5)
        return en

    def descrypt(self, text):
        """
        DES 解密
        :param text: 加密後的字符串,bytes
        :return:  解密後的字符串
        """
        secret_key = self.key
        iv = self.iv
        k = des(secret_key, CBC, iv, pad=None, padmode=PAD_PKCS5)
        de = k.decrypt(text, padmode=PAD_PKCS5)
        return de.decode()


class USE_DES3:
    """
    new(key, mode, *args, **kwargs)
    key:必須8bytes倍數介於16-24
    mode:
    iv:初始化向量適用於MODE_CBC、MODE_CFB、MODE_OFB、MODE_OPENPGP,4種模式
        ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB``長度爲8bytes
        ```MODE_OPENPGP```加密時8bytes解密時10bytes
        未提供默認隨機生成
    nonce:僅在 ``MODE_EAX`` and ``MODE_CTR``模式中使用
            ``MODE_EAX``建議16bytes
            ``MODE_CTR``建議[0, 7]長度
            未提供則隨機生成
    segment_size:分段大小,僅在 ``MODE_CFB``模式中使用,長度爲8倍數,未指定則默認爲8
    mac_len:適用``MODE_EAX``模式,身份驗證標記的長度(字節),它不能超過8(默認值)
    initial_value:適用```MODE_CTR```,計數器的初始值計數器塊。默認爲**0**。
    """
    def __init__(self, key):
        self.key = key
        self.mode = DES3.MODE_ECB

    def encrypt(self, text):
        """
        傳入明文
        :param text:bytes類型,長度是KEY的倍數
        :return:
        """
        if not isinstance(text, bytes):
            text = bytes(text, 'utf-8')
        x = len(text) % 8
        text = text+b'\0'*x
        cryptor = DES3.new(self.key, self.mode)
        ciphertext = cryptor.encrypt(text)
        return ciphertext

    def decrypt(self, text):
        cryptor = DES3.new(self.key, self.mode)
        plain_text = cryptor.decrypt(text)
        st = str(plain_text.decode("utf-8")).rstrip('\0')
        return st


def USE_MD5(test):
    if not isinstance(test, bytes):
        test = bytes(test, 'utf-8')
    m = hashlib.md5()
    m.update(test)
    return m.hexdigest()


def USE_HMAC(key, text):
    if not isinstance(key, bytes):
        key = bytes(key, 'utf-8')
    if not isinstance(text, bytes):
        text = bytes(text, 'utf-8')
    h = hmac.new(key, text, digestmod='MD5')
    return h.hexdigest()


def USE_SHA(text):
    if not isinstance(text, bytes):
        text = bytes(text, 'utf-8')
    sha = hashlib.sha1(text)
    encrypts = sha.hexdigest()
    return encrypts


if __name__ == '__main__':
    aes_test = USE_AES("assssssssdfasasasasa")
    a = aes_test.encrypt("測試")
    b = aes_test.decodebytes(a)
    rsa_test = USE_RSA()
    a = rsa_test.rsaEncrypt("測試加密")
    b = rsa_test.rsaDecrypt(a)
    des_test = USE_DES(b"12345678", b"12345678")
    a = des_test.encrypt("測試加密")
    b = des_test.descrypt(a)
    des3_test = USE_DES3(b"123456789qazxswe")
    a = des3_test.encrypt("測試加密")
    b = des3_test.decrypt(a)
    md5_test = USE_MD5("測試簽名")
    hmac_test = USE_HMAC("123456", "測試")
    sha_test = USE_SHA("測試加密")

小結

本文簡單介紹了關於JS調試加密字段的流程,並且分別調試了關於DES與Base64加密的兩個案例。

文中舉例的案例屬於菜鳥級別,但是千萬因爲這樣就小瞧JS逆向這門學問,因爲上面寫的案例其實連js逆向入門的門檻都沒跨過。

來源:
https://mp.weixin.qq.com/s/e0jFdh0hz4ro89i80SJuRA
http://xianyucoder.cn/2019/05/16/js%E5%8A%A0%E5%AF%86%E5%AD%A6%E4%B9%A001-%E5%9F%BA%E7%A1%80/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章