./others/vulndetect.py

0.
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
331.
332.
333.
334.
335.
336.
337.
338.
339.
340.
341.
342.
343.
344.
345.
346.
347.
348.
349.
350.
351.
352.
353.
354.
355.
356.
357.
358.
359.
360.
361.
362.
363.
364.
365.
366.
367.
368.
369.
370.
371.
372.
373.
374.
375.
376.
377.
378.
379.
380.
381.
382.
383.
384.
385.
386.
387.
388.
389.
390.
391.
392.
393.
394.
395.
396.
397.
398.
399.
400.
401.
402.
403.
404.
405.
406.
407.
408.
409.
410.
411.
412.
413.
414.
415.
416.
417.
418.
419.
420.
421.
422.
423.
424.
425.
426.
427.
428.
429.
430.
431.
432.
433.
434.
435.
436.
437.
438.
439.
440.
441.
442.
443.
444.
445.
446.
447.
448.
449.
450.
451.
452.
453.
454.
455.
456.
457.
458.
459.
460.
461.
462.
463.
464.
465.
466.
467.
468.
469.
470.
471.
472.
473.
474.
475.
476.
477.
478.
479.
480.
481.
482.
483.
484.
485.
486.
487.
488.
489.
490.
491.
492.
493.
494.
495.
496.
497.
498.
499.
500.
501.
502.
503.
504.
505.
506.
507.
508.
509.
510.
511.
512.
513.
514.
515.
516.
517.
518.
519.
520.
521.
522.
523.
524.
525.
526.
527.
528.
529.
530.
531.
532.
533.
534.
535.
536.
537.
538.
539.
540.
541.
542.
543.
544.
545.
546.
547.
548.
549.
550.
551.
552.
553.
554.
555.
556.
557.
558.
559.
560.
561.
562.
563.
564.
565.
566.
567.
568.
569.
570.
571.
572.
573.
574.
575.
576.
577.
578.
579.
580.
581.
582.
583.
584.
585.
586.
587.
588.
589.
590.
591.
592.
593.
594.
595.
596.
597.
598.
599.
600.
601.
602.
603.
604.
605.
606.
607.
608.
609.
610.
611.
612.
613.
614.
615.
616.
617.
618.
619.
620.
621.
622.
623.
624.
625.
626.
627.
628.
629.
630.
631.
632.
633.
634.
635.
636.
637.
638.
639.
640.
641.
642.
643.
644.
645.
646.
647.
648.
649.
650.
651.
652.
653.
654.
655.
656.
657.
658.
659.
660.
661.
662.
663.
664.
665.
666.
667.
668.
669.
670.
671.
672.
673.
674.
675.
676.
677.
678.
679.
680.
681.
682.
683.
684.
685.
686.
687.
688.
689.
690.
691.
692.
693.
694.
695.
696.
697.
698.
699.
700.
701.
702.
703.
704.
705.
706.
707.
708.
709.
710.
711.
712.
713.
714.
715.
716.
717.
718.
719.
720.
721.
722.
723.
724.
725.
726.
727.
728.
729.
730.
731.
732.
733.
734.
735.
736.
737.
738.
739.
740.
741.
742.
743.
744.
745.
746.
747.
748.
749.
750.
751.
752.
753.
754.
755.
756.
757.
758.
759.
760.
761.
762.
763.
764.
765.
766.
767.
768.
769.
770.
771.
772.
773.
774.
775.
776.
777.
778.
779.
780.
781.
782.
783.
784.
785.
786.
787.
788.
789.
790.
791.
792.
793.
794.
795.
796.
797.
798.
799.
800.
801.
802.
803.
804.
805.
806.
807.
808.
809.
810.
811.
812.
813.
814.
815.
816.
817.
818.
819.
820.
821.
822.
823.
824.
825.
826.
827.
828.
829.
830.
831.
832.
833.
834.
835.
836.
837.
838.
839.
840.
841.
842.
843.
844.
845.
846.
847.
848.
849.
850.
851.
852.
853.
854.
855.
856.
857.
858.
859.
860.
861.
862.
863.
864.
865.
866.
867.
868.
869.
870.
871.
872.
873.
874.
875.
876.
877.
878.
879.
880.
881.
882.
883.
884.
885.
886.
887.
888.
889.
890.
891.
892.
893.
894.
895.
896.
897.
898.
899.
900.
901.
902.
903.
904.
905.
906.
907.
908.
909.
910.
911.
912.
913.
914.
915.
916.
917.
918.
919.
920.
921.
922.
923.
924.
925.
926.
927.
928.
929.
930.
931.
932.
933.
934.
935.
936.
937.
938.
939.
940.
941.
942.
943.
944.
945.
946.
947.
948.
949.
950.
951.
952.
953.
954.
955.
956.
957.
958.
959.
960.
961.
962.
963.
964.
965.
966.
967.
968.
969.
970.
971.
972.
973.
974.
975.
976.
977.
978.
979.
980.
981.
982.
983.
984.
985.
986.
987.
988.
989.
990.
991.
992.
993.
994.
995.
996.
997.
998.
999.
1000.
1001.
1002.
1003.
1004.
1005.
1006.
1007.
1008.
1009.
1010.
1011.
1012.
1013.
1014.
1015.
1016.
1017.
1018.
1019.
1020.
1021.
1022.
1023.
1024.
1025.
1026.
1027.
1028.
1029.
1030.
1031.
1032.
1033.
1034.
1035.
1036.
1037.
1038.
1039.
1040.
1041.
#!/usr/bin/python
 
