Reads the Microsoft Baseline Security Analyzer 1.2.1 XML output and sends it to standard output in a readable text format.
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 | """
mbsa2txt.py
-- Reads the Microsoft Baseline Security Analyzer 1.2.1
XML output and sends it to standard output in a readable
text format.
-- Usage: python mbsa2txt.py mbsaScanFile.xml
Copyright (C) 2004
Shannon Eric Peevey
President, EriKin Corporation
speeves@erikin.com
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
import sys
import string
from xml.dom import minidom
file = sys.argv[1]
mbsa = minidom.parse(file)
def getSecscan(mbsa):
"""
Sets the first element, 'SecScan', to a variable 'secscan',
prints out the header of the file with
printSecScanAttributes(), and calls getCheck().
"""
secscan = mbsa.firstChild
secscanLength = len(secscan.childNodes)
#print secscanLength
printSecScanAttributes(secscan)
getCheck(secscan, secscanLength)
def getCheck(secscan, secscanLength):
"""
Sets the element, 'Check', to a variable 'check',
loops through the 'check'-list ;) , prints the
section header for each test with printCheckAttributes()
and calls getAdvice().
This element is a sibling to the 'IPList' element
and contains all of the elements we need to access
for the report.
"""
checkx = 3 # loop iterator
check = secscan.childNodes[checkx]
checkLength = len(check.childNodes)
checknumber = 1
while checkx < (secscanLength - 2):
printCheckAttributes(check, checknumber)
getAdvice(check)
if checkLength == 5:
getDetail(check)
checkx += 2
checknumber += 1
#print checkx
check = secscan.childNodes[checkx]
checkLength = len(check.childNodes)
def getAdvice(check):
"""
Prints the text from the 'Advice' element
under the header
"""
# check.childNodes[1] <Advice>
advice = check.childNodes[1]
adviceText = advice.childNodes[0]
#printCheckAttr(check[y])
print " - " + adviceText.data + "\n"
def getDetail(check):
"""
Sets the variable 'detail' equal to the 'Detail'
element, grabs the length of the list in 'detail'
and calls getHeadRow().
"""
# check.childNodes[3] <Detail>
detail = check.childNodes[3]
detailLength = len(detail.childNodes)
#print detailLength
getHeadRow(detail, detailLength)
def getHeadRow(detail, detailLength):
"""
Sets the variable 'headrow' equal to the 'Head'
or 'Row' elements. (Which are siblings under
'Detail'), grabs the length of the list in 'headrow',
and loops through the list. While looping through
'headrow', it calls gradeText() and getCol().
"""
# check.childNodes[checkx}.childNodes[detailx] <Head> and <Row>
headrowx = 1 # loop iterator
headrow = detail.childNodes[headrowx]
headrowLength = len(headrow.childNodes)
#print "detailLength = " + str(detailLength)
#print "headrowLength = " + str(headrowLength)
while headrowx <= (detailLength - 2):
gradeText = setGrade(headrow)
getCol(headrow, headrowLength, gradeText, headrowx)
headrowx = headrowx + 2
#print "headrowx = " + str(headrowx)
if headrowx <= (detailLength - 2):
headrow = detail.childNodes[headrowx]
headrowLength = len(headrow.childNodes)
print "\n"
def getCol(headrow, headrowLength, gradeText, headrowx):
"""
Sets the variable 'col' equal to the 'Col' elements
and prints out the values for each column.
"""
colx = 1 # loop iterator
col = headrow.childNodes[colx]
x = ""
while colx < headrowLength:
colText = col.childNodes[0]
if colx == 1:
#x = colText.data
if gradeText != "":
x = " -- " + gradeText + " | " + colText.data
elif gradeText == "" and headrowx == 1:
x = " -- Test Result " + "\t" + " | " + colText.data
else:
x = " -- " + "\t"*2 + " | " + colText.data
else:
x = x + " | " + colText.data
#print colx
colx += 2
if colx < headrowLength:
col = headrow.childNodes[colx]
if x != "":
print x
def printSecScanAttributes(secscan):
"""
Prints the header for the SecurityScan xml
file in a dictionary type format:
Computer Name: DOMAIN\computer
IP Address: 192.168.1.2
Scan Date: 2004-01-01 hh:mm:ss
Security Assessment: 2
"""
domain = secscan.attributes["Domain"]
machine = secscan.attributes["Machine"]
ip = secscan.attributes["IP"]
date = secscan.attributes["Date"]
grade = secscan.attributes["Grade"]
print "\n\n"
print "Computer Name: " + domain.value + "\\" + machine.value
print "IP Address: " + ip.value
print "Scan Date: " + date.value
print "Security Assessment: " + grade.value
print "\n\n"
def setGrade(headrow):
"""
Returns 'gradeText' based on grade.value. This is
numeric in the xml, but I just give them the text
values that are used in the MBSA interface. These are:
0 == Check Passed
1 == Additional Information
2 == Check Failed (Critical)
3 == Check Failed (Non-Critical)
4 == Note Message
5 == Check Passed
"""
grade = ""
gradeText = ""
if headrow.hasAttributes() != False:
grade = headrow.attributes["Grade"]
#print grade.value
if grade.value == '0':
gradeText = "Check Passed"
elif grade.value == '1':
gradeText = "Additional Information"
elif grade.value == '2':
gradeText = "Check Failed (Critical)"
elif grade.value == '3':
gradeText = "Check Failed (Non-Critical)"
elif grade.value == '4':
gradeText = "Note Message"
elif grade.value == '5':
gradeText = "Check Passed"
return gradeText
def printCheckAttributes(check, checknumber):
"""
Grabs the value of the attribute 'Name' from the
Check element and prints it to standard output.
"""
name = check.attributes["Name"]
print str(checknumber) + ". " + name.value + "\n"
getSecscan(mbsa)
|
As a security consultant, it is necessary to generate reports from disparate sources and generate a summary analysis for the client. After an unfruitful search for a suitable tool to parse the results from the Microsoft Baseline Security Analyzer and display it in a plain text format, I decided to write mbsa2txt.py.
-- Usage: python mbsa2txt.py mbsaScanFile.xml
It takes the name of the Documents and Settings\user\SecurityScans.xml file as an argument and outputs the results to standard output, which I redirect into a suitably named text file.
Limitations of this script is:
-- The formatting is very simple, and doesn't take advantage of text formatting techniques that would help generate final draft quality output. At this time, you will probably want to do some touch-up formatting before using this in a final draft.
The Dive into Python book by Mark Pilgrim, ( http://diveintopython.org ), and the Python Library Reference, ( http://www.python.org/doc/2.3.4/lib/lib.html ), were vital to the completion of this tool.
For a complete tarball of this application, you can download it at: