Update to v0.4.2

This commit is contained in:
Jan Rude
2015-08-21 12:13:52 +02:00
parent 71b1275c86
commit 57af1bb3a2
16 changed files with 6139 additions and 5817 deletions

View File

@@ -1,3 +1,9 @@
## Version 0.4.2
* Extensions installed with core are searched too
* Added new algorithms for Typo3 installation and used path
* Bugfixes
## Version 0.4.1 ## Version 0.4.1
* Fixed link to socksipy for python 3 * Fixed link to socksipy for python 3

View File

@@ -5,5 +5,4 @@
* Stop extension enumeration with ctrl-c * Stop extension enumeration with ctrl-c
* Privoxy check * Privoxy check
* --threads * --threads
* --user-agent (default is Mozilla/5.0) * --user-agent (default is Mozilla/5.0)
* --header (customize header fields)

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

@@ -59,8 +59,8 @@ rhu_excelexplorer
felib felib
eim2mvc eim2mvc
cherries cherries
mvwa_fortune
sm_charsethelper sm_charsethelper
mvwa_fortune
ws_test ws_test
survey survey
masi_utf8fs masi_utf8fs
@@ -95,15 +95,15 @@ jhe_dam_extender
dbreplace dbreplace
spriteiconoverview spriteiconoverview
eventmanagement eventmanagement
ms_fluid
abcconfig
bb_easyforms bb_easyforms
abcconfig
ms_fluid
ajax_report ajax_report
smu_chc_ext smu_chc_ext
ch_flash_carrousel ch_flash_carrousel
tcaobjects_demo tcaobjects_demo
jr_webmail
wsefs wsefs
jr_webmail
rhu_csvimport rhu_csvimport
pb_rsslaufschrift pb_rsslaufschrift
ch_bramacroofsimulator ch_bramacroofsimulator
@@ -112,20 +112,20 @@ p2_langfix_42
ter_tests ter_tests
clanbase clanbase
meta_openoffice meta_openoffice
st_validation_lpl
rhu_events rhu_events
st_validation_lpl
t3info t3info
ch_bramacproducts ch_bramacproducts
sort_table sort_table
bonus
alumnos
organizacionacademica organizacionacademica
alumnos
maja_condrequired maja_condrequired
bonus
hh_multipageform_example hh_multipageform_example
dsxsyndication
lz_lp_dm_log_fe lz_lp_dm_log_fe
ba_company dsxsyndication
zitatdt zitatdt
ba_company
svq_ebay svq_ebay
automator automator
rm_staticfile rm_staticfile
@@ -135,8 +135,8 @@ audio_conversion
error error
mbbrowserid mbbrowserid
wow_raid wow_raid
rg_usuarios
mf_trainmanagement mf_trainmanagement
rg_usuarios
rg_patrocinio rg_patrocinio
sp_newsteaserbox_hookexample sp_newsteaserbox_hookexample
redirectlog redirectlog
@@ -147,30 +147,31 @@ belink_syslang
buildtools buildtools
rg_empresas rg_empresas
tc_fbconnect tc_fbconnect
treppenpfosten_katalog
rf_library rf_library
treppenpfosten_katalog
ffunews ffunews
dre_besearch dre_besearch
elnews elnews
moox_template_free017
lo_backendhelper lo_backendhelper
ter_upload_test
ctefan_test
moox_news_geoinfo
moox_news_twitter
ckeditor
air_table
ft3_empty
dbal_utility
og_base
tgm_kickstart
tagger tagger
femanagerextended
boards
simplemvc_helloworld
downloads
ecs_steam
jh_extstatus
jh_pwcomments_plugin
visitorlist
xdbmysql xdbmysql
visitorlist
moox_news_twitter
air_table
moox_news_geoinfo
simplemvc_helloworld
jh_extstatus
ecs_steam
boards
tgm_kickstart
dbal_utility
ft3_empty
moox_template_free017
jh_pwcomments_plugin
ter_upload_test
ckeditor
downloads
og_base
ctefan_test
start
femanagerextended

View File