# VulnDetector Version 0.0.1pa
# Author: Brad Cable
# License: GPL Version 2
 
 
## basic config - these need to be changed depending on the site to be scanned ##
 
site="http://www.site.com/"          # URL to tree/scan
domains=[".site.com",".site2.com"]   # whitelist of domains to scan, with a "." infront, it matches all subdomains as well
pagetype="php"                       # type of code used on the site being scanned ("php" or "asp")
 
# log locations, all logs are stored at [the current directory]/logs/LOGFILE
vulnlogfile="gfqlog"                 # file to log all detected vulnerabilities as they are encountered
urllogfile="gfqurllog"               # file to log all urls fetched as they are fetched
reportfile="gfqreport"               # at the end of the scan, the detected vulnerabilities are compiled into a neat list, and logged to this file
usecookies=True                      # whether or not to send a cookie header value each time (True or False)
cookies=""                           # if usecookies is True, then 
 
## end basic config ##
 
 
 
 
 
## advanced config - only change these if you know what you are doing, you really shouldn't need to touch these at all... ##
 
xssscan=True              # scan for XSS vulns (True or False)
sqliscan=True             # scan for SQLI vulns (True or False)
 
checklevel=1              # checklevel:
                          #   1 = Silent SQL, Silent XSS
                          #   2 = Silent SQL, Silent XSS when possible (semi-silent when not)
                          #   3 = BLAST THE SITE! (AKA, non Silent SQL, non Silent XSS, causes tons of MySQL Errors
                          #                        on the site and could possibly flood someone's admin email)
 
levels=7                  # levels deep to tree the site (I recommend 6-8; 6 is shorter, and fairly thorough, while 8 is just plain crazy long and a little too thorough)
ignore_subdomain=True     # ignore subdomains for HTTP Host field and other places (should leave as True)
 
scanlimit=5               # times to scan the same URL with different query strings,
                          # "bob.php?id=1" and "bob.php?id=2" count as two scans,
                          # and until scanlimit is hit, it will continue to check
                          # vulnerabilities on that URL
 
indent="     "            # indent used when displaying the results
ignorefileext="swf,fla,gif,jpeg,jpg,tiff,png,mng,pdf,dat,mpeg,mpg,mp2,mp3,wav,mod,mov,avi,asf,asx,ogg,asc,tgz,rpm,deb,gz,bz2,zip,rar,c,cpp,h,o,ko,py,so,torrent,js,css,msi,exe,bin,dmg,x86,ut4mod,wmv,rmvb,txt,n64,cbs,max,xps,xpi" # list of file extensions that shouldn't be downloaded and scanned 
 
randidentlen=6            # this is so internal, you shouldn't touch it whatsoever
decapitation=True         # this is so internal, you shouldn't touch it whatsoever
 
## end advanced config ##
 
 
########################################
###     DO NOT TOUCH THE REST!!!     ###
########################################
 
## setup ##
 
# import modules
import socket,sre,time,random
 
# debugging
from sys import exit # exit() for debug
# debug mode
from sys import argv
debug=False
if len(argv)>=2: debug=(argv[1]=="1")
 
# declare output variables
urlfields={}
postfields={}
treedurls={}
reportvar={}
 
# get comment type to use
if pagetype=="asp": comnt="%2d%2d"
elif pagetype=="php": comnt="/*"
else:
	print "Unknown Page Type: "+pagetype.upper()
	print "Using Default Database Comment: --"
	comnt="%2d%2d"
 
# get session stuff to use
sessstr="(?i)"
if pagetype=="asp": sessstr+="aspsessionid([a-z]{8})=([a-z]{8})"
elif pagetype=="php": sessstr+="phpsessid=([a-z0-9]{32})"
else:
	print "Unknown Page Type: "+pagetype.upper()
	sessstr+=pagetype+"sessid=([a-z0-9]{32})"
	print "Using Default Session Syntax: --"
 
# set up the ignore file extension variable to be useable
ignorefileext=","+ignorefileext+","
 
## end setup ##
 
 
## function declaration ##
 
# function to determine if a list object is empty in any way
def listempty(listarg): return (listarg==None or listarg==[] or type(listarg)!=type([]) or len(listarg)==0)
 
# function to edit files easily
def filestuff(fname,body="",fptype=False):
 
	if not fptype:
		if body=="": fptype="r"
		else: fptype="a"
 
	fp=open(fname,fptype)
	fp.write(str(body))
	fp.close()
 
# function to remove non unique items
def uniqlist(listarg):
	if type(listarg)!=type([]): return
	newlist=[]
	for i in range(len(listarg)):
		if newlist.count(listarg[i])==0: newlist[len(newlist):len(newlist)]=[listarg[i]]
	return newlist
 
# function to get the page name of a url
def pagename(url):
	if url[:7]=="http://": url=url[7:]
	slash=url.find("/")
	if slash!=-1: url=url[slash:]
	else: url="/"
	return url
 
# function to fix urls like "http://www.google.com" or "www.google.com" into "http://www.google.com/"
def urlfix(url):
	if url[:7]!="http://": url="http://"+url
	slash=url[7:].find("/")
	if slash==-1: url+="/"
	return url
 
# function to get the server name of a url
def servername(url,ig_subd=ignore_subdomain):
	url=urlfix(url)[7:]
	url=url[:url.find("/")]
