#!/usr/bin/env python3 # -*- coding: utf-8 -*- #------------------------------------------------------------------------------- # Typo3Scan - Automatic Typo3 Enumeration Tool # Copyright (c) 2014-2020 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 # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/) #------------------------------------------------------------------------------- import re import string import random import sqlite3 from colorama import Fore import lib.request as request from pkg_resources import parse_version class Domain: """ This class stores following information about a domain: name: URL of the domain typo3: If Typo3 is installed typo3_version: Typo3 Version path: Full path to Typo3 installation installed_extensions: List of all installed extensions """ def __init__(self, name): if not ('http' in name): self.__name = 'https://' + name else: self.__name = name self.__typo3 = False self.__typo3_version = '' self.__path = '' self.__installed_extensions = {} def get_name(self): return self.__name def set_name(self, name): self.__name = name def is_typo3(self): return self.__typo3 def set_typo3(self): self.__typo3 = True def set_typo3_version(self, version): self.__typo3_version = version def get_typo3_version(self): return self.__typo3_version def set_path(self, path): self.__path = path def get_path(self): return self.__path def check_root(self): """ This method requests the root page and searches for a specific string. Usually there are some TYPO3 notes in the HTML comments. If found, it searches for a Typo3 path reference in order to determine the Typo3 installation path. """ response = request.get_request('{}'.format(self.get_name())) full_path = self.get_name() if re.search('powered by TYPO3', response['html']): self.set_typo3() path = re.search('="/?(\S*?)/?(?:typo3temp|typo3conf)/'.format(self.get_name()), response['html']) if path and path.groups()[0] != '': path = path.groups()[0].replace(self.get_name(), '') if path != '': full_path = '{}/{}'.format(self.get_name(), path) if full_path.endswith('/'): full_path = full_path[:-1] self.set_path(full_path) def check_default_files(self): """ This method requests different files, which are generated on installation. Note: They are not accessible anymore on newer Typo3 installations """ files = {'typo3_src/README.md':'TYPO3 CMS', 'typo3_src/README.txt':'TYPO3 CMS', 'typo3_src/INSTALL.md':'INSTALLING TYPO3', 'typo3_src/INSTALL.txt':'INSTALLING TYPO3', 'typo3_src/LICENSE.txt':'TYPO3', 'typo3_src/CONTRIBUTING.md':'TYPO3 CMS' } for path, regex in files.items(): try: response = request.get_request('{}/{}'.format(self.get_path(), path)) regex = re.compile(regex) searchInstallation = regex.search(response['html']) installation = searchInstallation.groups() self.set_typo3() return True except: pass return False def check_404(self): """ This method requests a site which is not available by using a random generated string. TYPO3 installations usually generate a default error page, which can be used as an indicator. """ random_string = ''.join(random.choice(string.ascii_lowercase) for i in range(10)) response = request.get_request('{}/{}'.format(self.get_path(), random_string)) search404 = re.search('[Tt][Yy][Pp][Oo]3 CMS', response['html']) if search404: self.set_typo3() def search_login(self): """ 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. """ print('[+] Backend Login') # maybe /typo3_src/typo3/index.php too? response = request.get_request('{}/typo3/index.php'.format(self.get_path())) searchTitle = re.search('