Update to v0.4

This commit is contained in:
Jan Rude
2015-03-29 19:13:03 +02:00
parent 265a0c688d
commit 12fbf5de4f
28 changed files with 16021 additions and 882 deletions

View File

@@ -1,3 +0,0 @@
#!/usr/bin/env python
pass

83
lib/check_installation.py Normal file
View File

@@ -0,0 +1,83 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------------
# Typo3 Enumerator - Automatic Typo3 Enumeration Tool
# Copyright (c) 2015 Jan Rude
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/)
#-------------------------------------------------------------------------------
import re
import sys
from colorama import Fore
from lib.request import Request
from lib.output import Output
class Typo3_Installation:
"""
This class checks, if Typo3 is used on the domain.
If Typo3 is used, a link to the login page is shown.
name: URL of the domain
extensions: Extensions to check for
typo3: If Typo3 is installed
"""
@staticmethod
def run(domain):
login_found = Typo3_Installation.search_login(domain)
if not login_found:
Typo3_Installation.check(domain)
# Searching for Typo3 references in HTML comments
@staticmethod
def check(domain):
response = Request.get_request(domain.get_name(), '/')
try:
print(Fore.GREEN + '[!] fe_typo_user:'.ljust(32) + response[2].cookies['fe_typo_user'] + Fore.RESET)
domain.set_typo3()
except:
try:
regex = re.compile('[Tt][Yy][Pp][Oo]3 (\d{1,2}\.\d{1,2}\.[0-9][0-9]?)')
searchVersion = regex.search(response[0])
version = searchVersion.groups()
domain.set_typo3()
domain.set_typo3_version(version[0].split()[0])
return True
except:
try:
regex = re.compile('TYPO3(.*)', re.IGNORECASE)
searchHTML = regex.search(response[0])
searchHTML.groups()[0]
domain.set_typo3()
return True
except:
return False
# Searching Typo3 login page
@staticmethod
def search_login(domain):
response = Request.get_request(domain.get_name(), '/typo3/index.php')
Request.interesting_headers(response[1])
try:
regex = re.compile('<title>(.*)</title>', re.IGNORECASE)
searchTitle = regex.search(response[0])
title = searchTitle.groups()[0]
if 'TYPO3' in title or 'TYPO3 SVN ID:' in response[0]:
domain.set_typo3()
domain.set_login_found()
return True
except:
pass
return False

83
lib/domain.py Normal file
View File

@@ -0,0 +1,83 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------------
# Typo3 Enumerator - Automatic Typo3 Enumeration Tool
# Copyright (c) 2015 Jan Rude
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/)
#-------------------------------------------------------------------------------
class Domain(object):
"""
This class stores following information about a domain:
name: URL of the domain
typo3: If Typo3 is installed
typo3_version: Typo3 Version
login_found: determines of the default login page was found or not
extensions: List of extensions to check for
installed_extensions: List of all installed extensions
"""
def __init__(self, name, ext_state, top=False):
if not ('http' in name):
self.__name = 'http://' + name
else:
self.__name = name
self.__typo3 = False
self.__typo3_version = ''
self.__login_found = False
self.__extension_config = [ext_state, top]
self.__extensions = None
self.__installed_extensions = {}
def get_name(self):
return self.__name
def set_name(self, name):
self.__name = name
def get_extensions(self):
return self.__extensions
def set_extensions(self, extensions):
self.__extensions = extensions
def get_extension_config(self):
return self.__extension_config
def get_installed_extensions(self):
return self.__installed_extensions
def set_installed_extensions(self, extension):
self.__installed_extensions[extension] = False
def set_installed_extensions_version(self, extension, ChangeLog):
self.__installed_extensions[extension] = ChangeLog
def get_typo3(self):
return self.__typo3
def set_typo3(self):
self.__typo3 = True
def set_typo3_version(self, version):
self.__typo3_version = version
def get_typo3_version(self):
return self.__typo3_version
def get_login_found(self):
return self.__login_found
def set_login_found(self):
self.__login_found = True

View File

