Updating to v0.3
This commit is contained in:
85
README.md
85
README.md
@@ -1,44 +1,55 @@
|
||||
Typo-Enumerator
|
||||
===============
|
||||
|
||||
Find out the Typo3 Version, Login-URL and Extensions
|
||||
Typo-Enumerator is an open source penetration testing tool that automates the process of detecting the [Typo3](https://typo3.org) CMS and its installed [extensions](https://typo3.org/extensions/repository/?id=23&L=0&q=&tx_solr[filter][outdated]=outdated%3AshowOutdated) (also the outdated ones!).
|
||||
If the --top parameter is set to a value, only the specified most downloaded extensions are tested.
|
||||
|
||||
This tool allows you to check, if a domain uses Typo3.<br>
|
||||
If so, it will try to find out the Typo3 version and the installed extensions.<br>
|
||||
If the --top parameter is set to a value, only the [value] top downloaded extensions are tested.<br><br>
|
||||
Usage:<br>
|
||||
./typoenum.py -d DOMAIN [DOMAIN ...] [--user_agent USER-AGENT] [--top VALUE] [-v] [--tor] <br>
|
||||
or <br>
|
||||
./typoenum.py -f FILE [--user_agent USER-AGENT] [--top VALUE] [-v] [--tor]
|
||||
<br>
|
||||
<br>
|
||||
It is possible to use POST instead of GET Requests and do all requests through the [TOR Hidden Service](https://www.torproject.org/) network, with the help of [Privoxy](www.privoxy.org), in order to prevent DNS leakage.
|
||||
|
||||
## 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 Privoxy and TOR
|
||||
```
|
||||
-> It is now possible to use Typo-Enumerator with Privoxy and TOR (--tor)
|
||||
Privoxy is used to prevent dns leakage ;)
|
||||
Please make sure the Privoxy config (/etc/privoxy/config) is set to something like:
|
||||
listen-address 127.0.0.1:8118
|
||||
forward-socks5 / 127.0.0.1:9050 .
|
||||
These are the standart ports for Privoxy and TOR
|
||||
If TOR is used, threads will be set to 2 in order to minimize errors
|
||||
Installation
|
||||
----
|
||||
|
||||
-> Version search for extensions is now more reliable
|
||||
```
|
||||
v0.8.1
|
||||
```
|
||||
-> Bugfixing
|
||||
You can download the latest tarball by clicking [here](https://github.com/whoot/Typo-Enumerator/tarball/master) or latest zipball by clicking [here](https://github.com/whoot/Typo-Enumerator/zipball/master).
|
||||
|
||||
-> It is now possible to specifiy the threads
|
||||
Default is 10.
|
||||
I strongly recommend to use only 2 or even 1 thread when using TOR!
|
||||
This is because TOR is (extremely) slow and will produce connection errors if too many threads are used.
|
||||
```
|
||||
Preferably, you can download Type-Enumerator by cloning the [Git](https://github.com/whoot/Typo-Enumerator) repository:
|
||||
|
||||
git clone https://github.com/whoot/Typo-Enumerator.git
|
||||
|
||||
Typo-Enumerator works out with [Python](http://www.python.org/download/) version **2.6.x** and **2.7.x** on any platform.
|
||||
|
||||
If you want to use Typo-Enumerator with TOR, you need the [SocksiPy](http://socksipy.sourceforge.net/) module.
|
||||
On Debian/Ubuntu you can install it with apt-get:
|
||||
|
||||
sudo apt-get install python-socksipy
|
||||
|
||||
Usage
|
||||
----
|
||||
|
||||
To get a list of all options use:
|
||||
|
||||
python typoenum.py -h
|
||||
|
||||
You can use Typo-Enumerator with domains:
|
||||
|
||||
python typoenum.py -d DOMAIN [DOMAIN ...] [--user_agent USER-AGENT] [--top VALUE] [-v] [--tor]
|
||||
|
||||
Or with a file with a list of domains:
|
||||
|
||||
python typoenum.py -f FILE [--user_agent USER-AGENT] [--top VALUE] [-v] [--tor]
|
||||
|
||||
Example:
|
||||
Test if Typo3 and top 20 downloaded extensions are installed on localhost:
|
||||
|
||||
python typoenum.py -d 127.0.0.1 --top 20
|
||||
|
||||
Bug Reporting
|
||||
----
|
||||
Bug reports are welcome! Please report all bugs on the [issue tracker](https://github.com/whoot/Typo-Enumerator/issues).
|
||||
|
||||
Links
|
||||
----
|
||||
|
||||
* Download: [.tar.gz](https://github.com/whoot/Typo-Enumerator/tarball/master) or [.zip](https://github.com/whoot/Typo-Enumerator/archive/master)
|
||||
* Changelog: https://github.com/whoot/Typo-Enumerator/doc/CHANGELOG.md
|
||||
* TODO: https://github.com/whoot/Typo-Enumerator/doc/TODO.md
|
||||
* Issue tracker: https://github.com/whoot/Typo-Enumerator/issues
|
||||
59
doc/CHANGELOG.md
Normal file
59
doc/CHANGELOG.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# Version 0.3
|
||||
|
||||
* Using modules instead of one class
|
||||
* Accepting now strg+c when in multithreaded mode
|
||||
* Update function will now generate a list with extensions instead of an xml. This list is sorted by default (download count). Loading this file is much faster than parsing the xml everytime.
|
||||
* It is now possible to use only TOR, Privoxy, or TOR with Privoxy (in order to prevent DNS leakage).
|
||||
* Max. threads are set to 10 to prevent connection issues and DoS, default threads are now 7.
|
||||
* Connection timeout can be set with '--timeout VALUE'. Default is 20.
|
||||
* Verbose mode lists also not installed extensions (but trust me, you don´t want to scroll through over 6400 entries).
|
||||
* Typo3 version search is more accurate
|
||||
* If the backend login page could not be found, but Typo3 is used, the user is asked, if he want to proceed. This will mostly lead to "no extensions are installed".
|
||||
|
||||
# Version 0.2.1
|
||||
|
||||
* Fixed some bugs
|
||||
* It is now possible to specifiy threads
|
||||
Default is 10.
|
||||
I strongly recommend to use only 2 or even 1 thread when using TOR!
|
||||
This is because TOR is (extremely) slow and will produce connection errors if too many threads are used.
|
||||
|
||||
# Version 0.2
|
||||
|
||||
* Added support for Privoxy and TOR
|
||||
* It is now possible to use Typo-Enumerator with Privoxy and TOR (--tor)
|
||||
Privoxy is used to prevent dns leakage ;)
|
||||
Please make sure the Privoxy config (/etc/privoxy/config) is set to something like:
|
||||
listen-address 127.0.0.1:8118
|
||||
forward-socks5 / 127.0.0.1:9050 .
|
||||
These are the standart ports for Privoxy and TOR
|
||||
If TOR is used, threads will be set to 2 in order to minimize errors
|
||||
* Version search for extensions is now more reliable
|
||||
|
||||
# Version 0.1.6
|
||||
|
||||
* Added version search for extensions
|
||||
|
||||
# Version 0.1.5
|
||||
|
||||
* Added extension search
|
||||
|
||||
# Version 0.1.4
|
||||
|
||||
* Added support for Typo v6.X
|
||||
|
||||
# Version 0.1.3
|
||||
|
||||
* Optimized requests
|
||||
|
||||
# Version 0.1.2
|
||||
|
||||
* Added version guessing
|
||||
|
||||
# Version 0.1.1
|
||||
|
||||
* Added version search for Typo3
|
||||
|
||||
# Version 0.1
|
||||
|
||||
* Prototype
|
||||
23
doc/LICENSE
Normal file
23
doc/LICENSE
Normal file
@@ -0,0 +1,23 @@
|
||||
Copyright (c) 2014, Jan Rude
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
7
doc/TODO.md
Normal file
7
doc/TODO.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# TODO
|
||||
|
||||
* Find better searching algorithm for Typo3 login.
|
||||
* Search for Typo3 version-specific extensions
|
||||
* Some extensions don't have any version information. These extensions must be listed in settings.NO_VERSIONINFO.
|
||||
* Use http:// or https:// plus the domain ?
|
||||
* Maybe use one library for all requests
|
||||
6414
extensions
Normal file
6414
extensions
Normal file
File diff suppressed because it is too large
Load Diff
3
lib/__init__.py
Normal file
3
lib/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
pass
|
||||
93
lib/extensions.py
Normal file
93
lib/extensions.py
Normal file
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Copyright (c) 2014 Jan Rude
|
||||
"""
|
||||
|
||||
import re
|
||||
import time
|
||||
import urllib2
|
||||
from Queue import Queue
|
||||
from colorama import Fore
|
||||
from os.path import isfile
|
||||
from threading import Thread, Lock
|
||||
from lib import settings
|
||||
|
||||
def generate_list():
|
||||
if not isfile('extensions'):
|
||||
print(Fore.RED + "\nExtensionfile not found!\nPlease update Typo-Enumerator (python typoenum.py -u)" + Fore.RESET)
|
||||
sys.exit(-2)
|
||||
with open('extensions', 'r') as f:
|
||||
count = 0
|
||||
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 on version if we get 200 or 403.
|
||||
def check_extension():
|
||||
while True:
|
||||
extension = settings.in_queue.get()
|
||||
for path in settings.EXTENSION_PATHS:
|
||||
try:
|
||||
req = urllib2.Request('http://' + 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:
|
||||
# settings.in_queue.put(extension)
|
||||
# if extension is not in any given path, it's not installed
|
||||
if settings.verbose:
|
||||
settings.out_queue.put(extension.ljust(32) + Fore.RED + 'not installed' + Fore.RESET)
|
||||
settings.in_queue.task_done()
|
||||
|
||||
# Searching version of installed extension
|
||||
def check_extension_version(path, extension):
|
||||
# if no version information is available, skip version search
|
||||
if extension in settings.NO_VERSIONINFO:
|
||||
if settings.verbose:
|
||||
settings.out_queue.put(extension.ljust(32) + Fore.GREEN + 'installed' + Fore.RESET + ' (no version information available)')
|
||||
else:
|
||||
settings.out_queue.put(extension.ljust(32) + Fore.GREEN + 'installed' + Fore.RESET)
|
||||
else:
|
||||
try:
|
||||
request = urllib2.Request('http://' + 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()
|
||||
settings.out_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})")
|
||||
search = regex.search(changelog)
|
||||
version = search.groups()
|
||||
settings.out_queue.put(extension.ljust(32) + Fore.GREEN + 'installed (last entry from ' + version[0] + ')' + Fore.RESET)
|
||||
except:
|
||||
if settings.verbose:
|
||||
settings.out_queue.put(extension.ljust(32) + Fore.GREEN + "installed" + Fore.RESET + " (no version information found)")
|
||||
else:
|
||||
settings.out_queue.put(extension.ljust(32) + Fore.GREEN + "installed" + Fore.RESET)
|
||||
except:
|
||||
settings.out_queue.put(extension.ljust(32) + Fore.GREEN + "installed" + Fore.RESET)
|
||||
100
lib/login.py
Normal file
100
lib/login.py
Normal file
@@ -0,0 +1,100 @@
|
||||
#!/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
|
||||
|
||||
# Searching Typo3 login page
|
||||
def search_login(domain):
|
||||
try:
|
||||
r = requests.get('http://' + domain + '/typo3/index.php', allow_redirects=False, timeout=settings.TIMEOUT, headers=settings.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:
|
||||
locsplit = location.split("//")
|
||||
new_location = locsplit[1].split("/")
|
||||
search_login(new_location[0])
|
||||
elif ("https://") in location:
|
||||
r = requests.get(location, timeout=settings.TIMEOUT, headers=settings.user_agent, verify=False)
|
||||
statusCode = r.status_code
|
||||
httpResponse = r.text
|
||||
return check_title(httpResponse, r.url)
|
||||
elif statusCode == 404:
|
||||
return check_main_page()
|
||||
else:
|
||||
print "Oops! Got unhandled code:".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):
|
||||
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 check_main_page()
|
||||
|
||||
# Searching for Typo3 references in HTML comments
|
||||
def check_main_page():
|
||||
req = urllib2.Request('http://' + 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:
|
||||
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):
|
||||
print Fore.RED + str(e) + "\nPlease ensure you entered the right url" + Fore.RESET
|
||||
else:
|
||||
print Fore.RED + "Got \"" + str(e) + "\" on testing main page." + Fore.RESET
|
||||
return False
|
||||
print "Typo3 Login:".ljust(32) + Fore.RED + "Typo3 is not used on this domain" + Fore.RESET
|
||||
return False
|
||||
|
||||
def bad_url():
|
||||
print "Typo3 Login:".ljust(32) + Fore.GREEN + "Typo3 is used, but could not find login" + Fore.RESET
|
||||
print "".ljust(32) + "This will mostly result in \"no extensions are installed\"."
|
||||
print "".ljust(32) + "Seems like something is wrong with the given url."
|
||||
var = raw_input("".ljust(32) + "Try anyway (y/n)? ")
|
||||
if var is 'y':
|
||||
return True
|
||||
return False
|
||||
20
lib/output.py
Normal file
20
lib/output.py
Normal file
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
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()
|
||||
print(extension)
|
||||
settings.out_queue.task_done()
|
||||
except Exception, e:
|
||||
print "Oops! Got:", e
|
||||
43
lib/privoxy_only.py
Normal file
43
lib/privoxy_only.py
Normal file
@@ -0,0 +1,43 @@
|
||||
import socket
|
||||
import urllib2
|
||||
import os, sys
|
||||
import re
|
||||
from colorama import Fore
|
||||
try:
|
||||
import socks
|
||||
except:
|
||||
print "The module 'SocksiPy' is not installed.\nPlease install it with: sudo apt-get install python-socksipy"
|
||||
sys.exit(-2)
|
||||
|
||||
def start_daemon():
|
||||
os.system('service privoxy start')
|
||||
print '[' + Fore.GREEN + ' ok ' + Fore.RESET + '] Starting privoxy daemon...done.'
|
||||
|
||||
# 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 Fore.RED + "Failed to connect through Privoxy!" + Fore.RESET
|
||||
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():
|
||||
print "\n"
|
||||
os.system('service privoxy stop')
|
||||
print '[' + Fore.GREEN + ' ok ' + Fore.RESET + '] Stopping privoxy daemon...done.'
|
||||
94
lib/settings.py
Normal file
94
lib/settings.py
Normal file
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Copyright (c) 2014 Jan Rude
|
||||
"""
|
||||
|
||||
from Queue import Queue
|
||||
from threading import Thread, Lock
|
||||
|
||||
# Domain to check
|
||||
# Valid: string
|
||||
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
|
||||
|
||||
# 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
|
||||
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)
|
||||
# Valid: integer
|
||||
# Default: 7
|
||||
THREADS = 7
|
||||
|
||||
# Verbosity.
|
||||
verbose = False
|
||||
|
||||
#Input and output queues
|
||||
in_queue = ""
|
||||
in_queue2 = ""
|
||||
out_queue = ""
|
||||
|
||||
# Seconds to wait before timeout connection.
|
||||
# Valid: int
|
||||
# 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')
|
||||
|
||||
EXTENSIONS_FOUND = {}
|
||||
|
||||
|
||||
|
||||
## 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
|
||||
64
lib/start.py
Normal file
64
lib/start.py
Normal file
@@ -0,0 +1,64 @@
|
||||
#!/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
|
||||
from colorama import Fore, Back
|
||||
from lib import settings
|
||||
from lib import versioninfo
|
||||
from lib import login
|
||||
from lib import output
|
||||
from lib import extensions
|
||||
|
||||
# Startmethod
|
||||
def start(domain):
|
||||
settings.in_queue = Queue()
|
||||
settings.out_queue = Queue()
|
||||
settings.DOMAIN = domain
|
||||
print '\n\n' + Fore.CYAN + '[ Checking ' + domain + ' ]' + '\n' + "-"* 70 + Fore.RESET
|
||||
|
||||
if login.search_login(domain) is True:
|
||||
versioninfo.search_version_info()
|
||||
versioninfo.output()
|
||||
|
||||
if not settings.EXTENSION_LIST:
|
||||
extensions.generate_list()
|
||||
|
||||
extensions.copy()
|
||||
extensions_to_check = settings.in_queue.qsize()
|
||||
|
||||
if extensions_to_check is not 0:
|
||||
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.1)
|
||||
for i in xrange(0, settings.THREADS):
|
||||
t = Thread(target=extensions.check_extension, args=())
|
||||
t.daemon = True
|
||||
t.start()
|
||||
else:
|
||||
break
|
||||
settings.in_queue.join()
|
||||
except KeyboardInterrupt:
|
||||
print Fore.RED + "\nReceived keyboard interrupt.\nQuitting..." + Fore.RESET
|
||||
exit(-1)
|
||||
|
||||
installed_ext = settings.out_queue.qsize()
|
||||
if installed_ext is 0:
|
||||
print Fore.RED + "No extensions installed" + Fore.RESET
|
||||
else:
|
||||
t = Thread(target=output.thread, args=())
|
||||
t.daemon = True
|
||||
t.start()
|
||||
settings.out_queue.join()
|
||||
print Fore.GREEN + '\n', str(installed_ext) + '/' + str(extensions_to_check),'extension(s) installed' + Fore.RESET
|
||||
|
||||
else:
|
||||
print '\nSkipping check for extensions...'
|
||||
BIN
lib/tor.pyc
Normal file
BIN
lib/tor.pyc
Normal file
Binary file not shown.
45
lib/tor_only.py
Normal file
45
lib/tor_only.py
Normal file
@@ -0,0 +1,45 @@
|
||||
import socket
|
||||
import urllib2
|
||||
import os, sys
|
||||
import re
|
||||
from colorama import Fore
|
||||
try:
|
||||
import socks
|
||||
except:
|
||||
print "The module 'SocksiPy' is not installed.\nPlease install it with: sudo apt-get install python-socksipy"
|
||||
sys.exit(-2)
|
||||
|
||||
def start_daemon():
|
||||
os.system('service tor start')
|
||||
|
||||
# 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 Fore.RED + "Failed to connect through TOR!" + Fore.RESET
|
||||
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 Fore.GREEN + "Connection to TOR established" + Fore.RESET
|
||||
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():
|
||||
print "\n"
|
||||
os.system('service tor stop')
|
||||
49
lib/tor_with_privoxy.py
Normal file
49
lib/tor_with_privoxy.py
Normal file
@@ -0,0 +1,49 @@
|
||||
import socket
|
||||
import urllib2
|
||||
import os, sys
|
||||
import re
|
||||
from colorama import Fore
|
||||
try:
|
||||
import socks
|
||||
except:
|
||||
print "The module 'SocksiPy' is not installed.\nPlease install it with: sudo apt-get install python-socksipy"
|
||||
sys.exit(-2)
|
||||
|
||||
def start_daemon():
|
||||
os.system('service tor start')
|
||||
os.system('service privoxy start')
|
||||
print '[' + Fore.GREEN + ' ok ' + Fore.RESET + '] Starting privoxy daemon...done.'
|
||||
|
||||
# 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 Fore.RED + "Failed to connect through Privoxy and/or TOR!" + Fore.RESET
|
||||
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 Fore.GREEN + "Connection to TOR established" + Fore.RESET
|
||||
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)
|
||||
|
||||
def stop():
|
||||
print "\n"
|
||||
os.system('service tor stop')
|
||||
os.system('service privoxy stop')
|
||||
print '[' + Fore.GREEN + ' ok ' + Fore.RESET + '] Stopping privoxy daemon...done.'
|
||||
44
lib/update.py
Normal file
44
lib/update.py
Normal file
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os, sys, gzip, urllib
|
||||
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("\rDownloading extentions: " + "%d%%" % percent)
|
||||
sys.stdout.flush()
|
||||
|
||||
# Download extensions from typo3 repository
|
||||
def download_ext():
|
||||
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()
|
||||
os.remove('extensions.gz')
|
||||
except Exception, e:
|
||||
print "Oops! Got:".ljust(32), e
|
||||
|
||||
# Parse extensions.xml and save extensions in file
|
||||
def generate_list():
|
||||
extension = 'extensions.xml'
|
||||
print "\nParsing file..."
|
||||
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)
|
||||
sorted_dict = sorted(exten_Dict.iteritems(), key=lambda x: int(x[1]), reverse=True)
|
||||
f = open('extensions','w')
|
||||
for i in xrange(0,len(exten_Dict)):
|
||||
f.write(sorted_dict[i][0]+'\n')
|
||||
f.close()
|
||||
print 'Loaded', len(exten_Dict), 'extensions\n'
|
||||
os.remove('extensions.xml')
|
||||
35
lib/versioninfo.py
Normal file
35
lib/versioninfo.py
Normal file
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Copyright (c) 2014 Jan Rude
|
||||
"""
|
||||
|
||||
import re
|
||||
import urllib2
|
||||
from colorama import Fore
|
||||
from lib import settings
|
||||
|
||||
# Searching for Typo3 version
|
||||
def search_version_info():
|
||||
for path, regex in settings.TYPO3_VERSION_INFO.iteritems():
|
||||
try:
|
||||
request = urllib2.Request('http://' + 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) + Fore.RED + "Not found" + Fore.RESET
|
||||
else:
|
||||
print "Typo3 Version:".ljust(32) + Fore.GREEN + settings.TYPO_VERSION + Fore.RESET
|
||||
print "Link to vulnerabilities:".ljust(32) + "http://www.cvedetails.com/version-search.php?vendor=&product=Typo3&version=" + settings.TYPO_VERSION.split()[1]
|
||||
459
typoenum.py
Normal file → Executable file
459
typoenum.py
Normal file → Executable 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 ) )
|
||||
Reference in New Issue
Block a user