def __init__(self, SESSION): self.scanned_targets = [] self.data = [] self.error_data = [] self.msTeamsActivated = False self.outputActivated = False self.helper = Helper() self.session = SESSION
def __init__(self, outputFolderName, scope, SESSION): self.data = [] self.error_data = [] self.textList = [] self.scope = scope self.bucketFinder = BucketFinder(SESSION) self.tokenFinder = TokenFinder(SESSION) self.headerFinder = HeaderFinder(outputFolderName, SESSION) self.openRedirect = OpenRedirect(SESSION) self.cssChecker = CssChecker(SESSION) self.endpointFinder = EndpointFinder(SESSION) self.firebaseFinder = FirebaseFinder(SESSION) self.helper = Helper() self.session = SESSION
def __init__(self, SESSION): self.scanned_targets = [] self.data = [] self.error_data = [] self.msTeamsActivated = False self.outputActivated = False self.helper = Helper() self.session = SESSION self.regions = [ 'us-east-2', 'us-east-1', 'us-west-1', 'us-west-2', 'ap-east-1', 'ap-south-1', 'ap-northeast-3', 'ap-northeast-2', 'ap-southeast-1', 'ap-southeast-2', 'ap-northeast-1', 'ca-central-1', 'cn-north-1', 'cn-northwest-1', 'eu-central-1', 'eu-west-1', 'eu-west-2', 'eu-west-3', 'eu-north-1', 'me-south-1', 'sa-east-1', 'us-gov-east-1', 'us-gov-west-1' ]
def __init__(self, SESSION): self.scanned_targets = [] self.openRedirect = OpenRedirect(SESSION) self.helper = Helper() self.data = [] self.error_data = [] self.outputActivated = False self.msTeamsActivated = False self.invalid_codes = [301,302,303,400,403,404,503] self.session = SESSION with open('extra/endpointFinder_endpoints.txt') as fp: lines = fp.read() self.endpoints = lines.split('\n')
def __init__(self, SESSION): self.scanned_targets = [] self.helper = Helper() self.data = [] self.error_data = [] self.outputActivated = False self.msTeamsActivated = False self.session = SESSION with open('extra/openRedirect_parameters.txt') as fp: lines = fp.read() self.parameters = lines.split('\n') with open('extra/openRedirect_payloads.txt') as fp: lines = fp.read() self.payloads = lines.split('\n')
class TokenFinder(): def __init__(self, SESSION): self.scanned_targets = [] self.data = [] self.error_data = [] self.outputActivated = False self.helper = Helper() self.session = SESSION def activateOutput(self): self.outputActivated = True def showStartScreen(self): print( '---------------------------------------------------------------------------------------' ) print( '---------------------------++++++++++++++------++++++++++++++----------./*/.-----------' ) print( '--------------------./*/.--++++++++++++++------++++++++++++++--------------------------' ) print( '--------------------------------++++-----------+++--------------./*/.------------------' ) print( '---./*/.------------------------++++-----------+++-------------------------------------' ) print( '--------------------------------++++-----------+++++++++++-----------------------------' ) print( '------------./*/.---------------++++-----------+++++++++++--------------./*/.----------' ) print( '--------------------------------++++-----------+++-------------------------------------' ) print( '--------------------------------++++-----------+++-------------------------------------' ) print( '--------------------------------++++-----------+++-----------------------------./*/.---' ) print( '------------./*/.---------------++++-----------+++---------------./*/.-----------------' ) print( '---------------------------------------------------------------------------------------' ) print( ' ' ) print( '----------------------------------- Handerllon ©_© ------------------------------------' ) print( ' ' ) print( '-------------------------------- Starting token finder --------------------------------' ) print('Searching sensitive info on input...') def showEndScreen(self): print( '---------------------------------------------------------------------------------------' ) print('Finished! Please check output for results!') def output(self): data_df = pd.DataFrame( self.data, columns=['Vulnerability', 'MainUrl', 'Reference', 'Description']) error_df = pd.DataFrame( self.error_data, columns=['Module', 'MainUrl', 'Reference', 'Reason']) return (data_df, error_df) def filterInvalids(self, some_list): res = [] #------ Filter invalid matches for item in some_list: if all(char not in item for char in ['\\', '=', '>', '<', '[', ']', '{', '}', ';', '(', ')']): res.append(item) return res return http_endpoints #Searches certain keywords on site def tokenProcess(self, session, host, url): output = [] verboseOutput = [] if url in self.scanned_targets: return output, verboseOutput self.scanned_targets.append(url) try: response = session.get(url, verify=False) except: return output, verboseOutput if response.status_code == 404: print('Url: ' + url + ' returned 404') self.error_data.append(['token', host, url, 'Returned 404']) return output, verboseOutput #Generic tokens licence_key = re.findall('license_key:"(.+?)"', response.text) if len(licence_key) > 0: for value in licence_key: self.data.append([ 'Information disclosure', host, url, 'The following licence_key was found: ' + value ]) output.append('Token finder found license_key: ' + value + ' at ' + url) verboseOutput.append('Token finder found license_key: ' + value + ' at ' + url) else: verboseOutput.append('No licence_key match found on the page') api_key = re.findall('api_key:"(.+?)"', response.text) if len(api_key) > 0: for value in api_key: self.data.append([ 'Information disclosure', host, url, 'The following key was found: ' + value ]) output.append('Token finder found api_key: ' + value + ' at ' + url) verboseOutput.append('Token finder found api_key: ' + value + ' at ' + url) else: verboseOutput.append('No api_key match found on the page') authorization = re.findall('authorization:"(.+?)"', response.text) if len(authorization) > 0: for value in authorization: self.data.append([ 'Information disclosure', host, url, 'The following auth_token was found: ' + value ]) output.append('Token finder found auth token: ' + value + ' at ' + url) verboseOutput.append('Token finder found auth token: ' + value + ' at ' + url) else: verboseOutput.append('No authorization match found on the page') access_token = re.findall('access_token:"(.+?)"', response.text) if len(access_token) > 0: for value in access_token: self.data.append([ 'Information disclosure', host, url, 'The following access_token was found: ' + value ]) output.append('Token finder found access token: ' + value + ' at ' + url) verboseOutput.append('Token finder found access token: ' + value + ' at ' + url) else: verboseOutput.append('No access_token match found on the page') access_token2 = re.findall('access-token:"(.+?)"', response.text) if len(access_token2) > 0: for value in access_token2: self.data.append([ 'Information disclosure', host, url, 'The following access-token was found: ' + value ]) output.append('Token finder found access token: ' + value + ' at ' + url) verboseOutput.append('Token finder found access token: ' + value + ' at ' + url) else: verboseOutput.append('No access-token match found on the page') token_1 = re.findall('Token:"(.+?)"', response.text) if len(token_1) > 0: for value in token_1: self.data.append([ 'Information disclosure', host, url, 'The following token was found: ' + value ]) output.append('Token finder found token: ' + value + ' at ' + url) verboseOutput.append('Token finder found token: ' + value + ' at ' + url) else: verboseOutput.append('No Token match found on the page') token_2 = re.findall('token:"(.+?)"', response.text) if len(token_2) > 0: for value in token_2: self.data.append([ 'Information disclosure', host, url, 'The following token was found: ' + value ]) output.append('Token finder found token: ' + value + ' at ' + url) verboseOutput.append('Token finder found token: ' + value + ' at ' + url) else: verboseOutput.append('No token match found on the page') #Specific Tokens #------------------------------ Algolia ------------------------------ # Algolia uses algoliasearch for connecting inside a js, we will search the key pair algolia_key_pair = re.findall('algoliasearch\((.+?)\);', response.text) if len(algolia_key_pair) > 0: for value in algolia_key_pair: self.data.append([ 'Information disclosure', host, url, 'The following algolia key pair was found: ' + value ]) output.append('Token finder found algolia key pair: ' + value + ' at ' + url) verboseOutput.append('Token finder found algolia key pair: ' + value + ' at ' + url) else: verboseOutput.append('No algoliasearch match found on the page') #------------------------------ Asana ------------------------------ asana_access_token = re.findall('useAccessToken\((.+?)\);', response.text) if len(asana_access_token) > 0: for value in asana_access_token: self.data.append([ 'Information disclosure', host, url, 'The following assana access token was found: ' + value ]) output.append('Token finder found assana access token: ' + value + ' at ' + url) verboseOutput.append( 'Token finder found assana access token: ' + value + ' at ' + url) else: verboseOutput.append( 'No asana access token match found on the page') #------------------------------ AWS ------------------------------ access_key_ids = re.findall('access_key_id:"(.+?)"', response.text) secret_access_key_ids = re.findall('secret_access_key_id:"(.+?)"', response.text) if len(access_key_ids) > 0: for value in access_key_ids: self.data.append([ 'Information disclosure', host, url, 'The following access_key_id was found: ' + value ]) output.append('Token finder found access_key_id: ' + value + ' at ' + url) verboseOutput.append('Token finder found access_key_id: ' + value + ' at ' + url) else: verboseOutput.append('No aws access_key_ids found on the page') if len(secret_access_key_ids) > 0: for value in secret_access_key_ids: self.data.append([ 'Information disclosure', host, url, 'The following secret_access_key_id was found: ' + value ]) output.append('Token finder found secret_access_key_id: ' + value + ' at ' + url) verboseOutput.append( 'Token finder found secret_access_key_id: ' + value + ' at ' + url) else: verboseOutput.append( 'No aws secret_access_key_id found on the page') #------------------------------ Bitly ------------------------------ bitlyTokens = re.findall('BitlyClient\((.+?)\);', response.text) if len(bitlyTokens) > 0: for value in bitlyTokens: self.data.append([ 'Information disclosure', host, url, 'The following bitly token was found: ' + value ]) output.append('Token finder found bitly token: ' + value + ' at ' + url) verboseOutput.append('Token finder found bitly token: ' + value + ' at ' + url) else: verboseOutput.append('No bitly token found on the page') #------------------------------ Branchio ------------------------------ # Here we will get the whole client definithion, which contains key and secret_key branchioInfo = re.findall('branchio\(\{(.+?)\}\);', response.text) if len(branchioInfo) > 0: for value in branchioInfo: self.data.append([ 'Information disclosure', host, url, 'The following branchio definition was found: ' + value ]) output.append('Token finder found branchio definition: ' + value + ' at ' + url) verboseOutput.append( 'Token finder found branchio definition: ' + value + ' at ' + url) else: verboseOutput.append('No branchio token found on the page') #------------------------------ Dropbox ------------------------------ # Dropbox uses a method to set access token inside the javascript code dropboxToken = re.findall('Dropbox\(\{(.+?)\}\);', response.text) if len(dropboxToken) > 0: for value in dropboxToken: self.data.append([ 'Information disclosure', host, url, 'The following dropbox token was found: ' + value ]) output.append('Token finder found dropbox token: ' + value + ' at ' + url) verboseOutput.append('Token finder found dropbox token: ' + value + ' at ' + url) else: verboseOutput.append('No dropbox token found on the page') #------------------------------ Firebase ------------------------------ firebaseConfig = re.findall('firebaseConfig(.+?)\};', response.text) if len(firebaseConfig) > 0: for value in firebaseConfig: self.data.append([ 'Information disclosure', host, url, 'The following firebase config info was found: ' + value ]) output.append('Token finder found firebase config info: ' + value + ' at ' + url) verboseOutput.append( 'Token finder found firebase config info: ' + value + ' at ' + url) else: verboseOutput.append('No firebase config info fonund on the page') #------------------------------ Gitlab ------------------------------ gitlabInfo = re.findall('Gitlab\(\{(.+?)\}\);', response.text) if len(gitlabInfo) > 0: for value in gitlabInfo: self.data.append([ 'Information disclosure', host, url, 'The following gitlab personal info was found: ' + value ]) output.append('Token finder found gitlab personal info: ' + value + ' at ' + url) verboseOutput.append( 'Token finder found gitlab personal info: ' + value + ' at ' + url) else: verboseOutput.append('No gitlab info found on the page') #------------------------------ Google cloud messaging ------------------------------ gcm_key = re.findall('gcm.Sender\((.+?)\);', response.text) if len(gcm_key) > 0: for value in gcm_key: self.data.append([ 'Information disclosure', host, url, 'The following gcm api_key was found: ' + value ]) output.append('Token finder found gcm api_key: ' + value + ' at ' + url) verboseOutput.append('Token finder found gcm api_key: ' + value + ' at ' + url) else: verboseOutput.append( 'No google cloud messaging key found on the page') #------------------------------ Google maps ------------------------------ g_maps_key = re.findall( "require('@google/maps').createClient\(\{(.+?)\}\);", response.text) if len(g_maps_key) > 0: for value in g_maps_key: self.data.append([ 'Information disclosure', host, url, 'The following google maps key was found: ' + value ]) output.append('Token finder found google maps key: ' + value + ' at ' + url) verboseOutput.append('Token finder found google maps key: ' + value + ' at ' + url) else: verboseOutput.append('No google maps key found on the page') #------------------------------ Google autocomplete ------------------------------ g_autocomplete_key = re.findall( "googleAutoCompleteKey:Object\(\{(.+?)\}\)", response.text) if len(g_autocomplete_key) > 0: for value in g_autocomplete_key: self.data.append([ 'Information disclosure', host, url, 'The following google autocomplete key was found: ' + value ]) output.append('Token finder found google autocomplete key: ' + value + ' at ' + url) verboseOutput.append( 'Token finder found google autocomplete key: ' + value + ' at ' + url) else: verboseOutput.append( 'No google autocomplete key found on the page') #------------------------------ Google recaptcha ------------------------------ g_recaptcha_key = re.findall('GoogleRecaptcha\(\{(.+?)\}', response.text) if len(g_recaptcha_key) > 0: for value in g_recaptcha_key: self.data.append([ 'Information disclosure', host, url, 'The following google recaptcha key was found: ' + value ]) output.append('Token finder found google recaptcha key: ' + value + ' at ' + url) verboseOutput.append( 'Token finder found google recaptcha key: ' + value + ' at ' + url) else: verboseOutput.append('No google recaptcha key found on the page') #------------------------------ Hubspot ------------------------------ hubspot_key = re.findall('Hubspot\(\{(.+?)\}', response.text) if len(hubspot_key) > 0: for value in hubspot_key: self.data.append([ 'Information disclosure', host, url, 'The following hubspot key was found: ' + value ]) output.append('Token finder found hubspot key: ' + value + ' at ' + url) verboseOutput.append('Token finder found hubspot key: ' + value + ' at ' + url) else: verboseOutput.append('No hubspot key found on the page') #------------------------------ Instagram ------------------------------ instagram_config = re.findall('Instagram\((.+?)\)', response.text) if len(instagram_config) > 0: for value in instagram_config: self.data.append([ 'Information disclosure', host, url, 'The following instagram config info was found: ' + value ]) output.append('Token finder found instagram config info: ' + value + ' at ' + url) verboseOutput.append( 'Token finder found instagram config info: ' + value + ' at ' + url) else: verboseOutput.append('No instagram config info found on the page') #------------------------------ Jump cloud ------------------------------ jumpcloud_key = re.findall('JumpCloud\((.+?)\);', response.text) if len(jumpcloud_key) > 0: for value in jumpcloud_key: self.data.append([ 'Information disclosure', host, url, 'The following jumpcloud key was found: ' + value ]) output.append('Token finder found jumpcloud key: ' + value + ' at ' + url) verboseOutput.append('Token finder found jumpcloud key: ' + value + ' at ' + url) else: verboseOutput.append('No jumpCloud key found on the page') #------------------------------ Mail Chimp ------------------------------ mailchimp_key = re.findall('Mailchimp\((.+?)\);', response.text) if len(mailchimp_key) > 0: for value in mailchimp_key: self.data.append([ 'Information disclosure', host, url, 'The following mailchimp key was found: ' + value ]) output.append('Token finder found mailchimp key: ' + value + ' at ' + url) verboseOutput.append('Token finder found mailchimp key: ' + value + ' at ' + url) else: verboseOutput.append('No mailchimp key found on the page') #------------------------------ Pagerduty ------------------------------ pagerduty_key = re.findall('pdapiToken\((.+?)\);', response.text) if len(pagerduty_key) > 0: for value in pagerduty_key: self.data.append([ 'Information disclosure', host, url, 'The following pagerduty key was found: ' + value ]) output.append('Token finder found pagerduty key: ' + value + ' at ' + url) verboseOutput.append('Token finder found pagerduty key: ' + value + ' at ' + url) else: verboseOutput.append('No paerduty key found on the page') #------------------------------ Paypal ------------------------------ paypal_config = re.findall('paypal.configure\(\{(.+?)\}\);', response.text) if len(paypal_config) > 0: for value in paypal_config: self.data.append([ 'Information disclosure', host, url, 'The following paypal config info was found: ' + value ]) output.append('Token finder found paypal config info: ' + value + ' at ' + url) verboseOutput.append( 'Token finder found paypal config info: ' + value + ' at ' + url) else: verboseOutput.append( 'No paypal config information found on the page') #------------------------------ Razorpay ------------------------------ razorpay_key = re.findall('Razorpay\(\{(.+?)\}\);', response.text) if len(razorpay_key) > 0: for value in razorpay_key: self.data.append([ 'Information disclosure', host, url, 'The following razorpay config info was found: ' + value ]) output.append('Token finder found razorpay config info: ' + value + ' at ' + url) verboseOutput.append( 'Token finder found razorpay config info: ' + value + ' at ' + url) else: verboseOutput.append('No razorpay key found on the page') #------------------------------ SauceLabs ------------------------------ sauceLabs_key = re.findall('SauceLabs\(\{(.+?)\}\);', response.text) if len(sauceLabs_key) > 0: for value in sauceLabs_key: self.data.append([ 'Information disclosure', host, url, 'The following saucelab config info was found: ' + value ]) output.append('Token finder found saucelab config info: ' + value + ' at ' + url) verboseOutput.append( 'Token finder found saucelab config info: ' + value + ' at ' + url) else: verboseOutput.append('No sauceLabs key found on the page') #------------------------------ Sendgrid ------------------------------ sendgrid_key = re.findall('sendgrid_api_key:"(.+?)"', response.text) if len(sendgrid_key) > 0: for value in sendgrid_key: self.data.append([ 'Information disclosure', host, url, 'The following sendgrid key was found: ' + value ]) output.append('Token finder found sendgrid key: ' + value + ' at ' + url) verboseOutput.append('Token finder found sendgrid key: ' + value + ' at ' + url) else: verboseOutput.append('No sendgrid key found on the page') #------------------------------ Slack ------------------------------ slack_key = re.findall('Slack\(\{(.+?)\}\)', response.text) if len(slack_key) > 0: for value in slack_key: self.data.append([ 'Information disclosure', host, url, 'The following slack key was found: ' + value ]) output.append('Token finder found slack key: ' + value + ' at ' + url) verboseOutput.append('Token finder found slack key: ' + value + ' at ' + url) else: verboseOutput.append('No slack key found on the page') #------------------------------ Spotify ------------------------------ spotify_key = re.findall('Spotify\(\{(.+?)\}\);', response.text) if len(spotify_key) > 0: for value in spotify_key: self.data.append([ 'Information disclosure', host, url, 'The following spotify config was found: ' + value ]) output.append('Token finder found spotify config: ' + value + ' at ' + url) verboseOutput.append('Token finder found spotify config: ' + value + ' at ' + url) else: verboseOutput.append('No spotify key found on the page') #------------------------------ Square ------------------------------ square_key = re.findall('oauth2.accessToken = "(.+?)"', response.text) if len(square_key) > 0: for value in square_key: self.data.append([ 'Information disclosure', host, url, 'The following square key was found: ' + value ]) output.append('Token finder found square key: ' + value + ' at ' + url) verboseOutput.append('Token finder found square key: ' + value + ' at ' + url) else: verboseOutput.append('No square key found on the page') #------------------------------ Travis ------------------------------ travis_key = re.findall('travis.auth.github.post\(\{(.+?)\}', response.text) if len(travis_key) > 0: for value in travis_key: self.data.append([ 'Information disclosure', host, url, 'The following travis key was found: ' + value ]) output.append('Token finder found travis key: ' + value + ' at ' + url) verboseOutput.append('Token finder found travis key: ' + value + ' at ' + url) else: verboseOutput.append('No travis key found on the page') #------------------------------ Twilio ------------------------------ twilio_account_sid = re.findall('accountSid =(.+?);', response.text) twilio_auth_token = re.findall('authToken =(.+?);', response.text) if len(twilio_account_sid) > 0: for value in twilio_account_sid: self.data.append([ 'Information disclosure', host, url, 'The following twilio account sid was found: ' + value ]) output.append('Token finder found twilio account sid key: ' + value + ' at ' + url) verboseOutput.append( 'Token finder found twilio account sid key: ' + value + ' at ' + url) else: verboseOutput.append('No twilio account sid found on the page') if len(twilio_auth_token) > 0: for value in twilio_auth_token: self.data.append([ 'Information disclosure', host, url, 'The following twilio auth token was found: ' + value ]) output.append('Token finder found twilio auth token: ' + value + ' at ' + url) verboseOutput.append('Token finder found twilio auth token: ' + value + ' at ' + url) else: verboseOutput.append('No twilio auth token found on the page') #------------------------------ Twitter ------------------------------ twitter_config = re.findall('Twitter\(\{(.+?)\}\)', response.text) if len(twitter_config) > 0: for value in twitter_config: self.data.append([ 'Information disclosure', host, url, 'The following twitter config info was found: ' + value ]) output.append('Token finder found twitter config info: ' + value + ' at ' + url) verboseOutput.append( 'Token finder found twitter config info: ' + value + ' at ' + url) else: verboseOutput.append( 'No twiter config information found on the page') #------------------------------ bugsnag ------------------------------ bugsnag = re.findall('bugsnagAPI:Object\(\{(.+?)\)\}', response.text) if len(bugsnag) > 0: for value in bugsnag: self.data.append([ 'Information disclosure', host, url, 'The following bugsnag config info was found: ' + value ]) output.append('Token finder found bugsnag config info: ' + value + ' at ' + url) verboseOutput.append( 'Token finder found bugsnag config info: ' + value + ' at ' + url) else: verboseOutput.append('No bugsnag API key found on the page') return output, verboseOutput def process(self, url, endpoint): output, verboseOutput = self.tokenProcess(self.session, url, endpoint) #output = self.helper.normalizeList(output) #verboseOutput = self.helper.normalizeList(verboseOutput) return output, verboseOutput def run(self, urls): for url in urls: output = [] verboseOutput = [] print('----------------------------------------------------') print('Scanning ' + url) if not self.helper.verifyURL(self.session, url, url, self.error_data, 'full'): continue js_in_url = self.helper.get_js_in_url(self.session, url) for js_endpoint in js_in_url: if not self.helper.verifyURL(self.session, url, js_endpoint, self.error_data, 'full'): continue output_tmp, verboseOutput_tmp = self.tokenProcess( self.session, url, js_endpoint) output.append(output_tmp) verboseOutput.append(verboseOutput_tmp) http_in_js = self.helper.get_http_in_js( self.session, js_endpoint) #print(http_in_js) for http_endpoint in http_in_js: if not self.helper.verifyURL( self.session, url, http_endpoint, self.error_data, 'full'): continue output_tmp, verboseOutput_tmp = self.tokenProcess( self.session, js_endpoint, http_endpoint) output.append(output_tmp) verboseOutput.append(verboseOutput_tmp) output = self.helper.normalizeList(output) verboseOutput = self.helper.normalizeList(verboseOutput) for item in output: print(item)
class OpenRedirect(): def __init__(self, SESSION): self.scanned_targets = [] self.helper = Helper() self.data = [] self.error_data = [] self.outputActivated = False self.msTeamsActivated = False self.session = SESSION with open('extra/openRedirect_parameters.txt') as fp: lines = fp.read() self.parameters = lines.split('\n') with open('extra/openRedirect_payloads.txt') as fp: lines = fp.read() self.payloads = lines.split('\n') def activateOutput(self): self.outputActivated = True def activateMSTeams(self, msTeams): self.msTeamsActivated = True self.msTeams = msTeams def showStartScreen(self): print( '---------------------------------------------------------------------------------------' ) print( '----------------------------++++++++++++------++++++++++++-------------./*/.-----------' ) print( '--------------------./*/.--++++++++++++++-----++++++++++++++---------------------------' ) print( '---------------------------+++--------+++-----+++-------+++++---./*/.------------------' ) print( '---./*/.-------------------+++--------+++-----+++------+++++---------------------------' ) print( '---------------------------+++--------+++-----++++++++++++-----------------------------' ) print( '------------./*/.----------+++--------+++-----+++++++++-----------------./*/.----------' ) print( '---------------------------+++--------+++-----+++---++++-------------------------------' ) print( '---------------------------+++--------+++-----+++-----++++-----------------------------' ) print( '---------------------------++++++++++++++-----+++-------++++-------------------./*/.---' ) print( '------------./*/.-----------++++++++++++------+++--------++++----./*/.-----------------' ) print( '---------------------------------------------------------------------------------------' ) print( ' ' ) print( '----------------------------------- Handerllon ©_© ------------------------------------' ) print( ' ' ) print( '--------------------------- Starting open redirect scanner ----------------------------' ) print('Scanning for open redirect on input...') def showEndScreen(self): print( '---------------------------------------------------------------------------------------' ) print('Finished! Please check output for results!') def output(self): data_df = pd.DataFrame( self.data, columns=['Vulnerability', 'MainUrl', 'Reference', 'Description']) error_df = pd.DataFrame( self.error_data, columns=['Module', 'MainUrl', 'Reference', 'Reason']) return (data_df, error_df) #Testing open redirect def testOpenRedirect(self, session, url): output = [] verboseOutput = [] if url in self.scanned_targets: return output, verboseOutput self.scanned_targets.append(url) if 'login' not in url: return output, verboseOutput try: response = session.get(url, verify=False) except Exception as e: verboseOutput.append('OpenRedirect finder caught exception ' + e) return output, verboseOutput #headers = response.headers #cookie = headers["Set-Cookie"] #header_update = {'Set-Cookie': cookie} #self.session.headers.update(header_update) #print(self.session.headers) #For each endpoint we try parameters and payloads for parameter in self.parameters: #print('Reached') for payload in self.payloads: finalPayload = parameter.replace("{payload}", payload) url_to_scan = url + finalPayload try: response = self.session.get(url_to_scan, verify=False) except Exception as e: verboseOutput.append( 'OpenRedirect finder caught exception ' + e) continue if response.status_code == 404: if self.outputActivated: print('Url: ' + url + ' returned 404') self.error_data.append( ['openred', url, url, 'Returned 404']) continue #If on the redirect history we see google.com as host #The information is added for output for resp in response.history: resp_split = resp.url.split('/') if resp_split[2] == 'google.com': print(resp.status_code, resp.url) self.data.append([ 'Open Redirect Vulnerability', url, url, 'An open redirect vulnerability was found with parameter: ' + parameter + ' and payload: ' + payload ]) output.append( 'OpenRedirectFinder found possible open redirect vulnerability on: ' + url + 'with parameter: ' + parameter + ' and payload: ' + payload) if self.msTeamsActivated: self.msTeams.title( 'Open redirect vulnerability found!') self.msTeams.text('Found at ' + url + 'with parameter: ' + parameter + ' and payload: ' + payload) self.msTeams.send() return output, verboseOutput def process(self, url, host): output = [] verboseOutput = [] output, verboseOutput = self.testOpenRedirect(self.session, url) return output, verboseOutput def run(self, urls): for url in urls: output = [] print('----------------------------------------------------') print('Scanning ' + url) if not self.helper.verifyURL(self.session, url, url, self.error_data, 'full'): continue output, verboseOutput = self.process(url, url) for item in output: print(item)
class FullScanner(): def __init__(self, outputFolderName, scope, SESSION): self.data = [] self.error_data = [] self.textList = [] self.scope = scope self.bucketFinder = BucketFinder(SESSION) self.tokenFinder = TokenFinder(SESSION) self.headerFinder = HeaderFinder(outputFolderName, SESSION) self.openRedirect = OpenRedirect(SESSION) self.cssChecker = CssChecker(SESSION) self.endpointFinder = EndpointFinder(SESSION) self.firebaseFinder = FirebaseFinder(SESSION) self.helper = Helper() self.session = SESSION def activateMSTeams(self, msTeams): self.bucketFinder.activateMSTeams(msTeams) self.openRedirect.activateMSTeams(msTeams) self.cssChecker.activateMSTeams(msTeams) self.endpointFinder.activateMSTeams(msTeams) self.firebaseFinder.activateMSTeams(msTeams) def showStartScreen(self): print('---------------------------------------------------------------------------------------') print('---------------------------++++++++++++++-------++++++++++++-----------./*/.-----------') print('--------------------./*/.--++++++++++++++------++++++++++++++--------------------------') print('---------------------------+++-----------------+++--------------./*/.------------------') print('---./*/.-------------------+++-----------------+++-------------------------------------') print('---------------------------+++++++++++---------+++++++++++++---------------------------') print('------------./*/.----------+++++++++++---------++++++++++++++-----------./*/.----------') print('---------------------------+++----------------------------+++--------------------------') print('---------------------------+++----------------------------+++--------------------------') print('---------------------------+++-----------------++++++++++++++------------------./*/.---') print('------------./*/.----------+++------------------+++++++++++++----./*/.-----------------') print('---------------------------------------------------------------------------------------') print(' ') print('----------------------------------- Handerllon ©_© ------------------------------------') print(' ') print('---------------------- Starting full scan, this may take a while ----------------------') print('Searching urls...') def showEndScreen(self): print('---------------------------------------------------------------------------------------') print('Finished! Please check output for results!') def output(self, path): #HeaderFinder output self.headerFinder.output(path) final_data_df = pd.DataFrame(self.data, columns = ['Vulnerability','MainUrl','Reference','Description']) final_error_df = pd.DataFrame(self.error_data, columns = ['Module','MainUrl','Reference','Reason']) #Adding bucket output data_df, error_df = self.bucketFinder.output() final_data_df = final_data_df.append(data_df) final_error_df = final_error_df.append(error_df) #Adding token output data_df, error_df = self.tokenFinder.output() final_data_df = final_data_df.append(data_df) final_error_df = final_error_df.append(error_df) #Adding openred output data_df, error_df = self.openRedirect.output() final_data_df = final_data_df.append(data_df) final_error_df = final_error_df.append(error_df) #Adding css checker output data_df, error_df = self.cssChecker.output() final_data_df = final_data_df.append(data_df) final_error_df = final_error_df.append(error_df) #Adding endpoint finder output data_df, error_df = self.endpointFinder.output() final_data_df = final_data_df.append(data_df) final_error_df = final_error_df.append(error_df) #Adding firebase finder output data_df, error_df = self.firebaseFinder.output() final_data_df = final_data_df.append(data_df) final_error_df = final_error_df.append(error_df) final_data_df.drop_duplicates(keep = 'first', inplace = True) final_error_df.drop_duplicates(keep = 'first', inplace = True) return(final_data_df, final_error_df, self.textList) def appendTxtInformation(self, url, bucketFinder, firebaseFinder, openRedirect, endpointFinder, tokenFinder, cssFinder): self.textList.append(url) self.textList.append(' BucketFinder:') if not bucketFinder: #print('No finds with bucketFinder') self.textList.append(' No finds with bucketFinder') else: for item in bucketFinder: self.textList.append(' ' + item) self.textList.append(' FirebaseFinder:') if not firebaseFinder: #print('No finds with firebaseFinder') self.textList.append(' No finds with firebaseFinder') else: for item in firebaseFinder: self.textList.append(' ' + item) self.textList.append(' OpenRedirect:') if not openRedirect: #print('No finds with openRedirect') self.textList.append(' No finds with openRedirectFinder') else: for item in openRedirect: self.textList.append(' ' + item) self.textList.append(' EndpointFinder:') if not endpointFinder: #print('No finds with endpointFinder') self.textList.append(' No finds with endpointFinder') else: for item in endpointFinder: self.textList.append(' ' + item) self.textList.append(' CssFinder:') if not cssFinder: #print('No finds with cssFinder') self.textList.append(' No finds with cssFinder') else: for item in cssFinder: self.textList.append(' ' + item) self.textList.append(' TokenFinder:') if not tokenFinder: #print('No finds with tokenFinder') self.textList.append(' No finds with tokenFinder') else: for item in tokenFinder: self.textList.append(' ' + item) def run(self, urls): self.bucketFinder.activateOutput() #Start by iterating over urls for url in urls: output = [] verboseOutput = [] bucketFinderOutput = [] bucketFinderVerboseOutput = [] firebaseFinderOutput = [] firebaseFinderVerboseOutput = [] openRedirectOutput = [] openRedirectVerboseOutput = [] endpointFinderOutput = [] endpointFinderVerboseOutput = [] tokenFinderOutput = [] tokenFinderVerboseOutput = [] cssFinderOutput = [] cssFinderVerboseOutput = [] print('----------------------------------------------------') print('Scanning '+ url) if not self.helper.verifyURL(self.session, url, url, self.error_data, 'full'): continue bucketFinderOutput_tmp, bucketFinderVerboseOutput_tmp = self.bucketFinder.process(url,url) bucketFinderOutput.append(bucketFinderOutput_tmp) bucketFinderVerboseOutput.append(bucketFinderVerboseOutput_tmp) firebaseFinderOutput_tmp, firebaseFinderVerboseOutput_tmp = self.firebaseFinder.process(url, url) firebaseFinderOutput.append(firebaseFinderOutput_tmp) firebaseFinderVerboseOutput.append(firebaseFinderVerboseOutput_tmp) output.append(self.headerFinder.process(url)) openRedirectOutput_tmp, openRedirectVerboseOutput_tmp = self.openRedirect.process(url, url) openRedirectOutput.append(openRedirectOutput_tmp) openRedirectVerboseOutput.append(openRedirectVerboseOutput_tmp) endpointFinderOutput_tmp, endpointFinderVerboseOutput_tmp = self.endpointFinder.process(url) endpointFinderOutput.append(endpointFinderOutput_tmp) endpointFinderVerboseOutput.append(endpointFinderVerboseOutput_tmp) #We get js files from the url js_in_url = self.helper.get_js_in_url(self.session, url) js_in_url = self.helper.checkScope(js_in_url, self.scope) #We get css from the url css_in_url = self.helper.get_css_in_url(self.session, url) css_in_url = self.helper.checkScope(css_in_url, self.scope) urls_in_url = self.helper.get_http_in_js(self.session, url) urls_in_url = self.helper.checkScope(urls_in_url, self.scope) for url_in_url in urls_in_url: if not self.helper.verifyURL(self.session, url, url_in_url, self.error_data, 'full'): continue bucketFinderOutput_tmp, bucketFinderVerboseOutput_tmp = self.bucketFinder.process(url,url_in_url) bucketFinderOutput.append(bucketFinderOutput_tmp) bucketFinderVerboseOutput.append(bucketFinderVerboseOutput_tmp) firebaseFinderOutput_tmp, firebaseFinderVerboseOutput_tmp = self.firebaseFinder.process(url, url_in_url) firebaseFinderOutput.append(firebaseFinderOutput_tmp) firebaseFinderVerboseOutput.append(firebaseFinderVerboseOutput_tmp) tokenFinderOutput_tmp, tokenFinderVerboseOutput_tmp = self.tokenFinder.process(url, url_in_url) tokenFinderOutput.append(tokenFinderOutput_tmp) tokenFinderVerboseOutput.append(tokenFinderVerboseOutput_tmp) #We run the tools that interact with js files for js_endpoint in js_in_url: if not self.helper.verifyURL(self.session, url, js_endpoint, self.error_data, 'full'): continue bucketFinderOutput_tmp, bucketFinderVerboseOutput_tmp = self.bucketFinder.process(url,js_endpoint) bucketFinderOutput.append(bucketFinderOutput_tmp) bucketFinderVerboseOutput.append(bucketFinderVerboseOutput_tmp) firebaseFinderOutput_tmp, firebaseFinderVerboseOutput_tmp = self.firebaseFinder.process(url, js_endpoint) firebaseFinderOutput.append(firebaseFinderOutput_tmp) firebaseFinderVerboseOutput.append(firebaseFinderVerboseOutput_tmp) tokenFinderOutput_tmp, tokenFinderVerboseOutput_tmp = self.tokenFinder.process(url, js_endpoint) tokenFinderOutput.append(tokenFinderOutput_tmp) tokenFinderVerboseOutput.append(tokenFinderVerboseOutput_tmp) #Search urls in js file urls_in_js = self.helper.get_http_in_js(self.session, js_endpoint) urls_in_js = self.helper.checkScope(urls_in_js, self.scope) #We run the tool that interacts with sub_urls for sub_url in urls_in_js: if not self.helper.verifyURL(self.session, url, js_endpoint, self.error_data, 'full'): continue bucketFinderOutput_tmp, bucketFinderVerboseOutput_tmp = self.bucketFinder.process(url,sub_url) bucketFinderOutput.append(bucketFinderOutput_tmp) bucketFinderVerboseOutput.append(bucketFinderVerboseOutput_tmp) firebaseFinderOutput_tmp, firebaseFinderVerboseOutput_tmp = self.firebaseFinder.process(url, sub_url) firebaseFinderOutput.append(firebaseFinderOutput_tmp) firebaseFinderVerboseOutput.append(firebaseFinderVerboseOutput_tmp) tokenFinderOutput_tmp, tokenFinderVerboseOutput_tmp = self.tokenFinder.process(url, sub_url) tokenFinderOutput.append(tokenFinderOutput_tmp) tokenFinderVerboseOutput.append(tokenFinderVerboseOutput_tmp) for css_endpoint in css_in_url: cssFinderOutput_tmp, cssFinderVerboseOutput_tmp = self.cssChecker.process(url, css_endpoint) cssFinderOutput.append(cssFinderOutput_tmp) cssFinderVerboseOutput.append(cssFinderVerboseOutput_tmp) bucketFinderOutput = self.helper.normalizeList(bucketFinderOutput) firebaseFinderOutput = self.helper.normalizeList(firebaseFinderOutput) openRedirectOutput = self.helper.normalizeList(openRedirectOutput) endpointFinderOutput = self.helper.normalizeList(endpointFinderOutput) tokenFinderOutput = self.helper.normalizeList(tokenFinderOutput) cssFinderOutput = self.helper.normalizeList(cssFinderOutput) bucketFinderVerboseOutput = self.helper.normalizeList(bucketFinderVerboseOutput) firebaseFinderVerboseOutput = self.helper.normalizeList(firebaseFinderVerboseOutput) openRedirectVerboseOutput = self.helper.normalizeList(openRedirectVerboseOutput) endpointFinderVerboseOutput = self.helper.normalizeList(endpointFinderVerboseOutput) tokenFinderVerboseOutput = self.helper.normalizeList(tokenFinderVerboseOutput) cssFinderVerboseOutput = self.helper.normalizeList(cssFinderVerboseOutput) self.appendTxtInformation(url, bucketFinderVerboseOutput, firebaseFinderVerboseOutput, openRedirectVerboseOutput, endpointFinderVerboseOutput, tokenFinderVerboseOutput, cssFinderVerboseOutput) output.append(bucketFinderOutput) output.append(firebaseFinderOutput) output.append(openRedirectOutput) output.append(endpointFinderOutput) output.append(tokenFinderOutput) output.append(cssFinderOutput) output = self.helper.normalizeList(output) for item in output: print(item)
class FirebaseFinder(): def __init__(self, SESSION): self.scanned_targets = [] self.data = [] self.error_data = [] self.msTeamsActivated = False self.outputActivated = False self.helper = Helper() self.session = SESSION def activateOutput(self): self.outputActivated = True def showStartScreen(self): print( '---------------------------------------------------------------------------------------' ) print( '---------------------------++++++++++++++----+++++++++++++-------------./*/.-----------' ) print( '--------------------./*/.--++++++++++++++----++++++++++++++----------------------------' ) print( '---------------------------+++---------------+++--------++++----./*/.------------------' ) print( '---./*/.-------------------+++---------------+++--------++++---------------------------' ) print( '---------------------------+++++++++---------++++++++++++++----------------------------' ) print( '------------./*/.----------+++++++++---------++++++++++++++-------------./*/.----------' ) print( '---------------------------+++---------------+++--------++++---------------------------' ) print( '---------------------------+++---------------+++--------++++---------------------------' ) print( '---------------------------+++---------------++++++++++++++--------------------./*/.---' ) print( '------------./*/.----------+++---------------+++++++++++++-------./*/.-----------------' ) print( '---------------------------------------------------------------------------------------' ) print( ' ' ) print( '----------------------------------- Handerllon ©_© ------------------------------------' ) print( ' ' ) print( '-------------------------- Starting vulnerable firebase finder --------------------------' ) print('Searching firebase databases on input...') def showEndScreen(self): print( '---------------------------------------------------------------------------------------' ) print('Finished! Please check output for results!') def output(self): data_df = pd.DataFrame( self.data, columns=['Vulnerability', 'MainUrl', 'Reference', 'Description']) error_df = pd.DataFrame( self.error_data, columns=['Module', 'MainUrl', 'Reference', 'Reason']) return (data_df, error_df) def activateMSTeams(self, msTeams): self.msTeamsActivated = True self.msTeams = msTeams def filterInvalids(self, some_list): res = [] #------ Filter invalid matches for item in some_list: if all( char not in item for char in ['\\', '=', '>', '<', '[', ']', '{', '}', ';', '(', ')', '_']): res.append(item) return res def check_firebase(self, url, endpoint, firebases): output = [] verboseOutput = [] for firebase in firebases: try: firebase_response = self.session.get(firebase, verify=False, timeout=3) except Exception as e: print(e) verboseOutput.append('Catched exception ' + e) continue if firebase_response.status_code == 200: output.append('FirebaseFinder found open firebase: ' + firebase) verboseOutput.append('FirebaseFinder found open firebase: ' + firebase) self.data.append([ 'Open firebase', url, endpoint, 'There was an open firebase found at ' + firebase ]) return output, verboseOutput def get_firebases(self, session, url, host): if url in self.scanned_targets: return [] self.scanned_targets.append(url) try: response = session.get(url, verify=False, timeout=3) except requests.exceptions.ConnectionError: return [] except requests.exceptions.ReadTimeout: return [] except Exception as e: return [] #Firebases come in the form #https://*.firebaseio.com #---------Way I---------- firebaseHTTPS = re.findall('"https://([^\"/,]+).firebaseio.com"', response.text) firebaseHTTPS = self.filterInvalids(firebaseHTTPS) firebaseHTTP = re.findall('"http://([^\"/,]+).firebaseio.com"', response.text) firebaseHTTP = self.filterInvalids(firebaseHTTP) firebase_list = firebaseHTTPS + firebaseHTTP firebase_list = list(dict.fromkeys(firebase_list)) for i in range(len(firebase_list)): firebase_list[ i] = 'http://' + firebase_list[i] + '.firebaseio.com/.json' return firebase_list def process(self, url, endpoint): output = [] verboseOutput = [] firebases = self.get_firebases(self.session, endpoint, url) try: output, verboseOutput = self.check_firebase(url, url, firebases) except Exception as e: output = [[]] verboseOutput = [[ 'Firebase finder presented error ' + str(e) + ' at ' + url ]] output = self.helper.normalizeList(output) verboseOutput = self.helper.normalizeList(verboseOutput) return output, verboseOutput #Receives an urlList def run(self, urls): for url in urls: output = [] verboseOutput = [] print('----------------------------------------------------') print('Scanning ' + url) if not self.helper.verifyURL(self.session, url, url, self.error_data, 'firebaseFinder'): continue firebases = self.get_firebases(self.session, url, url) output_tmp, verboseOutput_tmp = self.check_firebase( url, 'html code', firebases) output.append(output_tmp) verboseOutput.append(verboseOutput_tmp) js_in_url = self.helper.get_js_in_url(self.session, url) for js_endpoint in js_in_url: if not self.helper.verifyURL(self.session, url, js_endpoint, self.error_data, 'firebaseFinder'): continue # Searching for buckets firebases = self.get_firebases(self.session, js_endpoint, url) output_tmp, verboseOutput_tmp = self.check_firebase( url, js_endpoint, firebases) output.append(output_tmp) verboseOutput.append(verboseOutput_tmp) #Search urls in js file http_in_js = self.helper.get_http_in_js(self.session, url) for http_endpoint in http_in_js: if not self.helper.verifyURL( self.session, url, http_endpoint, self.error_data, 'firebaseFinder'): continue firebases = self.get_firebases(self.session, http_endpoint, url) output_tmp, verboseOutput_tmp = self.check_firebase( url, http_endpoint, firebases) output.append(output_tmp) verboseOutput.append(verboseOutput_tmp) output = self.helper.normalizeList(output) verboseOutput = self.helper.normalizeList(verboseOutput) for item in output: print(item)
class CssChecker(): def __init__(self, SESSION): self.scanned_targets = [] self.data = [] self.error_data = [] self.outputActivated = False self.msTeamsActivated = False self.helper = Helper() self.session = SESSION def activateOutput(self): self.outputActivated = True def activateMSTeams(self, msTeams): self.msTeamsActivated = True self.msTeams = msTeams def showStartScreen(self): print( '---------------------------------------------------------------------------------------' ) print( '----------------------------+++++++++++++------+++++++++++++-----------./*/.-----------' ) print( '--------------------./*/.--++++++++++++++-----++++++++++++++---------------------------' ) print( '---------------------------+++++--------------+++++-------------./*/.------------------' ) print( '---./*/.-------------------++++---------------++++-------------------------------------' ) print( '---------------------------++++---------------++++-------------------------------------' ) print( '------------./*/.----------++++---------------++++----------------------./*/.----------' ) print( '---------------------------++++---------------++++-------------------------------------' ) print( '---------------------------+++++--------------+++++------------------------------------' ) print( '---------------------------++++++++++++++-----++++++++++++++-------------------./*/.---' ) print( '------------./*/.-----------+++++++++++++------+++++++++++++-----./*/.-----------------' ) print( '---------------------------------------------------------------------------------------' ) print( ' ' ) print( '----------------------------------- Handerllon ©_© ------------------------------------' ) print( ' ' ) print( '-------------------------------- Starting css checker ---------------------------------' ) print('Listing headers on input...') def showEndScreen(self): print( '---------------------------------------------------------------------------------------' ) print('Finished! Please check output for results!') def output(self): data_df = pd.DataFrame( self.data, columns=['Vulnerability', 'MainUrl', 'Reference', 'Description']) error_df = pd.DataFrame( self.error_data, columns=['Module', 'MainUrl', 'Reference', 'Reason']) return (data_df, error_df) def filterInvalids(self, some_list): res = [] #------ Filter invalid matches for item in some_list: if all(char not in item for char in ['\\', '=', '>', '<', '[', ']', '{', '}', ';', '(', ')']): res.append(item) return res #Checks if css file found returns code 200 def scan_css(self, session, host, url): if url in self.scanned_targets: return self.scanned_targets.append(url) output = [] verboseOutput = [] #We split url and host to check, if vuln is found, if host domain != url domain url_split = url.split('/') host_split = host.split('/') if url[-1] == '\\' or url[-1] == '/': url = url[:-1] try: response = session.get(url, verify=False) except requests.exceptions.MissingSchema: if self.outputActivated: print('Missing schema error on ' + url) return output except: if url_split[2] != host_split[2]: self.data.append([ 'Possible css injection', ' ' + host, ' ' + url, 'Could not access the css file' ]) output.append('Possible css injection on: ' + url) verboseOutput.append('Possible css injection on: ' + url + 'could not access css file') if self.msTeamsActivated: self.msTeams.title('Possible css injection') self.msTeams.text('The css file ' + url + ' could not be accessed. Host url: ' + host) output('The css file ' + url + ' could not be accessed. Host url: ' + host) self.msTeams.send() else: verboseOutput.append('Css file ' + url + ' was accessed normally') return output, verboseOutput if response.status_code != 200: if url_split[2] != host_split[2]: self.data.append([ 'Possible css injection', host, url, ' Css file did not return 200' ]) output.append('CssChecker found possible injection: ' + url) verboseOutput.append('CssChecker found possible injection: ' + url + ' css file did not return 200') if self.msTeamsActivated: self.msTeams.title('Possible css injection') self.msTeams.text('The css file ' + url + ' did not return code 200. Host url: ' + host) self.msTeams.send() else: verboseOutput.append('Css file ' + url + ' was accessed normally') else: verboseOutput.append('Css file ' + url + ' was accessed normally') return output, verboseOutput def process(self, url, css): output = [] verboseOutput = [] try: output, verboseOutput = self.scan_css(self.session, url, css) except Exception as e: output = [] verboseOutput = [ 'Css checker presented error ' + str(e) + ' at ' + url ] return output, verboseOutput def run(self, urls): for url in urls: output = [] verboseOutput = [] print('----------------------------------------------------') print('Scanning ' + url) if not self.helper.verifyURL(self.session, url, url, self.error_data, 'cssChecker'): continue css_found = self.helper.get_css_in_url(self.session, url) #print(css_found) for css in css_found: output_tmp, verboseOutput_tmp = self.scan_css( self.session, url, css) output.append(output_tmp) verboseOutput.append(verboseOutput_tmp) output = self.helper.normalizeList(output) verboseOutput = self.helper.normalizeList(verboseOutput) for item in output: print(item)
class BucketFinder(): def __init__(self, SESSION): self.scanned_targets = [] self.data = [] self.error_data = [] self.msTeamsActivated = False self.outputActivated = False self.helper = Helper() self.session = SESSION self.regions = [ 'us-east-2', 'us-east-1', 'us-west-1', 'us-west-2', 'ap-east-1', 'ap-south-1', 'ap-northeast-3', 'ap-northeast-2', 'ap-southeast-1', 'ap-southeast-2', 'ap-northeast-1', 'ca-central-1', 'cn-north-1', 'cn-northwest-1', 'eu-central-1', 'eu-west-1', 'eu-west-2', 'eu-west-3', 'eu-north-1', 'me-south-1', 'sa-east-1', 'us-gov-east-1', 'us-gov-west-1' ] def activateOutput(self): self.outputActivated = True def showStartScreen(self): print( '---------------------------------------------------------------------------------------' ) print( '----------------------------++++++++++++-------++++++++++++++----------./*/.-----------' ) print( '--------------------./*/.--++++++++++++++------++++++++++++++--------------------------' ) print( '---------------------------+++----------------------------+++---./*/.------------------' ) print( '---./*/.-------------------+++----------------------------+++--------------------------' ) print( '---------------------------+++++++++++++-------++++++++++++++--------------------------' ) print( '------------./*/.----------++++++++++++++------++++++++++++++-----------./*/.----------' ) print( '--------------------------------------+++-----------------+++--------------------------' ) print( '--------------------------------------+++-----------------+++--------------------------' ) print( '---------------------------++++++++++++++------++++++++++++++------------------./*/.---' ) print( '------------./*/.-----------+++++++++++++------++++++++++++++----./*/.-----------------' ) print( '---------------------------------------------------------------------------------------' ) print( ' ' ) print( '----------------------------------- Handerllon ©_© ------------------------------------' ) print( ' ' ) print( '-------------------------- Starting vulnerable bucket finder --------------------------' ) print('Searching buckets on input...') def showEndScreen(self): print( '---------------------------------------------------------------------------------------' ) print('Finished! Please check output for results!') def output(self): data_df = pd.DataFrame( self.data, columns=['Vulnerability', 'MainUrl', 'Reference', 'Description']) error_df = pd.DataFrame( self.error_data, columns=['Module', 'MainUrl', 'Reference', 'Reason']) return (data_df, error_df) def activateMSTeams(self, msTeams): self.msTeamsActivated = True self.msTeams = msTeams def filterInvalids(self, some_list): res = [] #------ Filter invalid matches for item in some_list: if all(char not in item for char in ['\\', '=', '>', '<', '[', ']', '{', '}', ';', '(', ')']): res.append(item) return res def configureOutput(self, url, js_endpoint, bucket_list, ls_allowed, cprm_allowed, does_not_exist): output = [] verboseOutput = [] #------ Adding info for output for bucket in bucket_list: ls = False if bucket in ls_allowed: ls = True cprm = False if bucket in cprm_allowed: cprm = True not_exist = False if bucket in does_not_exist: not_exist = True if ls == True and cprm == True: self.data.append([ 'Misconfigured S3 bucket', url, js_endpoint, 'Bucket ' + bucket + ' has copy, remove and ls available for authenticated users' ]) output.append('BucketFinder found bucket ' + bucket + ' with ls and cprm allowed') verboseOutput.append('BucketFinder found bucket ' + bucket + ' with ls and cprm allowed') if self.msTeamsActivated: self.msTeams.title('Bucket found!') self.msTeams.text('Bucket ' + bucket + ' was found at host: ' + url + ' in: ' + js_endpoint + ' with ls and cprm allowed') self.msTeams.send() elif ls == True: self.data.append([ 'Misconfigured S3 bucket', url, js_endpoint, 'Bucket ' + bucket + ' has ls available for authenticated users' ]) output.append('BucketFinder found bucket ' + bucket + ' with ls allowed') verboseOutput.append('BucketFinder found bucket ' + bucket + ' with ls allowed') if self.msTeamsActivated: self.msTeams.title('Bucket found!') self.msTeams.text('Bucket ' + bucket + ' was found at host: ' + url + ' in: ' + js_endpoint + ' with ls allowed') self.msTeams.send() elif cprm == True: self.data.append([ 'Misconfigured S3 bucket', url, js_endpoint, 'Bucket ' + bucket + ' has copy and remove available for authenticated users' ]) output.append('BucketFinder found bucket ' + bucket + ' with cprm allowed') verboseOutput.append('BucketFinder found bucket ' + bucket + ' with cprm allowed') if self.msTeamsActivated: self.msTeams.title('Bucket found!') self.msTeams.text('Bucket ' + bucket + ' was found at host: ' + url + ' in: ' + js_endpoint + ' with cprm allowed') self.msTeams.send() elif not_exist == True: self.data.append([ 'Misconfigured S3 bucket', url, js_endpoint, 'Bucket ' + bucket + ' does not exist but resources are being loaded from it, bucket takeover possible' ]) output.append('BucketFinder found bucket ' + bucket + ' that is not claimed') verboseOutput.append('BucketFinder found bucket ' + bucket + ' that is not claimed') if self.msTeamsActivated: self.msTeams.title('Bucket found!') self.msTeams.text('Bucket ' + bucket + ' was found at host: ' + url + ' in: ' + js_endpoint + ' with does not exist error') self.msTeams.send() else: verboseOutput.append('BucketFinder found bucket ' + bucket + ' with no vulnerabilities') return output, verboseOutput def get_buckets(self, session, url, host): if url in self.scanned_targets: return [] self.scanned_targets.append(url) try: response = session.get(url, verify=False, timeout=3) except requests.exceptions.ConnectionError: return [] except requests.exceptions.ReadTimeout: return [] except Exception as e: return [] #Buckets can come in different ways #Way 1: http<s>://s3.amazonaws.com/bucketName #Way 2: http<s>://bucketName.s3.amazonaws.com #Way 3: //bucketName.s3.amazonaws.com #Way 4: https://s3-area.amazonaws.com/<bucketName>/ #---------Way I---------- bucketsFirstHTTPS = re.findall('"https://s3.amazonaws.com([^\"/,]+)"', response.text) bucketsFirstHTTPS = self.filterInvalids(bucketsFirstHTTPS) bucketsFirstHTTP = re.findall('"http://s3.amazonaws.com([^\"/,]+)"', response.text) bucketsFirstHTTP = self.filterInvalids(bucketsFirstHTTP) #---------Way II---------- bucketsSecondHTTPS = re.findall('https://([^\"/,]+).s3.amazonaws.com', response.text) bucketsSecondHTTPS = self.filterInvalids(bucketsSecondHTTPS) bucketsSecondHTTP = re.findall('http://([^\"/,]+).s3.amazonaws.com', response.text) bucketsSecondHTTP = self.filterInvalids(bucketsSecondHTTP) #---------Way III--------- bucketsThird = re.findall('\"//(.+?).s3.amazonaws.com', response.text) bucketsThird = self.filterInvalids(bucketsThird) #---------Way IV---------- bucketsFourth = re.findall('https://s3.amazonaws.com/(.+?)/', response.text) bucketsFourth = self.filterInvalids(bucketsFourth) wayIV_2 = re.findall('https://([^\"/,]+).s3.amazonaws.com/([^\"/,]+)/', response.text) for bucket in wayIV_2: #In this case the match are tuples, not lists bucket = list(bucket) if any(x in self.regions for x in bucket[0]): bucketsFourth.append(bucket[1]) #---------Way IV---------- bucketsFourth = re.findall('https://s3.amazonaws.com/(.+?)/', response.text) bucketsFourth = self.filterInvalids(bucketsFourth) bucketsFifth = list() wayV = re.findall('https://([^.\"/,]+).([^\"/,]+).amazonaws.com', response.text) for bucket in wayV: #In this case the match are tuples, not lists bucket = list(bucket) if 's3' in bucket[1]: bucketsFifth.append(bucket[0]) bucket_list = bucketsFirstHTTP + bucketsSecondHTTP + bucketsFirstHTTPS + bucketsSecondHTTPS + bucketsThird + bucketsFourth + bucketsFifth bucket_list = list(dict.fromkeys(bucket_list)) for i in range(len(bucket_list)): bucket_list[i] = bucket_list[i].replace('/', '') return bucket_list #--------------------- Get buckets that allow ls --------------------- def get_ls_buckets(self, bucket_list): ls_allowed_buckets = [] does_not_exist_buckets = [] for bucket in bucket_list: if (any(x.isupper() for x in bucket)): continue try: output = subprocess.check_output('aws s3 ls s3://' + bucket, shell=True, stderr=subprocess.STDOUT) #print(output) ls_allowed_buckets.append(bucket) except subprocess.CalledProcessError as e: if 'does not exist' in e.output.decode(): does_not_exist_buckets.append(bucket) continue return ls_allowed_buckets, does_not_exist_buckets #--------------------- Get buckets that allow mv and rm --------------------- def get_cprm_buckets(self, bucket_list): cprm_allowed_buckets = [] for bucket in bucket_list: try: output = subprocess.check_output('aws s3 cp test.txt s3://' + bucket, shell=True, stderr=subprocess.DEVNULL) subprocess.check_output('aws s3 rm s3://' + bucket + '/test.txt', shell=True) cprm_allowed_buckets.append(bucket) except subprocess.CalledProcessError as e: continue return cprm_allowed_buckets def check_buckets(self, hostname, subname, bucket_list): output = [] verboseOutput = [] if len(bucket_list) > 0: ls_allowed, does_not_exist = self.get_ls_buckets(bucket_list) cprm_allowed = self.get_cprm_buckets(bucket_list) access_denied = list( set(bucket_list) - set(ls_allowed) - set(cprm_allowed) - set(does_not_exist)) output_tmp, verboseOutput_tmp = self.configureOutput( hostname, subname, bucket_list, ls_allowed, cprm_allowed, does_not_exist) output.append(output_tmp) verboseOutput.append(verboseOutput_tmp) output = self.helper.normalizeList(output) verboseOutput = self.helper.normalizeList(verboseOutput) return output, verboseOutput def process(self, url, endpoint): bucket_list = self.get_buckets(self.session, endpoint, url) try: output, verboseOutput = self.check_buckets(url, endpoint, bucket_list) except Exception as e: output = [] verboseOutput = [ 'BucketFinder presented error ' + str(e) + ' at ' + url ] return output, verboseOutput #Receives an urlList def run(self, urls): for url in urls: output = [] verboseOutput = [] print('----------------------------------------------------') print('Scanning ' + url) if not self.helper.verifyURL(self.session, url, url, self.error_data, 's3bucket'): continue buckets_in_html = self.get_buckets(self.session, url, url) output_tmp, verboseOutput_tmp = self.check_buckets( url, 'html code', buckets_in_html) output.append(output_tmp) verboseOutput.append(verboseOutput_tmp) js_in_url = self.helper.get_js_in_url(self.session, url) #print(js_in_url) for js_endpoint in js_in_url: if not self.helper.verifyURL(self.session, url, js_endpoint, self.error_data, 's3bucket'): continue # Searching for buckets bucket_list = self.get_buckets(self.session, js_endpoint, url) #print(bucket_list) output_tmp, verboseOutput_tmp = self.check_buckets( url, js_endpoint, bucket_list) output.append(output_tmp) verboseOutput.append(verboseOutput_tmp) #Search urls in js file http_in_js = self.helper.get_http_in_js( self.session, js_endpoint) for http_endpoint in http_in_js: if not self.helper.verifyURL( self.session, url, http_endpoint, self.error_data, 's3bucket'): continue bucket_list = self.get_buckets(self.session, http_endpoint, url) output_tmp, verboseOutput_tmp = self.check_buckets( url, http_endpoint, bucket_list) output.append(output_tmp) verboseOutput.append(verboseOutput_tmp) output = self.helper.normalizeList(output) verboseOutput = self.helper.normalizeList(verboseOutput) for item in output: print(item)
class EndpointFinder(): def __init__(self, SESSION): self.scanned_targets = [] self.openRedirect = OpenRedirect(SESSION) self.helper = Helper() self.data = [] self.error_data = [] self.outputActivated = False self.msTeamsActivated = False self.invalid_codes = [301,302,303,400,403,404,503] self.session = SESSION with open('extra/endpointFinder_endpoints.txt') as fp: lines = fp.read() self.endpoints = lines.split('\n') #print(self.endpoints) def activateOutput(self): self.outputActivated = True def showStartScreen(self): print('---------------------------------------------------------------------------------------') print('---------------------------++++++++++++++------++++++++++++++----------./*/.-----------') print('--------------------./*/.--++++++++++++++------++++++++++++++--------------------------') print('---------------------------++++----------------++++-------------./*/.------------------') print('---./*/.-------------------++++----------------++++------------------------------------') print('---------------------------++++++++++++++------+++++++++++-----------------------------') print('------------./*/.----------++++++++++++++------+++++++++++--------------./*/.----------') print('---------------------------++++----------------++++------------------------------------') print('---------------------------++++----------------++++------------------------------------') print('---------------------------++++++++++++++------++++----------------------------./*/.---') print('------------./*/.----------++++++++++++++------++++--------------./*/.-----------------') print('---------------------------------------------------------------------------------------') print(' ') print('----------------------------------- Handerllon ©_© ------------------------------------') print(' ') print('-------------------------------- Starting endpoint finder --------------------------------') print('Searching endpoints...') def showEndScreen(self): print('---------------------------------------------------------------------------------------') print('Finished! Please check output for results!') def output(self): data_df = pd.DataFrame(self.data, columns = ['Vulnerability','MainUrl','Reference','Description']) error_df = pd.DataFrame(self.error_data, columns = ['Module','MainUrl','Reference','Reason']) return(data_df, error_df) def activateMSTeams(self, msTeams): self.msTeamsActivated = True self.msTeams = msTeams def scanEndpoint(self, url, endpoint): output = [] verboseOutput = [] try: normal_response = self.session.get(url, verify = False, timeout = 3, allow_redirects = False) except requests.exceptions.Timeout: return output, verboseOutput except Exception as e: print(e) return output, verboseOutput try: #Wont allow redirects endpoint_response = self.session.get(url+endpoint, verify = False, timeout = 3, allow_redirects = False) except requests.exceptions.Timeout: return output, verboseOutput except Exception as e: print(e) return output, verboseOutput for code in self.invalid_codes: if normal_response.status_code == code: return output, verboseOutput #Endpoint append returns 404 or 301 (redirect) for code in self.invalid_codes: if endpoint_response.status_code == code: return output, verboseOutput response_len = len(normal_response.text) end_response_len = len(endpoint_response.text) endpoint_len = len(endpoint) #Verifying response length #Cases where endpoint does not modify anything or only adds the endpoint len will return if(response_len - endpoint_len <= end_response_len <= response_len + endpoint_len): return output, verboseOutput else: if endpoint == '/login': output_tmp, verboseOutput_tmp = self.openRedirect.process(url+endpoint, url) output.append(output_tmp) output.append('EndpointFinder found: '+ url + endpoint) verboseOutput.append('EndpointFinder found login, started openRedirect') else: self.data.append(['Endpoint found',url,url,'Endpoint ' + url+endpoint + ' was found, it should be checked']) output.append('EndpointFinder found: '+ url + endpoint) verboseOutput.append('EndpointFinder found: '+ url + endpoint) output = [x for x in output if x != []] verboseOutput = [x for x in verboseOutput if x != []] return output, verboseOutput def process(self, url): if url in self.scanned_targets: return self.scanned_targets.append(url) output = [] verboseOutput = [] #Backspace verify if url[-1] == '/': url = url[:-1] for endpoint in self.endpoints: time.sleep(.5) output_tmp, verboseOutput_tmp = self.scanEndpoint(url, endpoint) output.append(output_tmp) verboseOutput.append(verboseOutput_tmp) output = self.helper.normalizeList(output) verboseOutput = self.helper.normalizeList(verboseOutput) return output, verboseOutput #Receives an urlList def run(self, urls): for url in urls: output = [] verboseOutput = [] print('----------------------------------------------------') print('Scanning '+ url) if not self.helper.verifyURL(self.session, url, url, self.error_data, 'endpointFinder'): continue output, verboseOutput = self.process(url) for item in output: print(item)