Class: Arachni::Element::Cookie

Inherits:
Base show all
Defined in:
lib/arachni/element/cookie.rb

Overview

Represents a Cookie object and provides helper class methods for parsing, encoding, etc.

Author:

Constant Summary collapse

DEFAULT =

Default cookie values

{
       "name" => nil,
      "value" => nil,
    "version" => 0,
       "port" => nil,
    "discard" => nil,
"comment_url" => nil,
    "expires" => nil,
    "max_age" => nil,
    "comment" => nil,
     "secure" => nil,
       "path" => nil,
     "domain" => nil,
   "httponly" => false
}

Constants included from Arachni::Element::Capabilities::Auditable

Arachni::Element::Capabilities::Auditable::OPTIONS

Constants included from Arachni::Element::Capabilities::Auditable::RDiff

Arachni::Element::Capabilities::Auditable::RDiff::RDIFF_OPTIONS

Constants included from Arachni::Element::Capabilities::Auditable::Taint

Arachni::Element::Capabilities::Auditable::Taint::TAINT_OPTIONS

Constants included from Arachni::Element::Capabilities::Mutable

Arachni::Element::Capabilities::Mutable::MUTATION_OPTIONS

Instance Attribute Summary

Attributes inherited from Base

#raw

Attributes included from Arachni::Element::Capabilities::Auditable

#auditor, #opts, #orig

Attributes included from Arachni::Element::Capabilities::Mutable

#altered

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

#action, #action=, #id, #method, #method=, #url, #url=

Methods included from Utilities

#cookie_encode, #cookies_from_document, #cookies_from_file, #cookies_from_response, #exception_jail, #exclude_path?, #extract_domain, #form_decode, #form_encode, #form_parse_request_body, #forms_from_document, #forms_from_response, #get_path, #hash_keys_to_str, #html_decode, #html_encode, #include_path?, #links_from_document, #links_from_response, #normalize_url, #page_from_response, #page_from_url, #parse_query, #parse_set_cookie, #parse_url_vars, #path_in_domain?, #path_too_deep?, #remove_constants, #seed, #skip_path?, #to_absolute, #uri_decode, #uri_encode, #uri_parse, #uri_parser, #url_sanitize

Methods included from Arachni::Element::Capabilities::Auditable

#==, #[], #[]=, #audit_id, #auditable, #changes, #debug?, #has_inputs?, #hash, #http, #info, #orphan?, #override_instance_scope, #override_instance_scope?, #print_bad, #print_debug, #print_debug_backtrace, #print_error, #print_error_backtrace, #print_info, #print_line, #print_ok, #print_status, #provisioned_issue_id, #remove_auditor, #reset, reset, reset_instance_scope, #reset_scope_override, restrict_to_elements, #scope_audit_id, #skip?, #skip_path?, #status_string, #submit, #update

Methods included from Arachni::Element::Capabilities::Auditable::RDiff

included, #rdiff_analysis

Methods included from Arachni::Element::Capabilities::Auditable::Timeout

add_timeout_audit_block, add_timeout_candidate, #call_on_timing_blocks, call_on_timing_blocks, current_timeout_audit_operations_cnt, included, on_timing_attacks, #responsive?, running_timeout_attacks?, #timeout_analysis, timeout_analysis_phase_2, timeout_audit_blocks, timeout_audit_operations_cnt, timeout_audit_run, timeout_loaded_modules

Methods included from Arachni::Element::Capabilities::Auditable::Taint

#taint_analysis

Methods included from Arachni::Element::Capabilities::Mutable

#altered_value, #altered_value=, #immutables, #mutated?, #mutations_for, #original?, #permutations, #permutations_for

Constructor Details

#initialize(url, raw = {}) ⇒ Cookie

Returns a new instance of Cookie.



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/arachni/element/cookie.rb', line 52

def initialize( url, raw = {} )
    super( url, raw )

    self.action = @url
    self.method = 'get'

    @raw ||= {}
    if @raw['name'] && @raw['value']
        self.auditable = { @raw['name'] => @raw['value'] }
    else
        self.auditable = raw.dup
    end

    @raw = @raw.merge( DEFAULT.merge( @raw ) )
    if @raw['value'] && !@raw['value'].empty?
        @raw['value'] = decode( @raw['value'].to_s )
    end

    parsed_uri = uri_parse( @url )
    if !@raw['path']
        path = parsed_uri.path
        path = !path.empty? ? path : '/'
        @raw['path'] = path
    end

    @raw['domain'] ||= parsed_uri.host

    @raw['max_age'] = @raw['max_age'] if @raw['max_age']

    @orig   = self.auditable.dup
    @orig.freeze
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(sym, *args, &block) ⇒ Object