@@ -1,113 +1,77 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------------
# Typo3 Enumerator - Automatic Typo3 Enumeration Tool
# Copyright (c) 2015 Jan Rude
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/)
#-------------------------------------------------------------------------------
"""
Copyright (c) 2014 Jan Rude
"""
import os.path
from lib.request import Request
from lib.output import Output
from lib.thread_pool import ThreadPool
import re
import os
import sys
import time
import urllib2
from Queue import Queue
try:
from colorama import Fore
except:
pass
from os.path import isfile
from threading import Thread, Lock
from lib import settings
class Extensions:
def __init__(self, ext_state, top):
self.__ext_state = ext_state
self.__top = top
def generate_list():
print ''
for ext_file in settings.EXTENSION_FILE:
if not isfile(os.path.join('extensions', ext_file)):
output("Could not find extension file " + ext_file
+ "\nPossible values are: experimental | alpha | beta | stable | outdated | all", False)
sys.exit(-1)
def load_extensions(self):
extensions = []
for state in self.__ext_state:
ext_file = state + '_extensions'
if not os.path.isfile(os.path.join('extensions', ext_file)):
raise Exception("\n\nCould not find extension file " + ext_file + '!\nTry --update')
with open(os.path.join('extensions', ext_file), 'r') as f:
count = 0
print "[+] Loading:", ext_file
for extension in f:
if settings.TOP_EXTENSION > count:
settings.EXTENSION_LIST.append(extension.split('\n')[0])
count += 1
else:
f.close()
return
def copy():
for extension in settings.EXTENSION_LIST:
settings.in_queue.put(extension)
# Searching installed extensions
# Check version if getting 200 or 403.
def check_extension():
while True:
extension = settings.in_queue.get()
for path in settings.EXTENSION_PATHS:
try:
req = urllib2.Request(settings.DOMAIN + path + extension + '/', None, settings.user_agent)
connection = urllib2.urlopen(req, timeout = settings.TIMEOUT)
connection.close()
check_extension_version(path, extension)
settings.in_queue.task_done()
return
except urllib2.HTTPError, e:
if e.code == 403:
check_extension_version(path, extension)
settings.in_queue.task_done()
return
except urllib2.URLError, e:
pass
#retry = raw_input('Error on checking ' + extension + ': ' + str(e.reason) + '\nRetrying? (y/n) ')
#if retry is 'y':
# settings.in_queue.put(extension)
# if extension is not in any given path, it's not installed
if settings.verbose:
output(extension.ljust(32) + 'not installed', False)
settings.in_queue.task_done()
# Searching version of installed extension
def check_extension_version(path, extension):
settings.EXTENSIONS_FOUND += 1
# if no version information is available, skip version search
if extension in settings.NO_VERSIONINFO:
if settings.verbose:
output(extension.ljust(32) + 'installed (no version information available)', True)
else:
output(extension.ljust(32) + 'installed', True)
else:
try:
request = urllib2.Request(settings.DOMAIN + path + extension +'/ChangeLog', None, settings.user_agent)
response = urllib2.urlopen(request, timeout = settings.TIMEOUT)
changelog = response.read(1500)
response.close()
try:
regex = re.compile("(\d{1,2}\.\d{1,2}\.?[0-9]?[0-9]?[' '\n])")
searchVersion = regex.search(changelog)
version = searchVersion.groups()
output(extension.ljust(32) + 'installed (v' + version[0].split()[0] + ')', True)
except:
try:
regex = re.compile("(\d{2,4}[\.\-]\d{1,2}[\.\-]\d{1,4})")
search = regex.search(changelog)
version = search.groups()
output(extension.ljust(32) + 'installed (last entry from ' + version[0] + ')', True)
except:
if settings.verbose:
output(extension.ljust(32) + 'installed (no version information found)', True)
with open(os.path.join('extensions', ext_file), 'r') as f:
count = 0
for extension in f:
if not(self.__top is None):
if count < self.__top:
extensions.append(extension.split('\n')[0])
count += 1
else:
output(extension.ljust(32) + 'installed', True)
except:
output(extension.ljust(32) + "installed", True)
extensions.append(extension.split('\n')[0])
f.close()
return extensions
def output(message, status):
if settings.COLORAMA:
if status:
print Fore.GREEN + message + Fore.RESET
else:
print Fore.RED + message + Fore.RESET
else:
print message
def search_extension(self, domain, extensions):
thread_pool = ThreadPool()
for ext in extensions:
# search local installation path
thread_pool.add_job((Request.head_request, (domain.get_name(), '/typo3conf/ext/' + ext)))
# search global installation path
thread_pool.add_job((Request.head_request, (domain.get_name(), '/typo3/ext/' + ext)))
thread_pool.start(6)
for installed_extension in thread_pool.get_result():
domain.set_installed_extensions(installed_extension[1][1])
def search_ext_version(self, domain, extension_dict):
thread_pool = ThreadPool()
for extension_path in extension_dict:
thread_pool.add_job((Request.head_request, (domain.get_name(), extension_path + '/ChangeLog')))
thread_pool.add_job((Request.head_request, (domain.get_name(), extension_path + '/Readme.txt')))
thread_pool.start(6, True)
for changelog_path in thread_pool.get_result():
ext, path = self.parse_extension(changelog_path)
domain.set_installed_extensions_version(path, ext[4])
def parse_extension(self, path):
ext = (path[1][1]).split('/')
path = ext[0] + '/' + ext[1] + '/' + ext[2] + '/' + ext[3]
return (ext, path)

View File

@@ -1,120 +0,0 @@
#!/usr/bin/env python
"""
Copyright (c) 2014 Jan Rude
"""
import re
import sys
import requests
import urllib2
from colorama import Fore
from lib import settings
if sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
import msvcrt
# Searching Typo3 login page
def search_login():
try:
r = requests.get(settings.DOMAIN + '/typo3/index.php', allow_redirects=False, timeout=settings.TIMEOUT, headers=settings.user_agent, verify=False)
statusCode = r.status_code
httpResponse = r.text
if statusCode == 200:
return check_title(httpResponse, r.url)
elif (statusCode == 301) or (statusCode == 302):
location = r.headers['location']
answer = ''
if sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
print 'Got redirect to: ' + str(location) + '\nFollow? (y/n) '
answer = msvcrt.getche()
elif sys.platform.startswith('linux'):
answer = raw_input('Got redirect to: ' + str(location) + '\nFollow? (y/n) ')
if answer is 'y':
locsplit = location.split('/')
settings.DOMAIN = locsplit[0] + '//' + locsplit[2]
return 'redirect'
else:
return check_title(httpResponse, r.url)
elif statusCode == 404:
return False
else:
print 'Oops! Got unhandled code:'.ljust(32) + str(statusCode) + ': ' + str(r.raise_for_status())
except requests.exceptions.Timeout:
output('Connection timed out')
except requests.exceptions.TooManyRedirects:
output('Too many redirects')
except requests.exceptions.RequestException as e:
output(str(e))
# Searching for Typo3 references in title
def check_title(response, url):
try:
regex = re.compile('<title>(.*)</title>', re.IGNORECASE)
searchTitle = regex.search(response)
title = searchTitle.groups()[0]
if 'TYPO3' in title or 'TYPO3 SVN ID:' in response:
print 'Typo3 Login:'.ljust(32) + Fore.GREEN + url + Fore.RESET
return True
except:
pass
return False
# Searching for Typo3 references in HTML comments
def check_main_page():
req = urllib2.Request(settings.DOMAIN, None, settings.user_agent)
req.add_header('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8')
try:
connection = urllib2.urlopen(req, timeout = settings.TIMEOUT)
response = connection.read()
connection.close()
try:
cookie = connection.info().getheader('Set-Cookie')
if 'fe_typo_user' in cookie:
return bad_url()
except KeyboardInterrupt:
output('\nReceived keyboard interrupt.\nQuitting...')
exit(-1)
except:
try:
regex = re.compile('TYPO3(.*)', re.IGNORECASE)
searchHTML = regex.search(response)
searchHTML.groups()[0]
try:
regex = re.compile('[Tt][Yy][Pp][Oo]3 (\d{1,2}\.\d{1,2}\.[0-9][0-9]?[' '\n])')
searchVersion = regex.search(response)
version = searchVersion.groups()
settings.TYPO_VERSION = 'Typo3 ' + version[0].split()[0]
except:
pass
return bad_url()
except:
pass
except Exception, e:
if '404' in str(e):
output(str(e) + '\nPlease ensure you entered the right url')
else:
output(str(e))
return 'skip'
return False
def bad_url():
print 'Typo3 Login:'.ljust(32) + 'Typo3 is used, but could not find login'
print ''.ljust(32) + 'This could result in \'no extensions are installed\'.'
print ''.ljust(32) + 'Seems like something is wrong with the given url.'
answer = ''
if sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
print ''.ljust(32) + 'Try anyway (y/n)? '
answer = msvcrt.getch()
elif sys.platform.startswith('linux'):
answer = raw_input(''.ljust(32) + 'Try anyway (y/n)? ')
if answer is 'y':
return True
return 'skip'
# printing error messages
def output(message):
if settings.COLORAMA:
print Fore.RED
print message
if settings.COLORAMA:
print Fore.RESET

