In between projects, we at Astyran have an internal project running to streamline reporting of our vulnerability assessments. One of the tools we use is Gremwell’s MagicTree.
Earlier I blogged about our XSLT style-sheet to import vulnerability data of the Arachni scanner. This style sheet created views on the data grouped per vulnerability type. However all other import sheets seem to prefer to group vulnerabilities per URL.
Personally I prefer to group vulnerabilities per type:
- it enables the designer/architect to really see the full picture at once, design a real solution, and assess the possible impact on development.
- it prevents developers to fix the issues per page, what leads to incomplete or plain wrong solutions and the endless “penetrate and patch” cycle.
- it gives a less daunting report to business management (“only 1 high rated issue on a total of 10)” as compared to “we have found 300 high rated issues on a total of 1100). Managers like to see that things in their business critical application can be fixed, not that the situation appears hopeless.
- it makes the development team happy: “only 1 item to fix”, we are not complete losers and did a reasonable good job;
- it makes the poor soul that imports the data into the change request management program also happy: only 10 items to import, classify, prioritize and follow-up as compared to 1.100 items - of which many will need to be closed as ‘duplicates’.
- it wastes less disk-space.
Unfortunately, that means that we have to change all XSLT transformation sheets to import the data the way we want.
Here the code to import Burp scanner data according to our wishes. Just as with our Arachni solution, it creates a (non-standard) “scaninfo” section that keeps information about the scans that were imported, as well as the (standard) “testdata” tree, but now ordered per finding and not per URL.
1: <?xml version="1.0" encoding="UTF-8"?>
2: <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
3: 4: <xsl:variable name="my_report_signature">
5: <xsl:text>Burp</xsl:text>
6: <xsl:value-of select="translate(/issues/@burpVersion,' 	
+-:','')"/>
7: <xsl:value-of select="translate(/issues/@exportTime,' 	
+-:','')"/>
8: </xsl:variable>
9: 10: <xsl:template name="burp-finding">
11: <xsl:param name="issue"/>
12: <finding class="MtTextObject" status="new">
13: <xsl:attribute name="title">
14: <xsl:value-of select="$issue/name" />
15: </xsl:attribute>
16: <xsl:attribute name="mergeID" >
17: <xsl:value-of select="$issue/name" />
18: </xsl:attribute>
19: <burptype><xsl:value-of select="$issue/type" /></burptype>
20: <source>
21: <xsl:text>Burp </xsl:text>
22: <xsl:value-of select="/issues/@exportTime" />
23: </source>
24: <xsl:call-template name="burp-severity">
25: <xsl:with-param name="severity" select="$issue/severity"/>
26: </xsl:call-template>
27: <xsl:value-of select="$issue/issueBackground" />
28: <solution title="Solution" class="MtTextObject">
29: <xsl:value-of select="$issue/remediationBackground" />
30: </solution>
31: <affects>
32: <xsl:attribute name="mergeID" >
33: <xsl:value-of select="concat($issue/host, $issue/path)" /> <!-- group output by URI -->
34: </xsl:attribute>
35: <xsl:value-of select="concat($issue/host, $issue/path)"/>
36: <output title="Details" class="MtTextObject">
37: <xsl:value-of select="$issue/issueDetail" />
38: </output>
39: <xsl:if test="string-length(normalize-space(substring-after(substring-before($issue/location,'parameter'),'[')))>0">
40: <parameter> <!-- I really hope nobody uses '[' in URLS -->
41: <xsl:value-of select="normalize-space(substring-after(substring-before($issue/location,'parameter'),'['))" />
42: </parameter>
43: </xsl:if>
44: <xsl:for-each select="requestresponse">
45: <requestresponse><xsl:number value="position()" format="1"/>
46: <request class="MtTextObject" title="Request">
47: <xsl:value-of select="request" />
48: </request>
49: <response class="MtTextObject" title="Response">
50: <xsl:value-of select="response" />
51: </response>
52: </requestresponse>
53: </xsl:for-each>
54: </affects>
55: </finding>
56: </xsl:template>
57: 58: <xsl:template name="burp-severity">
59: <xsl:param name="severity" />
60: <source-severity>
61: <xsl:choose>
62: <xsl:when test="$severity='High'">
63: high<numeric>3</numeric>
64: </xsl:when>
65: <xsl:when test="$severity='Medium'">
66: medium<numeric>3</numeric>
67: </xsl:when>
68: <xsl:when test="$severity='Low'">
69: low<numeric>1</numeric>
70: </xsl:when>
71: <xsl:when test="$severity='Information'">
72: info<numeric>0</numeric>
73: </xsl:when>
74: <xsl:otherwise>
75: unknown<numeric>-1</numeric>
76: </xsl:otherwise>
77: </xsl:choose>
78: </source-severity>
79: </xsl:template>
80: 81: <xsl:template name="get-port">
82: <xsl:param name="host" />
83: <xsl:variable name="proto" select="substring-before($host, ':')"/>
84: <xsl:variable name="host-port" select="substring-after($host, '://')"/>
85: <xsl:choose>
86: <xsl:when test="string-length(substring-after($host-port,':'))>0">
87: <!-- The port is explicitly specified-->
88: <xsl:value-of select="substring-after($host-port,':')" />
89: </xsl:when>
90: <xsl:otherwise>
91: <xsl:choose>
92: <xsl:when test="$proto='https'">
93: 44394: </xsl:when>
95: <xsl:otherwise>
96: 8097: </xsl:otherwise>
98: </xsl:choose>
99: </xsl:otherwise>
100: </xsl:choose>
101: </xsl:template>
102: 103: <xsl:template match="/">
104: <magictree class="MtBranchObject" xmlns:mt="http://www.gremwell.com/magictree">
105: <scaninfo class="MtBranchObject">
106: <scan status="new" class="MtTextObject">
107: <xsl:attribute name="title">
108: <xsl:text>Burp </xsl:text>
109: <xsl:value-of select="/issues/@exportTime" />
110: </xsl:attribute>
111: <!--xsl:attribute name="id">
112: This fails during import and MagicTree goes into endless loop
113: Reason to use this, was to enable references of items to report
114: <xsl:value-of select="$my_report_signature"/>
115: </xsl:attribute-->
116: <xsl:text>Burp </xsl:text>
117: <xsl:value-of select="/issues/@exportTime" />
118: <version>
119: <xsl:value-of select="/issues/@burpVersion" />
120: </version>
121: </scan>
122: </scaninfo> <!-- The end of our information about the scans-->
123: 124: <testdata class="MtBranchObject">
125: <xsl:for-each select="issues/issue">
126: <host><xsl:value-of select="host/@ip" />
127: <ipproto>tcp
128: <port>
129: <xsl:call-template name="get-port">
130: <xsl:with-param name="host" select="host"/>
131: </xsl:call-template>
132: <xsl:choose>
133: <xsl:when test="starts-with(host,'https')">
134: <tunnel>ssl
135: <service>http
136: <xsl:call-template name="burp-finding">
137: <xsl:with-param name="issue" select="."/>
138: </xsl:call-template>
139: </service>
140: </tunnel>
141: </xsl:when>
142: <xsl:otherwise>
143: <service>http
144: <xsl:call-template name="burp-finding">
145: <xsl:with-param name="issue" select="."/>
146: </xsl:call-template>
147: </service>
148: </xsl:otherwise>
149: </xsl:choose>
150: </port>
151: </ipproto>
152: </host>
153: </xsl:for-each>
154: </testdata>
155: </magictree>
156: </xsl:template>
157: </xsl:stylesheet>
And here a screenshot of the result.
Have fun and have a great week-end!
Wow, you are really digging in.
ReplyDeleteOur approach to it is grouping the findings in the report template, not in the XSLT. But your workflow may be different from ours. I'd like to hear about your streamlined reporting.
I agree that grouping findings is important. We are now trying to design a more flexible process for grouping the findings and putting customized texts in the reports. If you have any suggestions, they are very welcome.
Alla