arachni 0.2.2.1

Sign up to get free protection for your applications and to get access to all the features.
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