1
2
3 __docformat__ = 'restructuredtext'
4 __version__ = '$Id$'
5
6 from routerdefense.common import *
7 from routerdefense.metrics import *
8
9 -def htmlReport(outputFile,genericCfg, ManagementPlaneMetrics, ControlPlaneMetrics, DataPlaneMetrics):
10 import time
11 import datetime
12 import inspect
13 import __builtin__
14 date = time.strftime('%D')
15 try:
16 report = open(outputFile, 'w')
17 except IOError:
18 print "Error while accessing the Output file. Perhaps you should check the file permissions ;)"
19 exit(1)
20 htmlHeader = []
21 htmlFooter = []
22 htmlSummary = []
23 htmlTOC = []
24 htmlMPlane = []
25 htmlCPlane = []
26 htmlDPlane = []
27
28 MPlaneCounter = 0
29 CPlaneCounter = 0
30 DPlaneCounter = 0
31
32 htmlTOC.append('<div id="toc">')
33 htmlTOC.append('\n')
34 htmlTOC.append('<ol>')
35 htmlTOC.append('\n')
36
37 htmlSummary.append('<div id="summary">')
38 htmlSummary.append('\n')
39 htmlSummary.append('<table')
40 htmlSummary.append('\n')
41 htmlSummary.append('<thead><tr><th>Management Plane</th><th>Control Plane</th><th>Data Plane</th></tr></thead>')
42 htmlSummary.append('\n')
43 htmlSummary.append('<tbody>')
44 htmlSummary.append('\n')
45
46 htmlHeader.append('<!DOCTYPE html>')
47 htmlHeader.append('\n')
48 htmlHeader.append('<head>')
49 htmlHeader.append('\n')
50 htmlHeader.append('<title>'+ 'RouterDefense ' + date + '</title>')
51 htmlHeader.append('\n')
52 htmlHeader.append('<link rel="stylesheet" media="all" href="style.css" />')
53 htmlHeader.append('\n')
54 htmlHeader.append('<script src="http://code.jquery.com/jquery-latest.min.js"></script>')
55 htmlHeader.append('\n')
56 htmlHeader.append('</head>')
57 htmlHeader.append('\n')
58 htmlHeader.append('<body>')
59 htmlHeader.append('\n')
60 htmlHeader.append('<div id="content">')
61 htmlHeader.append('\n')
62 htmlHeader.append('<header role="banner">')
63 htmlHeader.append('\n')
64
65 htmlHeader.append('<h1><a href="http://code.google.com/p/routerdefense">Router <span>Defense</span></a></h1>')
66 htmlHeader.append('\n')
67 htmlHeader.append('<nav role="navigation"><a href=#MPlane>Management Plane</a> <a href=#CPlane>Control Plane</a> <a href=#DPlane>Data Plane</a></nav>')
68 htmlHeader.append('\n')
69 htmlHeader.append('</header>')
70 htmlHeader.append('\n')
71 htmlHeader.append('<p id="presentation">')
72 htmlHeader.append('\n')
73 htmlHeader.append('Documentation and new release can be found at: <a href="http://code.google.com/p/routerdefense">http://code.google.com/p/routerdefense</a>')
74 htmlHeader.append('\n')
75 htmlHeader.append('<br />')
76 htmlHeader.append('Document reference: ' + time.strftime("%d%b%Y-%H%M%S", time.gmtime()) )
77 htmlHeader.append('</p>')
78 htmlHeader.append('\n')
79 htmlHeader.append('<section class="content">')
80 htmlHeader.append('\n')
81
82 htmlHeader.append('<table>')
83 htmlHeader.append('\n')
84 htmlHeader.append('<thead>')
85 htmlHeader.append('\n')
86 htmlHeader.append('<tr><th>Hostname</th><th>IOS</th><th>Switching</th><th>Multicast</th><th>QoS</th><th>IPv6</th><th>IPSEC VPN</th></tr>')
87 htmlHeader.append('\n')
88 htmlHeader.append('</thead>')
89 htmlHeader.append('\n')
90 htmlHeader.append('<tbody>')
91 htmlHeader.append('\n')
92 htmlHeader.append('<tr>')
93 htmlHeader.append('\n')
94 htmlHeader.append('<td>' + genericCfg.hostName + '</td>')
95 htmlHeader.append('\n')
96 htmlHeader.append('<td>' + genericCfg.iosVersion + '</td>')
97 htmlHeader.append('\n')
98 htmlHeader.append('<td>' + genericCfg.switchingMethod + '</td>')
99 htmlHeader.append('\n')
100 htmlHeader.append('<td>' + genericCfg.multicast + '</td>')
101 htmlHeader.append('\n')
102 htmlHeader.append('<td>' + genericCfg.qos + '</td>')
103 htmlHeader.append('\n')
104 htmlHeader.append('<td>' + genericCfg.ipv6 + '</td>')
105 htmlHeader.append('\n')
106 htmlHeader.append('<td>' + genericCfg.ipsec + '</td>')
107 htmlHeader.append('\n')
108 htmlHeader.append('</tr>')
109 htmlHeader.append('\n')
110 htmlHeader.append('</tbody>')
111 htmlHeader.append('\n')
112 htmlHeader.append('</table>')
113 htmlHeader.append('\n')
114 htmlHeader.append('<br />')
115 htmlHeader.append('\n')
116
117 htmlMPlane.append('<a id="planeTitle" name="MPlane">Management Plane</a><br /><br />')
118 vulnIndex = 0
119 for name in ManagementPlaneMetrics:
120 if name != 'interface':
121 for k,v in inspect.getmembers(name):
122 if isinstance(v, dict):
123 if v['must_report'] == True:
124 vulnIndex = vulnIndex + 1
125 definition = v['definition'].strip()
126 threatInfo = v['threatInfo'].strip()
127 howtofix = v['howtofix'].split('\n')
128 fixImpact = v['fixImpact'].strip()
129 cvss = v['cvss'].strip()
130 htmlMPlane.append('\n')
131 htmlMPlane.append('<table id="namedef">')
132 htmlMPlane.append('\n')
133 htmlMPlane.append('<tbody>')
134 htmlMPlane.append('\n')
135 htmlMPlane.append('<tr>')
136 htmlMPlane.append('\n')
137 htmlMPlane.append('<a id="planeContent" name="MP'+ str(MPlaneCounter) +'">' + '<td id="name">' + name.long_name + '</td>' + '</a>')
138 htmlMPlane.append('\n')
139 htmlMPlane.append('<td id="definition">' + definition + '</td>')
140 htmlMPlane.append('\n')
141 if float(cvss) <= 4:
142 htmlMPlane.append('<td id="cvssGreen">' + cvss + '/10' + '</td>')
143 htmlMPlane.append('\n')
144 elif float(cvss) <= 7.9 and cvss >=4.1:
145 htmlMPlane.append('<td id="cvssOrange">' + cvss + '/10' + '</td>')
146 htmlMPlane.append('\n')
147 elif float(cvss) >=8:
148 htmlMPlane.append('<td id="cvssRed">' + cvss + '/10' + '</td>')
149 htmlMPlane.append('\n')
150 htmlMPlane.append('<td id="ToggleButton"><button id='+ str(vulnIndex) +'>Hide/Show</button></td>')
151 htmlMPlane.append('</tr>')
152 htmlMPlane.append('\n')
153 htmlMPlane.append('</tbody>')
154 htmlMPlane.append('\n')
155 htmlMPlane.append('</table>')
156 htmlMPlane.append('\n')
157 htmlMPlane.append('<article id="'+ str(vulnIndex) +'"><p>')
158 htmlMPlane.append('\n')
159 htmlMPlane.append('<p id="threatInfo">Threat information: </p>' + threatInfo + '<br />')
160 htmlMPlane.append('\n')
161 htmlMPlane.append('<p id="threatInfo">Fix impact: </p>' + fixImpact + '<br />')
162 htmlMPlane.append('\n')
163
164 htmlMPlane.append('<table id ="fix">')
165 htmlMPlane.append('\n')
166 htmlMPlane.append('<thead>')
167 htmlMPlane.append('\n')
168 htmlMPlane.append('<tr><th id="fix">How to fix</th></tr>')
169 htmlMPlane.append('\n')
170 htmlMPlane.append('</thead>')
171 htmlMPlane.append('\n')
172 htmlMPlane.append('<tbody>')
173 htmlMPlane.append('\n')
174 for index in howtofix:
175 htmlMPlane.append('<tr>')
176 htmlMPlane.append('\n')
177 htmlMPlane.append('<td id="fix">' + index + '</td>')
178 htmlMPlane.append('\n')
179 htmlMPlane.append('</tr>')
180 htmlMPlane.append('\n')
181 htmlMPlane.append('</tbody>')
182 htmlMPlane.append('\n')
183 htmlMPlane.append('</table>')
184 htmlMPlane.append('\n')
185 htmlMPlane.append('</p></article><br />')
186 htmlMPlane.append('\n')
187 htmlMPlane.append(' \
188 <script> \
189 $("button[id=' + str(vulnIndex) + ']").click(function () { \
190 $("article[id=' + str(vulnIndex) + ']").toggle("slow"); \
191 }); \
192 </script> \
193 ')
194
195 htmlTOC.append('<li><a href=#MP'+ str(MPlaneCounter) + '>' + name.long_name + ': ' + definition + '</a></li>')
196 htmlTOC.append('\n')
197 MPlaneCounter = MPlaneCounter + 1
198
199 htmlCPlane.append('<a id="planeTitle" name="CPlane">Control Plane</a><br /><br />')
200 htmlCPlane.append('\n')
201 for name in ControlPlaneMetrics:
202 if name != 'interface':
203 for k,v in inspect.getmembers(name):
204 if isinstance(v, dict):
205 if v['must_report'] == True:
206 vulnIndex = vulnIndex + 1
207 definition = v['definition'].strip()
208 threatInfo = v['threatInfo'].strip()
209 fixImpact = v['fixImpact'].strip()
210 cvss = v['cvss'].strip()
211 if definition == 'OSPF route filtering in':
212 v['howtofix'] = v['howtofix'].strip().replace('[%ospfPID]', ", ".join(name.rfilter_in['pid']), 1)
213 v['howtofix'] = v['howtofix'].strip().replace('[%ospfArea]', ", ".join(name.rfilter_in['area']), 1)
214 elif definition == 'OSPF MD5 authentication':
215 v['howtofix'] = v['howtofix'].strip().replace('[%ospfinterface]', ", ".join(name.auth_md5['interfaces']), 1)
216 v['howtofix'] = v['howtofix'].strip().replace('[%ospfArea]', ", ".join(name.auth_md5['area']), 1)
217 v['howtofix'] = v['howtofix'].strip().replace('[%ospfPID]', ", ".join(name.auth_md5['pid']), 1)
218 elif definition == 'OSPF route filtering out':
219 v['howtofix'] = v['howtofix'].strip().replace('[%ospfPID]', ", ".join(name.rfilter_out['pid']), 1)
220 v['howtofix'] = v['howtofix'].strip().replace('[%ospfArea]', ", ".join(name.rfilter_out['area']), 1)
221 elif definition == 'OSPF passive interface default':
222 v['howtofix'] = v['howtofix'].strip().replace('[%ospfInstance]', ", ".join(name.passive['pid']), 1)
223 elif definition == 'OSPF maximum LSA':
224 v['howtofix'] = v['howtofix'].strip().replace('[%ospfInstance]', ", ".join(name.maxLSA['pid']), 1)
225 elif definition == 'EIGRP MD5 authentication':
226 v['howtofix'] = v['howtofix'].strip().replace('[%eigrpinterface]', ", ".join(name.auth_md5['interfaces']), 1)
227 v['howtofix'] = v['howtofix'].strip().replace('[%eigrpAs]', ", ".join(name.auth_md5['asn']), 1)
228 elif definition == 'EIGRP passive interface default':
229 v['howtofix'] = v['howtofix'].strip().replace('[%eigrpAs]', ", ".join(name.passive['asn']), 1)
230 elif definition == 'EIGRP route filtering inbound':
231 v['howtofix'] = v['howtofix'].strip().replace('[%eigrpAs]', ", ".join(name.rfilter_in['asn']), 1)
232 elif definition == 'EIGRP route filtering outbound':
233 v['howtofix'] = v['howtofix'].strip().replace('[%eigrpAs]', ", ".join(name.rfilter_out['asn']), 1)
234 elif definition == 'RIP MD5 authentication':
235 v['howtofix'] = v['howtofix'].strip().replace('[%ripinterface]', ", ".join(name.auth_md5['interfaces']), 1)
236
237 howtofix = v['howtofix'].split('\n')
238 htmlCPlane.append(' \
239 <script> \
240 $("button").click(function () { \
241 $("article[id=' + str(vulnIndex) + ']").toggle("slow"); \
242 }); \
243 </script> \
244 ')
245 htmlCPlane.append('\n')
246 htmlCPlane.append('<article id="'+ str(vulnIndex) +'"><p>')
247 htmlCPlane.append('\n')
248 htmlCPlane.append('<table id="namedef">')
249 htmlCPlane.append('\n')
250 htmlCPlane.append('<tbody>')
251 htmlCPlane.append('\n')
252 htmlCPlane.append('<tr>')
253 htmlCPlane.append('\n')
254 htmlCPlane.append('<a id="planeContent" name="CP'+ str(CPlaneCounter) +'">' + '<td id="name">' + name.long_name + '</td>' + '</a>')
255 htmlCPlane.append('\n')
256 htmlCPlane.append('<td id="definition">' + definition + '</td>')
257 htmlCPlane.append('\n')
258 if float(cvss) <= 4:
259 htmlCPlane.append('<td id="cvssGreen">' + cvss + '/10' + '</td>')
260 htmlCPlane.append('\n')
261 elif float(cvss) <= 7.9 and cvss >=4.1:
262 htmlCPlane.append('<td id="cvssOrange">' + cvss + '/10' + '</td>')
263 htmlCPlane.append('\n')
264 elif float(cvss) >=8:
265 htmlCPlane.append('<td id="cvssRed">' + cvss + '/10' + '</td>')
266 htmlCPlane.append('\n')
267 htmlCPlane.append('<td id="ToggleButton"><button id='+ str(vulnIndex) +'>Hide/Show</button></td>')
268 htmlCPlane.append('</tr>')
269 htmlCPlane.append('\n')
270 htmlCPlane.append('</tbody>')
271 htmlCPlane.append('\n')
272 htmlCPlane.append('</table>')
273 htmlCPlane.append('\n')
274
275 htmlCPlane.append('<p id="threatInfo">Threat information: </p>' + threatInfo + '<br />')
276 htmlCPlane.append('\n')
277 htmlCPlane.append('<p id="threatInfo">Fix impact: </p>' + fixImpact + '<br />')
278 htmlCPlane.append('\n')
279
280 htmlCPlane.append('<table id ="fix">')
281 htmlCPlane.append('\n')
282 htmlCPlane.append('<thead>')
283 htmlCPlane.append('\n')
284 htmlCPlane.append('<tr><th id="fix">How to fix</th></tr>')
285 htmlCPlane.append('\n')
286 htmlCPlane.append('</thead>')
287 htmlCPlane.append('\n')
288 htmlCPlane.append('<tbody>')
289 htmlCPlane.append('\n')
290 for index in howtofix:
291 htmlCPlane.append('<tr>')
292 htmlCPlane.append('\n')
293 htmlCPlane.append('<td id="fix">' + index + '</td>')
294 htmlCPlane.append('\n')
295 htmlCPlane.append('</tr>')
296 htmlCPlane.append('\n')
297 htmlCPlane.append('</tbody>')
298 htmlCPlane.append('\n')
299 htmlCPlane.append('</table>')
300 htmlCPlane.append('\n')
301 htmlCPlane.append('</p></article><br />')
302 htmlCPlane.append('\n')
303 htmlCPlane.append(' \
304 <script> \
305 $("button[id=' + str(vulnIndex) + ']").click(function () { \
306 $("article[id=' + str(vulnIndex) + ']").toggle("slow"); \
307 }); \
308 </script> \
309 ')
310
311 htmlTOC.append('<li><a href=#CP'+ str(CPlaneCounter) + '>' + name.long_name + ': ' + definition + '</a></li>')
312 htmlTOC.append('\n')
313 CPlaneCounter = CPlaneCounter + 1
314
315 htmlDPlane.append('<a id="planeTitle" name="DPlane">Data Plane</a><br /><br />')
316 htmlDPlane.append('\n')
317 for name in DataPlaneMetrics:
318 if name != 'interface':
319 for k,v in inspect.getmembers(name):
320 if isinstance(v, dict):
321 if v['must_report'] == True:
322 vulnIndex = vulnIndex + 1
323 definition = v['definition'].strip()
324 threatInfo = v['threatInfo'].strip()
325 fixImpact = v['fixImpact'].strip()
326 cvss = v['cvss'].strip()
327 if definition == 'Port security violation':
328 v['howtofix'] = v['howtofix'].strip().replace('[%interface]', ", ".join(name.violation['candidates']), 1)
329 if definition == 'Port security MAC address sticky':
330 v['howtofix'] = v['howtofix'].strip().replace('[%interface]', ", ".join(name.sticky['candidates']), 1)
331 if definition == 'Port security total maximum MAC addresses':
332 v['howtofix'] = v['howtofix'].strip().replace('[%interface]', ", ".join(name.maximum_total['candidates']), 1)
333 if definition == 'Port security access vlan maximum MAC addresses':
334 v['howtofix'] = v['howtofix'].strip().replace('[%interface]', ", ".join(name.maximum_access['candidates']), 1)
335 if definition == 'Port security voice vlan maximum MAC addresses':
336 v['howtofix'] = v['howtofix'].strip().replace('[%interface]', ", ".join(name.maximum_voice['candidates']), 1)
337 if definition == 'DTP negotiation':
338 v['howtofix'] = v['howtofix'].strip().replace('[%interface]', ", ".join(name.nonegotiate['candidates']), 1)
339 if definition == 'Flow Control 802.3x':
340 v['howtofix'] = v['howtofix'].strip().replace('[%interface]', ", ".join(name.flowcontrol['candidates']), 1)
341 if definition == 'VLAN 1':
342 v['howtofix'] = v['howtofix'].strip().replace('[%interface]', ", ".join(name.vlan_1['candidates']), 1)
343 if definition == 'Unused ports':
344 v['howtofix'] = v['howtofix'].strip().replace('[%interface]', ", ".join(name.unused_ports['candidates']), 1)
345
346 howtofix = v['howtofix'].split('\n')
347 htmlDPlane.append(' \
348 <script> \
349 $("button").click(function () { \
350 $("article[id=' + str(vulnIndex) + ']").toggle("slow"); \
351 }); \
352 </script> \
353 ')
354 htmlDPlane.append('\n')
355 htmlDPlane.append('<article id="'+ str(vulnIndex) +'"><p>')
356 htmlDPlane.append('\n')
357 htmlDPlane.append('<table id="namedef">')
358 htmlDPlane.append('\n')
359 htmlDPlane.append('<tbody>')
360 htmlDPlane.append('\n')
361 htmlDPlane.append('<tr>')
362 htmlDPlane.append('\n')
363 htmlDPlane.append('<a id="planeContent" name="DP'+ str(DPlaneCounter) +'">' + '<td id="name">' + name.long_name + '</td>' + '</a>')
364 htmlDPlane.append('\n')
365 htmlDPlane.append('<td id="definition">' + definition + '</td>')
366 htmlDPlane.append('\n')
367 if float(cvss) <= 4:
368 htmlDPlane.append('<td id="cvssGreen">' + cvss + '/10' + '</td>')
369 htmlDPlane.append('\n')
370 elif float(cvss) <= 7.9 and cvss >=4.1:
371 htmlDPlane.append('<td id="cvssOrange">' + cvss + '/10' + '</td>')
372 htmlDPlane.append('\n')
373 elif float(cvss) >=8:
374 htmlDPlane.append('<td id="cvssRed">' + cvss + '/10' + '</td>')
375 htmlDPlane.append('\n')
376 htmlDPlane.append('<td id="ToggleButton"><button id='+ str(vulnIndex) +'>Hide/Show</button></td>')
377 htmlDPlane.append('</tr>')
378 htmlDPlane.append('\n')
379 htmlDPlane.append('</tbody>')
380 htmlDPlane.append('\n')
381 htmlDPlane.append('</table>')
382 htmlDPlane.append('\n')
383
384 htmlDPlane.append('<p id="threatInfo">Threat information: </p>' + threatInfo + '<br />')
385 htmlDPlane.append('\n')
386 htmlDPlane.append('<p id="threatInfo">Fix impact: </p>' + fixImpact + '<br />')
387 htmlDPlane.append('\n')
388
389 htmlDPlane.append('<table id ="fix">')
390 htmlDPlane.append('\n')
391 htmlDPlane.append('<thead>')
392 htmlDPlane.append('\n')
393 htmlDPlane.append('<tr><th id="fix">How to fix</th></tr>')
394 htmlDPlane.append('\n')
395 htmlDPlane.append('</thead>')
396 htmlDPlane.append('\n')
397 htmlDPlane.append('<tbody>')
398 htmlDPlane.append('\n')
399 for index in howtofix:
400 htmlDPlane.append('<tr>')
401 htmlDPlane.append('\n')
402 htmlDPlane.append('<td id="fix">' + index + '</td>')
403 htmlDPlane.append('\n')
404 htmlDPlane.append('</tr>')
405 htmlDPlane.append('\n')
406 htmlDPlane.append('</tbody>')
407 htmlDPlane.append('\n')
408 htmlDPlane.append('</table>')
409 htmlDPlane.append('\n')
410 htmlDPlane.append('</p></article><br />')
411 htmlDPlane.append('\n')
412 htmlDPlane.append(' \
413 <script> \
414 $("button[id=' + str(vulnIndex) + ']").click(function () { \
415 $("article[id=' + str(vulnIndex) + ']").toggle("slow"); \
416 }); \
417 </script> \
418 ')
419
420 htmlTOC.append('<li><a href=#DP'+ str(DPlaneCounter) + '>' + name.long_name + ': ' + definition + '</a></li>')
421 htmlTOC.append('\n')
422 DPlaneCounter = DPlaneCounter + 1
423
424
425 htmlSummary.append('<tr>')
426 htmlSummary.append('\n')
427 htmlSummary.append('<td>' + str(MPlaneCounter) + '</td>')
428 htmlSummary.append('\n')
429 htmlSummary.append('<td>' + str(CPlaneCounter) + '</td>')
430 htmlSummary.append('\n')
431 htmlSummary.append('<td>' + str(DPlaneCounter) + '</td>')
432 htmlSummary.append('\n')
433 htmlSummary.append('</tr>')
434 htmlSummary.append('\n')
435
436 htmlSummary.append('</tbody>')
437 htmlSummary.append('\n')
438 htmlSummary.append('</table>')
439 htmlSummary.append('\n')
440 htmlSummary.append('</div>')
441 htmlSummary.append('\n')
442
443 htmlSummary.append('<u>Management plane:</u> impact on management.<br /><u>Control plane:</u> impact on infrastructure protected by the device.<br /><u>Data plane:</u> impact on traffic flowing through the device.')
444 htmlSummary.append('\n')
445
446 htmlTOC.append('</ol>')
447 htmlTOC.append('\n')
448 htmlTOC.append('</div>')
449 htmlTOC.append('\n')
450
451 htmlFooter.append('</section>')
452 htmlFooter.append('\n')
453 htmlFooter.append('</div>')
454 htmlFooter.append('\n')
455 htmlFooter.append('<footer>')
456 htmlFooter.append('\n')
457 htmlFooter.append('<p id="presentation">')
458 htmlFooter.append('\n')
459 htmlFooter.append('RouterDefense is created and maintained by Francois Ropert.')
460 htmlFooter.append('\n')
461 htmlFooter.append('</p>')
462 htmlFooter.append('\n')
463 htmlFooter.append('</footer>')
464 htmlFooter.append('\n')
465 htmlFooter.append('</body>')
466 htmlFooter.append('\n')
467
468 for line in htmlHeader:
469 report.write(line)
470 report.write('<font size="+1"><b><u>Recommandations found</u></b></font>')
471 report.write('<br /><br />')
472 for line in htmlSummary:
473 report.write(line)
474 report.write('<br /><br />')
475 report.write('<font size="+1"><b><u>Table of contents</u></b></font>')
476 report.write('<br /><br />')
477 for line in htmlTOC:
478 report.write(line)
479 report.write('<br />')
480 for line in htmlMPlane:
481 report.write(line)
482 report.write('<br />')
483 for line in htmlCPlane:
484 report.write(line)
485 report.write('<br />')
486 for line in htmlDPlane:
487 report.write(line)
488 for line in htmlFooter:
489 report.write(line)
490
491 report.close()
492 print "Audit has been saved under the filename: %s " % outputFile
493 return "HTML"
494