Class: Arachni::Issue

Inherits:
Object show all
Defined in:
lib/arachni/issue.rb,
lib/arachni/issue/severity.rb,
lib/arachni/issue/severity/base.rb

Overview

Represents a detected issue.

Author:

  • Tasos “Zapotek” Laskos <tasos.laskos@arachni-scanner.com>

Defined Under Namespace

Modules: Severity

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Issue

Returns a new instance of Issue.

Parameters:

  • options (Hash) (defaults to: {})

    Configuration hash holding instance attributes.



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/arachni/issue.rb', line 107

def initialize( options = {} )
    # Make sure we're dealing with UTF-8 data.
    options = options.recode

    options.each do |k, v|
        send( "#{k.to_s.downcase}=", v )
    end

    fail ArgumentError, 'Missing :vector' if !@vector

    @remarks    ||= {}
    @trusted      = true if @trusted.nil?
    @references ||= {}
    @tags       ||= []
end

Instance Attribute Details

#checkHash

Returns Information about the check that logged the issue.

Returns:



85
86
87
# File 'lib/arachni/issue.rb', line 85

def check
  @check
end

#cweString

Returns The CWE ID number of the issue.

Returns:

  • (String)

    The CWE ID number of the issue.

See Also:



56
57
58
# File 'lib/arachni/issue.rb', line 56

def cwe
  @cwe
end

#descriptionString

Note:

Should be treated as Markdown.

Returns Brief description.

Returns:

  • (String)

    Brief description.



26
27
28
# File 'lib/arachni/issue.rb', line 26

def description
  @description
end

#nameString

Returns Name.

Returns:



20
21
22
# File 'lib/arachni/issue.rb', line 20

def name
  @name
end

#pagePage

Returns Page proving the issue.

Returns:

  • (Page)

    Page proving the issue.



81
82
83
# File 'lib/arachni/issue.rb', line 81

def page
  @page
end

#platform_nameSymbol

Returns Name of the vulnerable platform.

Returns:

  • (Symbol)

    Name of the vulnerable platform.

See Also:



62
63
64
# File 'lib/arachni/issue.rb', line 62

def platform_name
  @platform_name
end

#platform_typeSymbol

Returns Type of the vulnerable platform.

Returns:

  • (Symbol)

    Type of the vulnerable platform.

See Also:



68
69
70
# File 'lib/arachni/issue.rb', line 68

def platform_type
  @platform_type
end

#proofString

Returns Data that was matched by the #signature.

Returns:



93
94
95
# File 'lib/arachni/issue.rb', line 93

def proof
  @proof
end

#referencesHash

Returns References related to the issue.

Returns:

  • (Hash)

    References related to the issue.



50
51
52
# File 'lib/arachni/issue.rb', line 50

def references
  @references
end

#referring_pagePage

Returns Page containing the #vector and whose audit resulted in the discovery of the issue.

Returns:

  • (Page)

    Page containing the #vector and whose audit resulted in the discovery of the issue.



77
78
79
# File 'lib/arachni/issue.rb', line 77

def referring_page
  @referring_page
end

#remarksHash

Returns Remarks about the issue. Key is the name of the entity which made the remark, value is an `Array` of remarks.

Returns:

  • (Hash)

    Remarks about the issue. Key is the name of the entity which made the remark, value is an `Array` of remarks.



103
104
105
# File 'lib/arachni/issue.rb', line 103

def remarks
  @remarks
end

#remedy_codeString

Returns Code snippet demonstrating how to remedy the Issue.

Returns:

  • (String)

    Code snippet demonstrating how to remedy the Issue.



36
37
38
# File 'lib/arachni/issue.rb', line 36

def remedy_code
  @remedy_code
end

#remedy_guidanceString

Note:

Should be treated as Markdown.

Returns Brief text explaining how to remedy the issue.

Returns:

  • (String)

    Brief text explaining how to remedy the issue.



32
33
34
# File 'lib/arachni/issue.rb', line 32

def remedy_guidance
  @remedy_guidance
end

#severityString

Returns Severity of the issue.

Returns:

  • (String)

    Severity of the issue.

See Also:



42
43
44
# File 'lib/arachni/issue.rb', line 42

def severity
  @severity
end

#signatureString

Returns The signature/pattern that identified the issue.

Returns:

  • (String)

    The signature/pattern that identified the issue.



89
90
91
# File 'lib/arachni/issue.rb', line 89

def signature
  @signature
end

#tagsArray<String>

Returns Tags categorizing the issue.

Returns:



46
47
48
# File 'lib/arachni/issue.rb', line 46

def tags
  @tags
end

#trustedBool

