/src/pentest/grabber/javascript.py
Python | 182 lines | 168 code | 3 blank | 11 comment | 1 complexity | 8140ae72c78b80e62cddbc4650f473e8 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, MPL-2.0-no-copyleft-exception, GPL-2.0, GPL-3.0
- #!/usr/bin/env python
- """
- Simple JavaScript Checker Module for Grabber v0.1
- Copyright (C) 2006 - Romain Gaucher - http://rgaucher.info
-
- - Look at the JavaScript Source...
-
- """
- import sys, re, os
- from spider import htmlencode
- from xml.sax import * # Need PyXML [http://pyxml.sourceforge.net/]
-
- # JavaScript Configuration variables
- jsAnalyzerBin= None
- jsAnalyzerInputParam = None
- jsAnalyzerOutputParam = None
- jsAnalyzerConfParam = None
- jsAnalyzerConfFile= None
- jsAnalyzerExtension = None
- jsAnalyzerPattern = None
-
- # { 'FILENAME' : { 'line' : ['error 1', 'error 2'] } }
- jsDatabase = {}
-
- """
- <?xml version="1.0"?>
- <!-- JavaScript Source Code Analyzer configuration file -->
- <javascript version="0.1">
- <!--
- Analyzer information, here JavaScript Lint by Matthias Miller
- http://www.JavaScriptLint.com
- -->
- <analyzer>
- <path input="-process" output="">C:\server\jsl-0.3.0\jsl.exe</path>
- <configuration param="-conf">C:\server\jsl-0.3.0\jsl.grabber.conf</configuration>
- <extension>js</extension>
- </analyzer>
- </javascript>
- """
-
- def normalize_whitespace(text):
- return ' '.join(text.split())
-
- def clear_whitespace(text):
- return text.replace(' ','')
-
- # Handle the XML file with a SAX Parser
- class JavaScriptConfHandler(ContentHandler):
- def __init__(self):
- self.inAnalyzer = False
- self.string = ""
-
- def startElement(self, name, attrs):
- global jsAnalyzerInputParam, jsAnalyzerOutputParam, jsAnalyzerConfParam
- self.string = ""
- self.currentKeys = []
- if name == 'analyzer':
- self.inAnalyzer = True
- elif name == 'path' and self.inAnalyzer:
- # store the attributes input and output
- if 'input' in attrs.keys() and 'output' in attrs.keys():
- jsAnalyzerInputParam = attrs.getValue('input')
- jsAnalyzerOutputParam = attrs.getValue('output')
- else:
- raise KeyError("JavaScriptXMLConf: <path> needs 'input' and 'output' attributes")
- elif name == 'configuration' and self.inAnalyzer:
- # store the attribute 'param'
- if 'param' in attrs.keys():
- jsAnalyzerConfParam = attrs.getValue('param')
- else:
- raise KeyError("JavaScriptXMLConf: <configuration> needs 'param' attribute")
-
- def characters(self, ch):
- self.string = self.string + ch
-
- def endElement(self, name):
- global jsAnalyzerBin, jsAnalyzerConfFile, jsAnalyzerExtension,jsAnalyzerPattern
- if name == 'configuration':
- jsAnalyzerConfFile = normalize_whitespace(self.string)
- elif name == 'extension' and self.inAnalyzer:
- jsAnalyzerExtension = normalize_whitespace(self.string)
- elif name == 'path' and self.inAnalyzer:
- jsAnalyzerBin = normalize_whitespace(self.string)
- elif name == "analyzer":
- self.inAnalyzer = False
- elif name == "pattern":
- jsAnalyzerPattern = normalize_whitespace(self.string)
-
- def execCmd(program, args):
- buff = []
- p = os.popen(program + " " + args)
- buff = p.readlines()
- p.close()
- return buff
-
-
- def generateListOfFiles(localDB, urlGlobal):
- global jsDatabase
- """
- Create a ghost in ./local/crystal/current and /local/crystal/analyzed
- And run the SwA tool
- """
- regScripts = re.compile(r'(.*).' + jsAnalyzerExtension + '$', re.I)
- # escape () and []
- localRegOutput = jsAnalyzerPattern
- localRegOutput = localRegOutput.replace('(', '\(')
- localRegOutput = localRegOutput.replace(')', '\)')
- localRegOutput = localRegOutput.replace('[', '\[')
- localRegOutput = localRegOutput.replace(']', '\]')
- localRegOutput = localRegOutput.replace(':', '\:')
- localRegOutput = localRegOutput.replace('__LINE__', '(\d+)')
- localRegOutput = localRegOutput.replace('__FILENAME__', '(.+)')
- localRegOutput = localRegOutput.replace('__ERROR__', '(.+)')
- regOutput = re.compile('^'+localRegOutput+'$', re.I)
-
- print "Running the static analysis tool..."
- for file in localDB:
- print file
- file = file.replace(urlGlobal + '/', '')
- fileIn = os.path.abspath(os.path.join('./local', file))
- cmdLine = jsAnalyzerConfParam + " " +jsAnalyzerConfFile + " " + jsAnalyzerInputParam + " " + fileIn
- if jsAnalyzerOutputParam != "":
- cmdLine += " " + jsAnalyzerOutputParam + " " + fileIn+'.jslint'
- output = execCmd(jsAnalyzerBin, cmdLine)
- # Analyze the output
- for o in output:
- lO = o.replace('\n','')
- if regOutput.match(lO):
- out = regOutput.search(lO)
- if file not in jsDatabase:
- jsDatabase[file] = {}
- line = clear_whitespace(out.group(2))
- if line not in jsDatabase[file]:
- jsDatabase[file][line] = []
- jsDatabase[file][line].append(normalize_whitespace(out.group(3)))
- # sort the dictionary
- # + file
- # + lines
-
-
- def process(urlGlobal, localDB, attack_list):
- """
- Crystal Module entry point
- """
- print "JavaScript Module Start"
- try:
- f = open("javascript.conf.xml", 'r')
- f.close()
- except IOError:
- print "The javascript module needs the 'javascript.conf.xml' configuration file."
- sys.exit(1)
- parser = make_parser()
- js_handler = JavaScriptConfHandler()
- # Tell the parser to use our handler
- parser.setContentHandler(js_handler)
- try:
- parser.parse("javascript.conf.xml")
- except KeyError, e:
- print e
- sys.exit(1)
-
- # only a white box testing...
- generateListOfFiles(localDB,urlGlobal)
- # create the report
- plop = open('results/javascript_Grabber.xml','w')
- plop.write("<javascript>\n")
- plop.write("<site>\n")
- for file in jsDatabase:
- plop.write("\t<file name='%s'>\n" % file)
- for line in jsDatabase[file]:
- if len(jsDatabase[file][line]) > 1:
- plop.write("\t\t<line number='%s'>\n" % line)
- for error in jsDatabase[file][line]:
- plop.write("\t\t\t<error>%s</error>\n" % htmlencode(error))
- plop.write("\t\t</line>\n")
- else:
- plop.write("\t\t<line number='%s'>%s</line>\n" % (line, htmlencode(jsDatabase[file][line][0])))
- plop.write("\t</file>\n")
- plop.write("</site>\n")
- plop.write("</javascript>\n")
- plop.close()
-