Welcome, guest | Sign In | My Account | Store | Cart

Reads the Microsoft Baseline Security Analyzer 1.2.1 XML output and sends it to standard output in a readable text format.

Python, 224 lines
  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:

http://www.erikin.com/index/softwaresolutions/oss/mbsa2txt/