# 	if ig_subd: url=sre.sub("^.*?([^\.]*\.[^\.]*)$","\\1",url)
	return url
 
def checkserver(server):
	global domains
	for domain in domains:
		if domain[:1]==".":
			if server[-len(domain)+1:]==domain[1:]: return True
		else:
			if server==domain: return True
	return False
 
# function to fix the headers so they don't contain %25's (%'s) or the xxploit code
def headerfupr(hdr,explt):
	hdr=hdr.replace("%25","%")
	hdr=hdr.replace(explt,"")
	return hdr
 
# function to remove urls from the body of a page
def removeurls(body): return sre.sub("http://([^ \"\']+)","",body)
 
# function to retreive the full path of a url based on the current page url
def fullpath(url,pageurl):
 
	if url.lower()[:7]=="http://": return url
 
	if pageurl.count("?")!=0: pageurl=pageurl[:pageurl.find("?")]
 
	if url.count("?")>0:
		if url[:1]=="?": return pageurl+url
		pageurl=pageurl[:pageurl.find("?")]
 
	#pageurl=pageurl[:pageurl.find("?")]
 
	pagedomain=pageurl[:pageurl[7:].find("/")+7]
	if url[:1]=="/": return pagedomain+url
 
	pagepath=pageurl[pageurl[7:].find("/")+7:]
	pagepath=pagepath[:pagepath.rfind("/")+1]
	path=pagepath+url
	path=sre.sub("\.\/","\/",path)
	path=sre.sub("\/([^\/]+)\/..\/","\/",path)
 
	return pagedomain+path
 
# function to get the value of HTML attribute before a ">"
def getattrval(body,attr):
	body=sre.sub("([^\>]*)\>([^\000]*)","\\1",body)
        if sre.search(attr+"=(\"|'|)([^\\1\ \>]*)\\1",body)!=None:
		delim=sre.sub("[^\>]* "+attr+"=(\"|'|)([^\\1\ \>]*)\\1([^\>]*)","\\1",body)
		exp="[^\>]* "+attr+"=(\\"+delim+")([^"
		if delim=="": exp+="\ "
		else: exp+=delim
		exp+="\>]*)\\"+delim+"([^\>]*)"
		return sre.sub(exp,"\\2",body)
	else: return ""
 
# function to retreive a page based on input
def getpage(url,dheaders=1,redir=0,realpage=0,poststring="",exceptions=0):
 
	# function to recurse and try getpage() again with new values
	def recurse(exceptions):
 
		sock.close()
		exceptions+=1
 
		if exceptions<=6: return getpage(url,dheaders,redir,realpage,poststring,exceptions)
		else:
			print "Too many recursions, skipping..."
			return
 
 
	global usecookies,urllogfile,debug,ignorefileext
	if not checkserver(servername(url)): return
 
	if url.find("#")!=-1: url=url[:url.find("#")]
 
	# file extensions that need to be ignored code
	fileext=sre.sub(".*(http\://[^/]*/).*","\\1",url)
	if url==fileext: fileext="None"
	else: fileext=sre.sub("^.*\/[^/]*\.([^\&\#\?\/]*)[^/]*$","\\1",url)
	if ignorefileext.count(","+fileext+",")!=0: return
 
	try:
 
		sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
		sock.connect((servername(url,False),80))
 
		workurl=pagename(url)
		theurl=url
		if redir!=1: theurl=workurl
 
		qrytype="GET"
		if poststring!="": qrytype="POST"
		out=(qrytype+" "+theurl+" HTTP/1.1\n"
		     "Host: "+servername(url,False)+"\n"
		     "Connection: close\n")
		if usecookies:
			global cookies
			out+="Cookie: "+cookies+"\n"
		if poststring!="":
			out+="Content-Type: application/x-www-form-urlencoded\n"
			out+="Content-Length: "+str(len(poststring))
			out+="\n\n"+poststring+"\n"
		out+="\r\n\r\n"
		sock.send(out)
 
		# get response type and log the page
		response=sock.recv(12)[-3:]
		fp=open("logs/"+urllogfile,"a")
		fp.write(url+": "+response+" "+str(realpage)+"\n")
		if poststring!="": fp.write(indent+"POST: "+poststring+"\n")
		fp.close()
 
 
		# at 404 response, close connection and fail
		if response=="404" or response=="500":
			sock.close()
			return
 
		# at 30[1237] response types, recurse new page
		if sre.search("30[1237]",response):
			while 1:
				chunk=""
				byte=sock.recv(1)
				while byte!="\r":
					chunk+=byte
					byte=sock.recv(1)
				sock.recv(1)
				if chunk.lower()[:9]=="location:":
					location=chunk.lower()[9:].strip()
					if location=="http://"+servername(url,False)+url: location="/"
					locpage=fullpath(location,url)
					sock.close()
# 					if url[len(url)-2:]=="" and locpage[len(locpage)-4:]=="": break
					redir=1
					if locpage!=url:
						redir=0
						if pagename(sre.sub("\\\\(\"|\')","\\1",locpage))==pagename(url):
							print "QUOTE REDIR"
							return
					print "OLD:",url
					print "NEW:",chunk.lower()
					print "REDIR:",locpage
					return getpage(locpage,redir=redir,realpage=realpage)
			if realpage==1:
				sock.close()
				return
 
		elif realpage==1:
			sock.close()
			return url
 
		# get headers, ignoring certain HTTP headers
		headers=""
		type=0
		while 1:
			chunk=""
			byte=sock.recv(1)
			if byte=="\r":
				sock.recv(1)
				break
			while byte!="\r":
				chunk+=byte
				byte=sock.recv(1)
			sock.recv(1)
 
			if chunk.lower()[:11]!="set-cookie:" and chunk.lower()[:5]!="date:" and chunk.lower()[:15]!="content-length:" and chunk.lower()[:11]!="keep-alive:" and chunk.lower()[:18]!="transfer-encoding:" and chunk.lower()[:11]!="connection:":
				headers+=chunk
 