Uses the method name as a key to cookie attributes in DEFAULT.

Examples:

c = Cookie.from_set_cookie( 'http://owner-url.com/stuff', 'session=stuffstuffstuff' ).first

p c.name
#=> "session"

p c.value
#=> "stuffstuffstuff"

p c.path
#=> "/stuff"


454
455
456
457
# File 'lib/arachni/element/cookie.rb', line 454

def method_missing( sym, *args, &block )
    return @raw[sym.to_s] if respond_to?( sym )
    super( sym, *args, &block )
end

Class Method Details

.decode(str) ⇒ String

Decodes a String encoded for the Cookie header field.

Examples:

p Cookie.decode "%2B%3B%25%3D%00+"
#=> "+;%=\x00 "

Parameters:

Returns:

  • (String)

    the decoded string



1024
1025
1026
# File 'lib/arachni/element/cookie.rb', line 1024

def self.decode( str )
    URI.decode( str.gsub( '+', ' ' ) )
end

.encode(str) ⇒ String

Encodes a String‘s reserved characters in order to prepare it for the ’Cookie’ header field.

#example

p Cookie.encode "+;%=\0 "
#=> "%2B%3B%25%3D%00+"

Parameters:

Returns:

  • (String)

    the encoded string



1005
1006
1007
# File 'lib/arachni/element/cookie.rb', line 1005

def self.encode( str )
    URI.encode( str, "+;%=\0" ).gsub( ' ', '+' )
end

.expires_to_time(expires) ⇒ Time

Converts a cookie’s expiration date to a Ruby Time object.

Examples:

String time format

p Cookie.expires_to_time "Tue, 02 Oct 2012 19:25:57 GMT"
#=> 2012-10-02 22:25:57 +0300

Seconds since Epoch

p Cookie.expires_to_time "1596981560"
#=> 2020-08-09 16:59:20 +0300

p Cookie.expires_to_time 1596981560
#=> 2020-08-09 16:59:20 +0300

Parameters:

Returns:

  • (Time)


636
637
638
639
# File 'lib/arachni/element/cookie.rb', line 636

def self.expires_to_time( expires )
    return nil if expires == '0'
    (expires_to_i = expires.to_i) > 0 ? Time.at( expires_to_i ) : Time.parse( expires )
end

.from_document(url, document) ⇒ Array<Cookie>

Returns an array of cookies from a document based on Set-Cookie http-equiv meta tags.

Examples:


body = <<-HTML
    <html>
        <head>
            <meta http-equiv="Set-Cookie" content="cookie=val; httponly">
            <meta http-equiv="Set-Cookie" content="cookie2=val2; Expires=Thu, 01 Jan 1970 00:00:01 GMT; Path=/; Domain=.foo.com; HttpOnly; secure">
        </head>
    </html>
HTML

p Cookie.from_document 'http://owner-url.com', body
#=> [cookie=val, cookie2=val2]

p Cookie.from_document 'http://owner-url.com', Nokogiri::HTML( body )
#=> [cookie=val, cookie2=val2]

# Fancy dump:
# [
#     [0] #<Arachni::Element::Cookie:0x02a23030
#         attr_accessor :action = "http://owner-url.com/",
#         attr_accessor :auditable = {
#             "cookie" => "val"
#         },
#         attr_accessor :method = "get",
#         attr_accessor :url = "http://owner-url.com/",
#         attr_reader :hash = 1135494168462266792,
#         attr_reader :opts = {},
#         attr_reader :orig = {
#             "cookie" => "val"
#         },
#         attr_reader :raw = {
#                    "name" => "cookie",
#                   "value" => "val",
#                 "version" => 0,
#                    "port" => nil,
#                 "discard" => nil,
#             "comment_url" => nil,
#                 "expires" => nil,
#                 "max_age" => nil,
#                 "comment" => nil,
#                  "secure" => nil,
#                    "path" => "/",
#                  "domain" => "owner-url.com",
#                "httponly" => true
#         }
#     >,
#     [1] #<Arachni::Element::Cookie:0x026745b0
#         attr_accessor :action = "http://owner-url.com/",
#         attr_accessor :auditable = {
#             "cookie2" => "val2"
#         },
#         attr_accessor :method = "get",
#         attr_accessor :url = "http://owner-url.com/",
#         attr_reader :hash = -765632517082248204,
#         attr_reader :opts = {},
#         attr_reader :orig = {
#             "cookie2" => "val2"
#         },
#         attr_reader :raw = {
#                    "name" => "cookie2",
#                   "value" => "val2",
#                 "version" => 0,
#                    "port" => nil,
#                 "discard" => nil,
#             "comment_url" => nil,
#                 "expires" => 1970-01-01 02:00:01 +0200,
#                 "max_age" => nil,
#                 "comment" => nil,
#                  "secure" => true,
#                    "path" => "/",
#                  "domain" => ".foo.com",
#                "httponly" => true
#         }
#     >
# ]

