Class: Arachni::Framework
- Includes:
- Mixins::Observable, UI::Output, Utilities
- Defined in:
- lib/arachni/framework.rb
Overview
The Framework class ties together all the components.
It should be wrapped by a UI class.
It’s the brains of the operation, it bosses the rest of the classes around.
It runs the audit, loads modules and reports and runs them according to user options.
Direct Known Subclasses
Constant Summary collapse
- REVISION =
the version of this class
'0.2.7'
Instance Attribute Summary collapse
-
#http ⇒ Arachni::HTTP
readonly
HTTP instance.
-
#modules ⇒ Arachni::Module::Manager
readonly
Module manager.
-
#opts ⇒ Options
readonly
Instance options.
-
#page_queue_total_size ⇒ Integer
readonly
Total number of pages added to their audit queue.
-
#plugins ⇒ Arachni::Plugin::Manager
readonly
Plugin manager.
-
#reports ⇒ Arachni::Report::Manager
readonly
Report manager.
-
#session ⇒ Session
readonly
Webapp session helper.
-
#sitemap ⇒ Array
readonly
URLs of all discovered pages.
-
#spider ⇒ Spider
readonly
Webapp spider.
-
#url_queue_total_size ⇒ Integer
readonly
Total number of urls added to their audit queue.
Class Method Summary collapse
-
.reset ⇒ Object
Resets everything and allows the framework to be re-used.
Instance Method Summary collapse
-
#audit_store ⇒ AuditStore
(also: #auditstore)
Returns the results of the audit as an AuditStore instance.
-
#clean_up(skip_audit_queue = false) ⇒ True
(also: #clean_up!)
Cleans up the framework; should be called after running the audit or after canceling a running scan.
-
#initialize(opts = Arachni::Options.instance) ⇒ Framework
constructor
Initializes system components.
-
#lsmod ⇒ Array<Hash>
Returns an array of hashes with information about all available modules.
-
#lsplug ⇒ Array<Hash>
Returns an array of hashes with information about all available reports.
-
#lsrep ⇒ Array<Hash>
Returns an array of hashes with information about all available reports.
- #on_run_mods(&block) ⇒ Object
-
#pause ⇒ TrueClass
(also: #pause!)
Pauses the framework on a best effort basis, might take a while to take effect.
-
#paused? ⇒ Bool
True if the framework is paused or in the process of.
-
#push_to_page_queue(page) ⇒ Object
Pushes a page to the page audit queue and updates #page_queue_total_size.
-
#push_to_url_queue(url) ⇒ Object
Pushes a URL to the URL audit queue and updates #url_queue_total_size.
-
#reset ⇒ Object
Resets everything and allows the framework to be re-used.
- #reset_spider ⇒ Object
-
#resume ⇒ TrueClass
(also: #resume!)
Resumes the scan/audit.
-
#revision ⇒ String
Returns the revision of the Framework (this) class.
-
#run(&block) ⇒ Object
Runs the system.
-
#running? ⇒ Bool
True if the framework is running.
-
#stats(refresh_time = false, override_refresh = false) ⇒ Hash
Returns the following framework stats:.
-
#status ⇒ String
Returns the status of the instance as a string.
-
#version ⇒ String
Returns the version of the framework.
Methods included from Mixins::Observable
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 UI::Output
#debug?, #debug_off, #debug_on, #disable_only_positives, #flush_buffer, #mute, #muted?, old_reset_output_options, #only_positives, #only_positives?, #print_bad, #print_debug, #print_debug_backtrace, #print_debug_pp, #print_error, #print_error_backtrace, #print_info, #print_line, #print_ok, #print_status, #print_verbose, #reroute_to_file, #reroute_to_file?, reset_output_options, #set_buffer_cap, #uncap_buffer, #unmute, #verbose, #verbose?
Constructor Details
#initialize(opts = Arachni::Options.instance) ⇒ Framework
Initializes system components.
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 |
# File 'lib/arachni/framework.rb', line 135 def initialize( opts = Arachni::Options.instance ) Encoding.default_external = 'BINARY' Encoding.default_internal = 'BINARY' @opts = opts @modules = Module::Manager.new( self ) @reports = Report::Manager.new( @opts ) @plugins = Plugin::Manager.new( self ) @session = Session.new( @opts ) reset_spider @http = HTTP.instance # will store full-fledged pages generated by the Trainer since these # may not be be accessible simply by their URL # @page_queue = ::Arachni::Database::Queue.new @page_queue = Queue.new @page_queue_total_size = 0 # will hold paths found by the spider in order to be converted to pages # and ultimately audited by the modules @url_queue = Queue.new @url_queue_total_size = 0 # deep clone the redundancy rules to preserve their counter # for the reports @orig_redundant = @opts.redundant.deep_clone @running = false @status = :ready @paused = [] @auditmap = [] @sitemap = [] @current_url = '' end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method in the class Arachni::Mixins::Observable
Instance Attribute Details
#http ⇒ Arachni::HTTP (readonly)
107 108 109 |
# File 'lib/arachni/framework.rb', line 107 def http @http end |
#modules ⇒ Arachni::Module::Manager (readonly)
91 92 93 |
# File 'lib/arachni/framework.rb', line 91 def modules @modules end |
#opts ⇒ Options (readonly)
Instance options
81 82 83 |
# File 'lib/arachni/framework.rb', line 81 def opts @opts end |
#page_queue_total_size ⇒ Integer (readonly)
Total number of pages added to their audit queue
121 122 123 |
# File 'lib/arachni/framework.rb', line 121 def page_queue_total_size @page_queue_total_size end |
#plugins ⇒ Arachni::Plugin::Manager (readonly)
96 97 98 |
# File 'lib/arachni/framework.rb', line 96 def plugins @plugins end |
#reports ⇒ Arachni::Report::Manager (readonly)
86 87 88 |
# File 'lib/arachni/framework.rb', line 86 def reports @reports end |
#session ⇒ Session (readonly)
99 100 101 |
# File 'lib/arachni/framework.rb', line 99 def session @session end |
#sitemap ⇒ Array (readonly)
URLs of all discovered pages
114 115 116 |
# File 'lib/arachni/framework.rb', line 114 def sitemap @sitemap end |
#spider ⇒ Spider (readonly)
102 103 104 |
# File 'lib/arachni/framework.rb', line 102 def spider @spider end |
#url_queue_total_size ⇒ Integer (readonly)
Total number of urls added to their audit queue
128 129 130 |
# File 'lib/arachni/framework.rb', line 128 def url_queue_total_size @url_queue_total_size end |
Class Method Details
.reset ⇒ Object
Resets everything and allows the framework to be re-used.
You should first update Options.
579 580 581 582 583 584 585 586 587 |
# File 'lib/arachni/framework.rb', line 579 def self.reset Module::Auditor.reset Module::ElementDB.reset Element::Capabilities::Auditable.reset Module::Manager.reset Plugin::Manager.reset Report::Manager.reset HTTP.reset end |
Instance Method Details
#audit_store ⇒ AuditStore Also known as: auditstore
Returns the results of the audit as an AuditStore instance
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 |
# File 'lib/arachni/framework.rb', line 372 def audit_store opts = @opts.to_hash.deep_clone # restore the original redundancy rules and their counters opts['redundant'] = @orig_redundant opts['mods'] = @modules.keys AuditStore.new( version: version, revision: revision, options: opts, sitemap: auditstore_sitemap || [], issues: @modules.results.deep_clone, plugins: @plugins.results ) end |
#clean_up(skip_audit_queue = false) ⇒ True Also known as: clean_up!
Cleans up the framework; should be called after running the audit or after canceling a running scan.
It stops the clock, waits for the plugins to finish up, registers their results and also refreshes the auditstore.
It also runs #audit_queue in case any new pages have been added by the plugins.
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 |
# File 'lib/arachni/framework.rb', line 529 def clean_up( skip_audit_queue = false ) @status = :cleanup @opts.finish_datetime = Time.now @opts.start_datetime ||= Time.now @opts.delta_time = @opts.finish_datetime - @opts.start_datetime # make sure this is disabled or it'll break report output disable_only_positives @running = false # wait for the plugins to finish @plugins.block # a plug-in may have updated the page queue, rock it! audit_queue if !skip_audit_queue true end |
#lsmod ⇒ Array<Hash>
Returns an array of hashes with information about all available modules
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 |
# File 'lib/arachni/framework.rb', line 396 def lsmod loaded = @modules.loaded @modules.clear @modules.available.map do |name| path = @modules.name_to_path( name ) next if !lsmod_match?( path ) @modules[name].info.merge( mod_name: name, author: [@modules[name].info[:author]].flatten.map { |a| a.strip }, path: path.strip ) end.compact ensure @modules.clear @modules.load( loaded ) end |
#lsplug ⇒ Array<Hash>
Returns an array of hashes with information about all available reports
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 |
# File 'lib/arachni/framework.rb', line 444 def lsplug loaded = @plugins.loaded @plugins.clear @plugins.available.map do |plugin| path = @plugins.name_to_path( plugin ) next if !lsplug_match?( path ) @plugins[plugin].info.merge( plug_name: plugin, path: path, author: [@plugins[plugin].info[:author]].flatten.map { |a| a.strip } ) end.compact ensure @plugins.clear @plugins.load( loaded ) end |
#lsrep ⇒ Array<Hash>
Returns an array of hashes with information about all available reports
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 |
# File 'lib/arachni/framework.rb', line 420 def lsrep loaded = @reports.loaded @reports.clear @reports.available.map do |report| path = @reports.name_to_path( report ) next if !lsrep_match?( path ) @reports[report].info.merge( rep_name: report, path: path, author: [@reports[report].info[:author]].flatten.map { |a| a.strip } ) end.compact ensure @reports.clear @reports.load( loaded ) end |
#on_run_mods(&block) ⇒ Object
551 552 553 |
# File 'lib/arachni/framework.rb', line 551 def on_run_mods( &block ) add_on_run_mods( &block ) end |
#pause ⇒ TrueClass Also known as: pause!
480 481 482 483 484 |
# File 'lib/arachni/framework.rb', line 480 def pause spider.pause @paused << caller true end |
#paused? ⇒ Bool
472 473 474 |
# File 'lib/arachni/framework.rb', line 472 def paused? !@paused.empty? end |
#push_to_page_queue(page) ⇒ Object
Pushes a page to the page audit queue and updates #page_queue_total_size
346 347 348 349 350 351 |
# File 'lib/arachni/framework.rb', line 346 def push_to_page_queue( page ) @page_queue << page @page_queue_total_size += 1 @sitemap |= [page.url] end |
#push_to_url_queue(url) ⇒ Object
Pushes a URL to the URL audit queue and updates #url_queue_total_size
356 357 358 359 360 361 362 363 |
# File 'lib/arachni/framework.rb', line 356 def push_to_url_queue( url ) abs = to_absolute( url ) @url_queue.push( abs ? abs : url ) @url_queue_total_size += 1 @sitemap |= [url] end |
#reset ⇒ Object
Resets everything and allows the framework to be re-used.
You should first update Options.
Prefer this if you already have an instance.
566 567 568 569 570 571 572 |
# File 'lib/arachni/framework.rb', line 566 def reset reset_spider @modules.clear @reports.clear @plugins.clear self.class.reset end |
#reset_spider ⇒ Object
555 556 557 |
# File 'lib/arachni/framework.rb', line 555 def reset_spider @spider = Spider.new( @opts ) end |
#resume ⇒ TrueClass Also known as: resume!
490 491 492 493 494 |
# File 'lib/arachni/framework.rb', line 490 def resume @paused.delete( caller ) spider.resume true end |
#revision ⇒ String
Returns the revision of the Arachni::Framework (this) class
511 512 513 |
# File 'lib/arachni/framework.rb', line 511 def revision REVISION end |
#run(&block) ⇒ Object
Runs the system
It parses the instance options, #prepare, runs the #audit and #clean_up!.
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/arachni/framework.rb', line 183 def run( &block ) prepare # catch exceptions so that if something breaks down or the user opted to # exit the reports will still run with whatever results Arachni managed to gather exception_jail( false ){ audit } clean_up exception_jail( false ){ block.call } if block_given? @status = :done # run reports @reports.run( audit_store ) if !@reports.empty? true end |
#running? ⇒ Bool
465 466 467 |
# File 'lib/arachni/framework.rb', line 465 def running? @running end |
#stats(refresh_time = false, override_refresh = false) ⇒ Hash
Returns the following framework stats:
-
:requests – HTTP request count
-
:responses – HTTP response count
-
:time_out_count – Amount of timed-out requests
-
:time – Amount of running time
-
:avg – Average requests per second
-
:sitemap_size – Number of discovered pages
-
:auditmap_size – Number of audited pages
-
:progress – Progress percentage
-
:curr_res_time – Average response time for the current burst of requests
-
:curr_res_cnt – Amount of responses for the current burst
-
:curr_avg – Average requests per second for the current burst
-
:average_res_time – Average response time
-
:max_concurrency – Current maximum concurrency of HTTP requests
-
:current_page – URL of the currently audited page
-
:eta – Estimated time of arrival i.e. estimated remaining time
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 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 333 334 335 336 337 338 339 340 341 |
# File 'lib/arachni/framework.rb', line 246 def stats( refresh_time = false, override_refresh = false ) req_cnt = http.request_count res_cnt = http.response_count @opts.start_datetime = Time.now if !@opts.start_datetime sitemap_sz = @sitemap.size auditmap_sz = @auditmap.size if( !refresh_time || auditmap_sz == sitemap_sz ) && !override_refresh @opts.delta_time ||= Time.now - @opts.start_datetime else @opts.delta_time = Time.now - @opts.start_datetime end avg = 0 avg = (res_cnt / @opts.delta_time).to_i if res_cnt > 0 # we need to remove URLs that lead to redirects from the sitemap # when calculating the progress %. # # this is because even though these URLs are valid webapp paths # they are not actual pages and thus can't be audited; # so the sitemap and auditmap will never match and the progress will # never get to 100% which may confuse users. # redir_sz = spider.redirects.size # # There are 2 audit phases: # * regular analysis attacks # * timing attacks # # When calculating the progress % we have to take both into account, # however each is calculated using different criteria. # # Progress of regular attacks is calculated as: # amount of audited pages / amount of all discovered pages # # However, the progress of the timing attacks is calculated as: # amount of called timeout blocks / amount of total blocks # # The timing attack modules are run with the regular ones however # their procedures are piled up into an array of Procs # which are called after the regular attacks. # # So when we reach the point of needing to include their progress in # the overall progress percentage we'll be working with accurate # data regarding the total blocks, etc. # # # If we have timing attacks then each phase must account for half # of the progress. # # This is not very granular but it's good enough for now... # multi = Module::Auditor.timeout_loaded_modules.size > 0 ? 50 : 100 progress = (Float( auditmap_sz ) / ( sitemap_sz - redir_sz ) ) * multi if Module::Auditor.running_timeout_attacks? called_blocks = Module::Auditor.timeout_audit_operations_cnt - Module::Auditor.current_timeout_audit_operations_cnt progress += ( Float( called_blocks ) / Module::Auditor.timeout_audit_operations_cnt ) * multi end begin progress = Float( sprintf( "%.2f", progress ) ) rescue progress = 0.0 end # sometimes progress may slightly exceed 100% # which can cause a few strange stuff to happen progress = 100.0 if progress > 100.0 pb = Mixins::ProgressBar.eta( progress, @opts.start_datetime ) { requests: req_cnt, responses: res_cnt, time_out_count: http.time_out_count, time: audit_store.delta_time, avg: avg, sitemap_size: @sitemap.size, auditmap_size: auditmap_sz, progress: progress, curr_res_time: http.curr_res_time, curr_res_cnt: http.curr_res_cnt, curr_avg: http.curr_res_per_second, average_res_time: http.average_res_time, max_concurrency: http.max_concurrency, current_page: @current_url, eta: pb } end |
#status ⇒ String
Returns the status of the instance as a string.
Possible values are (in order):
-
ready – Just initialised and waiting for instructions
-
preparing – Getting ready to start (i.e. initing plugins etc.)
-
crawling – The instance is crawling the target webapp
-
auditing– The instance is currently auditing the webapp
-
paused – The instance has posed (if applicable)
-
cleanup – The scan has completed and the instance is cleaning up after itself (i.e. waiting for plugins to finish etc.).
-
done – The scan has completed
215 216 217 218 |
# File 'lib/arachni/framework.rb', line 215 def status return 'paused' if paused? @status.to_s end |