#			if chunk.lower()[:15]=="content-length:":
#				type=1
#				conlen=int(chunk[16:])
 
			if chunk.lower()[:26]=="transfer-encoding: chunked": type=2
 
		# no special type specified, just get the page
		if type==0:
			body=""
			while 1:
				chunk=sock.recv(200)
				body+=chunk
				if chunk=="": break
 
 
		# set it up if it does have a type
#		else:
#			byte=sock.recv(1)
#			if byte=="\r": sock.recv(1)
#			else:
#				while 1:
#					i=-1
#					while byte!="\r":
#						i+=1
#						byte=sock.recv(1)
#					nbytes=sock.recv(3)
#					if nbytes=="\n\r\n": break
 
#		# content-length
#		if type==1:
#			body=""
#			for i in range(conlen):
#				chunk=sock.recv(1)
#				body+=chunk
 
		# transfer-encoding: chunked
		if type==2:
			body=""
			chunksize=""
			while chunksize!=0:
				byte=""
				chunk=""
				while byte!="\r":
					chunk+=byte
					byte=sock.recv(1)
				sock.recv(1)
				chunksize=int(chunk,16)
				wchunksz=chunksize
				while wchunksz>=1:
					subchunk=sock.recv(wchunksz)
					body+=subchunk
					wchunksz-=len(subchunk)
				sock.recv(2)
 
		# clean up and return
		sock.close()
		if dheaders!=1: headers=""
 
		return [headers,body,urlfix(url)]
 
	# catch socket errors, such as "connection reset by peer" - trys again until it gives up and goes on to the next page
	except socket.error:
		print "Socket Error, Recursing..."
		return recurse(exceptions)
 
# function to remove everything in the "<head>" tag from a server response
def decapitate(body):
 
	if body==None: return
 
	global decapitation
	if decapitation==True: body=sre.sub("<head>(.+?)</head>","",body)
 
	return body
 
 
# function to generate a random identification string
def randident(thelen=randidentlen,randchars="Bghi3rj9uwEFabTGH1ImnL4xpCstUOvoPYk25qVJK8Z0Q67lWXefMRSDcdyzAN"):
# 	global randidentlen
	rndidnt=""
	while len(rndidnt)<thelen:
		random.seed(time.time())
		rand=random.random()
		rndidnt+=randchars[int(round(rand*(len(randchars)-1)))]
	return rndidnt
 
def randident_num(thelen=None):
	if not thelen:
		global randidentlen
		thelen=randidentlen
	return int(randident(thelen,"3490168257"))
 
# function to initiate a single exploit
def exploit(url,qry,namval,explt,post,poststring="",randstr=""):
 
	def removeexplt(body,explt):
 
		def removeit(body,explt): return body.replace(explt,"")
		remove=lambda:removeit(body,explt)
 
		try:
			explt=str(int(explt))
			body=sre.sub("(?<![0-9])"+explt+"(?![0-9])","",body)
 
		except ValueError:
 
			body=remove()
			explt=parsebody(explt)
			body=remove()
 
# 			if pagetype=="asp":
# 				explt=explt.replace("%2D","-")
# 				body=remove()
# 	
# 			explt=explt.replace("+"," ")
# 			body=remove()
# 	
# 			explt=explt.replace("%20"," ")
# 			body=remove()
# 	
# 			explt=explt.replace("%2b","+")
# 			body=remove()
 
# 		body=body.replace(explt.replace("+"," "),"")
# 			body=body.replace(explt.replace("%2D","-"),"")
# 			body=body.replace(explt.replace("+"," ").replace("%2D","-"),"")
		return body
 
	explt=str(explt)
	randstr=str(randstr)
 
	if randstr!="" and explt!=randstr: explt+=randstr # explt!=randstr possibly not needed
 
	expltqry=sre.sub(namval+"[^\&]*(?=\&|$)",namval+explt,qry)
	if not post: hab=getpage(url+expltqry,poststring=poststring)
	else: hab=getpage(url,poststring=expltqry)
	if listempty(hab): return
 
# 	headers=hab[0]
	body=hab[1]
 
	##### ? # sre for all this crap? #####
	if len(explt)>=4:
		body=removeexplt(body,explt)
		body=parsebody(body)
		body=removeexplt(body,explt)
	else: body=parsebody(body)
	if randstr!="": body=removeexplt(body,randstr)
 
	return body
 
# function to parse the body for checking agsinst others
def parsebody(body):
 
	global sessstr,pagetype
 
	body=body.replace("%2d","-")
	body=body.replace("%2D","-")
	body=body.replace("%25","%")
	body=body.replace("%20"," ")
	body=body.replace("+"," ")
	body=body.replace("%2b","+")
	body=body.replace("%2B","+")
	body=body.replace("%22","\"")
	body=body.replace("\\\"","\"")
	body=body.replace("\\'","'")
	body=body.replace("\n","")
	body=body.replace("\r","")
	body=sre.sub(sessstr,"",body)
 
	# These might cause problems
	body=sre.sub("\<script([^\>]*)\>(.*?)\</script\>","",body)
	body=sre.sub("\<!--(.*?)--\>","",body)
 
	if pagetype=="php":
		body=sre.sub("(?i)\<input type=\"hidden\" name=\"phpsessid\" value=\"([a-z0-9]{32})\"( /|)\>","",body)
	body=sre.sub(" alt=(\"|\')([^\\1\>]*)\\1","",body)
	body=removeurls(body)
 
	return body
 
