CVE-2025-59953 CrowdStrike LogScale · LogScale

Detect LMDeploy Pickle Deserialization RCE via zmq_rpc.call_and_response() (CVE-2025-59953) in CrowdStrike LogScale

Detects exploitation of CVE-2025-59953, a critical (CVSS 9.8) unsafe Python pickle deserialization remote code execution vulnerability in InternLM's LMDeploy. The ZeroMQ RPC layer (zmq_rpc.call_and_response()) deserializes attacker-controlled messages with Python's pickle module, allowing an unauthenticated attacker who can reach the internal ZMQ RPC sockets to execute arbitrary code via a malicious pickle payload (CWE-502). Affected versions are >= 0.9.1 and < 0.10.2; fixed in 0.10.2. This detection surfaces suspicious child processes spawned by the LMDeploy Python service, anomalous inbound connections to LMDeploy ZMQ RPC ports, and pickle __reduce__ gadget indicators in traffic/logs.

MITRE ATT&CK

Tactic
Initial Access Execution

LogScale Detection Query

CrowdStrike LogScale (LogScale)
cql
#event_simpleName=ProcessRollup2
| ParentBaseFileName=/^(python|python3|lmdeploy|uvicorn|gunicorn)$/i
| CommandLine=/lmdeploy|zmq_rpc|api_server|turbomind/i OR ParentCommandLine=/lmdeploy|zmq_rpc|api_server|turbomind/i
| FileName=/^(sh|bash|dash|zsh|nc|ncat|curl|wget|whoami|id|perl|ruby|cmd\.exe|powershell\.exe)$/i
| table([@timestamp, aid, ComputerName, ParentBaseFileName, ParentCommandLine, FileName, CommandLine, UserName])
critical severity high confidence

CrowdStrike CQL detecting suspicious child processes spawned by LMDeploy Python services.

Data Sources

Falcon ProcessRollup2EDR

Required Tables

ProcessRollup2

False Positives & Tuning

  • Legitimate model-load shell wrappers
  • Interactive admin diagnostics
  • Automated weight-fetch curl/wget activity

Other platforms for CVE-2025-59953


Testing Methodology

Validate this detection against 3 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.

  1. Test 1Simulate LMDeploy pickle RCE child shell spawn

    Expected signal: Process-creation event with parent image lmdeploy_sim (python) spawning /bin/sh executing id/whoami

  2. Test 2Malicious pickle __reduce__ gadget execution (lab)

    Expected signal: python3 process invoking os.system which spawns sh -c touch, plus creation of /tmp/cve_2025_59953_poc

  3. Test 3Inbound connection to LMDeploy ZMQ RPC port

    Expected signal: Network connection event to TCP/5555 carrying a pickle protocol marker (\x80) payload


Response Playbook

Triage

  1. Confirm the LMDeploy version on the affected host (pip show lmdeploy); any version >= 0.9.1 and < 0.10.2 is vulnerable and should be treated as exploitable.
  2. Identify the parent LMDeploy/Python process and inspect its command line for api_server/turbomind/zmq_rpc arguments and the listening ZMQ RPC ports.
  3. Review the suspicious child process command line, user context, and working directory to determine whether execution is malicious or benign automation.
  4. Correlate inbound network connections to the LMDeploy ZMQ RPC sockets around the process-spawn timestamp to identify the source host.

Containment

  1. Isolate the affected host/container from the network to stop further RPC-delivered pickle payloads.
  2. Restrict access to LMDeploy ZMQ RPC ports via firewall/security-group rules so only trusted internal hosts can reach them, and stop the exposed api_server if not needed.
  3. Upgrade LMDeploy to 0.10.2 or later on all affected systems before returning them to service.

Evidence Collection

  1. Capture the full process tree, command lines, and environment of the LMDeploy service and any spawned children.
  2. Preserve ZMQ RPC endpoint logs and any packet captures of traffic to the RPC ports, which may contain the pickle payload.
  3. Collect the LMDeploy application logs, container image digest, and pip freeze output for version confirmation.