View File

@@ -1,22 +1,49 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------------
# Typo3 Enumerator - Automatic Typo3 Enumeration Tool
# Copyright (c) 2015 Jan Rude
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/)
#-------------------------------------------------------------------------------
"""
Copyright (c) 2014 Jan Rude
"""
from Queue import Queue
from colorama import Fore
from threading import Thread, Lock
from lib import settings
# Output thread
def thread():
while settings.out_queue is not settings.out_queue.empty():
try:
extension = settings.out_queue.get()
if not "not installed" in extension:
settings.EXTENSIONS_FOUND += 1
print(extension)
settings.out_queue.task_done()
except Exception, e:
print "Oops! Got:", e
class Output:
"""
This class handles the output
"""
def __init__(self):
pass
def typo3_installation(domain):
print('')
print('[+] Typo3 default login:'.ljust(30) + Fore.GREEN + domain.get_name() + '/typo3/index.php' + Fore.RESET)
print('[+] Typo3 version:'.ljust(30) + Fore.GREEN + domain.get_typo3_version() + Fore.RESET)
print(' | known vulnerabilities:'.ljust(30) + Fore.GREEN + 'http://www.cvedetails.com/version-search.php?vendor=&product=Typo3&version=' + domain.get_typo3_version() + Fore.RESET)
print('')
def interesting_headers(name, value):
string = '[!] ' + name + ':'
print(string.ljust(30) + value)
def extension_output(extens):
if not extens:
print(Fore.RED + ' | No extension found' + Fore.RESET)
else:
for extension in extens:
print(Fore.BLUE + '\n[+] Name: ' + extension.split('/')[3] + '\n' + "-"* 25 + Fore.RESET)
print(' | Location:'.ljust(16) + extension)
if not (extens[extension] == False):
print(' | ' + extens[extension].split('.')[0] + ':'.ljust(4) + (extension + '/'+ extens[extension]))

View File

@@ -1,56 +1,76 @@
#-------------------------------------------------------------------------------
# Typo3 Enumerator - Automatic Typo3 Enumeration Tool
# Copyright (c) 2015 Jan Rude
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/)
#-------------------------------------------------------------------------------
import socket
import urllib2
import os, sys
import re
from colorama import Fore
from lib.request import Request
try:
import socks
except:
print "The module 'SocksiPy' is not installed."
print(Fore.RED + 'The module \'SocksiPy\' is not installed.')
if sys.platform.startswith('linux'):
"Please install it with: sudo apt-get install python-socksipy"
print('Please install it with: sudo apt-get install python-socksipy' + Fore.RESET)
else:
"You can download it from http://socksipy.sourceforge.net/"
print('You can download it from http://socksipy.sourceforge.net/' + Fore.RESET)
sys.exit(-2)
def start_daemon():
if sys.platform.startswith('linux'):
os.system('service privoxy start')
print '[ ok ] Starting privoxy daemon...done.'
elif sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
print "Please make sure Privoxy is running..."
else:
print "You are using", sys.platform, ", which is not supported (yet)."
sys.exit(-2)
# Using Privoxy for all connections
def connect(port):
print "\nChecking connection..."
socks.setdefaultproxy(socks.PROXY_TYPE_HTTP, "127.0.0.1", port, True)
socket.socket = socks.socksocket
try:
url = urllib2.Request('https://check.torproject.org/')
torcheck = urllib2.urlopen(url)
response = torcheck.read()
torcheck.close()
except:
print "Failed to connect through Privoxy!"
print "Please make sure your configuration is right!\n"
sys.exit(-2)
try:
# TODO: Check on privoxy at http://ha.ckers.org/weird/privoxy.html
regex = re.compile("(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})")
searchIP = regex.search(response)
IP = searchIP.groups()[0]
print "Your IP is: ", IP
except:
print "It seems like Privoxy is not used.\nAborting...\n"
sys.exit(-2)
class Privoxy:
def __init__(self, port=8118):
self.__port = port
def stop():
print "\n"
if sys.platform.startswith('linux'):
os.system('service privoxy stop')
print '[ ok ] Stopping privoxy daemon...done.'
elif sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
print "You can close Privoxy now..."
def start_daemon(self):
if sys.platform.startswith('linux'):
os.system('service privoxy start')
print('[ ok ] Starting privoxy daemon...done.')
elif sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
print('Please make sure Privoxy is running...')
else:
print('You are using', sys.platform, ', which is not supported (yet).')
sys.exit(-2)
# Using Privoxy for all connections
def connect(self):
print('\nChecking connection...')
socks.setdefaultproxy(socks.PROXY_TYPE_HTTP, '127.0.0.1', self.__port, True)
socket.socket = socks.socksocket
try:
request = Request.get_request('https://check.torproject.org/')
response = request[1]
except:
print('Failed to connect through Privoxy!')
print('Please make sure your configuration is right!\n')
sys.exit(-2)
try:
# TODO: Check on privoxy at http://ha.ckers.org/weird/privoxy.html
regex = re.compile("(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})")
searchIP = regex.search(response)
IP = searchIP.groups()[0]
print('Your IP is: ', IP)
except:
print('It seems like Privoxy is not used.\nAborting...\n')
sys.exit(-2)
def stop(self):
print('\n')
if sys.platform.startswith('linux'):
os.system('service privoxy stop')
print('[ ok ] Stopping privoxy daemon...done.')
elif sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
print('You can close Privoxy now...')