# function to check a value for SQL Injection
def sqli_check(body,theurl,qry,namval,quot,post,poststring):
	if sqli_intcheck(body,theurl,qry,namval,post,poststring): return True
	if sqli_stringcheck(body,theurl,qry,namval,quot,post,poststring): return True
	return
 
# function to check an integer value for SQL Injection, this is a near 100% sure way to test integers for SQLI
def sqli_intcheck(body,theurl,qry,namval,post,poststring):
 
	name=namval[:namval.find("=")]
	rvalue=namval[namval.find("=")+1:]
	try: rvalue=int(rvalue)
	except ValueError: return # Not an integer, sorry :(
 
	while True:
		xtrm=randident_num(5)
		if rvalue!=xtrm: break
	bodyxtrm=exploit(theurl,qry,name+"=",xtrm,post,poststring,xtrm) # integer is random 5 characters, creating an "extreme" page to check against
 
	i_s=[0,4,6]
	i_s.sort()
	i_s.reverse()
	for i in i_s:
		if i==0:
			value=rvalue
			body=exploit(theurl,qry,name+"=",str(value-1)+"%2b1",post,poststring)
			if body!=bodyxtrm: break
			return
 
		value=randident_num(i)
		body=exploit(theurl,qry,name+"=",str(value-1)+"%2b1",post,poststring)
		if body!=bodyxtrm: break
 
	bodyplus=exploit(theurl,qry,name+"=",str(value-2)+"%2b2",post,poststring)
 
	filestuff("1",body,"w")
	filestuff("2",bodyplus,"w")
	filestuff("3",bodyxtrm,"w")
 
	# if the addition occurs and the extreme case is different, it's vulnerable
	if bodyplus==body and body!=bodyxtrm:
		print "INTEGER VULN:",theurl,namval
		return True
	return
 
# function to check a string value for SQL Injection, this is not as precise as the integer check, but it's still good
def sqli_stringcheck(body,theurl,qry,namval,quot,post,poststring):
	randstr=randident()
	bodyemp=exploit(theurl,qry,namval,quot+"+"+comnt,post,poststring)
	pbodyq=exploit(theurl,qry,namval,quot+"+"+comnt,post,poststring,randstr)
	if bodyemp!=pbodyq:
		randstr=""
		pbodyq=bodyemp
 
	firsttrue=True
	if body!=pbodyq:
		ordtest=pbodyq
		pbodyand=exploit(theurl,qry,namval,quot+"+and+1%3D1+"+comnt,post,poststring,randstr)
		if body!=pbodyand:
			ordtest=pbodyand
			pbodyord=exploit(theurl,qry,namval,quot+"+order+by+1+"+comnt,post,poststring,randstr)
			if body!=pbodyord:
				ordtest=pbodyord
				pbodynb=exploit(theurl,qry,namval,quot+"+and+"+quot+"1"+quot+"%3D"+quot+"1",post,poststring)
				if body!=pbodynb:
					firsttrue=False
	else:
		pbodyord=exploit(theurl,qry,namval,quot+"+order+by+1+"+comnt,post,poststring,randstr)
		if body!=pbodyord:
			ordtest=pbodyord
		else:
			pbodyand=exploit(theurl,qry,namval,quot+"+and+1%3D1+"+comnt,post,poststring,randstr)
			if body!=pbodyand:
				ordtest=pbodyand
			else:
				ordtest=body
 
 
	if firsttrue:
		nbodyrand=exploit(theurl,qry,namval,quot+"+"+randident(),post,poststring,randstr)
		if body!=nbodyrand and ordtest!=nbodyrand:
			nbodyq=exploit(theurl,qry,namval,"'\"",post,poststring,randstr)
			if body!=nbodyq and ordtest!=nbodyq:
				nbodyord=exploit(theurl,qry,namval,quot+"+order+by+999+"+comnt,post,poststring,randstr)
				if body!=nbodyord and ordtest!=nbodyord:
					print "STRING VULN:",theurl,namval
					return True
 
	return
 
#	nbodynb=exploit(theurl,qry,namval,quot+"+and+"+quot+"1"+quot+"%3D"+quot+"0",post,poststring)
#	if (body==pbodyq or body==pbodyand or body==pbodyord or body==pbodynb) and (body!=nbodyq and body!=nbodyord):
 
# function to fully exploit a url, and return the results
def fullxplt(worldbody,theurl,vars,qry,post,poststring=""):
 
	global pagetype,xssscan,sqliscan,checklevel
 
	sqlivulns=[]
	xssvulns=[]
	worldbody=decapitate(worldbody)
 
	for i in range(len(vars)):
 
		namval=vars[i]
		name=namval[:namval.find("=")]
