1 '''
2 An embeded web server that displays fuzzing status.
3
4 @authors: Michael Eddington (mike@phed.org)
5 Blake Frantz (blakefrantz@gmail.org)
6
7 @version: $Id: webwatcher.py 863 2008-05-11 10:25:32Z meddingt $
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 import sys, os, time, threading
40 from parser import *
41 from dom import DomPrint
42 from engine import *
43 import engine
44
45 from twisted.web import server, resource, static
46 from twisted.internet import reactor
47
49
50 gadgetData = "%RUN_NAME%,%TEST_NAME%,%TEST_COUNT%,%TEST_TOTALCOUNT%,%FAULT_COUNT%"
51
52 html = """
53
54 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
55 <html>
56 <head>
57 <meta http-equiv="content-type" content="text/html; charset=iso-8859-1"/>
58 <meta http-equiv="refresh" content="10" />
59 <title>Peach Run Monitor</title>
60 <style>
61 /*#############################################################
62 Name: Indigo
63 Description: A lightweight (7kb images), simple and professional design.
64 Date: 2006-07-27
65 Author: Viktor Persson
66 URL: http://arcsin.se
67
68 Feel free to use and modify but please provide credits.
69 #############################################################*/
70
71 /* standard elements */
72 * {
73 margin: 0;
74 padding: 0;
75 }
76 a {
77 color: #F70;
78 }
79 a:hover {
80 color: #C60;
81 }
82 body {
83 background: #0094D6 url(img/bg.gif) repeat-x;
84 color: #466;
85 font: normal 62.5% "Lucida Sans Unicode",sans-serif;
86 margin: 0;
87 }
88 input {
89 color: #555;
90 font: normal 1.1em "Lucida Sans Unicode",sans-serif;
91 }
92 p,cite,code,ul {
93 font-size: 1.2em;
94 padding-bottom: 1.2em;
95 }
96 h1 {
97 font-size: 1.4em;
98 margin-bottom: 4px;
99 }
100 code {
101 background: url(img/bgcode.gif);
102 border: 1px solid #F0F0F0;
103 border-left: 6px solid #39F;
104 color: #555;
105 display: block;
106 font: normal 1.1em "Lucida Sans Unicode",serif;
107 margin-bottom: 12px;
108 padding: 8px 10px;
109 white-space: pre;
110 }
111 cite {
112 background: url(img/quote.gif) no-repeat;
113 color: #666;
114 display: block;
115 font: normal 1.3em "Lucida Sans Unicode",serif;
116 padding-left: 28px;
117 }
118 h1,h2,h3 {
119 color: #06C;
120 padding-top: 6px;
121 }
122 /* misc */
123 .clearer {
124 clear: both;
125 }
126
127 /* structure */
128 .container {
129 background: url(img/topleft.png) no-repeat;
130 }
131
132 .header {
133 height: 92px;
134 }
135
136 /* title */
137 .title {
138 float: left;
139 padding: 28px 0 0 76px;
140 }
141 .title h1 {
142 color: #FFF;
143 font: normal 2em Verdana,sans-serif;
144 }
145 /* navigation */
146 .navigation {
147 float: left;
148 height: 92px;
149 margin-left: 24px;
150 padding: 0 16px;
151 }
152 .navigation a {
153 color: #FFF;
154 float: left;
155 font: bold 1.2em "Trebuchet MS",sans-serif;
156 margin-top: 56px;
157 padding: 8px 18px;
158 text-align: center;
159 text-decoration: none;
160 }
161 .navigation a:hover {
162 background-color: #4A91C3;
163 color: #FFF;
164 }
165
166 /* main */
167 .main {
168 background: #FFF url(img/bgmain.gif) no-repeat;
169 clear: both;
170 padding: 12px 12px 0 52px;
171 }
172
173 /* main left */
174 .sidenav {
175 float: left;
176 width: 24%;
177 }
178 .sidenav h1 {
179 border-bottom: 1px dashed #DDD;
180 color: #E73;
181 font-size: 1.2em;
182 height: 20px;
183 margin-top: 1.2em;
184 }
185 .sidenav ul {
186 margin: 0;
187 padding: 0;
188 }
189 .sidenav li {
190 border-bottom: 1px dashed #EEE;
191 list-style: none;
192 margin: 0;
193 }
194 .sidenav li a {
195 color: #777;
196 display: block;
197 font-size: 0.9em;
198 padding: 3px 6px 3px 18px;
199 text-decoration: none;
200 }
201 .sidenav li a:hover {
202 color: #111;
203 background: url(img/nav_li.gif) no-repeat;
204 }
205
206 /* content */
207 .content {
208 float: left;
209 margin-right: 4%;
210 width: 69%;
211 }
212 .content .descr {
213 color: #C60;
214 margin-bottom: 6px;
215 }
216 .content li {
217 list-style: url(img/li.gif);
218 margin-left: 18px;
219 }
220
221 /* search form */
222 .styled {
223 border: 3px double #E5E5E5;
224 padding: 2px 3px;
225 }
226 .button {
227 border: 1px solid #AAA;
228 margin-left: 5px;
229 padding: 2px 3px;
230 }
231
232 /* footer */
233 .footer {
234 background: #0094D6 url(img/bgfooter.gif) repeat-x;
235 color: #C1DEF0;
236 font-size: 1.1em;
237 line-height: 40px;
238 text-align: center;
239 }
240 .footer a {
241 color: #FFF;
242 text-decoration: none;
243 }
244 .footer a:hover {
245 color: #FFF;
246 text-decoration: underline;
247 }
248 </style>
249 </head>
250 <body>
251 <div class="container">
252 <div class="header">
253 <div class="title">
254 <h1>Peach Run Monitor</h1>
255 </div>
256 </div>
257 <div class="main">
258 <div class="content">
259 <h1>%RUN_NAME% -- %TEST_NAME%</h1>
260 <div class="descr">%TEST_COUNT% of %TEST_TOTALCOUNT% <b>/</b> %FAULT_COUNT% faults detected</div>
261 <p></p>
262
263 <b>Current test case:</b> <br>
264 <!-- <b>Length</b>: %TEST_VALUE_LENGTH%<br /> -->
265 %TEST_VALUE%
266
267 <br /><br /><br /><br /><br /><br /><br />
268 <br /><br /><br /><br /><br /><br /><br />
269 <br /><br /><br /><br /><br /><br /><br />
270
271 <br />
272 <br />
273 <p>
274 </p>
275 </div>
276 <div class="sidenav">
277 <br />
278 %FAULTS%
279 <!-- <br />
280 <p>
281 Fault detected on test case #47<br />
282 <ul>
283 <li><a href="">Data.txt</a></li>
284 <li><a href="">Debugger.txt</a></li>
285 <li><a href="">Network.pcap</a></li>
286 </ul>
287 </p> -->
288 </div>
289 <div class="clearer"><span> </span></div>
290 </div>
291 </div>
292 <div class="footer"> </div>
293 </body>
294 </html>"""
295
296 isLeaf = True
297
298
299
300
301
302
303
304 ret = ""
305
306 dataUri = re.compile(r"^/stuff/(\d+)_(\d+)_(.*)$")
307
308
309 gadgetDataUri = re.compile(r"^/\?gadgetData")
310
312
313 self.parent._lock.acquire()
314
315 try:
316
317
318
319 m = self.dataUri.search(request.uri)
320 if m != None:
321
322 faultIndex = int(m.group(1))
323 faultKey = m.group(3)
324
325 if faultKey[-3:] == "txt":
326 return "<body><pre>" + self.parent._faultData[faultIndex][1][faultKey] + "</pre></body>"
327
328 else:
329 ret = self.parent._faultData[faultIndex][1][faultKey]
330
331 self.parent._lock.release()
332 return ret
333
334
335 m = self.gadgetDataUri.search(request.uri)
336
337 if m != None:
338 ret = self.gadgetData
339 else:
340 ret = self.html
341
342
343 if self.parent._run != None:
344 ret = ret.replace("%RUN_NAME%", self.parent._run.name)
345 else:
346 ret = ret.replace("%RUN_NAME%", "")
347 if self.parent._test != None:
348 ret = ret.replace("%TEST_NAME%", self.parent._test.name)
349 else:
350 ret = ret.replace("%TEST_NAME%", "")
351 if self.parent._variationCount != None:
352 ret = ret.replace("%TEST_COUNT%", str(self.parent._variationCount))
353 else:
354 ret = ret.replace("%TEST_COUNT%", "")
355 if self.parent._totalVariations!= None:
356 ret = ret.replace("%TEST_TOTALCOUNT%", str(self.parent._totalVariations))
357 else:
358 ret = ret.replace("%TEST_TOTALCOUNT%", "")
359 if self.parent._value != None:
360
361 buff = ""
362 for value in self.parent._value:
363 if len(value) < 3:
364 continue
365
366 buff += "<b>%s: %s length: %d</b><br/><textarea rows=\"20\" cols=\"60\" readonly=\"true\">%s</textarea><br/>" % (value[1], value[0], len(value[2]), repr(value[2]))
367
368 ret = ret.replace("%TEST_VALUE%", buff)
369 else:
370 ret = ret.replace("%TEST_VALUE%", "")
371
372 ret = ret.replace("%FAULT_COUNT%", str(self.parent._faultCount))
373
374 faultHtml = ''
375 if self.parent._faultCount > 0:
376
377
378 for i in range(len(self.parent._faultData)):
379 fault = self.parent._faultData[i]
380
381 faultHtml += '<br /><p>Fault detected on test case #' + str(fault[0]) + '<br /><ul>'
382
383 for key in fault[1].keys():
384 faultHtml += '<li><a href="/stuff/%d_%d_%s">%s</a></li>' % (i, fault[0], key, key)
385
386 faultHtml += '</ul></p>'
387
388 ret = ret.replace("%FAULTS%", faultHtml)
389
390 finally:
391 self.parent._lock.release()
392
393 return str(ret)
394
396 '''
397 Base for a class that receives callback when events occur
398 in the Peach Engine.
399 '''
400
402 threading.Thread.__init__(self)
403
404 self._port = port
405 self._run = None
406 self._test = None
407 self._totalVariations = 0
408 self._variationCount = 0
409 self._value = None
410 self._exception = None
411 self._isFinished = False
412 self._lock = threading.Lock()
413 self._faultCount = 0
414 self._faultData = []
415
416 self.start()
417
418
419 try:
420 params = [ 'explorer', "http://127.0.0.1:"+str(self._port)]
421 ret = os.spawnv(os.P_NOWAIT, "c:/windows/explorer.exe", params )
422 except:
423 pass
424
426 if engine.__file__[1] != ':':
427 imgPath = os.path.dirname(os.path.join(os.getcwd(), engine.__file__))
428 else:
429 imgPath = os.path.dirname(engine.__file__)
430 imgPath = os.path.join(imgPath, 'img')
431
432 res = static.File(imgPath)
433 handler = WebHandler()
434
435 res.putChild('img', static.File(imgPath))
436 res.putChild('', handler)
437 res.putChild('stuff', handler)
438
439
440 self._site = server.Site(res)
441 handler.parent = self
442 reactor.listenTCP(9001, self._site)
443 print "Listening on port 9001."
444 reactor.run(installSignalHandlers=0)
445
447 self._lock.acquire()
448 self._totalVariations = totalVariations
449 self._lock.release()
450
452 self._lock.acquire()
453 self._run = run
454 self._lock.release()
455
457 self._lock.acquire()
458 self._isFinished = True
459 self._lock.release()
460
461 print "\n\n --- Type CTRL-BREAK To End Peach Web Server --- \n"
462
464 self._lock.acquire()
465 self._test = test
466 self._totalVariations = totalVariations
467 self._lock.release()
468
470 self._lock.acquire()
471 self._test = None
472 self._lock.release()
473
476
479
481 self._lock.acquire()
482 self._exception = exception
483 self._lock.release()
484
486 self._lock.acquire()
487 self._variationCount = variationCount
488 self._value = actionValues
489 self._lock.release()
490
491 - def OnFault(self, run, test, variationCount, monitorData, value):
492 self._faultCount += 1
493 self._faultData.append((variationCount, monitorData))
494
495
496
497