Class: Arachni::Plugins::LoginScript

Inherits:
Arachni::Plugin::Base show all
Defined in:
components/plugins/login_script.rb

Overview

Automated login plugin using a custom login script.

Author:

Constant Summary collapse

STATUSES =
{
    success:         'Login was successful.',
    failure:         'The script was executed successfully, but the login check failed.',
    error:           'An error was encountered while executing the login script.',
    missing_browser: 'A browser is required for this operation but is not available.',
    missing_check:   'No session check was provided, either via interface options or the script.'
}

Constants included from Arachni

BANNER, Cookie, Form, Header, JSON, Link, LinkTemplate, NestedCookie, Severity, UIForm, UIInput, VERSION, WEBSITE, WIKI, XML

Instance Attribute Summary

Attributes inherited from Arachni::Plugin::Base

#framework, #options

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Arachni::Plugin::Base

#browser_cluster, #clean_up, distributable, distributable?, #framework_abort, #framework_pause, #framework_resume, gems, #http, #info, #initialize, is_distributable, merge, #register_results, #restore, #run, #session, #suspend, #wait_while_framework_running, #with_browser

Methods inherited from Component::Base

author, description, fullname, #shortname, shortname, shortname=, version

Methods included from Component::Output

#depersonalize_output, #depersonalize_output?, #intercept_print_message

Methods included from UI::Output

#caller_location, #debug?, #debug_level, #debug_level_1?, #debug_level_2?, #debug_level_3?, #debug_level_4?, #debug_off, #debug_on, #disable_only_positives, #error_buffer, #error_log_fd, #error_logfile, #has_error_log?, #included, #log_error, #mute, #muted?, #only_positives, #only_positives?, #print_bad, #print_debug, #print_debug_backtrace, #print_debug_exception, #print_debug_level_1, #print_debug_level_2, #print_debug_level_3, #print_debug_level_4, #print_error, #print_error_backtrace, #print_exception, #print_info, #print_line, #print_ok, #print_status, #print_verbose, #reroute_to_file, #reroute_to_file?, reset_output_options, #set_error_logfile, #unmute, #verbose?, #verbose_off, #verbose_on

Methods included from Component::Utilities

#read_file

Methods included from Utilities

#available_port, available_port_mutex, #bytes_to_kilobytes, #bytes_to_megabytes, #caller_name, #caller_path, #cookie_decode, #cookie_encode, #cookies_from_file, #cookies_from_parser, #cookies_from_response, #exception_jail, #exclude_path?, #follow_protocol?, #form_decode, #form_encode, #forms_from_parser, #forms_from_response, #full_and_absolute_url?, #generate_token, #get_path, #hms_to_seconds, #html_decode, #html_encode, #include_path?, #links_from_parser, #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 Arachni

URI, collect_young_objects, #get_long_win32_filename, jruby?, null_device, profile?, windows?

Constructor Details

This class inherits a constructor from Arachni::Plugin::Base

Class Method Details

.infoObject



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'components/plugins/login_script.rb', line 107