83
lib/request.py Normal file
View File

@@ -0,0 +1,83 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------------
# Typo3 Enumerator - Automatic Typo3 Enumeration Tool
# Copyright (c) 2015 Jan Rude
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/)
#-------------------------------------------------------------------------------
import requests
import re
from colorama import Fore
requests.packages.urllib3.disable_warnings()
from lib.output import Output
class Request:
"""
This class is used to make all server requests
"""
@staticmethod
def get_request(domain_name, path):
try:
r = requests.get(domain_name + path, timeout=10, headers={'User-Agent' : "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)"}, verify=False)
httpResponse = r.text
headers = r.headers
cookies = r.cookies
status_code = r.status_code
response = [httpResponse, headers, cookies, status_code]
return response
except requests.exceptions.Timeout:
print(Fore.RED + '[x] Connection timed out' + Fore.RESET)
except requests.exceptions.ConnectionError as e:
print(Fore.RED + '[x] Connection aborted.\n Please make sure you provided the right URL' + Fore.RESET)
except requests.exceptions.RequestException as e:
print(Fore.RED + str(e) + Fore.RESET)
@staticmethod
def head_request(domain_name, path):
try:
r = requests.head(domain_name + path, timeout=10, headers={'User-Agent' : "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)"}, allow_redirects=False, verify=False)
status_code = str(r.status_code)
if status_code == '405':
print("WARNING, (HEAD) method not allowed!!")
exit(-1)
return status_code
except requests.exceptions.Timeout:
print(Fore.RED + '[x] Connection timed out' + Fore.RESET)
except requests.exceptions.ConnectionError as e:
print(Fore.RED + '[x] Connection aborted.\n Please make sure you provided the right URL' + Fore.RESET)
except requests.exceptions.RequestException as e:
print(Fore.RED + str(e) + Fore.RESET)
@staticmethod
def interesting_headers(headers):
for header in headers:
if header == 'server':
Output.interesting_headers('Server', headers.get('server'))
elif header == 'x-powered-by':
Output.interesting_headers('X-Powered-By', headers.get('x-powered-by'))
elif header == 'via':
Output.interesting_headers('Via', headers.get('via'))
@staticmethod
# not used atm because unreliable
def version_information(domain_name, path, regex):
r = requests.get(domain_name + path, stream=True, timeout=10, headers={'User-Agent' : "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)"}, verify=False)
if r.status_code == 200:
for content in r.iter_content(chunk_size=400, decode_unicode=False):
regex = re.compile(regex)
search = regex.search(str(content))
version = search.groups()[0]
return version

View File

@@ -1,97 +0,0 @@
#!/usr/bin/env python
"""
Copyright (c) 2014 Jan Rude
"""
from Queue import Queue
from threading import Thread, Lock
# Domain to check
DOMAIN = ''
# Maximum number of threads (avoiding connection issues and/or DoS)
MAX_NUMBER_OF_THREADS = 10
# Default port used by Tor
DEFAULT_TOR_PORT = 9050
# Default ports used in Tor proxy bundles
DEFAULT_PRIVOXY_PORT = 8118
# Default extension file
# Default: all available Typo3 extensions
EXTENSION_FILE = ['all_extensions']
# List with selected extensions
EXTENSION_LIST = []
# List with extensions, where no versioninformation is available
NO_VERSIONINFO = ['wt_spamshield', 'introduction'] #introduction has ChangeLog, but will use "Typo3 4.5.0" as version info!
# Check only top X extensions
# Default: all extensions
TOP_EXTENSION = 'all'
# HTTP User-Agent header value. Useful to fake the HTTP User-Agent header value at each HTTP request
# Default: Mozilla/5.0
user_agent = {'User-Agent' : "Mozilla/5.0"}
# Maximum number of concurrent HTTP(s) requests (handled with Python threads)
# Default: 7
THREADS = 7
# Verbosity.
verbose = False
#Input queue
in_queue = ''
# Seconds to wait before timeout connection.
# Default: 20
TIMEOUT = 20
# Possible paths to Typo3 loginpage !! not used atm !!
LOGIN_PATHS = ()
# Possible paths and regex to typo3 version information
TYPO3_VERSION_INFO = {'/typo3_src/ChangeLog':'RELEASE] Release of TYPO3 (.*)', '/typo3_src/NEWS.txt':'http://wiki.typo3.org/TYPO3_(\d{1,2}\.\d{1,2})', '/typo3_src/NEWS.md':"(.*) - WHAT'S NEW",
'/ChangeLog':'RELEASE] Release of TYPO3 (.*)', '/NEWS.txt':'http://wiki.typo3.org/TYPO3_(\d{1,2}\.\d{1,2})', '/NEWS.md':"(.*) - WHAT'S NEW"}
# Typo3 verision details
TYPO_VERSION = None
# Possible paths to an extension
EXTENSION_PATHS = ('/typo3conf/ext/', '/typo3/sysext/')
# Possible version info file
EXTENSION_VERSION_INFO = ('ChangeLog', 'README.txt')
# Installed extensions on targed domain
EXTENSIONS_FOUND = 0
# Colorama is not used, if not installed
COLORAMA = False
## Not used atm ##
# Maximum total number of redirections (regardless of URL) - before assuming we're in a loop
MAX_TOTAL_REDIRECTIONS = 10
# Maximum number of connection retries (to prevent problems with recursion)
MAX_CONNECT_RETRIES = 100
# Delay in seconds between each HTTP request.
# Valid: float
# Default: 0
delay = 0
# Maximum number of retries when the HTTP connection timeouts.
# Valid: integer
# Default: 3
retries = 3
# Use persistent HTTP(s) connections.
KEEPALIVE = False