Parameters:

  • url (String)

    owner URL

  • document (String, Nokogiri::HTML::Document)

Returns:

See Also:



853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
# File 'lib/arachni/element/cookie.rb', line 853

def self.from_document( url, document )
    # optimizations in case there are no cookies in the doc,
    # avoid parsing unless absolutely necessary!
    if !document.is_a?( Nokogiri::HTML::Document )
        # get get the head in order to check if it has an http-equiv for set-cookie
        head = document.to_s.match( /<head(.*)<\/head>/imx )

        # if it does feed the head to the parser in order to extract the cookies
        return [] if !head || !head.to_s.downcase.substring?( 'set-cookie' )

        document = Nokogiri::HTML( head.to_s )
    end

    Arachni::Utilities.exception_jail {
        document.search( "//meta[@http-equiv]" ).map do |elem|
            next if elem['http-equiv'].downcase != 'set-cookie'
            parse_set_cookie( url, elem['content'] )
        end.flatten.compact
    } rescue []
end

.from_file(url, filepath) ⇒ Array<Cookie>

Returns an array of cookies from an Netscape HTTP cookiejar file.

Examples:

Parsing a Netscape HTTP cookiejar file


# Given a cookie-jar file with the following contents:
#
#   # comment, should be ignored
#   .domain.com	TRUE	/path/to/somewhere	TRUE	Tue, 02 Oct 2012 19:25:57 GMT	first_name	first_value
#
#   # ignored again
#   another-domain.com	FALSE	/	FALSE	second_name	second_value
#
#   # with expiry date as seconds since epoch
#   .blah-domain	TRUE	/	FALSE	1596981560	NAME	OP5jTLV6VhYHADJAbJ1ZR@L8~081210

p Cookie.from_file 'http://owner-url.com', 'cookies.jar'
#=> [first_name=first_value, second_name=second_value, NAME=OP5jTLV6VhYHADJAbJ1ZR@L8~081210]

# And here's the fancier dump:
# [
#     [0] #<Arachni::Element::Cookie:0x011636d0
#         attr_accessor :action = "http://owner-url.com/",
#         attr_accessor :auditable = {
#             "first_name" => "first_value"
#         },
#         attr_accessor :method = "get",
#         attr_accessor :url = "http://owner-url.com/",
#         attr_reader :hash = -473180912834263695,
#         attr_reader :opts = {},
#         attr_reader :orig = {
#             "first_name" => "first_value"
#         },
#         attr_reader :raw = {
#                  "domain" => ".domain.com",
#                    "path" => "/path/to/somewhere",
#                  "secure" => true,
#                 "expires" => 2012-10-02 22:25:57 +0300,
#                    "name" => "first_name",
#                   "value" => "first_value",
#                 "version" => 0,
#                    "port" => nil,
#                 "discard" => nil,
#             "comment_url" => nil,
#                 "max_age" => nil,
#                 "comment" => nil,
#                "httponly" => false
#         }
#     >,
#     [1] #<Arachni::Element::Cookie:0x011527b8
#         attr_accessor :action = "http://owner-url.com/",
#         attr_accessor :auditable = {
#             "second_name" => "second_value"
#         },
#         attr_accessor :method = "get",
#         attr_accessor :url = "http://owner-url.com/",
#         attr_reader :hash = -2673771862017142861,
#         attr_reader :opts = {},
#         attr_reader :orig = {
#             "second_name" => "second_value"
#         },
#         attr_reader :raw = {
#                  "domain" => "another-domain.com",
#                    "path" => "/",
#                  "secure" => false,
#                 "expires" => nil,
#                    "name" => "second_name",
#                   "value" => "second_value",
#                 "version" => 0,
#                    "port" => nil,
#                 "discard" => nil,
#             "comment_url" => nil,
#                 "max_age" => nil,
#                 "comment" => nil,
#                "httponly" => false
#         }
#     >,
#     [2] #<Arachni::Element::Cookie:0x011189f0
#         attr_accessor :action = "http://owner-url.com/",
#         attr_accessor :auditable = {
#             "NAME" => "OP5jTLV6VhYHADJAbJ1ZR@L8~081210"
#         },
#         attr_accessor :method = "get",
#         attr_accessor :url = "http://owner-url.com/",
#         attr_reader :hash = 4086929775905476282,
#         attr_reader :opts = {},
#         attr_reader :orig = {
#             "NAME" => "OP5jTLV6VhYHADJAbJ1ZR@L8~081210"
#         },
#         attr_reader :raw = {
#                  "domain" => ".blah-domain",
#                    "path" => "/",
#                  "secure" => false,
#                 "expires" => 2020-08-09 16:59:20 +0300,
#                    "name" => "NAME",
#                   "value" => "OP5jTLV6VhYHADJAbJ1ZR@L8~081210",
#                 "version" => 0,
#                    "port" => nil,
#                 "discard" => nil,
#             "comment_url" => nil,
#                 "max_age" => nil,
#                 "comment" => nil,
#                "httponly" => false
#         }
#     >
# ]

