#!/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 = {}
"""
C:\server\jsl-0.3.0\jsl.exe
C:\server\jsl-0.3.0\jsl.grabber.conf
js
"""
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: 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: 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("\n")
plop.write("\n")
for file in jsDatabase:
plop.write("\t\n" % file)
for line in jsDatabase[file]:
if len(jsDatabase[file][line]) > 1:
plop.write("\t\t\n" % line)
for error in jsDatabase[file][line]:
plop.write("\t\t\t%s\n" % htmlencode(error))
plop.write("\t\t\n")
else:
plop.write("\t\t%s\n" % (line, htmlencode(jsDatabase[file][line][0])))
plop.write("\t\n")
plop.write("\n")
plop.write("\n")
plop.close()