View File

@@ -1,89 +0,0 @@
#!/usr/bin/env python
"""
Copyright (c) 2014 Jan Rude
"""
import time
from Queue import Queue
from os.path import isfile
from threading import Thread, Lock
try:
from colorama import Fore, Back
except:
pass
from lib import settings
from lib import versioninfo
from lib import login
from lib import output
from lib import extensions
# Startmethod
def check_typo_installation(domain):
settings.DOMAIN = domain
settings.EXTENSIONS_FOUND = 0
if settings.COLORAMA:
output = Fore.CYAN + '[ Checking ' + domain + ' ]' + '\n' + "-"* 70 + Fore.RESET
else:
output = '[ Checking ' + domain + ' ]' + '\n' + "-"* 70
print '\n\n' + output
check = login.search_login()
if check is "redirect":
check_typo_installation(settings.DOMAIN)
elif check is True:
init_extension_search()
else:
mainpage = login.check_main_page()
if mainpage is True:
init_extension_search()
elif mainpage is not "skip":
output("Typo3 Login:".ljust(32) + "Typo3 is not used on this domain", False)
def init_extension_search():
settings.in_queue = Queue()
versioninfo.search_version_info()
versioninfo.output()
if settings.TOP_EXTENSION != 0:
if not settings.EXTENSION_LIST:
extensions.generate_list()
extensions.copy()
extensions_to_check = settings.in_queue.qsize()
print '\nChecking', extensions_to_check, 'extension(s)...'
# Thanks to 'RedSparrow': http://stackoverflow.com/questions/17991033/python-cant-kill-main-thread-with-keyboardinterrupt
try:
while True:
if settings.in_queue.empty() == False:
time.sleep(0.5)
for i in xrange(0, settings.THREADS):
t = Thread(target=extensions.check_extension, args=())
t.daemon = True
t.start()
else:
break
except KeyboardInterrupt:
output("\nReceived keyboard interrupt.\nQuitting...", False)
exit(-1)
settings.in_queue.join()
installed_ext = settings.EXTENSIONS_FOUND
if installed_ext == 0:
output("No extensions installed", False)
else:
output('\n' + str(settings.EXTENSIONS_FOUND) + '/' + str(extensions_to_check) + ' extension(s) installed', True)
else:
print '\nSkipping check for extensions...'
# print error messages
def output(message, setting):
if settings.COLORAMA:
if not setting:
print Fore.RED + message + Fore.RESET
if setting:
print Fore.GREEN + message + Fore.RESET
else:
print message

132
lib/thread_pool.py Normal file
View File

@@ -0,0 +1,132 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------------
# Typo3 Enumerator - Automatic Typo3 Enumeration Tool
# Copyright (c) 2015 Jan Rude
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/)
#-------------------------------------------------------------------------------
import threading
from queue import Queue
class ThreadPoolSentinel:
pass
class ThreadPool:
"""
Generic Thread Pool used for searching extensions and changelog/readme.
Any found extension or changelog/readme goes to the result queue:
work_queue: Working queue
result_queue: Result queue
active_threads: Number of active threads
thread_list: List of worker threads
"""
def __init__(self):
self.__work_queue = Queue()
self.__result_queue = Queue()
self.__active_threads = 0
self.__thread_list = []
def add_job(self, job):
# Load job in queue
self.__work_queue.put(job)
def get_result(self):
active_threads = self.__active_threads
while (active_threads) or (not self.__result_queue.empty()):
result = self.__result_queue.get()
if isinstance(result, ThreadPoolSentinel): # One thread was done
active_threads -= 1
self.__result_queue.task_done()
continue
else: # Getting an actual result
self.__result_queue.task_done()
yield result
def start(self, threads, version_search=False):
if self.__active_threads:
raise Exception('Threads already started.')
if not version_search:
# Create thread pool
for _ in range(threads):
worker = threading.Thread(
target=_work_function,
args=(self.__work_queue, self.__result_queue))
worker.start()
self.__thread_list.append(worker)
self.__active_threads += 1
else:
for _ in range(threads):
worker = threading.Thread(
target=_work_function_version,
args=(self.__work_queue, self.__result_queue))
worker.start()
self.__thread_list.append(worker)
self.__active_threads += 1
# Put sentinels to let the threads know when there's no more jobs
[self.__work_queue.put(ThreadPoolSentinel()) for worker in self.__thread_list]
def join(self): # Clean exit
self.__work_queue.join()
[worker.join() for worker in self.__thread_list]
self.__active_threads = 0
self.__result_queue.join()
def _work_function(job_q, result_q):
"""Work function expected to run within threads."""
while True:
job = job_q.get()
if isinstance(job, ThreadPoolSentinel): # All the work is done, get out
result_q.put(ThreadPoolSentinel())
job_q.task_done()
break
function = job[0]
args = job[1]
try:
result = function(*args)
except Exception as e:
print(e)
else:
if result == ('301' or '200' or '403'):
result_q.put((job))
finally:
job_q.task_done()
def _work_function_version(job_q, result_q):
"""Work function expected to run within threads."""
while True:
job = job_q.get()
if isinstance(job, ThreadPoolSentinel): # All the work is done, get out
result_q.put(ThreadPoolSentinel())
job_q.task_done()
break
function = job[0]
args = job[1]
try:
result = function(*args)
except Exception as e:
print(e)
else:
if result == ('200'):
result_q.put((job))
finally:
job_q.task_done()

View File

