This commit is contained in:
whoot
2020-01-06 18:03:23 +01:00
parent b90db75880
commit 17d9b7b8e6
7 changed files with 30 additions and 13 deletions

View File

@@ -7,7 +7,7 @@ Typo3Scan does not exploit any vulnerabilities! It´s soley purpose was to enume
**Note:** **Note:**
When I started this project many years ago, the version information could be easily read from text files (Readmes, Changelogs, etc.). Since then a lot has changed. When I started this project many years ago, the version information could be easily read from text files (Readmes, Changelogs, etc.). Since then a lot has changed.
Typo3 now restricts access to directories and files by default and since the use of [Composer](https://github.com/composer/composer), version information of extensions are not available in files anymore. Typo3 now restricts access to directories and files by default and version information of extensions may not available in files anymore.
In addition, various basic functions have changed over time. In addition, various basic functions have changed over time.
For these reasons this tool will probably *not receive further major releases*. For these reasons this tool will probably *not receive further major releases*.

View File

@@ -1,3 +1,7 @@
## Version 0.5.1
* Output and version detection fix
## Version 0.5 ## Version 0.5
* Rename to Typo3Scan * Rename to Typo3Scan

View File

@@ -232,4 +232,4 @@ class Domain:
print(' \u251c Subcomponent:'.ljust(29), vuln[2]) print(' \u251c Subcomponent:'.ljust(29), vuln[2])
print(' \u2514 Affected Versions:'.ljust(29), '{} - {}\n'.format(vuln[3], vuln[4])) print(' \u2514 Affected Versions:'.ljust(29), '{} - {}\n'.format(vuln[3], vuln[4]))
else: else:
print(' \u251c', Fore.RED + 'No version information found' + Fore.RESET) print(' \u2514', Fore.RED + 'No version information found.' + Fore.RESET)

View File

@@ -36,7 +36,7 @@ class Extensions:
This method loads the extensions from the database and searches for installed extensions. This method loads the extensions from the database and searches for installed extensions.
/typo3conf/ext/: Local installation path. This is where extensions usually get installed. /typo3conf/ext/: Local installation path. This is where extensions usually get installed.
/typo3/ext/: Global installation path (not used atm) /typo3/ext/: Global installation path (not used atm)
/typo3/sysext/: Extensions shipped with core /typo3/sysext/: Extensions shipped with core
""" """
found_extensions = {} found_extensions = {}
thread_pool = ThreadPool() thread_pool = ThreadPool()
@@ -60,12 +60,15 @@ class Extensions:
thread_pool = ThreadPool() thread_pool = ThreadPool()
for extension,values in found_extensions.items(): for extension,values in found_extensions.items():
thread_pool.add_job((request.version_information, (values['url'] + 'Documentation/ChangeLog/Index.rst', None))) thread_pool.add_job((request.version_information, (values['url'] + 'Documentation/ChangeLog/Index.rst', None)))
thread_pool.add_job((request.version_information, (values['url'] + 'Documentation/Changelog/Index.rst', None)))
thread_pool.add_job((request.version_information, (values['url'] + 'Documentation/Settings.cfg', None))) thread_pool.add_job((request.version_information, (values['url'] + 'Documentation/Settings.cfg', None)))
thread_pool.add_job((request.version_information, (values['url'] + 'Documentation/Settings.yml', None))) thread_pool.add_job((request.version_information, (values['url'] + 'Documentation/Settings.yml', '(?:release:)\s?([0-9]+\.[0-9]+\.?[0-9]?[0-9]?)')))
thread_pool.add_job((request.version_information, (values['url'] + 'Settings.yml', None))) thread_pool.add_job((request.version_information, (values['url'] + 'Settings.yml', '(?:release:)\s?([0-9]+\.[0-9]+\.?[0-9]?[0-9]?)')))
thread_pool.add_job((request.version_information, (values['url'] + 'Documentation/ChangeLog', None)))
thread_pool.add_job((request.version_information, (values['url'] + 'Documentation/Index.rst', None))) thread_pool.add_job((request.version_information, (values['url'] + 'Documentation/Index.rst', None)))
thread_pool.add_job((request.version_information, (values['url'] + 'composer.json', '(?:"dev-master":|"version":)\s?"([0-9]+\.[0-9]+\.[0-9x][0-9x]?)'))) thread_pool.add_job((request.version_information, (values['url'] + 'composer.json', '(?:"dev-master":|"version":)\s?"([0-9]+\.[0-9]+\.[0-9x][0-9x]?)')))
thread_pool.add_job((request.version_information, (values['url'] + 'Index.rst', None))) thread_pool.add_job((request.version_information, (values['url'] + 'Index.rst', None)))
thread_pool.add_job((request.version_information, (values['url'] + 'doc/manual.sxw', None)))
thread_pool.add_job((request.version_information, (values['url'] + 'ChangeLog', None))) thread_pool.add_job((request.version_information, (values['url'] + 'ChangeLog', None)))
thread_pool.add_job((request.version_information, (values['url'] + 'CHANGELOG.md', None))) thread_pool.add_job((request.version_information, (values['url'] + 'CHANGELOG.md', None)))
thread_pool.add_job((request.version_information, (values['url'] + 'ChangeLog.txt', None))) thread_pool.add_job((request.version_information, (values['url'] + 'ChangeLog.txt', None)))
@@ -81,6 +84,8 @@ class Extensions:
name = version_path[0][0] name = version_path[0][0]
if 'Documentation/' in name: if 'Documentation/' in name:
name = name[:name.rfind('Documentation/')+1] name = name[:name.rfind('Documentation/')+1]
if 'doc/' in name:
name = name[:name.rfind('doc/')+1]
name = name[name.find('ext/')+4:name.rfind('/')] name = name[name.find('ext/')+4:name.rfind('/')]
found_extensions[name]['version'] = version found_extensions[name]['version'] = version
found_extensions[name]['file'] = path found_extensions[name]['file'] = path
@@ -90,7 +95,7 @@ class Extensions:
def output(self, extension_dict, database): def output(self, extension_dict, database):
conn = sqlite3.connect(database) conn = sqlite3.connect(database)
c = conn.cursor() c = conn.cursor()
print('\n\n [+] Extension information\n \\') print('\n |\n [+] Extension information\n \\')
for extension,info in extension_dict.items(): for extension,info in extension_dict.items():
c.execute('SELECT title FROM extensions where extensionkey=?', (extension,)) c.execute('SELECT title FROM extensions where extensionkey=?', (extension,))
title = c.fetchone()[0] title = c.fetchone()[0]

View File

@@ -123,6 +123,8 @@ def version_information(url, regex):
else: else:
r = requests.get(url, stream=True, timeout=config['timeout'], headers=custom_headers, verify=False) r = requests.get(url, stream=True, timeout=config['timeout'], headers=custom_headers, verify=False)
if r.status_code == 200: if r.status_code == 200:
if 'manual.sxw' in url:
return 'check manually'
try: try:
for content in r.iter_content(chunk_size=400, decode_unicode=False): for content in r.iter_content(chunk_size=400, decode_unicode=False):
search = re.search(regex, str(content)) search = re.search(regex, str(content))
@@ -130,5 +132,11 @@ def version_information(url, regex):
r.close() r.close()
return version return version
except: except:
r.close() try:
return None search = re.search('([0-9]+-[0-9]+-[0-9]+)', str(content))
version = search.group(1)
r.close()
return version
except:
r.close()
return None

View File

@@ -23,7 +23,7 @@ from queue import Queue
from progressbar import Bar, AdaptiveETA, Percentage, ProgressBar from progressbar import Bar, AdaptiveETA, Percentage, ProgressBar
bar = None bar = None
number = 1 number = 0
class ThreadPoolSentinel: class ThreadPoolSentinel:
pass pass
@@ -38,7 +38,7 @@ class ThreadPool:
""" """
def __init__(self): def __init__(self):
global number global number
number = 1 number = 0
self.__work_queue = Queue() self.__work_queue = Queue()
self.__result_queue = Queue() self.__result_queue = Queue()
self.__active_threads = 0 self.__active_threads = 0
@@ -114,6 +114,6 @@ def _work_function(job_q, result_q, version_search):
except Exception as e: except Exception as e:
print(e) print(e)
finally: finally:
bar.update(number)
number = number+1 number = number+1
bar.update(number)
job_q.task_done() job_q.task_done()

View File

@@ -18,7 +18,7 @@
# 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.5' __version__ = '0.5.1'
__program__ = 'Typo3Scan' __program__ = 'Typo3Scan'
__description__ = 'Automatic Typo3 enumeration tool' __description__ = 'Automatic Typo3 enumeration tool'
__author__ = 'https://github.com/whoot' __author__ = 'https://github.com/whoot'
@@ -145,7 +145,7 @@ Options:
check.search_typo3_version() check.search_typo3_version()
# Search extensions # Search extensions
print(' [+] Extension Search') print('\n [+] Extension Search')
if not self.__extensions: if not self.__extensions:
conn = sqlite3.connect(database) conn = sqlite3.connect(database)
c = conn.cursor() c = conn.cursor()