Class: Arachni::Element::Form
- Includes:
- Capabilities::Analyzable, Capabilities::Auditable, Capabilities::Mutable, Capabilities::Refreshable, Capabilities::Submittable, Capabilities::WithDOM
- Defined in:
- lib/arachni/element/form.rb,
lib/arachni/element/form/dom.rb,
lib/arachni/element/form/capabilities/mutable.rb,
lib/arachni/element/form/capabilities/with_dom.rb,
lib/arachni/element/form/capabilities/auditable.rb,
lib/arachni/element/form/capabilities/submittable.rb
Overview
Represents an auditable form element
Defined Under Namespace
Modules: Capabilities Classes: DOM, Error
Constant Summary collapse
- ORIGINAL_VALUES =
'__original_values__'
- SAMPLE_VALUES =
'__sample_values__'
Constants included from Capabilities::Mutable
Capabilities::Mutable::EXTRA_NAME, Capabilities::Mutable::FUZZ_NAME, Capabilities::Mutable::FUZZ_NAME_VALUE, Capabilities::Mutable::MUTATION_OPTIONS
Constants included from Capabilities::Auditable
Capabilities::Auditable::OPTIONS
Constants included from Capabilities::Inputtable
Capabilities::Inputtable::INPUTTABLE_CACHE
Constants included from Capabilities::Analyzable::Differential
Capabilities::Analyzable::Differential::DIFFERENTIAL_OPTIONS
Constants included from Capabilities::Analyzable::Timeout
Capabilities::Analyzable::Timeout::TIMEOUT_OPTIONS
Constants included from Capabilities::Analyzable::Taint
Capabilities::Analyzable::Taint::TAINT_CACHE, Capabilities::Analyzable::Taint::TAINT_OPTIONS
Constants inherited from Base
Instance Attribute Summary collapse
-
#name ⇒ String?
Name of the form, if it has one.
-
#nonce_name ⇒ String
The name of the input name that holds the nonce.
Attributes included from Capabilities::Mutable
#affected_input_name, #format, #seed
Attributes included from Capabilities::Auditable
Attributes included from Capabilities::WithAuditor
Attributes included from Capabilities::Inputtable
Attributes included from Capabilities::WithDOM
Attributes included from Capabilities::Analyzable::Differential
#differential_analysis_options
Attributes included from Capabilities::Analyzable::Timeout
Attributes inherited from Base
#initialization_options, #page
Class Method Summary collapse
- .attributes_to_hash(attributes) ⇒ Object
-
.decode(string) ⇒ String
Decodes a String encoded for an HTTP request’s body.
-
.encode(string) ⇒ String
Encodes a String‘s reserved characters in order to prepare it to be included in a request body.
-
.from_document(url, document, ignore_scope = false) ⇒ Array<Form>
Extracts forms from an HTML document.
- .from_node(url, node, ignore_scope = false) ⇒ Object
-
.from_response(response, ignore_scope = false) ⇒ Array<Form>
Extracts forms by parsing the body of an HTTP response.
Instance Method Summary collapse
- #decode(str) ⇒ Object
-
#details_for(input) ⇒ Hash
Information about the given input’s attributes.
- #dup ⇒ Object
- #encode(str) ⇒ Object
- #fake_field?(name) ⇒ Boolean
-
#field_type_for(name) ⇒ String
Retrieves a field type for the given field ‘name`.
- #force_train? ⇒ Boolean
-
#has_nonce? ⇒ Bool
‘true` if the form contains a nonce, `false` otherwise.
-
#initialize(options) ⇒ Form
constructor
A new instance of Form.
- #mirror_password_fields ⇒ Object
-
#name_or_id ⇒ String
Name of ID HTML attributes for this form.
-
#requires_password? ⇒ Bool
Checks whether or not the form contains 1 or more password fields.
-
#simple ⇒ Hash
A simple representation of self including attributes and inputs.
Methods included from Capabilities::Mutable
#affected_input_value, #affected_input_value=, #each_mutation, #immutables, #inspect, #mutation?, #mutations, #reset, #switch_method, #to_h, #to_rpc_data
Methods included from Capabilities::Submittable
#action, #action=, #http, #id, #method, #method=, #platforms, #submit, #to_h
Methods included from Capabilities::Auditable
#audit, #audit_id, #audit_status_message, #audit_status_message_action, #audit_verbose_message, #coverage_hash, #coverage_id, #matches_skip_like_blocks?, #reset, reset, skip_like
Methods included from Capabilities::WithAuditor
#marshal_dump, #orphan?, #prepare_for_report, #remove_auditor
Methods included from Capabilities::Inputtable
#[], #[]=, #changes, #has_inputs?, #inputtable_id, #reset, #to_h, #try_input, #update, #valid_input_data?, #valid_input_name?, #valid_input_name_data?, #valid_input_value?, #valid_input_value_data?
Methods included from Utilities
#available_port, #bytes_to_kilobytes, #bytes_to_megabytes, #caller_name, #caller_path, #cookie_decode, #cookie_encode, #cookies_from_document, #cookies_from_file, #cookies_from_response, #exception_jail, #exclude_path?, #follow_protocol?, #form_decode, #form_encode, #forms_from_document, #forms_from_response, #full_and_absolute_url?, #generate_token, #get_path, #hms_to_seconds, #html_decode, #html_encode, #include_path?, #links_from_document, #links_from_response, #normalize_url, #page_from_response, #page_from_url, #parse_set_cookie, #path_in_domain?, #path_too_deep?, #port_available?, #rand_port, #random_seed, #redundant_path?, #regexp_array_match, #remove_constants, #request_parse_body, #seconds_to_hms, #skip_page?, #skip_path?, #skip_resource?, #skip_response?, #to_absolute, #uri_decode, #uri_encode, #uri_parse, #uri_parse_query, #uri_parser, #uri_rewrite
Methods included from Capabilities::WithDOM
Methods included from Capabilities::Refreshable
Methods included from Capabilities::Analyzable
has_timeout_candidates?, reset, timeout_audit_run
Methods included from Capabilities::Analyzable::Differential
#differential_analysis, reset, #to_rpc_data
Methods included from Capabilities::Analyzable::Timeout
add_phase_2_candidate, candidates_include?, deduplicate, deduplicate?, do_not_deduplicate, #ensure_responsiveness, has_candidates?, payload_delay_from_options, reset, run, #timeout_analysis, timeout_from_options, #timeout_id, #timing_attack_probe, #timing_attack_verify, #to_rpc_data
Methods included from Capabilities::Analyzable::Taint
Methods inherited from Base
#==, #action, from_rpc_data, #hash, #id, #marshal_dump, #marshal_load, #persistent_hash, #prepare_for_report, #reset, #to_h, #to_hash, #to_rpc_data, too_big?, type, #type, #url, #url=
Methods included from Capabilities::WithScope
Constructor Details
#initialize(options) ⇒ Form
Returns a new instance of Form.
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/arachni/element/form.rb', line 79 def initialize( ) super( ) @name = [:name] @id = [:id] @input_details = {} cinputs = ([:inputs] || {}).inject({}) do |h, (name, value_or_info)| if value_or_info.is_a? Hash value_or_info = value_or_info.my_symbolize_keys h[name] = value_or_info[:value] @input_details[name.to_s] = value_or_info else h[name] = value_or_info end h end self.inputs = (method == :get ? (self.inputs || {}).merge(cinputs) : cinputs ) @default_inputs = self.inputs.dup.freeze end |
Instance Attribute Details
#name ⇒ String?
Returns Name of the form, if it has one.
56 57 58 |
# File 'lib/arachni/element/form.rb', line 56 def name @name end |
#nonce_name ⇒ String
Returns The name of the input name that holds the nonce.
52 53 54 |
# File 'lib/arachni/element/form.rb', line 52 def nonce_name @nonce_name end |
Class Method Details
.attributes_to_hash(attributes) ⇒ Object
386 387 388 |
# File 'lib/arachni/element/form.rb', line 386 def attributes_to_hash( attributes ) attributes.inject( {} ){ |h, (k, v)| h[k.to_sym] = v.to_s; h } end |
.decode(string) ⇒ String
Decodes a String encoded for an HTTP request’s body.
405 406 407 |
# File 'lib/arachni/element/form.rb', line 405 def decode( string ) ::URI.decode_www_form_component string.to_s end |
.encode(string) ⇒ String
Encodes a String‘s reserved characters in order to prepare it to be included in a request body.
396 397 398 |
# File 'lib/arachni/element/form.rb', line 396 def encode( string ) Arachni::HTTP::Request.encode string end |
.from_document(url, document, ignore_scope = false) ⇒ Array<Form>
Extracts forms from an HTML document.
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'lib/arachni/element/form.rb', line 264 def from_document( url, document, ignore_scope = false ) if !document.is_a?( Nokogiri::HTML::Document ) document = document.to_s return [] if !(document =~ /<\s*form/i) document = Nokogiri::HTML( document ) end base_url = (document.search( '//base[@href]' )[0]['href'] rescue url) base_url = to_absolute( base_url, url ) document.search( '//form' ).map do |node| next if !(forms = from_node( base_url, node, ignore_scope )) next if forms.empty? forms.each do |form| form.url = url.freeze form end end.flatten.compact end |
.from_node(url, node, ignore_scope = false) ⇒ Object
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 |
# File 'lib/arachni/element/form.rb', line 287 def from_node( url, node, ignore_scope = false ) = attributes_to_hash( node.attributes ) [:url] = url.freeze [:action] = to_absolute( [:action], url ).freeze [:inputs] = {} [:source] = node.to_html.freeze if (parsed_url = Arachni::URI( [:action] )) return if !ignore_scope && parsed_url.scope.out? end # Forms can have many submit inputs with identical names but different # values, to act as a sort of multiple choice. # However, each Arachni Form can have only unique input names, so # we keep track of this here and create a new form for each choice. multiple_choice_submits = {} %w(textarea input select button).each do |attr| [attr] ||= [] node.search( ".//#{attr}" ).each do |elem| elem_attrs = attributes_to_hash( elem.attributes ) elem_attrs[:type] = elem_attrs[:type].to_sym if elem_attrs[:type] name = elem_attrs[:name] || elem_attrs[:id] next if !name # Handle the easy stuff first... if elem.name != 'select' [:inputs][name] = elem_attrs if elem_attrs[:type] == :submit multiple_choice_submits[name] ||= Set.new multiple_choice_submits[name] << elem_attrs[:value] end [:inputs][name][:type] ||= :text [:inputs][name][:value] ||= '' if too_big?( [:inputs][name][:value] ) [:inputs][name][:value] = '' end next end # If the select has options figure out which to use. if elem.children.css('option').any? elem.children.css('option').each do |child| h = attributes_to_hash( child.attributes ) h[:type] = :select h[:value] ||= child.text if too_big?( h[:value] ) h[:value] = '' end # Prefer the selected or first option. if h[:selected] [:inputs][name] = h else [:inputs][name] ||= h end end # The select has no options, use an empty string. else [:inputs][name] = { type: :select, value: '' } end end end return [new( )] if multiple_choice_submits.empty? # If there are multiple submit with the same name but different values, # create forms for each value. multiple_choice_submits.map do |name, values| values.map.with_index do |value, i| o = if values.size > 1 o = .deep_clone o[:inputs][name][:value] = value # We need to add this here because if the forms have the # same input names only the first one will be audited. o[:inputs]["_#{name}_#{i}"] = { type: :fake, value: value } end new( o ) end end.flatten.compact end |
Instance Method Details
#decode(str) ⇒ Object
231 232 233 |
# File 'lib/arachni/element/form.rb', line 231 def decode( str ) self.class.decode( str ) end |
#details_for(input) ⇒ Hash
Returns Information about the given input’s attributes.
113 114 115 |
# File 'lib/arachni/element/form.rb', line 113 def details_for( input ) @input_details[input.to_s] || {} end |
#dup ⇒ Object
235 236 237 238 239 240 241 242 243 244 |
# File 'lib/arachni/element/form.rb', line 235 def dup super.tap do |f| f.nonce_name = nonce_name.dup if nonce_name f.mutation_with_original_values if mutation_with_original_values? f.mutation_with_sample_values if mutation_with_sample_values? f.requires_password = requires_password? end end |
#encode(str) ⇒ Object
223 224 225 |
# File 'lib/arachni/element/form.rb', line 223 def encode( str ) self.class.encode( str ) end |
#fake_field?(name) ⇒ Boolean
215 216 217 |
# File 'lib/arachni/element/form.rb', line 215 def fake_field?( name ) field_type_for( name ) == :fake end |
#field_type_for(name) ⇒ String
Retrieves a field type for the given field ‘name`.
211 212 213 |
# File 'lib/arachni/element/form.rb', line 211 def field_type_for( name ) details_for( name )[:type] || :text end |
#force_train? ⇒ Boolean
104 105 106 |
# File 'lib/arachni/element/form.rb', line 104 def force_train? mutation_with_original_values? || mutation_with_sample_values? end |
#has_nonce? ⇒ Bool
Returns ‘true` if the form contains a nonce, `false` otherwise.
157 158 159 |
# File 'lib/arachni/element/form.rb', line 157 def has_nonce? !!nonce_name end |
#mirror_password_fields ⇒ Object
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/arachni/element/form.rb', line 129 def mirror_password_fields return if !requires_password? # if there are two password type fields in the form there's a good # chance that it's a 'please retype your password' thing so make sure # that we have a variation which has identical password values password_fields = inputs.keys. select { |input| field_type_for( input ) == :password } return if password_fields.size != 2 self[password_fields[0]] = self[password_fields[1]] nil end |
#name_or_id ⇒ String
Returns Name of ID HTML attributes for this form.
119 120 121 |
# File 'lib/arachni/element/form.rb', line 119 def name_or_id name || @id end |
#requires_password? ⇒ Bool
Checks whether or not the form contains 1 or more password fields.
149 150 151 152 153 |
# File 'lib/arachni/element/form.rb', line 149 def requires_password? return @requires_password if !@requires_password.nil? inputs.each { |k, _| return @requires_password = true if field_type_for( k ) == :password } @requires_password = false end |
#simple ⇒ Hash
Returns A simple representation of self including attributes and inputs.
125 126 127 |
# File 'lib/arachni/element/form.rb', line 125 def simple @initialization_options.merge( url: url, action: action, inputs: inputs ) end |