Wordpresscan/engine/scan.py

252 lines
7.6 KiB
Python

#!/usr/bin/python
# -*- coding: utf-8 -*-
import requests
import re
import json
from tornado import ioloop, httpclient
from core import *
from wordpress import *
from lxml import etree
from multiprocessing import Process, Pool
class Scan_Engine:
def __init__(self, wordpress, aggressive):
self.fingerprint_wp_version(wordpress)
self.list_wp_version_vulnerabilities(wordpress, "wordpresses")
if aggressive == False:
self.enumerating_themes_passive(wordpress)
self.enumerating_plugins_passive(wordpress)
else:
self.enumerating_themes_aggressive(wordpress)
self.enumerating_plugins_aggressive(wordpress)
"""
name : fingerprint_wp_version_meta_based(wordpress)
description : detect the version of WordPress based on the meta tag
"""
def fingerprint_wp_version_meta_based(self, wordpress):
regex = re.compile('meta name="generator" content="WordPress (.*?)"')
match = regex.findall(wordpress.index.text)
if match != []:
wordpress.version = match[0]
print critical("WordPress version %s identified from advanced fingerprinting" % wordpress.version)
return True
return False
"""
name : fingerprint_wp_version_feed_based(wordpress)
description : detect the version of WordPress based on the generator tag in index.php/feed/
"""
def fingerprint_wp_version_feed_based(self, wordpress):
r = requests.get(wordpress.url + "index.php/feed", headers={"User-Agent":wordpress.agent}).text
regex = re.compile('generator>https://wordpress.org/\?v=(.*?)<\/generator')
match = regex.findall(r)
if match != []:
wordpress.version = match[0]
print critical("WordPress version %s identified from advanced fingerprinting" % wordpress.version)
return True
return False
"""
name : fingerprint_wp_version_hash_based(wordpress)
description : compare hashes of unique files in order to detect the version
"""
def fingerprint_wp_version_hash_based(self, wordpress):
tree = etree.parse("database/wp_versions.xml")
root = tree.getroot()
# Iterating through 'src' file
for i in range(len(root)):
# Download file
ddl_url = (wordpress.url + root[i].get('src') ).replace('$','')
ddl_name = "/tmp/" + (root[i].get('src').replace('/','-'))
download_file( ddl_url , ddl_name , True )
# Get hash of the file
ddl_hash = md5_hash(ddl_name)
# Delete the file
remove_file(ddl_name)
# Iterating throug 'md5' hash
for j in range(len(root[i])):
if "Element" in str(root[i][j]):
# Detect the version
if ddl_hash == root[i][j].get('md5'):
wordpress.version = root[i][j][0].text
print critical("WordPress version %s identified from advanced fingerprinting" % wordpress.version)
return
"""
name : fingerprint_wp_version(wordpress)
description : launch different methods to get the wordpress version
"""
def fingerprint_wp_version(self, wordpress):
# Meta tag based
if self.fingerprint_wp_version_meta_based(wordpress) != True:
# Feed based <generator>
if self.fingerprint_wp_version_feed_based(wordpress) != True:
# Hash based
self.fingerprint_wp_version_hash_based(wordpress)
"""
name : list_wp_version_vulnerabilities(self, wordpress, file)
description : display info about vulnerabilities affecting the current wordpress
"""
def list_wp_version_vulnerabilities(self, wordpress, file):
# Load json file
with open('database/'+file+'.json') as data_file:
data = json.load(data_file)
# Try to get a close result if the version is not in the list
version = wordpress.version
if data[wordpress.version]["vulnerabilities"] == []:
versions = data.keys()
for v in versions:
if v[:4] in wordpress.version and is_lower(wordpress.version, v, False):
version = v
# Best accurate result
for vuln in data[version]["vulnerabilities"]:
# Basic infos
print warning("\t%s : %s - ID:%s" % (vuln['vuln_type'], vuln['title'] , vuln['id']) )
print info("\tFixed in %s"% vuln['fixed_in'])
# Display references
print info("\tReferences:")
for refkey in vuln['references'].keys():
for ref in vuln['references'][refkey]:
if refkey != 'url':
print "\t\t - %s %s" % (refkey.capitalize(), ref)
else:
print "\t\t - %s" %ref
print ""
"""
name : enumerating_themes_passive(self, wordpress)
description : enumerate every theme used by the wordpress
"""
def enumerating_themes_passive(self, wordpress):
print notice("Enumerating themes from passive detection ...")
# Theme name (css file)
regex = re.compile('wp-content/themes/(.*?)/.*?[css|js].*?ver=([0-9\.]*)')
match = regex.findall(wordpress.index.text)
theme = {}
# Unique theme
for m in match:
# Remove minified and github version
theme_name = m[0]
theme_name = theme_name.replace('-master','')
theme_name = theme_name.replace('.min','')
theme_version = m[1]
if m[0] not in theme.keys():
theme[m[0]] = m[1]
display_vulnerable_component(theme_name, theme_version, "themes")
wordpress.themes = theme
"""
name : enumerating_plugins_passive(self, wordpress)
description : enumerate every plugins used by the wordpress
"""
def enumerating_plugins_passive(self, wordpress):
print notice("Enumerating plugins from passive detection ...")
# Plugin name (js file)
regex = re.compile('wp-content/plugins/(.*?)/.*?[css|js].*?ver=([0-9\.]*)')
match = regex.findall(wordpress.index.text)
plugin = {}
# Unique plugin
for m in match:
# Remove minified and github version
plugin_name = m[0]
plugin_name = plugin_name.replace('-master','')
plugin_name = plugin_name.replace('.min','')
plugin_version = m[1]
if plugin_name not in plugin.keys() and m[1]!='1':
plugin[plugin_name] = m[1]
display_vulnerable_component(plugin_name, plugin_version, "plugins")
wordpress.plugins = plugin
"""
name : enumerating_themes_aggressive(self, wordpress)
description : enumerate every themes used by the wordpress
"""
def enumerating_themes_aggressive(self, wordpress):
print notice("Enumerating themes from aggressive detection ...")
# Load json file
with open('database/themes.json') as data_file:
data = json.load(data_file)
# Run through every themes
global iter_aggressive
iter_aggressive = 0
http_client = httpclient.AsyncHTTPClient()
for plugin in data.keys():
iter_aggressive += 1
http_client.fetch(wordpress.url+'/wp-content/themes/' + plugin, aggressive_request_themes, method='HEAD') == True
ioloop.IOLoop.instance().start()
"""
name : enumerating_plugins_aggressive(self, wordpress)
description : enumerate every plugins used by the wordpress
"""
def enumerating_plugins_aggressive(self, wordpress):
print notice("Enumerating plugins from aggressive detection ...")
# Load json file
with open('database/plugins.json') as data_file:
data = json.load(data_file)
# Run through every plugin
global iter_aggressive
iter_aggressive = 0
http_client = httpclient.AsyncHTTPClient()
for plugin in data.keys():
iter_aggressive += 1
http_client.fetch(wordpress.url+'/wp-content/plugins/' + plugin, aggressive_request_plugins, method='HEAD') == True
ioloop.IOLoop.instance().start()
def aggressive_request_plugins(response):
if (response.code) == 200:
display_vulnerable_component(response.effective_url.split('/')[-2], "Unknown", "plugins")
global iter_aggressive
iter_aggressive-= 1
if iter_aggressive == 0:
ioloop.IOLoop.instance().stop()
def aggressive_request_themes(response):
if (response.code) == 200:
display_vulnerable_component(response.effective_url.split('/')[-2], "Unknown", "themes")
global iter_aggressive
iter_aggressive-= 1
if iter_aggressive == 0:
ioloop.IOLoop.instance().stop()