Parameters:

  • url (String)

    request URL

  • filepath (String)

    Netscape HTTP cookiejar file

Returns:



596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
# File 'lib/arachni/element/cookie.rb', line 596

def self.from_file( url, filepath )
    File.open( filepath, 'r' ).map do |line|
        # skip empty lines
        next if (line = line.strip).empty? || line[0] == '#'

        c = {}
        c['domain'], foo, c['path'], c['secure'], c['expires'], c['name'],
            c['value'] = *line.split( "\t" )

        # expiry date is optional so if we don't have one push everything back
        begin
            c['expires'] = expires_to_time( c['expires'] )
        rescue
            c['value'] = c['name'].dup
            c['name'] = c['expires'].dup
            c['expires'] = nil
        end
        c['secure'] = (c['secure'] == 'TRUE') ? true : false
        new( url, c )
    end.flatten.compact
end

.from_headers(url, headers) ⇒ Array<Cookie>

Returns an array of cookies from the Set-Cookie header field.

Examples:

p Cookie.from_headers 'http://owner-url.com', { 'Set-Cookie' => "coo%40ki+e2=blah+val2%40" }
#=> [coo@ki+e2=blah+val2@]

# Fancy dump:
# [
#     [0] #<Arachni::Element::Cookie:0x01e17250
#         attr_accessor :action = "http://owner-url.com/",
#         attr_accessor :auditable = {
#             "coo@ki e2" => "blah val2@"
#         },
#         attr_accessor :method = "get",
#         attr_accessor :url = "http://owner-url.com/",
#         attr_reader :hash = -1249755840178478661,
#         attr_reader :opts = {},
#         attr_reader :orig = {
#             "coo@ki e2" => "blah val2@"
#         },
#         attr_reader :raw = {
#                    "name" => "coo@ki e2",
#                   "value" => "blah val2@",
#                 "version" => 0,
#                    "port" => nil,
#                 "discard" => nil,
#             "comment_url" => nil,
#                 "expires" => nil,
#                 "max_age" => nil,
#                 "comment" => nil,
#                  "secure" => nil,
#                    "path" => "/",
#                  "domain" => "owner-url.com",
#                "httponly" => false
#         }
#     >
# ]

Parameters:

  • url (String)

    request URL

  • headers (Hash)

Returns:

See Also:

  • forms_set_cookie


920
921
922
923
924
925
926
927
928
# File 'lib/arachni/element/cookie.rb', line 920

def self.from_headers( url, headers )
    set_strings = []
    headers.each { |k, v| set_strings = [v].flatten if k.downcase == 'set-cookie' }

    return set_strings if set_strings.empty?
    exception_jail {
        set_strings.map { |c| parse_set_cookie( url, c ) }.flatten
    } rescue []
end

.from_response(response) ⇒ Array<Cookie>

Returns an array of cookies from an HTTP response.

Examples:

body = <<-HTML
    <html>
        <head>
            <meta http-equiv="Set-Cookie" content="cookie=val; httponly">
            <meta http-equiv="Set-Cookie" content="cookie2=val2; Expires=Thu, 01 Jan 1970 00:00:01 GMT; Path=/; Domain=.foo.com; HttpOnly; secure">
        </head>
    </html>
HTML

response = Typhoeus::Response.new(
    body:          body,
    effective_url: 'http://stuff.com',
    headers_hash:  {
       'Set-Cookie' => "coo%40ki+e2=blah+val2%40; Expires=Thu, 01 Jan 1970 00:00:01 GMT; Path=/; Domain=.foo.com; HttpOnly"
   }
)

p Cookie.from_response response
# [cookie=val, cookie2=val2, coo@ki+e2=blah+val2@]

