Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

OWTF 0.12 Wicky release

  • Loading branch information...
commit 991a099b69bf53d82d0ddb1a68d404ece1e62a71 1 parent 6fd3a31
@7a 7a authored
Showing with 30,424 additions and 169 deletions.
  1. +9 −0 .gitignore
  2. +4 −0 dictionaries/README
  3. +80 −0 dictionaries/update_convert_cms_explorer_dicts.sh
  4. +19 −29 framework/config/config.py
  5. BIN  framework/config/config.pyc
  6. +6 −2 framework/config/framework_config.cfg
  7. BIN  framework/config/health_check.pyc
  8. +1 −1  framework/config/plugin.py
  9. BIN  framework/config/plugin.pyc
  10. BIN  framework/db/db.pyc
  11. +13 −9 framework/db/plugin_register.py
  12. BIN  framework/db/plugin_register.pyc
  13. +0 −1  framework/db/transaction_manager.py
  14. BIN  framework/db/transaction_manager.pyc
  15. +1 −1  framework/http/requester.py
  16. BIN  framework/http/requester.pyc
  17. +2 −2 framework/plugin/plugin_handler.py
  18. BIN  framework/plugin/plugin_handler.pyc
  19. +40 −13 framework/plugin/plugin_helper.py
  20. BIN  framework/plugin/plugin_helper.pyc
  21. +16 −18 framework/report/header.py
  22. BIN  framework/report/header.pyc
  23. 0  framework/report/html/filter/__init__.py
  24. +1 −0  framework/report/html/filter/bypasses/basic.txt
  25. +1 −0  framework/report/html/filter/bypasses/basic2.txt
  26. +1 −0  framework/report/html/filter/bypasses/css_bypass.txt
  27. +1 −0  framework/report/html/filter/bypasses/css_bypass2.txt
  28. +1 −0  framework/report/html/filter/bypasses/href.txt
  29. +1 −0  framework/report/html/filter/bypasses/href2.txt
  30. +1 −0  framework/report/html/filter/bypasses/malformed.txt
  31. +101 −0 framework/report/html/filter/sanitiser.py
  32. +1 −0  framework/report/html/filter/test_malformed/malformed.txt
  33. +1 −0  framework/report/html/filter/test_malformed/malformed2.txt
  34. +1 −0  framework/report/html/filter/test_malformed/malformed3.txt
  35. +1 −0  framework/report/html/filter/test_malformed/malformed4.txt
  36. +1 −0  framework/report/html/filter/test_malformed/malformed5.txt
  37. +1 −0  framework/report/html/filter/test_malformed/malformed6.txt
  38. +41 −0 framework/report/html/filter/test_sanitiser.sh
  39. +167 −0 framework/report/html/filter/test_valid/legitimate_robots.txt
  40. +17 −1 framework/report/html/renderer.py
  41. BIN  framework/report/html/renderer.pyc
  42. +1 −1  framework/report/html/tabcreator.py
  43. BIN  framework/report/html/tabcreator.pyc
  44. +176 −78 framework/report/reporter.py
  45. BIN  framework/report/reporter.pyc
  46. +20 −13 framework/report/summary.py
  47. BIN  framework/report/summary.pyc
  48. BIN  images/bug.png
  49. BIN  images/computer.png
  50. BIN  images/computer_small.png
  51. BIN  images/info16x16.png
  52. BIN  images/info24x24.png
  53. BIN  images/options.png
  54. BIN  images/radio-button_on.png
  55. BIN  images/shopping_cart.png
  56. BIN  images/star_2.png
  57. BIN  images/star_3.png
  58. BIN  images/target.png
  59. BIN  images/target2.png
  60. BIN  images/target3.png
  61. BIN  images/wizard.png
  62. +24 −0 includes/ckeditor/.htaccess
  63. +1,433 −0 includes/ckeditor/CHANGES.html
  64. +92 −0 includes/ckeditor/INSTALL.html
  65. +1,327 −0 includes/ckeditor/LICENSE.html
  66. +32 −0 includes/ckeditor/_samples/adobeair/application.xml
  67. +9 −0 includes/ckeditor/_samples/adobeair/run.bat
  68. +8 −0 includes/ckeditor/_samples/adobeair/run.sh
  69. +45 −0 includes/ckeditor/_samples/adobeair/sample.html
  70. +98 −0 includes/ckeditor/_samples/ajax.html
  71. +192 −0 includes/ckeditor/_samples/api.html
  72. +198 −0 includes/ckeditor/_samples/api_dialog.html
  73. +28 −0 includes/ckeditor/_samples/api_dialog/my_dialog.js
  74. +105 −0 includes/ckeditor/_samples/asp/advanced.asp
  75. +136 −0 includes/ckeditor/_samples/asp/events.asp
  76. +103 −0 includes/ckeditor/_samples/asp/index.html
  77. +72 −0 includes/ckeditor/_samples/asp/replace.asp
  78. +77 −0 includes/ckeditor/_samples/asp/replaceall.asp
  79. +46 −0 includes/ckeditor/_samples/asp/sample_posteddata.asp
  80. +72 −0 includes/ckeditor/_samples/asp/standalone.asp
  81. +59 −0 includes/ckeditor/_samples/assets/_posteddata.php
  82. BIN  includes/ckeditor/_samples/assets/output_for_flash.fla
  83. BIN  includes/ckeditor/_samples/assets/output_for_flash.swf
  84. +204 −0 includes/ckeditor/_samples/assets/output_xhtml.css
  85. +70 −0 includes/ckeditor/_samples/assets/parsesample.css
  86. +18 −0 includes/ckeditor/_samples/assets/swfobject.js
  87. +108 −0 includes/ckeditor/_samples/autogrow.html
  88. +125 −0 includes/ckeditor/_samples/bbcode.html
  89. +94 −0 includes/ckeditor/_samples/devtools.html
  90. +154 −0 includes/ckeditor/_samples/divreplace.html
  91. +115 −0 includes/ckeditor/_samples/enterkey.html
  92. +82 −0 includes/ckeditor/_samples/fullpage.html
  93. +116 −0 includes/ckeditor/_samples/index.html
  94. +99 −0 includes/ckeditor/_samples/jqueryadapter.html
  95. +275 −0 includes/ckeditor/_samples/output_for_flash.html
  96. +285 −0 includes/ckeditor/_samples/output_html.html
  97. +177 −0 includes/ckeditor/_samples/output_xhtml.html
  98. +120 −0 includes/ckeditor/_samples/php/advanced.php
  99. +153 −0 includes/ckeditor/_samples/php/events.php
  100. +47 −0 includes/ckeditor/_samples/php/index.html
  101. +87 −0 includes/ckeditor/_samples/php/replace.php
  102. +88 −0 includes/ckeditor/_samples/php/replaceall.php
  103. +83 −0 includes/ckeditor/_samples/php/standalone.php
  104. +81 −0 includes/ckeditor/_samples/placeholder.html
  105. +91 −0 includes/ckeditor/_samples/readonly.html
  106. +64 −0 includes/ckeditor/_samples/replacebyclass.html
  107. +97 −0 includes/ckeditor/_samples/replacebycode.html
  108. +163 −0 includes/ckeditor/_samples/sample.css
  109. +65 −0 includes/ckeditor/_samples/sample.js
  110. +21 −0 includes/ckeditor/_samples/sample_posteddata.php
  111. +153 −0 includes/ckeditor/_samples/sharedspaces.html
  112. +110 −0 includes/ckeditor/_samples/skins.html
  113. +93 −0 includes/ckeditor/_samples/stylesheetparser.html
  114. +115 −0 includes/ckeditor/_samples/tableresize.html
  115. +129 −0 includes/ckeditor/_samples/ui_color.html
  116. +134 −0 includes/ckeditor/_samples/ui_languages.html
  117. +306 −0 includes/ckeditor/_source/adapters/jquery.js
  118. +87 −0 includes/ckeditor/_source/core/_bootstrap.js
  119. +141 −0 includes/ckeditor/_source/core/ckeditor.js
  120. +227 −0 includes/ckeditor/_source/core/ckeditor_base.js
  121. +238 −0 includes/ckeditor/_source/core/ckeditor_basic.js
  122. +209 −0 includes/ckeditor/_source/core/command.js
  123. +129 −0 includes/ckeditor/_source/core/commanddefinition.js
  124. +439 −0 includes/ckeditor/_source/core/config.js
  125. +65 −0 includes/ckeditor/_source/core/dataprocessor.js
  126. +20 −0 includes/ckeditor/_source/core/dom.js
  127. +32 −0 includes/ckeditor/_source/core/dom/comment.js
  128. +251 −0 includes/ckeditor/_source/core/dom/document.js
  129. +49 −0 includes/ckeditor/_source/core/dom/documentfragment.js
  130. +258 −0 includes/ckeditor/_source/core/dom/domobject.js
  131. +1,691 −0 includes/ckeditor/_source/core/dom/element.js
  132. +119 −0 includes/ckeditor/_source/core/dom/elementpath.js
  133. +145 −0 includes/ckeditor/_source/core/dom/event.js
  134. +696 −0 includes/ckeditor/_source/core/dom/node.js
  135. +26 −0 includes/ckeditor/_source/core/dom/nodelist.js
  136. +2,054 −0 includes/ckeditor/_source/core/dom/range.js
  137. +213 −0 includes/ckeditor/_source/core/dom/rangelist.js
  138. +128 −0 includes/ckeditor/_source/core/dom/text.js
  139. +462 −0 includes/ckeditor/_source/core/dom/walker.js
  140. +96 −0 includes/ckeditor/_source/core/dom/window.js
  141. +266 −0 includes/ckeditor/_source/core/dtd.js
  142. +1,059 −0 includes/ckeditor/_source/core/editor.js
  143. +186 −0 includes/ckeditor/_source/core/editor_basic.js
  144. +305 −0 includes/ckeditor/_source/core/env.js
  145. +342 −0 includes/ckeditor/_source/core/event.js
  146. +120 −0 includes/ckeditor/_source/core/eventInfo.js
  147. +152 −0 includes/ckeditor/_source/core/focusmanager.js
  148. +224 −0 includes/ckeditor/_source/core/htmlparser.js
  149. +145 −0 includes/ckeditor/_source/core/htmlparser/basicwriter.js
  150. +43 −0 includes/ckeditor/_source/core/htmlparser/cdata.js
  151. +60 −0 includes/ckeditor/_source/core/htmlparser/comment.js
  152. +308 −0 includes/ckeditor/_source/core/htmlparser/element.js
  153. +288 −0 includes/ckeditor/_source/core/htmlparser/filter.js
  154. +518 −0 includes/ckeditor/_source/core/htmlparser/fragment.js
  155. +53 −0 includes/ckeditor/_source/core/htmlparser/text.js
  156. +157 −0 includes/ckeditor/_source/core/lang.js
  157. +240 −0 includes/ckeditor/_source/core/loader.js
  158. +83 −0 includes/ckeditor/_source/core/plugindefinition.js
  159. +103 −0 includes/ckeditor/_source/core/plugins.js
  160. +238 −0 includes/ckeditor/_source/core/resourcemanager.js
  161. +180 −0 includes/ckeditor/_source/core/scriptloader.js
  162. +184 −0 includes/ckeditor/_source/core/skins.js
  163. +19 −0 includes/ckeditor/_source/core/themes.js
  164. +763 −0 includes/ckeditor/_source/core/tools.js
  165. +128 −0 includes/ckeditor/_source/core/ui.js
  166. +84 −0 includes/ckeditor/_source/lang/_languages.js
  167. +61 −0 includes/ckeditor/_source/lang/_translationstatus.txt
  168. +815 −0 includes/ckeditor/_source/lang/af.js
  169. +815 −0 includes/ckeditor/_source/lang/ar.js
  170. +815 −0 includes/ckeditor/_source/lang/bg.js
  171. +815 −0 includes/ckeditor/_source/lang/bn.js
  172. +815 −0 includes/ckeditor/_source/lang/bs.js
  173. +815 −0 includes/ckeditor/_source/lang/ca.js
  174. +815 −0 includes/ckeditor/_source/lang/cs.js
  175. +815 −0 includes/ckeditor/_source/lang/cy.js
  176. +815 −0 includes/ckeditor/_source/lang/da.js
