# nvd.py -- simplistic NVD parser # Copyright (C) 2005 Florian Weimer # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """This module parses the XML files provided by the National Vulnerability Database (NVD) """ import xml.sax import xml.sax.handler class _Parser(xml.sax.handler.ContentHandler): """Parser helper class.""" def __init__(self): self.result = [] self.start_dispatcher = {} for x in ('entry', 'local', 'network', 'local_network', 'user_init', 'avail', 'conf', 'int', 'sec_prot'): self.start_dispatcher[x] = getattr(self, 'TAG_' + x) self.path = [] def _noop(*args): pass def startElement(self, name, attrs): self.path.append((name, attrs)) self.start_dispatcher.get(name, self._noop)(name, attrs) def TAG_entry(self, name, attrs): self.name = attrs['name'].encode('utf-8') self.published = attrs['published'].encode('utf-8') self.severity = attrs.get('severity', u'').encode('utf-8') self.discovered = attrs.get('discovered', u'').encode('utf-8') self.cve_desc = "" self.range_local = self.range_remote = self.range_user_init = 0 self.loss_avail = self.loss_conf = self.loss_int \ = self.loss_sec_prot_user = self.loss_sec_prot_admin \ = self.loss_sec_prot_other = 0 def TAG_local(self, name, attrs): self.range_local = 1 def TAG_network(self, name, attrs): self.range_remote = 1 def TAG_local_network(self, name, attrs): self.range_remote = 1 def TAG_user_init(self, name, attrs): self.range_user_init = 1 def TAG_avail(self, name, attrs): self.loss_avail = 1 def TAG_conf(self, name, attrs): self.loss_conf = 1 def TAG_int(self, name, attrs): self.loss_int = 1 def TAG_sec_prot(self, name, attrs): if 'user' in attrs: self.loss_sec_prot_user = 1 if 'admin' in attrs: self.loss_sec_prot_admin = 1 if 'other' in attrs: self.loss_sec_prot_other = 1 def endElement(self, name): if name == 'entry': self.result.append((self.name, self.cve_desc, self.discovered, self.published, self.severity, self.range_local, self.range_remote, self.range_user_init, self.loss_avail, self.loss_conf, self.loss_int, self.loss_sec_prot_user, self.loss_sec_prot_admin, self.loss_sec_prot_other)) del self.path[-1] def characters(self, content): (name, attrs) = self.path[-1] if name == 'descript' and attrs['source'] == 'cve': self.cve_desc += content def parse(file): """Parses the indicated file object. Returns a list of tuples, containing the following elements: - CVE name - discovery data (can be empty) - publication date - severity (can be empty) - local range flag - remote range flag - availability loss type flag - confidentiality loss type flag - integrity loss type flag - security protection (user) loss type flag - security protection (admin) loss type flag - security protection (other) loss type flag """ parser = xml.sax.make_parser() parser.setFeature(xml.sax.handler.feature_namespaces, 0) p = _Parser() parser.setContentHandler(p) parser.parse(file) return p.result if __name__ == "__main__": import sys for name in sys.argv[1:]: parse(file(name))