# Fancy dump:
# [
#     [0] #<Arachni::Element::Cookie:0x028e30f8
#         attr_accessor :action = "http://stuff.com/",
#         attr_accessor :auditable = {
#             "cookie" => "val"
#         },
#         attr_accessor :method = "get",
#         attr_accessor :url = "http://stuff.com/",
#         attr_reader :hash = 2101892390575163651,
#         attr_reader :opts = {},
#         attr_reader :orig = {
#             "cookie" => "val"
#         },
#         attr_reader :raw = {
#                    "name" => "cookie",
#                   "value" => "val",
#                 "version" => 0,
#                    "port" => nil,
#                 "discard" => nil,
#             "comment_url" => nil,
#                 "expires" => nil,
#                 "max_age" => nil,
#                 "comment" => nil,
#                  "secure" => nil,
#                    "path" => "/",
#                  "domain" => "stuff.com",
#                "httponly" => true
#         }
#     >,
#     [1] #<Arachni::Element::Cookie:0x028ec0e0
#         attr_accessor :action = "http://stuff.com/",
#         attr_accessor :auditable = {
#             "cookie2" => "val2"
#         },
#         attr_accessor :method = "get",
#         attr_accessor :url = "http://stuff.com/",
#         attr_reader :hash = 1525536412599744532,
#         attr_reader :opts = {},
#         attr_reader :orig = {
#             "cookie2" => "val2"
#         },
#         attr_reader :raw = {
#                    "name" => "cookie2",
#                   "value" => "val2",
#                 "version" => 0,
#                    "port" => nil,
#                 "discard" => nil,
#             "comment_url" => nil,
#                 "expires" => 1970-01-01 02:00:01 +0200,
#                 "max_age" => nil,
#                 "comment" => nil,
#                  "secure" => true,
#                    "path" => "/",
#                  "domain" => ".foo.com",
#                "httponly" => true
#         }
#     >,
#     [2] #<Arachni::Element::Cookie:0x028ef3f8
#         attr_accessor :action = "http://stuff.com/",
#         attr_accessor :auditable = {
#             "coo@ki e2" => "blah val2@"
#         },
#         attr_accessor :method = "get",
#         attr_accessor :url = "http://stuff.com/",
#         attr_reader :hash = 3179884445716720825,
#         attr_reader :opts = {},
#         attr_reader :orig = {
#             "coo@ki e2" => "blah val2@"
#         },
#         attr_reader :raw = {
#                    "name" => "coo@ki e2",
#                   "value" => "blah val2@",
#                 "version" => 0,
#                    "port" => nil,
#                 "discard" => nil,
#             "comment_url" => nil,
#                 "expires" => 1970-01-01 02:00:01 +0200,
#                 "max_age" => nil,
#                 "comment" => nil,
#                  "secure" => nil,
#                    "path" => "/",
#                  "domain" => ".foo.com",
#                "httponly" => true
#         }
#     >
# ]

Parameters:

Returns:

See Also:



761
762
763
764
# File 'lib/arachni/element/cookie.rb', line 761

def self.from_response( response )
    ( from_document( response.effective_url, response.body ) |
     from_headers( response.effective_url, response.headers_hash ) )
end

Parses the Set-Cookie header value into cookie elements.

Examples:

p Cookie.from_set_cookie 'http://owner-url.com', "coo%40ki+e2=blah+val2%40"
#=> [coo@ki+e2=blah+val2@]

# Fancy dump:
# [
#     [0] #<Arachni::Element::Cookie:0x01e17250
#         attr_accessor :action = "http://owner-url.com/",
#         attr_accessor :auditable = {
#             "coo@ki e2" => "blah val2@"
#         },
#         attr_accessor :method = "get",
#         attr_accessor :url = "http://owner-url.com/",
#         attr_reader :hash = -1249755840178478661,
#         attr_reader :opts = {},
#         attr_reader :orig = {
#             "coo@ki e2" => "blah val2@"
#         },
#         attr_reader :raw = {
#                    "name" => "coo@ki e2",
#                   "value" => "blah val2@",
#                 "version" => 0,
#                    "port" => nil,
#                 "discard" => nil,
#             "comment_url" => nil,
#                 "expires" => nil,
#                 "max_age" => nil,
#                 "comment" => nil,
#                  "secure" => nil,
#                    "path" => "/",
#                  "domain" => "owner-url.com",
#                "httponly" => false
#         }
#     >
# ]

Parameters:

  • url (String)

    request URL

  • str (Hash)

    Set-Cookie string

Returns:



975
976
977
978
979
980
981
982
983
984
985
986
987
988
# File 'lib/arachni/element/cookie.rb', line 975

def self.from_set_cookie( url, str )
    WEBrick::Cookie.parse_set_cookies( str ).flatten.uniq.map do |cookie|
        cookie_hash = {}
        cookie.instance_variables.each do |var|
            cookie_hash[var.to_s.gsub( /@/, '' )] = cookie.instance_variable_get( var )
        end
        cookie_hash['expires'] = cookie.expires

        cookie_hash['name']  = decode( cookie.name )
        cookie_hash['value'] = decode( cookie.value )

        new( url.to_s, cookie_hash )
    end.flatten.compact
end


989
990
991
# File 'lib/arachni/element/cookie.rb', line 989