Escalation Criteria

  • !Escalate to incident response if any child process performed reconnaissance, credential access, lateral movement, or outbound C2 connections.
  • !Escalate if the LMDeploy RPC port was reachable from untrusted networks (internet-exposed) or if payload delivery from an external source is confirmed.

Investigation Guide

Related Techniques

Forensic Artifacts

  • >Process-creation records showing python/lmdeploy spawning shell or network utilities
  • >ZMQ RPC socket logs and packet captures containing pickle opcodes (e.g. leading \x80 protocol markers and 'c__builtin__' / posix system references)
  • >LMDeploy application and container logs around the spawn timestamp
  • >pip metadata (lmdeploy version) confirming exposure window

Tuning Guidance

Baseline the legitimate child processes of your LMDeploy deployment (e.g. nvidia-smi, environment wrappers, health-check curl) and add them to an allowlist keyed on parent command line plus child image plus arguments. Focus alerting on interactive shells, netcat, and reverse-shell patterns. If LMDeploy runs in a locked-down container that never legitimately spawns shells, tighten to alert on ANY unexpected child process. Prioritize hosts where the ZMQ RPC port is reachable beyond localhost.


Hunting Queries

Hunts for LMDeploy service processes spawning shell/network child processes across the fleet.

Hunting — KQL
kql
DeviceProcessEvents | where InitiatingProcessCommandLine has_any ("lmdeploy","zmq_rpc","api_server") | where FileName in~ ("sh","bash","nc","curl","wget") | summarize count() by DeviceName, InitiatingProcessCommandLine, FileName, bin(Timestamp,1h)
Hunting — SPL
spl
index=edr (parent_process=*lmdeploy* OR parent_process=*zmq_rpc*) process_name IN ("sh","bash","nc","curl","wget") | stats count by host parent_process process_name

Atomic Red Team Tests

Test 1 Simulate LMDeploy pickle RCE child shell spawn
linux

Emulates the post-exploitation signal by having a process named like the LMDeploy service spawn a shell command, matching the detection logic without exploiting a real instance.

Command

bash
cp /usr/bin/python3 /tmp/lmdeploy_sim 2>/dev/null; /tmp/lmdeploy_sim -c "import subprocess; subprocess.call(['/bin/sh','-c','id; whoami'])"

Cleanup

bash
rm -f /tmp/lmdeploy_sim

Expected Telemetry

Process-creation event with parent image lmdeploy_sim (python) spawning /bin/sh executing id/whoami

Expected Detection

KQL/SPL/EQL rules fire on the python-parent -> sh child correlation

Test 2 Malicious pickle __reduce__ gadget execution (lab)
linux

Deserializes a locally crafted malicious pickle in an isolated lab to reproduce the code-execution primitive behind CVE-2025-59953.

Command

bash
python3 -c "import pickle,os,base64; payload=pickle.dumps(type('e',(object,),{'__reduce__':lambda s:(os.system,('touch /tmp/cve_2025_59953_poc',))})()); pickle.loads(payload)"

Cleanup

bash
rm -f /tmp/cve_2025_59953_poc

Expected Telemetry

python3 process invoking os.system which spawns sh -c touch, plus creation of /tmp/cve_2025_59953_poc

Expected Detection

Endpoint rules flag the python-to-shell child process chain and file-creation artifact

Test 3 Inbound connection to LMDeploy ZMQ RPC port
linux

Generates an anomalous inbound TCP connection to a simulated LMDeploy ZMQ RPC listener to validate network-side detection and triage correlation.

Command

bash
python3 -c "import socket,threading,time; srv=socket.socket(); srv.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1); srv.bind(('0.0.0.0',5555)); srv.listen(1); threading.Thread(target=lambda:(time.sleep(1), socket.create_connection(('127.0.0.1',5555)).sendall(b'\x80\x04pickle_payload'))).start(); c,_=srv.accept(); print(c.recv(64)); srv.close()"

Cleanup

bash
pkill -f 'bind..0.0.0.0.,5555' 2>/dev/null; true

Expected Telemetry

Network connection event to TCP/5555 carrying a pickle protocol marker (\x80) payload

Expected Detection

Network/triage correlation flags inbound traffic to the LMDeploy RPC port around a process-spawn event

Related Detections