@@ -1,58 +1,81 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------------
# Typo3 Enumerator - Automatic Typo3 Enumeration Tool
# Copyright (c) 2015 Jan Rude
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/)
#-------------------------------------------------------------------------------
import socket
import urllib2
import os, sys
import re
from colorama import Fore
from lib.request import Request
try:
import socks
except:
print "The module 'SocksiPy' is not installed."
print(Fore.RED + 'The module \'SocksiPy\' is not installed.')
if sys.platform.startswith('linux'):
"Please install it with: sudo apt-get install python-socksipy"
print('Please install it with: sudo apt-get install python-socksipy' + Fore.RESET)
else:
"You can download it from http://socksipy.sourceforge.net/"
print('You can download it from http://socksipy.sourceforge.net/' + Fore.RESET)
sys.exit(-2)
def start_daemon():
if sys.platform.startswith('linux'):
os.system('service tor start')
elif sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
print "Please make sure TOR is running..."
else:
print "You are using", sys.platform, ", which is not supported (yet)."
sys.exit(-2)
# Using TOR for all connections
def connect(port):
print "\nChecking connection..."
socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, "127.0.0.1", port, True)
socket.socket = socks.socksocket
try:
url = urllib2.Request('https://check.torproject.org/')
torcheck = urllib2.urlopen(url)
response = torcheck.read()
torcheck.close()
except Exception, e:
print e
print "Failed to connect through TOR!"
print "Please make sure your configuration is right!\n"
sys.exit(-2)
try:
regex = re.compile('Congratulations. This browser is configured to use Tor.')
searchVersion = regex.search(response)
version = searchVersion.groups()
print "Connection to TOR established"
regex = re.compile("(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})")
searchIP = regex.search(response)
IP = searchIP.groups()[0]
print "Your IP is: ", IP
except:
print "It seems like TOR is not used.\nAborting...\n"
sys.exit(-2)
class Tor:
def __init__(self, port=9050):
self.__port = port
def stop():
print "\n"
if sys.platform.startswith('linux'):
os.system('service tor stop')
elif sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
print "You can close TOR now..."
def start_daemon(self):
if sys.platform.startswith('linux'):
os.system('service tor start')
elif sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
print('Please make sure TOR is running...')
else:
print('You are using', sys.platform, ', which is not supported (yet).')
sys.exit(-2)
# Using TOR for all connections
def connect(self):
print('\nChecking connection...')
socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, '127.0.0.1', self.__port, True)
socket.socket = socks.socksocket
try:
request = Request.get_request('https://check.torproject.org/')
response = request[1]
except Exception, e:
print(e)
print('Failed to connect through TOR!')
print('Please make sure your configuration is right!\n')
sys.exit(-2)
try:
regex = re.compile('Congratulations. This browser is configured to use Tor.')
searchVersion = regex.search(response)
version = searchVersion.groups()
pprint('Connection to TOR established')
regex = re.compile("(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})")
searchIP = regex.search(response)
IP = searchIP.groups()[0]
print('Your IP is: ', IP)
except:
print('It seems like TOR is not used.\nAborting...\n')
sys.exit(-2)
def stop(self):
print('\n')
if sys.platform.startswith('linux'):
os.system('service tor stop')
elif sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
print('You can close TOR now...')

View File

@@ -1,62 +1,84 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------------
# Typo3 Enumerator - Automatic Typo3 Enumeration Tool
# Copyright (c) 2015 Jan Rude
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/)
#-------------------------------------------------------------------------------
import socket
import urllib2
import requests
import os, sys
import re
from colorama import Fore
from lib.request import Request
try:
import socks
except:
print "The module 'SocksiPy' is not installed."
print(Fore.RED + 'The module \'SocksiPy\' is not installed.')
if sys.platform.startswith('linux'):
"Please install it with: sudo apt-get install python-socksipy"
print('Please install it with: sudo apt-get install python-socksipy' + Fore.RESET)
else:
"You can download it from http://socksipy.sourceforge.net/"
print('You can download it from http://socksipy.sourceforge.net/' + Fore.RESET)
sys.exit(-2)
def start_daemon():
if sys.platform.startswith('linux'):
os.system('service tor start')
os.system('service privoxy start')
print '[ ok ] Starting privoxy daemon...done.'
elif sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
print "Please make sure TOR and Privoxy are running..."
else:
print "You are using", sys.platform, ", which is not supported (yet)."
sys.exit(-2)
# Using Privoxy and TOR for all connections
def connect(port):
print "\nChecking connection..."
socks.setdefaultproxy(socks.PROXY_TYPE_HTTP, "127.0.0.1", port, True)
socket.socket = socks.socksocket
try:
url = urllib2.Request('https://check.torproject.org/')
torcheck = urllib2.urlopen(url)
response = torcheck.read()
torcheck.close()
except:
print "Failed to connect through Privoxy and/or TOR!"
print "Please make sure your configuration is right!\n"
sys.exit(-2)
try:
regex = re.compile('Congratulations. This browser is configured to use Tor.')
searchVersion = regex.search(response)
version = searchVersion.groups()
print "Connection to TOR established"
regex = re.compile("(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})")
searchIP = regex.search(response)
IP = searchIP.groups()[0]
print "Your IP is: ", IP
except Exception, e:
print e
print "It seems like TOR is not used.\nAborting...\n"
sys.exit(-2)
class Tor_with_Privoxy:
def __init__(self, port=8118):
self.__port = port
def stop():
print "\n"
if sys.platform.startswith('linux'):
os.system('service tor stop')
os.system('service privoxy stop')
print '[ ok ] Stopping privoxy daemon...done.'
elif sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
print "You can close TOR and Privoxy now..."
def start_daemon(self):
if sys.platform.startswith('linux'):
os.system('service tor start')
os.system('service privoxy start')
print('[ ok ] Starting privoxy daemon...done.')
elif sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
print('Please make sure TOR and Privoxy are running...')
else:
print('You are using', sys.platform, ', which is not supported (yet).')
sys.exit(-2)
# Using Privoxy and TOR for all connections
def connect(self):
print('\nChecking connection...')
socks.setdefaultproxy(socks.PROXY_TYPE_HTTP, "127.0.0.1", self.__port, True)
socket.socket = socks.socksocket
try:
request = Request.get_request('https://check.torproject.org/')
response = request[1]
except:
print('Failed to connect through Privoxy and/or TOR!')
print('Please make sure your configuration is right!\n')
sys.exit(-2)
try:
regex = re.compile('Congratulations. This browser is configured to use Tor.')
searchVersion = regex.search(response)
version = searchVersion.groups()
print('Connection to TOR established')
regex = re.compile("(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})")
searchIP = regex.search(response)
IP = searchIP.groups()[0]
print('Your IP is: ', IP)
except Exception as e:
print('It seems like TOR is not used.\nAborting...\n')
sys.exit(-2)
def stop(self):
print('\n')
if sys.platform.startswith('linux'):
os.system('service tor stop')
os.system('service privoxy stop')
print('[ ok ] Stopping privoxy daemon...done.')
elif sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
print('You can close TOR and Privoxy now...')