def self.parse_set_cookie( *args )
    from_set_cookie( *args )
end

Instance Method Details

#audit(*args) ⇒ Object

Overrides Arachni::Element::Capabilities::Auditable#audit to enforce cookie exclusion settings from Options#exclude_cookies.



91
92
93
94
95
96
97
# File 'lib/arachni/element/cookie.rb', line 91

def audit( *args )
    if Arachni::Options.exclude_cookies.include?( name )
        auditor.print_info "Skipping audit of '#{name}' cookie."
        return
    end
    super( *args )
end

#auditable=(inputs) ⇒ Object

Sets auditable inputs as a key=>value pair.

Examples:

p c = Cookie.from_set_cookie( 'http://owner-url.com', 'session=stuffstuffstuff' ).first
#=> ["session=stuffstuffstuff"]

p c.auditable
#=> {"session"=>"stuffstuffstuff"}

p c.auditable = { 'new-name' => 'new-value' }
#=> {"new-name"=>"new-value"}

p c
#=> new-name=new-value

Parameters:

  • inputs (Hash)

    name => value pair



249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'lib/arachni/element/cookie.rb', line 249

def auditable=( inputs )
    k = inputs.keys.first.to_s
    v = inputs.values.first.to_s

    raw = @raw.dup
    raw['name']  = k
    raw['value'] = v

    @raw = raw.freeze

    if k.to_s.empty?
        super( {} )
    else
        super( { k => v } )
    end
end

#decode(str) ⇒ Object

See Also:



1028
1029
1030
# File 'lib/arachni/element/cookie.rb', line 1028

def decode( str )
    self.class.decode( str )
end

#dupObject



224
225
226
227
228
# File 'lib/arachni/element/cookie.rb', line 224

def dup
    d = super
    d.action = self.action
    d
end

#encode(str) ⇒ Object

See Also:



1009
1010
1011
# File 'lib/arachni/element/cookie.rb', line 1009

def encode( str )
    self.class.encode( str )
end

#expired?(time = Time.now) ⇒ Boolean

Indicates whether or not the cookie has expired.

Examples:

Without a time argument.


# session cookie
p Cookie.from_set_cookie( 'http://owner-url.com', 'session=stuffstuffstuff' ).first.expired?
#=> false

# cookie with the expiration date in the future
p Cookie.from_set_cookie( 'http://owner-url.com', 'session=stuffstuffstuff; Expires=Thu, 01 Jan 2020 00:00:01 GMT' ).first.expired?
#=> true

# expired cookie
p Cookie.from_set_cookie( 'http://owner-url.com', 'session=stuffstuffstuff; Expires=Thu, 01 Jan 1970 00:00:01 GMT' ).first.expired?
#=> true

With a time argument.


future_time = Cookie.expires_to_time( 'Thu, 01 Jan 2021 00:00:01 GMT' )

# session cookie
p Cookie.from_set_cookie( 'http://owner-url.com', 'session=stuffstuffstuff' ).first.expired?( future_time )
#=> false

# cookie with the expiration date in the future
p Cookie.from_set_cookie( 'http://owner-url.com', 'session=stuffstuffstuff; Expires=Thu, 01 Jan 2020 00:00:01 GMT' ).first.expired?( future_time )
#=> true

# expired cookie
p Cookie.from_set_cookie( 'http://owner-url.com', 'session=stuffstuffstuff; Expires=Thu, 01 Jan 1970 00:00:01 GMT' ).first.expired?( future_time )
#=> true

Parameters:

  • time (Time) (defaults to: Time.now)

    to compare against

Returns:

  • (Boolean)


203
204
205
# File 'lib/arachni/element/cookie.rb', line 203

def expired?( time = Time.now )
    expires_at != nil && time > expires_at
end

#expires_atTime, NilClass

Returns expiration Time of the cookie or nil if it doesn’t have one (i.e. is a session cookie).

Examples:

p Cookie.from_set_cookie( 'http://owner-url.com', 'session=stuffstuffstuff' ).first.expires_at
#=> nil

p Cookie.from_set_cookie( 'http://owner-url.com', 'session=stuffstuffstuff; Expires=Thu, 01 Jan 1970 00:00:01 GMT' ).first.expires_at
#=> 1970-01-01 02:00:01 +0200

Returns:

  • (Time, NilClass)

    expiration Time of the cookie or nil if it doesn’t have one (i.e. is a session cookie)



163
164
165
# File 'lib/arachni/element/cookie.rb', line 163

def expires_at
    expires
end

#http_only?Bool

Indicates whether the cookie is safe from modification from client-side code.

Examples:

p Cookie.from_set_cookie( 'http://owner-url.com', 'session=stuffstuffstuff; httpOnly' ).first.http_only?
#=> true

