浅浅分析宝塔WAF网页动态解密

前言 看了一眼一个朋友的网站, 都用上宝塔的动态解密了... 我这好奇心一下就上来了 网页解密 初步查看 直接F12看一眼, 发现页面内容是正常的, 那么index.html应该是一开始就被WAF替换了, 然后加载的btwaf_aes_forge_xxxx.js应该只是AES工具库

前言

看了一眼一个朋友的网站, 都用上宝塔的动态解密了... 我这好奇心一下就上来了

网页解密

初步查看

直接F12看一眼, 发现页面内容是正常的, 那么index.html应该是一开始就被WAF替换了, 然后加载的btwaf_aes_forge_xxxx.js应该只是AES工具库

查看Cookie, 发现Cookie中多了两个值

分析

直奔index.html看script, 发现这纯纯就是被Obfuscator混淆过的, 直接扔去deobfuscate.io去混淆, 发现有形如:

// 调用函数_0x38b8的字符串混淆没有去除
document.querySelector(_0x38b8("0x13", "jlJv"))[_0x38b8("0x2f", ")0Uo")][_0x38b8("0x1a", "LL)M")] = _0x38b8("0x8", "^[5Y");
var _0x18d8d3 = window[_0x38b8("0x1", "dVLj")][_0x38b8("0x11", "^[5Y")];
var _0x5ceda4 = forge.md[_0x38b8("0x0", "YFaR")][_0x38b8("0x2", "FbCr")]();
var _0x46b71e = _0x5ceda4[_0x38b8("0xe", "9(gM")](_0x18d8d3);

选择写代码处理AST进行去除:

// 依赖acorn, escodegen, acorn-walk
const acorn = require('acorn')
const escodegen = require('escodegen')
const walk = require('acorn-walk')
const fs = require('fs')

