arachni 0.2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (262) hide show
  1. data/ACKNOWLEDGMENTS.md +14 -0
  2. data/AUTHORS.md +6 -0
  3. data/CHANGELOG.md +162 -0
  4. data/CONTRIBUTORS.md +10 -0
  5. data/EXPLOITATION.md +429 -0
  6. data/HACKING.md +101 -0
  7. data/LICENSE.md +341 -0
  8. data/README.md +350 -0
  9. data/Rakefile +86 -0
  10. data/bin/arachni +22 -0
  11. data/bin/arachni_web +77 -0
  12. data/bin/arachni_xmlrpc +21 -0
  13. data/bin/arachni_xmlrpcd +82 -0
  14. data/bin/arachni_xmlrpcd_monitor +74 -0
  15. data/conf/README.webui.yaml.txt +44 -0
  16. data/conf/webui.yaml +11 -0
  17. data/external/metasploit/LICENSE +24 -0
  18. data/external/metasploit/modules/exploits/unix/webapp/arachni_exec.rb +142 -0
  19. data/external/metasploit/modules/exploits/unix/webapp/arachni_path_traversal.rb +113 -0
  20. data/external/metasploit/modules/exploits/unix/webapp/arachni_php_eval.rb +150 -0
  21. data/external/metasploit/modules/exploits/unix/webapp/arachni_php_include.rb +141 -0
  22. data/external/metasploit/modules/exploits/unix/webapp/arachni_sqlmap.rb +92 -0
  23. data/external/metasploit/plugins/arachni.rb +536 -0
  24. data/getoptslong.rb +241 -0
  25. data/lib/anemone.rb +2 -0
  26. data/lib/anemone/cookie_store.rb +35 -0
  27. data/lib/anemone/core.rb +371 -0
  28. data/lib/anemone/exceptions.rb +5 -0
  29. data/lib/anemone/http.rb +144 -0
  30. data/lib/anemone/page.rb +337 -0
  31. data/lib/anemone/page_store.rb +160 -0
  32. data/lib/anemone/storage.rb +34 -0
  33. data/lib/anemone/storage/base.rb +75 -0
  34. data/lib/anemone/storage/exceptions.rb +15 -0
  35. data/lib/anemone/storage/mongodb.rb +89 -0
  36. data/lib/anemone/storage/pstore.rb +50 -0
  37. data/lib/anemone/storage/redis.rb +90 -0
  38. data/lib/anemone/storage/tokyo_cabinet.rb +57 -0
  39. data/lib/anemone/tentacle.rb +40 -0
  40. data/lib/arachni.rb +16 -0
  41. data/lib/audit_store.rb +346 -0
  42. data/lib/component_manager.rb +293 -0
  43. data/lib/component_options.rb +395 -0
  44. data/lib/exceptions.rb +76 -0
  45. data/lib/framework.rb +637 -0
  46. data/lib/http.rb +809 -0
  47. data/lib/issue.rb +302 -0
  48. data/lib/module.rb +4 -0
  49. data/lib/module/auditor.rb +455 -0
  50. data/lib/module/base.rb +188 -0
  51. data/lib/module/element_db.rb +158 -0
  52. data/lib/module/key_filler.rb +87 -0
  53. data/lib/module/manager.rb +87 -0
  54. data/lib/module/output.rb +68 -0
  55. data/lib/module/trainer.rb +240 -0
  56. data/lib/module/utilities.rb +110 -0
  57. data/lib/options.rb +547 -0
  58. data/lib/parser.rb +2 -0
  59. data/lib/parser/auditable.rb +522 -0
  60. data/lib/parser/elements.rb +296 -0
  61. data/lib/parser/page.rb +149 -0
  62. data/lib/parser/parser.rb +717 -0
  63. data/lib/plugin.rb +4 -0
  64. data/lib/plugin/base.rb +110 -0
  65. data/lib/plugin/manager.rb +162 -0
  66. data/lib/report.rb +4 -0
  67. data/lib/report/base.rb +119 -0
  68. data/lib/report/manager.rb +92 -0
  69. data/lib/rpc/xml/client/base.rb +71 -0
  70. data/lib/rpc/xml/client/dispatcher.rb +49 -0
  71. data/lib/rpc/xml/client/instance.rb +88 -0
  72. data/lib/rpc/xml/server/base.rb +90 -0
  73. data/lib/rpc/xml/server/dispatcher.rb +357 -0
  74. data/lib/rpc/xml/server/framework.rb +206 -0
  75. data/lib/rpc/xml/server/instance.rb +191 -0
  76. data/lib/rpc/xml/server/module/manager.rb +46 -0
  77. data/lib/rpc/xml/server/options.rb +124 -0
  78. data/lib/rpc/xml/server/output.rb +299 -0
  79. data/lib/rpc/xml/server/plugin/manager.rb +58 -0
  80. data/lib/ruby.rb +5 -0
  81. data/lib/ruby/object.rb +32 -0
  82. data/lib/ruby/string.rb +74 -0
  83. data/lib/ruby/xmlrpc/server.rb +27 -0
  84. data/lib/spider.rb +200 -0
  85. data/lib/typhoeus/request.rb +91 -0
  86. data/lib/typhoeus/response.rb +34 -0
  87. data/lib/ui/cli/cli.rb +744 -0
  88. data/lib/ui/cli/output.rb +279 -0
  89. data/lib/ui/web/log.rb +82 -0
  90. data/lib/ui/web/output_stream.rb +94 -0
  91. data/lib/ui/web/report_manager.rb +222 -0
  92. data/lib/ui/web/server.rb +903 -0
  93. data/lib/ui/web/server/db/placeholder +0 -0
  94. data/lib/ui/web/server/public/banner.png +0 -0
  95. data/lib/ui/web/server/public/bodybg-small.png +0 -0
  96. data/lib/ui/web/server/public/bodybg.png +0 -0
  97. data/lib/ui/web/server/public/css/smoothness/images/pbar-ani.gif +0 -0
  98. data/lib/ui/web/server/public/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  99. data/lib/ui/web/server/public/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  100. data/lib/ui/web/server/public/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  101. data/lib/ui/web/server/public/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  102. data/lib/ui/web/server/public/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  103. data/lib/ui/web/server/public/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  104. data/lib/ui/web/server/public/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  105. data/lib/ui/web/server/public/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  106. data/lib/ui/web/server/public/css/smoothness/images/ui-icons_222222_256x240.png +0 -0
  107. data/lib/ui/web/server/public/css/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  108. data/lib/ui/web/server/public/css/smoothness/images/ui-icons_454545_256x240.png +0 -0
  109. data/lib/ui/web/server/public/css/smoothness/images/ui-icons_888888_256x240.png +0 -0
  110. data/lib/ui/web/server/public/css/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  111. data/lib/ui/web/server/public/css/smoothness/jquery-ui-1.8.9.custom.css +573 -0
  112. data/lib/ui/web/server/public/favicon.ico +0 -0
  113. data/lib/ui/web/server/public/footer.jpg +0 -0
  114. data/lib/ui/web/server/public/icons/error.png +0 -0
  115. data/lib/ui/web/server/public/icons/info.png +0 -0
  116. data/lib/ui/web/server/public/icons/ok.png +0 -0
  117. data/lib/ui/web/server/public/icons/status.png +0 -0
  118. data/lib/ui/web/server/public/js/jquery-1.4.4.min.js +167 -0
  119. data/lib/ui/web/server/public/js/jquery-ui-1.8.9.custom.min.js +781 -0
  120. data/lib/ui/web/server/public/logo.png +0 -0
  121. data/lib/ui/web/server/public/nav-left.jpg +0 -0
  122. data/lib/ui/web/server/public/nav-right.jpg +0 -0
  123. data/lib/ui/web/server/public/nav-selected-left.jpg +0 -0
  124. data/lib/ui/web/server/public/nav-selected-right.jpg +0 -0
  125. data/lib/ui/web/server/public/reports/placeholder +1 -0
  126. data/lib/ui/web/server/public/sidebar-bottom.jpg +0 -0
  127. data/lib/ui/web/server/public/sidebar-h4.jpg +0 -0
  128. data/lib/ui/web/server/public/sidebar-top.jpg +0 -0
  129. data/lib/ui/web/server/public/spider.png +0 -0
  130. data/lib/ui/web/server/public/style.css +604 -0
  131. data/lib/ui/web/server/tmp/placeholder +0 -0
  132. data/lib/ui/web/server/views/dispatcher.erb +85 -0
  133. data/lib/ui/web/server/views/dispatcher_error.erb +14 -0
  134. data/lib/ui/web/server/views/error.erb +1 -0
  135. data/lib/ui/web/server/views/flash.erb +18 -0
  136. data/lib/ui/web/server/views/home.erb +14 -0
  137. data/lib/ui/web/server/views/instance.erb +213 -0
  138. data/lib/ui/web/server/views/layout.erb +95 -0
  139. data/lib/ui/web/server/views/log.erb +40 -0
  140. data/lib/ui/web/server/views/modules.erb +71 -0
  141. data/lib/ui/web/server/views/options.erb +23 -0
  142. data/lib/ui/web/server/views/output_results.erb +51 -0
  143. data/lib/ui/web/server/views/plugins.erb +42 -0
  144. data/lib/ui/web/server/views/report_formats.erb +30 -0
  145. data/lib/ui/web/server/views/reports.erb +55 -0
  146. data/lib/ui/web/server/views/settings.erb +120 -0
  147. data/lib/ui/web/server/views/welcome.erb +38 -0
  148. data/lib/ui/xmlrpc/dispatcher_monitor.rb +204 -0
  149. data/lib/ui/xmlrpc/xmlrpc.rb +843 -0
  150. data/logs/placeholder +0 -0
  151. data/metamodules/autothrottle.rb +74 -0
  152. data/metamodules/timeout_notice.rb +118 -0
  153. data/metamodules/uniformity.rb +98 -0
  154. data/modules/audit/code_injection.rb +136 -0
  155. data/modules/audit/code_injection_timing.rb +115 -0
  156. data/modules/audit/code_injection_timing/payloads.txt +4 -0
  157. data/modules/audit/csrf.rb +301 -0
  158. data/modules/audit/ldapi.rb +103 -0
  159. data/modules/audit/ldapi/errors.txt +26 -0
  160. data/modules/audit/os_cmd_injection.rb +103 -0
  161. data/modules/audit/os_cmd_injection/payloads.txt +2 -0
  162. data/modules/audit/os_cmd_injection_timing.rb +104 -0
  163. data/modules/audit/os_cmd_injection_timing/payloads.txt +3 -0
  164. data/modules/audit/path_traversal.rb +141 -0
  165. data/modules/audit/response_splitting.rb +105 -0
  166. data/modules/audit/rfi.rb +193 -0
  167. data/modules/audit/sqli.rb +120 -0
  168. data/modules/audit/sqli/regexp_ids.txt +90 -0
  169. data/modules/audit/sqli_blind_rdiff.rb +321 -0
  170. data/modules/audit/sqli_blind_timing.rb +103 -0
  171. data/modules/audit/sqli_blind_timing/payloads.txt +51 -0
  172. data/modules/audit/trainer.rb +89 -0
  173. data/modules/audit/unvalidated_redirect.rb +90 -0
  174. data/modules/audit/xpath.rb +104 -0
  175. data/modules/audit/xpath/errors.txt +26 -0
  176. data/modules/audit/xss.rb +99 -0
  177. data/modules/audit/xss_event.rb +134 -0
  178. data/modules/audit/xss_path.rb +125 -0
  179. data/modules/audit/xss_script_tag.rb +112 -0
  180. data/modules/audit/xss_tag.rb +112 -0
  181. data/modules/audit/xss_uri.rb +125 -0
  182. data/modules/recon/allowed_methods.rb +104 -0
  183. data/modules/recon/backdoors.rb +131 -0
  184. data/modules/recon/backdoors/filenames.txt +16 -0
  185. data/modules/recon/backup_files.rb +177 -0
  186. data/modules/recon/backup_files/extensions.txt +28 -0
  187. data/modules/recon/common_directories.rb +138 -0
  188. data/modules/recon/common_directories/directories.txt +265 -0
  189. data/modules/recon/common_files.rb +138 -0
  190. data/modules/recon/common_files/filenames.txt +17 -0
  191. data/modules/recon/directory_listing.rb +171 -0
  192. data/modules/recon/grep/captcha.rb +62 -0
  193. data/modules/recon/grep/credit_card.rb +85 -0
  194. data/modules/recon/grep/cvs_svn_users.rb +73 -0
  195. data/modules/recon/grep/emails.rb +59 -0
  196. data/modules/recon/grep/html_objects.rb +53 -0
  197. data/modules/recon/grep/private_ip.rb +54 -0
  198. data/modules/recon/grep/ssn.rb +53 -0
  199. data/modules/recon/htaccess_limit.rb +82 -0
  200. data/modules/recon/http_put.rb +95 -0
  201. data/modules/recon/interesting_responses.rb +118 -0
  202. data/modules/recon/unencrypted_password_forms.rb +119 -0
  203. data/modules/recon/webdav.rb +126 -0
  204. data/modules/recon/xst.rb +107 -0
  205. data/path_extractors/anchors.rb +35 -0
  206. data/path_extractors/forms.rb +35 -0
  207. data/path_extractors/frames.rb +38 -0
  208. data/path_extractors/generic.rb +39 -0
  209. data/path_extractors/links.rb +35 -0
  210. data/path_extractors/meta_refresh.rb +39 -0
  211. data/path_extractors/scripts.rb +37 -0
  212. data/path_extractors/sitemap.rb +31 -0
  213. data/plugins/autologin.rb +137 -0
  214. data/plugins/content_types.rb +90 -0
  215. data/plugins/cookie_collector.rb +99 -0
  216. data/plugins/form_dicattack.rb +185 -0
  217. data/plugins/healthmap.rb +94 -0
  218. data/plugins/http_dicattack.rb +133 -0
  219. data/plugins/metamodules.rb +118 -0
  220. data/plugins/proxy.rb +248 -0
  221. data/plugins/proxy/server.rb +66 -0
  222. data/plugins/waf_detector.rb +184 -0
  223. data/profiles/comprehensive.afp +74 -0
  224. data/profiles/full.afp +75 -0
  225. data/reports/afr.rb +59 -0
  226. data/reports/ap.rb +55 -0
  227. data/reports/html.rb +179 -0
  228. data/reports/html/default.erb +967 -0
  229. data/reports/metareport.rb +139 -0
  230. data/reports/metareport/arachni_metareport.rb +174 -0
  231. data/reports/plugin_formatters/html/content_types.rb +82 -0
  232. data/reports/plugin_formatters/html/cookie_collector.rb +66 -0
  233. data/reports/plugin_formatters/html/form_dicattack.rb +54 -0
  234. data/reports/plugin_formatters/html/healthmap.rb +76 -0
  235. data/reports/plugin_formatters/html/http_dicattack.rb +54 -0
  236. data/reports/plugin_formatters/html/metaformatters/timeout_notice.rb +65 -0
  237. data/reports/plugin_formatters/html/metaformatters/uniformity.rb +71 -0
  238. data/reports/plugin_formatters/html/metamodules.rb +93 -0
  239. data/reports/plugin_formatters/html/waf_detector.rb +54 -0
  240. data/reports/plugin_formatters/stdout/content_types.rb +73 -0
  241. data/reports/plugin_formatters/stdout/cookie_collector.rb +61 -0
  242. data/reports/plugin_formatters/stdout/form_dicattack.rb +52 -0
  243. data/reports/plugin_formatters/stdout/healthmap.rb +72 -0
  244. data/reports/plugin_formatters/stdout/http_dicattack.rb +53 -0
  245. data/reports/plugin_formatters/stdout/metaformatters/timeout_notice.rb +55 -0
  246. data/reports/plugin_formatters/stdout/metaformatters/uniformity.rb +68 -0
  247. data/reports/plugin_formatters/stdout/metamodules.rb +89 -0
  248. data/reports/plugin_formatters/stdout/waf_detector.rb +48 -0
  249. data/reports/plugin_formatters/xml/content_types.rb +91 -0
  250. data/reports/plugin_formatters/xml/cookie_collector.rb +70 -0
  251. data/reports/plugin_formatters/xml/form_dicattack.rb +57 -0
  252. data/reports/plugin_formatters/xml/healthmap.rb +82 -0
  253. data/reports/plugin_formatters/xml/http_dicattack.rb +57 -0
  254. data/reports/plugin_formatters/xml/metaformatters/timeout_notice.rb +67 -0
  255. data/reports/plugin_formatters/xml/metaformatters/uniformity.rb +82 -0
  256. data/reports/plugin_formatters/xml/metamodules.rb +91 -0
  257. data/reports/plugin_formatters/xml/waf_detector.rb +58 -0
  258. data/reports/stdout.rb +182 -0
  259. data/reports/txt.rb +77 -0
  260. data/reports/xml.rb +231 -0
  261. data/reports/xml/buffer.rb +98 -0
  262. metadata +516 -0