p Cookie.from_set_cookie( 'http://owner-url.com', 'session=stuffstuffstuff' ).first.http_only?
#=> false

Returns:

  • (Bool)


127
128
129
# File 'lib/arachni/element/cookie.rb', line 127

def http_only?
    @raw['httponly'] == true
end

#mutations(injection_str, opts = {}) ⇒ Object

Overrides Arachni::Element::Capabilities::Mutable#mutations to handle cookie-specific limitations and the Options#audit_cookies_extensively option.

c = Cookie.from_set_cookie( 'http://owner-url.com', 'session=stuffstuffstuff' ).first

Examples:

Default

p c.mutations 'seed'
#=> [session=seed, session=stuffstuffstuffseed, session=seed%00, session=stuffstuffstuffseed%00]

With parameter flip

p c.mutations 'seed', param_flip: true
#=> [session=seed, session=stuffstuffstuffseed, session=seed%00, session=stuffstuffstuffseed%00, seed=eb987f5d6a6948193f3677ee70eaedf0e1454f1eb715322ec627f0a32848f8bd]

Extensive audit


Arachni::Options.audit_cookies_extensively = true

# this option presupposes that an auditor (with page) is available
Auditor = Class.new do
    include Arachni::Module::Auditor

    def page
        Page.new( links: [Link.new( 'http://owner-url.com', input1: 'value1' )] )
    end

    def self.info
        { name: 'My custom auditor' }
    end
end

c.auditor = Auditor.new

p mutations = c.mutations( 'seed' )
#=> [session=seed, session=stuffstuffstuffseed, session=seed%00, session=stuffstuffstuffseed%00, http://owner-url.com/?input1=value1, http://owner-url.com/?input1=value1, http://owner-url.com/?input1=value1, http://owner-url.com/?input1=value1]

# if we take a closer look at the Link mutations we see that this link will be submitted with various cookie mutations
ap mutations.select { |m| m.is_a? Link }
#=> [
#     [0] #<Arachni::Element::Link:0x02de90e8
#         @audit_id_url = "http://owner-url.com/",
#         attr_accessor :action = "http://owner-url.com/",
#         attr_accessor :altered = "mutation for the 'session' cookie",
#         attr_accessor :auditable = {
#             "input1" => "value1"
#         },
#         attr_accessor :auditor = #<Auditor:0x000000029e7648>,
#         attr_accessor :method = "get",
#         attr_accessor :url = "http://owner-url.com/",
#         attr_reader :hash = -4537574543719230301,
#         attr_reader :opts = {
#             :cookies => {
#                 "session" => "seed"
#             }
#         },
#         attr_reader :orig = {
#             "input1" => "value1"
#         },
#         attr_reader :raw = {
#             :input1 => "value1"
#         }
#     >,
#     [1] #<Arachni::Element::Link:0x02df3f98
#         @audit_id_url = "http://owner-url.com/",
#         attr_accessor :action = "http://owner-url.com/",
#         attr_accessor :altered = "mutation for the 'session' cookie",
#         attr_accessor :auditable = {
#             "input1" => "value1"
#         },
#         attr_accessor :auditor = #<Auditor:0x000000029e7648>,
#         attr_accessor :method = "get",
#         attr_accessor :url = "http://owner-url.com/",
#         attr_reader :hash = -4537574543719230301,
#         attr_reader :opts = {
#             :cookies => {
#                 "session" => "stuffstuffstuffseed"
#             }
#         },
#         attr_reader :orig = {
#             "input1" => "value1"
#         },
#         attr_reader :raw = {
#             :input1 => "value1"
#         }
#     >,
#     [2] #<Arachni::Element::Link:0x02adcf80
#         @audit_id_url = "http://owner-url.com/",
#         attr_accessor :action = "http://owner-url.com/",
#         attr_accessor :altered = "mutation for the 'session' cookie",
#         attr_accessor :auditable = {
#             "input1" => "value1"
#         },
#         attr_accessor :auditor = #<Auditor:0x000000029e7648>,
#         attr_accessor :method = "get",
#         attr_accessor :url = "http://owner-url.com/",
#         attr_reader :hash = -4537574543719230301,
#         attr_reader :opts = {
#             :cookies => {
#                 "session" => "seed\x00"
#             }
#         },
#         attr_reader :orig = {
#             "input1" => "value1"
#         },
#         attr_reader :raw = {
#             :input1 => "value1"
#         }
#     >,
#     [3] #<Arachni::Element::Link:0x02b0c0a0
#         @audit_id_url = "http://owner-url.com/",
#         attr_accessor :action = "http://owner-url.com/",
#         attr_accessor :altered = "mutation for the 'session' cookie",
#         attr_accessor :auditable = {
#             "input1" => "value1"
#         },
#         attr_accessor :auditor = #<Auditor:0x000000029e7648>,
#         attr_accessor :method = "get",
#         attr_accessor :url = "http://owner-url.com/",
#         attr_reader :hash = -4537574543719230301,
#         attr_reader :opts = {
#             :cookies => {
#                 "session" => "stuffstuffstuffseed\x00"
#             }
#         },
#         attr_reader :orig = {
#             "input1" => "value1"
#         },
#         attr_reader :raw = {
#             :input1 => "value1"
#         }
#     >
# ]