/*
从混淆后代码里扣下来的
*/
var _0xdc14 = ["YgtTSFHCrQ==", "w6PCuSjDg0k=", "w4wsw7M5w4sV", "wpJ1wqXCo8OWMQ==", "wq/Dsh5AFUPCpVAd", "G8OKVsO8Kw==", "bQvCky3Chw4=", "G0NHw4EH", "CzQROcORIB4cwrQBTQc=", "KXNGd8O9", "wqIKw67DjMK9Dg==", "wofDhXdDZsONUhPDlMOnLFIYLQ==", "wr4Mw6PCkcOpXA==", "VMKhY0DCosO1wrIOGQ==", "w6LCpyLDgVbDtw==", "wqY2UMOU", "w7LCkcKRw6A=", "A8O5B8O1w5V9wo7Cgl4=", "w4lpKcKGw4LDh8OoXcOvwpNrSRt7wr8=", "wrbCgcOgwpklwoJjE1BQcQ9EwrzCv2fDuMKGWmwOwpDDvDsSwpUUQADDocOXL8ODw51awqBWFsO2w40lw5s1w4HDmjTCjMOQfSjDicKdccK2w5U=", "woVpwq7CocOJ", "GWIhwrbDiMOqIg==", "wpPDp8Kl", "LkMiRjgt", "BcO5E8Ouwptx", "wpLDvcKmwoJHYA==", "wqXCv8ORw6RrWg==", "KjUOTghV", "w75cwrHDrQ==", "wpJ2wqTCsMOjMxnCmcOV", "M2lRfsOqw4TCihbDvw==", "w6jDvgRHCHM=", "w4bCoMKrwqHDtRoK", "wpZcwqzCnQI=", "wp0Cwr4=", "w4Mmw7I1w5YY", "H8O5HsOl", "JsKnwrQVMVrDrA==", "VsOvwpEew7PDlgg=", "w44mw6o=", "IiUOahRMwp0=", "w4bCk8OBf8Okw4A=", "w50qfMOrD2nCinAy", "OWtQaMO9", "GzINNMOA", "HsO+KsKP", "wpMMwqHDlBrDnA==", "TcO0wpo=", "wqvDvQRGDw==", "egfCgBzCnRcB"];
  (function (_0xec2f8c, _0xdc145) {
    var _0x38b800 = function (_0x32eaf6) {
      while (--_0x32eaf6) {
        _0xec2f8c.push(_0xec2f8c.shift());
      }
    };
    _0x38b800(++_0xdc145);
  })(_0xdc14, 162);
  var _0x38b8 = function (_0xec2f8c, _0xdc145) {
    _0xec2f8c = _0xec2f8c - 0;
    var _0x38b800 = _0xdc14[_0xec2f8c];
    if (_0x38b8.acwAJB === undefined) {
      (function () {
        var _0x6e6627 = function () {
          var _0x421212;
          try {
            _0x421212 = Function("return (function() {}.constructor(\"return this\")( ));")();
          } catch (_0x465179) {
            _0x421212 = window;
          }
          return _0x421212;
        };
        var _0x2dde24 = _0x6e6627();
        if (!_0x2dde24.atob) {
          _0x2dde24.atob = function (_0x36284a) {
            var _0x448c8d = String(_0x36284a).replace(/=+$/, "");
            var _0x13d4e1 = "";
            var _0x201742 = 0;
            var _0x57c50a;
            var _0xcfdd65;
            for (var _0xdd164a = 0; _0xcfdd65 = _0x448c8d.charAt(_0xdd164a++); ~_0xcfdd65 && (_0x57c50a = _0x201742 % 4 ? _0x57c50a * 64 + _0xcfdd65 : _0xcfdd65, _0x201742++ % 4) ? _0x13d4e1 += String.fromCharCode(255 & _0x57c50a >> (-2 * _0x201742 & 6)) : 0) {
              _0xcfdd65 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(_0xcfdd65);
            }
            return _0x13d4e1;
          };
        }
      })();
      var _0x171f74 = function (_0x1255dc, _0x3d9a3b) {
        var _0x2d4570 = [];
        var _0x46ad2f = 0;
        var _0x45d77d;
        var _0x142035 = "";
        var _0x1d1cd0 = "";
        _0x1255dc = atob(_0x1255dc);
        var _0x2bc9a5 = 0;
        for (var _0x42f1e5 = _0x1255dc.length; _0x2bc9a5 < _0x42f1e5; _0x2bc9a5++) {
          _0x1d1cd0 += "%" + ("00" + _0x1255dc.charCodeAt(_0x2bc9a5).toString(16)).slice(-2);
        }
        _0x1255dc = decodeURIComponent(_0x1d1cd0);
        var _0x1b46f2;
        for (_0x1b46f2 = 0; _0x1b46f2 < 256; _0x1b46f2++) {
          _0x2d4570[_0x1b46f2] = _0x1b46f2;
        }
        for (_0x1b46f2 = 0; _0x1b46f2 < 256; _0x1b46f2++) {
          _0x46ad2f = (_0x46ad2f + _0x2d4570[_0x1b46f2] + _0x3d9a3b.charCodeAt(_0x1b46f2 % _0x3d9a3b.length)) % 256;
          _0x45d77d = _0x2d4570[_0x1b46f2];
          _0x2d4570[_0x1b46f2] = _0x2d4570[_0x46ad2f];
          _0x2d4570[_0x46ad2f] = _0x45d77d;
        }
        _0x1b46f2 = 0;
        _0x46ad2f = 0;
        for (var _0x74d41e = 0; _0x74d41e < _0x1255dc.length; _0x74d41e++) {
          _0x1b46f2 = (_0x1b46f2 + 1) % 256;
          _0x46ad2f = (_0x46ad2f + _0x2d4570[_0x1b46f2]) % 256;
          _0x45d77d = _0x2d4570[_0x1b46f2];
          _0x2d4570[_0x1b46f2] = _0x2d4570[_0x46ad2f];
          _0x2d4570[_0x46ad2f] = _0x45d77d;
          _0x142035 += String.fromCharCode(_0x1255dc.charCodeAt(_0x74d41e) ^ _0x2d4570[(_0x2d4570[_0x1b46f2] + _0x2d4570[_0x46ad2f]) % 256]);
        }
        return _0x142035;
      };
      _0x38b8.ZmStqO = _0x171f74;
      _0x38b8.iOfGRj = {};
      _0x38b8.acwAJB = true;
    }
    var _0x32eaf6 = _0x38b8.iOfGRj[_0xec2f8c];
    if (_0x32eaf6 === undefined) {
      if (_0x38b8.WLIatA === undefined) {
        _0x38b8.WLIatA = true;
      }
      _0x38b800 = _0x38b8.ZmStqO(_0x38b800, _0xdc145);
      _0x38b8.iOfGRj[_0xec2f8c] = _0x38b800;
    } else {
      _0x38b800 = _0x32eaf6;
    }
    return _0x38b800;
  };