# 		if name=="xss": return
		value=namval[namval.find("=")+1:]
 
		if pagetype=="php" and name.lower()=="phpsessid":
			continue
 
		# SQLI (SQL Injection) Vulnerability Checker
		if sqliscan:
			worldbody=parsebody(worldbody)
			if checklevel<=2:
				if sqli_intcheck(worldbody,theurl,qry,namval,post,poststring): sqlivulns.append(name)
			else:
				bodychk=decapitate(exploit(theurl,qry,namval,"'\"",post,poststring))
				if worldbody!=bodychk:
					if sqli_check(worldbody,theurl,qry,namval,"",post,poststring): sqlivulns.append(name)
					elif sqli_check(worldbody,theurl,qry,namval,"'",post,poststring): sqlivulns.append(name)
					elif sqli_check(worldbody,theurl,qry,namval,'"',post,poststring): sqlivulns.append(name)
 
		# XSS (Cross Site Scripting) Vulnerability Checker
		if xssscan:
 
			if checklevel<=2:
				try:
					value=int(value)
					xssplt=str(randident_num())
				except ValueError:
					if checklevel==1: continue
					xssplt=randident()
 
				xssplt+="<script>"
 
				if post==0: body=getpage(theurl+sre.sub(namval+"[^\&]*(?=\&|$)",namval+xssplt,qry),poststring=poststring)
				else: body=getpage(theurl,poststring=sre.sub(namval+"[^\&]*(?=\&|$)",namval+xssplt,qry))
				if not listempty(body):
					body=body[1]
					if body.count(xssplt)!=0:
						xssvulns.append(name)
						continue
 
 
			else:
				xssplt=randident()+"<d>"
				#xssplt=randident()+randident() # old method
				if post==0: body=getpage(theurl+sre.sub(namval+"[^\&]*(?=\&|$)",namval+xssplt,qry),poststring=poststring)
				else: body=getpage(theurl,poststring=sre.sub(namval+"[^\&]*(?=\&|$)",namval+xssplt,qry))
				if not listempty(body):
					body=body[1]
					if body.count(xssplt)!=0:
						xssvulns.append(name)
						continue
 
				xssplt=randident()+'"fg'
				if post==0: body=getpage(theurl+sre.sub(namval+"[^\&]*(?=\&|$)",namval+xssplt,qry),poststring=poststring)
				else: body=getpage(theurl,poststring=sre.sub(namval+"[^\&]*(?=\&|$)",namval+xssplt,qry))
				if not listempty(body):
					body=body[1]
					if body.count(xssplt)!=0:
						xssvulns.append(name)
						continue
 
	return [sqlivulns,xssvulns]
 
# function to prepare for fullxplt()
def checkvars(url,poststring=""):
 
	print "( __ )",url
 
	global pagetype,comnt
	post=0
	if poststring!="": post=1
	getvars=[]
	postvars=[]
 
	qloc=url.find("?")
	if qloc!=-1:
		theurl=url[:qloc]+"?"
		qry=url[qloc+1:].replace("&amp;","&")
		getvars=qry.split("&")
	elif post==0: return
 
	if post==1:
		postvars=poststring.split("&")
		hab=getpage(url,poststring)
	else: hab=getpage(url)
 
	print "PP"
 
	if listempty(hab): return
 
	getvars=uniqlist(getvars)
	postvars=uniqlist(postvars)
 
	worldbody=hab[1]
	getvulns=[]
	postvulns=[]
 
	print "QQ",getvars,postvars
 
	if not listempty(getvars): getvulns=fullxplt(worldbody,theurl,getvars,qry,0,poststring)
	if not listempty(postvars): postvulns=fullxplt(worldbody,url,postvars,poststring,1)
 
	print "ZAP!"
 
	if not listempty(getvulns): getvulns=[uniqlist(getvulns[0]),uniqlist(getvulns[1])]
	if not listempty(postvulns): postvulns=[uniqlist(postvulns[0]),uniqlist(postvulns[1])]
 
	return [hab[2],getvulns,postvulns]
 
# function to display the results of a single exploit, and record the results to the reportvar variable
def dispvulns(vulns,url):
 
	global indent,reportvar,vulnlogfile
 
	if url.find("?")!=-1: url=url[:url.find("?")]
	output=url+":"
 
	if not listempty(vulns):
 
		getvulns=vulns[1]
		postvulns=vulns[2]
 
		gvtest=not listempty(getvulns)
		if gvtest: gvtest=not listempty(getvulns[0]) or not listempty(getvulns[1])
 
		pvtest=not listempty(postvulns)
		if pvtest: pvtest=not listempty(postvulns[0]) or not listempty(postvulns[1])
 
		if gvtest or pvtest:
 
			output+="\n"
 
			if gvtest:
				getvulns[0].sort()
				getvulns[1].sort()
				output+=indent+"GET: "
				if not listempty(getvulns[0]):
					output+="SQLI - "+str(getvulns[0])
					if not listempty(getvulns[1]):
						output+=" | "
				if not listempty(getvulns[1]):
					output+="XSS - "+str(getvulns[1])
				output+="\n"
 
			if pvtest:
				postvulns[0].sort()
				postvulns[1].sort()
				output+=indent+"POST: "
				if not listempty(postvulns[0]):
					output+="SQLI - "+str(postvulns[0])
					if not listempty(postvulns[1]):
						output+=" | "
				if not listempty(postvulns[1]):
					output+="XSS - "+str(postvulns[1])
				output+="\n"
 
			output=output[:-1]
 
			# record results to the reportvar variable
			if reportvar.has_key(url):
				getlist=reportvar[url][0]
				if not listempty(getvulns):
					if listempty(getlist): getlist=getvulns
					else:
 
						if not listempty(getlist[0]):
							getlist[0][len(getlist[0]):len(getvulns[0])]=getvulns[0]
							getlist[0]=uniqlist(getlist[0])
						else: getlist[0]=getvulns[0]
 
						if not listempty(getlist[1]):
							getlist[1][len(getlist[1]):len(getvulns[1])]=getvulns[1]
							getlist[1]=uniqlist(getlist[1])
						else: getlist[1]=getvulns[1]
 
				postlist=reportvar[url][1]
				if not listempty(postvulns):
					if listempty(postlist): postlist=postvulns
					else:
 
						if not listempty(postlist[0]):
							postlist[0][len(postlist[0]):len(postvulns[0])]=postvulns[0]
							postlist[0]=uniqlist(postlist[0])
						else: postlist[0]=postvulns[0]
 
						if not listempty(postlist[1]):
							postlist[1][len(postlist[1]):len(postvulns[1])]=postvulns[1]
							postlist[1]=uniqlist(postlist[1])
						else: postlist[1]=postvulns[1]
			else:
				reportvar[url]=[getvulns,postvulns]
		else: return
	else: return
 
	filestuff("logs/"+vulnlogfile,output+"\n")
	print output
 