See Also:



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
431
432
433
434
435
436
# File 'lib/arachni/element/cookie.rb', line 402

def mutations( injection_str, opts = {} )
    flip = opts.delete( :param_flip )
    muts = super( injection_str, opts )

    if flip
        elem = self.dup

        # when under HPG mode element auditing is strictly regulated
        # and when we flip params we essentially create a new element
        # which won't be on the whitelist
        elem.override_instance_scope

        elem.altered = 'Parameter flip'
        elem.auditable = { injection_str => seed }
        muts << elem
    end

    if !orphan? && Arachni::Options.audit_cookies_extensively?
        # submit all links and forms of the page along with our cookie mutations
        muts << muts.map do |m|
            (auditor.page.links | auditor.page.forms).map do |e|
                next if e.auditable.empty?
                c = e.dup
                c.altered = "mutation for the '#{m.altered}' cookie"
                c.auditor = auditor
                c.opts[:cookies] = m.auditable.dup
                c.auditable = Arachni::Module::KeyFiller.fill( c.auditable.dup )
                c
            end
        end.flatten.compact
        muts.flatten!
    end

    muts
end

#respond_to?(sym) ⇒ Bool

Used by #method_missing to determine if it should process the call.

Returns:

  • (Bool)


464
465
466
# File 'lib/arachni/element/cookie.rb', line 464

def respond_to?( sym )
    @raw.include?( sym.to_s ) || super( sym )
end

#secure?Bool

Indicates whether the cookie must be only sent over an encrypted channel.

Examples:

p Cookie.from_set_cookie( 'http://owner-url.com', 'session=stuffstuffstuff; secure' ).first.secure?
#=> true

p Cookie.from_set_cookie( 'http://owner-url.com', 'session=stuffstuffstuff' ).first.secure?
#=> false

Returns:

  • (Bool)


111
112
113
# File 'lib/arachni/element/cookie.rb', line 111

def secure?
    @raw['secure'] == true
end

#session?Bool

Indicates whether the cookie is to be discarded at the end of the session.

Doesn’t play a role during the scan but it can provide useful info to modules and such.

Examples:

# doesn't have an expiration date, i.e. it should be discarded at the end of the session
p Cookie.from_set_cookie( 'http://owner-url.com', 'session=stuffstuffstuff' ).first.session?
#=> true

# does have an expiration date, i.e. not a session cookie
p Cookie.from_set_cookie( 'http://owner-url.com', 'session=stuffstuffstuff; Expires=Thu, 01 Jan 1970 00:00:01 GMT' ).first.session?
#=> false

Returns:

  • (Bool)


147
148
149
# File 'lib/arachni/element/cookie.rb', line 147

def session?
    @raw['expires'].nil?
end

#simpleHash

Returns simple representation of the cookie as a hash with the cookie name as key and the cookie value as value.

Examples:

p Cookie.from_set_cookie( 'http://owner-url.com', 'session=stuffstuffstuff' ).first.simple
#=> {"session"=>"stuffstuffstuff"}

Returns:

  • (Hash)

    simple representation of the cookie as a hash with the cookie name as key and the cookie value as value.



215
216
217
# File 'lib/arachni/element/cookie.rb', line 215

def simple
    self.auditable.dup
end

#to_sString

Returns to be used in a ‘Cookie’ request header. (name=value).

Examples:

p Cookie.from_set_cookie( 'http://owner-url.com/', 'session=stuffstuffstuff' ).first.to_s
#=> "session=stuffstuffstuff"

p Cookie.new( 'http://owner-url.com/', '% ; freaky name' => 'freaky value;%' ).to_s
#=> "%25+%3B+freaky+name=freaky+value%3B%25"

Returns:

  • (String)

    to be used in a ‘Cookie’ request header. (name=value)



479
480
481
# File 'lib/arachni/element/cookie.rb', line 479

def to_s
    "#{encode( name )}=#{encode( value )}"
end

#typeString

Returns name of the current element, ‘cookie’ in this case.

Returns:

  • (String)

    name of the current element, ‘cookie’ in this case.



220
221
222
# File 'lib/arachni/element/cookie.rb', line 220

def type
    Arachni::Element::COOKIE
end