def start(id, url, ua, ga, source): version = '0' cmseek.statement('Detecting Version and vulnerabilities') if ga == '1' or ga == '2' or ga == '3': ## something good was going to happen but my sleep messed it up TODO: will fix it later cmseek.statement('Generator Tag Available... Trying version detection using generator meta tag') rr = re.findall(r'<meta name=\"generator\" content=\"WordPress (.*?)\"', source) if rr != []: version = rr[0] cmseek.success(cmseek.bold + cmseek.fgreen + "Version Detected, WordPress Version %s" % version + cmseek.cln) else: cmseek.warning("Generator tag was a big failure.. looking up /feed/") fs = cmseek.getsource(url + '/feed/', ua) if fs[0] != '1': # Something messed up real bad cmseek.warning("Couldn't get feed source code, Error: %s" % fs[1]) else: fv = re.findall(r'<generator>https://wordpress.org/\?v=(.*?)</generator>', fs[1]) if fv != []: # Not empty good news xD version = fv[0] cmseek.success(cmseek.bold + cmseek.fgreen + "Version Detected, WordPress Version %s" % version + cmseek.cln) else: cmseek.warning("Well even feed was a failure... let's lookup wp-links-opml then") opmls = cmseek.getsource(url + '/wp-links-opml.php', ua) if opmls[0] != '1': # Something messed up real bad cmseek.warning("Couldn't get wp-links-links source code, Error: %s" % opmls[1]) else: fv = re.findall(r'generator=\"wordpress/(.*?)\"', opmls[1]) if fv != []: # Not empty good news xD || you can guess it's copied right? version = fv[0] cmseek.success(cmseek.bold + cmseek.fgreen + "Version Detected, WordPress Version %s" % version + cmseek.cln) else: ## new version detection methods will be added in the future updates cmseek.error("Couldn't Detect Version") #sorry master thingy removed... sounded kinda cheesy -_- version = '0' return version
def start(id, url, ua, ga, source): cmseek.info("Starting Username Harvest") # User enumertion via site's json api cmseek.info('Harvesting usernames from wp-json api') wpjsonuser = [] wpjsonsrc = cmseek.getsource(url + '/wp-json/wp/v2/users', ua) if wpjsonsrc[0] != "1" or 'slug' not in wpjsonsrc[1]: cmseek.warning("Json api method failed trying with next") else: try: for user in json.loads(wpjsonsrc[1]): wpjsonuser.append(user['slug']) cmseek.success("Found user from wp-json : " + cmseek.fgreen + cmseek.bold + user['slug'] + cmseek.cln) except: cmseek.warning("Failed to parse json") # user enumertion vua jetpack api cmseek.info('Harvesting usernames from jetpack public api') jpapiuser = [] strippedurl = url.replace('http://','') strippedurl = strippedurl.replace('https://', '') # Pretty sure it is an ugly solution but oh well jpapisrc = cmseek.getsource('https://public-api.wordpress.com/rest/v1.1/sites/' + strippedurl + '/posts?number=100&pretty=true&fields=author', ua) if jpapisrc[0] != '1' or 'login' not in jpapisrc[1]: cmseek.warning('No results from jetpack api... maybe the site doesn\'t use jetpack') else: for user in json.loads(jpapisrc[1])['posts']: if user['author']['login'] not in str(jpapiuser): jpapiuser.append(user['author']['login']) cmseek.success("Found user from Jetpack api : " + cmseek.fgreen + cmseek.bold + user['author']['login'] + cmseek.cln) jpapiuser = list(set(usr.strip() for usr in jpapiuser)) # Removing duplicate usernames # the regular way of checking vua user Parameter -- For now just check upto 20 ids cmseek.info('Harvesting usernames from wordpress author Parameter') global wpparamuser wpparamuser = [] usrrange = range(31) # ain't it Obvious threads = [threading.Thread(target=wpauthorenum, args=(ua,url,r)) for r in usrrange] for thread in threads: thread.start() for thread in threads: thread.join() # Combine all the usernames that we collected usernames = set(wpjsonuser+jpapiuser+wpparamuser) if len(usernames) > 0: usernamesgen = '1' # Some usernames were harvested if len(usernames) == 1: cmseek.success(cmseek.bold + cmseek.fgreen + str(len(usernames)) + " Usernames" + " was enumerated" + cmseek.cln) else: cmseek.success(cmseek.bold + cmseek.fgreen + str(len(usernames)) + " Usernames" + " were enumerated" + cmseek.cln) else: usernamesgen = '0' # Failure cmseek.warning("Couldn't enumerate usernames :( ") return [usernamesgen, usernames]
def start(id, url, ua, ga, source, detection_method, headers): if id == 'umbraco': cms_version = 0 cmseek.statement('Starting Umbraco DeepScan') if detection_method == 'source': # detect if it's false positive umbraco_url = url + '/umbraco' test_src = cmseek.getsource(umbraco_url, ua) if test_src[0] == '1': # okay we got the source let's test it if 'var Umbraco' in test_src[1]: # Umbraco Detected! # Let's get version cms_version = umbraco_version_detect.start(headers, url, ua, test_src[1]) else: falsepositive() else: falsepositive() else: # detection method was different so we are good and no need to check for false positive i guess cms_version = umbraco_version_detect.start(headers, url, ua) cmseek.clearscreen() cmseek.banner("CMS Scan Results") sresult.target(url) sresult.cms('Umbraco',cms_version,'https://umbraco.com') cmseek.update_log('cms_name', 'Umbraco') # update log if cms_version != '0' and cms_version != None: cmseek.update_log('cms_version', cms_version) # update log cmseek.update_log('cms_url', 'https://umbraco.com') # update log comptime = round(time.time() - cmseek.cstart, 2) log_file = os.path.join(cmseek.log_dir, 'cms.json') sresult.end(str(cmseek.total_requests), str(comptime), log_file) return
def check(url, ua): robots = url + '/robots.txt' robots_source = cmseek.getsource(robots, ua) if robots_source[0] == '1' and robots_source[1] != '': # Check begins here robotstr = robots_source[1] if 'If the Joomla site is installed' in robotstr or 'Disallow: /administrator/' in robotstr: return ['1', 'joom'] if 'Allow: /core/*.css$' in robotstr or 'Disallow: /index.php/user/login/' in robotstr or 'Disallow: /web.config' in robotstr: return ['1', 'dru'] if 'Disallow: /wp-admin/' in robotstr or 'Allow: /wp-admin/admin-ajax.php' in robotstr: return ['1', 'wp'] if 'Disallow: /kernel/' in robotstr and 'Disallow: /language/' in robotstr and 'Disallow: /templates_c/' in robotstr: return ['1', 'xoops'] if 'Disallow: /textpattern' in robotstr: return ['1', 'tpc'] if 'Disallow: /sitecore' in robotstr or 'Disallow: /sitecore_files' in robotstr or 'Disallow: /sitecore modules' in robotstr: return ['1', 'score'] t3_regex = re.search(r'Sitemap: http(.*?)\?type=', robotstr) if t3_regex != None: return ['1', 'tp3'] return ['0', ''] else: cmseek.error('robots.txt not found or empty!') return ['0', '']
def start(headers, url, ua, temp_src=''): cmseek.statement('Detecting Umbraco using headers [Method 1 of 2]') header = headers.split('\n') regex = [] for tail in header: if 'x-umbraco-version:' in tail.lower(): regex = re.findall(r'X-Umbraco-Version: (.*)', tail, re.IGNORECASE) if regex != [] and regex[0] != "": # detection via headers successful cmseek.success('Umbraco version ' + cmseek.bold + cmseek.fgreen + regex[0] + cmseek.cln + ' detected') return regex[0] else: cmseek.statement('Detecting Umbraco using source code [Method 2 of 2]') if temp_src == '': # no additional source code sent so we have to get it temp_url = url + '/umbraco' temp_src = cmseek.getsource(temp_url, ua) if temp_src[0] == '1': temp_src = temp_src[1] else: cmseek.error('Version detection failed!') return '0' new_regex = re.findall('"version"\: "(.*?)"', temp_src) if new_regex != [] and new_regex[0] != "": # detection via headers successful cmseek.success('Umbraco version ' + cmseek.bold + cmseek.fgreen + new_regex[0] + cmseek.cln + ' detected') return new_regex[0] else: cmseek.error('Version detection failed!') return '0'
def start(source, url, ua): regex = re.findall(r'<!--.*-->', source, re.DOTALL) if regex != []: for r in regex: if 'FlexCMP' in r and 'v.' in r: tmp = r.split('\n') for t in tmp: if 'v.' in t: kek = re.findall(r'v. (.*?) -', t) if kek != []: # coding this was actually fun idk why ;--; version = kek[0] cmseek.success('FlexCMP version ' + cmseek.bold + cmseek.fgreen + version + cmseek.cln + ' detected from source') return version else: kurama = cmseek.getsource(url, ua) header = kurama[2].split('\n') regex = [] for tail in header: if 'X-Powered-By' in tail and 'FlexCMP' in tail: regex = re.findall( r'X-Powered-By: FlexCMP Application Server \[v\. (.*?) - ', tail) if regex != []: cmseek.success('FlexCMP version ' + cmseek.bold + cmseek.fgreen + regex[0] + cmseek.cln + ' detected from header') return regex[0] else: cmseek.error('Version detection failed!') return '0'
def start(id, url, ua, ga, source): if ga == '1': # well for now we only have one way of detecting the version - Not any more! cmseek.statement( 'Detecting version using generator meta tag [Method 1 of 2]') regex = re.findall( r'<meta name="Generator" content="Drupal (.*?) \(http(s|):\/\/(www\.|)drupal.org\)"', source) if regex != []: cmseek.success('Drupal version ' + cmseek.bold + regex[0][0] + cmseek.cln + ' detected') return regex[0][0] else: # Detect version via CHANGELOG.txt (not very accurate) cmseek.statement( 'Detecting version using CHANGELOG.txt [Method 2 of 2]') changelog = url + '/CHANGELOG.txt' changelog_source = cmseek.getsource(changelog, ua) if changelog_source[0] == '1' and 'Drupal' in changelog_source[1]: cl_array = changelog_source[1].split('\n') for line in cl_array: match = re.findall(r'Drupal (.*?),', line) if match != []: cmseek.success('Drupal version ' + cmseek.bold + match[0] + cmseek.cln + ' detected') return match[0] cmseek.error('Drupal version detection failed!') return '0' else: cmseek.error('Drupal version detection failed!') return '0' return '0'
def start(version, ua): if version == "0": cmseek.warning( "Skipping version vulnerability scan as WordPress Version wasn't detected" ) wpvdbres = '0' # fix for issue #3 result = "" vfc = "" else: ## So we have a version let's scan for vulnerabilities cmseek.info( "Checking version vulnerabilities [props to wpvulndb for their awesome api ;)]" ) vfc = version.replace( '.', '' ) # NOT IMPORTANT: vfc = version for check well we have to kill all the .s in the version for looking it up on wpvulndb.. kinda weird if you ask me ws = cmseek.getsource("https://wpvulndb.com/api/v2/wordpresses/" + vfc, ua) print(ws[0]) if ws[0] == "1": # wjson = json.loads(ws[1]) + vfd + "['release_date']" wpvdbres = '1' ## We have the wpvulndb results result = json.loads(ws[1])[version] else: wpvdbres = '0' result = "" cmseek.error('Error Retriving data from wpvulndb') return [wpvdbres, result, vfc]
def check_directory(url, file, ua): global joom_dir_found, joom_dirs file_check = cmseek.getsource(url + '/' + file, ua) if file_check[0] == '1': if 'Index of' in file_check[1] or 'Last modified</a>' in file_check[1]: cmseek.success('Directory listing enabled in: ' + cmseek.bold + cmseek.fgreen + file + cmseek.cln) joom_dir_found += 1 joom_dirs.append(file)
def check(url, ua): robots = url + '/robots.txt' robots_source = cmseek.getsource(robots, ua) # print(robots_source[1]) if robots_source[0] == '1' and robots_source[1] != '': # Check begins here robotstr = robots_source[1] if 'If the Joomla site is installed' in robotstr or 'Disallow: /administrator/' in robotstr: return ['1', 'joom'] if 'Allow: /core/*.css$' in robotstr or 'Disallow: /index.php/user/login/' in robotstr or 'Disallow: /web.config' in robotstr: return ['1', 'dru'] if 'Disallow: /wp-admin/' in robotstr or 'Allow: /wp-admin/admin-ajax.php' in robotstr: return ['1', 'wp'] if 'Disallow: /kernel/' in robotstr and 'Disallow: /language/' in robotstr and 'Disallow: /templates_c/' in robotstr: return ['1', 'xoops'] if 'Disallow: /textpattern' in robotstr: return ['1', 'tpc'] if 'Disallow: /sitecore' in robotstr or 'Disallow: /sitecore_files' in robotstr or 'Disallow: /sitecore modules' in robotstr: return ['1', 'score'] if 'Disallow: /phpcms' in robotstr or 'robots.txt for PHPCMS' in robotstr: return ['1', 'phpc'] if 'Disallow: /*mt-content*' in robotstr or 'Disallow: /mt-includes/' in robotstr: return ['1', 'moto'] if 'Disallow: /jcmsplugin/' in robotstr: return ['1', 'jcms'] if 'Disallow: /ip_cms/' in robotstr or 'ip_backend_frames.php' in robotstr or 'ip_backend_worker.php' in robotstr: return ['1', 'impage'] if 'Disallow: /flex/tmp/' in robotstr or 'flex/Logs/' in robotstr: return ['1', 'flex'] if 'Disallow: /e107_admin/' in robotstr or 'e107_handlers' in robotstr or 'e107_files/cache' in robotstr: return ['1', 'e107'] t3_regex = re.search(r'Sitemap: http(.*?)\?type=', robotstr) if t3_regex != None: return ['1', 'tp3'] return ['0', ''] else: cmseek.error('robots.txt not found or empty!') return ['0', '']
def start(url, ua): kurama = cmseek.getsource(url, ua) header = kurama[2].split('\n') regex = [] for tail in header: if 'X-Powered-By: CMS Danneo' in tail: regex = re.findall(r'X-Powered-By: CMS Danneo (.*)', tail) if regex != []: cmseek.success('Danneo CMS version ' + cmseek.bold + cmseek.fgreen + regex[0] + cmseek.cln + ' detected') return regex[0] else: cmseek.error('Version detection failed!') return '0'
def start(url, ua): kurama = cmseek.getsource(url, ua) header = kurama[2].split('\n') regex = [] for tail in header: if 'Server' in tail and 'OpenCms' in tail: regex = re.findall(r'Server: OpenCms/(.*)', tail) if regex != []: cmseek.success('OpenCms version ' + cmseek.bold + cmseek.fgreen + regex[0] + cmseek.cln + ' detected') return regex[0] else: cmseek.error('Version detection failed!') return '0'
def start(url, ua): kurama = cmseek.getsource(url, ua) header = kurama[2].split('\n') regex = [] for tail in header: if 'MicrosoftSharePointTeamServices' in tail: regex = re.findall(r'MicrosoftSharePointTeamServices: (.*)', tail) if regex != []: cmseek.success('SharePoint version ' + cmseek.bold + cmseek.fgreen + regex[0] + cmseek.cln + ' detected') return regex[0] else: cmseek.error('Version detection failed!') return '0'
def start(url, ua): reg_url = url + '/wp-login.php?action=register' cmseek.info('Checking user registration status') reg_source = cmseek.getsource(reg_url, ua) reg_status = '0' if reg_source[0] == '1' and '<form' in reg_source[1]: if 'Registration confirmation will be emailed to you' in reg_source[ 1] or 'value="Register"' in reg_source[ 1] or 'id="user_email"' in reg_source[1]: cmseek.success('User registration open: ' + cmseek.bold + cmseek.fgreen + reg_url + cmseek.cln) reg_status = '1' return [reg_status, reg_url]
def start(url, ua): kurama = cmseek.getsource(url, ua) # was listening to https://soundcloud.com/ahmed-a-zidan/naruto-sad-music no better came to mind header = kurama[2].split('\n') regex = [] for tail in header: if 'X-CMS-Version' in tail: regex = re.findall(r'X-CMS-Version: (.*)', tail) if regex != []: cmseek.success('UMI.CMS version ' + cmseek.bold + cmseek.fgreen + regex[0] + cmseek.cln + ' detected') return regex[0] else: cmseek.error('Version detection failed!') return '0'
def start(url, ua): kurama = cmseek.getsource(url, ua) header = kurama[2].split('\n') regex = [] for tail in header: if 'X-Garden-Version: Vanilla' in tail: regex = re.findall(r'X-Garden-Version: Vanilla (\d.*)', tail) if regex != []: cmseek.success('Vanilla version ' + cmseek.bold + cmseek.fgreen + regex[0] + cmseek.cln + ' detected') return regex[0] else: cmseek.error('Version detection failed!') return '0'
def start(url, ua): reg_url = url + '/index.php?option=com_users&view=registration' reg_source = cmseek.getsource(reg_url, ua) if reg_source[0] == '1': if 'registration.register' in reg_source[ 1] or 'jform_password2' in reg_source[ 1] or 'jform_email2' in reg_source[1]: cmseek.success('User registration open, ' + cmseek.bold + reg_url + cmseek.cln) return ['1', reg_url] else: return ['0', ''] else: return ['0', '']
def start(url, ua): rss_file = url + '/wp-includes/rss.php' rss_source = cmseek.getsource(rss_file, ua) if rss_source[0] == '1' and 'on line' in rss_source[1]: path = re.findall(r'<b>/(.*?)wp-includes/rss.php</b>', rss_source[1]) if path != []: return path[0] tw_theme = url + '/wp-content/themes/twentyfifteen/index.php' theme_source = cmseek.getsource(tw_theme, ua) if theme_source[0] == '1' and 'Uncaught Error:' in theme_source[1]: path = re.findall( r'<b>(.*?)wp-content/themes/twentyfifteen/index.php</b>', theme_source[1]) if path != []: return path[0] tw_theme = url + '/wp-content/themes/twentysixteen/index.php' theme_source = cmseek.getsource(tw_theme, ua) if theme_source[0] == '1' and 'Uncaught Error:' in theme_source[1]: path = re.findall( r'<b>(.*?)wp-content/themes/twentyfifteen/index.php</b>', theme_source[1]) if path != []: return path[0] tw_theme = url + '/wp-content/themes/twentyseventeen/index.php' theme_source = cmseek.getsource(tw_theme, ua) if theme_source[0] == '1' and 'Uncaught Error:' in theme_source[1]: path = re.findall( r'<b>(.*?)wp-content/themes/twentyfifteen/index.php</b>', theme_source[1]) if path != []: return path[0] return ""
def start(url, ua): # Detect version via magento_version (not very accurate) cmseek.statement('Detecting version using magento_version [Method 1 of 1]') magento_version = url + '/magento_version' changelog_source = cmseek.getsource(magento_version, ua) if changelog_source[0] == '1' and 'Magento' in changelog_source[1]: cl_array = changelog_source[1].split('/') if cl_array != []: cmseek.success('Magento version ' + cmseek.bold + cl_array[1] + cmseek.cln + ' detected') return cl_array[1] cmseek.error('Magento version detection failed!') return '0' else: cmseek.error('Magento version detection failed!') return '0'
def start(url, ua): cmseek.statement('Detecting Commerce Server using headers [Method 1 of 1]') kurama = cmseek.getsource(url, ua) header = kurama[2].split('\n') regex = [] for tail in header: if 'commerce-server-software:' in tail.lower(): regex = re.findall(r'commerce-server-software: (.*)', tail, re.IGNORECASE) if regex != [] and regex[0] != "": cmseek.success('Commerce Server version ' + cmseek.bold + cmseek.fgreen + regex[0] + cmseek.cln + ' detected') return regex[0] else: cmseek.error('Version detection failed!') return '0'
def wpauthorenum(ua, url, param): ## WordPress function for Collecting usernames from author Parameter ## Had to create a different function to avoid some pickle issues param = param + 1 i = str(param) # cmseek.statement('Checking for ?author=' + i) # Looks Ugly.. enable if you want over verbose result authorsrc = cmseek.getsource(url + '/?author=' + i, ua) if authorsrc[0] == '1' and '/author/' in authorsrc[3]: ## Detection using the url redirection author = re.findall(r'/author/(.*?)/', str(authorsrc[3])) if author != []: cmseek.success('Found user from redirection: ' + cmseek.fgreen + cmseek.bold + author[0] + cmseek.cln) return author[0] elif authorsrc[0] == '1' and '/author/' in authorsrc[1]: author = re.findall(r'/author/(.*?)/', str(authorsrc[1])) if author != []: cmseek.success('Found user from source code: ' + cmseek.fgreen + cmseek.bold + author[0] + cmseek.cln) return author[0]
def start(ga_content, url, ua): ga_content = ga_content.lower() regex = re.findall(r'ophal (.*?) \(ophal.org\)', ga_content) if regex != []: version = regex[0] cmseek.success('Ophal version ' + cmseek.bold + cmseek.fgreen + version + cmseek.cln + ' detected') return version else: kurama = cmseek.getsource(url, ua) # copypasta header = kurama[2].split('\n') regex = [] for tail in header: if 'x-powered-by' in tail: regex = re.findall(r'x-powered-by: Ophal (.*?) \(ophal.org\)', tail) if regex != []: cmseek.success('Ophal version ' + cmseek.bold + cmseek.fgreen + regex[0] + cmseek.cln + ' detected') return regex[0] else: cmseek.error('Version detection failed!') return '0'
def check(url, ua): robots = url + '/robots.txt' robots_source = cmseek.getsource(robots, ua) # print(robots_source[1]) if robots_source[0] == '1' and robots_source[1] != '': # Check begins here robots_txt_content = robots_source[1] #### START DETECTION FROM HERE ## || <- if either of it matches cms detected ## :::: <- all the strings has to match (implemented to decrease false positives) robots_txt_detection_keys = [ 'If the Joomla site is installed::::Disallow: /administrator/:-joom', 'Allow: /core/*.css$||Disallow: /index.php/user/login/||Disallow: /web.config:-dru', 'Disallow: /wp-admin/||Allow: /wp-admin/admin-ajax.php:-wp', 'Disallow: /kernel/::::Disallow: /language/::::Disallow: /templates_c/:-xoops', 'Disallow: /textpattern:-tpc', 'Disallow: /sitecore||Disallow: /sitecore_files||Disallow: /sitecore modules:-score', 'Disallow: /phpcms||robots.txt for PHPCMS:-phpc', 'Disallow: /*mt-content*||Disallow: /mt-includes/:-moto', 'Disallow: /jcmsplugin/:-jcms', 'Disallow: /ip_cms/||ip_backend_frames.php||ip_backend_worker.php:-impage', 'Disallow: /flex/tmp/||flex/Logs/:-flex', 'Disallow: /e107_admin/||e107_handlers||e107_files/cache:-e107', 'Disallow: /plus/ad_js.php||Disallow: /plus/erraddsave.php||Disallow: /plus/posttocar.php||Disallow: /plus/disdls.php||Disallow: /plus/mytag_js.php||Disallow: /plus/stow.php:-dede', 'modules/contentbox/themes/:-cbox', 'Disallow: /contao/:-contao', 'Disallow: /concrete:-con5', 'Disallow: /auth/cas::::Disallow: /auth/cas/callback:-dscrs', 'uc_client::::uc_server::::forum.php?mod=redirect*:-discuz', 'Disallow: /AfterbuySrcProxy.aspx||Disallow: /afterbuy.asmx||Disallow: /afterbuySrc.asmx:-abuy', 'Disallow: /craft/:-craft', # Chances of it being a falsepositive are higher than the chances of me doing something good with my life ;__; 'Disallow: /app/::::Disallow: /store_closed.html:-csc', 'Disallow: /*?cartcmd=*:-dweb', 'Disallow: /epages/Site.admin/||Disallow: /epages/*:-epgs', 'Disallow: /Mediatheque/:-ezpub', 'robots.txt automaticaly generated by PrestaShop:-presta', 'demandware.store||demandware.static||demandware.net:-sfcc', 'robots.txt for Umbraco||Disallow: /umbraco||Disallow: /umbraco_client:-umbraco', 'we use Shopify:-shopify', 'diskuse::::wysiwyg::::dotaz::::hodnoceni:-shoptet', 'Disallow: /broker::::Disallow: /broker/orders:-smartstore', 'gestion_e_commerce:-solusquare', 'spree/products/:-spree', '/admin::::/_admin::::offset=0::::_print_version:-amiro', 'Disallow: /ajax::::Disallow: /apps:-weebly', 'Disallow: /_backup/::::Disallow: /_mygallery/::::Disallow: /_temp/::::Disallow: /_tempalbums/::::Disallow: /_tmpfileop/::::Disallow: /dbboon/:-godaddywb' ] for detection_key in robots_txt_detection_keys: if ':-' in detection_key: detection_array = detection_key.split(':-') if '||' in detection_array[0]: detection_strings = detection_array[0].split('||') for detection_string in detection_strings: if detection_string in robots_txt_content and detection_array[ 1] not in cmseek.ignore_cms: if cmseek.strict_cms == [] or detection_array[ 1] in cmseek.strict_cms: return ['1', detection_array[1]] elif '::::' in detection_array[0]: match_status = '0' # 0 = neutral, 1 = passed, 2 = failed match_strings = detection_array[0].split('::::') for match_string in match_strings: if match_status == '0' or match_status == '1': if match_string in robots_txt_content: match_status = '1' else: match_status = '2' else: match_status = '2' if match_status == '1' and detection_array[ 1] not in cmseek.ignore_cms: if cmseek.strict_cms == [] or detection_array[ 1] in cmseek.strict_cms: return ['1', detection_array[1]] else: if detection_array[ 0] in robots_txt_content and detection_array[ 1] not in cmseek.ignore_cms: if cmseek.strict_cms == [] or detection_array[ 1] in cmseek.strict_cms: return ['1', detection_array[1]] t3_regex = re.search(r'Sitemap: http(.*?)\?type=', robots_txt_content) if t3_regex != None and 'tp3' not in cmseek.ignore_cms: if cmseek.strict_cms == [] or 'tp3' in cmseek.strict_cms: return ['1', 'tp3'] return ['0', ''] else: cmseek.error('robots.txt not found or empty!') return ['0', '']
def start(): cmseek.clearscreen() cmseek.banner("Joomla Bruteforce Module") url = cmseek.targetinp("") # input('Enter Url: ') cmseek.info("Checking for Joomla") bsrc = cmseek.getsource(url, cmseek.randomua('foodislove')) joomcnf = '0' if bsrc[0] != '1': cmseek.error("Could not get target source, CMSeek is quitting") cmseek.handle_quit() else: ## Parse generator meta tag parse_generator = generator.parse(bsrc[1]) ga = parse_generator[0] ga_content = parse_generator[1] try1 = generator.scan(ga_content) if try1[0] == '1' and try1[1] == 'joom': joomcnf = '1' else: try2 = source.check(bsrc[1], url) if try2[0] == '1' and try2[1] == 'joom': joomcnf = '1' else: try3 = header.check(bsrc[2]) # Headers Check! if try3[0] == '1' and try3[1] == 'joom': joomcnf = '1' else: joomcnf = '0' if joomcnf != '1': cmseek.error('Could not confirm Joomla... CMSeek is quitting') cmseek.handle_quit() else: cmseek.success( "Joomla Confirmed... Confirming form and getting token...") joomloginsrc = cmseek.getsource(url + '/administrator/index.php', cmseek.randomua('thatsprettygay')) if joomloginsrc[0] == '1' and '<form' in joomloginsrc[1]: # joomtoken = re.findall(r'type=\"hidden\" name=\"(.*?)\" value=\"1\"', joomloginsrc[1]) # if len(joomtoken) == 0: # cmseek.error('Unable to get token... CMSeek is quitting!') # cmseek.handle_quit() # cmseek.success("Token grabbed successfully: " + cmseek.bold + joomtoken[0] + cmseek.cln) # token = joomtoken[0] joomparamuser = [] rawuser = input( "[~] Enter Usernames with coma as separation without any space (example: cris,harry): " ).split(',') for rusr in rawuser: joomparamuser.append(rusr) joombruteusers = set( joomparamuser ) ## Strip duplicate usernames in case any smartass didn't read the full thing and entered admin as well for user in joombruteusers: passfound = '0' print('\n') cmseek.info("Bruteforcing User: "******"wordlist/passwords.txt", "r") passwords = pwd_file.read().split('\n') passwords.insert(0, user) for password in passwords: if password != '' and password != '\n': sys.stdout.write('[*] Testing Password: '******'%s\r\r' % password) sys.stdout.flush() # print("Testing Pass: "******"Ret URL: " + str(cursrc[3])) if 'logout' in str(cursrc[1]): print('\n') cmseek.success('Password found!') print(" |\n |--[username]--> " + cmseek.bold + user + cmseek.cln + "\n |\n |--[password]--> " + cmseek.bold + password + cmseek.cln + "\n |") cmseek.success('Enjoy The Hunt!') cmseek.savebrute(url, url + '/administrator/index.php', user, password) passfound = '1' break else: continue break if passfound == '0': cmseek.error('\n\nCould Not find Password!') print('\n\n') else: cmseek.error("Couldn't find login form... CMSeeK is quitting") cmseek.handle_quit()
def check(url, ua): robots = url + '/robots.txt' robots_source = cmseek.getsource(robots, ua) # print(robots_source[1]) if robots_source[0] == '1' and robots_source[1] != '': # Check begins here robotstr = robots_source[1] hstring = robotstr # too lazy to rename variables from the copied part below '-' #### START DETECTION FROM HERE ## || <- if either of it matches cms detected ## :::: <- all the strings has to match (implemented to decrease false positives) hkeys = [ 'If the Joomla site is installed::::Disallow: /administrator/:-joom', 'Allow: /core/*.css$||Disallow: /index.php/user/login/||Disallow: /web.config:-dru', 'Disallow: /wp-admin/||Allow: /wp-admin/admin-ajax.php:-wp', 'Disallow: /kernel/::::Disallow: /language/::::Disallow: /templates_c/:-xoops', 'Disallow: /textpattern:-tpc', 'Disallow: /sitecore||Disallow: /sitecore_files||Disallow: /sitecore modules:-score', 'Disallow: /phpcms||robots.txt for PHPCMS:-phpc', 'Disallow: /*mt-content*||Disallow: /mt-includes/:-moto', 'Disallow: /jcmsplugin/:-jcms', 'Disallow: /ip_cms/||ip_backend_frames.php||ip_backend_worker.php:-impage', 'Disallow: /flex/tmp/||flex/Logs/:-flex', 'Disallow: /e107_admin/||e107_handlers||e107_files/cache:-e107', 'Disallow: /plus/ad_js.php||Disallow: /plus/erraddsave.php||Disallow: /plus/posttocar.php||Disallow: /plus/disdls.php||Disallow: /plus/mytag_js.php||Disallow: /plus/stow.php:-dede', 'modules/contentbox/themes/:-cbox', 'Disallow: /contao/:-contao', 'Disallow: /concrete:-con5', 'Disallow: /auth/cas::::Disallow: /auth/cas/callback:-dscrs', 'uc_client::::uc_server::::forum.php?mod=redirect*:-discuz', 'Disallow: /AfterbuySrcProxy.aspx||Disallow: /afterbuy.asmx||Disallow: /afterbuySrc.asmx:-abuy', 'Disallow: /craft/:-craft', # Chances of it being a falsepositive are higher than the chances of me doing something good with my life ;__; 'Disallow: /app/::::Disallow: /store_closed.html:-csc', 'Disallow: /*?cartcmd=*:-dweb', 'Disallow: /epages/Site.admin/||Disallow: /epages/*:-epgs', 'Disallow: /Mediatheque/:-ezpub', 'robots.txt automaticaly generated by PrestaShop:-presta' ] for keyl in hkeys: if ':-' in keyl: det = keyl.split(':-') if '||' in det[0]: idkwhat = det[0] dets = idkwhat.split('||') for d in dets: if d in hstring: return ['1', det[1]] elif '::::' in det[0]: # yet again i know there can be a better way of doing it and feel free to correct it :) and_chk = '0' # 0 = neutral, 1 = passed, 2 = failed chks = det[0].split('::::') for chk in chks: if and_chk == '0' or and_chk == '1': if chk in hstring: and_chk = '1' else: and_chk = '2' else: and_chk = '2' if and_chk == '1': return ['1', det[1]] else: if det[0] in hstring: return ['1', det[1]] t3_regex = re.search(r'Sitemap: http(.*?)\?type=', robotstr) if t3_regex != None: return ['1', 'tp3'] return ['0', ''] else: cmseek.error('robots.txt not found or empty!') return ['0', '']
def start(id, url, ua, ga, source): version = '0' cmseek.info('detecting joomla version') # version detection stats here if ga == '1': # Detect version via generator meta tag cmseek.statement('Detecting version using generator meta tag [Method 1 of 4]') regex_1 = re.findall(r'content=(?:\"|\')Joomla! (.*?) - Open Source Content Management(?:\"|\')', source) if regex_1 != []: cmseek.success('Joomla version detected, version: ' + cmseek.bold + regex_1[0] + cmseek.cln) return regex_1[0] if version == '0': # Detections using the xml files xml_files = ['administrator/manifests/files/joomla.xml','language/en-GB/en-GB.xml','administrator/components/com_content/content.xml','administrator/components/com_plugins/plugins.xml','administrator/components/com_media/media.xml','mambots/content/moscode.xml'] cmseek.statement('Detecting version using xml files [Method 2 of 4]') for xml_file in xml_files: xml_source = cmseek.getsource(url + '/' + xml_file, ua) if xml_source[0] == '1': regex_2 = re.findall(r'<version>(.*?)</version>', xml_source[1]) if regex_2 != []: cmseek.success('Joomla version detected, version: ' + cmseek.bold + regex_2[0] + cmseek.cln) return regex_2[0] # Detection method 3 if version == '0': other_files = ['language/en-GB/en-GB.xml','templates/system/css/system.css','media/system/js/mootools-more.js','language/en-GB/en-GB.ini','htaccess.txt','language/en-GB/en-GB.com_media.ini'] cmseek.statement('Detecting version using advanced fingerprinting [Method 3 of 4]') for file in other_files: file_source = cmseek.getsource(url + '/' + file, ua) if file_source[0] == '1': # Regex find regex_3 = re.findall(r'<meta name="Keywords" content="(.*?)">', file_source[1]) if regex_3 != []: cmseek.success('Joomla version detected, version: ' + cmseek.bold + regex_3[0] + cmseek.cln) return regex_3[0] # Joomla version 1.6 j16 = ['system.css 20196 2011-01-09 02:40:25Z ian','MooTools.More={version:"1.3.0.1"','en-GB.ini 20196 2011-01-09 02:40:25Z ian','en-GB.ini 20990 2011-03-18 16:42:30Z infograf768','20196 2011-01-09 02:40:25Z ian'] for j in j16: rsearch = re.search(j,file_source[1]) if rsearch is not None: cmseek.success('Joomla version detected, version: ' + cmseek.bold + '1.6' + cmseek.cln) return '1.6' # Joomla version 1.5 j15 = ['Joomla! 1.5','MooTools={version:\'1.12\'}','11391 2009-01-04 13:35:50Z ian'] for j in j15: rsearch = re.search(j,file_source[1]) if rsearch is not None: cmseek.success('Joomla version detected, version: ' + cmseek.bold + '1.5' + cmseek.cln) return '1.5' # Joomla version 1.7 j17 = ['system.css 21322 2011-05-11 01:10:29Z dextercowley','MooTools.More={version:"1.3.2.1"','22183 2011-09-30 09:04:32Z infograf768','21660 2011-06-23 13:25:32Z infograf768'] for j in j17: rsearch = re.search(j,file_source[1]) if rsearch is not None: cmseek.success('Joomla version detected, version: ' + cmseek.bold + '1.7' + cmseek.cln) return '1.7' # Joomla version 1.0 j10 = ['(Copyright (C) 2005 - 200(6|7))','47 2005-09-15 02:55:27Z rhuk','423 2005-10-09 18:23:50Z stingrey','1005 2005-11-13 17:33:59Z stingrey','1570 2005-12-29 05:53:33Z eddieajau','2368 2006-02-14 17:40:02Z stingrey','1570 2005-12-29 05:53:33Z eddieajau','4085 2006-06-21 16:03:54Z stingrey','4756 2006-08-25 16:07:11Z stingrey','5973 2006-12-11 01:26:33Z robs','5975 2006-12-11 01:26:33Z robs'] for j in j10: rsearch = re.search(j,file_source[1]) if rsearch is not None: cmseek.success('Joomla version detected, version: ' + cmseek.bold + '1.0' + cmseek.cln) return '1.0' # Joomla version 2.5 j25 = ['Copyright (C) 2005 - 2012 Open Source Matters','MooTools.More={version:"1.4.0.1"'] for j in j25: rsearch = re.search(j,file_source[1]) if rsearch is not None: cmseek.success('Joomla version detected, version: ' + cmseek.bold + '2.5' + cmseek.cln) return '2.5' # Detection using README file if version == '0': cmseek.statement('Detecting version from README file [Method 4 of 4]') readme_file = url + '/README.txt' readme_source = cmseek.getsource(readme_file, ua) if readme_source[0] == '1': regex_4 = re.findall(r'package to version (.*?)', readme_source[1]) if regex_4 != []: cmseek.success('Joomla version detected, version: ' + cmseek.bold + regex_4[0] + cmseek.cln) return regex_4[0] # if we fail ĀÆ\_(ć)_/ĀÆ return version
def start(id, url, ua, ga, source): # init variables vuln_detection = '0' vuln_count = 0 joom_vulns = [] # Version Detection version = version_detect.start(id, url, ua, ga, source) # Detecting joomla core vulnerabilities jcv = core_vuln.start(version) vuln_detection = jcv[0] vuln_count = jcv[1] joom_vulns = jcv[2] # README.txt readmesrc = cmseek.getsource(url + '/README.txt', ua) if readmesrc[ 0] != '1': ## something went wrong while getting the source codes cmseek.statement( "Couldn't get readme file's source code most likely it's not present" ) readmefile = '0' elif 'This is a Joomla!' in readmesrc[1]: cmseek.info('README.txt file found') readmefile = '1' # Readme file present else: readmefile = '2' # Readme file found but most likely it's not of joomla # Debug Mode cmseek.info('Checking debug mode status') debug_mode = check_debug.start(source) # Check user registration status cmseek.statement('Checking if user registration is enabled') registration = user_registration.start(url, ua) # Find admin url cmseek.info('Locating admin url') admin = admin_finder.start(url, ua) # Backups check cmseek.info('Checking for common Backups') backups = backup_finder.start(url, ua) # Check Potential configuration file leak cmseek.info('Looking for potential config leak') configs = config_check.start(url, ua) # Checking for directory listing cmseek.statement('Checking for directory listing') directories = dir_list.start(url, ua) ### THE RESULTS START FROM HERE cmseek.clearscreen() cmseek.banner("Deep Scan Results") cmseek.result('Target: ', url) cmseek.result("Detected CMS: ", 'Joomla') cmseek.update_log('cms_name', 'joomla') # update log cmseek.result("CMS URL: ", "https://joomla.org") cmseek.update_log('cms_url', "https://joomla.org") # update log if version != '0': cmseek.result("Joomla Version: ", version) cmseek.update_log('joomla_version', version) if registration[0] == '1': cmseek.result('User registration enabled: ', registration[1]) cmseek.update_log('user_registration_url', registration[1]) if debug_mode == '1': cmseek.result('Debug mode enabled', '') cmseek.update_log('joomla_debug_mode', 'enabled') else: cmseek.update_log('joomla_debug_mode', 'disabled') if readmefile == '1': cmseek.result('Readme file: ', url + '/README.txt') cmseek.update_log('joomla_readme_file', url + '/README.txt') if admin[0] > 0: cmseek.result('Admin URL: ', url + admin[1][0]) admin_log = '' for adm in admin[1]: admin_log += url + '/' + adm + ',' # print(cmseek.bold + cmseek.fgreen + " [B] " + cmseek.cln + url + '/' + adm) cmseek.update_log('joomla_backup_files', admin_log) print('\n') if directories[0] > 0: cmseek.result('Open directories: ', str(directories[0])) cmseek.success('Open directory url: ') dirs = '' for dir in directories[1]: dirs += url + '/' + dir + ',' print(cmseek.bold + cmseek.fgreen + " [>] " + cmseek.cln + url + dir) cmseek.update_log('directory_listing', dirs) print('\n') if backups[0] > 0: cmseek.result('Found potential backup file: ', str(backups[0])) cmseek.success('Backup URLs: ') bkup_log = '' for backup in backups[1]: bkup_log += url + '/' + backup + ',' print(cmseek.bold + cmseek.fgreen + " [B] " + cmseek.cln + url + '/' + backup) cmseek.update_log('joomla_backup_files', bkup_log) print('\n') if configs[0] > 0: cmseek.result('Found potential Config file: ', str(configs[0])) cmseek.success('Config URLs: ') conf_log = '' for config in configs[1]: conf_log += url + '/' + config + ',' print(cmseek.bold + cmseek.fgreen + " [c] " + cmseek.cln + url + '/' + config) cmseek.update_log('joomla_config_files', conf_log) print('\n') if vuln_detection == '1' and vuln_count > 0: cmseek.result('Total joomla core vulnerabilities: ', str(vuln_count)) cmseek.info('Vulnerabilities found: \n') for vuln in joom_vulns: vuln = vuln.replace('\\n', cmseek.cln + '\n ') print(cmseek.bold + cmseek.red + '[v] ' + vuln) print('\n') elif vuln_detection == '2': cmseek.warning( 'Couldn\'t find core vulnerabilities, No VERSION detected') elif vuln_detection == '3': cmseek.error('Core vulnerability database not found!') else: cmseek.warning('No core vulnerabilities detected!')
def main_proc(site, cua): cmseek.clearscreen() cmseek.banner("CMS Detection And Deep Scan") cmseek.info("Scanning Site: " + site) cmseek.statement("User Agent: " + cua) cmseek.statement("Collecting Headers and Page Source for Analysis") init_source = cmseek.getsource(site, cua) if init_source[0] != '1': cmseek.error( "Aborting CMSeek! Couldn't connect to site \n Error: %s" % init_source[1]) return else: scode = init_source[1] headers = init_source[2] if site != init_source[3] and site + '/' != init_source[3]: cmseek.info('Target redirected to: ' + cmseek.bold + cmseek.fgreen + init_source[3] + cmseek.cln) follow_redir = input('[#] Set ' + cmseek.bold + cmseek.fgreen + init_source[3] + cmseek.cln + ' as target? (y/n): ') if follow_redir.lower() == 'y': site = init_source[3] if scode == '': # silly little check thought it'd come handy cmseek.error('Aborting detection, source code empty') return cmseek.statement("Detection Started") ## init variables cms = '' # the cms id if detected cms_detected = '0' # self explanotory detection_method = '' # ^ ga = '0' # is generator available if 'generator' in scode or 'Generator' in scode: ga = '1' cmseek.statement("Using headers to detect CMS (Stage 1 of 3)") header_detection = header.check(headers) if header_detection[0] == '1': detection_method = 'header' cms = header_detection[1] cms_detected = '1' if cms_detected == '0' and ga == '1': # cms detection via generator cmseek.statement( "Using Generator meta tag to detect CMS (Stage 2 of 3)") gen_detection = source.generator(scode) if gen_detection[0] == '1': detection_method = 'generator' cms = gen_detection[1] cms_detected = '1' else: # Check cms using source code cmseek.statement("Using source code to detect CMS (Stage 3 of 3)") source_check = source.check(scode, site) if source_check[0] == '1': detection_method = 'source' cms = source_check[1] cms_detected = '1' if cms_detected == '1': cmseek.success('CMS Detected, CMS ID: ' + cmseek.bold + cms + cmseek.cln + ', Detection method: ' + cmseek.bold + detection_method + cmseek.cln) cmseek.update_log('detection_param', detection_method) cmseek.update_log('cms_id', cms) # update log cmseek.statement('Getting CMS info from databse') cms_info = getattr(cmsdb, cms) if cms_info['deeps'] == '1': # cmseek.success('Starting ' + cmseek.bold + cms_info['name'] + ' deep scan' + cmseek.cln) advanced.start(cms, site, cua, ga, scode) return elif cms_info['vd'] == '1': cmseek.success('Version detection available') cms_version = version_detect.start(cms, site, cua, ga, scode) cmseek.clearscreen() cmseek.banner("CMS Scan Results") cmseek.result('Target: ', site) cmseek.result("Detected CMS: ", cms_info['name']) cmseek.update_log('cms_name', cms_info['name']) # update log if cms_version != '0': cmseek.result("CMS Version: ", cms_version) cmseek.update_log('cms_version', cms_version) # update log cmseek.result("CMS URL: ", cms_info['url']) cmseek.update_log('cms_url', cms_info['url']) # update log return else: # nor version detect neither DeepScan available cmseek.clearscreen() cmseek.banner("CMS Scan Results") cmseek.result('Target: ', site) cmseek.result("Detected CMS: ", cms_info['name']) cmseek.update_log('cms_name', cms_info['name']) # update log cmseek.result("CMS URL: ", cms_info['url']) cmseek.update_log('cms_url', cms_info['url']) # update log return else: print('\n') cmseek.error( 'CMS Detection failed, if you know the cms please help me improve CMSeeK by reporting the cms along with the target by creating an issue' ) print(''' {2}Create issue:{3} https://github.com/Tuhinshubhra/CMSeeK/issues/new {4}Title:{5} [SUGGESTION] CMS detction failed! {6}Content:{7} - CMSeeK Version: {0} - Target: {1} - Probable CMS: <name and/or cms url> N.B: Create issue only if you are sure, please avoid spamming! '''.format(cmseek.cmseek_version, site, cmseek.bold, cmseek.cln, cmseek.bold, cmseek.cln, cmseek.bold, cmseek.cln)) return return
def main_proc(site, cua): cmseek.clearscreen() cmseek.banner("CMS Detection And Deep Scan") cmseek.info("Scanning Site: " + site) cmseek.statement("User Agent: " + cua) cmseek.statement("Collecting Headers and Page Source for Analysis") init_source = cmseek.getsource(site, cua) if init_source[0] != '1': cmseek.error( "Aborting CMSeek! Couldn't connect to site \n Error: %s" % init_source[1]) return else: scode = init_source[1] headers = init_source[2] if site != init_source[3] and site + '/' != init_source[3]: cmseek.info('Target redirected to: ' + cmseek.bold + cmseek.fgreen + init_source[3] + cmseek.cln) follow_redir = input('[#] Set ' + cmseek.bold + cmseek.fgreen + init_source[3] + cmseek.cln + ' as target? (y/n): ') if follow_redir.lower() == 'y': site = init_source[3] cmseek.statement( "Reinitiating Headers and Page Source for Analysis") tmp_req = cmseek.getsource(site, cua) scode = tmp_req[1] headers = tmp_req[2] if scode == '': # silly little check thought it'd come handy cmseek.error('Aborting detection, source code empty') return cmseek.statement("Detection Started") ## init variables cms = '' # the cms id if detected cms_detected = '0' # self explanotory detection_method = '' # ^ ga = '0' # is generator available ga_content = '' # Generator content ## Parse generator meta tag parse_generator = generator.parse(scode) ga = parse_generator[0] ga_content = parse_generator[1] cmseek.statement("Using headers to detect CMS (Stage 1 of 4)") header_detection = header.check(headers) if header_detection[0] == '1': detection_method = 'header' cms = header_detection[1] cms_detected = '1' if cms_detected == '0' and ga == '1': # cms detection via generator cmseek.statement( "Using Generator meta tag to detect CMS (Stage 2 of 4)") gen_detection = generator.scan(ga_content) if gen_detection[0] == '1': detection_method = 'generator' cms = gen_detection[1] cms_detected = '1' else: cmseek.statement('Skipping stage 2 of 4: No Generator meta tag found') if cms_detected == '0': # Check cms using source code cmseek.statement("Using source code to detect CMS (Stage 3 of 4)") source_check = source.check(scode, site) if source_check[0] == '1': detection_method = 'source' cms = source_check[1] cms_detected = '1' if cms_detected == '0': # Check cms using robots.txt cmseek.statement("Using robots.txt to detect CMS (Stage 4 of 4)") robots_check = robots.check(site, cua) if robots_check[0] == '1': detection_method = 'robots' cms = robots_check[1] cms_detected = '1' if cms_detected == '1': cmseek.success('CMS Detected, CMS ID: ' + cmseek.bold + cmseek.fgreen + cms + cmseek.cln + ', Detection method: ' + cmseek.bold + cmseek.lblue + detection_method + cmseek.cln) cmseek.update_log('detection_param', detection_method) cmseek.update_log('cms_id', cms) # update log cmseek.statement('Getting CMS info from database') # freaking typo cms_info = getattr(cmsdb, cms) if cms_info['deeps'] == '1': # cmseek.success('Starting ' + cmseek.bold + cms_info['name'] + ' deep scan' + cmseek.cln) advanced.start(cms, site, cua, ga, scode, ga_content) return elif cms_info['vd'] == '1': cmseek.success('Starting version detection') cms_version = '0' # Failsafe measure cms_version = version_detect.start(cms, site, cua, ga, scode, ga_content) cmseek.clearscreen() cmseek.banner("CMS Scan Results") result.target(site) result.cms(cms_info['name'], cms_version, cms_info['url']) cmseek.update_log('cms_name', cms_info['name']) # update log if cms_version != '0' and cms_version != None: cmseek.update_log('cms_version', cms_version) # update log cmseek.update_log('cms_url', cms_info['url']) # update log comptime = round(time.time() - cmseek.cstart, 2) log_dir = cmseek.log_dir if log_dir is not "": log_file = log_dir + "/cms.json" result.end(str(cmseek.total_requests), str(comptime), log_file) ''' cmseek.result('Target: ', site) cmseek.result("Detected CMS: ", cms_info['name']) cmseek.update_log('cms_name', cms_info['name']) # update log if cms_version != '0' and cms_version != None: cmseek.result("CMS Version: ", cms_version) cmseek.update_log('cms_version', cms_version) # update log cmseek.result("CMS URL: ", cms_info['url']) cmseek.update_log('cms_url', cms_info['url']) # update log ''' return else: # nor version detect neither DeepScan available cmseek.clearscreen() cmseek.banner("CMS Scan Results") result.target(site) result.cms(cms_info['name'], '0', cms_info['url']) comptime = round(time.time() - cmseek.cstart, 2) log_dir = cmseek.log_dir if log_dir is not "": log_file = log_dir + "/cms.json" result.end(str(cmseek.total_requests), str(comptime), log_file) ''' cmseek.result('Target: ', site) cmseek.result("Detected CMS: ", cms_info['name']) cmseek.update_log('cms_name', cms_info['name']) # update log cmseek.result("CMS URL: ", cms_info['url']) cmseek.update_log('cms_url', cms_info['url']) # update log ''' return else: print('\n') cmseek.error( 'CMS Detection failed, if you know the cms please help me improve CMSeeK by reporting the cms along with the target by creating an issue' ) print(''' {2}Create issue:{3} https://github.com/Tuhinshubhra/CMSeeK/issues/new {4}Title:{5} [SUGGESTION] CMS detction failed! {6}Content:{7} - CMSeeK Version: {0} - Target: {1} - Probable CMS: <name and/or cms url> N.B: Create issue only if you are sure, please avoid spamming! '''.format(cmseek.cmseek_version, site, cmseek.bold, cmseek.cln, cmseek.bold, cmseek.cln, cmseek.bold, cmseek.cln)) return return
def start(id, url, ua, ga, source, detection_method): ''' id = ID of the cms url = URL of target ua = User Agent ga = [0/1] is GENERATOR meta tag available source = source code ''' ## Do shits later [update from later: i forgot what shit i had to do ;___;] if id == "wp": # referenced before assignment fix vulnss = version = wpvdbres = result = plugins_found = usernames = usernamesgen = '0' cmseek.statement('Starting WordPress DeepScan') # Check if site really is WordPress if detection_method == 'source': # well most of the wordpress false positives are from source detections. cmseek.statement('Checking if the detection is false positive') temp_domain = re.findall( '^(?:https?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:\/\n\?\=]+)', url)[0] wp_match_pattern = temp_domain + '\/wp-(content|include|admin)\/' if not re.search(wp_match_pattern, source): cmseek.error( 'Detection was false positive! CMSeeK is quitting!') cmseek.success( 'Run CMSeeK with {0}{1}{2} argument next time'.format( cmseek.fgreen, '--ignore-cms wp', cmseek.cln)) #cmseek.handle_quit() return # Version detection version = wordpress_version_detect.start(id, url, ua, ga, source) ## Check for minor stuffs like licesnse readme and some open directory checks cmseek.statement("Initiating open directory and files check") ## Readme.html readmesrc = cmseek.getsource(url + '/readme.html', ua) if readmesrc[ 0] != '1': ## something went wrong while getting the source codes cmseek.statement( "Couldn't get readme file's source code most likely it's not present" ) readmefile = '0' # Error Getting Readme file elif 'Welcome. WordPress is a very special project to me.' in readmesrc[ 1]: readmefile = '1' # Readme file present else: readmefile = '2' # Readme file found but most likely it's not of wordpress ## license.txt licsrc = cmseek.getsource(url + '/license.txt', ua) if licsrc[0] != '1': cmseek.statement('license file not found') licfile = '0' elif 'WordPress - Web publishing software' in licsrc[1]: licfile = '1' else: licfile = '2' ## wp-content/uploads/ folder wpupsrc = cmseek.getsource(url + '/wp-content/uploads/', ua) if wpupsrc[0] != '1': wpupdir = '0' elif 'Index of /wp-content/uploads' in wpupsrc[1]: wpupdir = '1' else: wpupdir = '2' ## xmlrpc xmlrpcsrc = cmseek.getsource(url + '/xmlrpc.php', ua) if xmlrpcsrc[0] != '1': cmseek.statement('XML-RPC interface not available') xmlrpc = '0' elif 'XML-RPC server accepts POST requests only.' in xmlrpcsrc[1]: xmlrpc = '1' else: xmlrpc = '2' ## Path disclosure cmseek.statement('Looking for potential path disclosure') path = path_disclosure.start(url, ua) if path != "": cmseek.success('Path disclosure detected, path: ' + cmseek.bold + path + cmseek.cln) ## Check for user registration usereg = check_reg.start(url, ua) reg_found = usereg[0] reg_url = usereg[1] ## Plugins Enumeration plug_enum = wp_plugins_enum.start(source) plugins_found = plug_enum[0] plugins = plug_enum[1] ## Themes Enumeration theme_enum = wp_theme_enum.start(source, url, ua) themes_found = theme_enum[0] themes = theme_enum[1] ## User enumeration uenum = wp_user_enum.start(id, url, ua, ga, source) usernamesgen = uenum[0] usernames = uenum[1] ## Version Vulnerability Detection if version != '0': version_vuln = wp_vuln_scan.start(version, ua) wpvdbres = version_vuln[0] result = version_vuln[1] if wpvdbres != '0' and version != '0': vulnss = len(result['vulnerabilities']) vfc = version_vuln[2] ### Deep Scan Results comes here comptime = round(time.time() - cmseek.cstart, 2) log_file = os.path.join(cmseek.log_dir, 'cms.json') cmseek.clearscreen() cmseek.banner("Deep Scan Results") sresult.target(url) sresult.cms('WordPress', version, 'https://wordpress.org') #cmseek.result("Detected CMS: ", 'WordPress') cmseek.update_log('cms_name', 'WordPress') # update log #cmseek.result("CMS URL: ", "https://wordpress.org") cmseek.update_log('cms_url', "https://wordpress.org") # update log sresult.menu('[WordPress Deepscan]') item_initiated = False item_ended = False if readmefile == '1': sresult.init_item("Readme file found: " + cmseek.fgreen + url + '/readme.html' + cmseek.cln) cmseek.update_log('wp_readme_file', url + '/readme.html') item_initiated = True if licfile == '1': cmseek.update_log('wp_license', url + '/license.txt') if item_initiated == False: sresult.init_item("License file: " + cmseek.fgreen + url + '/license.txt' + cmseek.cln) else: sresult.item("License file: " + cmseek.fgreen + url + '/license.txt' + cmseek.cln) if wpvdbres == '1': if item_initiated == False: sresult.init_item('Changelog: ' + cmseek.fgreen + str(result['changelog_url']) + cmseek.cln) else: sresult.item('Changelog: ' + cmseek.fgreen + str(result['changelog_url']) + cmseek.cln) cmseek.update_log('wp_changelog_file', str(result['changelog_url'])) if wpupdir == '1': cmseek.update_log('wp_uploads_directory', url + '/wp-content/uploads') if item_initiated == False: sresult.init_item("Uploads directory has listing enabled: " + cmseek.fgreen + url + '/wp-content/uploads' + cmseek.cln) else: sresult.item("Uploads directory has listing enabled: " + cmseek.fgreen + url + '/wp-content/uploads' + cmseek.cln) if xmlrpc == '1': cmseek.update_log('xmlrpc', url + '/xmlrpc.php') if item_initiated == False: sresult.init_item("XML-RPC interface: " + cmseek.fgreen + url + '/xmlrpc.php' + cmseek.cln) else: sresult.item("XML-RPC interface: " + cmseek.fgreen + url + '/xmlrpc.php' + cmseek.cln) if reg_found == '1': sresult.item('User registration enabled: ' + cmseek.bold + cmseek.fgreen + reg_url + cmseek.cln) cmseek.update_log('user_registration', reg_url) if path != "": sresult.item('Path disclosure: ' + cmseek.bold + cmseek.orange + path + cmseek.cln) cmseek.update_log('path', path) if plugins_found != 0: plugs_count = len(plugins) sresult.init_item("Plugins Enumerated: " + cmseek.bold + cmseek.fgreen + str(plugs_count) + cmseek.cln) wpplugs = "" for i, plugin in enumerate(plugins): plug = plugin.split(':') wpplugs = wpplugs + plug[0] + ' Version ' + plug[1] + ',' if i == 0 and i != plugs_count - 1: sresult.init_sub('Plugin: ' + cmseek.bold + cmseek.fgreen + plug[0] + cmseek.cln) sresult.init_subsub('Version: ' + cmseek.bold + cmseek.fgreen + plug[1] + cmseek.cln) sresult.end_subsub('URL: ' + cmseek.fgreen + url + '/wp-content/plugins/' + plug[0] + cmseek.cln) elif i == plugs_count - 1: sresult.empty_sub() sresult.end_sub('Plugin: ' + cmseek.bold + cmseek.fgreen + plug[0] + cmseek.cln) sresult.init_subsub( 'Version: ' + cmseek.bold + cmseek.fgreen + plug[1] + cmseek.cln, True, False) sresult.end_subsub( 'URL: ' + cmseek.fgreen + url + '/wp-content/plugins/' + plug[0] + cmseek.cln, True, False) else: sresult.empty_sub() sresult.sub_item('Plugin: ' + cmseek.bold + cmseek.fgreen + plug[0] + cmseek.cln) sresult.init_subsub('Version: ' + cmseek.bold + cmseek.fgreen + plug[1] + cmseek.cln) sresult.end_subsub('URL: ' + cmseek.fgreen + url + '/wp-content/plugins/' + plug[0] + cmseek.cln) cmseek.update_log('wp_plugins', wpplugs) sresult.empty_item() if themes_found != 0: thms_count = len(themes) sresult.init_item("Themes Enumerated: " + cmseek.bold + cmseek.fgreen + str(thms_count) + cmseek.cln) wpthms = "" for i, theme in enumerate(themes): thm = theme.split(':') thmz = thm[1].split('|') wpthms = wpthms + thm[0] + ' Version ' + thmz[0] + ',' if i == 0 and i != thms_count - 1: sresult.init_sub('Theme: ' + cmseek.bold + cmseek.fgreen + thm[0] + cmseek.cln) sresult.init_subsub('Version: ' + cmseek.bold + cmseek.fgreen + thmz[0] + cmseek.cln) if thmz[1] != '': sresult.subsub('Theme Zip: ' + cmseek.bold + cmseek.fgreen + url + thmz[1] + cmseek.cln) sresult.end_subsub('URL: ' + cmseek.fgreen + url + '/wp-content/themes/' + thm[0] + cmseek.cln) elif i == thms_count - 1: sresult.empty_sub(True) sresult.end_sub('Theme: ' + cmseek.bold + cmseek.fgreen + thm[0] + cmseek.cln) sresult.init_subsub( 'Version: ' + cmseek.bold + cmseek.fgreen + thmz[0] + cmseek.cln, True, False) if thmz[1] != '': sresult.subsub( 'Theme Zip: ' + cmseek.bold + cmseek.fgreen + url + thmz[1] + cmseek.cln, True, False) sresult.end_subsub( 'URL: ' + cmseek.fgreen + url + '/wp-content/themes/' + thm[0] + cmseek.cln, True, False) else: sresult.sub_item('Theme: ' + cmseek.bold + cmseek.fgreen + thm[0] + cmseek.cln) sresult.init_subsub('Version: ' + cmseek.bold + cmseek.fgreen + thmz[0] + cmseek.cln) if thmz[1] != '': sresult.subsub('Theme Zip: ' + cmseek.bold + cmseek.fgreen + url + thmz[1] + cmseek.cln) sresult.end_subsub('URL: ' + cmseek.fgreen + url + '/wp-content/themes/' + thm[0] + cmseek.cln) cmseek.update_log('wp_themes', wpthms) sresult.empty_item() if usernamesgen == '1': user_count = len(usernames) sresult.init_item("Usernames harvested: " + cmseek.bold + cmseek.fgreen + str(user_count) + cmseek.cln) wpunames = "" for i, u in enumerate(usernames): wpunames = wpunames + u + "," if i == 0 and i != user_count - 1: sresult.init_sub(cmseek.bold + cmseek.fgreen + u + cmseek.cln) elif i == user_count - 1: sresult.end_sub(cmseek.bold + cmseek.fgreen + u + cmseek.cln) else: sresult.sub_item(cmseek.bold + cmseek.fgreen + u + cmseek.cln) cmseek.update_log('wp_users', wpunames) sresult.empty_item() if version != '0': # cmseek.result("Version: ", version) cmseek.update_log('wp_version', version) if wpvdbres == '1': sresult.end_item('Version vulnerabilities: ' + cmseek.bold + cmseek.fgreen + str(vulnss) + cmseek.cln) cmseek.update_log('wp_vuln_count', str(vulnss)) if vulnss > 0: for i, vuln in enumerate(result['vulnerabilities']): if i == 0 and i != vulnss - 1: sresult.empty_sub(False) sresult.init_sub( cmseek.bold + cmseek.fgreen + str(vuln['title']) + cmseek.cln, False) sresult.init_subsub( "Type: " + cmseek.bold + cmseek.fgreen + str(vuln['vuln_type']) + cmseek.cln, False, True) sresult.subsub( "Link: " + cmseek.bold + cmseek.fgreen + "http://wpvulndb.com/vulnerabilities/" + str(vuln['id']) + cmseek.cln, False, True) strvuln = str(vuln) if 'cve' in strvuln: for ref in vuln['references']['cve']: sresult.subsub( "CVE: " + cmseek.fgreen + "http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-" + str(ref) + cmseek.cln, False, True) if 'exploitdb' in strvuln: for ref in vuln['references']['exploitdb']: sresult.subsub( "ExploitDB Link: " + cmseek.fgreen + "http://www.exploit-db.com/exploits/" + str(ref) + cmseek.cln, False, True) if 'metasploit' in strvuln: for ref in vuln['references']['metasploit']: sresult.subsub( "Metasploit Module: " + cmseek.fgreen + "http://www.metasploit.com/modules/" + str(ref) + cmseek.cln, False, True) if 'osvdb' in strvuln: for ref in vuln['references']['osvdb']: sresult.subsub( "OSVDB Link: " + cmseek.fgreen + "http://osvdb.org/" + str(ref) + cmseek.cln, False, True) if 'secunia' in strvuln: for ref in vuln['references']['secunia']: sresult.subsub( "Secunia Advisory: " + cmseek.fgreen + "http://secunia.com/advisories/" + str(ref) + cmseek.cln, False, True) if 'url' in strvuln: for ref in vuln['references']['url']: sresult.subsub( "Reference: " + cmseek.fgreen + str(ref) + cmseek.cln, False, True) sresult.end_subsub( "Fixed In Version: " + cmseek.bold + cmseek.fgreen + str(vuln['fixed_in']) + cmseek.cln, False, True) elif i == vulnss - 1: sresult.empty_sub(False) sresult.end_sub( cmseek.bold + cmseek.fgreen + str(vuln['title']) + cmseek.cln, False) sresult.init_subsub( "Type: " + cmseek.bold + cmseek.fgreen + str(vuln['vuln_type']) + cmseek.cln, False, False) sresult.subsub( "Link: " + cmseek.bold + cmseek.fgreen + "http://wpvulndb.com/vulnerabilities/" + str(vuln['id']) + cmseek.cln, False, False) strvuln = str(vuln) if 'cve' in strvuln: for ref in vuln['references']['cve']: sresult.subsub( "CVE: " + cmseek.fgreen + "http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-" + str(ref) + cmseek.cln, False, False) if 'exploitdb' in strvuln: for ref in vuln['references']['exploitdb']: sresult.subsub( "ExploitDB Link: " + cmseek.fgreen + "http://www.exploit-db.com/exploits/" + str(ref) + cmseek.cln, False, False) if 'metasploit' in strvuln: for ref in vuln['references']['metasploit']: sresult.subsub( "Metasploit Module: " + cmseek.fgreen + "http://www.metasploit.com/modules/" + str(ref) + cmseek.cln, False, False) if 'osvdb' in strvuln: for ref in vuln['references']['osvdb']: sresult.subsub( "OSVDB Link: " + cmseek.fgreen + "http://osvdb.org/" + str(ref) + cmseek.cln, False, False) if 'secunia' in strvuln: for ref in vuln['references']['secunia']: sresult.subsub( "Secunia Advisory: " + cmseek.fgreen + "http://secunia.com/advisories/" + str(ref) + cmseek.cln, False, False) if 'url' in strvuln: for ref in vuln['references']['url']: sresult.subsub( "Reference: " + cmseek.fgreen + str(ref) + cmseek.cln, False, False) sresult.end_subsub( "Fixed In Version: " + cmseek.bold + cmseek.fgreen + str(vuln['fixed_in']) + cmseek.cln, False, False) else: sresult.empty_sub(False) sresult.sub_item( cmseek.bold + cmseek.fgreen + str(vuln['title']) + cmseek.cln, False) sresult.init_subsub( "Type: " + cmseek.bold + cmseek.fgreen + str(vuln['vuln_type']) + cmseek.cln, False, True) sresult.subsub( "Link: " + cmseek.bold + cmseek.fgreen + "http://wpvulndb.com/vulnerabilities/" + str(vuln['id']) + cmseek.cln, False, True) strvuln = str(vuln) if 'cve' in strvuln: for ref in vuln['references']['cve']: sresult.subsub( "CVE: " + cmseek.fgreen + "http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-" + str(ref) + cmseek.cln, False, True) if 'exploitdb' in strvuln: for ref in vuln['references']['exploitdb']: sresult.subsub( "ExploitDB Link: " + cmseek.fgreen + "http://www.exploit-db.com/exploits/" + str(ref) + cmseek.cln, False, True) if 'metasploit' in strvuln: for ref in vuln['references']['metasploit']: sresult.subsub( "Metasploit Module: " + cmseek.fgreen + "http://www.metasploit.com/modules/" + str(ref) + cmseek.cln, False, True) if 'osvdb' in strvuln: for ref in vuln['references']['osvdb']: sresult.subsub( "OSVDB Link: " + cmseek.fgreen + "http://osvdb.org/" + str(ref) + cmseek.cln, False, True) if 'secunia' in strvuln: for ref in vuln['references']['secunia']: sresult.subsub( "Secunia Advisory: " + cmseek.fgreen + "http://secunia.com/advisories/" + str(ref) + cmseek.cln, False, True) if 'url' in strvuln: for ref in vuln['references']['url']: sresult.subsub( "Reference: " + cmseek.fgreen + str(ref) + cmseek.cln, False, True) sresult.end_subsub( "Fixed In Version: " + cmseek.bold + cmseek.fgreen + str(vuln['fixed_in']) + cmseek.cln, False, True) sresult.end(str(cmseek.total_requests), str(comptime), log_file) return return