@@ -0,0 +1,2 @@
1
+ opts = Arachni::Options.instance
2
+ require opts.dir['lib'] + 'parser/parser'
@@ -0,0 +1,522 @@
1
+ module Arachni
2
+
3
+ require Arachni::Options.instance.dir['lib'] + 'module/output'
4
+ require Arachni::Options.instance.dir['lib'] + 'module/utilities'
5
+ require Arachni::Options.instance.dir['lib'] + 'module/key_filler'
6
+
7
+ module Element
8
+
9
+ class Auditable
10
+
11
+ include Arachni::Module::Utilities
12
+
13
+ def self.reset
14
+ @@audited = Set.new
15
+ end
16
+
17
+ attr_accessor :altered
18
+ attr_reader :opts
19
+
20
+ #
21
+ # Holds constant bitfields that describe the preferred formatting
22
+ # of injection strings.
23
+ #
24
+ module Format
25
+
26
+ #
27
+ # Leaves the injection string as is.
28
+ #
29
+ STRAIGHT = 1 << 0
30
+
31
+ #
32
+ # Apends the injection string to the default value of the input vector.<br/>
33
+ # (If no default value exists Arachni will choose one.)
34
+ #
35
+ APPEND = 1 << 1
36
+
37
+ #
38
+ # Terminates the injection string with a null character.
39
+ #
40
+ NULL = 1 << 2
41
+
42
+ #
43
+ # Prefix the string with a ';', useful for command injection modules
44
+ #
45
+ SEMICOLON = 1 << 3
46
+ end
47
+
48
+ def auditor( auditor )
49
+ @auditor = auditor
50
+ end
51
+
52
+ #
53
+ # Delegate output related methods to the auditor
54
+ #
55
+
56
+ def debug?
57
+ @auditor.debug? rescue false
58
+ end
59
+
60
+ def print_error( str = '' )
61
+ @auditor.print_error( str )
62
+ end
63
+
64
+ def print_status( str = '' )
65
+ @auditor.print_status( str )
66
+ end
67
+
68
+ def print_debug( str = '' )
69
+ @auditor.print_debug( str )
70
+ end
71
+
72
+
73
+ #
74
+ # Callback invoked by {Arachni::Element::Auditable#audit} to submit
75
+ # the object via {Arachni::Module::HTTP}.
76
+ #
77
+ # Must be implemented by the extending class.
78
+ #
79
+ # @param [String] url
80
+ # @param [Hash] opts
81
+ #
82
+ # @see #submit
83
+ #
84
+ def http_request( url, opts )
85
+
86
+ end
87
+
88
+ #
89
+ # Submits self using {#http_request}.
90
+ #
91
+ # @param [Hash] opts
92
+ #
93
+ # @see #http_request
94
+ #
95
+ def submit( opts = {} )
96
+
97
+ opts = Arachni::Module::Auditor::OPTIONS.merge( opts )
98
+ opts[:params] = @auditable.dup
99
+ @opts = opts
100
+
101
+ return http_request( @action, opts )
102
+ end
103
+
104
+ #
105
+ # Audits self
106
+ #
107
+ # @param [String] injection_str the string to be injected
108
+ # @param [Hash] opts options as described in {Arachni::Module::Auditor#OPTIONS}
109
+ # @param [Block] &block block to be passed the:
110
+ # * HTTP response
111
+ # * name of the input vector
112
+ # * updated opts
113
+ # The block will be called as soon as the
114
+ # HTTP response is received.
115
+ #
116
+ def audit( injection_str, opts = { }, &block )
117
+
118
+ # respect user audit options
119
+ audit_opt = "@audit_#{self.type}s"
120
+ return if !Arachni::Options.instance.instance_variable_get( audit_opt )
121
+
122
+ @@audited ||= Set.new
123
+
124
+ opts = Arachni::Module::Auditor::OPTIONS.merge( opts )
125
+ opts[:element] = self.type
126
+
127
+ opts[:injected_orig] = injection_str
128
+
129
+ # if we don't have any auditable elements just return
130
+ return if auditable.empty?
131
+
132
+ audit_id = audit_id( injection_str, opts )
133
+ return if !opts[:redundant] && audited?( audit_id )
134
+
135
+ results = []
136
+ # iterate through all variation and audit each one
137
+ injection_sets( injection_str, opts ).each {
138
+ |elem|
139
+
140
+ opts[:altered] = elem.altered.dup
141
+
142
+ return if skip?( elem )
143
+
144
+ # inform the user about what we're auditing
145
+ print_status( get_status_str( opts[:altered] ) )
146
+
147
+ # submit the element with the injection values
148
+ req = elem.submit( opts )
149
+ return if !req
150
+
151
+ on_complete( req, elem, &block )
152
+ req.after_complete {
153
+ |result|
154
+ results << result.flatten[1] if result.flatten[1]
155
+ }
156
+ }
157
+
158
+ audited( audit_id )
159
+ end
160
+
161
+ def skip?( elem )
162
+ return @auditor.skip?( elem )
163
+ end
164
+
165
+ #
166
+ # Injectes the injecton_str in self's values according to formatting options
167
+ # and returns an array of hashes in the form of:
168
+ # <altered_variable> => <new element>
169
+ #
170
+ # @param [String] injection_str the string to inject
171
+ #
172
+ # @return [Array]
173
+ #
174
+ def injection_sets( injection_str, opts = { } )
175
+
176
+ opts = Arachni::Module::Auditor::OPTIONS.merge( opts )
177
+ hash = auditable( ).dup
178
+
179
+ var_combo = []
180
+ if( !hash || hash.size == 0 ) then return [] end
181
+
182
+ if( self.is_a?( Arachni::Parser::Element::Form ) )
183
+
184
+ if !audited?( audit_id( Arachni::Parser::Element::Form::FORM_VALUES_ORIGINAL ) )
185
+ # this is the original hash, in case the default values
186
+ # are valid and present us with new attack vectors
187
+ elem = self.dup
188
+ elem.altered = Arachni::Parser::Element::Form::FORM_VALUES_ORIGINAL
189
+ var_combo << elem
190
+ end
191
+
192
+ if !audited?( audit_id( Arachni::Parser::Element::Form::FORM_VALUES_SAMPLE ) )
193
+ duphash = hash.dup
194
+ elem = self.dup
195
+ elem.auditable = Arachni::Module::KeyFiller.fill( duphash )
196
+ elem.altered = Arachni::Parser::Element::Form::FORM_VALUES_SAMPLE
197
+ var_combo << elem
198
+ end
199
+ end
200
+
201
+ chash = hash.dup
202
+ hash.keys.each {
203
+ |k|
204
+
205
+ # don't audit parameter flips
206
+ next if hash[k] == seed
207
+
208
+ chash = Arachni::Module::KeyFiller.fill( chash )
209
+ opts[:format].each {
210
+ |format|
211
+
212
+ str = format_str( injection_str, chash[k], format )
213
+
214
+ elem = self.dup
215
+ elem.altered = k.dup
216
+ elem.auditable = chash.merge( { k => str } )
217
+ var_combo << elem
218
+ }
219
+
220
+ }
221
+
222
+ if opts[:param_flip]
223
+ elem = self.dup
224
+ elem.altered = 'Parameter flip'
225
+ elem.auditable[injection_str] = seed
226
+ var_combo << elem
227
+ end
228
+
229
+ print_debug_injection_set( var_combo, opts )
230
+
231
+ return var_combo
232
+ end
233
+
234
+
235
+ # impersonate the auditor to the output methods
236
+ def info
237
+ @auditor ? @auditor.class.info : { :name => '' }
238
+ end
239
+
240
+ #
241
+ # Returns a status string that explaining what's happening.
242
+ #
243
+ # The string contains the name of the input that is being audited
244
+ # the url and the type of the input (form, link, cookie...)
245
+ #
246
+ # @param [String] url the url under audit
247
+ # @param [Hash] input
248
+ # @param [Hash] opts
249
+ #
250
+ # @return [String]
251
+ #
252
+ def get_status_str( altered )
253
+ return "Auditing #{self.type} variable '" + altered + "' of " + @action
254
+ end
255
+
256
+
257
+ private
258
+
259
+ #
260
+ # Registers a block to be executed as soon as the Typhoeus request (reg)
261
+ # has been completed and a response has been received.
262
+ #
263
+ # If no &block has been provided {#get_matches} will be called instead.
264
+ #
265
+ # @param [Typhoeus::Request] req
266
+ # @param [Arachni::Element::Auditable] auditable element
267
+ # @param [Hash] opts an updated hash of options
268
+ # @param [Block] &block block to be passed the:
269
+ # * HTTP response
270
+ # * name of the input vector
271
+ # * updated opts
272
+ # The block will be called as soon as the
273
+ # HTTP response is received.
274
+ #
275
+ def on_complete( req, elem, &block )
276
+
277
+ elem.opts[:injected] = elem.auditable[elem.altered].to_s
278
+ elem.opts[:combo] = elem.auditable
279
+ elem.opts[:action] = elem.action
280
+
281
+ if( !elem.opts[:async] )
282
+
283
+ if( req && req.response )
284
+ block.call( req.response, elem.opts, elem )
285
+ end
286
+
287
+ return
288
+ end
289
+
290
+ req.on_complete {
291
+ |res|
292
+
293
+ # make sure that we have a response before continuing
294
+ if !res
295
+ print_error( 'Failed to get responses, backing out... ' )
296
+ next
297
+ else
298
+ print_status( 'Analyzing response #' + res.request.id.to_s + '...' )
299
+ end
300
+
301
+ # call the block, if there's one
302
+ if block_given?
303
+ block.call( res, elem.opts, elem )
304
+ next
305
+ end
306
+
307
+ next if !res.body
308
+
309
+ # get matches
310
+ get_matches( res.dup, elem.opts )
311
+ }
312
+ end
313
+
314
+ #
315
+ # Tries to identify an issue through regexp pattern matching.
316
+ #
317
+ # If a issue is found a message will be printed and a hash
318
+ # will be returned describing the conditions under which
319
+ # the issue was discovered.
320
+ #
321
+ # @param [Typhoeus::Response]
322
+ # @param [Hash] opts
323
+ #
324
+ # @return [Hash]
325
+ #
326
+ def get_matches( res, opts )
327
+ [opts[:regexp]].flatten.compact.each { |regexp| match_regexp_and_log( regexp, res, opts ) }
328
+ [opts[:substring]].flatten.compact.each { |substring| match_substring_and_log( substring, res, opts ) }
329
+ end
330
+
331
+ def match_substring_and_log( substring, res, opts )
332
+
333
+ verification = false
334
+
335
+ # an annoying encoding exception may be thrown by scan()
336
+ # the sob started occuring again....
337
+ begin
338
+ if( @auditor.page.html.substring?( substring ) )
339
+ verification = true
340
+ end
341
+ rescue
342
+ end
343
+
344
+ if res.body.substring?( substring )
345
+ opts[:regexp] = opts[:id] = opts[:match] = substring.clone
346
+ @auditor.log( opts, res )
347
+ end
348
+ end
349
+
350
+ def match_regexp_and_log( regexp, res, opts )
351
+
352
+ match_data = res.body.scan( regexp )[0]
353
+ match_data = match_data.to_s
354
+
355
+ verification = false
356
+
357
+ # an annoying encoding exception may be thrown by scan()
358
+ # the sob started occuring again....
359
+ begin
360
+ if( @auditor.page.html.scan( regexp )[0] )
361
+ opts[:verification] = true
362
+ end
363
+ rescue
364
+ end
365
+
366
+ # fairly obscure condition...pardon me...
367
+ if ( opts[:match] && match_data == opts[:match] ) ||
368
+ ( !opts[:match] && match_data && match_data.size > 0 )
369
+
370
+ opts[:id] = opts[:match] = opts[:match] ? opts[:match] : match_data
371
+ opts[:regexp] = regexp
372
+
373
+ @auditor.log( opts, res )
374
+ end
375
+ end
376
+
377
+ #
378
+ # Returns am audit identifier string to be registered using {#audited}.
379
+ #
380
+ # @param [Hash] input
381
+ # @param [Hash] opts
382
+ #
383
+ # @return [String]
384
+ #
385
+ def audit_id( injection_str, opts = {} )
386
+ vars = auditable.keys.sort.to_s
387
+
388
+ timeout = opts[:timeout] || ''
389
+ return "#{@auditor.class.info[:name]}:" +
390
+ "#{@action}:" + "#{self.type}:" +
391
+ "#{vars}=#{injection_str.to_s}:timeout=#{timeout}"
392
+ end
393
+
394
+ #
395
+ # Checks whether or not an audit has been already performed.
396
+ #
397
+ # @param [String] audit_id a string returned by {#audit_id}
398
+ #
399
+ def audited?( audit_id )
400
+ ret = @@audited.include?( audit_id )
401
+
402
+ msg = 'Current audit ID: ' if !ret
403
+ msg = 'Skipping, already audited: ' if ret
404
+ print_debug( msg + audit_id )
405
+
406
+ return ret
407
+ end
408
+
409
+ #
410
+ # Registers an audit
411
+ #
412
+ # @param [String] audit_id a string returned by {#audit_id}
413
+ #
414
+ def audited( audit_id )
415
+ @@audited << audit_id
416
+ end
417
+
418
+ #
419
+ # Prepares an injection string following the specified formating options
420
+ # as contained in the format bitfield.
421
+ #
422
+ # @see Format
423
+ # @param [String] injection_str
424
+ # @param [String] default_str default value to be appended by the
425
+ # injection string if {Format::APPEND} is set in 'format'
426
+ # @param [Integer] format bitfield describing formating preferencies
427
+ #
428
+ # @return [String]
429
+ #
430
+ def format_str( injection_str, default_str, format )
431
+
432
+ semicolon = null = append = ''
433
+
434
+ null = "\0" if ( format & Format::NULL ) != 0
435
+ semicolon = ';' if ( format & Format::SEMICOLON ) != 0
436
+ append = default_str if ( format & Format::APPEND ) != 0
437
+ semicolon = append = null = '' if ( format & Format::STRAIGHT ) != 0
438
+
439
+
440
+ return semicolon + append + injection_str + null
441
+ end
442
+
443
+ def print_debug_injection_set( var_combo, opts )
444
+ return if !debug?
445
+
446
+ print_debug( )
447
+ print_debug_trainer( opts )
448
+ print_debug_formatting( opts )
449
+ print_debug_combos( var_combo )
450
+ end
451
+
452
+ def print_debug_formatting( opts )
453
+ print_debug( '------------' )
454
+
455
+ print_debug( 'Injection string format combinations set to:' )
456
+ print_debug( '|')
457
+ msg = []
458
+ opts[:format].each {
459
+ |format|
460
+
461
+ if( format & Format::NULL ) != 0
462
+ msg << 'null character termination (Format::NULL)'
463
+ end
464
+
465
+ if( format & Format::APPEND ) != 0
466
+ msg << 'append to default value (Format::APPEND)'
467
+ end
468
+
469
+ if( format & Format::STRAIGHT ) != 0
470
+ msg << 'straight, leave as is (Format::STRAIGHT)'
471
+ end
472
+
473
+ prep = msg.join( ' and ' ).capitalize + ". [Combo mask: #{format}]"
474
+ prep.gsub!( 'format::null', "Format::NULL [#{Format::NULL}]" )
475
+ prep.gsub!( 'format::append', "Format::APPEND [#{Format::APPEND}]" )
476
+ prep.gsub!( 'format::straight', "Format::STRAIGHT [#{Format::STRAIGHT}]" )
477
+ print_debug( "|----> " + prep )
478
+
479
+ msg.clear
480
+ }
481
+
482
+ end
483
+
484
+ def print_debug_combos( combos )
485
+
486
+ print_debug( )
487
+ print_debug( 'Prepared combinations:' )
488
+ print_debug('|' )
489
+
490
+ combos.each{
491
+ |elem|
492
+
493
+ altered = elem.altered
494
+ combo = elem.auditable
495
+
496
+
497
+ print_debug( '|' )
498
+ print_debug( "|--> Auditing: " + altered )
499
+ print_debug( "|--> Combo: " )
500
+
501
+ combo.each {
502
+ |combo|
503
+ print_debug( "|------> " + combo.to_s )
504
+ }
505
+
506
+ }
507
+
508
+ print_debug( )
509
+ print_debug( '------------' )
510
+ print_debug( )
511
+
512
+ end
513
+
514
+ def print_debug_trainer( opts )
515
+ print_debug( 'Trainer set to: ' + ( opts[:train] ? 'ON' : 'OFF' ) )
516
+ end
517
+
518
+
519
+ end
520
+
521
+ end
522
+ end