This commit is contained in:
Jan Rude
2017-02-09 16:32:26 +01:00
parent 0e37596ba1
commit ec592fafb5
20 changed files with 6867 additions and 6712 deletions

View File

@@ -22,9 +22,9 @@ You might need to install following packages:
* [Requests](https://pypi.python.org/pypi/requests/)
* [Colorama](https://pypi.python.org/pypi/colorama)
On Debian/Ubuntu you can install the packages with apt-get:
You can install the packages with pip3 on Debian/Ubuntu and Windows:
apt-get install python3-requests python3-colorama
pip3 install requests colorama
On Redhat you can install all needed packages with easy_install:
@@ -39,23 +39,24 @@ Usage
To get a list of all options use:
python3 typoenum.py -h
python3 typo3_enumerator.py -h
You can use Typo3-Enumerator with domains:
python3 typoenum.py -d DOMAIN [DOMAIN ...] [--top VALUE]
python3 typo3_enumerator.py -d DOMAIN [DOMAIN ...] [--top VALUE]
Or with a file with a list of domains:
python3 typoenum.py -f FILE [--top VALUE]
python3 typo3_enumerator.py -f FILE [--top VALUE]
Example:
Test if Typo3 and top 200 downloaded extensions are installed on 192.168.0.24:
python3 typoenum.py -d 192.168.0.24/testsite --top 200
python3 typo3_enumerator.py -d 192.168.0.24/testsite --top 200
![ScreenShot](/doc/Screenshot.jpg)
Bug Reporting
----
Bug reports are welcome! Please report all bugs on the [issue tracker](https://github.com/whoot/Typo-Enumerator/issues).
@@ -72,7 +73,7 @@ Links
Typo3 Enumerator - Automatic Typo3 Enumeration Tool
Copyright (c) 2016 Jan Rude
Copyright (c) 2015-2017 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

View File

@@ -1,3 +1,10 @@
## Version 0.4.5.1
* Fixed error on launch when launching from different directory
* IP address restriction for backend login is now shown
* Code cleanup
* Suppress InsecureRequestWarning
## Version 0.4.5
* Version search for Typo3 v8

View File

@@ -1,3 +1,5 @@
# TODO
* Newer Typo3 installations use /typo3/index.php?id=xxx
* Version search fix
* Stop extension enumeration with ctrl-c

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -94,10 +94,10 @@ test_uploaddependency
jhe_dam_extender
dbreplace
spriteiconoverview
eventmanagement
ms_fluid
abcconfig
eventmanagement
bb_easyforms
ms_fluid
ajax_report
smu_chc_ext
ch_flash_carrousel
@@ -112,18 +112,18 @@ p2_langfix_42
clanbase
ter_tests
meta_openoffice
rhu_events
st_validation_lpl
rhu_events
t3info
ch_bramacproducts
sort_table
organizacionacademica
alumnos
bonus
maja_condrequired
alumnos
lz_lp_dm_log_fe
hh_multipageform_example
dsxsyndication
hh_multipageform_example
zitatdt
ba_company
svq_ebay
@@ -133,10 +133,10 @@ contactformgenerator
rg_links
audio_conversion
error
wow_raid
mbbrowserid
mf_trainmanagement
wow_raid
rg_usuarios
mf_trainmanagement
rg_patrocinio
sp_newsteaserbox_hookexample
redirectlog
@@ -146,34 +146,34 @@ asvtiger
belink_syslang
buildtools
rg_empresas
rf_library
tc_fbconnect
treppenpfosten_katalog
rf_library
ffunews
dre_besearch
elnews
ckeditor
reint_mailtask_example
jh_pwcomments_plugin
xdbmysql
tagger
tgm_kickstart
contentfce
og_base
visitorlist
moox_news_twitter
lo_backendhelper
ctefan_test
air_table
moox_news_geoinfo
boards
ft3_empty
femanagerextended
mr_base_config
ter_upload_test
fluidfoundationtheme
ecs_steam
simplemvc_helloworld
downloads
moox_news_twitter
boards
reint_mailtask_example
xdbmysql
contentfce
ctefan_test
tagger
ckeditor
dbal_utility
visitorlist
jh_pwcomments_plugin
og_base
moox_news_geoinfo
jh_extstatus
air_table
ter_upload_test
tgm_kickstart
simplemvc_helloworld
cabag_deploy
downloads
lo_backendhelper
mr_base_config

View File

@@ -1,5 +1,6 @@
newloginbox
ter_update_check
realurl
csh_de
csh_nl
th_mailformplus
@@ -21,6 +22,7 @@ sr_rtehtmlarea_xpblue
eco_gal
dmmjobcontrol
rte_conf
ws_sitemap
smile_workflow
typo3_tut
modern_skin
@@ -119,14 +121,14 @@ sg_fenewsedit
csh_sk
cobwebphpadsnew
dynbeedit
glossarysearch
csh_gr
glossarysearch
csh_hk
csh_br
dubletfinder
prototypejs
wa_contentrenderinghook
hsapp_longerfeusername
wa_contentrenderinghook
de_contentorganizer
danp_skinsupport
alt_forms_field_title
@@ -183,8 +185,8 @@ localphpinclude
tm_classes
fl_langtranslate
danp_userlisttemplate
tebay
cobweb_protector
tebay
rtehtmlarea_definitionlist
yag_theme_perfectlightbox
eco_content
@@ -193,8 +195,8 @@ csh_vn
tm_minijoboffers
paysuite
idaa_fe_utilies
go_maps_ap
mailformplusplus
go_maps_ap
ak_mobile_device
iwbase
eu_correcturls
@@ -222,6 +224,7 @@ stfl_startendtime
completebackup
speedy
sav_library_extends
tinysource
mm_forum_news
flow4t3
browser_tut_ajax_en
@@ -239,8 +242,8 @@ smile_form_archive
tagpackprovider
dfluess
doc_core_tca
jhe_adventcalender
redirection
jhe_adventcalender
sav_library_example5
maag_imagerotator
xliff
@@ -253,8 +256,8 @@ st_readmore
mak_randlistnum
extended_sys_note
static_info_tables_ga
advancedform
delete_staticfile_by_3party
advancedform
ics_errorhandler
ods_workspace_mail
extend_dcdgooglemap
@@ -262,18 +265,18 @@ tm_gallery
ttnews_href_marker
doc_tut_editors
st_metatags
doc_guide_security
doc_core_skinning
doc_guide_security
ics_templavoila_mirgation_tool
ttnewscacheexpire
form4_contentpagination
realurl_autoconf_autodelete
paymentlib_dibs
paymentlib_quickpay_dk
smile_jumpurl_fix
tgm_gallery
tm_cssfilelinks
smile_jumpurl_fix
tsincludeorder
tm_cssfilelinks
tgmv_gallery
tm_import
nc_videostatistics
@@ -283,32 +286,34 @@ dialogcentral
dscentral
jb_metaexec_doc
maag_cenoshop
mm_forum_blog
moox_feusers
form4_tags
wt_spamshield_formhandler
browser_tut_map_en
lvrandfiles
coreupdate
barscheduler
jh_ter_announcer
form4_pages
form4_filecache
dyncss_turbine
barscheduler
coo_facebook
uploadtest
attachmentdelete
external_link_parameter
moox_flexisel
form4_teaser
filedeletion
browser_manual_ootb_en
view
form4_realurl
browser_tut_map_en
moox_flexisel
fluidfoundationtheme
onm_redirect_linkhandling
coreupdate
moox_feusers
form4_pages
ajax_calendar
layersliderlight
form4_faq
fluidcontent_fed
dyncss_phpsass
moox_slider
form4_pages_counter
view
moox_slider
form4_filecache
form4_teaser
uploadtest
form4_realurl
layersliderlight
attachmentdelete
jh_ter_announcer
mm_forum_blog
form4_faq
external_link_parameter
wt_spamshield_formhandler
dyncss_phpsass
fluidcontent_fed
filedeletion
form4_tags

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------------
# Typo3 Enumerator - Automatic Typo3 Enumeration Tool
# Copyright (c) 2016 Jan Rude
# Copyright (c) 2014-2017 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
@@ -27,13 +27,12 @@ from lib.output import Output
class Typo3_Installation:
"""
This class checks, if Typo3 is used on the domain with different approaches.
If Typo3 is used, a link to the login page is shown.
If Typo3 is used, a link to the default login page is shown.
"""
@staticmethod
def run(domain):
root = Typo3_Installation.check_root(domain)
check_installation = Typo3_Installation.check_installation(domain)
if not root:
check_on_root = Typo3_Installation.check_root(domain)
if not check_on_root:
default_files = Typo3_Installation.check_default_files(domain)
if not default_files:
typo = Typo3_Installation.check_404(domain)
@@ -42,33 +41,19 @@ class Typo3_Installation:
This method requests the root page
and searches for a specific string in the response.
Usually there are some TYPO3 notes in the HTML comments.
"""
@staticmethod
def check_root(domain):
try:
response = Request.get_request(domain.get_name(), '/')
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()[0]
domain.set_typo3()
domain.set_typo3_version(version)
return True
except:
return False
"""
This method requests the homepage
and searches for a Typo3 path reference
If found, it searches for a Typo3 path reference
in order to determine the Typo3 installation path.
"""
@staticmethod
def check_installation(domain):
def check_root(domain):
response = Request.get_request(domain.get_name(), '/')
if not response:
exit(-1)
if re.search('[Tt][Yy][Pp][Oo]3', response[0]):
domain.set_typo3()
headers = Request.interesting_headers(response[1], response[2])
for key in headers:
domain.set_interesting_headers(key, headers[key])
try:
path = re.search('(href|src|content)=(.{0,35})(typo3temp/|typo3conf/)', response[0])
if not (path.groups()[1] == '"' or '"../' in path.groups()[1]):
@@ -78,22 +63,24 @@ class Typo3_Installation:
else:
domain.set_name(domain.get_name() + real_path[0:len(real_path)-1])
domain.set_path(real_path[0:len(real_path)-1])
domain.set_typo3()
return True
except:
pass
return True
else:
return False
"""
This method requests different files, which are generated on installation.
Usually they are not deleted by admins
and can be used as an idicator of a TYPO3 installation.
and can be used as an indicator of a TYPO3 installation.
"""
@staticmethod
def check_default_files(domain):
files = {'/README.md':'[Tt][Yy][Pp][Oo]3 [Cc][Mm][Ss]',
'/README.txt':'[Tt][Yy][Pp][Oo]3 [Cc][Mm][Ss]',
'/INSTALL.txt':'INSTALLING [Tt][Yy][Pp][Oo]3',
'/typo3_src/LICENSE.txt':'The [Tt][Yy][Pp][Oo]3 licensing conditions'
files = {'/typo3_src/README.md':'[Tt][Yy][Pp][Oo]3 [Cc][Mm][Ss]',
'/typo3_src/README.txt':'[Tt][Yy][Pp][Oo]3 [Cc][Mm][Ss]',
'/typo3_src/INSTALL.txt':'INSTALLING [Tt][Yy][Pp][Oo]3',
'/typo3_src/INSTALL.md':'INSTALLING [Tt][Yy][Pp][Oo]3',
'/typo3_src/LICENSE.txt':'[Tt][Yy][Pp][Oo]3'
}
for path, regex in files.items():
@@ -138,10 +125,17 @@ class Typo3_Installation:
regex = re.compile('<title>(.*)</title>', re.IGNORECASE)
searchTitle = regex.search(response[0])
title = searchTitle.groups()[0]
if ('TYPO3' in title) or ('TYPO3 CMS' in response[0]) or (response[3] == 403):
domain.set_typo3()
domain.set_login_found()
login_text = Fore.GREEN + domain.get_name() + '/typo3/index.php' + Fore.RESET
login_text += '\n | Accessible?'.ljust(30)
if ('TYPO3 Backend access denied: The IP address of your client' in response[0]) or (response[3] == 403):
login_text += (Fore.YELLOW + ' Forbidden (IP Address Restriction)' + Fore.RESET)
elif ('TYPO3 Login' in title):
login_text += Fore.GREEN + ' Yes' + Fore.RESET
else:
login_text = Fore.RED + 'Could not be found' + Fore.RESET
domain.set_login_found(login_text)
return True
except:
pass
return False

View File

@@ -1 +1 @@
{"timeout": 10, "agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0", "threads": 5}
{"agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0", "timeout": 10, "threads": 5}

View File

@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------------
# Typo3 Enumerator - Automatic Typo3 Enumeration Tool
# Copyright (c) 2016 Jan Rude
# Copyright (c) 2014-2017 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
@@ -36,7 +36,7 @@ class Domain(object):
self.__name = name
self.__typo3 = False
self.__typo3_version = ''
self.__login_found = False
self.__login_found = ''
self.__path = ''
self.__extension_config = [ext_state, top]
self.__extensions = None
@@ -88,8 +88,8 @@ class Domain(object):
def get_login_found(self):
return self.__login_found
def set_login_found(self):
self.__login_found = True
def set_login_found(self, path):
self.__login_found = path
def set_interesting_headers(self, header_key, header_value):
self.__interesing_header[header_key] = header_value

View File

@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------------
# Typo3 Enumerator - Automatic Typo3 Enumeration Tool
# Copyright (c) 2016 Jan Rude
# Copyright (c) 2014-2017 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
@@ -28,9 +28,10 @@ class Extensions:
"""
Extension class
"""
def __init__(self, ext_state, top):
def __init__(self, ext_state, top, path):
self.__ext_state = ext_state
self.__top = top
self.__path = path
def load_extensions(self):
"""
@@ -40,10 +41,10 @@ class Extensions:
extensions = []
for state in self.__ext_state:
ext_file = state + '_extensions'
if not os.path.isfile(os.path.join('extensions', ext_file)):
if not os.path.isfile(os.path.join(self.__path, '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:
with open(os.path.join(self.__path, 'extensions', ext_file), 'r') as f:
count = 0
for extension in f:
if not(self.__top is None):
@@ -62,7 +63,7 @@ class Extensions:
/typo3/ext/: Global installation path (not used atm)
/typo3/sysext/: Extensions shipped with core (not used atm)
"""
config = json.load(open('lib/config.json'))
config = json.load(open(os.path.join(self.__path, 'lib', 'config.json')))
thread_pool = ThreadPool()
for ext in extensions:
thread_pool.add_job((Request.head_request, (domain.get_name(), '/typo3conf/ext/' + ext)))

View File

@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------------
# Typo3 Enumerator - Automatic Typo3 Enumeration Tool
# Copyright (c) 2016 Jan Rude
# Copyright (c) 2014-2017 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
@@ -33,7 +33,7 @@ class Output:
Additionally, if the version search was successful, the version and a link to cvedetails is given.
"""
print('')
print('[+] Typo3 backend login:'.ljust(30) + Fore.GREEN + domain.get_name() + '/typo3/index.php' + Fore.RESET)
print('[+] Typo3 backend login:'.ljust(30) + domain.get_login_found())
if (domain.get_typo3_version() != 'could not be determined'):
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)

View File

@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------------
# Typo3 Enumerator - Automatic Typo3 Enumeration Tool
# Copyright (c) 2016 Jan Rude
# Copyright (c) 2014-2017 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
@@ -21,8 +21,9 @@
import re
import json
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
from colorama import Fore
requests.packages.urllib3.disable_warnings()
from lib.output import Output
class Request:

View File

@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------------
# Typo3 Enumerator - Automatic Typo3 Enumeration Tool
# Copyright (c) 2016 Jan Rude
# Copyright (c) 2014-2017 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

View File

@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------------
# Typo3 Enumerator - Automatic Typo3 Enumeration Tool
# Copyright (c) 2016 Jan Rude
# Copyright (c) 2014-2017 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

View File

@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------------
# Typo3 Enumerator - Automatic Typo3 Enumeration Tool
# Copyright (c) 2016 Jan Rude
# Copyright (c) 2014-2017 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
@@ -18,7 +18,7 @@
# along with this program. If not, see [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/)
#-------------------------------------------------------------------------------
import os, sys, gzip, urllib.request
import os, sys, gzip, urllib.request, inspect
from collections import OrderedDict
import xml.etree.ElementTree as ElementTree
@@ -29,8 +29,9 @@ class Update:
It will download the extension file from the official repository,
unpack it and sort the extensions in different files
"""
def __init__(self):
def __init__(self, path):
print('')
self.__path = path
self.download_ext()
self.generate_list()
@@ -54,7 +55,7 @@ class Update:
with gzip.open('extensions.gz', 'rb') as f:
file_content = f.read()
f.close()
outF = open('extensions.xml', 'wb')
outF = open('/extensions.xml', 'wb')
outF.write(file_content)
outF.close()
os.remove('extensions.gz')
@@ -110,32 +111,32 @@ class Update:
sorted_allExt = sorted(allExt.items(), key=lambda x: int(x[1]), reverse=True)
print ('[+] Generating files...')
f = open(os.path.join('extensions', 'experimental_extensions'),'w')
f = open(os.path.join(self.__path, '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', 'alpha_extensions'),'w')
f = open(os.path.join(self.__path, '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', 'beta_extensions'),'w')
f = open(os.path.join(self.__path, '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', 'stable_extensions'),'w')
f = open(os.path.join(self.__path, 'extensions', 'stable_extensions'), 'w')
for i in range(0,len(sorted_stable)):
f.write(sorted_stable[i][0]+'\n')
f.close()
f = open(os.path.join('extensions', 'outdated_extensions'),'w')
f = open(os.path.join(self.__path, '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')
f = open(os.path.join(self.__path, 'extensions', 'all_extensions'), 'w')
for i in range(0,len(sorted_allExt)):
f.write(sorted_allExt[i][0]+'\n')
f.close()

View File

@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------------
# Typo3 Enumerator - Automatic Typo3 Enumeration Tool
# Copyright (c) 2016 Jan Rude
# Copyright (c) 2014-2017 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

View File

@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------------
# Typo3 Enumerator - Automatic Typo3 Enumeration Tool
# Copyright (c) 2016 Jan Rude
# Copyright (c) 2014-2017 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
@@ -18,7 +18,7 @@
# along with this program. If not, see [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/)
#-------------------------------------------------------------------------------
__version__ = '0.4.5'
__version__ = '0.4.5.1'
__program__ = 'Typo-Enumerator'
__description__ = 'Automatic Typo3 enumeration tool'
__author__ = 'https://github.com/whoot'
@@ -28,6 +28,7 @@ import os.path
import datetime
import argparse
import json
import inspect
from colorama import Fore, init, deinit, Style
from lib.check_installation import Typo3_Installation
from lib.version_information import VersionInformation
@@ -41,10 +42,11 @@ class Typo3:
def __init__(self):
self.__domain_list = []
self.__extensions = None
self.__path = path = os.path.dirname(os.path.abspath(__file__))
def print_help():
print(
"""\nUsage: python3 typoenum.py [options]
"""\nUsage: python3 typo3_enumerator.py [options]
Options:
-h, --help Show this help message and exit
@@ -106,7 +108,7 @@ Options:
try:
if args.update:
Update()
Update(self.__path)
return True
if args.tor:
@@ -131,7 +133,7 @@ Options:
self.__domain_list.append(Domain(line.strip('\n'), args.ext_state, args.top))
config = {'threads':args.threads, 'agent':args.agent, 'timeout':args.timeout}
json.dump(config, open('lib/config.json', 'w'))
json.dump(config, open(os.path.join(self.__path, 'lib', 'config.json'), 'w'))
for domain in self.__domain_list:
print('\n\n' + Fore.CYAN + Style.BRIGHT + '[ Checking ' + domain.get_name() + ' ]' + '\n' + '-'* 73 + Fore.RESET + Style.RESET_ALL)
@@ -141,20 +143,13 @@ Options:
if not domain.get_typo3():
print(Fore.RED + '\n[x] It seems that Typo3 is not used on this domain' + Fore.RESET)
else:
if len(domain.get_typo3_version()) <= 3:
version = VersionInformation()
version.search_typo3_version(domain)
login = Typo3_Installation.search_login(domain)
Output.typo3_installation(domain)
if not login:
print(Fore.YELLOW + '[!] Backend login not found')
print(' | Extension search would fail')
print(' | Skipping...')
print(Fore.RESET)
else:
# Loading extensions
if (self.__extensions is None):
ext = Extensions(args.ext_state, args.top)
ext = Extensions(args.ext_state, args.top, self.__path)
self.__extensions = ext.load_extensions()
# copy them in domain object
if (domain.get_extensions() is None):