treeglob=1
 
# function to tree a site and initiate vulnerability checks on the pages found
def treepages(url,level):
 
	global treeglob,urlfields,postfields,treedurls,levels,server,vulnlogfile,scanlimit,ignorefileext
	print ">>>>>>>>",level,"<<<<<<<<"
 
	print " ---> "+url
 
	pageinfo=getpage(url)
	if listempty(pageinfo): return
 
	body=pageinfo[1].lower()
 
	print "AA"
 
	# select/option, textarea
	# check for forms
	bodyarr=sre.split("<form",body)
	for i in range(len(bodyarr)):
 
		frmsect=bodyarr[i][:bodyarr[i].find(">")]
		frmbody=bodyarr[i][bodyarr[i].find(">"):][:bodyarr[i].find("</form>")]
 
		actionurl=getattrval(frmsect,"action")
		if actionurl=="" or actionurl==frmsect or actionurl=="\"\"": actionurl=pageinfo[2]
		if actionurl.count(";")>0: actionurl=actionurl[actionurl.find(";")+1:]
		if actionurl[:11].lower()=="javascript:": continue
		actionurl=fullpath(actionurl,pageinfo[2])
 
		print "ACTION:",actionurl
 
		# get the input variables
		poststring=""
		inputarr=sre.sub("(.*?)\<input([^\>]*)\>(.*?)","\\2|ZZaaXXaaZZ|",frmbody).split("|ZZaaXXaaZZ|")
		for j in range(len(inputarr)):
 
			name=getattrval(inputarr[j],"name")
			if name==inputarr[j] or name=="" or name=="\"\"": continue
 
			value=getattrval(inputarr[j],"value")
			if value==inputarr[j] or value=="" or value=="\"\"": value=""
 
			if poststring!="": poststring+="&"
			poststring+=name+"="+value
 
		# get select/option tags
		selectarr=sre.sub("(.*?)\<select([^\>]*)\>(.*?)","\\2|ZZaaXXaaZZ|",frmbody).split("|ZZaaXXaaZZ|")
		for j in range(len(selectarr)):
 
			name=getattrval(selectarr[j],"name")
			if name==selectarr[j] or name=="" or name=="\"\"": continue
 
			value=sre.sub("(.*?)\<option([^\>]*)value=(\"|'|)([^\\3\ ]*)\\3([^\>]*)\>(.*?)","\\2",selectarr[j])
			if value==selectarr[j] or value=="" or value=="\"\"": value=""
 
			if poststring!="": poststring+="&"
			poststring+=name+"="+value
			print "sel/opt: "+name+"="+value
 
		if poststring=="": continue
 
		if sre.search("method=([\'\"]|)post([\'\"]|)",frmsect[:frmsect.find(">")].lower())==None:
			if actionurl.find("?")!=-1: actionurl+="&"
			else: actionurl+="?"
			actionurl+=poststring
			body+='<a href="'+actionurl+'">'
			print 'GETT <a href="'+actionurl+'">'
			continue
 
		# determine if it needs to be scanned, and if so, scan it
		postscan=0
		postvars=poststring.split("&")
		if postfields.has_key(actionurl):
			for j in range(len(postvars)):
				postvars[j]=postvars[j][:postvars[j].find("=")]
				if postfields[actionurl].count(postvars[j])==0:
					postfields[actionurl].append(postvars[j])
					postscan=1
		else:
			for j in range(len(postvars)): postvars[j]=postvars[j][:postvars[j].find("=")]
			postfields[actionurl]=postvars
			postscan=1
 
		if postscan==1:
			vulns=checkvars(actionurl,poststring)
			if not listempty(vulns): dispvulns(vulns,actionurl)
 
	print "BB"
 
	# check for urls in "href" tags
	# ? # part of 3? (src|href|location|window.open)= and http://
	urlreg="(\'|\")(?!javascript:)(([^\>]+?)(?!\.("+ignorefileext.replace(",","|")+"))(.{3,8}?)(|\?([^\>]+?)))"
	urlarr=sre.sub("(?s)(?i)(.+?)((src|href)=|location([\ ]*)=([\ ]*)|window\.open\()"+urlreg+"\\6","\\7|ZZaaXXaaZZ|",body).split("|ZZaaXXaaZZ|")
	del urlarr[len(urlarr)-1]
	urlarr.append(sre.sub("(?s)(?i)(.+?)(src|href)="+urlreg+"\\3","\\4|ZZaaXXaaZZ|",body).split("|ZZaaXXaaZZ|"))
	del urlarr[len(urlarr)-1]
	for i in range(len(urlarr)):
 
		theurl=fullpath(urlarr[i],pageinfo[2])
		if not checkserver(servername(theurl)): continue
 
		# determine if it needs scanned and/or treed, and if so, scan and/or tree it
		getscan=0
		if theurl.count("?")!=0:
			nqurl=theurl[:theurl.find("?")]
			query=theurl[theurl.find("?")+1:]
			query=sre.sub("\&amp\;","\&",query)
			qryvars=query.split("&")
			if urlfields.has_key(nqurl):
				for j in range(len(qryvars)):
					qryvars[j]=qryvars[j][:qryvars[j].find("=")]
					if urlfields[nqurl].count(qryvars[j])==0:
						urlfields[nqurl].append(qryvars[j])
						getscan=1
			else:
				for j in range(len(qryvars)): qryvars[j]=qryvars[j][:qryvars[j].find("=")]
				urlfields[nqurl]=qryvars
				getscan=1
		else:
			if urlfields.has_key(theurl)==False: urlfields[theurl]=[]
			nqurl=theurl
 
		if getscan==1:
			vulns=checkvars(theurl)
			if not listempty(vulns): dispvulns(vulns,theurl)
		tree=treeglob
		if treedurls.has_key(nqurl):
			if treedurls[nqurl].count(theurl)==0 and len(treedurls[nqurl])<=scanlimit:
				treedurls[nqurl].append(theurl)
			else: tree=0
 
		else: treedurls[nqurl]=[theurl]
		if tree==1 and level<levels:
			realurl=getpage(theurl,realpage=1)
			if theurl!=realurl and realurl!=None:
				body+=' href="'+realurl+'" '
			print "treeee"
			try: treepages(theurl,level+1)
			except KeyboardInterrupt:
				treeglob=0
				print "TREEGLOB CHANGED TO ZERO"
				treepages(theurl,level+1)
 
 
