Updating to v0.3

This commit is contained in:
root
2014-08-10 16:31:21 +02:00
parent 481972a6cb
commit 156fc12a4c
18 changed files with 7241 additions and 396 deletions

459
typoenum.py Normal file → Executable file
View File

@@ -1,389 +1,130 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
################## ChangeLog ##################
## v0.1 Prototype ##
## v0.2 Added version search for Typo3 ##
## v0.3 Added version guessing ##
## v0.4 Optimized requests ##
## v0.5 Added support for Typo v6.X ##
## v0.6 Added extension search ##
## v0.7 Added version search for extensions ##
## v0.8 Added support for TOR Service ##
###############################################
############ Version information ##############
__version__ = "0.8.1"
__version__ = "0.3"
__program__ = "Typo-Enumerator v" + __version__
__description__ = 'Find out the Typo3 Version, Login-URL and Extensions'
__description__ = 'Automatic Typo3 and Typo3 extensions enumeration tool'
__author__ = "Jan Rude"
__licence__ = "BSD Licence"
__status__ = "Development" # ("Prototype", "Development", "Final")
__status__ = "Development"
###############################################
################## Imports ####################
import os
import re
import gzip
import time
import socket
import urllib
import urllib2
import requests
import argparse
import datetime
from Queue import Queue
from colorama import Fore
from os.path import isfile
from operator import itemgetter
from threading import Thread, Lock
from collections import OrderedDict
import xml.etree.ElementTree as ElementTree
###############################################
############### Global variables ##############
user_agent = {'User-Agent' : None}
extension_list = []
verbosity = False
###############################################
# Searching for Typo3 version in ChangeLog
def check_typo_version_ChangeLog(domain):
global user_agent
try:
url = urllib2.Request('http://' + domain + '/typo3_src/ChangeLog', None, user_agent)
f = urllib2.urlopen(url, timeout = 3.0)
changelog = f.read(200)
f.close()
regex = re.compile("RELEASE] Release of (.*)")
searchVersion = regex.search(changelog)
version = searchVersion.groups()
print "Typo3 Version:".ljust(32) + Fore.GREEN + version[0] + Fore.RESET
print "Link to vulnerabilities:".ljust(32) + "http://www.cvedetails.com/version-search.php?vendor=&product=Typo3&version=" + version[0].split()[1]
except Exception, e:
check_typo_version_NEWS_TXT(domain)
# Searching for Typo3 version in NEWS.txt
def check_typo_version_NEWS_TXT(domain):
global user_agent
try:
url = urllib2.Request('http://' + domain + '/typo3_src/NEWS.txt', None, user_agent)
f = urllib2.urlopen(url, timeout = 3.0)
changelog = f.read(500)
f.close()
regex = re.compile("This document contains information about (.*) which")
searchVersion = regex.search(changelog)
version = searchVersion.groups()
print "Typo3 Version:".ljust(32), Fore.GREEN + version[0] + '.XX' + Fore.RED + ' (only guessable)'+ Fore.RESET
print "Link to vulnerabilities:".ljust(32) + "http://www.cvedetails.com/version-search.php?vendor=&product=Typo3&version=" + version[0].split()[2]
except:
check_typo_version_NEWS_MD(domain)
# Searching for Typo3 version in NEWS.md
def check_typo_version_NEWS_MD(domain):
global user_agent
try:
url = urllib2.Request('http://' + domain + '/typo3_src/NEWS.md', None, user_agent)
f = urllib2.urlopen(url, timeout = 3.0)
changelog = f.read(80)
f.close()
regex = re.compile("(.*) - WHAT'S NEW")
searchVersion = regex.search(changelog)
version = searchVersion.groups()
print "Typo3 Version:\t\t", Fore.GREEN + version[0] + '.XX' + Fore.RED + ' (only guessable)'+ Fore.RESET
print "Link to vulnerabilities:".ljust(32) + "http://www.cvedetails.com/version-search.php?vendor=&product=Typo3&version=" + version[0].split()[2]
except:
print "Typo3 Version:".ljust(32) + Fore.RED + "Not found" + Fore.RESET
# Searching Typo3 login page
def check_typo_login(domain):
global user_agent
try:
return check_main_page(domain)
r = requests.get('http://' + domain + '/typo3/index.php', allow_redirects=False, timeout=8.0, headers=user_agent)
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']
if ("http://") in location:
new = location.split("//")
new2 = new[1].split("/")
check_typo_login(new2[0])
elif ("https://") in location:
r = requests.get(location, timeout=8.0, headers=user_agent, verify=False)
statusCode = r.status_code
httpResponse = r.text
return check_title(httpResponse, r.url)
elif statusCode == 404:
return check_main_page(domain)
else:
print "Oops! Got:".ljust(32) + str(statusCode) + ": " + str(r.raise_for_status())
except requests.exceptions.Timeout:
print Fore.RED + "Connection timed out" + Fore.RESET
except requests.exceptions.TooManyRedirects:
print Fore.RED + "Too many redirects" + Fore.RESET
except requests.exceptions.RequestException as e:
print Fore.RED + str(e) + Fore.RESET
# Searching for Typo3 references in title
def check_title(response, url):
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
else:
print "Typo3 Login:".ljust(32) + Fore.RED + "Typo3 is not used on this domain" + Fore.RESET
return False
# Searching for Typo3 references in HTML comments
def check_main_page(domain):
req = urllib2.Request('http://' + domain, None, user_agent)
connection = urllib2.urlopen(req)
response = connection.read()
connection.close()
if 'fe_typo_user' in connection.info().getheader('Set-Cookie'):
print "Typo3 Login:".ljust(32) + Fore.GREEN + "Typo3 is used, but could not find login" + Fore.RESET
return True
else:
try:
regex = re.compile("This website is powered by TYPO3(.*)", re.IGNORECASE)
searchHTML = regex.search(response)
searchHTML.groups()[0]
print "Typo3 Login:".ljust(32) + Fore.GREEN + "Typo3 is used, but could not find login" + Fore.RESET
return True
except:
print "Typo3 Login:".ljust(32) + Fore.RED + "Typo3 is not used on this domain" + Fore.RESET
return False
# Searching installed extensions
def check_extensions(domain, input_queue, output_queue):
global user_agent
global verbosity
while True:
extension = input_queue.get()
try:
req = urllib2.Request('http://' + domain + '/typo3conf/ext/' + extension + "/", None, user_agent)
connection = urllib2.urlopen(req)
connection.close()
print "TEST:"
check_extension_version(domain, extension, output_queue)
except urllib2.HTTPError, e:
print "CODE:", e.code
if e.code == 403:
check_extension_version(domain, extension, output_queue)
elif e.code == 404:
if verbosity:
output_queue.put(extension.ljust(32) + Fore.RED + "not installed" + Fore.RESET)
pass
except urllib2.URLError, e:
print "CODE:", e
print str(e.reason)
except Exception, e:
import traceback
print ('generic exception: ', traceback.format_exc())
input_queue.task_done()
# Searching version of installed extension
def check_extension_version(domain, extension, output_queue):
global verbosity
global user_agent
try:
url = urllib2.Request('http://' + domain + '/typo3conf/ext/' + extension + '/ChangeLog', None, user_agent)
connection = urllib2.urlopen(url, timeout = 15.0)
changelog = connection.read(1500)
connection.close()
regex = re.compile("(\d{1,2}\.\d{1,2}\.[0-9][0-9]?[' '\n])")
searchVersion = regex.search(changelog)
version = searchVersion.groups()
output_queue.put(extension.ljust(32) + Fore.GREEN + "installed (v" + version[0].split()[0] + ")" + Fore.RESET)
except:
try:
regex = re.compile("(\d{2,4}[\.\-]\d{1,2}[\.\-]\d{1,4})")
searchVersion = regex.search(changelog)
version = searchVersion.groups()
output_queue.put(extension.ljust(32) + Fore.GREEN + "installed (last entry from " + version[0] + ")" + Fore.RESET)
except:
if verbosity:
output_queue.put(extension.ljust(32) + Fore.GREEN + "installed" + Fore.RESET + " (no version information found)")
else:
output_queue.put(extension.ljust(32) + Fore.GREEN + "installed" + Fore.RESET)
# Output thread
def output_thread(q):
if q.empty():
print Fore.RED + "No extensions are installed" + Fore.RESET
else:
while q is not q.empty():
try:
extension = q.get()
print(extension)
q.task_done()
except Exception, e:
print "Oops! Got:", e
# Loading extensions
def generate_extensions_list(top):
global extension_list
extension = 'extensions.xml'
print "\nLoading extensions..."
if not isfile(extension):
print(Fore.RED + "File not found: " + extension + "\nAborting..." + Fore.RESET)
sys.exit(-2)
tree = ElementTree.parse(extension)
tag_dict = tree.getroot()
exten_Dict = {}
for extensions in tag_dict.getchildren():
ext = {extensions.get('extensionkey'):extensions[0].text}
exten_Dict.update(ext)
print 'Loaded ' , len(exten_Dict), ' extensions\n'
if top is not None:
sorted_dict = sorted(exten_Dict.iteritems(), key=lambda x: int(x[1]), reverse=True)
for i in xrange(0,top):
extension_list.append(sorted_dict[i][0])
else:
for extension_name in tag_dict:
extension_list.append(extension_name.get('extensionkey'))
# Copy selected extensions in queue
def copy_extensions(input_queue):
global extension_list
for ext in extension_list:
input_queue.put(ext)
# Progressbar
def dlProgress(count, blockSize, totalSize):
percent = int(count*blockSize*100/totalSize)
sys.stdout.write("\rDownloading extentions: " + "%d%%" % percent)
sys.stdout.flush()
# Update function
def update():
try:
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()
print "\n"
os.remove('extensions.gz')
except Exception, e:
print "Oops! Got:".ljust(32), e
# Using Privoxy and TOR for all connections
def setting_up_tor():
try:
import socks
except:
print "The module 'SocksiPy' is not installed.\nPlease install it with: sudo apt-get install python-socksipy"
sys.exit(-2)
print "Checking connection to TOR through Privoxy"
socks.setdefaultproxy(socks.PROXY_TYPE_HTTP, "127.0.0.1", 8118, 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 to Privoxy and/or TOR!\nPlease make sure they are running and configured!\nYou can start them with:\nservice privoxy start\nservice tor start\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"
except:
print "It seems like TOR is not used.\nAborting...\n"
sys.exit(-2)
# Startmethod
def start(domain, top, threads):
in_queue = Queue()
out_queue = Queue()
regex = re.compile("(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})")
searchIP = regex.search(domain)
if not (searchIP is None):
IP = searchIP.groups()[0]
hostname = socket.gethostbyaddr(IP)
print("\n\n[*] Check for " + domain + " (" + hostname[0] + ")")
else:
print("\n\n[*] Check for " + domain)
if check_typo_login(domain) is True:
if not extension_list:
generate_extensions_list(top)
check_typo_version_ChangeLog(domain)
copy_extensions(in_queue)
print '\nChecking', in_queue.qsize(), 'Extensions:\nThis may take a while...'
for i in xrange(0, threads):
t = Thread(target=check_extensions, args=(domain, in_queue, out_queue))
t.daemon = True
t.start()
in_queue.join()
t = Thread(target=output_thread, args=(out_queue,))
t.daemon = True
t.start()
out_queue.join()
import argparse
import warnings
from colorama import Fore, Style
warnings.filterwarnings(action="ignore", message=".*was already imported", category=UserWarning)
warnings.filterwarnings(action="ignore", category=DeprecationWarning)
from lib import settings
from lib import update
from lib import start
# Main
def main(argv):
global user_agent
global verbosity
parser = argparse.ArgumentParser(add_help=False, usage='typoenum.py -d DOMAIN [DOMAIN ...] | -f FILE [--user_agent USER-AGENT] [--top VALUE] [-v] [--tor]')
parser = argparse.ArgumentParser(usage='typoenum.py [options]')
group = parser.add_mutually_exclusive_group()
anonGroup = parser.add_mutually_exclusive_group()
group.add_argument('-d', '--domain', dest='domain', type=str, nargs='+')
group.add_argument('-f', '--file', dest='file', help='File with a list of domains')
group.add_argument('-u', '--update', dest='update', action='store_true',help='Get/Update the extension file')
parser.add_argument('--user_agent', dest='user_agent', default='Mozilla/5.0', metavar='USER-AGENT (default: Mozilla/5.0)')
parser.add_argument('--top', type=int, dest='top', metavar='VALUE', help='Check only most X downloaded extensions (default: all)', default=None)
group.add_argument('-u', '--update', dest='update', action='store_true',help='Update the extension file')
parser.add_argument('--user_agent', dest='user_agent', metavar='USER-AGENT (default: Mozilla/5.0)')
parser.add_argument('--top', type=int, dest='top', metavar='VALUE', help='Check only most X downloaded extensions (default: all)')
anonGroup.add_argument('--tor', help='using only TOR for connections', action='store_true')
anonGroup.add_argument('--privoxy', help='using only Privoxy for connections', action='store_true')
anonGroup.add_argument('--tp', help='using TOR and Privoxy for connections', action='store_true')
parser.add_argument('-p', '--port', dest='port', help='Port for TOR/Privoxy (default: 9050/8118)', type=int)
parser.add_argument('-t', '--threads', dest='threads', default=settings.THREADS, type=int, help=' Threads for HTTP connections (default: 7)')
parser.add_argument('--timeout', dest='timeout', default=settings.TIMEOUT, type=int, help='(default: 20)')
parser.add_argument('-v', '--verbose', help='increase output verbosity', action='store_true')
parser.add_argument('--tor', help='using tor for connections', action='store_true')
parser.add_argument('-t', '--threads', dest='threads', default=10, type=int, help='(default: 10)')
args = parser.parse_args()
if not args.domain and not args.file and not args.update:
parser.print_help()
return True
try:
if args.update:
update.download_ext()
update.generate_list()
return True
if args.tor:
setting_up_tor()
if args.update:
update()
return True
user_agent = {'User-Agent' : args.user_agent}
verbosity = args.verbose
if args.domain and not args.file:
for dom in args.domain:
start(dom, args.top, args.threads)
elif not args.domain and args.file:
if not isfile(args.file):
print(Fore.RED + "\nFile not found: " + args.file + "\nAborting..." + Fore.RESET)
if args.threads > settings.MAX_NUMBER_OF_THREADS:
print Fore.RED + "Warning! Threads are set to", args.threads,"(max value is 10)\nThis can cause connection issues and/or DoS\nAborting...." + Fore.RESET
sys.exit(-2)
else:
with open(args.file, 'r') as f:
for line in f:
start(line.strip(), args.top, args.threads)
print '\n'
now = datetime.datetime.now()
print __program__ + ' finished at ' + now.strftime("%Y-%m-%d %H:%M:%S") + '\n'
return True
if args.tor:
from lib import tor_only
tor_only.start_daemon()
if args.port:
tor_only.connect(args.port)
else:
tor_only.connect(settings.DEFAULT_TOR_PORT)
elif args.privoxy:
from lib import privoxy_only
privoxy_only.start_daemon()
if args.port:
privoxy_only.connect(args.port)
else:
privoxy_only.connect(settings.DEFAULT_PRIVOXY_PORT)
elif args.tp:
from lib import tor_with_privoxy as tp
tp.start_daemon()
if args.port:
tp.connect(args.port)
else:
tp.connect(settings.DEFAULT_PRIVOXY_PORT)
if args.user_agent:
settings.user_agent.update({'User-Agent':args.user_agent})
if args.verbose:
settings.verbose = args.verbose
if args.top or args.top is 0:
settings.TOP_EXTENSION = args.top
if args.timeout:
settings.TIMEOUT = args.timeout
if args.domain:
for dom in args.domain:
start.start(dom)
elif args.file:
if not isfile(args.file):
print(Fore.RED + "\nFile not found: " + args.file + "\nAborting..." + Fore.RESET)
sys.exit(-2)
else:
with open(args.file, 'r') as f:
for line in f:
start.start(line.strip('\n')[0])
except Exception, e:
import traceback
print ('generic exception: ', traceback.format_exc())
finally:
if args.tor:
tor_only.stop()
elif args.privoxy:
privoxy_only.stop()
elif args.tp:
tp.stop()
print '\n'
now = datetime.datetime.now()
print __program__ + ' finished at ' + now.strftime("%Y-%m-%d %H:%M:%S") + '\n'
Style.RESET_ALL
return True
if __name__ == "__main__":
import sys
print('\n' + 70*'*')
print(Style.BRIGHT + '\n' + 70*'*')
print('\t' + __program__ )
print('\t' + __description__)
print('\t' + '(c)2014 by ' + __author__)
print('\t' + 'Status:\t' + __status__)
print('\t' + 'For legal purposes only!')
print(70*'*' + '\n')
sys.exit( not main( sys.argv ) )
print(70*'*')
sys.exit( not main( sys.argv ) )