def main(): start = time.time() """ Parse input arguments """ args = parseArguments() """ We need some of them in every case """ validateArguments(args) """ Save input arguments """ withWordList, url, verbose, extended, paramlist, chunksize, extendedchar, waittime = getArguments( args) """ Deconstruct input url into base url without query string and list of query parameters """ baseUrl, parametersInUrl = deconstructUrl(url) initialRequestUrl = baseUrl + "?r4nd0mStr1ng=gn1rtSm0dn4r" """ Make inital paramter to base url using some bogus random string to verify that its not reflected """ content = request(initialRequestUrl, payload="?r4nd0mStr1ng=gn1rtSm0dn4r", waittime=waittime, showrequest=True) initialReflectionTest(content, extended) """ Extract interesting parameters based on input fields, textareas, ... """ interestingParameters = getInterestingParameters(content) reportParameterFindingInDom(interestingParameters) reportParameterFindingInUrl(parametersInUrl) """ Get our ~2500 word parameter list """ wordlistParameters = getParamsFromWordList(withWordList, paramlist) """ Combine all parameters (wordlist, params found in html response and parameters from url """ parameters = combineFoundParameters(wordlistParameters, interestingParameters, parametersInUrl) """ Add a payload to every parameter (necessary to detect a certain reflected parameter) """ parametersPayloaded = createOnePayloadPerParam(parameters, extendedchar) """ Create chunks of a given size... this reduces the number of requests needed to check all parameters. """ chunkedParmeterList = makeChunks(parametersPayloaded, chunksize) """ Now iterate through every chunk""" for iterator, chunk in enumerate(chunkedParmeterList): print(Alert.info() + "Request #{} started...".format(iterator + 1)) """ Construct our test url with parameter-value string """ getQuery = constructGetQuery(chunk) testUrl = "{}?{}".format(baseUrl, getQuery) """ Get the html response """ content = request(testUrl, payload="?" + getQuery, waittime=waittime, showrequest=verbose) """ Check if one of the current chunk payloads was found in the html response, if so report...""" reportReflection(content, chunk) print("") """ Small reminder for non extended mode """ if extended == False: print( Alert.info() + "If some reflected parameters were found using the default mode, I advice you too use the " "extended mode with some special characters like double quote, 'less than' or 'greater than' " "to check if those characters are reflected as well without sanitization: --extended -extendedchar '><'" ) end = time.time() print("Process finished after: {} seconds".format(end - start))
def validateArguments(args): if args.url is None: print(Alert.error() + "URL missing") sys.exit(1) if args.extended is True and (args.extendedchar is None or args.extendedchar is ""): print(Alert.error() + "Please specify a character for extended tests (e.g. > or <)") sys.exit(1)
def getParamsFromWordList(withWordList, paramlist): if withWordList == False: print(Alert.warning() + "No wordlist specified - we will use only custom paramters found in HTML response or URL") return [] if (os.path.exists(paramlist) == False): print(Alert.error() + "Wordlist specified but not found on filesystem") sys.exit(1) print(Alert.info() + "Reading wordlist...") return open(paramlist, 'r').read().splitlines()
def combineFoundParameters(wordlistParameters, interestingParameters, parametersInUrl): print(Alert.info() + "Custom parameters: {}".format(len(interestingParameters))) print(Alert.info() + "Inital get parameters: {}".format(len(parametersInUrl))) print(Alert.info() + "Wordlist parameters: {}".format(len(wordlistParameters))) combinedParameters = list(set(wordlistParameters + interestingParameters + parametersInUrl)) print(Alert.success() + "Deleting duplicates...") print(Alert.info() + "Using {} unique parameters".format(len(combinedParameters))) return combinedParameters
def reportParameterFindingInUrl(parametersInUrl): interestingParametersCount = len(parametersInUrl) if interestingParametersCount > 0: print(Alert.success() + "{} parameters found in URL".format(interestingParametersCount)) if interestingParametersCount is 0: print(Alert.info() + "No parameters found in URL") for iterator, param in enumerate(parametersInUrl): print(Alert.info() + "Parameter #{}: {}".format((iterator + 1), param))
def reportParameterFindingInDom(interestingParameters): interestingParametersCount = len(interestingParameters) if interestingParametersCount > 0: print(Alert.success() + "{} parameters found in HTML response".format( interestingParametersCount)) if interestingParametersCount is 0: print(Alert.info() + "No parameters found in HTML response") for iterator, param in enumerate(interestingParameters): print(Alert.info() + "Parameter #{}: {}".format((iterator + 1), param))
def initialReflectionTest(content, modeextended): paramWasReflected = False killScript = False if "r4nd0mStr1ng" in content: paramWasReflected = True print( Alert.warning() + "Random parameter (\"r4nd0mStr1ng\") was reflected in the inital request." ) print( Alert.warning() + "This will result in a lot false results, if you are not using extended mode!" ) if modeextended == True: print(Alert.success() + "Thank god! You are using the extended mode!") elif modeextended == False and paramWasReflected: killScript = True print(Alert.warning() + "You should use the extended test mode!") if killScript: sys.exit(1)
def createOnePayloadPerParam(parameters, extendedchar=""): hashes = [] parametersPayloaded = [] for param in parameters: hash = "{}{}a".format(hashlib.md5(param.encode('utf-8')).hexdigest()[0:7], extendedchar) if hash in hashes: print(Alert.warning() + "Duplicate payload identifier found... {}".format(hash)) parametersPayloaded.append([ param, hash ]) hashes.append(hash) return parametersPayloaded
def reportReflection(content, chunk): for param, payload in chunk: if payload in content: all_reflections[param] = payload print(Alert.reflection() + "Parameter '{}' with value '{}'".format(param, payload))
def request(url, payload, waittime=0, showrequest=False): if showrequest: print(Alert.info() + "Scraping '{}' ...".format(url)) try: res = make_request(url) if res.history and showrequest: print(Alert.warning() + "Request was redirected") print( Alert.success() + "Final destination: {} ({})".format(res.url, res.status_code)) if res.history and payload not in res.url and showrequest: print(Alert.warning() + "Sending new corrected request...") print(Alert.info() + "Corrected request: " + res.url + payload) confirm( prompt=Alert.info() + "Do you want to proceed? Please check the new url and use verbose mode!", resp=True) if res.history and payload not in res.url: res = make_request(res.url + payload) if res.status_code is 200: print(Alert.success() + "Statuscode 200") if res.status_code > 200 and res.status_code < 500: print(Alert.warning() + "Statuscode {}".format(res.status_code)) if res.status_code >= 500: print(Alert.error() + "Statuscode {}".format(res.status_code)) if res.text is None or res.text is '': print(Alert.error() + "No content fetched... (WAF?)") else: print(Alert.success() + "Content Length: {}".format(len(res.text))) if waittime > 0: print(Alert.info() + "Waiting {} seconds...".format(waittime)) time.sleep(waittime) return res.text except Exception as e: print(Alert.error() + "Exception while requesting victims url:") print(e) sys.exit(1)