Programatically scanning using Arachni (Part 2)
…continuing from where I left off, it’s time to do something more useful with the framework.
Running a full scan
I’m the sort of guy who wants to run before I can walk so let’s take the same approach here.
You might be thinking that:
So what, last time you only showed how to scan one form of a single page…big whoop!
Funnily enough, it’s easier to perform a full fuck audit than a restricted one.
If you remove the path restriction from the last example, the scan will cover the whole website:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | require 'arachni/ui/cli/output' require 'arachni' # shut the system up Arachni::UI::Output.mute! # get an instance of the options class opts = Arachni::Options.instance # we wan to audit forms opts.audit_forms = true # this is the seed URL opts.url = 'http://testfire.net/' # instantiate the framework framework = Arachni::Framework.new( opts ) # load the xss module framework.modules.load( ['xss'] ) # get cracking! framework.run # get the issues framework.audit_store.issues.each { |issue| puts "#{issue.name} at #{issue.url} in #{issue.elem} input <pre class="inline:true decode:1 " >#{issue.var} |
using #{issue.method}.”
}
Which will audit every form found in the website and output:
1 | Cross-Site Scripting (XSS) at http://testfire.net/search.aspx in form input <pre class="inline:true decode:1 " >txtSearch |
using GET.
Cross-Site Scripting (XSS) at http://testfire.net/comment.aspx in form input name using POST.
You can audit cookies, links and headers by setting the following opts:
1 2 3 4 5 | opts.audit_links = true opts.audit_cookies = true # auditing headers is significantly more time consuming opts.audit_headers = true |
That will take a lot more time and will output:
1 | Cross-Site Scripting (XSS) at http://testfire.net/search.aspx in form input <pre class="inline:true decode:1 " >txtSearch |
using GET.
Cross-Site Scripting (XSS) at http://testfire.net/comment.aspx in form input name using POST.
Cross-Site Scripting (XSS) at http://testfire.net/notfound.aspx in link input aspxerrorpath using GET.
Cookies and headers seem XSS-free. ![]()
(You may see some libxml2 warnings which I can't do anything about, don't worry though they won't affect the scan.)
Show some progress (and grab some stats)
The last scan took a while, it'd sure be nice if we could see some progress and some statistics while it's running:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | require 'arachni/ui/cli/output' require 'arachni' def show_progress( framework ) # clear the screen print "\e[H\e[2J" # the true flag updates the timer stats = framework.stats( true ) puts "Scan progress: #{stats[:progress]}% ( Discovered #{stats[:sitemap_size]} pages )" if stats[:current_page] && !stats[:current_page].empty? puts "Currently auditing: #{stats[:current_page]}" else puts "Crawling..." end # the true flag forces the auditstore to refresh # instead of returning the cached object issues = framework.audit_store( true ).issues puts puts "#{issues.count} issues found thus far." issues.each.with_index { |issue, i| puts " [#{i + 1}] #{issue.name} at #{issue.url} in #{issue.elem} input <pre class="inline:true decode:1 " >#{issue.var} |
using #{issue.method}."
}
puts
puts "Sent #{stats[:requests]} requests."
puts "Received and analyzed #{stats[:responses]} responses."
puts 'In ' + stats[:time]
puts 'Average: ' + stats[:avg].to_s + ' requests/second.'
end
# shut the system up
Arachni::UI::Output.mute!
# get an instance of the options class
opts = Arachni::Options.instance
# we wan to audit forms
opts.audit_forms = true
opts.audit_links = true
# this is the seed URL
opts.url = 'http://testfire.net/'
# instantiate the framework
framework = Arachni::Framework.new( opts )
# load the xss module
framework.modules.load( ['xss'] )
# put the scan operation in its own thread
# so that we can do stuff while it's running -- like show progress data..
scan = Thread.new { framework.run }
# show progress every 0.3 seconds while the framework is running
show_progress( framework ) while sleep( 0.3 ) && framework.running?
# the scan is finished, wait for the thread to return cleanly
scan.join
I removed cookie and header auditing from the example, I couldn't bother waiting for it to finish...
Once it finishes you should be seeing something like:
1 2 3 4 5 | Scan progress: 98.46% ( Discovered 66 pages ) Currently auditing: http://testfire.net/default.aspx?content=inside_jobs.htm&job=LoyaltyMarketingProgramManager:Marketing 3 issues found thus far. [1] Cross-Site Scripting (XSS) at http://testfire.net/search.aspx in form input <pre class="inline:true decode:1 " >txtSearch |
using GET.
[2] Cross-Site Scripting (XSS) at http://testfire.net/comment.aspx in form input name using POST.
[3] Cross-Site Scripting (XSS) at http://testfire.net/notfound.aspx in link input aspxerrorpath using GET.
Sent 205 requests.
Received and analyzed 204 responses.
In 00:00:36
Average: 5 requests/second.
You don't see 100% in the final stats because we skipped the last beat, no worries though everything's cool. ![]()
Performing a comprehensive audit
Let's get real though shall we?
That was nothing...just an XSS audit pftt...small potatoes -- let's go for the full monty!
Let's load plugins, reports and all the modules to perform a comprehensive scan which will include links, forms, cookies and headers:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | require 'arachni/ui/cli/output' require 'arachni' def show_progress( framework ) # clear the screen print "\e[H\e[2J" # the true flag updates the timer stats = framework.stats( true ) puts "Scan progress: #{stats[:progress]}% ( Discovered #{stats[:sitemap_size]} pages )" if stats[:current_page] && !stats[:current_page].empty? puts "Currently auditing: #{stats[:current_page]}" else puts "Crawling..." end # the true flag forces the auditstore to refresh # instead of returning the cached object auditstore = framework.audit_store( true ) issues = auditstore.issues puts puts "#{issues.count} issues found thus far." issues.each.with_index { |issue, i| puts " [#{i + 1}] #{issue.name} at #{issue.url} in #{issue.elem} input <pre class="inline:true decode:1 " >#{issue.var} |
using #{issue.method}."
}
puts
puts "Sent #{stats[:requests]} requests."
puts "Received and analyzed #{stats[:responses]} responses."
puts 'In ' + stats[:time]
puts 'Average: ' + stats[:avg].to_s + ' requests/second.'
end
# shut the system up
Arachni::UI::Output.mute!
# get an instance of the options class
opts = Arachni::Options.instance
opts.audit_forms = true
opts.audit_links = true
opts.audit_cookies = true
opts.audit_headers = true
# this is the seed URL
opts.url = 'http://testfire.net/'
# configure the json and stdout reports
opts.reports = {
'json' => {
'outfile' => 'my_report.json'
},
'stdout' => {}
}
# instantiate the framework
framework = Arachni::Framework.new( opts )
# load all modules
framework.modules.load( [ '*' ] )
# =>
# ["interesting_responses",
# "common_files",
# "mixed_resource",
# "xst",
# "http_put",
# "webdav",
# "directory_listing",
# "allowed_methods",
# "htaccess_limit",
# "ssn",
# "private_ip",
# "emails",
# "credit_card",
# "cvs_svn_users",
# "captcha",
# "html_objects",
# "unencrypted_password_forms",
# "backdoors",
# "backup_files",
# "common_directories",
# "trainer",
# "os_cmd_injection",
# "sqli",
# "xss_script_tag",
# "sqli_blind_rdiff",
# "path_traversal",
# "xss_event",
# "xss_uri",
# "sqli_blind_timing",
# "code_injection",
# "rfi",
# "xss_tag",
# "response_splitting",
# "csrf",
# "os_cmd_injection_timing",
# "ldapi",
# "code_injection_timing",
# "xss_path",
# "xpath",
# "unvalidated_redirect",
# "xss"]
# load default plugins
framework.plugins.load_defaults!
# =>
# ["healthmap",
# "timing_attacks",
# "discovery",
# "manual_verification",
# "uniformity",
# "content_types",
# "autothrottle"]
# load the configured reports
framework.reports.load( opts.reports.keys )
# put the scan operation in its own thread
# so that we can do stuff while it's running -- like show progress data..
scan = Thread.new {
framework.run {
# this block will be run right after the scan has finished and
# before the reports are run
# because we selected the stdout report we have to unmute the output
Arachni::UI::Output.unmute!
}
}
# show progress every 0.3 seconds while the framework is running
show_progress( framework ) while sleep( 0.3 ) && framework.running?
# the scan is finished, wait for the thread to return cleanly
scan.join
# the auditstore holds many a treat, including plug-in results
# pp framework.audit_store.plugins
There you go, a comprehensive audit in just a few lines -- around 20 lines if you don't take into account comments and the presentation code.
More to come, c ya next time ![]()
Posted in: Arachni, Open Source, Programming, Projects, Ruby, Security, Web Application
Leave a comment