def self.info
    {
        name:        'Login script',
        description: %q{
Loads and sets an external script as the system's login sequence, to be executed
prior to the scan and whenever a log-out is detected.

The script needn't necessarily perform an actual login operation. If another
process is used to manage sessions, the script can be used to communicate with
that process and, for example, load and set cookies from a shared cookie-jar.

# Ruby

## With browser (slow)

If a [browser](http://watir.github.io/) is available, it will be exposed to
the script via the `browser` variable. Otherwise, that variable will have a
value of `nil`.

browser.goto 'http://testfire.net/bank/login.aspx'

form = browser.form( id: 'login' )
form.text_field( name: 'uid' ).set 'jsmith'
form.text_field( name: 'passw' ).set 'Demo1234'

form.submit

# You can also configure the session check from the script, dynamically,
# if you don't want to set static options via the user interface.
framework.options.session.check_url     = browser.url
framework.options.session.check_pattern = /Sign Off|MY ACCOUNT/

## Without browser (fast)

If a real browser environment is not required for the login operation, then
using the system-wide HTTP interface is preferable, as it will be much faster
and consume much less resources.

response = http.post( 'http://testfire.net/bank/login.aspx',
    parameters:     {
        'uid'   => 'jsmith',
        'passw' => 'Demo1234'
    },
    mode:           :sync,
    update_cookies: true
)

framework.options.session.check_url     = to_absolute( response.headers.location, response.url )
framework.options.session.check_pattern = /Sign Off|MY ACCOUNT/

## From cookie-jar

If an external process is used to manage sessions, you can keep Arachni in sync
by loading cookies from a shared Netscape-style cookie-jar file.

http.cookie_jar.load 'cookies.txt'

## Advanced session check configuration

In addition to just settings the `check_url` and `check_pattern` options,
you can also set arbitrary HTTP request options for the login check, to cover
cases where extra tokens or a method other than `GET` must be used.

session.check_options = {
    # :get, :post, :put, :delete
    method:     :post,

    # URL query parameters.
    parameters: {
        'param1' => 'value'
    },

    # Request body parameters -- can also be a String instead of Hash.
    body:       {
        'body_param1' => 'value'
    },

    cookies:    {
        'custom_cookie' => 'value'
    },

    headers:    {
        'X-Custom-Header' => 'value'
    }
}

# Javascript

When the given script has a `.js` file extension, it will be loaded and executed
in the browser, within the page of the target URL.

document.getElementById( 'uid' ).value   = 'jsmith';
document.getElementById( 'passw' ).value = 'Demo1234';

document.getElementById( 'login' ).submit();

},
        author:      'Tasos "Zapotek" Laskos <[email protected]>',
        version:     '0.2.3',
        options:     [
            Options::Path.new( :script,
                required:    true,
                description: 'Script that includes the login sequence.'
            ),
        ],
        priority:    0 # run before any other plugin
    }
end

Instance Method Details

#javascript?Boolean

Returns:

  • (Boolean)


85
86
87
# File 'components/plugins/login_script.rb', line 85

def javascript?
    @options[:script].split( '.' ).last == 'js'
end

#prepareObject



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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 'components/plugins/login_script.rb', line 22

def prepare
    script    = IO.read( @options[:script] )
    @script   = proc do |browser|
        if javascript?
            browser.goto @framework.options.url
            browser.execute_script script
        else
            eval script
        end
    end

    if javascript? && !session.has_browser?
        set_status :missing_browser, :error
        return
    end

    session. do |browser|
        print_info 'Running the script.'

        if browser
            watir = browser.watir
            watir.window.resize_to(
                Arachni::Options.browser_cluster.screen_width,
                Arachni::Options.browser_cluster.screen_height
            )
            @script.call watir
            browser.wait_till_ready
        else
            @script.call
        end

        print_info 'Execution completed.'
    end

    begin
        session.( true )
    rescue Exception => e
        print_exception e
        set_status :error
        return
    end

    if !session.logged_in?
        set_status :failure, :error
        return
    end

    cookies = http.cookies.inject({}){ |h, c| h.merge!( c.simple ) }

    set_status :success, :ok, { 'cookies' => cookies }

    print_info 'Cookies set to:'
    cookies.each do |name, val|
        print_info "    * #{name.inspect} = #{val.inspect}"
    end

rescue Arachni::Session::Error::NoLoginCheck
    set_status :missing_check, :error
rescue => e
    set_status :error
    print_exception e
end

#set_status(status, type = nil, extra = {}) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'components/plugins/login_script.rb', line 89

def set_status( status, type = nil, extra = {} )
    type ||= status

    register_results(
        {
            'status'  => status.to_s,
            'message' => STATUSES[status]
        }.merge( extra )
    )

    send "print_#{type}", STATUSES[status]

    if type == :error
        print_info 'Aborting the scan.'
        framework_abort
    end
end