## end function declaration ##
 
## initialize the script ##
 
# setup
# server=servername(site)
starttime=time.time()
treedurls[site]=[site]
 
# url="http://www.omnipen.net/vuln.php?id=2&xss=1"
# domains=[".omnipen.net"]
# usecookies=False
#http://client.gamecenter.com/pages/gamespace/story.php?sid=6127385&pid=199212"
# exit()
# url="http://blogs.bnet.com/smallbusiness/index.php?p=21?tag=bnet.blogdoor" # diff tests
# url="http://blogs.bnet.com/"
#url="http://www.mp3.com/games/soundtrack.php?game_id=68" # NO
#url="http://www.mp3.com/faq/terms.php?tag=mp3.ft.no" # NO
#url="http://www.gamespot.com/cgi/gumclik.html?id=11917&s=6117511&p=5" # SQLI - id
#url="http://forums.gamespot.com/gamespot/report_abuse.php?message_id=202371898&topic_id=19054979&board_id=909100112" # SQLI - all 3
# print checkvars(url,"")
# print getpage(url)
# print treepages(url,0)
# print "FINAL QUIT"
# exit()
 
# initiate treeing, and handle keyboard interrupts
if debug: treepages(site,0)
else:
	try: treepages(site,0)
	except KeyboardInterrupt: print "\nKeyboard Interrupt, exiting..."
 
## end initialization ##
 
 
# get time elapsed, write it, and print it
 
endtime=time.time()
timeelapsed=endtime-starttime
timeout="Time Elapsed: "+str(timeelapsed)+" Seconds\n"
 
filestuff("logs/"+vulnlogfile,"\n"+timeout+"\n")
 
print timeout
 
 
## write report ##
 
urls=reportvar.keys()
urls.sort()
if not listempty(urls):
 
	fp=open("logs/"+reportfile,"w")
 
	for i in range(len(urls)):
 
		fp.write(urls[i]+":\n")
		reporturl=reportvar[urls[i]]
		if not listempty(reporturl):
 
			if not listempty(reporturl[0]):
				if not listempty(reporturl[0][0]) or not listempty(reporturl[0][1]):
					reporturl[0][0].sort()
					reporturl[0][1].sort()
 
					fp.write(indent+"GET: ")
					if not listempty(reporturl[0][0]):
						fp.write("SQLI - "+str(reporturl[0][0]))
						if not listempty(reporturl[0][1]):
							fp.write(" | ")
					if not listempty(reporturl[0][1]):
						fp.write("XSS - "+str(reporturl[0][1]))
					fp.write("\n")
 
			if not listempty(reporturl[1]):
				if not listempty(reporturl[1][0]) or not listempty(reporturl[1][1]):
					reporturl[1][0].sort()
					reporturl[1][1].sort()
 
					fp.write(indent+"POST: ")
					if not listempty(reporturl[1][0]):
						fp.write("SQLI - "+str(reporturl[1][0]))
						if not listempty(reporturl[1][1]):
							fp.write(" | ")
					if not listempty(reporturl[1][1]):
						fp.write("XSS - "+str(reporturl[1][1]))
					fp.write("\n")
 
 
			fp.write("\n")
 
	fp.write("\n"+timeout+"\n")
 
	fp.close()
 
print "Report Written: "+reportfile
 
## end write report ##
 
### END ###
 

Back