Returns `true` if the issue can be trusted (doesn't require manual verification), `false` otherwise.

Returns:

  • (Bool)

    `true` if the issue can be trusted (doesn't require manual verification), `false` otherwise.



98
99
100
# File 'lib/arachni/issue.rb', line 98

def trusted
  @trusted
end

#vectorElement::Base?

Returns Instance of the relevant vector if available.

Returns:

  • (Element::Base, nil)

    Instance of the relevant vector if available.



72
73
74
# File 'lib/arachni/issue.rb', line 72

def vector
  @vector
end

Class Method Details

.from_rpc_data(data) ⇒ Issue

Parameters:

Returns:



419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
# File 'lib/arachni/issue.rb', line 419

def self.from_rpc_data( data )
    instance = allocate

    data.each do |name, value|
        value = case name
                    when 'vector'
                        element_string_to_class( value.delete('class') ).from_rpc_data( value )

                    when 'check'
                        if value['elements']
                            value['elements'] = (value['elements'].map do |class_name|
                                element_string_to_class( class_name )
                            end)
                        end

                        value.my_symbolize_keys(false)

                    when 'remarks'
                        value.my_symbolize_keys

                    when 'platform_name', 'platform_type'
                        next if !value
                        value.to_sym

                    when 'severity'
                        next if value.to_s.empty?
                        Severity.const_get( value.upcase.to_sym )

                    when 'page', 'referring_page'
                        Arachni::Page.from_rpc_data( value )

                    else
                        value
                end

        instance.instance_variable_set( "@#{name}", value )
    end

    instance
end

Instance Method Details

#<(other) ⇒ Object



387
388
389
# File 'lib/arachni/issue.rb', line 387

def <( other )
    severity < other.severity
end

#<=>(other) ⇒ Object



383
384
385
# File 'lib/arachni/issue.rb', line 383

def <=>( other )
    severity <=> other.severity
end

#==(other) ⇒ Object



371
372
373
# File 'lib/arachni/issue.rb', line 371

def ==( other )
    hash == other.hash
end

#>(other) ⇒ Object



391
392
393
# File 'lib/arachni/issue.rb', line 391

def >( other )
    severity > other.severity
end

#active?Boolean

Returns `true` if the issue was discovered by manipulating an input, `false` otherwise.

Returns:

  • (Boolean)

    `true` if the issue was discovered by manipulating an input, `false` otherwise.

See Also:



200
201
202
203
204
205
# File 'lib/arachni/issue.rb', line 200

def active?
    !!(
        (vector.respond_to?( :affected_input_name ) && vector.affected_input_name) &&
            (vector.respond_to?( :seed ) && vector.seed)
    )
end

#add_remark(author, string) ⇒ Object

Adds a remark as a heads-up to the end user.

Parameters:

  • author (String, Symbol)

    Component which made the remark.

  • string (String)

    Remark.



188
189
190
191
192
193
# File 'lib/arachni/issue.rb', line 188

def add_remark( author, string )
    fail ArgumentError, 'Author cannot be blank.' if author.to_s.empty?
    fail ArgumentError, 'String cannot be blank.' if string.to_s.empty?

    (@remarks[author] ||= []) << string
end

#affected_input_nameString?

Returns The name of the affected input, `nil` if the issue is #passive?.

Returns:

  • (String, nil)

    The name of the affected input, `nil` if the issue is #passive?.

See Also:



211
212
213
214
# File 'lib/arachni/issue.rb', line 211

def affected_input_name
    return if !active?
    vector.affected_input_name
end

#affected_input_valueString?

Returns The name of the affected input, `nil` if the issue is #passive?.

Returns:

  • (String, nil)

    The name of the affected input, `nil` if the issue is #passive?.

See Also:



220
221
222
223
# File 'lib/arachni/issue.rb', line 220

def affected_input_value
    return if !active?
    vector.inputs[affected_input_name]
end

#cwe_urlString

Returns CWE reference URL.

Returns:



255
256
257
258
# File 'lib/arachni/issue.rb', line 255

def cwe_url
    return if !cwe
    @cwe_url ||= "http://cwe.mitre.org/data/definitions/#{cwe}.html".freeze
end

#digestInteger

Returns A hash uniquely identifying this issue.

Returns:

  • (Integer)

    A hash uniquely identifying this issue.

See Also:



367
368
369
# File 'lib/arachni/issue.rb', line 367

def digest
    unique_id.persistent_hash
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


379
380
381
# File 'lib/arachni/issue.rb', line 379

def eql?( other )
    hash == other.hash
end

#hashObject



375
376
377
# File 'lib/arachni/issue.rb', line 375

def hash
    unique_id.hash
end

#passive?Boolean

Returns `true` if the issue was discovered passively, `false` otherwise.

Returns:

  • (Boolean)

    `true` if the issue was discovered passively, `false` otherwise.

See Also:

  • audit?


229
230
231
# File 'lib/arachni/issue.rb', line 229

def passive?
    !active?
end

#recheck(framework = nil) ⇒ Issue?

Note:

The whole environment needs to be fresh.

Rechecks the existence of this issue.

Parameters:

Returns:



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/arachni/issue.rb', line 133

def recheck( framework = nil )
    original_options = Options.to_h

    new_issue = nil
    checker = proc do |f|
        if active?
            referring_page.update_element_audit_whitelist vector
            f.options.audit.elements vector.class.type
            f.options.audit.include_vector_patterns = [affected_input_name]
        end

        f.options.url = referring_page.url

        f.checks.load( check[:shortname] )
        f.plugins.load( f.options.plugins.keys )

        f.push_to_page_queue referring_page
        # Needs to happen **AFTER** the push to page queue.
        f.options.scope.do_not_crawl

        f.run

        new_issue = Data.issues[digest]
    end

    if framework
        checker.call framework
    else
        Framework.new( &checker )
    end

    new_issue
ensure
    Options.reset
    Options.set original_options
end

#requestHTTP::Request

Returns:



177
178
179
180
# File 'lib/arachni/issue.rb', line 177

def request
    return if !response
    response.request
end

#responseHTTP::Response

Returns:



171
172
173
174
# File 'lib/arachni/issue.rb', line 171

def response
    return if !page
    page.response
end

#to_hHash Also known as: to_hash

Returns:



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
# File 'lib/arachni/issue.rb', line 295

def to_h
    h = {}

    self.instance_variables.each do |var|
        h[normalize_name( var )] = try_dup( instance_variable_get( var ) )
    end

    h[:vector] = vector.to_h
    h.delete( :unique_id )

    h[:vector][:affected_input_name] = affected_input_name

    h[:digest]   = digest
    h[:severity] = severity.to_sym
    h[:cwe_url]  = cwe_url if cwe_url

    # Since we're doing the whole cross-platform hash thing better switch
    # the Element classes in the check's info data to symbols.
    h[:check][:elements] ||= []
    h[:check][:elements]   = h[:check][:elements].map(&:type)

    if page
        dom_h = page.dom.to_h
        dom_h.delete(:skip_states)

        h[:page] = {
            body: page.body,
            dom:  dom_h
        }
    end

    if referring_page
        referring_page_dom_h = referring_page.dom.to_h
        referring_page_dom_h.delete(:skip_states)

        h[:referring_page] = {
            body: referring_page.body,
            dom:  referring_page_dom_h
        }
    end

    h[:response] = response.to_h if response
    h[:request]  = request.to_h  if request

    h
end

#to_rpc_dataHash

Returns Data representing this instance that are suitable the RPC transmission.

Returns:

  • (Hash)

    Data representing this instance that are suitable the RPC transmission.



397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
# File 'lib/arachni/issue.rb', line 397

def to_rpc_data
    data = {}
    instance_variables.each do |ivar|
        data[ivar.to_s.gsub('@','')] =
            instance_variable_get( ivar ).to_rpc_data_or_self
    end

    if data['check'] && data['check'][:elements]
        data['check'] = data['check'].dup
        data['check'][:elements] = data['check'][:elements].map(&:to_s)
    end

    data['unique_id'] = unique_id
    data['digest']    = digest
    data['severity']  = data['severity'].to_s

    data
end

#trusted?Bool

Returns `true` if the issue can be trusted (doesn't require manual verification), `false` otherwise.

Returns:

  • (Bool)

    `true` if the issue can be trusted (doesn't require manual verification), `false` otherwise.

See Also:

  • #requires_verification?


238
239
240
# File 'lib/arachni/issue.rb', line 238

def trusted?
    !!@trusted
end

#unique_idString

Returns A string uniquely identifying this issue.

Returns:

  • (String)

    A string uniquely identifying this issue.



345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
# File 'lib/arachni/issue.rb', line 345

def unique_id
    return @unique_id if @unique_id

    vector_info =   if passive?
                        proof
                    else
                        if vector.respond_to?( :method )
                            vector.method
                        end
                    end.to_s.dup

    if vector.respond_to?( :affected_input_name )
        vector_info << ":#{vector.affected_input_name}"
    end

    "#{name}:#{vector_info}:#{vector.action.split( '?' ).first}"
end

#untrusted?Boolean

Returns:

  • (Boolean)

See Also:



243
244
245
# File 'lib/arachni/issue.rb', line 243

def untrusted?
    !trusted?
end