PYTHON   14

wordpress.py

Guest on 12th September 2021 10:08:57 AM

  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. import requests
  4. import re
  5. import json
  6. from random import randint
  7. from core import *
  8.  
  9. class Wordpress:
  10.         url     = "http://wp-example.com"
  11.         version = "0.0.0"
  12.         plugins = {}
  13.         themes  = {}
  14.         index   = None
  15.         agent   = False
  16.         users   = {}
  17.         files   = set()
  18.  
  19.         def __init__(self, url, user_agent, nocheck, max_threads):
  20.                 print info("URL: %s" % url)
  21.                 self.url   = url
  22.                 self.agent = user_agent
  23.                 self.max_threads = int(max_threads)
  24.                 self.random_agent()
  25.                 self.clean_url()
  26.                 self.is_up_and_installed()
  27.                 self.is_wordpress(nocheck)
  28.                 self.is_readme()
  29.                 self.is_debug_log()
  30.                 self.is_backup_file()
  31.                 self.is_xml_rpc()
  32.                 self.is_directory_listing()
  33.                 self.is_robots_text()
  34.                 self.is_common_file()
  35.                 self.full_path_disclosure()
  36.                 self.enum_wordpress_users()
  37.  
  38.  
  39.         """
  40.         name        : clean_url()
  41.         description : set the url to http(s)://example.com/
  42.         """
  43.         def clean_url(self):
  44.                 if self.url[-1] != '/':
  45.                         self.url = self.url + '/'
  46.  
  47.         """
  48.         name        : random_agent()
  49.         description : give a random user agent
  50.         """
  51.         def random_agent(self):
  52.                 if self.agent != "random_agent":
  53.                         self.agent = "Wordpresscan - For educational purpose only !"
  54.                 else:
  55.                         with open('database/user-agents.txt','r') as f:
  56.                                 uas = f.read()
  57.  
  58.                                 # remove '#SOMETHING' and '\n\n'
  59.                                 uas = re.sub("#.*","", uas)
  60.                                 uas = uas.replace("\n\n","")
  61.                                 uas = uas.split('\n')
  62.  
  63.                         random = randint(0, len(uas))
  64.                         self.agent = uas[random]
  65.  
  66.         """
  67.         name        : is_wordpress()
  68.         description : detect a WordPress instance
  69.         """
  70.         def is_wordpress(self, nocheck):
  71.                 self.index = requests.get(self.url, headers={"User-Agent":self.agent}, verify=False)
  72.                 if nocheck == False:
  73.                         if not "wp-" in self.index.text:
  74.                                 print critical("Not a WordPress !")
  75.                                 exit()
  76.  
  77.         """
  78.         name        : is_up_and_installed()
  79.         description : check if a website is up or down, then check the installation and a forced redirect
  80.         """
  81.         def is_up_and_installed(self):
  82.                 try:
  83.                         r = requests.get(self.url, allow_redirects=False, headers={"User-Agent":self.agent} , verify=False)
  84.  
  85.                         if 'location' in r.headers:
  86.  
  87.                                 # Install is not complete
  88.                                 if "wp-admin/install.php" in r.headers['location']:
  89.                                         print critical("The Website is not fully configured and currently in install mode. Call it to create a new admin user.")
  90.                                         exit()
  91.  
  92.                                 # Redirect
  93.                                 print notice("The remote host tried to redirect to: %s" % r.headers['location'])
  94.                                 user_input = str(raw_input("[?] Do you want to follow the redirection ? [Y]es [N]o, "))
  95.  
  96.                                 if user_input.lower() == "y":
  97.                                         self.url = r.headers['location']
  98.  
  99.                                 else:
  100.                                         print critical("Redirection not followed - End of the scan !")
  101.                                         exit()
  102.  
  103.                 except Exception as e:
  104.                         print e
  105.                         print critical("Website down!")
  106.                         exit()
  107.  
  108.  
  109.         """
  110.         name        : is_readme()
  111.         description : get the readme file and extract the version is there is any
  112.         """
  113.         def is_readme(self):
  114.                 r = requests.get(self.url + 'readme.html', headers={"User-Agent":self.agent}, verify=False)
  115.  
  116.                 if "200" in str(r):
  117.                         self.files.add('readme.html')
  118.  
  119.                         # Basic version fingerprinting
  120.                         regex = 'Version (.*)'
  121.                         regex = re.compile(regex)
  122.                         matches = regex.findall(r.text)
  123.  
  124.                         if len(matches) > 0 and matches[0] != None and matches[0] != "":
  125.                                 self.version = matches[0]
  126.                                 print critical("The Wordpress '%s' file exposing a version number: %s" % (self.url+'readme.html', matches[0]))
  127.  
  128.         """
  129.         name        : is_debug_log()
  130.         description : determine if there is a debug.log file
  131.         """
  132.         def is_debug_log(self):
  133.                 r = requests.get(self.url + 'debug.log', headers={"User-Agent":self.agent}, verify=False)
  134.                 if "200" in str(r) and not "404" in r.text :
  135.                         self.files.add('debug.log')
  136.                         print critical( "Debug log file found: %s" % (self.url + 'debug.log') )
  137.  
  138.  
  139.         """
  140.         name        : is_backup_file()
  141.         description : determine if there is any unsafe wp-config backup
  142.         """
  143.         def is_backup_file(self):
  144.                 backup = [
  145.                         'wp-config.php~', 'wp-config.php.save', '.wp-config.php.bck',
  146.                         'wp-config.php.bck', '.wp-config.php.swp', 'wp-config.php.swp',
  147.                         'wp-config.php.swo', 'wp-config.php_bak', 'wp-config.bak',
  148.                         'wp-config.php.bak', 'wp-config.save', 'wp-config.old',
  149.                         'wp-config.php.old', 'wp-config.php.orig', 'wp-config.orig',
  150.                         'wp-config.php.original', 'wp-config.original', 'wp-config.txt',
  151.                         'wp-config.php.txt', 'wp-config.backup', 'wp-config.php.backup',
  152.                         'wp-config.copy', 'wp-config.php.copy', 'wp-config.tmp',
  153.                         'wp-config.php.tmp', 'wp-config.zip', 'wp-config.php.zip',
  154.                         'wp-config.db', 'wp-config.php.db', 'wp-config.dat',
  155.                         'wp-config.php.dat', 'wp-config.tar.gz', 'wp-config.php.tar.gz',
  156.                         'wp-config.back', 'wp-config.php.back', 'wp-config.test',
  157.                         'wp-config.php.test', "wp-config.php.1","wp-config.php.2",
  158.                         "wp-config.php.3", "wp-config.php._inc", "wp-config_inc",
  159.                        
  160.                         'wp-config.php.SAVE', '.wp-config.php.BCK',
  161.                         'wp-config.php.BCK', '.wp-config.php.SWP', 'wp-config.php.SWP',
  162.                         'wp-config.php.SWO', 'wp-config.php_BAK', 'wp-config.BAK',
  163.                         'wp-config.php.BAK', 'wp-config.SAVE', 'wp-config.OLD',
  164.                         'wp-config.php.OLD', 'wp-config.php.ORIG', 'wp-config.ORIG',
  165.                         'wp-config.php.ORIGINAL', 'wp-config.ORIGINAL', 'wp-config.TXT',
  166.                         'wp-config.php.TXT', 'wp-config.BACKUP', 'wp-config.php.BACKUP',
  167.                         'wp-config.COPY', 'wp-config.php.COPY', 'wp-config.TMP',
  168.                         'wp-config.php.TMP', 'wp-config.ZIP', 'wp-config.php.ZIP',
  169.                         'wp-config.DB', 'wp-config.php.DB', 'wp-config.DAT',
  170.                         'wp-config.php.DAT', 'wp-config.TAR.GZ', 'wp-config.php.TAR.GZ',
  171.                         'wp-config.BACK', 'wp-config.php.BACK', 'wp-config.TEST',
  172.                         'wp-config.php.TEST', "wp-config.php._INC", "wp-config_INC"
  173.                         ]
  174.  
  175.                 for b in backup:
  176.                         r = requests.get(self.url + b, headers={"User-Agent":self.agent}, verify=False)
  177.                         if "200" in str(r) and not "404" in r.text :
  178.                                 self.files.add(b)
  179.                                 print critical("A wp-config.php backup file has been found in: %s" % (self.url + b) )
  180.  
  181.  
  182.         """
  183.         name        : is_xml_rpc()
  184.         description : determine if there is an xml rpc interface
  185.         """
  186.         def is_xml_rpc(self):
  187.                 r = requests.get(self.url + "xmlrpc.php", headers={"User-Agent":self.agent}, verify=False)
  188.                 if r.status_code == 405 :
  189.                         self.files.add("xmlrpc.php")
  190.                         print info("XML-RPC Interface available under: %s " % (self.url+"xmlrpc.php") )
  191.  
  192.  
  193.         """
  194.         name        : is_directory_listing()
  195.         description : detect if a directory is misconfigured
  196.         """
  197.         def is_directory_listing(self):
  198.                 directories = ["wp-content/uploads/", "wp-content/plugins/", "wp-content/themes/","wp-includes/", "wp-admin/"]
  199.                 dir_name    = ["Uploads", "Plugins", "Themes", "Includes", "Admin"]
  200.  
  201.                 for directory, name in zip(directories,dir_name):
  202.                         r = requests.get(self.url + directory, headers={"User-Agent":self.agent}, verify=False)
  203.                         if "Index of" in r.text:
  204.                                 self.files.add(directory)
  205.                                 print warning("%s directory has directory listing enabled : %s" % (name, self.url + directory))
  206.  
  207.  
  208.         """
  209.         name        : is_robots_text()
  210.         description : detect if a robots.txt file
  211.         """
  212.         def is_robots_text(self):
  213.                 r = requests.get(self.url + "robots.txt", headers={"User-Agent":self.agent}, verify=False)
  214.                 if "200" in str(r) and not "404" in r.text :
  215.                         self.files.add("robots.txt")
  216.                         print info("robots.txt available under: %s " % (self.url+"robots.txt") )
  217.                         lines = r.text.split('\n')
  218.                         for l in lines:
  219.                                 if "Disallow:" in l:
  220.                                         print info("\tInteresting entry from robots.txt: %s" % (l))
  221.  
  222.         """
  223.         name        : is_common_file()
  224.         description : detect if a common file such as license.txt is present
  225.         """
  226.         def is_common_file(self):
  227.                 files = ["sitemap.xml","license.txt"]
  228.                 for f in files:
  229.                         r = requests.get(self.url + f, headers={"User-Agent":self.agent}, verify=False)
  230.                         if "200" in str(r) and not "404" in r.text :
  231.                                 self.files.add(f)
  232.                                 print info("%s available under: %s " % (f, self.url+f) )
  233.  
  234.         """
  235.         name        : full_path_disclosure()
  236.         description : detect a full path disclosure
  237.         """
  238.         def full_path_disclosure(self):
  239.                 r = requests.get(self.url + "wp-includes/rss-functions.php", headers={"User-Agent":self.agent}, verify=False).text
  240.                 regex = re.compile("Fatal error:.*? in (.*?) on", re.S)
  241.                 matches = regex.findall(r)
  242.  
  243.                 if matches != []:
  244.                         print warning("Full Path Disclosure (FPD) in %s exposing %s" % (self.url + "wp-includes/rss-functions.php", matches[0].replace('\n','')) )
  245.  
  246.  
  247.         """
  248.         name        : enum_wordpress_users()
  249.         description : enumerate every users of the wordpress
  250.         """
  251.         def enum_wordpress_users(self):
  252.                 r = requests.get(self.url + "wp-json/wp/v2/users", headers={"User-Agent":self.agent} , verify=False)
  253.  
  254.                 if "200" in str(r):
  255.                         print notice("Enumerating Wordpress users")
  256.                         users = json.loads(r.text)
  257.                         for user in users:
  258.                                 print info("\tIdentified the following user : %s, %s, %s" % (user['id'], user['name'], user['slug']) )
  259.                         self.users = users
  260.  
  261.  
  262.         """
  263.         name        : to_string()
  264.         description : display a debug view of the object
  265.         """
  266.         def to_string(self):
  267.                 print "--------WORDPRESS----------"
  268.                 print "URL     : %s" % self.url
  269.                 print "Version : %s" % self.version
  270.                 print "Plugins : %s" % self.plugins
  271.                 print "Themes  : %s" % self.themes
  272.                 print "Agent   : %s" % self.agent
  273.                 print "Users   : %s" % self.users
  274.                 print "Files   : %s" % self.files
  275.                 print "---------------------------"

Raw Paste


Login or Register to edit or fork this paste. It's free.