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:

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.



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/arachni/issue.rb', line 111

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

#parentIssue?

Returns Parent of variation.

Returns:

  • (Issue, nil)

    Parent of variation.



107
108
109
# File 'lib/arachni/issue.rb', line 107

def parent
  @parent
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:



391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
# File 'lib/arachni/issue.rb', line 391

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



355
356
357
# File 'lib/arachni/issue.rb', line 355

def ==( other )
    hash == other.hash
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:



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

def active?
    !!(vector.respond_to?( :affected_input_name ) && vector.affected_input_name)
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.



190
191
192
193
194
195
# File 'lib/arachni/issue.rb', line 190

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:



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

def affected_input_name
    return if !active?
    vector.affected_input_name
end

#cwe_urlString

Returns CWE reference URL.

Returns:



245
246
247
248
# File 'lib/arachni/issue.rb', line 245

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:



351
352
353
# File 'lib/arachni/issue.rb', line 351

def digest
    unique_id.persistent_hash
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


363
364
365
# File 'lib/arachni/issue.rb', line 363

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

#hashObject



359
360
361
# File 'lib/arachni/issue.rb', line 359

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?


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

def passive?
    !active?
end

#recheck(framework = nil) ⇒ Issue?

Note:

The whole environment needs to be fresh.

Rechecks the existence of this issue.

Parameters:

  • framework (Framework.nil) (defaults to: nil)

    Framework to use, if ‘nil` is given a new Framework will be instantiated and used.

Returns:



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

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( parent ? parent.check[:shortname] : check[:shortname] )
        f.push_to_page_queue referring_page

        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:



179
180
181
182
# File 'lib/arachni/issue.rb', line 179

def request
    return if !response
    response.request
end

#responseHTTP::Response

Returns:



173
174
175
176
# File 'lib/arachni/issue.rb', line 173

def response
    return if !page
    page.response
end

#to_hHash Also known as: to_hash

Returns:



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

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.delete :parent

    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.



369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
# File 'lib/arachni/issue.rb', line 369

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?


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

def trusted?
    !!@trusted
end

#unique_idString

Returns A string uniquely identifying this issue.

Returns:

  • (String)

    A string uniquely identifying this issue.



337
338
339
340
341
342
343
344
345
# File 'lib/arachni/issue.rb', line 337

def unique_id
    return @unique_id if @unique_id

    vector_info = active? ?
        "#{vector.method}:#{vector.affected_input_name}:" :
        "#{proof}:"

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

#untrusted?Boolean

Returns:

  • (Boolean)

See Also:



233
234
235
# File 'lib/arachni/issue.rb', line 233

def untrusted?
    !trusted?
end