View File

@@ -1,105 +1,132 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------------
# Typo3 Enumerator - Automatic Typo3 Enumeration Tool
# Copyright (c) 2015 Jan Rude
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/)
#-------------------------------------------------------------------------------
import os, sys, gzip, urllib
import os, sys, gzip, urllib.request
from collections import OrderedDict
import xml.etree.ElementTree as ElementTree
# Progressbar
def dlProgress(count, blockSize, totalSize):
percent = int(count*blockSize*100/totalSize)
sys.stdout.write("\r[+] Downloading extentions: " + "%d%%" % percent)
sys.stdout.flush()
class Update:
"""
This class updates the Typo3 extensions
# Download extensions from typo3 repository
def download_ext():
try:
urllib.URLopener.version = 'TYPO3/7.0.0'
urllib.urlretrieve('http://ter.sitedesign.dk/ter/extensions.xml.gz', 'extensions.gz', reporthook=dlProgress)
inf = gzip.open('extensions.gz', 'rb')
file_content = inf.read()
inf.close()
outF = file("extensions.xml", 'wb')
outF.write(file_content)
outF.close()
os.remove('extensions.gz')
except Exception, e:
print "\nOops! Got:", e
It will download the extension file from the official repository,
unpack it and sort the extensions in different files
"""
def __init__(self):
self.download_ext()
self.generate_list()
# Parse extensions.xml and save extensions in files
def generate_list():
experimental = {} # everything with 'experimental' and 'test'
alpha = {}
beta = {}
stable = {}
outdated = {} # everything with 'obsolete' and 'outdated'
allExt = {}
# Progressbar
def dlProgress(self, count, blockSize, totalSize):
percent = int(count*blockSize*100/totalSize)
sys.stdout.write("\r[+] Downloading extentions: " + "%d%%" % percent)
sys.stdout.flush()
print "\n[+] Parsing file..."
tree = ElementTree.parse('extensions.xml')
root = tree.getroot()
extension = 0
# for every extension in file
for child in root:
# insert every extension in "allExt" dictionary
allExt.update({child.get('extensionkey'):child[0].text})
# and search the last version entry
version = 0
for version_entry in root[extension].iter('version'):
version +=1
# get the state of the latest version
state = (str(root[extension][version][2].text)).lower()
if state == 'experimental' or state == 'test':
experimental.update({child.get('extensionkey'):child[0].text})
elif state == 'alpha':
alpha.update({child.get('extensionkey'):child[0].text})
elif state == 'beta':
beta.update({child.get('extensionkey'):child[0].text})
elif state == 'stable':
stable.update({child.get('extensionkey'):child[0].text})
elif state == 'obsolete' or state == 'outdated':
outdated.update({child.get('extensionkey'):child[0].text})
extension+=1
# Download extensions from typo3 repository
def download_ext(self):
try:
urllib.request.urlretrieve('http://ter.sitedesign.dk/ter/extensions.xml.gz', 'extensions.gz', reporthook=self.dlProgress)
with gzip.open('extensions.gz', 'rb') as f:
file_content = f.read()
f.close()
outF = open("extensions.xml", 'wb')
outF.write(file_content)
outF.close()
os.remove('extensions.gz')
except Exception as e:
print ('\n', e)
# sorting lists according to number of downloads
print "[+] Sorting according to number of downloads..."
sorted_experimental = sorted(experimental.iteritems(), key=lambda x: int(x[1]), reverse=True)
sorted_alpha = sorted(alpha.iteritems(), key=lambda x: int(x[1]), reverse=True)
sorted_beta = sorted(beta.iteritems(), key=lambda x: int(x[1]), reverse=True)
sorted_stable = sorted(stable.iteritems(), key=lambda x: int(x[1]), reverse=True)
sorted_outdated = sorted(outdated.iteritems(), key=lambda x: int(x[1]), reverse=True)
sorted_allExt = sorted(allExt.iteritems(), key=lambda x: int(x[1]), reverse=True)
# Parse extensions.xml and save extensions in files
def generate_list(self):
experimental = {} # 'experimental' and 'test'
alpha = {}
beta = {}
stable = {}
outdated = {} # 'obsolete' and 'outdated'
allExt = {}
print "[+] Generating files..."
f = open(os.path.join('extensions', 'experimental_extensions'),'w')
for i in xrange(0,len(sorted_experimental)):
f.write(sorted_experimental[i][0]+'\n')
f.close()
print ("\n[+] Parsing file...")
tree = ElementTree.parse('extensions.xml')
root = tree.getroot()
extension = 0
# for every extension in file
for child in root:
# insert every extension in "allExt" dictionary
allExt.update({child.get('extensionkey'):child[0].text})
# and search the last version entry
version = 0
for version_entry in root[extension].iter('version'):
version +=1
# get the state of the latest version
state = (str(root[extension][version][2].text)).lower()
if state == 'experimental' or state == 'test':
experimental.update({child.get('extensionkey'):child[0].text})
elif state == 'alpha':
alpha.update({child.get('extensionkey'):child[0].text})
elif state == 'beta':
beta.update({child.get('extensionkey'):child[0].text})
elif state == 'stable':
stable.update({child.get('extensionkey'):child[0].text})
elif state == 'obsolete' or state == 'outdated':
outdated.update({child.get('extensionkey'):child[0].text})
extension+=1
f = open(os.path.join('extensions', 'alpha_extensions'),'w')
for i in xrange(0,len(sorted_alpha)):
f.write(sorted_alpha[i][0]+'\n')
f.close()
# sorting lists according to number of downloads
print ("[+] Sorting according to number of downloads...")
sorted_experimental = sorted(experimental.items(), key=lambda x: int(x[1]), reverse=True)
sorted_alpha = sorted(alpha.items(), key=lambda x: int(x[1]), reverse=True)
sorted_beta = sorted(beta.items(), key=lambda x: int(x[1]), reverse=True)
sorted_stable = sorted(stable.items(), key=lambda x: int(x[1]), reverse=True)
sorted_outdated = sorted(outdated.items(), key=lambda x: int(x[1]), reverse=True)
sorted_allExt = sorted(allExt.items(), key=lambda x: int(x[1]), reverse=True)
f = open(os.path.join('extensions', 'beta_extensions'),'w')
for i in xrange(0,len(sorted_beta)):
f.write(sorted_beta[i][0]+'\n')
f.close()
print ("[+] Generating files...")
f = open(os.path.join('extensions', 'experimental_extensions'),'w')
for i in range(0,len(sorted_experimental)):
f.write(sorted_experimental[i][0]+'\n')
f.close()
f = open(os.path.join('extensions', 'stable_extensions'),'w')
for i in xrange(0,len(sorted_stable)):
f.write(sorted_stable[i][0]+'\n')
f.close()
f = open(os.path.join('extensions', 'alpha_extensions'),'w')
for i in range(0,len(sorted_alpha)):
f.write(sorted_alpha[i][0]+'\n')
f.close()
f = open(os.path.join('extensions', 'outdated_extensions'),'w')
for i in xrange(0,len(sorted_outdated)):
f.write(sorted_outdated[i][0]+'\n')
f.close()
f = open(os.path.join('extensions', 'beta_extensions'),'w')
for i in range(0,len(sorted_beta)):
f.write(sorted_beta[i][0]+'\n')
f.close()
f = open(os.path.join('extensions', 'all_extensions'),'w')
for i in xrange(0,len(sorted_allExt)):
f.write(sorted_allExt[i][0]+'\n')
f.close()
f = open(os.path.join('extensions', 'stable_extensions'),'w')
for i in range(0,len(sorted_stable)):
f.write(sorted_stable[i][0]+'\n')
f.close()
print '[+] Loaded', len(sorted_allExt), 'extensions\n'
os.remove('extensions.xml')
f = open(os.path.join('extensions', 'outdated_extensions'),'w')
for i in range(0,len(sorted_outdated)):
f.write(sorted_outdated[i][0]+'\n')
f.close()
f = open(os.path.join('extensions', 'all_extensions'),'w')
for i in range(0,len(sorted_allExt)):
f.write(sorted_allExt[i][0]+'\n')
f.close()
print ('[+] Loaded', len(sorted_allExt), 'extensions\n')
os.remove('extensions.xml')