Sorry, we could not display the entire diff because too many files (722) changed.
View
9 .gitignore
@@ -0,0 +1,9 @@
+# Compiled source and other garbage #
+#####################################
+*.pyc
+*.swp
+
+# Directories with potential license restrictions that prevent re-distribution #
+################################################################################
+dictionaries/restricted/*
+tools/restricted/*
View
4 dictionaries/README
@@ -0,0 +1,4 @@
+Have a look at this for more background:
+
+http://pauldotcom.com/2011/08/dirbuster-to-burp-the-missing.html
+http://www.mavitunasecurity.com/blog/svn-digger-better-lists-for-forced-browsing/
View
80 dictionaries/update_convert_cms_explorer_dicts.sh
@@ -0,0 +1,80 @@
+#!/usr/bin/env bash
+# Description: This script grabs all the excellent CMS Explorer dictionaries, updates them and converts them into DirBuster format (much faster than CMS Explorer)
+#
+# owtf is an OWASP+PTES-focused try to unite great tools and facilitate pen testing
+# Copyright (c) 2011, Abraham Aranguren <name.surname@gmail.com> Twitter: @7a_ http://7-a.org
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the copyright owner nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+CMS_EXPLORER_DIR="/pentest/enumeration/web/cms-explorer" # Backtrack 5 location, you may need to change this
+CMS_DICTIONARIES_DIR="/root/owtf/dictionaries/restricted/cms" # CMS dictionaries location, you may need to change this
+
+DICTIONARIES="$CMS_EXPLORER_DIR/drupal_plugins.txt
+$CMS_EXPLORER_DIR/joomla_themes.txt
+$CMS_EXPLORER_DIR/wp_plugins.txt
+$CMS_EXPLORER_DIR/drupal_themes.txt
+$CMS_EXPLORER_DIR/wp_themes.txt
+$CMS_EXPLORER_DIR/joomla_plugins.txt"
+
+echo "[*] Going into directory: $CMS_EXPLORER_DIR"
+cd $CMS_EXPLORER_DIR
+echo "[*] Updating cms-explorer.pl dictionaries.."
+./cms-explorer.pl -update
+
+echo "[*] Going into directory: $CMS_DICTIONARIES_DIR"
+cd $CMS_DICTIONARIES_DIR
+
+echo "[*] Copying updated dictionaries from $CMS_EXPLORER_DIR to $CMS_DICTIONARIES_DIR"
+for i in $(echo $DICTIONARIES); do
+ cp $i $CMS_DICTIONARIES_DIR # echo "[*] Copying $i .."
+done
+
+DIRBUSTER_PREFIX="dir_buster"
+for cms in $(echo "drupal joomla wp"); do
+ mkdir -p $cms # Create CMS specific directory
+ rm -f $cms/* # Remove previous dictionaries
+ mv $cms* $cms 2> /dev/null # Move relevant dictionaries to directory, getting rid of "cannot move to myself" error, which is ok
+ cd $cms # Enter directory
+ for dict in $(ls); do # Now process each CMS-specific dictionary and convert it
+ cat $dict | tr '/' "\n" | sort -u > $DIRBUSTER_PREFIX.$dict # Convert to DirBuster format (i.e. get rid of the "/" and duplicate parent directories)
+ rm -f $dict # Remove since this only works with CMS explorer
+ done
+ # Create all-in-one CMS-specific dictionaries:
+ cat $DIRBUSTER_PREFIX* > $DIRBUSTER_PREFIX.all.$cms.txt
+ cd ..
+done
+
+echo "[*] Creating all-in-one CMS dictionaries for DirBuster and CMS Explorer"
+for bruteforcer in $(echo "$DIRBUSTER_PREFIX"); do
+ ALLINONE_DICT="$bruteforcer.all_in_one.txt"
+ rm -f $ALLINONE_DICT # Remove previous, potentially outdated all-in-one dict
+ for all_dict in $(find . -name *all*.txt | grep $bruteforcer); do
+ cat $all_dict >> $ALLINONE_DICT
+ done
+ cat $ALLINONE_DICT | sort -u > $ALLINONE_DICT.tmp # Remove duplicates, just in case
+ mv $ALLINONE_DICT.tmp $ALLINONE_DICT
+done
+
+echo "[*] Done!]"
View
48 framework/config/config.py
@@ -305,39 +305,29 @@ def GetTXTTransacLog(self, Partial = False):
def IsHostNameNOTIP(self):
return self.Get('HOST_NAME') != self.Get('HOST_IP') # Host
- def GetIPFromHostname(self, hostname):
- ip = ''
- try:
- socket.inet_pton(socket.AF_INET, hostname)
- ip = hostname
- except socket.error:
- # Check if it's an IPv6 address - not optimal
- # may be better to regex for : and decide
- # up front whether to check with AF_INET or AF_INET6
- try:
- socket.inet_pton(socket.AF_INET6, ip)
- ip = hostname
- except socket.error:
- # ideally we would not double up on this - wicky
- ip = socket.gethostbyname(hostname)
- else:
- ip = socket.gethostbyname(hostname)
-
- #ip=self.Core.Shell.shell_exec('host '+hostname+'|grep "has address"|cut -f4 -d" "')
- ipchunks = ip.strip().split("\n")
+ def GetIPFromHostname(self, Hostname):
+ IP = ''
+ for Socket in [ socket.AF_INET, socket.AF_INET6 ]: # IP validation based on @marcwickenden's pull request, thanks!
+ try:
+ socket.inet_pton(Socket, Hostname)
+ IP = Hostname
+ break
+ except socket.error: continue
+ if not IP:
+ try: IP = socket.gethostbyname(Hostname)
+ except socket.gaierror: self.Core.Error.FrameworkAbort("Cannot resolve Hostname: "+Hostname)
+
+ ipchunks = IP.strip().split("\n")
AlternativeIPs = []
if len(ipchunks) > 1:
- ip = ipchunks[0]
- cprint(hostname+" has several IP addresses: ("+", ".join(ipchunks)[0:-3]+"). Choosing first: "+ip+"")
+ IP = ipchunks[0]
+ cprint(Hostname+" has several IP addresses: ("+", ".join(ipchunks)[0:-3]+"). Choosing first: "+IP+"")
AlternativeIPs = ipchunks[1:]
self.Set('ALTERNATIVE_IPS', AlternativeIPs)
- ip = ip.strip()
- if len(ip.split('.')) != 4: # TODO: Add IPv6 support!
- self.Core.Error.FrameworkAbort("Cannot resolve hostname: "+hostname)
- # Good IPv4 IP
- self.Set('INTERNAL_IP', self.Core.IsIPInternal(ip))
- cprint("The IP address for "+hostname+" is: '"+ip+"'")
- return ip
+ IP = IP.strip()
+ self.Set('INTERNAL_IP', self.Core.IsIPInternal(IP))
+ cprint("The IP address for "+Hostname+" is: '"+IP+"'")
+ return IP
def GetAll(self, Key): # Retrieves a config setting value on all target configurations
Matches = []
View
BIN  framework/config/config.pyc
Binary file not shown
View
8 framework/config/framework_config.cfg
@@ -1,4 +1,4 @@
-VERSION: 0.11 "Vienna"
+VERSION: 0.12 "Wicky"
INSTALL_SCRIPT: @@@FRAMEWORK_DIR@@@/install.sh
WEB_TEST_GROUPS: @@@FRAMEWORK_DIR@@@/framework/config/web_testgroups.cfg
@@ -45,11 +45,15 @@ RESPONSE_REGEXP_FOR_SSI: Server Side Includes_____<!--#_____(<!--(#.*)?-->)
# The following icons _must_ exist, but you can change the icon if you wish
# WARNING!!!: The following icons are best kept as they are, if a new icon is wanted it should have the same name (at least for now):
+#FIXED_ICON_MATCHES: shopping_cart
+FIXED_ICON_MATCHES: target
FIXED_ICON_INFO: info
+FIXED_ICON_PLUGIN_INFO: info24x24
FIXED_ICON_NOFLAG: envelope
FIXED_ICON_UNSTRIKETHROUGH: eraser
FIXED_ICON_STRICKETHROUGH: pencil
FIXED_ICON_NOTES: lamp_active
FIXED_ICON_REMOVE: delete
FIXED_ICON_REFRESH: refresh
-COLLAPSED_REPORT_SIZE: 90
+FIXED_ICON_OPTIONS: options
+COLLAPSED_REPORT_SIZE: 64
View
BIN  framework/config/health_check.pyc
Binary file not shown
View
2  framework/config/plugin.py
@@ -46,7 +46,7 @@ def GetTypesForGroup(self, PluginGroup):
PluginTypes = []
for PluginType, Plugins in self.AllPlugins[PluginGroup].items():
PluginTypes.append(PluginType)
- return PluginTypes
+ return sorted(PluginTypes) # Return list in alphabetical order
def GetAllTypes(self):
AllPluginTypes = []
View
BIN  framework/config/plugin.pyc
Binary file not shown
View
BIN  framework/db/db.pyc
Binary file not shown
View
22 framework/db/plugin_register.py
@@ -34,15 +34,16 @@
# Start, End, Runtime, Command, LogStatus = self.Core.DB.DBCache['RUN_DB'][-1]#.split(" | ")
CODE = 0
TYPE = 1
-PATH = 2
-TARGET = 3 # The same plugin and type can be run against different targets, they should have different paths, but we need the target to get the right codes in the report
-ARGS = 4 # Auxiliary plugins have metasploit-like arguments
-REVIEW_OFFSET = 5
-START = 6
-END = 7
-RUNTIME = 8
+GROUP = 2
+PATH = 3
+TARGET = 4 # The same plugin and type can be run against different targets, they should have different paths, but we need the target to get the right codes in the report
+ARGS = 5 # Auxiliary plugins have metasploit-like arguments
+REVIEW_OFFSET = 6
+START = 7
+END = 8
+RUNTIME = 9
-NAME_TO_OFFSET = { 'Code' : CODE, 'Type' : TYPE, 'Path' : PATH, 'Target' : TARGET, 'Args' : ARGS, 'ReviewOffset' : REVIEW_OFFSET, 'Start' : START, 'End' : END, 'RunTime' : RUNTIME }
+NAME_TO_OFFSET = { 'Code' : CODE, 'Type' : TYPE, 'Group' : GROUP, 'Path' : PATH, 'Target' : TARGET, 'Args' : ARGS, 'ReviewOffset' : REVIEW_OFFSET, 'Start' : START, 'End' : END, 'RunTime' : RUNTIME }
class PluginRegister:
def __init__(self, Core):
@@ -56,7 +57,10 @@ def AlreadyRegistered(self, Plugin, Path, Target):
def Add(self, Plugin, Path, Target): # Registers a Plugin/Path/Target combination only if not already registered
if not self.AlreadyRegistered(Plugin, Path, Target):
- self.Core.DB.Add('PLUGIN_REPORT_REGISTER', [ Plugin['Code'], Plugin['Type'], Path, Target, Plugin['Args'], self.Core.Config.Get('REVIEW_OFFSET'), Plugin['Start'], Plugin['End'], Plugin['RunTime'] ] )
+ if 'RunTime' not in Plugin:
+ Plugin['RunTime'] = self.Core.Timer.GetElapsedTimeAsStr('Plugin')
+ Plugin['End'] = self.Core.Timer.GetEndDateTimeAsStr('Plugin')
+ self.Core.DB.Add('PLUGIN_REPORT_REGISTER', [ Plugin['Code'], Plugin['Type'], Plugin['Group'], Path, Target, Plugin['Args'], self.Core.Config.Get('REVIEW_OFFSET'), Plugin['Start'], Plugin['End'], Plugin['RunTime'] ] )
def Search(self, Criteria):
return self.Core.DB.Search('PLUGIN_REPORT_REGISTER', Criteria, NAME_TO_OFFSET)
View
BIN  framework/db/plugin_register.pyc
Binary file not shown
View
1  framework/db/transaction_manager.py
@@ -287,4 +287,3 @@ def GrepMultiLineResponseRegexp(self, ResponseRegexp):
return [ Command, RegexpName, Matches ] # Return All matches and the file they were retrieved from
else: # wtf?
raise PluginAbortException("ERROR: Inforrect Configuration setting for Response Regexp: '"+str(ResponseRegexp)+"'")
-
View
BIN  framework/db/transaction_manager.pyc
Binary file not shown
View
2  framework/http/requester.py
@@ -128,7 +128,7 @@ def StringToDict(self, String):
Dict = defaultdict(list)
Count = 0
PrevItem = ''
- for Item in String.split('='):
+ for Item in String.strip().split('='):
if Count % 2 == 1: # Key
Dict[PrevItem] = Item
else: # Value
View
BIN  framework/http/requester.pyc
Binary file not shown
View
4 framework/plugin/plugin_handler.py
@@ -210,8 +210,6 @@ def GetPluginFullPath(self, PluginDir, Plugin):
return PluginDir+"/"+Plugin['Type']+"/"+Plugin['File'] # Path to run the plugin
def RunPlugin(self, PluginDir, Plugin):
- self.Core.Timer.StartTimer('Plugin') # Time how long it takes the plugin to execute
- Plugin['Start'] = self.Core.Timer.GetStartDateTimeAsStr('Plugin')
PluginPath = self.GetPluginFullPath(PluginDir, Plugin)
(Path, Name) = os.path.split(PluginPath)
#(Name, Ext) = os.path.splitext(Name)
@@ -220,6 +218,8 @@ def RunPlugin(self, PluginDir, Plugin):
self.SavePluginInfo(PluginOutput, Plugin) # Timer retrieved here
def ProcessPlugin(self, PluginDir, Plugin, Status):
+ self.Core.Timer.StartTimer('Plugin') # Time how long it takes the plugin to execute
+ Plugin['Start'] = self.Core.Timer.GetStartDateTimeAsStr('Plugin')
if not self.CanPluginRun(Plugin, True):
return None # Skip
Status['AllSkipped'] = False # A plugin is going to be run
View
BIN  framework/plugin/plugin_handler.pyc
Binary file not shown
View
53 framework/plugin/plugin_helper.py
@@ -53,22 +53,49 @@ def DrawLinkList(self, LinkListName, Links): # Wrapper to allow rendering a bunc
def DrawResourceLinkList(self, ResourceListName, ResourceList): # Draws an HTML Search box for defined Vuln Search resources
LinkList = []
- List = []
+ HTMLLinkList = []
for Name, Resource in ResourceList:
URL = MultipleReplace(Resource.strip(), self.Core.Config.GetReplacementDict()).replace('"', '%22')
- #URL = Resource.replace('@@@PLACE_HOLDER@@@', self.Core.Config.Get('HOST_NAME')).strip()
LinkList.append(URL)
cprint("Generating link for "+Name+"..") # Otherwise there would be a lovely python exception and we would not be here :)
- #List += '<li>'+self.Core.Reporter.Render.DrawButtonLink(Name, URL)+"</li>\n"
- List.append(self.Core.Reporter.Render.DrawButtonLink(Name, URL))
- #List += '</ul>'
+ HTMLLinkList.append(self.Core.Reporter.Render.DrawButtonLink(Name, URL))
+ return self.DrawListPostProcessing(ResourceListName, LinkList, HTMLLinkList)
+
+ def DrawListPostProcessing(self, ResourceListName, LinkList, HTMLLinkList):
Content = '<hr />'+ResourceListName+': '
if len(LinkList) > 1: # Open All In Tabs only makes sense if num items > 1
Content += self.Core.Reporter.Render.DrawButton('Open All In Tabs', "OpenAllInTabs(new Array('"+"','".join(LinkList)+"'))")
- #Content += '<br /><ul>\n'+List
- Content += self.Core.Reporter.Render.DrawHTMLList(List)
+ Content += self.Core.Reporter.Render.DrawHTMLList(HTMLLinkList)
return Content
+ def RequestAndDrawLinkList(self, ResourceListName, ResourceList, PluginInfo):
+ #for Name, Resource in Core.Config.GetResources('PassiveRobotsAnalysisHTTPRequests'):
+ LinkList = []
+ HTMLLinkList = []
+ for Name, Resource in ResourceList:
+ Chunks = Resource.split('###POST###')
+ URL = Chunks[0]
+ POST = None
+ Method = 'GET'
+ if len(Chunks) > 1: # POST
+ Method = 'POST'
+ POST = Chunks[1]
+ Transaction = self.Core.Requester.GetTransaction(True, URL, Method, POST)
+ if Transaction.Found:
+ Path, HTMLLink = self.SaveSandboxedTransactionHTML(Name, Transaction, PluginInfo)
+ HTMLLinkList.append(HTMLLink)
+ LinkList.append(Path)
+ return self.DrawListPostProcessing(ResourceListName, LinkList, HTMLLinkList)
+
+ def SaveSandboxedTransactionHTML(self, Name, Transaction, PluginInfo): # 1st filters HTML, 2nd builds sandboxed iframe, 3rd give link to sandboxed content
+ RawHTML = Transaction.GetRawResponseBody()
+ #print "RawHTML="+RawHTML
+ FilteredHTML = self.Core.Reporter.Sanitiser.CleanThirdPartyHTML(RawHTML)
+ #print "FilteredHTML="+FilteredHTML
+ NotSandboxedPath, Discarded = self.DumpFile("NOT_SANDBOXED_"+Name+".html", FilteredHTML, PluginInfo, Name)
+ SandboxedPath, HTMLLink = self.DumpFile("SANDBOXED_"+Name+".html", self.Core.Reporter.Render.DrawiFrame( { 'src' : NotSandboxedPath.split('/')[-1], 'sandbox' : '', 'security' : 'restricted', 'width' : '100%', 'height' : '100%', 'frameborder' : '0', 'style' : "overflow-y:auto; overflow-x:hidden;" } ), PluginInfo, Name)
+ return [ SandboxedPath, HTMLLink ]
+
def DrawVulnerabilitySearchBox(self, SearchStr): # Draws an HTML Search box for defined Vuln Search resources
ProductId = 'prod'+self.Core.DB.GetNextHTMLID() # Keep product id unique among different search boxes (so that Javascript works)
Count = 0
@@ -222,15 +249,15 @@ def DrawCommandDump(self, CommandIntro, OutputIntro, ResourceList, PluginInfo, P
raise FrameworkAbortException(PreviousOutput+Content)
return Content
- def DumpFile(self, Filename, Contents, PluginInfo):
+ def DumpFile(self, Filename, Contents, PluginInfo, LinkName = ''):
save_path = self.Core.PluginHandler.DumpPluginFile(Filename, Contents, PluginInfo)
+ if not LinkName:
+ LinkName = save_path
cprint("File: "+Filename+" saved to: "+save_path)
- return [ save_path, '<br />Saved to: '+self.Core.Reporter.Render.DrawButtonLink(save_path, save_path, {}, True) ]
+ return [ save_path, self.Core.Reporter.Render.DrawButtonLink(LinkName, save_path, {}, True) ]
- def DumpFileGetLink(self, Filename, Contents, PluginInfo, LinkName):
- save_path = self.Core.PluginHandler.DumpPluginFile(Filename, Contents, PluginInfo)
- cprint("File: "+Filename+" saved to: "+save_path)
- return self.Core.Reporter.Render.DrawButtonLink(LinkName, save_path, {}, True)
+ def DumpFileGetLink(self, Filename, Contents, PluginInfo, LinkName = ''):
+ return self.DumpFile(Filename, Contents, PluginInfo, LinkName)[0]
def AnalyseRobotsEntries(self, Contents): # Find the entries of each kind and count them
num_lines = len(Contents.split("\n")) # Total number of robots.txt entries
View
BIN  framework/plugin/plugin_helper.pyc
Binary file not shown
View
34 framework/report/header.py
@@ -108,7 +108,7 @@ def DrawURLDBs(self, DBPrefix = ""):
], 'DrawButtonLink', {})
def DrawFilters(self):
- return self.Core.Reporter.DrawCounters(True)
+ return self.Core.Reporter.DrawCounters(self.ReportType)
def AddMiscelaneousTabs(self, Tabs):
Tabs.AddCustomDiv('Miscelaneous:') # First create custom tab, without javascript
@@ -120,20 +120,12 @@ def AddMiscelaneousTabs(self, Tabs):
def DrawOWTFBox(self):
OWTF = self.Core.Reporter.Render.CreateTable( { 'class' : 'report_intro' } )
OWTF.CreateRow( [ 'Seed', 'Review Size', 'Total Size', 'Version', 'Site' ], True)
- OWTF.CreateRow( [ '<span id="seed">'+self.Core.GetSeed()+'</span>', '<div id="js_db_size"></div>', '<div id="total_js_db_size"></div>', self.Version, self.Core.Reporter.Render.DrawButtonLink('owtf.org', 'http://owtf.org') ] )
+ OWTF.CreateRow( [ '<span id="seed">'+self.Core.GetSeed()+'</span>', '<div id="js_db_size" style="float:left; display: inline; padding-top: 7px"></div><div style="float:right; inline">'+ self.Core.Reporter.DrawHelpLink('ReviewSize')+"</div>", '<div id="total_js_db_size"></div>', self.Version, self.Core.Reporter.Render.DrawButtonLink('owtf.org', 'http://owtf.org') ] )
return '<div style="position: absolute; top: 6px; right: 6px; float: right">'+OWTF.Render()+'</div>'
def DrawBackToSummaryIcon(self):
return self.Core.Reporter.Render.DrawLink(self.Core.Reporter.DrawImageFromConfigPair( [ 'FIXED_ICON_TO_SUMMARY', 'NAV_TOOLTIP_TO_SUMMARY' ] ), self.Core.Config.Get('HTML_REPORT'), { 'target' : '' } )
- def ExpandDetailedReportJS(self):
- return "window.parent.document.getElementById('iframe_"+self.Core.Config.Get('REVIEW_OFFSET')+"').style.height = '100%';"
- def CollapseDetailedReportJS(self):
- return "var iframe = window.parent.document.getElementById('iframe_"+self.Core.Config.Get('REVIEW_OFFSET')+"'); iframe.style.height = '"+self.Core.Config.Get('COLLAPSED_REPORT_SIZE')+"'; window.location.hash = ''; window.parent.location.hash = '';"
-
- def AnalyseDetailedReportJS(self):
- return self.ExpandDetailedReportJS() + "window.parent.location.hash = 'anchor_"+self.Core.Config.Get('REVIEW_OFFSET')+"';"
-
def DrawURLTop(self, Embed = ''):
AlternativeIPsStr = ""
if len(self.AlternativeIPs) > 0:
@@ -142,13 +134,14 @@ def DrawURLTop(self, Embed = ''):
# Target.CreateRow( [ 'Target URL', 'Target IP(s)', '&nbsp;' ], True)
# Target.CreateRow( [ self.Core.Reporter.Render.DrawButtonLink(self.TargetURL, self.TargetURL, {'id' : 'target_url'}), self.HostIP+AlternativeIPsStr, self.DrawBackToSummaryIcon() ] )
Icons = "&nbsp;" * 1 + ("&nbsp;" * 1).join(self.Core.Reporter.Render.DrawLinkPairs( [
-[ self.Core.Reporter.DrawImageFromConfigPair( [ 'FIXED_ICON_ANALYSE_REPORT', 'NAV_TOOLTIP_ANALYSE_REPORT' ]), self.AnalyseDetailedReportJS() ],
-[ self.Core.Reporter.DrawImageFromConfigPair( [ 'FIXED_ICON_EXPAND_REPORT', 'NAV_TOOLTIP_EXPAND_REPORT' ]), self.ExpandDetailedReportJS() ],[ self.Core.Reporter.DrawImageFromConfigPair( [ 'FIXED_ICON_CLOSE_REPORT', 'NAV_TOOLTIP_CLOSE_REPORT' ]), self.CollapseDetailedReportJS() ] ], 'DrawButtonJSLink', { 'class' : 'icon' }))
- Target.CreateCustomRow('<tr><th>'+self.Core.Reporter.Render.DrawButtonLink(self.TargetURL, self.TargetURL, {'id' : 'target_url'})+'</th><td>'+self.HostIP+AlternativeIPsStr+'</td><td class="disguise">'+Icons+'</td></tr>')
+[ self.Core.Reporter.DrawImageFromConfigPair( [ 'FIXED_ICON_GENERATE_REPORT', 'NAV_TOOLTIP_GENERATE_REPORT' ]), "ToggleReportMode()" ],
+[ self.Core.Reporter.DrawImageFromConfigPair( [ 'FIXED_ICON_ANALYSE_REPORT', 'NAV_TOOLTIP_ANALYSE_REPORT' ]), "DetailedReportAnalyse()" ],
+[ self.Core.Reporter.DrawImageFromConfigPair( [ 'FIXED_ICON_EXPAND_REPORT', 'NAV_TOOLTIP_EXPAND_REPORT' ]), 'DetailedReportAdjust()' ], [ self.Core.Reporter.DrawImageFromConfigPair( [ 'FIXED_ICON_CLOSE_REPORT', 'NAV_TOOLTIP_CLOSE_REPORT' ]), 'DetailedReportCollapse()' ] ], 'DrawButtonJSLink', { 'class' : 'icon' }))
+ Target.CreateCustomRow('<tr><th>'+self.Core.Reporter.Render.DrawButtonLink(self.TargetURL, self.TargetURL, {'id' : 'target_url'})+'</th><td>'+cgi.escape(self.HostIP+AlternativeIPsStr)+'</td><td>' + cgi.escape(self.PortNumber) + '</td><td class="disguise">'+Icons+'</td></tr>')
#<td class="disguise">'+Embed+'</td>
#return '<div style="display:inline; align:left; position:fixed; top:0px; z-index:0; opacity:1; background-color:red; width:100%;">'+self.WrapTop(Target.Render())
Content = Target.Render() + '<div style="position: absolute; top: 6px; right: 6px; float: right;">'+Embed+'</div>'
- return '<div class="detailed_report">'+self.WrapTop(Content)+'</div>' + '<br />' * 2
+ return '<div class="detailed_report" style="display: inline; float:left">'+self.WrapTop(Content)+'</div>'+'<div class="iframe_padding"></div>'
#return self.WrapTop(Target.Render())
def WrapTop(self, LeftBoxStr):
@@ -164,7 +157,8 @@ def DrawTop(self, Embed = ''):
if self.ReportType == 'URL':
return self.DrawURLTop(Embed)
elif self.ReportType == 'NetMap':
- return self.WrapTop('<h2>Summary Report</h2><br />')
+ return self.WrapTop('<h2>Summary Report</h2>')
+ #return self.WrapTop('<h2>Summary Report</h2><div class="iframe_padding"></div>')
elif self.ReportType == 'AUX':
return self.WrapTop('<h2>Auxiliary Plugins '+self.DrawBackToSummaryIcon()+'</h2>')
@@ -175,7 +169,7 @@ def GetJavaScriptStorage(self): # Loads the appropriate JavaScript library files
return "\n".join(Libraries)
def Save(self, Report, Options):
- self.TargetOutputDir, self.FrameworkDir, self.Version, self.TargetURL, self.HostIP, self.TransactionLogHTML, self.AlternativeIPs = self.Core.Config.GetAsList(['OUTPUT_PATH', 'FRAMEWORK_DIR', 'VERSION', 'TARGET_URL', 'HOST_IP', 'TRANSACTION_LOG_HTML', 'ALTERNATIVE_IPS'])
+ self.TargetOutputDir, self.FrameworkDir, self.Version, self.TargetURL, self.HostIP, self.PortNumber, self.TransactionLogHTML, self.AlternativeIPs = self.Core.Config.GetAsList(['OUTPUT_PATH', 'FRAMEWORK_DIR', 'VERSION', 'TARGET_URL', 'HOST_IP', 'PORT_NUMBER', 'TRANSACTION_LOG_HTML', 'ALTERNATIVE_IPS'])
self.ReportType = Options['ReportType']
if not self.Init:
self.CopyAccessoryFiles()
@@ -220,8 +214,12 @@ def Save(self, Report, Options):
"""+RenderTopStr+"""
"""+TabsStr+"""
<script type="text/javascript" src="includes/jquery-1.6.4.js"></script>\n
-<script type="text/javascript" src="includes/owtf.js"></script>\n
+<script type="text/javascript" src="includes/owtf_general.js"></script>\n
+<script type="text/javascript" src="includes/owtf_review.js"></script>\n
+<script type="text/javascript" src="includes/owtf_filter.js"></script>\n
+<script type="text/javascript" src="includes/owtf_reporting.js"></script>\n
<script type="text/javascript" src="includes/jsonStringify.js"></script>\n
+<script type="text/javascript" src="includes/ckeditor/ckeditor.js"></script>
+<script type="text/javascript" src="includes/ckeditor/adapters/jquery.js"></script>
"""+self.GetJavaScriptStorage()+"""
""") # Init HTML Report
-
View
BIN  framework/report/header.pyc
Binary file not shown
View
0  framework/report/html/filter/__init__.py
No changes.
View
1  framework/report/html/filter/bypasses/basic.txt
@@ -0,0 +1 @@
+<a href="javascript:alert(1)">⃒<h1>CLICKME
View
1  framework/report/html/filter/bypasses/basic2.txt
@@ -0,0 +1 @@
+<a href="javascript:alert(1)">
View
1  framework/report/html/filter/bypasses/css_bypass.txt
@@ -0,0 +1 @@
+<style>*{x=expression\28write\28 1\29\29}</style>
View
1  framework/report/html/filter/bypasses/css_bypass2.txt
@@ -0,0 +1 @@
+<style>@\import "data:,*%7bx:expression%28write%281%29%29%7D";</style>
View
1  framework/report/html/filter/bypasses/href.txt
@@ -0,0 +1 @@
+<a href="data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20standalone%3D%22no%22%3F%3E%0A%3C%21DOCTYPE%20svg%20PUBLIC%20%22-%2f%2fW3C%2f%2fDTD%20SVG%201.1%2f%2fEN%22%20%0A%20%20%22http%3A%2f%2fwww.w3.org%2fGraphics%2fSVG%2f1.1%2fDTD%2fsvg11.dtd%22%3E%0A%3Csvg%20width%3D%224in%22%20height%3D%224in%22%20id%3D%22the_svg%22%0A%20%20%20%20%20viewBox%3D%220%200%204%204%22%20version%3D%221.1%22%0A%20%20%20%20%20xmlns%3D%22http%3A%2f%2fwww.w3.org%2f2000%2fsvg%22%3E%0A%09%3Ccircle%20cx%3D%221%22%20cy%3D%221%22%20r%3D%221%22%20fill%3D%22blue%22%20stroke%3D%22none%22%20id%3D%22the_circle%22%2f%3E%0A%20%20%20%3Cscript%20type%3D%22text%2fecmascript%22%3E%0A%20%20%20%3C%21%5BCDATA%5B%0A%20%20%20%5D%5D%3E%0Aalert%281%29%3B%0A%20%20%3C%2fscript%3E%0A%3C%2fsvg%3E">Click</a>
View
1  framework/report/html/filter/bypasses/href2.txt
@@ -0,0 +1 @@
+<a href='feed:data:x,123456'>Click</a>
View
1  framework/report/html/filter/bypasses/malformed.txt
@@ -0,0 +1 @@
+<junk1:junk2:script>alert(1)</junk3>
View
101 framework/report/html/filter/sanitiser.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+'''
+owtf is an OWASP+PTES-focused try to unite great tools and facilitate pen testing
+Copyright (c) 2011, Abraham Aranguren <name.surname@gmail.com> Twitter: @7a_ http://7-a.org
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the copyright owner nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The sanitiser module allows the rest of the framework to sanitise input
+Requires lxml, installation instructions here: http://lxml.de/installation.html
+In Backtrack 5: /usr/bin/easy_install --allow-hosts=lxml.de,*.python.org lxml
+Tip for Ubuntu courtesy of Mario Heiderich: Python2.7-dev is needed to compile this lib properly
+Clean HTML reference: http://lxml.de/lxmlhtml.html#cleaning-up-html
+Library documentation: http://lxml.de/api/lxml.html.clean.Cleaner-class.html
+'''
+import sys
+from lxml.html.clean import Cleaner, clean_html
+import lxml.html
+from urlparse import urlparse
+ALLOWED_TAGS = ('html', 'body', 'a', 'p', 'h1', 'h2', 'h3', 'h4', 'div', 'span', 'i', 'b', 'u', 'table', 'tbody', 'tr', 'td', 'th', 'strong', 'em', 'sup', 'sub', 'ul', 'ol', 'li')
+ALLOWED_URL_SCHEMES = [ 'http', 'https', 'ftp', 'mailto', 'sftp', 'shttp' ]
+
+class HTMLSanitiser:
+ def __init__(self):
+ self.Cleaner = Cleaner(scripts = False, javascript = False, comments = False, links = False, meta = True, page_structure = False, processing_instructions = False, embedded = False, frames = False, forms = False, annoying_tags = False, remove_unknown_tags = False, safe_attrs_only = True, allow_tags=ALLOWED_TAGS)
+ #self.Cleaner = Cleaner(allow_tags=ALLOWED_TAGS, remove_unknown_tags=False)
+
+ def IsValidURL(self, URL):
+ ParsedURL = urlparse(URL)
+ return (ParsedURL.scheme in ALLOWED_URL_SCHEMES)
+
+ def CleanURLs(self, HTML):
+ # Largely Inspired from: http://stackoverflow.com/questions/5789127/how-to-replace-links-using-lxml-and-iterlinks
+ ParsedHTML = lxml.html.document_fromstring(HTML)
+ #print dir(ParsedHTML)
+ #'iter', 'iterancestors', 'iterchildren'
+ #for Element in ParsedHTML.iterchildren():
+ # print dir(Element)
+ # print Element.tag
+ for Element, Attribute, Link, Pos in ParsedHTML.iterlinks():
+ if not self.IsValidURL(Link):
+ Element.set(Attribute, Link.replace(Link, ''))
+ return lxml.html.tostring(ParsedHTML)
+
+ def CleanThirdPartyHTML(self, HTML):
+ # 1st clean URLs, 2nd get rid of basics, 3rd apply white list
+ return self.Cleaner.clean_html(clean_html(self.CleanURLs(HTML)))
+
+ def TestPrint(self, TestInfo, TestOutput):
+ TestInfo += "_" * (60 - len(TestInfo)) # Make info visually easier to compare
+ print TestInfo + TestOutput
+
+# For testing as a standalone script:
+if 'sanitiser.py' in sys.argv[0]: # When called as a script run tests
+ Sanitiser = HTMLSanitiser()
+ Input = sys.stdin.read() # Read for stdin so that we can cat whatever | sanitiser => easier to test in bulk
+ Sanitiser.TestPrint("raw input=", Input)
+ Sanitiser.TestPrint("Filter 1 - clean_html=", clean_html(Input))
+ Sanitiser.TestPrint("Filter 2 - white_list=", Sanitiser.Cleaner.clean_html(Input))
+ Sanitiser.TestPrint("Filter 3 - clean_html(white_list) =", clean_html(Sanitiser.Cleaner.clean_html(Input)))
+ Sanitiser.TestPrint("Filter 4 = cleanURLs(clean_html(white_list)) =", Sanitiser.CleanURLs(clean_html(Sanitiser.Cleaner.clean_html(Input))))
+ Sanitiser.TestPrint("Filter 5 = cleanURLs(white_list(clean_html)) =", Sanitiser.CleanURLs(Sanitiser.Cleaner.clean_html(clean_html(Input))))
+ Sanitiser.TestPrint("Filter 6 = white_list(clean_html(cleanURLs))", Sanitiser.Cleaner.clean_html(clean_html(Sanitiser.CleanURLs(Input))))
+ Sanitiser.TestPrint("Latest - Step 1 - CleanURLs =", Sanitiser.CleanURLs(Input))
+ Sanitiser.TestPrint("Latest - Step 2 - clean_html(CleanURLs) =", clean_html(Sanitiser.CleanURLs(Input)))
+ Sanitiser.TestPrint("Latest - Step 3 - white_list(clean_html(CleanURLs)) =", Sanitiser.CleanThirdPartyHTML(Input))
+"""
+#WIP below
+, remove_tags = None
+hash(x)
+ allow_tags = None
+hash(x)
+ kill_tags = None
+hash(x)
+ remove_unknown_tags = True
+ safe_attrs_only = True
+ add_nofollow = False
+ host_whitelist = ()
+ whitelist_tags = set(['embed', 'iframe'])
+ _tag_link_attrs = {'a': 'href', 'applet': ['code', 'object'],
+"""
View
1  framework/report/html/filter/test_malformed/malformed.txt
@@ -0,0 +1 @@
+<junk1:junk2:script>alert(1)</junk3>
View
1  framework/report/html/filter/test_malformed/malformed2.txt
@@ -0,0 +1 @@
+<junk1:script>alert(1)</junk2>
View
1  framework/report/html/filter/test_malformed/malformed3.txt
@@ -0,0 +1 @@
+<junk1:junk2:junk3:script>alert(1)</junk4>
View
1  framework/report/html/filter/test_malformed/malformed4.txt
@@ -0,0 +1 @@
+<junk1:junk2:junk3:junk4:script>alert(1)</junk5>
View
1  framework/report/html/filter/test_malformed/malformed5.txt
@@ -0,0 +1 @@
+<junk1:junk2:junk3:junk4:junk5:script>alert(1)</junk6>
View
1  framework/report/html/filter/test_malformed/malformed6.txt
@@ -0,0 +1 @@
+<junk1:junk2:junk3:junk4:junk5:junk6:script>alert(1)</junk7>
View
41 framework/report/html/filter/test_sanitiser.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+#
+# owtf is an OWASP+PTES-focused try to unite great tools and facilitate pen testing
+# Copyright (c) 2011, Abraham Aranguren <name.surname@gmail.com> Twitter: @7a_ http://7-a.org
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the copyright owner nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+if [ $# -ne 1 ]; then
+ echo "Syntax $0 <test directory>"
+ exit
+fi
+
+DIR=$1
+for file in $(ls $DIR); do
+ echo "TESTING: $file"
+ cat $DIR/$file | ./sanitiser.py
+ echo "press Enter to continue"
+ read key
+done
View
167 framework/report/html/filter/test_valid/legitimate_robots.txt
@@ -0,0 +1,167 @@
+<title>New Robots.txt Syntax Checker: a validator for robots.txt files</title>
+<meta name="description" content="If you care about validation, this robots.txt validator is a tester that will check your robots.txt file searching for syntax errors">
+<meta name="keywords" content="robots.txt validator,analyzer,checker">
+<link rel="StyleSheet" href="robots-style.css" type="text/css">
+<script language="javascript" type="text/javascript">
+function swap() {
+ if (document.getElementsByTagName) {
+ for (i=0; i < document.getElementsByTagName("TR").length; i++) {
+ if (document.getElementsByTagName("TR")[i].className == "off") {
+ document.getElementsByTagName("TR")[i].className = "on";
+ } else {
+ if (document.getElementsByTagName("TR")[i].className == "on") {
+ document.getElementsByTagName("TR")[i].className = "off";
+ }
+ }
+ }
+ }
+}
+</script>
+
+
+
+
+
+<h3>Analyzing file http://hackademic1.teilar.gr/robots.txt</h3>
+<h3>No errors found in this robots.txt file</h3><p align="CENTER">Hide empty and comments lines: <input name="hide" onclick="swap()" type="CHECKBOX">
+
+</p><p><table class="report" align="CENTER" width="80%">
+<tbody><tr>
+<td colspan="2">The following block of code <span class="red">DISALLOWS</span> the crawling of the following files and directories: <b> /administrator/ /cache/ /components/ /images/ /includes/ /installation/ /language/ /libraries/ /media/ /modules/ /plugins/ /templates/ /tmp/ /xmlrpc/ </b> to <b>all spiders/robots</b>. </td>
+</tr>
+<tr>
+<td align="RIGHT" valign="TOP"><span class="nowrap">Line 1</span></td>
+<td width="100%"><span class="code">User-agent: *</span></td>
+</tr>
+<tr>
+<td align="RIGHT" valign="TOP"><span class="nowrap">Line 2</span></td>
+<td width="100%"><span class="code">Disallow: /administrator/</span></td>
+</tr>
+<tr>
+<td align="RIGHT" valign="TOP"><span class="nowrap">Line 3</span></td>
+<td width="100%"><span class="code">Disallow: /cache/</span></td>
+</tr>
+<tr>
+<td align="RIGHT" valign="TOP"><span class="nowrap">Line 4</span></td>
+<td width="100%"><span class="code">Disallow: /components/</span></td>
+</tr>
+<tr>
+<td align="RIGHT" valign="TOP"><span class="nowrap">Line 5</span></td>
+<td width="100%"><span class="code">Disallow: /images/</span></td>
+</tr>
+<tr>
+<td align="RIGHT" valign="TOP"><span class="nowrap">Line 6</span></td>
+<td width="100%"><span class="code">Disallow: /includes/</span></td>
+</tr>
+<tr>
+<td align="RIGHT" valign="TOP"><span class="nowrap">Line 7</span></td>
+<td width="100%"><span class="code">Disallow: /installation/</span></td>
+</tr>
+<tr>
+<td align="RIGHT" valign="TOP"><span class="nowrap">Line 8</span></td>
+<td width="100%"><span class="code">Disallow: /language/</span></td>
+</tr>
+<tr>
+<td align="RIGHT" valign="TOP"><span class="nowrap">Line 9</span></td>
+<td width="100%"><span class="code">Disallow: /libraries/</span></td>
+</tr>
+<tr>
+<td align="RIGHT" valign="TOP"><span class="nowrap">Line 10</span></td>
+<td width="100%"><span class="code">Disallow: /media/</span></td>
+</tr>
+<tr>
+<td align="RIGHT" valign="TOP"><span class="nowrap">Line 11</span></td>
+<td width="100%"><span class="code">Disallow: /modules/</span></td>
+</tr>
+<tr>
+<td align="RIGHT" valign="TOP"><span class="nowrap">Line 12</span></td>
+<td width="100%"><span class="code">Disallow: /plugins/</span></td>
+</tr>
+<tr>
+<td align="RIGHT" valign="TOP"><span class="nowrap">Line 13</span></td>
+<td width="100%"><span class="code">Disallow: /templates/</span></td>
+</tr>
+<tr>
+<td align="RIGHT" valign="TOP"><span class="nowrap">Line 14</span></td>
+<td width="100%"><span class="code">Disallow: /tmp/</span></td>
+</tr>
+<tr>
+<td align="RIGHT" valign="TOP"><span class="nowrap">Line 15</span></td>
+<td width="100%"><span class="code">Disallow: /xmlrpc/</span></td>
+</tr>
+<tr class="on">
+<td align="RIGHT" valign="TOP"><span class="nowrap">Line 16</span></td>
+<td width="100%"><span class="code"></span></td>
+</tr>
+</tbody></table>
+
+</p><p></p><div class="icon-advice">If you want to show your readers that your web site uses a correct robots.txt file, you can display the following icon on your main page: <img src="pic/valid-robots.png">.<br>
+Here is the HTML code you should insert into your web page in order to show the icon:
+<pre>&lt;p&gt;
+&lt;a href="http://tool.motoricerca.info/robots-checker.phtml?checkreferer=1"&gt;
+&lt;img src="http://tool.motoricerca.info/pic/valid-robots.png" border="0"
+alt="Valid Robots.txt" width="88" height="31"&gt;&lt;/a&gt;
+&lt;/p&gt;</pre><p>If you prefere, you can use this icon: <img src="pic/valid-robots-small.png">, copying the following HTML code:
+</p><pre>&lt;p&gt;
+&lt;a href="http://tool.motoricerca.info/robots-checker.phtml?checkreferer=1"&gt;
+&lt;img src="http://tool.motoricerca.info/pic/valid-robots-small.png" border="0"
+alt="Valid Robots.txt" width="80" height="15"&gt;&lt;/a&gt;
+&lt;/p&gt;</pre></div>
+
+<h1>Robots.txt Checker</h1>
+
+<p>Robots.txt files (often <strong>erroneously</strong> called robot.txt,
+in singular) are created by webmasters to mark (disallow) files and
+directories of a web site that search engine spiders (and other types of
+robots) should not access.
+
+</p><p>This <i>robots.txt checker</i> is a "validator" that analyzes the syntax of a
+robots.txt file to see if its format is valid as established by
+<a href="http://www.robotstxt.org/wc/norobots.html">Robot Exclusion Standard</a> (please read the documentation
+and the tutorial to learn the basics) or if it contains errors.
+
+
+</p><p><table>
+<tbody><tr>
+ <td valign="TOP"><img class="bullet" src="pic/1.png" alt="1"></td>
+ <td><strong>Simple usage:</strong> How to check your robots.txt file format? Just insert the <b>full URL</b> (Example: http://www.yourdomain.com/robots.txt) of the robots.txt file you want to analyze and hit Enter</td>
+</tr>
+<tr>
+ <td valign="TOP"><img class="bullet" src="pic/2.png" alt="2"></td>
+ <td><strong>Powerful:</strong> The checker finds syntax errors, "logic" errors, mistyped words and it gives you useful optimization tips</td>
+</tr>
+<tr>
+ <td valign="TOP"><img class="bullet" src="pic/3.png" alt="3"></td>
+ <td><strong>Accurate:</strong> The validation process takes in account both Robots Exclusion Standard rules and spider-specific (Google, Inktomi, etc.) extensions (including the new "Sitemap" command).</td>
+</tr>
+</tbody></table>
+
+</p><p>This robots.txt analyzer is provided by <a href="http://www.motoricerca.info/">Motoricerca</a>,
+a non-profit italian guide to web site optimization and search engine positioning.
+
+
+</p><form method="post" action="robots-checker.phtml" onsubmit="formTracker._trackEvent('Submit','Robots.txt check')">
+<p><span class="features">Robots.txt <strong>full</strong> URL (Example: http://www.domain.com/<strong>robots.txt</strong>):</span><br>
+<input name="url" value="http://hackademic1.teilar.gr/robots.txt" size="45" type="text"><br>
+<input value="Check robots.txt" type="submit"><br>
+<span class="features">If you'll find the analysis of this robots.txt validator useful, please think about offering a link to this page from your web site.
+
+
+
+
+</span></p></form><ul>
+<li> <a href="http://www.dhd24.com">dhd24</a> (Classifieds)</li>
+<li> <a href="http://news.feed-reader.net">News Reader</a> </li>
+<li> <a href="http://www.webmarketingpros.com">Web Marketing</a> </li>
+<li> <a href="http://testingbot.com">Cross Browser Testing</a> </li>
+</ul>
+<script type="text/javascript">
+var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+</script><script src="http://www.google-analytics.com/ga.js" type="text/javascript"></script>
+<script type="text/javascript">
+var pageTracker = _gat._getTracker("UA-2028837-2");
+pageTracker._initData();
+pageTracker._trackPageview();
+var formTracker = pageTracker._createEventTracker('Form');
+</script>
View
18 framework/report/html/renderer.py
@@ -64,7 +64,7 @@ def DrawButtonJSLink(self, Name, JSCode, Attribs = None, IgnoredParam = ''):
def GetAttribsAsStr(self, Attribs = {}):
AttribStr = ""
for Attrib, Value in Attribs.items():
- AttribStr += " "+Attrib+'="'+Value+'"'
+ AttribStr += " "+Attrib+'="'+cgi.escape(Value)+'"'
return AttribStr
def DrawImage(self, FileName, Attribs = {}):
@@ -118,3 +118,19 @@ def DrawLinkPairsAsHTMLList(self, PairList, Method = 'DrawLink', Attribs = {}, T
def DrawButton(self, Name, JavaScript):
return '<button onclick="javascript:'+JavaScript+'">'+Name+'</button>'
+ def DrawDiv(self, Content, Attribs = {}):
+ return "<div"+self.GetAttribsAsStr(Attribs)+">" + Content + "</div>"
+
+ def DrawOption(self, Descrip, Attribs):
+ return "<option"+self.GetAttribsAsStr(Attribs)+">" + cgi.escape(Descrip) + "</div>"
+
+ def DrawSelect(self, Data, SelectedValueList, Attribs = {}):
+ #multiple, size, autocomplete, disabled, name, id
+ Options = []
+ for Value, Descrip in Data:
+ #Attribs = defaultdict(list)
+ OptionAttribs = { 'value' : Value }.copy()
+ if Value in SelectedValueList:
+ OptionAttribs['selected'] = ''
+ Options.append(self.DrawOption(Descrip, OptionAttribs))
+ return "<select"+self.GetAttribsAsStr(Attribs)+">" + ''.join(Options) + "</div>"
View
BIN  framework/report/html/renderer.pyc
Binary file not shown
View
2  framework/report/html/tabcreator.py
@@ -127,7 +127,7 @@ def DrawTabFlowButtons(self):
return "&nbsp;".join(self.Renderer.DrawLinkPairs( [
[self.DrawImageFromConfigPair( [ 'FIXED_ICON_EXPAND_PLUGINS', 'NAV_TOOLTIP_EXPAND_PLUGINS' ]), self.ShowDivs()+self.UnhighlightTabs() ]
, [self.DrawImageFromConfigPair( [ 'FIXED_ICON_CLOSE_PLUGINS', 'NAV_TOOLTIP_CLOSE_PLUGINS' ]), self.HideDivs()+self.UnhighlightTabs()]
-], 'DrawButtonJSLink', { 'class' : 'icon' }))+self.Renderer.DrawButtonJSLink(self.DrawImageFromConfigPair( [ 'FIXED_ICON_INFO', 'FILTER_TOOLTIP_INFO_UNFILTER' ]), self.UnhighlightTabs()+'UnfilterBrotherTabs(this)', { 'class' : 'icon_unfilter', 'style' : 'display: none;' })
+], 'DrawButtonJSLink', { 'class' : 'icon' }))+self.Renderer.DrawButtonJSLink( '&nbsp;' + self.DrawImageFromConfigPair( [ 'FIXED_ICON_PLUGIN_INFO', 'FILTER_TOOLTIP_INFO_UNFILTER' ]), self.UnhighlightTabs()+'UnfilterBrotherTabs(this)', { 'class' : 'icon_unfilter', 'style' : 'display: none;' })
#return "&nbsp;".join(self.Renderer.DrawLinkPairs( [ ["<img src='images/arrow_down16x16.png' />", self.ShowDivs()+self.UnhighlightTabs() ], ["<img src='images/arrow_up16x16.png' />", self.HideDivs()+self.UnhighlightTabs()] ], 'DrawButtonJSLink', { 'class' : 'icon' }))
def RenderTabs(self, Attribs = {}):
View
BIN  framework/report/html/tabcreator.pyc
Binary file not shown
View
254 framework/report/reporter.py
@@ -31,9 +31,13 @@
import os, re, cgi, sys
from framework.lib.general import *
from framework.report.html import renderer
+from framework.report.html.filter import sanitiser
from framework.report import header, summary
from collections import defaultdict
+PLUGIN_DELIM = '__' # Characters like ; | . or / trip CKEditor as separators
+REPORT_PREFIX = '__rep__'
+
class Reporter:
def __init__(self, CoreObj):
self.Core = CoreObj # Keep Reference to Core Object
@@ -41,9 +45,23 @@ def __init__(self, CoreObj):
self.Render = renderer.HTMLRenderer(self.Core)
self.Header = header.Header(self.Core)
self.Summary = summary.Summary(self.Core)
+ self.Sanitiser = sanitiser.HTMLSanitiser()
self.PluginDivIds = {}
self.CounterList = []
+ def DrawImageFromConfigPair(self, ConfigList):
+ FileName, ToolTip = self.Core.Config.GetAsList(ConfigList)
+ return self.Render.DrawImage(FileName, { 'title' : ToolTip })
+
+ def GetPluginDelim(self):
+ return PLUGIN_DELIM
+
+ def GetPluginDivId(self, Plugin):
+ # "Compression" attempt while keeping uniqueness:
+ # First letter from plugin type is enough to make plugin div ids unique and predictable
+ #return MultipleReplace(Code, { 'OWASP' : 'O', 'OWTF' : 'F', '-' : '', '0' : '' })+PluginType[0]
+ return self.GetPluginDelim().join( [ Plugin['Group'], Plugin['Type'], Plugin['Code'] ] ) # Need this info for fast filtering in JS
+
def DrawCommand(self, Command):
#cgi.escape(MultipleReplace(ModifiedCommand, self.Core.Config.GetReplacementDict()))
return cgi.escape(Command)#.replace(';', '<br />') -> Sometimes ";" encountered in UA, cannot do this and it is not as helpful anyway
@@ -54,77 +72,134 @@ def DrawCommandTable(self, Command):
Table.CreateRow( [ self.DrawCommand(Command) ] )
return Table.Render()
- def GetIconFunction(self, Icon, IconToFunction, DivId = ''):
- Function = Icon
- if Icon in IconToFunction:
- Function = IconToFunction[Icon]
- FunctionStr = "FilterResults('"+Function+"')"
- if len(DivId) > 0:
- FunctionStr = "Rate('"+DivId+"', '"+Function+"')"
- return [ Function, FunctionStr ]
+ def DrawHelpLink(self, Anchor):
+ return self.Render.DrawLink(self.DrawImageFromConfigPair( [ 'FIXED_ICON_REVIEW_SIZE_HELP', 'NAV_TOOLTIP_REVIEW_SIZE_HELP' ] ), 'includes/help/help.html#'+Anchor, { 'target' : '_blank' } )
+
+ def GetIconLinks(self, IconList, Options):
+ List = []
+ for I in IconList:
+ if I['Icon'] == I['Icon'].upper(): # Icon in capitals = config setting
+ for Item in [ 'Icon', 'ToolTip' ]:
+ I[Item] = self.Core.Config.Get(I[Item]) # Override settings with config values
+ Image = self.Render.DrawImage(I['Icon'], { 'title' : I['ToolTip'] })
+ Attribs = { 'class' : 'icon' }
+ if 'Attribs' in I:
+ Attribs = I['Attribs'].copy()
+ if 'id' in Attribs:
+ pass # id already passed, ignore below
+ elif 'CounterName' in I:
+ Attribs['id'] = Options['IdPrefix'] + I['CounterName'] # Give each counter a unique id
+ elif 'IdPrefix' in Options: # Each link must have a unique id
+ #Attribs['id'] = Options['IdPrefix'] + I['Function'].split('(')[0] # Give each link a unique id
+ Attribs['id'] = Options['IdPrefix'] + I['Icon']
+ LinkImage = self.Render.DrawButtonJSLink(Image, I['Function'], Attribs)
+ PrefixStr = ''
+ if 'Counters' in Options and 'IdPrefix' in Options:
+ #Counters are drawn in a table, list is a row of HTML table cells with counters:
+ CounterName = I['Icon']
+ if 'CounterName' in I:
+ CounterName = I['CounterName']
+ CounterId = Options['IdPrefix']+CounterName+'_counter'
+ self.CounterList.append(CounterId)
+ PrefixStr = '<td>' + self.Render.DrawDiv('', { 'id' : CounterId, 'class' : 'counter' }) + '</td>'
+ List.append(PrefixStr + '<td>' + LinkImage + '</td>')
+ return List
+
+ def DrawReviewIconLinks(self, IconList, Options): # Options = {}
+ Table = self.Render.CreateTable({'class' : 'counter'})
+ Table.CreateCustomRow( '<tr>' + ''.join(self.GetIconLinks(IconList, Options)) + '</tr>' )
+ DivStyle = 'display:inline;'
+ if not 'Counters' in Options:
+ DivStyle += 'float:right;'
+ return self.Render.DrawDiv(Table.Render() + self.DrawFilterOptions(), { 'style' : DivStyle })
+
+ def GetSelectListFromList(self, List):
+ NewList = []
+ for Item in List:
+ NewList.append( [ Item, Item ] )
+ return NewList
- def DrawReviewIconLinks(self, IconList, IconToFunction, DivId = '', IdPrefix = None, Counters = False):
+ def GetSelectListFromDict(self, Dict, ValueField, ConcatDescripFieldList, ConcatStr = '-'):
+ List = []
+ for Item in Dict:
+ FieldList = []
+ for Field in ConcatDescripFieldList:
+ #if not Field.strip(): continue
+ #print "Field=" + str(Field) + str(ConcatDescripFieldList)
+ FieldList.append(Item[Field])
+ List.append( [ Item[ValueField], ConcatStr.join(FieldList) ] )
+ return List
+
+ def DrawFilterOptions(self):
+ TableG = self.Render.CreateTable( { 'class' : 'transaction_log' } )
+ TableG.CreateRow( [ 'Plugin Groups', 'Web Plugin Types', 'Aux Plugin Types' ], True)
+ #multiple, size, autocomplete, disabled, name, id
+ TableG.CreateRow( [
+self.Render.DrawSelect(self.GetSelectListFromList(self.Core.Config.Plugin.GetAllGroups()), [], { 'multiple' : 'multiple', 'id' : 'SelectPluginGroup', 'onchange' : 'SetSelectFilterOptions(this)' })
+, self.Render.DrawSelect(self.GetSelectListFromList(self.Core.Config.Plugin.GetTypesForGroup('web')), [], { 'multiple' : 'multiple', 'id' : 'SelectPluginTypesWeb', 'size' : '6', 'onchange' : 'SetSelectFilterOptions(this)' })
+, self.Render.DrawSelect(self.GetSelectListFromList(self.Core.Config.Plugin.GetTypesForGroup('aux')), [], { 'multiple' : 'multiple', 'id' : 'SelectPluginTypesAux', 'size' : '6', 'onchange' : 'SetSelectFilterOptions(this)' })
+] )
+ TableD = self.Render.CreateTable( { 'class' : 'transaction_log' } )
+ TableD.CreateRow( [ 'Web Test Groups' ], True)
+ TableD.CreateRow( [
+self.Render.DrawSelect(self.GetSelectListFromDict(self.Core.Config.Plugin.GetWebTestGroups(), 'Code', [ 'Code', 'Descrip', 'Hint' ], ' - ' ), [], { 'multiple' : 'multiple', 'id' : 'SelectWebTestGroups', 'size' : '10', 'onchange' : 'SetSelectFilterOptions(this)' })
+] )
+ return self.Render.DrawDiv( '<h4>Filter Options</h4><p>Tip: Hold the Ctrl key while selecting or unselecting for multiple choices.<br />NOTE: Clicking on any filter will apply these options from now on. Options will survive a screen refresh</p>' + TableG.Render() + TableD.Render(), { 'id' : 'advanced_filter_options', 'style' : 'display: none;' })
+
+ def DrawCounters(self, ReportType, IdPrefix = 'filter'):
+ ReportTypeStr = "'" + ReportType + "'"
+ FixedStartIcons = [
+{ 'Icon' : 'FIXED_ICON_MATCHES', 'ToolTip' : 'FILTER_TOOLTIP_MATCHES', 'Function' : "", 'CounterName' : 'matches' },
+{ 'Icon' : 'FIXED_ICON_INFO', 'ToolTip' : 'FILTER_TOOLTIP_INFO', 'Function' : "FilterResults('info', "+ReportTypeStr+")", 'CounterName' : 'info' },
+{ 'Icon' : 'FIXED_ICON_NOFLAG', 'ToolTip' : 'FILTER_TOOLTIP_NOFLAG', 'Function' : "FilterResults('no_flag', "+ReportTypeStr+")", 'CounterName' : 'no_flag' },
+{ 'Icon' : 'FIXED_ICON_UNSTRIKETHROUGH', 'ToolTip' : 'FILTER_TOOLTIP_UNSTRIKETHROUGH', 'Function' : "FilterResults('unseen', "+ReportTypeStr+")", 'CounterName' : 'unseen' },
+{ 'Icon' : 'FIXED_ICON_STRICKETHROUGH', 'ToolTip' : 'FILTER_TOOLTIP_STRIKETHROUGH', 'Function' : "FilterResults('seen', "+ReportTypeStr+")", 'CounterName' : 'seen' },
+{ 'Icon' : 'FIXED_ICON_NOTES', 'ToolTip' : 'FILTER_TOOLTIP_NOTES', 'Function' : "FilterResults('notes', "+ReportTypeStr+")", 'CounterName' : 'notes' }
+]
+ DynamicIcons = self.GetChosenReviewIconList('', 'FilterResults', ReportTypeStr)
+
+ Counters = FixedStartIcons + DynamicIcons
+
+ Counters += [
+{ 'Icon' : 'FIXED_ICON_REMOVE', 'ToolTip' : 'FILTER_TOOLTIP_REMOVE_FILTER', 'Function' : "FilterResults('delete', "+ReportTypeStr+")" },
+{ 'Icon' : 'FIXED_ICON_OPTIONS', 'ToolTip' : 'FILTER_TOOLTIP_OPTIONS', 'Function' : "ToggleFilterOptions()" },
+{ 'Icon' : 'FIXED_ICON_REFRESH', 'ToolTip' : 'FILTER_TOOLTIP_REFRESH', 'Function' : "FilterResults('refresh', "+ReportTypeStr+")" }
+]
+ return self.DrawReviewIconLinks(Counters, { 'IdPrefix' : IdPrefix, 'Counters' : True })
+
+ def GetChosenReviewIconList(self, DivId, Function, ReportTypeStr = ''): # This list is dynamic: depends on what the user configured
+ List = []
Setting = 'CHOSEN_ICONS_FOR_REVIEW'
- DrawList = []
- for IconInfo in IconList:
+ for IconInfo in self.Core.Config.Get(Setting).split(','):
IconInfo = IconInfo.split('@') # Convert from config file
if len(IconInfo) != 2:
self.Core.Error.Add("USER ERROR: Error in conf. file setting: CHOSEN_ICONS_FOR_REVIEW -> icon@title ("+str(IconInfo)+")", 'user')
break # Abort loop + end processing
Icon, Title = IconInfo
- Function, FunctionStr = self.GetIconFunction(Icon, IconToFunction, DivId)
- #DrawList.append( [ self.Render.DrawImage(Icon, 'title' : Title }), FunctionStr ] )
- Image = self.Render.DrawImage(Icon, { 'title' : Title })
- Attribs = { 'class' : 'icon' }
- if IdPrefix != None: # Each link must have a unique id
- Attribs['id'] = IdPrefix+Function # Give each link a unique id
- LinkImage = self.Render.DrawButtonJSLink(Image, FunctionStr, Attribs)
- if Counters and IdPrefix != None:
- CounterId = IdPrefix+Function+'_counter'
- self.CounterList.append(CounterId)
- DrawList.append('<td><div id="'+CounterId+'" class="counter">0</div></td><td>'+LinkImage+'</td>')
- continue # Counters are drawn in a table, list is a row of HTML table cells instead of plain links like below = must skip below
- DrawList.append( LinkImage )
- if len(DrawList) == 0: # Must select at least 1 flag
+ FunctionStr = "FilterResults('"+Icon+"', "+ReportTypeStr+")"
+ if 'Rate' == Function:
+ FunctionStr = "Rate('"+DivId+"', '"+Icon+"', this)"
+ List.append( { 'Icon' : Icon, 'ToolTip' : Title, 'Function' : FunctionStr } )
+ if len(List) == 0: # Must select at least 1 flag
self.Core.Error.Add("USER ERROR: Error in configuration file -> no items selected for setting: "+Setting, 'user')
- return ''
- #return "&nbsp;".join(self.Render.DrawLinkPairs(DrawList, 'DrawButtonJSLink', { 'class' : 'icon' }))
- if Counters:
- Table = self.Render.CreateTable({'class' : 'counter'})
- Table.CreateCustomRow( '<tr>'+''.join(DrawList)+'</tr>' )
- return Table.Render()
- return "&nbsp;".join(DrawList)
-
- def DrawCounters(self, Filter = False, IdPrefix = 'filter'):
- CounterList = self.GetIconInfoPairsAsStrList([
-[ 'FIXED_ICON_INFO', 'FILTER_TOOLTIP_INFO' ]
-, [ 'FIXED_ICON_NOFLAG', 'FILTER_TOOLTIP_NOFLAG' ]
-, [ 'FIXED_ICON_UNSTRIKETHROUGH', 'FILTER_TOOLTIP_UNSTRIKETHROUGH' ]
-, [ 'FIXED_ICON_STRICKETHROUGH', 'FILTER_TOOLTIP_STRIKETHROUGH' ]
-, [ 'FIXED_ICON_NOTES', 'FILTER_TOOLTIP_NOTES' ]
-]) # End of first fixed filter icons
- for IconInfo in self.Core.Config.Get('CHOSEN_ICONS_FOR_REVIEW').split(','): # User-configurable icons
- CounterList.append( IconInfo )
- if Filter:
- CounterList += self.GetIconInfoPairsAsStrList([
-[ 'FIXED_ICON_REMOVE', 'FILTER_TOOLTIP_REMOVE_FILTER' ]
-, [ 'FIXED_ICON_REFRESH', 'FILTER_TOOLTIP_REFRESH' ]
-])
- #print "FilterList="+str(FilterList)
- IconToFunction = { self.Core.Config.Get('FIXED_ICON_NOFLAG') : 'no_flag', self.Core.Config.Get('FIXED_ICON_UNSTRIKETHROUGH') : 'unseen', self.Core.Config.Get('FIXED_ICON_STRICKETHROUGH') : 'seen', self.Core.Config.Get('FIXED_ICON_NOTES') : 'notes' }
- return self.DrawReviewIconLinks(CounterList, IconToFunction, '', IdPrefix, True) # Add counters to filter
+ return []
+ return List
- def DrawImageFromConfigPair(self, ConfigList):
- FileName, ToolTip = self.Core.Config.GetAsList(ConfigList)
- return self.Render.DrawImage(FileName, { 'title' : ToolTip })
-
- def GetPluginDivId(self, Code, PluginType):
- # "Compression" attempt while keeping uniqueness:
- # First letter from plugin type is enough to make plugin div ids unique and predictable
- return MultipleReplace(Code, { 'OWASP' : 'O', 'OWTF' : 'F', '-' : '', '0' : '' })+PluginType[0]
+ def GetReviewIconList(self, DivId):
+ FixedStartIcons = [
+{ 'Icon' : 'FIXED_ICON_NOTES', 'ToolTip' : 'REVIEW_TOOLTIP_NOTES', 'Function' : "ToggleNotesBox('"+DivId+"')" },
+{ 'Icon' : 'FIXED_ICON_STRICKETHROUGH', 'ToolTip' : 'REVIEW_TOOLTIP_STRIKETHROUGH', 'Function' : "MarkAsSeen('"+DivId+"')", 'Attribs' : { 'id' : 'l'+DivId, 'class' : 'icon' } }
+]
+ DynamicIcons = self.GetChosenReviewIconList(DivId, 'Rate')
+
+ FixedEndIcons = [
+{ 'Icon' : 'FIXED_ICON_REMOVE', 'ToolTip' : 'REVIEW_TOOLTIP_REMOVE', 'Function' : "Rate('"+DivId+"', 'delete', this)" },
+{ 'Icon' : 'FIXED_ICON_CLOSE_PLUGIN', 'ToolTip' : 'REVIEW_TOOLTIP_CLOSE_PLUGIN', 'Function' : "HidePlugin('"+DivId+"')" }
+]
+ return FixedStartIcons + DynamicIcons + FixedEndIcons
def DrawReviewButtons(self, DivId):
- return self.Render.DrawButtonJSLink( self.DrawImageFromConfigPair( [ 'FIXED_ICON_NOTES', 'REVIEW_TOOLTIP_NOTES' ]), "ToggleNotesBox('"+DivId+"')", { 'class' : 'icon' })+"&nbsp;" +self.Render.DrawButtonJSLink(self.DrawImageFromConfigPair( [ 'FIXED_ICON_STRICKETHROUGH', 'REVIEW_TOOLTIP_STRIKETHROUGH' ]), "MarkAsSeen('"+DivId+"')", { 'id' : 'l'+DivId, 'class' : 'icon' })+"&nbsp;" +self.DrawReviewIconLinks(self.Core.Config.Get('CHOSEN_ICONS_FOR_REVIEW').split(','), {}, DivId) +"&nbsp;".join(self.Render.DrawLinkPairs([ [ self.DrawImageFromConfigPair( [ 'FIXED_ICON_REMOVE', 'REVIEW_TOOLTIP_REMOVE' ] ), "Rate('"+DivId+"', 'delete')" ] , [ self.DrawImageFromConfigPair( [ 'FIXED_ICON_CLOSE_PLUGIN', 'REVIEW_TOOLTIP_CLOSE_PLUGIN' ] ), "HidePlugin('"+DivId+"')" ] ], 'DrawButtonJSLink', { 'class' : 'icon' }))
+ return self.DrawReviewIconLinks(self.GetReviewIconList(DivId), { 'IdPrefix' : DivId } )
def DrawTransacLinksStr(self, PathList, ToFile = True):
URL, TransacPath, ReqPath, ResHeadersPath, ResBodyPath = PathList
@@ -146,7 +221,7 @@ def SavePluginReport(self, HTMLtext, Plugin):
save_dir = self.Core.PluginHandler.GetPluginOutputDir(Plugin)
if HTMLtext == None:
HTMLtext = cprint("PLUGIN BUG!!: on: "+PluginType.strip()+"/"+PluginFile.strip()+" no content returned")
- DivId = self.GetPluginDivId(Plugin['Code'], Plugin['Type'])
+ DivId = self.GetPluginDivId(Plugin)
PluginReportPath = save_dir + "report.html"
self.Core.CreateMissingDirs(save_dir)
with open(PluginReportPath, 'w') as file: # 'w' is important to overwrite the partial report, necesary for scanners
@@ -154,17 +229,19 @@ def SavePluginReport(self, HTMLtext, Plugin):
Table.CreateRow(['Plugin', 'Start', 'End', 'Runtime', 'Output Files'], True)
Plugin['RunTime'] = self.Core.Timer.GetElapsedTimeAsStr('Plugin')
Plugin['End'] = self.Core.Timer.GetEndDateTimeAsStr('Plugin')
- Table.CreateRow([ Plugin['Type']+'/'+Plugin['File'], Plugin['Start'], Plugin['End'], Plugin['RunTime'], self.Core.Reporter.Render.DrawButtonLink('Browse Plugin Output Files', self.Core.GetPartialPath(save_dir)) ])
+ Table.CreateRow([ Plugin['Type']+'/'+Plugin['File'], Plugin['Start'], Plugin['End'], Plugin['RunTime'], self.Core.Reporter.Render.DrawButtonLink('Browse', self.Core.GetPartialPath(save_dir)) ])
PluginHeader = '<h4 id="h'+DivId+'"><u>'+Plugin['Title']+'</u> - <i>'+Plugin['Type'].replace('_', ' ').upper()+'</i>'
PluginHeader += "&nbsp;" * 2 +self.DrawReviewButtons(DivId)+'</h4>'+Table.Render()
# Generate unique id every time to detect if plugin report changed to highlight modified stuff without losing review data (i.e. same plugin id):
PluginHeader += "<div id='token_"+DivId+"' style='display: none;'>"+self.Core.DB.GetNextHTMLID()+"</div>"
- NotesBox = self.Render.CreateTable({ 'class' : 'report_intro' })
+ NotesBox = self.Render.CreateTable({ 'class' : 'transaction_log' })
NotesBox.CreateRow(['Notes'], True)
# NOTE: autocomplete must be off because otherwise you see the text but is not saved in the review at all, which is counter-intuitive
- NotesBox.CreateRow(['<textarea id="note_text_'+DivId+'" autocomplete="off" onChange="SaveComments(\''+DivId+'\')" rows=15 cols=150></textarea>'])
- # Better with auto-save: NotesBox.CreateCustomRow('<tr><td align="right">'+self.Render.DrawButtonJSLink('<img src="images/floppy.png" />', "SaveComments('"+DivId+"')", { 'class' : 'icon' })+'</td></tr>')
- PluginHeader += "<div id='notes_"+DivId+"' style='display: none;'>"+NotesBox.Render()+"</div><hr />"
+ NotesBox.CreateRow( [ '<div id="note_preview_'+DivId+'"></div><div style="float: right;"><a href="javascript:ToggleNotesBox(\'' + DivId + '\')">Edit</a></div><div id="notes_'+DivId+'" style="display: none;"><textarea id="note_text_'+DivId+'" autocomplete="off" rows=15 cols=150></textarea> </div>' ] )
+ # NotesBox.CreateRow(['<textarea id="'+TextAreaId+'" autocomplete="off" onChange="SaveComments(\''+DivId+'\')" rows=15 cols=150></textarea><script type="text/javascript">CKEDITOR.replace( "'+TextAreaId+'" );</script>'])
+ # Better with auto-save: NotesBox.CreateCustomRow('<tr><td align="right">'+self.Render.DrawButtonJSLink('<img src="images/floppy.png" />', "SaveComments('"+DivId+"')", { 'class' : 'icon' })+'</td></tr>')
+ PluginHeader += "<div>"+NotesBox.Render()+"</div><hr />"
+ #PluginHeader += "<div id='notes_"+DivId+"' style='display: none;'>"+NotesBox.Render()+"</div><hr />"
file.write("\n"+PluginHeader+HTMLtext+"\n")
#print "Plugin="+str(Plugin)
self.Core.DB.PluginRegister.Add(Plugin, PluginReportPath, self.Core.Config.GetTarget())
@@ -208,13 +285,14 @@ def GetRegisteredWebPlugins(self, ReportType): # Web Plugins go in OWASP Testing
Match['Label'] = Match['Type'] # For url plugins the Label is a display of the plugin type (passive, semi_passive, etc)
RegisteredPluginList.append(Match)
TestGroups.append( {
-'TestGroupHeaderStr' : '<div id="'+TestGroup['Code']+'"><br />'+self.Render.DrawButtonLink(TestGroup['Descrip']+" ("+TestGroup['Code']+")", TestGroup['URL'], { 'class' : 'report_index' })+"&nbsp;"+TestGroup['Hint']
+'TestGroupHeaderStr' : '<div id="'+TestGroup['Code']+'" class="testgroup">'+self.Render.DrawButtonLink(TestGroup['Descrip']+" ("+TestGroup['Code']+")", TestGroup['URL'], { 'class' : 'report_index' })+"&nbsp;"+TestGroup['Hint']
, 'RegisteredPlugins' : RegisteredPluginList } )
+ #'TestGroupHeaderStr' : '<div id="'+TestGroup['Code']+'"><br />'+self.Render.DrawButtonLink(TestGroup['Descrip']+" ("+TestGroup['Code']+")", TestGroup['URL'], { 'class' : 'report_index' })+"&nbsp;"+TestGroup['Hint']
return TestGroups
def GetRegisteredAuxPlugins(self, ReportType): # Web Plugins go in OWASP Testing Guide order
TestGroups = []
- for PluginType in sorted(self.Core.Config.Plugin.GetTypesForGroup('aux')): # Report aux plugins in alphabetical order
+ for PluginType in self.Core.Config.Plugin.GetTypesForGroup('aux'): # Report aux plugins in alphabetical order
RegisteredPlugins = self.Core.DB.PluginRegister.Search( { 'Type' : PluginType, 'Target' : 'aux' } ) # Aux plugins have an aux target
if not RegisteredPlugins:
continue # The plugin has not been registered yet
@@ -233,6 +311,19 @@ def GetTestGroups(self, ReportType):
elif ReportType == 'AUX':
return self.GetRegisteredAuxPlugins(ReportType)
+ def DrawReportSkeleton(self): # Create Div + Tab structure for Review + Report ease of navigation
+ Tabs = self.Render.CreateTabs()
+ for Section in [ ['stats', 'Statistics'], ['passed', 'Passed Tests'], ['findings', 'Findings'], ['unrated', 'Not Rated'] ]:
+ Id, Label = Section
+ Tabs.AddDiv(REPORT_PREFIX + Id, Label, '')
+ Tabs.CreateTabs()
+ Tabs.CreateTabButtons()
+ return """
+<div id="generated_report" class="generated_report" style="display:none;">
+<div id='""" + REPORT_PREFIX + """intro'></div>""" + Tabs.Render() + """</div>
+<div id="review_content" class="review_content">
+"""
+
def ReportFinish(self): # Group all partial reports (whether done before or now) into the final report
Target = self.Core.Config.GetTarget()
if not self.Core.DB.PluginRegister.NumPluginsForTarget(Target) > 0:
@@ -240,15 +331,19 @@ def ReportFinish(self): # Group all partial reports (whether done before or now)
return None # Must abort here, before report is generated
self.ReportStart() # Wipe report
with open(self.Core.Config.Get('HTML_DETAILED_REPORT_PATH'), 'a') as file:
- file.write('<div id="GlobalReportButtonsTop" style="display:none;"></div>') # Start OWASP Testing Guide Item List
+ file.write('<div id="GlobalReportButtonsTop" style="display:none;"></div>' + self.DrawReportSkeleton()) # Start OWASP Testing Guide Item List
AllPluginsTabIdList = []
AllPluginsDivIdList = []
+ AllCodes = []
for TestGroup in self.GetTestGroups(self.Core.Config.Get('REPORT_TYPE')):
HeaderStr = TestGroup['TestGroupHeaderStr']
Tabs = self.Render.CreateTabs()
for Match in TestGroup['RegisteredPlugins']:
- PluginType = Match['Type']
- DivId = self.GetPluginDivId(Match['Code'], PluginType)
+ if Match['Code'] not in AllCodes:
+ AllCodes.append(Match['Code'])
+ #PluginType = Match['Type']
+ #DivId = self.GetPluginDivId(Match['Code'], PluginType)
+ DivId = self.GetPluginDivId(Match)
Tabs.AddDiv(DivId, Match['Label'], open(Match['Path']).read())
AllPluginsTabIdList.append(Tabs.GetTabIdForDiv(DivId))
AllPluginsDivIdList.append(DivId)
@@ -256,8 +351,8 @@ def ReportFinish(self): # Group all partial reports (whether done before or now)
Tabs.CreateCustomTab('Results:') # First create custom tab, without javascript
Tabs.CreateTabs() # Create the hide/show deal tabs
Tabs.CreateTabButtons() # Add handy tab navigation buttons to the right
- HeaderStr += "&nbsp;" * 3 + ("&nbsp;" * 4).join(self.Render.DrawLinkPairs( [ [ self.DrawImageFromConfigPair( [ 'FIXED_ICON_EXPAND_REPORT', 'NAV_TOOLTIP_EXPAND_REPORT' ]), "ClickLinkById('expand_report')" ], [ self.DrawImageFromConfigPair( [ 'FIXED_ICON_CLOSE_REPORT', 'NAV_TOOLTIP_CLOSE_REPORT' ]), "ClickLinkById('collapse_report')" ] ], 'DrawButtonJSLink', { 'class' : 'icon' }))
- HeaderStr += "<br />"
+ HeaderStr += "&nbsp;" * 1 + ("&nbsp;" * 1).join(self.Render.DrawLinkPairs( [ [ self.DrawImageFromConfigPair( [ 'FIXED_ICON_EXPAND_REPORT', 'NAV_TOOLTIP_EXPAND_REPORT' ]), "ClickLinkById('expand_report')" ], [ self.DrawImageFromConfigPair( [ 'FIXED_ICON_CLOSE_REPORT', 'NAV_TOOLTIP_CLOSE_REPORT' ]), "ClickLinkById('collapse_report')" ] ], 'DrawButtonJSLink', { 'class' : 'icon' }))
+ #HeaderStr += "<br />"
file.write(HeaderStr+Tabs.Render()+"</div>") # Save plugin reports in OWASP Guide order => 1 write per item = less memory-intensive
if len(AllPluginsTabIdList) == 0:
cprint("ERROR: No plugins found, cannot write report")
@@ -266,14 +361,18 @@ def ReportFinish(self): # Group all partial reports (whether done before or now)
PluginDivs = self.Render.DrawJSArrayFromList(AllPluginsDivIdList)
HideReportPluginDivsJS = UnhighlightReportPluginTabsJS+"; HideDivs("+PluginDivs+")"
ShowReportPluginDivsJS = UnhighlightReportPluginTabsJS+"; ShowDivs("+PluginDivs+")"
- file.write("""
+ file.write("""</div>
<br />
<div id='GlobalReportButtonsBottom' style='display:none;'>"""+self.Render.DrawButtonJSLink('+', ShowReportPluginDivsJS, { 'id' : 'expand_report' })+"&nbsp;"+self.Render.DrawButtonJSLink('-', HideReportPluginDivsJS, { 'id' : 'collapse_report' })+"""</div>
<script>
-var AllPlugins = """+PluginDivs+"""
-var Offset = '"""+self.Core.Config.Get('REVIEW_OFFSET')+"""'
-"""+self.DrawJSCounterList()+"""
+var AllPlugins = """ + PluginDivs + """
+var AllCodes = """ + self.Render.DrawJSArrayFromList(AllCodes) + """
+var Offset = '""" + self.Core.Config.Get('REVIEW_OFFSET') + """'
+""" + self.DrawJSCounterList() + """
var DetailedReport = true
+var PluginDelim = '""" + self.GetPluginDelim() + """'
+var ReportMode = false
+var REPORT_PREFIX = '""" + REPORT_PREFIX + """'
</script>
</body></html>""") # Closing HTML Report
cprint("Report written to: "+self.Core.Config.Get('HTML_DETAILED_REPORT_PATH'))
@@ -287,4 +386,3 @@ def ReportWrite(self, html, text):
cprint(text) # Text displayed on console only, html saved in report
with open(self.Core.Config.Get('HTML_DETAILED_REPORT_PATH'), 'a') as file:
file.write(html) # Closing HTML Report
-
View
BIN  framework/report/reporter.pyc
Binary file not shown
View
33 framework/report/summary.py
@@ -31,6 +31,7 @@
import os, re, cgi
from framework.lib.general import *
from collections import defaultdict
+import json
class Summary:
def __init__(self, Core):
@@ -72,24 +73,21 @@ def RenderNetMap(self):
IPs = []
for IP in self.GetSortedIPs():
IPs.append(self.RenderIP(IP))
- return self.Core.Reporter.Render.DrawHTMLList(IPs)
+ return self.Core.Reporter.Render.DrawHTMLList(IPs, { 'class' : 'ip_list' } )
+
+ def RenderIPValue(self, IP):
+ return '<div id="' + cgi.escape(IP) + '">' + cgi.escape(IP) + '</div>'
def RenderIP(self, IP):
Ports = []
for Port in self.GetSortedPorts(IP):
Ports.append(self.RenderPortInfo(IP, Port))
- return IP + self.Core.Reporter.Render.DrawHTMLList(Ports)
+ return self.RenderIPValue(IP) + self.Core.Reporter.Render.DrawHTMLList(Ports, { 'class' : 'port_list' })
def CountPluginsFinished(self, ReviewOffset):
FinishedForOffset = len(self.Core.DB.PluginRegister.Search( { 'ReviewOffset' : ReviewOffset } ))
self.PluginsFinished.append( { 'Offset' : ReviewOffset, 'NumFinished' : FinishedForOffset } )
- def RenderPluginCountersAsJSON(self):
- Output = []
- for Info in self.PluginsFinished:# Offset, NumFinished
- Output.append("'"+Info['Offset']+"' : '"+str(Info['NumFinished'])+"'")
- return "{" + ", ".join(Output) + "}"
-
def IsOffsetUnReachable(self, ReviewOffset):
OffsetPlugins = self.Core.DB.PluginRegister.Search( { 'ReviewOffset' : ReviewOffset } )
if len(OffsetPlugins) > 0:
@@ -98,6 +96,9 @@ def IsOffsetUnReachable(self, ReviewOffset):
return self.Core.IsTargetUnreachable(Target)
return False # Assume false until proven otherwise :P -must do this for passive testing + external plugins-
+ def DrawHiddenOffsetIPAndPort(self, ReviewOffset, IP, Port): # Pass IP and Port mapping to offset for code simplification in JS
+ return self.Core.Reporter.Render.DrawDiv(IP, { 'id' : 'ip_' + ReviewOffset, 'style' : 'display: none' })+self.Core.Reporter.Render.DrawDiv(Port, { 'id' : 'port_' + ReviewOffset, 'style' : 'display: none' })
+
def RenderPortInfo(self, IP, Port):
Offsets = []
UnReachable = True
@@ -107,8 +108,7 @@ def RenderPortInfo(self, IP, Port):
#self.Core.IsTargetUnreachable()
ReportPath = self.Core.DB.ReportRegister.Search( { 'ReviewOffset' : ReviewOffset } )[0]['ReportPath']
#print "IP="+str(IP)+", Port="+str(Port)+" -> ReviewOffset="+str(ReviewOffset)+", ReportPath="+str(ReportPath)
- #Offsets.append(self.Core.Reporter.Render.DrawButtonLink(ReviewOffset, self.Core.GetPartialPath(ReportPath), { 'target' : '' } )+self.Core.Reporter.DrawCounters(False, ReviewOffset)+self.Core.Reporter.Render.DrawiFrame( { 'src' : self.Core.GetPartialPath(ReportPath), 'width' : '100%', 'height' : '100%' }))
- Offsets.append('<div style="display:none;">'+self.Core.Reporter.DrawCounters(False, ReviewOffset)+'</div><a name="anchor_'+ReviewOffset+'">'+self.Core.Reporter.Render.DrawiFrame( { 'id' : 'iframe_'+ReviewOffset, 'src' : self.Core.GetPartialPath(ReportPath), 'width' : '100%', 'height' : '100%', 'frameborder' : '0', 'style' : "overflow-y:auto; overflow-x:hidden;", 'onload' : "this.style.height='"+self.Core.Config.Get('COLLAPSED_REPORT_SIZE')+"';" })+"</a>")
+ Offsets.append('<a name="anchor_'+ReviewOffset+'">'+self.Core.Reporter.Render.DrawiFrame( { 'id' : 'iframe_'+ReviewOffset, 'src' : self.Core.GetPartialPath(ReportPath), 'width' : '100%', 'height' : self.Core.Config.Get('COLLAPSED_REPORT_SIZE'), 'frameborder' : '0', 'class' : 'iframe_collapsed' })+"</a>" + self.DrawHiddenOffsetIPAndPort(ReviewOffset, IP, Port))
self.CountPluginsFinished(ReviewOffset)
UnReachable = False
#Output += "IP="+IP+", Port="+Port+"->"+
@@ -116,8 +116,11 @@ def RenderPortInfo(self, IP, Port):
if UnReachable:
Output = "&nbsp;" * 5 + "<strike>Port unreachable</strike>"
else:
- Output = self.Core.Reporter.Render.DrawHTMLList(Offsets)
- return Port + Output
+ Output = self.Core.Reporter.Render.DrawHTMLList(Offsets, { 'class' : 'review_offset_list' } )
+ return self.RenderPortValue(Port) + Output
+
+ def RenderPortValue(self, Port):
+ return '<div id="' + cgi.escape(Port) + '">' + cgi.escape(Port) + '</div>'
def RenderAUX(self):
AuxSearch = self.Core.DB.ReportRegister.Search( { 'ReportType' : 'AUX' } )
@@ -139,8 +142,12 @@ def ReportFinish(self):
HTML += """
<script>
var DetailedReport = false
-var PluginCounters = """+self.RenderPluginCountersAsJSON()+"""
"""+self.Core.Reporter.DrawJSCounterList()+"""
+var CollapsedReportSize = '"""+self.Core.Config.Get('COLLAPSED_REPORT_SIZE')+"""'
+var NetMap = """ + json.dumps(self.NetMap)+"""
+var PluginDelim = '""" + self.Core.Reporter.GetPluginDelim() + """'
+var SeverityWeightOrder = """ + self.Core.Reporter.Render.DrawJSArrayFromList(self.Core.Config.Get('SEVERITY_WEIGHT_ORDER').split(',')) + """
+var PassedTestIcons = """ + self.Core.Reporter.Render.DrawJSArrayFromList(self.Core.Config.Get('PASSED_TEST_ICONS').split(',')) + """
</script>
"""
with open(self.Core.Config.Get('HTML_REPORT_PATH'), 'a') as file:
View
BIN  framework/report/summary.pyc
Binary file not shown
View
BIN  images/bug.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  images/computer.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  images/computer_small.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  images/info16x16.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  images/info24x24.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  images/options.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  images/radio-button_on.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  images/shopping_cart.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  images/star_2.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  images/star_3.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  images/target.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  images/target2.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  images/target3.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  images/wizard.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
24 includes/ckeditor/.htaccess
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.
+# For licensing, see LICENSE.html or http://ckeditor.com/license
+#
+
+#
+# On some specific Linux installations you could face problems with Firefox.
+# It could give you errors when loading the editor saying that some illegal
+# characters were found (three strange chars in the beginning of the file).
+# This could happen if you map the .js or .css files to PHP, for example.
+#
+# Those characters are the Byte Order Mask (BOM) of the Unicode encoded files.
+# All FCKeditor files are Unicode encoded.
+#
+
+AddType application/x-javascript .js
+AddType text/css .css
+
+#
+# If PHP is mapped to handle XML files, you could have some issues. The
+# following will disable it.
+#
+
+AddType text/xml .xml
View
1,433 includes/ckeditor/CHANGES.html
1,433 additions, 0 deletions not shown
View
92 includes/ckeditor/INSTALL.html
@@ -0,0 +1,92 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!--
+Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+-->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Installation Guide - CKEditor</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <style type="text/css">
+ h3
+ {
+ border-bottom: 1px solid #AAAAAA;
+ }
+ pre
+ {
+ background-color: #F9F9F9;
+ border: 1px dashed #2F6FAB;
+ padding: 1em;
+ line-height: 1.1em;
+ }
+ #footer hr
+ {
+ margin: 10px 0 15px 0;
+ height: 1px;
+ border: solid 1px gray;
+ border-bottom: none;
+ }
+ #footer p
+ {
+ margin: 0 10px 10px 10px;
+ float: left;
+ }
+ #footer #copy
+ {
+ float: right;
+ }
+ </style>
+</head>
+<body>
+ <h1>
+ CKEditor Installation Guide</h1>
+ <h3>
+ What&#39;s CKEditor?</h3>
+ <p>
+ CKEditor is a text editor to be used inside web pages. It&#39;s not a replacement
+ for desktop text editors like Word or OpenOffice, but a component to be used as
+ part of web applications and web sites.</p>
+ <h3>
+ Installation</h3>
+ <p>
+ Installing CKEditor is an easy task. Just follow these simple steps:</p>
+ <ol>
+ <li><strong>Download</strong> the latest version of the editor from our web site: <a
+ href="http://ckeditor.com">http://ckeditor.com</a>. You should have already completed
+ this step, but be sure you have the very latest version.</li>
+ <li><strong>Extract</strong> (decompress) the downloaded file into the root of your
+ web site.</li>
+ </ol>
+ <p>
+ <strong>Note:</strong> CKEditor is by default installed in the &quot;ckeditor&quot;
+ folder. You can place the files in whichever you want though.</p>
+ <h3>
+ Checking Your Installation
+ </h3>
+ <p>
+ The editor comes with a few sample pages that can be used to verify that installation
+ proceeded properly. Take a look at the <a href="_samples">_samples</a> directory.</p>
+ <p>
+ To test your installation, just call the following page at your web site:</p>
+ <pre>
+http://&lt;your site&gt;/&lt;CKEditor installation path&gt;/_samples/index.html
+
+For example:
+http://www.example.com/ckeditor/_samples/index.html</pre>
+ <h3>
+ Documentation</h3>
+ <p>
+ The full editor documentation is available online at the following address:<br />
+ <a href="http://docs.cksource.com/ckeditor">http://docs.cksource.com/ckeditor</a></p>
+ <div id="footer">
+ <hr />
+ <p>
+ CKEditor - The text editor for Internet - <a href="http://ckeditor.com/">http://ckeditor.com</a>
+ </p>
+ <p id="copy">
+ Copyright &copy; 2003-2011, <a href="http://cksource.com/">CKSource</a> - Frederico
+ Knabben. All rights reserved.
+ </p>
+ </div>
+</body>
+</html>
View
1,327 includes/ckeditor/LICENSE.html
@@ -0,0 +1,1327 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!--
+== BEGIN TEXT ONLY VERSION ==
+
+Software License Agreement
+==========================
+
+CKEditor - The text editor for Internet - http://ckeditor.com
+Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.
+
+Licensed under the terms of any of the following licenses at your
+choice:
+
+ - GNU General Public License Version 2 or later (the "GPL")
+ http://www.gnu.org/licenses/gpl.html
+ (See Appendix A)
+
+ - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ http://www.gnu.org/licenses/lgpl.html
+ (See Appendix B)
+
+ - Mozilla Public License Version 1.1 or later (the "MPL")
+ http://www.mozilla.org/MPL/MPL-1.1.html
+ (See Appendix C)
+
+You are not required to, but if you want to explicitly declare the
+license you have chosen to be bound to when using, reproducing,
+modifying and distributing this software, just include a text file
+titled "legal.txt" in your version of this software, indicating your
+license choice.
+
+Sources of Intellectual Property Included in CKEditor
+=====================================================
+
+Where not otherwise indicated, all CKEditor content is authored by
+CKSource engineers and consists of CKSource-owned intellectual
+property. In some specific instances, CKEditor will incorporate work
+done by developers outside of CKSource with their express permission.
+
+Trademarks
+==========
+
+CKEditor is a trademark of CKSource - Frederico Knabben. All other brand
+and product names are trademarks, registered trademarks or service
+marks of their respective holders.
+
+Appendix A: The GPL License
+===========================
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software-to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not