#!/usr/bin/env python import re import os import sys from zenmapCore.Paths import Path from zenmapCore.UmitLogging import log NMAPDATADIR = Path.nmap_dir def get_prefix(): """ returns the prefix at which nmap files are located """ prefix = os.getenv("NMAPDIR") if(prefix): # search in environmental variable NMAPDIR return prefix if sys.platform not in "win32": #UNIX based system search in user directories USERDIR = os.path.expanduser('~/.nmap') if os.path.isdir(USERDIR): if "scripts" in os.listdir(USERDIR) and "nselib" in os.listdir(USERDIR): return USERDIR if(NMAPDATADIR): if os.path.isdir(os.path.join(NMAPDATADIR,"scripts")) and os.path.isdir(os.path.join(NMAPDATADIR,"nselib")): return NMAPDATADIR pwd = os.getcwd() if "scripts" in os.listdir(pwd) and "nselib" in os.listdir(pwd): return pwd else: raise LocationError() def get_script_path(): """ Returns the path to script.db file""" prefix = get_prefix(); return os.path.join(prefix,"scripts","script.db"); def get_script_dir(): """ Return the path to script directory """ prefix = get_prefix(); return os.path.join(prefix,"scripts"); def get_nselib_path(): """ Return the path to nselib""" prefix = get_prefix(); return os.path.join(prefix,"nselib") class metadata_entry: def __init__(self): self.Filename="" self.Categories =[] self.License ="" self.Author ="" self.NSEDocURL = "" self.Description = "" self.Arguments = [] #arguments including library arguments self.ScriptArguments = [] self.Argsdescription = {} self.Output = "" self.Usage = "" class scriptdb: def __init__(self): self.entries_list = [] self.construct_list() def check_syntax_entry(self,line): """ Checks the syntax error found in each entry""" entryexpr = re.compile("Entry {(.)*}") nameexpr = re.compile("filename = [\"\-a-zA-Z0-9\.]*.nse") categoryexpr = re.compile("categories = {[a-zA-Z\"\, ]*}") if entryexpr.search(line)and nameexpr.search(line) and categoryexpr.search(line): return True def construct_list(self): """ constructs list of dictioanories""" try: path = get_script_path() f = open(path,'r') # hardcoded for line in f.readlines(): if self.check_syntax_entry(line): here_entry = self.parse_entry(line) self.entries_list.append(here_entry) # adds the dictionary to list elif not self.check_syntax_entry(line): raise CorruptedFile() except CorruptedFile: log.warning("The script.db database could not be parsed.") self.entries_list = [] # clear already added entries except LocationError: log.warning("script.db cannot be found. Set the NMAPDIR environment variable.") def parse_entry(self,line): """ parses a line passed and stores the key:value pair in Dictionary and return the dictionary""" entry = {} copy_line = line[:] copy_line = copy_line.lstrip('Entry') copy_line = copy_line.lstrip('{ ') copy_line = copy_line.rstrip('}') copy_line = copy_line.replace(' ','') copy_line = copy_line.replace('"','') first,second,third = copy_line.partition('=') # first contains "filename",second containd "=" # third contains remaining part first1,second1,third1 = third.partition(',') #partition the third part to obtain filename #first1 contain ,second1 contains "," #third1 contains Remaining part entry[first] = first1 # stores the filename in dictioanry filename = first1 third1 = third1.replace("{",'') third1 = third1.replace("}",'') first2,second2,third2 = third1.partition('=') third3 = third2.split(',') third3.pop() entry[first2] = third3 # stores category list in dictionary return entry def get_entries_list(self): return self.entries_list class scriptmetadata: def __init__(self): self.library_arguments = {} self.construct_library_arguments() self.URLprefix = "http://nmap.org/nsedoc/scripts/" def construct_library_arguments(self): """ Constructs Dictionary of library arguments using library names as keys""" try: path = get_nselib_path() args_expr = re.compile("@args[ ]*[0-9a-zA-Z\-._]*") for files in os.listdir(path): filepath = os.path.join(path,files) files = files.replace(".luadoc","") files = files.replace(".lua","") files = files.strip() file_arg_list =[] if os.path.isfile(filepath): libfile = open(filepath,"r") for line in libfile.readlines(): grp_argument = args_expr.search(line) if grp_argument is not None: argument = grp_argument.group(); argument = argument.lstrip("@args") argument = argument.strip() file_arg_list.append(argument) #print files,file_arg_list self.library_arguments[files]=file_arg_list except LocationError: print "NSElib folder cannot be located. Try setting NMAPDIR Variable" def get_file_contents(self,filename): """ Returns the file contents""" path = get_script_dir() if filename.rfind(".nse")!= -1: abs_filename = filename else: abs_filename = filename + ".nse" filepath = os.path.join(path,abs_filename) script_file = open(filepath,"r") contents = script_file.read() return contents def get_description(self,filename): """ get description of script on passing script filename""" contents = self.get_file_contents(filename) start = contents.index('[[') end = contents.index(']]') desc = contents[start+2:end] if desc is None: return "No Description found" else: return desc def get_author(self,filename): contents = self.get_file_contents(filename) author_expr = re.compile("author = [\"|\'][0-9a-zA-Z ,.<>@\:\-/\'\[\]()]*[\"|\']") grp_author = author_expr.search(contents) if grp_author is None: start = contents.index('author = [[') author = "[[" for i in contents[start+10:]: if i != ']': author = author + i else: break author = author.lstrip('[') else: author = grp_author.group() author = author.lstrip("author = ") author = author.replace('"',"") author = author.replace("'","") return author def get_license(self,filename): contents = self.get_file_contents(filename) license_expr = re.compile("license[ ]*=[ ]*[\"|\'][a-zA-Z0-9 /:.\-]*[\"|\']") grp_license = license_expr.search(contents) if grp_license is None: license_str = '[' start = contents.index('license =') for i in contents[start+10:]: if i!=']': license_str = license_str + i else: break license_str=license_str.lstrip('[') else: license_str = grp_license.group() license_str = license_str.lstrip("license =") license_str = license_str.replace('"',"") license_str = license_str.replace("'","") return license_str def get_arguments(self,filename): """ Returns list of arguments on passing the file name""" argument_list = [] scriptargs = [] path = get_script_dir() if filename.rfind(".nse")!= -1: abs_filename = filename else: abs_filename = filename + ".nse" filepath = os.path.join(path,abs_filename) script_file = open(filepath,"r") args_expr = re.compile("@args[ ]*[0-9a-zA-Z\-._]*") require_expr = re.compile("require[ ]*[\(]*[\'|\"|][a-zA-Z0-9\-]*[\'|\"][\)]*") for line in script_file.readlines(): grp_args = args_expr.search(line) grp_require = require_expr.search(line) if grp_args is not None: argument = grp_args.group() argument = argument.lstrip('@args') argument = argument.strip() argument_list.append(argument) scriptargs.append(argument) if grp_require is not None: require = grp_require.group() require = require.lstrip("require") require = require.replace("'","") require = require.replace('"',"") require = require.replace('(',"") require = require.replace(')',"") require = require.strip() if self.library_arguments.has_key(require): argument_list = argument_list + self.library_arguments[require] return argument_list,scriptargs def get_output(self,filename): """ This function returns the contents present at @output section """ output = "" lineno = 0 count = 0 path = get_script_dir() if filename.rfind(".nse")!= -1: abs_filename = filename else: abs_filename = filename + ".nse" filepath = os.path.join(path,abs_filename) script_file = open(filepath,"r") outputexpr = re.compile("@output") nextline = re.compile("--[ ]*(.)+") for line in script_file.readlines(): grp_output = outputexpr.search(line) lineno = lineno + 1 if grp_output: break script_file.seek(0) for line in script_file.readlines(): if count < lineno-1: count = count + 1 continue grp_nextline = nextline.match(line) if grp_nextline: outputline = grp_nextline.group(0) if (outputline.find("@usage") == -1) and (outputline.find("@args") == -1): output = output + outputline output = output + "\n" else: break else: break return output def get_usage(self,filename): """ This function returns the contents present in @usage section""" usage = "" lineno = 0 count = 0 path = get_script_dir() if filename.rfind(".nse")!= -1: abs_filename = filename else: abs_filename = filename + ".nse" filepath = os.path.join(path,abs_filename) script_file = open(filepath,"r") usageexpr = re.compile("@usage") nextline = re.compile("--[ ]*(.)+") for line in script_file.readlines(): grp_usage = usageexpr.search(line) lineno = lineno + 1 if grp_usage: break script_file.seek(0) for line in script_file.readlines(): if count < lineno-1: count = count + 1 continue grp_nextline = nextline.match(line) if grp_nextline: usageline = grp_nextline.group(0) if (usageline.find("@output") == -1) and (usageline.find("@args") == -1): usage = usage + usageline usage = usage + "\n" else: break else: break return usage def get_args_description(self,entry): """ This method returns the description text present in @args section""" filename = entry.Filename argsdescription = {} scriptargs = entry.ScriptArguments anycharexpr = re.compile("[a-zA-Z0-9]") path = get_script_dir() if filename.rfind(".nse")!= -1: abs_filename = filename else: abs_filename = filename + ".nse" filepath = os.path.join(path,abs_filename) script_file = open(filepath,"r") if(len(scriptargs) == 0): return None for arg in scriptargs: if arg=="": return None description = "" argfound = 0 script_file.seek(0) for line in script_file.readlines(): if(line.find(arg) != -1) and (line.find("@args") != -1) and (argfound == 0): argfound = 1 description = description + line else: if(argfound == 1): if anycharexpr.search(line) and (line.find("@output") == -1) and (line.find("@usage") == -1) and (line.find("@args") == -1): description = description + line else: break description = description.replace("\n","") description = description.replace("--","") description = description.replace("@args","") description = description.replace(arg,"") argsdescription[arg] = description return argsdescription def get_URL(self,filename): """ Returns the NSEDoc URL """ URL = self.URLprefix + filename + ".html" return URL class CorruptedFile(Exception):pass class LocationError(Exception):pass def get_script_entry(): metadata_list=[] #list of script-entry objects sdb = scriptdb() smetadata = scriptmetadata() file_list = sdb.get_entries_list() for dbentry in file_list: entry = metadata_entry() entry.Filename = dbentry["filename"] entry.Categories = entry.Categories + dbentry["categories"] entry.License = smetadata.get_license(entry.Filename) entry.Author = smetadata.get_author(entry.Filename) entry.NSEDocURL = smetadata.get_URL(entry.Filename) entry.Description = smetadata.get_description(entry.Filename) entry.Arguments,entry.ScriptArguments = smetadata.get_arguments(entry.Filename) entry.Output = smetadata.get_output(entry.Filename) entry.Usage = smetadata.get_usage(entry.Filename) entry.Argsdescription = smetadata.get_args_description(entry) metadata_list.append(entry) return metadata_list def get_script_entries(): script_entries =[] metadata_list = get_script_entry() for entry in metadata_list: script_entries.append(entry) return script_entries if __name__ == '__main__': for entry in get_script_entry(): print "*" * 75 print "Filename:",entry.Filename print "Argument Description:", entry.Argsdescription print "Categories:",entry.Categories print "License:",entry.License print "Author:",entry.Author print "URL:",entry.NSEDocURL print "Description:",entry.Description print "\n",entry.Arguments print "\n",entry.ScriptArguments print "Output :\n",entry.Output print "Usage :\n" ,entry.Usage print "*" * 75