/*
AST处理部分, 实际上就是把函数调用转成字面量了
*/
let AST = acorn.parse(fs.readFileSync('btwaf.js', 'utf8'))
walk.simple(
    AST,
    {
      CallExpression(node) {
          if (node.callee.type == 'Identifier' && node.callee.name === '_0x38b8') {
              node.type = 'Literal';
              node.value = _0x38b8(node.arguments[0].value, node.arguments[1].value);
          }
      }
    }
  )
console.log(escodegen.generate(AST))

经过这两波处理后, 代码就好看多了:

function raoction() {
    n = 0;
    t = Object.prototype.hasOwnProperty;
    i = '1651sd5f1sf';
    if (undefined === n) {
        n = i;
    }
    var r = t.call(this, 'number' == typeof n ? i + ': ' + n + ' (see https://github.com/apollographql/invariant-packages)' : n) || this;
    r.framesToPop = 1;
    r.name = i;
}
;
var f1 = function (b, a) {
    a.push(b);
    f2(b, a);
};
var f2 = function (b, a) {
    b.push(a);
    f1(a, b);
};
var oncheck = function (isKEY) {
    if (isKEY) {
        return 'parser:@typescript-eslint/parser,ecmaVersion:latest';
    }
    return 'sourceType:module,ecmaFeatures:{jsx:true}';
};
raoction();
var checkF = new RegExp('\\w *\\(\\){.+}');
var checkR = new RegExp('(\\[x|u](\\w){2,4})+');
if (checkF['test'](oncheck['toString']())) {
    f1([1], [2]);
} else if (checkR.test(oncheck.toString())) {
    f1([1], [2], [6], [12]);
}
;
// AES密钥
var raw_key = [
    101, 73, 103, 77, 81, 119, 117, 89, 90, 74, 108, 72, 109, 118, 66, 122, 89, 71, 87, 101, 51, 108, 71, 112, 54, 100, 101, 106, 100, 112, 121, 80
];

// AES使用的TAG
var tag = new Uint8Array([
    35, 34, 100, 103, 8, 20, 13, 159, 117, 120, 125, 253, 186, 165, 183, 214
]);

// AES使用的IV
var iv = new Uint8Array([
    115, 80, 100, 103, 114, 86, 103, 98, 102, 72, 68, 87
]);

window['onload'] = function () {
    var _0x4f1205 = Date['now']();
    var _0x41801c = forge['cipher']['createDecipher']('AES-GCM', raw_key);
    _0x41801c['start']({
        iv: iv,
        tag: tag
    });
    // '......'为页面数据, 过长省略
    var _0x2016db = new Uint8Array('......'['match'](/.{1,2}/g)['map'](_0x1cf997 => parseInt(_0x1cf997, 16)));
    _0x41801c['update'](forge['util']['createBuffer'](_0x2016db));
    var _0x197fc7 = _0x41801c['finish']();
    if (_0x197fc7) {
        var _0x50e333 = new DOMParser()['parseFromString'](_0x41801c['output'], 'text/html');
        var _0x195f90 = Date['now']();
        // 如果Cookie不存在
        if (!_0xb7413f('btwaf-21cb7f37099ce405e82768674d54a499-0711fc5487872cd6')) {
            document.querySelector('.btbox')['style']['display'] = 'block';
            var _0x18d8d3 = window['navigator']['userAgent'];
            var _0x5ceda4 = forge.md['sha256']['create']();
            var _0x46b71e = _0x5ceda4['update'](_0x18d8d3); // 对UA进行SHA-256
            _0xd578ea('btwaf-21cb7f37099ce405e82768674d54a499-0711fc5487872cd6', _0x46b71e['digest']().toHex(), 2592000, '/');
            setTimeout(function () {
                _0x25b2f3(_0x50e333['head']['innerHTML']); // 回填页面文件
            }, Math['max'](3000 - (_0x195f90 - _0x4f1205), 0));
        } else {
            setTimeout(function () {
                _0x25b2f3(_0x50e333['head']['innerHTML']); // 回填页面文件
            }, 0);
        }
    } else {
        document.querySelector('.btbox')['style'].display = 'block';
        window.location['reload']();
    }
    function _0x25b2f3(_0x1f8cfb) {
        document['head']['innerHTML'] = _0x1f8cfb;
        document.open();
        document['write'](_0x41801c['output']);
        document['close']();
    }
    function _0xb7413f(_0x3e0587) {
        const _0x45b33b = encodeURIComponent(_0x3e0587) + '=';
        const _0x77337f = document['cookie']['split'](';');
        for (let _0x52812a = 0; _0x52812a < _0x77337f['length']; _0x52812a++) {
            let _0x430b0c = _0x77337f[_0x52812a]['trim']();
            if (_0x430b0c['indexOf'](_0x45b33b) === 0) {
                return true;
            }
        }
        return false;
    }
    function _0xd578ea(_0x4ee2d8, _0x2fa9fb, _0x306905, _0x4a6bfb) {
        var _0xa14cb4 = new Date();
        _0xa14cb4['setTime'](_0xa14cb4['getTime']() + _0x306905 * 1000);
        var _0x85777 = 'expires=' + _0xa14cb4.toUTCString();
        document['cookie'] = encodeURIComponent(_0x4ee2d8) + '=' + encodeURIComponent(_0x2fa9fb) + '; ' + _0x85777 + '; path=' + _0x4a6bfb;
    }
};