@@ -30,7 +30,6 @@ newloginbox_tmplable
bzd_staff_directory bzd_staff_directory
cc_devlog cc_devlog
sr_language_detect sr_language_detect
multicolumn
rte_chooser rte_chooser
sp_news_catimgs sp_news_catimgs
doc_core_tsref doc_core_tsref
@@ -46,6 +45,7 @@ cc_metaexif
sr_rtehtmlarea_bluelook sr_rtehtmlarea_bluelook
jf_headerslide jf_headerslide
doc_core_tsconfig doc_core_tsconfig
ml_links
imailframe imailframe
kb_cont_slide kb_cont_slide
cc_metaexec cc_metaexec
@@ -124,8 +124,8 @@ csh_hk
csh_br csh_br
dubletfinder dubletfinder
prototypejs prototypejs
wa_contentrenderinghook
hsapp_longerfeusername hsapp_longerfeusername
wa_contentrenderinghook
de_contentorganizer de_contentorganizer
danp_skinsupport danp_skinsupport
alt_forms_field_title alt_forms_field_title
@@ -181,8 +181,8 @@ sp_betterflex
localphpinclude localphpinclude
tm_classes tm_classes
danp_userlisttemplate danp_userlisttemplate
cobweb_protector
tebay tebay
cobweb_protector
rtehtmlarea_definitionlist rtehtmlarea_definitionlist
yag_theme_perfectlightbox yag_theme_perfectlightbox
eco_content eco_content
@@ -191,8 +191,8 @@ csh_vn
tm_minijoboffers tm_minijoboffers
paysuite paysuite
idaa_fe_utilies idaa_fe_utilies
go_maps_ap
mailformplusplus mailformplusplus
go_maps_ap
ak_mobile_device ak_mobile_device
iwbase iwbase
eu_correcturls eu_correcturls
@@ -235,13 +235,13 @@ mpr
displaycontroller_advanced displaycontroller_advanced
smile_form_archive smile_form_archive
tagpackprovider tagpackprovider
dfluess
doc_core_tca doc_core_tca
dfluess
jhe_adventcalender jhe_adventcalender
redirection redirection
sav_library_example5 sav_library_example5
xliff
maag_imagerotator maag_imagerotator
xliff
metadata_ts metadata_ts
remote_server remote_server
doc_tut_ts45 doc_tut_ts45
@@ -251,26 +251,26 @@ st_readmore
mak_randlistnum mak_randlistnum
extended_sys_note extended_sys_note
static_info_tables_ga static_info_tables_ga
advancedform
delete_staticfile_by_3party delete_staticfile_by_3party
ics_errorhandler advancedform
ods_workspace_mail ods_workspace_mail
ics_errorhandler
extend_dcdgooglemap extend_dcdgooglemap
tm_gallery tm_gallery
ttnews_href_marker ttnews_href_marker
sav_library_mvc_example0 sav_library_mvc_example0
doc_tut_editors doc_tut_editors
st_metatags st_metatags
doc_guide_security
ics_templavoila_mirgation_tool ics_templavoila_mirgation_tool
doc_guide_security
doc_core_skinning doc_core_skinning
ttnewscacheexpire ttnewscacheexpire
form4_contentpagination form4_contentpagination
realurl_autoconf_autodelete realurl_autoconf_autodelete
paymentlib_dibs paymentlib_dibs
paymentlib_quickpay_dk paymentlib_quickpay_dk
tgm_gallery
smile_jumpurl_fix smile_jumpurl_fix
tgm_gallery
tm_cssfilelinks tm_cssfilelinks
tsincludeorder tsincludeorder
tgmv_gallery tgmv_gallery
@@ -282,18 +282,19 @@ dialogcentral
dscentral dscentral
jb_metaexec_doc jb_metaexec_doc
maag_cenoshop maag_cenoshop
wt_spamshield_formhandler
mm_forum_blog
form4_pages_counter
fluidcontent_fed
form4_filecache
uploadtest
coo_facebook
browser_tut_map_en
filedeletion
coreupdate coreupdate
attachmentdelete
view
external_link_parameter
browser_manual_ootb_en
form4_faq form4_faq
filedeletion
wt_spamshield_formhandler
form4_pages_counter
barscheduler
browser_manual_ootb_en
attachmentdelete
browser_tut_map_en
view
mm_forum_blog
coo_facebook
form4_filecache
external_link_parameter
fluidcontent_fed
uploadtest

File diff suppressed because it is too large Load Diff

View File