View File

@@ -0,0 +1,50 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------------
# Typo3 Enumerator - Automatic Typo3 Enumeration Tool
# Copyright (c) 2015 Jan Rude
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/)
#-------------------------------------------------------------------------------
import re
from lib.request import Request
class VersionInformation:
"""
This class will search for version information
"""
def search_typo3_version(self, domain):
ChangeLog = {'/typo3_src/ChangeLog':'(\d{1,2}\.\d{1,2}\.?[0-9]?[0-9]?)',
'/ChangeLog':'(\d{1,2}\.\d{1,2}\.?[0-9]?[0-9]?)'
}
News = {'/typo3_src/NEWS.txt':'http://wiki.typo3.org/TYPO3_(\d{1,2}\.\d{1,2})',
'/typo3_src/NEWS.md':"TYPO3 CMS (\d{1,2}\.\d{1,2}) - WHAT'S NEW",
'/NEWS.txt':'http://wiki.typo3.org/TYPO3_(\d{1,2}\.\d{1,2})',
'/NEWS.md':"TYPO3 CMS (\d{1,2}\.\d{1,2}) - WHAT'S NEW"
}
version = 'could not determine'
for path, regex in ChangeLog.items():
response = Request.version_information(domain.get_name(), path, regex)
if not(response is None):
version = response
break
if version == 'could not determine':
for path, regex in News.items():
response = Request.version_information(domain.get_name(), path, regex)
if not(response is None):
version = response
break
domain.set_typo3_version(version)

View File

@@ -1,47 +0,0 @@
#!/usr/bin/env python
"""
Copyright (c) 2014 Jan Rude
"""
import re
import urllib2
from lib import settings
try:
from colorama import Fore
except:
pass
# Searching for Typo3 version
def search_version_info():
for path, regex in settings.TYPO3_VERSION_INFO.iteritems():
try:
request = urllib2.Request(settings.DOMAIN + path, None, settings.user_agent)
response = urllib2.urlopen(request, timeout = settings.TIMEOUT)
news = response.read(700)
response.close()
regex = re.compile(regex)
search = regex.search(news)
version = search.groups()
if settings.TYPO_VERSION is None or (len('Typo3' + version[0]) > len(settings.TYPO_VERSION)):
settings.TYPO_VERSION = 'Typo3 ' + version[0]
return
except:
pass
# Output of Typo3 version
def output():
if settings.TYPO_VERSION is None:
print "Typo3 Version:".ljust(32)
if settings.COLORAMA:
print Fore.RED
print "Not found"
if settings.COLORAMA:
Fore.RESET
else:
if settings.COLORAMA:
output = Fore.GREEN + settings.TYPO_VERSION + Fore.RESET
else:
output = settings.TYPO_VERSION
print "Typo3 Version:".ljust(32) + output
print "Link to vulnerabilities:".ljust(32) + "http://www.cvedetails.com/version-search.php?vendor=&product=Typo3&version=" + settings.TYPO_VERSION.split()[1]