分析代码可知, 其使用AES-GCM模式, 以raw_key 作为Key, iv 作为IV, new Uint8Array(encrypted.match(/.{1,2}/g).map(i => parseInt(i, 16)) 作为密文, tag作为tag, 解密后将解密出的HTML回填, 四个值均可从页面中简单提出

但是抽象的是, 其还有另外一种情况, 此时使用AES-CBC, 值的提取同理(无tag )

解密脚本

GCM模式:

from Crypto.Cipher import AES

# 这四组数据替换为你获取到的值
raw_key = bytes([
    101, 73, 103, 77, 81, 119, 117, 89, 90, 74, 108, 72, 109, 118, 66, 122, 89, 71, 87, 101, 51, 108, 71, 112, 54, 100, 101, 106, 100, 112, 121, 80
])
iv = bytes([
    115, 80, 100, 103, 114, 86, 103, 98, 102, 72, 68, 87
])
tag = bytes([
    35, 34, 100, 103, 8, 20, 13, 159, 117, 120, 125, 253, 186, 165, 183, 214
])
encrypted = '3e0f3209a5a3839e70c6967ac534c10dd17f632a0dd0bf352120665f8dc0ac42e5a91ceb579021d2c394dad3fc7d3e8708309d1841272216eb6e2493face572dd8563cea88bb017c0966fbd5b1bb775448e36cc6a2deeb4f4712f734618aec529aa9de10846eeb0af66762ebf169e72f1349f062c700248a6abf5bc2dc8232b6f37fdd0f83db1c3e81a8f31312fd6a64996714a41d61d0827ba1f63ec689406b5b4fb0b1454913e31f2a9eb7faed921aa1a5124271531d8c1827b403d9bbf017fdd732810ffff8af7beb89d885253e39df7865a1961eb5fb448bf5de5d1c8694c5c2e2327a1130ad3e2e63a5093b9fdfd4fb7555381710250a52f85eb9555dbfb9c90ef1a585c9bf91fffbb4720dc21906c24c1218651df99aab99b02caef658a1836eb5223427d1d0c718be7aff777a00b39e49c8c2c54c972182104bab0c82a9e46989dc1131fd9b13e2ba1df44de7a07f0a97ab210a84cc40aefaf3473424f7caeaa36a0e2096c418c6f2fbf650a1beee157a0bd2ff5da749c9199f6c410b677999c07163662e3c16c2b67645781ce1795ddb03bb683138b3e7d9cc16b4ee777fdd758690552b55cfc973c8793f704f7ffc0709b36f20dc855ad871fd0d1c2012aa50eba074960f6009a1a04e0b81fc605091da6e0003cb1c2934ee1fddef5eecbdffc9878695a5dd8de13e1072ff30d9f5de5e2440396c522c5a12dc4d6a55d6fa7dba1844d38f49e7379d5397c20724a55f2ee9e85eba27f5afd7ce61affa43b261a18dcfde2ed5fc914df517ac392959387828b0cfdac4a985534b1618515955e4227b24834cefef84468c9b53715ee8f1643d171ebd24e46d32720c322590b9577274bb0cc0340d2c93cd70549ba8d22cf4ecd8b34715fc2be2a77632008256d33a419ed6ca98a8c175977ad7dbccfd44a553610cb44e6b5e38e5ca67d35f1bdefb4f3b12fd4139cab0140db125fcc750338ba663c80ede4ab95e600ec577c5cb749512598bbdefa63e7d41cfcbab6dbedf5d82b57755bd0bbd80b77aa2929781d0d2e98d41c616a3cbebf79b3e81476eecf80820a8e9a61d09d4291d17d603fc021a1c0ff0fc50aa691e33dee1ef2b7ee021edb6da81375b0963c544412e20dd45e5893ca2272e8279f1677a9a0c97d375ca73e3458b5d306c7e66c664a185b2f67493b2938a3efb13996e318af004f6b659e7d548f7666de38347960e6bce3a0da4a3c04bf07e420e244c41854b813dc16cf63bb56735eaceda36123ce7486adbfa1364e09af854f5de27a8474b59b84f9199213787e61ccd4f46c47593f2efee3e92e046988a370e19c59b809b7a1df1fcf3b1a7f18e6db9b6346af27945083ef5c89518cd5424f465d187c87ce82bb975248f841f9b630577e00c568b9df366bf1de79ac7c2c39b10a99805faa6a8820a84a681b44fa4b2e107f6c3d3383d6242e244f57fff7e3ac920d03660ad915d87c203c1079dce393eeba720bf22014f75d764f24a86aa5b57cdb3ae28241367ed64a4cfb0712c5e67b0bedad2cd71e3a73c813bfc42b38bf48dde5722ab4a46b66ce38453a83d908558f0043db74d62a19de693c774707713ab81c7dde94ce4cd78d8c62caac082303bb03b55acfd374da32749f148ad08022e8cc884762c7e121a4fe7907f41c4338415a91c4cba107e43f03865a2175225df4475dcf556bb90cde822ec5c47db51faf9039056672d39006d0487bd5ba0a3f139a2070d539b25dad511e5a39788541342ae778fe03fb6dad5ecd93dcc437b97c89cb141e314901698da6ad21b2587015a76c16df16074b445333f1ac2ec2f9d60d819ee50d931ee4fca0cad7fad523ff4b3d75d0043814aa38b73ab4295a44e6ec35adc5a5f7771f19de265ba02e5d3ffc90b9765e83690c71afe7594c36ef242380c9362380aa5c1650b342fdbcfd69442d8b80439f82e402a9e1f444e48c0d48ca1021a3d2338c3d077a38f21354521257b92589e7bc5fcfe9ffc7c09a2f8afc61d0a24bbca101bc40e39342305e165393f46b88beb509df18744508711fbcdd836f3908e615433a4c124b3273f4198506e0b2ed1585aa238187afcec4b4b6dfbb5a55361b15ebdf798cbadc466cd4bde636b3fa3fb138b0a42049b7a25e70a3276c6025079ff1c89f4282b2bffc994fbfd5caf45ca4411f0213637464f2c68d29c61ad7d6e4926e0761a55be5403feefd3343324e8faf7f377b6e83012ee2ba2eaec24d1a1b9d81bd7adcad6f3287c2f7443f1898b49387e8614e81db5fda8ee51220bc6ad9c63d3e9bf65c4acc12c8c3eabf924d3a7e6fc3da55428b7df430534bdcf60f7810aa2095f518610d42b7e19ecfa60a3a31deb80b852fda562c23f1c66c6c4aadb62189ab5c851e53ae5b57b02208072560beda7b1cc4f101c5cd1cab578bc49822d1cbb5b1ad4a1de58ed7a3a3687bec37f9bbd0138d540e3bfd2c889ff65b68b5d1b6b43d8f1b78526358eb704a99512de685d6a25d0693a4b42e1e877dd352ba6bbe552596be3dd0144728d4edae5572fe25e374769968e04349750c8c25850d1a39ebfdca50639130d07932954d3f1cf4113eccf37c78b83c005c44096fd27db4c650a472be4a560db44068e34711ddb6824199f0457314d6fd0b7153d3f2126e7d52a498daab77813b7c55ca021e0e641f08f4de29e8f4c474333d795da52f9e6b0b9f048a8949962985fc6b2715974e7638bb5c7256f5d7a8419f5fdcfb4505899fabac6176eb4f7cadf7416d43d217e09661efaaa2fa68f79752d9e2e0634855a484c77ec432a3fee91e92dc4564dc5c8c0a55e07a29741ebcd95b5b24f237f37ecea2e3b9297b092cc23141479c9fdf2eaa21a4c43cb58029658d0c8f33c2def3b23c3d0a7ea1527821ab9d5e7789697e9bf67df2e301acc978c2bd7ac71f02830ca4f318ade7c81f45e5086757c92a5cc393e2c6a40b792cf8068236d7771600fbfb92db1bf362305bb4f3a266dfb2347e6f95dd8ed0e87b5cbceea7c15b10d7f3c0985d2d88c48a14e13d7aa745c7e350f8c8c5e5d495da577387e697b52768ba422f916288337fa2bd4816e306448d28980e8c9d988df4cf5029e891b918d2a04b713cd074ec2d39ccb7e9ae3aa3c96822cd250283e472c9f209a9811729c476330ef591f68fb0035cb3c22154662df23ec22909a39f9fbcd9c0363981992cb5dcf5b525278f6bf799de06ce1b69f0d5afefaa3f02921832d6bf615ea07f30fdb5db11fa391f7d8d63e443797f623525accba235e489e7e13503d0ddfb8ba23d9150edf1ad34e27ff69af0c17b0beabc157a564983dbfbf58223d0bf49d137af0479506dd6cb762fd6d674ae14ccd4b1ad67c4b34307fe8ee09637afb5fc785ea19051d85c225268ffe7a07b5387ff94cf7936b7cd384c57e70406f01ac3e86d780300e2fe4a40eb776a82e65f1ff7d705be0066cacd42b9978734588491dd6a0d17e86939e3e9d7b8e0bba8326d4784cfbe9f948b5a543d10347a63596fca666881b017dc02c0eb23e5a41350e3bf372bbad3ffa55d8cdaf3201503bccaa21e83aa307abae3f23dc49f0c18f6eebfbafcc469d99f6ccf28a52c270dba3175ea22df694d0ce7052e0fe5064f3c6ef088d32c4b997de9828fb0d175daeb17899487a71040090fc3a7209e9172ea202f580ff001e642bf169196920a96296b518dc5925cd135656f8595d3f4549766c074e9f01afd58540a134e0abd35f3583122fc565dd385495b81f9af36e5c40288d05f37f3de19084d555e83387f75d72346fd571a9b054fe3c1d02597c47b3c87f51afe01aedb5d1c131219a5835044f92834ca32e297daafa03a35278c25835a278d49c46b89362219b3750a5b824f9928b7ec026fcb306bb0d93aee9c8a8f4cc576b6a157aa46ca31ca8bc254af02a16738c9e3b9b70fd8def5eff72a0e8a13aeb579357060be5bb9cd94e51e8fe1d1d2f88a85fd07a26275310acfd1c2fe4e693eb6dde0edee3a4fe53ac086b7f1c824ba1a1d40910654ba7fdd37581f8b2e0113062d014e4bcc38a23899d20dd8174002085bfa4f0b8572d135d700b3c906ea7067249db0b6722e467c8d102552839634b96b7bbbf427ad9245f16bac167a58cdf554ffb5583ed4c2b80737f6e7490706f1687a4713d2b2fabe136c9e627e44491d40a291a775ead8dcc1e1673f05543763c208db08433863a15f3f3c409322759d4e9142481f32cf6d7bb58e1aa43c0668dee2f4d6cb896ca83024d32100343f16de86c1b16c70085d2ec95a5d3fc7d482e8465919be072667fdf85abf65585b57d93dd6844fe24556a7ba866f2d61484b696110fa2a922f205a19edc183f973197ad31b87d55b38163f61672a13b32fcca4926a232de4f311ed87563ea98c0b3255bc4c7decfe7cbedfa1103d89bdb4b1dfeb43b31728b14f08cee1597ad1f685ea26f1bd16ca6a951459a502965bb29392e1e0094fdc83ed0dabc4ff383c94681fc42d2709c67ba068d603f86e250c5a3c692be9a264b0cb812365e6c99d915b7d86f61d55ff0a66c91671181f6737cb7988487d87b7dadb9dbb8fa6cb7a99fade37cf3aeb6557c8a527ef52f7039dea719fb5b0a5c179df68911aba2f75248fde540d49fbd78e989e43311c0ea1f6eca79e19f2def39f3c7ca9fee2b7bb709b709c401ff7536f026483e74fa149b93596a64a30f58eb5835c9182a915e10678d71a9e63429eff3169e2ce756ea8a83d25d561534828f31e3fee87c978c38e28170b23bb8ce509ec2fd2770742630ba399f7df742f7cab1434a11bab1c65b6dd948c81e02ea8774b27d73aee0cdc831dec6e16ba341659b19e0bca7858f039525519570b6c5d777cb2d9e6421fb39803a8fd9e2417ab1ff9ff315532403c1923545c8adab373abfa0db29bda15f6dbf4cc33ffbc0a71f00d675796285d37a779832d39431333a8633cf7b5051285e02439b127a097326e3d7be78d97947f88e7daff06ac6cd70dacdc112401a82e4f433fbb0458f841c3441e5e40e4bcdd76ddf0156f9e61568c9a6920f34ca47a0ee8c249f6312c64f2bfb8df8a02cdf3fda07d07591b1e07118bb712b604e6cbcdff3fd9abbebbc4ee70e6b5e025f8dd63d43c1611bdfbeba881b4e12c1ef67de24bd02ae907c653ffd8032976ac521c7795e6269fc4b3cb3fed9d0f0a8ccf728c5caddafb82a41652dcd16dda3e10504799560050420d0e98803da1df844eac462718f1f2d5a6fdd6c8a296643b33b7c2202b1dfeedd944f203b5c842d36992ec2c48efe3f0e9e3d36ab68d5628f909d3ffddbe4810f0c6ba3e22725682db46298a84e2692e4fc6bbae8ab87f8593b5ca5246916f542f2fd940f3b2dcba04f53beb782f2a64042458dad5372f4da4c83f785866c85896f99b951fd13f9fd17e0977b864e3b323813365357793dd9acb80afc57f5bdb0048ecc019300eb9d9833ee5f0920eff12e7a0894cfd5af8ebbbc325d755ea4e878ed9cc08bc3511c0e29f8bce14e22941f7abea7048a5acca05ee82c6d0f7215ee0edaccdeb0e2d99cac2dab1c2f34f3f848f300842a78ea74ba57a66c8aae282a1a9e2d0b5dfa2032e56bb8394f1503db9245f27035bcfa07688940b8ffbf06c20c45cc55c7ec19195c632985d72675b5c39cf8459439841545509abb13904e1efc1306a0987bb393ce8aebe83d1486762afc69996f46202a0bdc15a9adfd6a834d8b1265f0c079db0ecad936c8019383b233a7d78f4039998a836a7def4f2d3018adf0fdc7668d4f8f6a97c84e9d9a9a5cbf7c996509cae2c48b925a3b692ac43c142bc1e045a260a6b24e6bfdfdaa2c419f835976d2d93e49c52bd976b63ca315ded5d345687c27b222bc754a5138fe0868ffd994cb08f1a3b6ce235dd04eeb328d29b26717ad1efb068d242c3a7fd9b02227afdcf8b5dd9249adad2f61fe1f3ef9eb'  



# 解密
encrypted_bytes = bytes([int(b, 16) for b in encrypted.strip().split()]) if ' ' in encrypted else bytes.fromhex(encrypted)
# 初始化 AES-GCM 解密器
cipher = AES.new(raw_key, AES.MODE_GCM, nonce=iv)
# 添加 tag(GCM 模式下解密时必须)
cipher.update(b'')

# 最终解密结果
plaintext = cipher.decrypt_and_verify(encrypted_bytes, tag)

CBC模式同理, 只不过无TAG, 懒得写了

结语

好耶, 水了一篇文章

LICENSED UNDER CC BY-NC-SA 4.0
Comment