@@ -26,52 +26,119 @@ from lib.output import Output
class Typo3_Installation: class Typo3_Installation:
""" """
This class checks, if Typo3 is used on the domain. 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 login page is shown.
name: URL of the domain
extensions: Extensions to check for
typo3: If Typo3 is installed
""" """
@staticmethod @staticmethod
def run(domain): def run(domain):
login_found = Typo3_Installation.search_login(domain) root = Typo3_Installation.check_root(domain)
if not login_found: check_installation = Typo3_Installation.check_installation(domain)
Typo3_Installation.check(domain) if not root:
default_files = Typo3_Installation.check_default_files(domain)
if not default_files:
typo = Typo3_Installation.check_404(domain)
# Searching for Typo3 references in HTML comments """
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 @staticmethod
def check(domain): def check_root(domain):
response = Request.get_request(domain.get_name(), '/')
Request.interesting_headers(domain, response[1], response[2])
try: try:
regex = re.compile('[Tt][Yy][Pp][Oo]3 (\d{1,2}\.\d{1,2}\.[0-9][0-9]?)') 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]) searchVersion = regex.search(response[0])
version = searchVersion.groups() version = searchVersion.groups()[0]
domain.set_typo3() domain.set_typo3()
domain.set_typo3_version(version[0].split()[0]) domain.set_typo3_version(version)
return True return True
except: except:
return False
"""
This method requests the homepage
and searches for a Typo3 path reference
in order to determine the Typo3 installation path.
"""
@staticmethod
def check_installation(domain):
response = Request.get_request(domain.get_name(), '/')
if not response:
exit(-1)
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]):
real_path = (path.groups()[1].split('"')[1])
if 'http' in real_path:
domain.set_name(real_path)
else:
domain.set_name(domain.get_name() + real_path)
domain.set_path(real_path)
domain.set_typo3()
return True
except:
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.
"""
@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'
}
for path, regex in files.items():
try: try:
regex = re.compile('TYPO3 (\d{1,2}\.\d{1,2}) CMS') response = Request.get_request(domain.get_name(), path)
searchHTML = regex.search(response[0]) regex = re.compile(regex)
version = searchHTML.groups() searchInstallation = regex.search(response[0])
installation = searchInstallation.groups()
domain.set_typo3() domain.set_typo3()
domain.set_typo3_version(version[0].split()[0])
return True return True
except: except:
return False pass
return False
# Searching Typo3 login page """
This method requests a site which is not available.
TYPO3 installations usually generate a default error page,
which can be used as an indicator.
"""
@staticmethod
def check_404(domain):
domain_name = domain.get_name()
response = Request.get_request((domain_name.split('/')[0] + '//' + domain_name.split('/')[2]), '/idontexist')
try:
regex = re.compile('[Tt][Yy][Pp][Oo]3 CMS')
searchInstallation = regex.search(response[0])
installation = searchInstallation.groups()
domain.set_typo3()
return True
except:
return False
"""
This method requests the default login page
and searches for a specific string in the title or the response.
If the access is forbidden (403), extension search is still possible.
"""
@staticmethod @staticmethod
def search_login(domain): def search_login(domain):
try: try:
response = Request.get_request(domain.get_name(), '/typo3/index.php') response = Request.get_request(domain.get_name(), '/typo3/index.php')
Request.interesting_headers(domain, response[1], response[2])
regex = re.compile('<title>(.*)</title>', re.IGNORECASE) regex = re.compile('<title>(.*)</title>', re.IGNORECASE)
searchTitle = regex.search(response[0]) searchTitle = regex.search(response[0])
title = searchTitle.groups()[0] title = searchTitle.groups()[0]
if 'TYPO3' in title or 'TYPO3 SVN ID:' in response[0]: if ('TYPO3' in title) or ('TYPO3 CMS' in response[0]) or (response[3] == 403):
domain.set_typo3() domain.set_typo3()
domain.set_login_found() domain.set_login_found()
return True return True

View File

@@ -24,9 +24,10 @@ class Domain(object):
name: URL of the domain name: URL of the domain
typo3: If Typo3 is installed typo3: If Typo3 is installed
typo3_version: Typo3 Version typo3_version: Typo3 Version
login_found: determines of the default login page was found or not login_found: Determines of the default login page was found or not
extensions: List of extensions to check for extensions: List of extensions to check for
installed_extensions: List of all installed extensions installed_extensions: List of all installed extensions
interesting_header: List of interesting headers
""" """
def __init__(self, name, ext_state, top=False): def __init__(self, name, ext_state, top=False):
if not ('http' in name): if not ('http' in name):
@@ -36,6 +37,7 @@ class Domain(object):
self.__typo3 = False self.__typo3 = False
self.__typo3_version = '' self.__typo3_version = ''
self.__login_found = False self.__login_found = False
self.__path = '/'
self.__extension_config = [ext_state, top] self.__extension_config = [ext_state, top]
self.__extensions = None self.__extensions = None
self.__installed_extensions = {} self.__installed_extensions = {}
@@ -77,6 +79,12 @@ class Domain(object):
def get_typo3_version(self): def get_typo3_version(self):
return self.__typo3_version return self.__typo3_version
def set_path(self, path):
self.__path = path
def get_path(self):
return self.__path
def get_login_found(self): def get_login_found(self):
return self.__login_found return self.__login_found

View File

@@ -54,6 +54,8 @@ class Extensions:
thread_pool.add_job((Request.head_request, (domain.get_name(), '/typo3conf/ext/' + ext))) thread_pool.add_job((Request.head_request, (domain.get_name(), '/typo3conf/ext/' + ext)))
# search global installation path # search global installation path
thread_pool.add_job((Request.head_request, (domain.get_name(), '/typo3/ext/' + ext))) thread_pool.add_job((Request.head_request, (domain.get_name(), '/typo3/ext/' + ext)))
# search extensions shipped with core
thread_pool.add_job((Request.head_request, (domain.get_name(), '/typo3/sysext/' + ext)))
thread_pool.start(6) thread_pool.start(6)
for installed_extension in thread_pool.get_result(): for installed_extension in thread_pool.get_result():

View File

@@ -29,21 +29,28 @@ class Output:
def typo3_installation(domain): def typo3_installation(domain):
print('') print('')
print('[+] Typo3 default login:'.ljust(30) + Fore.GREEN + domain.get_name() + '/typo3/index.php' + Fore.RESET) if domain.get_login_found():
if domain.get_name().endswith('/'):
print('[+] Typo3 backend login:'.ljust(30) + Fore.GREEN + domain.get_name() + 'typo3/index.php' + Fore.RESET)
else:
print('[+] Typo3 backend login:'.ljust(30) + Fore.GREEN + domain.get_name() + '/typo3/index.php' + Fore.RESET)
else:
print('[+] Typo3 backend login:'.ljust(30) + Fore.RED + 'not found' + Fore.RESET)
print('[+] Typo3 version:'.ljust(30) + Fore.GREEN + domain.get_typo3_version() + 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) if (domain.get_typo3_version() != 'could not be determined'):
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('') print('')
def interesting_headers(name, value): def interesting_headers(name, value):
string = '[!] ' + name + ':' string = '[!] ' + name + ':'
print(string.ljust(30) + value) print(string.ljust(30) + value)
def extension_output(extens): def extension_output(path, extens):
if not extens: if not extens:
print(Fore.RED + ' | No extension found' + Fore.RESET) print(Fore.RED + ' | No extension found' + Fore.RESET)
else: else:
for extension in extens: for extension in extens:
print(Fore.BLUE + '\n[+] Name: ' + extension.split('/')[3] + '\n' + "-"* 25 + Fore.RESET) print(Fore.BLUE + '\n[+] Name: ' + extension.split('/')[3] + '\n' + "-"* 31 + Fore.RESET)
print(' | Location:'.ljust(16) + extension) print(' | Location:'.ljust(16) + path + extension[1:])
if not (extens[extension] == False): if not (extens[extension] == False):
print(' | ' + extens[extension].split('.')[0] + ':'.ljust(4) + (extension + '/'+ extens[extension])) print(' | ' + extens[extension].split('.')[0] + ':'.ljust(4) + (path + extension[1:] + '/'+ extens[extension]))

View File

@@ -44,7 +44,7 @@ class Request:
except requests.exceptions.Timeout: except requests.exceptions.Timeout:
print(Fore.RED + '[x] Connection timed out' + Fore.RESET) print(Fore.RED + '[x] Connection timed out' + Fore.RESET)
except requests.exceptions.ConnectionError as e: except requests.exceptions.ConnectionError as e:
print(Fore.RED + '[x] Connection aborted.\n Please make sure you provided the right URL' + Fore.RESET) print(Fore.RED + '[x] Connection error\n | Please make sure you provided the right URL' + Fore.RESET)
except requests.exceptions.RequestException as e: except requests.exceptions.RequestException as e:
print(Fore.RED + str(e) + Fore.RESET) print(Fore.RED + str(e) + Fore.RESET)
@@ -65,32 +65,36 @@ class Request:
print(Fore.RED + str(e) + Fore.RESET) print(Fore.RED + str(e) + Fore.RESET)
@staticmethod @staticmethod
def interesting_headers(domain, headers, cookies): def interesting_headers(headers, cookies):
found_headers = {}
for header in headers: for header in headers:
if header == 'server': if header == 'server':
domain.set_interesting_headers('Server', headers.get('server')) found_headers['Server'] = headers.get('server')
elif header == 'x-powered-by': elif header == 'x-powered-by':
domain.set_interesting_headers('X-Powered-By', headers.get('x-powered-by')) found_headers['X-Powered-By'] = headers.get('x-powered-by')
elif header == 'via': elif header == 'via':
domain.set_interesting_headers('Via', headers.get('via')) found_headers['Via'] = headers.get('via')
try: try:
typo_cookie = cookies['be_typo_user'] typo_cookie = cookies['be_typo_user']
domain.set_interesting_headers('be_typo_user',typo_cookie) found_headers['be_typo_user'] = typo_cookie
except: except:
pass pass
try: try:
typo_cookie = cookies['fe_typo_user'] typo_cookie = cookies['fe_typo_user']
domain.set_interesting_headers('fe_typo_user', typo_cookie) found_headers['fe_typo_user'] = typo_cookie
except: except:
pass pass
return found_headers
@staticmethod @staticmethod
# not used atm because unreliable
def version_information(domain_name, path, regex): def version_information(domain_name, path, regex):
r = requests.get(domain_name + path, stream=True, timeout=timeout, headers=header, verify=False) r = requests.get(domain_name + path, stream=True, timeout=timeout, headers=header, verify=False)
if r.status_code == 200: if r.status_code == 200:
for content in r.iter_content(chunk_size=400, decode_unicode=False): try:
regex = re.compile(regex) for content in r.iter_content(chunk_size=400, decode_unicode=False):
search = regex.search(str(content)) regex = re.compile(regex)
version = search.groups()[0] search = regex.search(str(content))
return version version = search.groups()[0]
return version
except:
return None

View File

@@ -30,13 +30,14 @@ class Update:
unpack it and sort the extensions in different files unpack it and sort the extensions in different files
""" """
def __init__(self): def __init__(self):
print('')
self.download_ext() self.download_ext()
self.generate_list() self.generate_list()
# Progressbar # Progressbar
def dlProgress(self, count, blockSize, totalSize): def dlProgress(self, count, blockSize, totalSize):
percent = int(count*blockSize*100/totalSize) percent = int(count*blockSize*100/totalSize)
sys.stdout.write("\r[+] Downloading extentions: " + "%d%%" % percent) sys.stdout.write('\r[+] Downloading extentions: ' + '%d%%' % percent)
sys.stdout.flush() sys.stdout.flush()
# Download extensions from typo3 repository # Download extensions from typo3 repository
@@ -46,7 +47,7 @@ class Update:
with gzip.open('extensions.gz', 'rb') as f: with gzip.open('extensions.gz', 'rb') as f:
file_content = f.read() file_content = f.read()
f.close() f.close()
outF = open("extensions.xml", 'wb') outF = open('extensions.xml', 'wb')
outF.write(file_content) outF.write(file_content)
outF.close() outF.close()
os.remove('extensions.gz') os.remove('extensions.gz')
@@ -62,7 +63,7 @@ class Update:
outdated = {} # 'obsolete' and 'outdated' outdated = {} # 'obsolete' and 'outdated'
allExt = {} allExt = {}
print ("\n[+] Parsing file...") print ('\n[+] Parsing file...')
tree = ElementTree.parse('extensions.xml') tree = ElementTree.parse('extensions.xml')
root = tree.getroot() root = tree.getroot()
extension = 0 extension = 0
@@ -89,7 +90,7 @@ class Update:
extension+=1 extension+=1
# sorting lists according to number of downloads # sorting lists according to number of downloads
print ("[+] Sorting 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_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_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_beta = sorted(beta.items(), key=lambda x: int(x[1]), reverse=True)
@@ -97,7 +98,7 @@ class Update:
sorted_outdated = sorted(outdated.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) sorted_allExt = sorted(allExt.items(), key=lambda x: int(x[1]), reverse=True)
print ("[+] Generating files...") print ('[+] Generating files...')
f = open(os.path.join('extensions', 'experimental_extensions'),'w') f = open(os.path.join('extensions', 'experimental_extensions'),'w')
for i in range(0,len(sorted_experimental)): for i in range(0,len(sorted_experimental)):
f.write(sorted_experimental[i][0]+'\n') f.write(sorted_experimental[i][0]+'\n')
@@ -128,5 +129,5 @@ class Update:
f.write(sorted_allExt[i][0]+'\n') f.write(sorted_allExt[i][0]+'\n')
f.close() f.close()
print ('[+] Loaded', len(sorted_allExt), 'extensions\n') print ('[+] Loaded', len(sorted_allExt), 'extensions')
os.remove('extensions.xml') os.remove('extensions.xml')

View File

@@ -19,32 +19,41 @@
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
import re import re
import time
from lib.request import Request from lib.request import Request
class VersionInformation: class VersionInformation:
""" """
This class will search for version information This class will search for version information.
The exact version can be found in the ChangeLog,
less specific version information can be found in the NEWS or INSTALL file.
""" """
def search_typo3_version(self, domain): def search_typo3_version(self, domain):
ChangeLog = {'/typo3_src/ChangeLog':'(\d{1,2}\.\d{1,2}\.?[0-9]?[0-9]?)', changelog = {'/typo3_src/ChangeLog':'[Tt][Yy][Pp][Oo]3 (\d{1,2}\.\d{1,2}\.?[0-9]?[0-9]?)',
'/ChangeLog':'(\d{1,2}\.\d{1,2}\.?[0-9]?[0-9]?)' '/ChangeLog':'[Tt][Yy][Pp][Oo]3 (\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 = {'/typo3_src/NEWS.txt':'http://wiki.typo3.org/TYPO3_(\d{1,2}\.\d{1,2})',
'/typo3_src/NEWS.md':'[Tt][Yy][Pp][Oo]3 [Cc][Mm][Ss] (\d{1,2}\.\d{1,2}) - WHAT\'S NEW',
'/NEWS.txt':'http://wiki.typo3.org/TYPO3_(\d{1,2}\.\d{1,2})', '/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" '/NEWS.md':'[Tt][Yy][Pp][Oo]3 [Cc][Mm][Ss] (\d{1,2}\.\d{1,2}) - WHAT\'S NEW',
'/INSTALL.md':'[Tt][Yy][Pp][Oo]3 [Cc][Mm][Ss] (\d{1,2}\.\d{1,2}) [Ll][Tt][Ss]'
} }
version = 'could not determine' version = 'could not be determined'
for path, regex in ChangeLog.items(): for path, regex in changelog.items():
response = Request.version_information(domain.get_name(), path, regex) response = Request.version_information(domain.get_name(), path, regex)
if not(response is None): if not (response is None):
version = response version = response
break domain.set_typo3_version(version)
if version == 'could not determine': return True
for path, regex in News.items():
if version == 'could not be determined':
for path, regex in news.items():
response = Request.version_information(domain.get_name(), path, regex) response = Request.version_information(domain.get_name(), path, regex)
if not(response is None): if not (response is None):
version = response if len(response) > len(domain.get_typo3_version()):
break domain.set_typo3_version(version)
return True
domain.set_typo3_version(version) domain.set_typo3_version(version)

View File

@@ -18,10 +18,10 @@
# along with this program. If not, see [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/) # along with this program. If not, see [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/)
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
__version__ = "0.4.1" __version__ = '0.4.2'
__program__ = "Typo-Enumerator" __program__ = 'Typo-Enumerator'
__description__ = 'Automatic Typo3 enumeration tool' __description__ = 'Automatic Typo3 enumeration tool'
__author__ = "https://github.com/whoot" __author__ = 'https://github.com/whoot'
import sys import sys
import os.path import os.path
@@ -55,9 +55,9 @@ class Typo3:
anonGroup.add_argument('--tp', help='using TOR and 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('-p', '--port', dest='port', help='Port for TOR/Privoxy (default: 9050/8118)', type=int)
parser.add_argument( "-h", "--help", action="help") parser.add_argument( '-h', '--help', action='help')
args = parser.parse_args() args = parser.parse_args()
force = 'n'
try: try:
if args.update: if args.update:
Update() Update()
@@ -95,27 +95,31 @@ class Typo3:
self.__domain_list.append(Domain(dom, args.ext_state, args.top)) self.__domain_list.append(Domain(dom, args.ext_state, args.top))
elif args.file: elif args.file:
if not os.path.isfile(args.file): if not os.path.isfile(args.file):
print(Fore.RED + "\n[x] File not found: " + args.file + "\n | Aborting..." + Fore.RESET) print(Fore.RED + '\n[x] File not found: ' + args.file + '\n | Aborting...' + Fore.RESET)
sys.exit(-2) sys.exit(-1)
else: else:
with open(args.file, 'r') as f: with open(args.file, 'r') as f:
for line in f: for line in f:
self.__domain_list.append(Domain(line.strip('\n'), args.ext_state, args.top)) self.__domain_list.append(Domain(line.strip('\n'), args.ext_state, args.top))
for domain in self.__domain_list: for domain in self.__domain_list:
print('\n\n' + Fore.CYAN + Style.BRIGHT + '[ Checking ' + domain.get_name() + ' ]' + '\n' + "-"* 73 + Fore.RESET + Style.RESET_ALL) print('\n\n' + Fore.CYAN + Style.BRIGHT + '[ Checking ' + domain.get_name() + ' ]' + '\n' + '-'* 73 + Fore.RESET + Style.RESET_ALL)
Typo3_Installation.run(domain) Typo3_Installation.run(domain)
for key, value in domain.get_interesting_headers().items(): for key, value in domain.get_interesting_headers().items():
Output.interesting_headers(key, value) Output.interesting_headers(key, value)
if not domain.get_typo3(): if not domain.get_typo3():
print(Fore.RED + '\n[x] Typo3 is not used on this domain' + Fore.RESET) print(Fore.RED + '\n[x] It seems that Typo3 is not used on this domain' + Fore.RESET)
else: else:
if domain.get_login_found(): if len(domain.get_typo3_version()) <= 3:
# search version info
version = VersionInformation() version = VersionInformation()
version.search_typo3_version(domain) version.search_typo3_version(domain)
login = Typo3_Installation.search_login(domain)
Output.typo3_installation(domain) Output.typo3_installation(domain)
if not domain.get_login_found(): if not login:
print(Fore.YELLOW + '[!] Backend login not found\n | Extension enumeration would be failing\n | Skipping...' + Fore.RESET) print(Fore.YELLOW + '[!] Backend login not found')
print(' | Extension search would fail')
print(' | Skipping...')
print(Fore.RESET)
else: else:
# Loading extensions # Loading extensions
if (self.__extensions is None): if (self.__extensions is None):
@@ -128,19 +132,20 @@ class Typo3:
print ('\n[ Searching', len(self.__extensions), 'extensions ]') print ('\n[ Searching', len(self.__extensions), 'extensions ]')
ext.search_extension(domain, self.__extensions) ext.search_extension(domain, self.__extensions)
ext.search_ext_version(domain, domain.get_installed_extensions()) ext.search_ext_version(domain, domain.get_installed_extensions())
Output.extension_output(domain.get_installed_extensions()) Output.extension_output(domain.get_path(), domain.get_installed_extensions())
except KeyboardInterrupt: except KeyboardInterrupt:
print("\nReceived keyboard interrupt.\nQuitting...") print('\nReceived keyboard interrupt.\nQuitting...')
exit(-1) exit(-1)
finally: finally:
deinit() deinit()
now = datetime.datetime.now() now = datetime.datetime.now()
print('\n\n' + __program__ + ' finished at ' + now.strftime("%Y-%m-%d %H:%M:%S") + '\n') print('\n\n' + __program__ + ' finished at ' + now.strftime('%Y-%m-%d %H:%M:%S') + '\n')
if __name__ == "__main__": if __name__ == '__main__':
print('\n' + 73*'=' + Style.BRIGHT) print('\n' + 73*'=' + Style.BRIGHT)
print(Fore.BLUE + ' _______ ______ '.center(73)) print(Fore.BLUE)
print(' _______ ______ '.center(73))
print('|_ _|.--.--.-----.-----.|__ |'.center(73)) print('|_ _|.--.--.-----.-----.|__ |'.center(73))
print(' | | | | | _ | _ ||__ |'.center(73)) print(' | | | | | _ | _ ||__ |'.center(73))
print(' |___| |___ | __|_____||______|'.center(73)) print(' |___| |___ | __|_____||______|'.center(73))