arachni 0.2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ACKNOWLEDGMENTS.md +14 -0
- data/AUTHORS.md +6 -0
- data/CHANGELOG.md +162 -0
- data/CONTRIBUTORS.md +10 -0
- data/EXPLOITATION.md +429 -0
- data/HACKING.md +101 -0
- data/LICENSE.md +341 -0
- data/README.md +350 -0
- data/Rakefile +86 -0
- data/bin/arachni +22 -0
- data/bin/arachni_web +77 -0
- data/bin/arachni_xmlrpc +21 -0
- data/bin/arachni_xmlrpcd +82 -0
- data/bin/arachni_xmlrpcd_monitor +74 -0
- data/conf/README.webui.yaml.txt +44 -0
- data/conf/webui.yaml +11 -0
- data/external/metasploit/LICENSE +24 -0
- data/external/metasploit/modules/exploits/unix/webapp/arachni_exec.rb +142 -0
- data/external/metasploit/modules/exploits/unix/webapp/arachni_path_traversal.rb +113 -0
- data/external/metasploit/modules/exploits/unix/webapp/arachni_php_eval.rb +150 -0
- data/external/metasploit/modules/exploits/unix/webapp/arachni_php_include.rb +141 -0
- data/external/metasploit/modules/exploits/unix/webapp/arachni_sqlmap.rb +92 -0
- data/external/metasploit/plugins/arachni.rb +536 -0
- data/getoptslong.rb +241 -0
- data/lib/anemone.rb +2 -0
- data/lib/anemone/cookie_store.rb +35 -0
- data/lib/anemone/core.rb +371 -0
- data/lib/anemone/exceptions.rb +5 -0
- data/lib/anemone/http.rb +144 -0
- data/lib/anemone/page.rb +337 -0
- data/lib/anemone/page_store.rb +160 -0
- data/lib/anemone/storage.rb +34 -0
- data/lib/anemone/storage/base.rb +75 -0
- data/lib/anemone/storage/exceptions.rb +15 -0
- data/lib/anemone/storage/mongodb.rb +89 -0
- data/lib/anemone/storage/pstore.rb +50 -0
- data/lib/anemone/storage/redis.rb +90 -0
- data/lib/anemone/storage/tokyo_cabinet.rb +57 -0
- data/lib/anemone/tentacle.rb +40 -0
- data/lib/arachni.rb +16 -0
- data/lib/audit_store.rb +346 -0
- data/lib/component_manager.rb +293 -0
- data/lib/component_options.rb +395 -0
- data/lib/exceptions.rb +76 -0
- data/lib/framework.rb +637 -0
- data/lib/http.rb +809 -0
- data/lib/issue.rb +302 -0
- data/lib/module.rb +4 -0
- data/lib/module/auditor.rb +455 -0
- data/lib/module/base.rb +188 -0
- data/lib/module/element_db.rb +158 -0
- data/lib/module/key_filler.rb +87 -0
- data/lib/module/manager.rb +87 -0
- data/lib/module/output.rb +68 -0
- data/lib/module/trainer.rb +240 -0
- data/lib/module/utilities.rb +110 -0
- data/lib/options.rb +547 -0
- data/lib/parser.rb +2 -0
- data/lib/parser/auditable.rb +522 -0
- data/lib/parser/elements.rb +296 -0
- data/lib/parser/page.rb +149 -0
- data/lib/parser/parser.rb +717 -0
- data/lib/plugin.rb +4 -0
- data/lib/plugin/base.rb +110 -0
- data/lib/plugin/manager.rb +162 -0
- data/lib/report.rb +4 -0
- data/lib/report/base.rb +119 -0
- data/lib/report/manager.rb +92 -0
- data/lib/rpc/xml/client/base.rb +71 -0
- data/lib/rpc/xml/client/dispatcher.rb +49 -0
- data/lib/rpc/xml/client/instance.rb +88 -0
- data/lib/rpc/xml/server/base.rb +90 -0
- data/lib/rpc/xml/server/dispatcher.rb +357 -0
- data/lib/rpc/xml/server/framework.rb +206 -0
- data/lib/rpc/xml/server/instance.rb +191 -0
- data/lib/rpc/xml/server/module/manager.rb +46 -0
- data/lib/rpc/xml/server/options.rb +124 -0
- data/lib/rpc/xml/server/output.rb +299 -0
- data/lib/rpc/xml/server/plugin/manager.rb +58 -0
- data/lib/ruby.rb +5 -0
- data/lib/ruby/object.rb +32 -0
- data/lib/ruby/string.rb +74 -0
- data/lib/ruby/xmlrpc/server.rb +27 -0
- data/lib/spider.rb +200 -0
- data/lib/typhoeus/request.rb +91 -0
- data/lib/typhoeus/response.rb +34 -0
- data/lib/ui/cli/cli.rb +744 -0
- data/lib/ui/cli/output.rb +279 -0
- data/lib/ui/web/log.rb +82 -0
- data/lib/ui/web/output_stream.rb +94 -0
- data/lib/ui/web/report_manager.rb +222 -0
- data/lib/ui/web/server.rb +903 -0
- data/lib/ui/web/server/db/placeholder +0 -0
- data/lib/ui/web/server/public/banner.png +0 -0
- data/lib/ui/web/server/public/bodybg-small.png +0 -0
- data/lib/ui/web/server/public/bodybg.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/pbar-ani.gif +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/lib/ui/web/server/public/css/smoothness/jquery-ui-1.8.9.custom.css +573 -0
- data/lib/ui/web/server/public/favicon.ico +0 -0
- data/lib/ui/web/server/public/footer.jpg +0 -0
- data/lib/ui/web/server/public/icons/error.png +0 -0
- data/lib/ui/web/server/public/icons/info.png +0 -0
- data/lib/ui/web/server/public/icons/ok.png +0 -0
- data/lib/ui/web/server/public/icons/status.png +0 -0
- data/lib/ui/web/server/public/js/jquery-1.4.4.min.js +167 -0
- data/lib/ui/web/server/public/js/jquery-ui-1.8.9.custom.min.js +781 -0
- data/lib/ui/web/server/public/logo.png +0 -0
- data/lib/ui/web/server/public/nav-left.jpg +0 -0
- data/lib/ui/web/server/public/nav-right.jpg +0 -0
- data/lib/ui/web/server/public/nav-selected-left.jpg +0 -0
- data/lib/ui/web/server/public/nav-selected-right.jpg +0 -0
- data/lib/ui/web/server/public/reports/placeholder +1 -0
- data/lib/ui/web/server/public/sidebar-bottom.jpg +0 -0
- data/lib/ui/web/server/public/sidebar-h4.jpg +0 -0
- data/lib/ui/web/server/public/sidebar-top.jpg +0 -0
- data/lib/ui/web/server/public/spider.png +0 -0
- data/lib/ui/web/server/public/style.css +604 -0
- data/lib/ui/web/server/tmp/placeholder +0 -0
- data/lib/ui/web/server/views/dispatcher.erb +85 -0
- data/lib/ui/web/server/views/dispatcher_error.erb +14 -0
- data/lib/ui/web/server/views/error.erb +1 -0
- data/lib/ui/web/server/views/flash.erb +18 -0
- data/lib/ui/web/server/views/home.erb +14 -0
- data/lib/ui/web/server/views/instance.erb +213 -0
- data/lib/ui/web/server/views/layout.erb +95 -0
- data/lib/ui/web/server/views/log.erb +40 -0
- data/lib/ui/web/server/views/modules.erb +71 -0
- data/lib/ui/web/server/views/options.erb +23 -0
- data/lib/ui/web/server/views/output_results.erb +51 -0
- data/lib/ui/web/server/views/plugins.erb +42 -0
- data/lib/ui/web/server/views/report_formats.erb +30 -0
- data/lib/ui/web/server/views/reports.erb +55 -0
- data/lib/ui/web/server/views/settings.erb +120 -0
- data/lib/ui/web/server/views/welcome.erb +38 -0
- data/lib/ui/xmlrpc/dispatcher_monitor.rb +204 -0
- data/lib/ui/xmlrpc/xmlrpc.rb +843 -0
- data/logs/placeholder +0 -0
- data/metamodules/autothrottle.rb +74 -0
- data/metamodules/timeout_notice.rb +118 -0
- data/metamodules/uniformity.rb +98 -0
- data/modules/audit/code_injection.rb +136 -0
- data/modules/audit/code_injection_timing.rb +115 -0
- data/modules/audit/code_injection_timing/payloads.txt +4 -0
- data/modules/audit/csrf.rb +301 -0
- data/modules/audit/ldapi.rb +103 -0
- data/modules/audit/ldapi/errors.txt +26 -0
- data/modules/audit/os_cmd_injection.rb +103 -0
- data/modules/audit/os_cmd_injection/payloads.txt +2 -0
- data/modules/audit/os_cmd_injection_timing.rb +104 -0
- data/modules/audit/os_cmd_injection_timing/payloads.txt +3 -0
- data/modules/audit/path_traversal.rb +141 -0
- data/modules/audit/response_splitting.rb +105 -0
- data/modules/audit/rfi.rb +193 -0
- data/modules/audit/sqli.rb +120 -0
- data/modules/audit/sqli/regexp_ids.txt +90 -0
- data/modules/audit/sqli_blind_rdiff.rb +321 -0
- data/modules/audit/sqli_blind_timing.rb +103 -0
- data/modules/audit/sqli_blind_timing/payloads.txt +51 -0
- data/modules/audit/trainer.rb +89 -0
- data/modules/audit/unvalidated_redirect.rb +90 -0
- data/modules/audit/xpath.rb +104 -0
- data/modules/audit/xpath/errors.txt +26 -0
- data/modules/audit/xss.rb +99 -0
- data/modules/audit/xss_event.rb +134 -0
- data/modules/audit/xss_path.rb +125 -0
- data/modules/audit/xss_script_tag.rb +112 -0
- data/modules/audit/xss_tag.rb +112 -0
- data/modules/audit/xss_uri.rb +125 -0
- data/modules/recon/allowed_methods.rb +104 -0
- data/modules/recon/backdoors.rb +131 -0
- data/modules/recon/backdoors/filenames.txt +16 -0
- data/modules/recon/backup_files.rb +177 -0
- data/modules/recon/backup_files/extensions.txt +28 -0
- data/modules/recon/common_directories.rb +138 -0
- data/modules/recon/common_directories/directories.txt +265 -0
- data/modules/recon/common_files.rb +138 -0
- data/modules/recon/common_files/filenames.txt +17 -0
- data/modules/recon/directory_listing.rb +171 -0
- data/modules/recon/grep/captcha.rb +62 -0
- data/modules/recon/grep/credit_card.rb +85 -0
- data/modules/recon/grep/cvs_svn_users.rb +73 -0
- data/modules/recon/grep/emails.rb +59 -0
- data/modules/recon/grep/html_objects.rb +53 -0
- data/modules/recon/grep/private_ip.rb +54 -0
- data/modules/recon/grep/ssn.rb +53 -0
- data/modules/recon/htaccess_limit.rb +82 -0
- data/modules/recon/http_put.rb +95 -0
- data/modules/recon/interesting_responses.rb +118 -0
- data/modules/recon/unencrypted_password_forms.rb +119 -0
- data/modules/recon/webdav.rb +126 -0
- data/modules/recon/xst.rb +107 -0
- data/path_extractors/anchors.rb +35 -0
- data/path_extractors/forms.rb +35 -0
- data/path_extractors/frames.rb +38 -0
- data/path_extractors/generic.rb +39 -0
- data/path_extractors/links.rb +35 -0
- data/path_extractors/meta_refresh.rb +39 -0
- data/path_extractors/scripts.rb +37 -0
- data/path_extractors/sitemap.rb +31 -0
- data/plugins/autologin.rb +137 -0
- data/plugins/content_types.rb +90 -0
- data/plugins/cookie_collector.rb +99 -0
- data/plugins/form_dicattack.rb +185 -0
- data/plugins/healthmap.rb +94 -0
- data/plugins/http_dicattack.rb +133 -0
- data/plugins/metamodules.rb +118 -0
- data/plugins/proxy.rb +248 -0
- data/plugins/proxy/server.rb +66 -0
- data/plugins/waf_detector.rb +184 -0
- data/profiles/comprehensive.afp +74 -0
- data/profiles/full.afp +75 -0
- data/reports/afr.rb +59 -0
- data/reports/ap.rb +55 -0
- data/reports/html.rb +179 -0
- data/reports/html/default.erb +967 -0
- data/reports/metareport.rb +139 -0
- data/reports/metareport/arachni_metareport.rb +174 -0
- data/reports/plugin_formatters/html/content_types.rb +82 -0
- data/reports/plugin_formatters/html/cookie_collector.rb +66 -0
- data/reports/plugin_formatters/html/form_dicattack.rb +54 -0
- data/reports/plugin_formatters/html/healthmap.rb +76 -0
- data/reports/plugin_formatters/html/http_dicattack.rb +54 -0
- data/reports/plugin_formatters/html/metaformatters/timeout_notice.rb +65 -0
- data/reports/plugin_formatters/html/metaformatters/uniformity.rb +71 -0
- data/reports/plugin_formatters/html/metamodules.rb +93 -0
- data/reports/plugin_formatters/html/waf_detector.rb +54 -0
- data/reports/plugin_formatters/stdout/content_types.rb +73 -0
- data/reports/plugin_formatters/stdout/cookie_collector.rb +61 -0
- data/reports/plugin_formatters/stdout/form_dicattack.rb +52 -0
- data/reports/plugin_formatters/stdout/healthmap.rb +72 -0
- data/reports/plugin_formatters/stdout/http_dicattack.rb +53 -0
- data/reports/plugin_formatters/stdout/metaformatters/timeout_notice.rb +55 -0
- data/reports/plugin_formatters/stdout/metaformatters/uniformity.rb +68 -0
- data/reports/plugin_formatters/stdout/metamodules.rb +89 -0
- data/reports/plugin_formatters/stdout/waf_detector.rb +48 -0
- data/reports/plugin_formatters/xml/content_types.rb +91 -0
- data/reports/plugin_formatters/xml/cookie_collector.rb +70 -0
- data/reports/plugin_formatters/xml/form_dicattack.rb +57 -0
- data/reports/plugin_formatters/xml/healthmap.rb +82 -0
- data/reports/plugin_formatters/xml/http_dicattack.rb +57 -0
- data/reports/plugin_formatters/xml/metaformatters/timeout_notice.rb +67 -0
- data/reports/plugin_formatters/xml/metaformatters/uniformity.rb +82 -0
- data/reports/plugin_formatters/xml/metamodules.rb +91 -0
- data/reports/plugin_formatters/xml/waf_detector.rb +58 -0
- data/reports/stdout.rb +182 -0
- data/reports/txt.rb +77 -0
- data/reports/xml.rb +231 -0
- data/reports/xml/buffer.rb +98 -0
- metadata +516 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
Arachni
|
|
3
|
+
Copyright (c) 2010-2011 Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
|
4
|
+
|
|
5
|
+
This is free software; you can copy and distribute and modify
|
|
6
|
+
this program under the term of the GPL v2.0 License
|
|
7
|
+
(See LICENSE file for details)
|
|
8
|
+
|
|
9
|
+
=end
|
|
10
|
+
|
|
11
|
+
module Arachni
|
|
12
|
+
module Plugins
|
|
13
|
+
|
|
14
|
+
#
|
|
15
|
+
#
|
|
16
|
+
# @author: Tasos "Zapotek" Laskos
|
|
17
|
+
# <tasos.laskos@gmail.com>
|
|
18
|
+
# <zapotek@segfault.gr>
|
|
19
|
+
# @version: 0.1
|
|
20
|
+
#
|
|
21
|
+
class CookieCollector < Arachni::Plugin::Base
|
|
22
|
+
|
|
23
|
+
#
|
|
24
|
+
# @param [Arachni::Framework] framework
|
|
25
|
+
# @param [Hash] options options passed to the plugin
|
|
26
|
+
#
|
|
27
|
+
def initialize( framework, options )
|
|
28
|
+
super( framework, options )
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def prepare
|
|
32
|
+
@cookies = []
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def run( )
|
|
36
|
+
@framework.http.on_complete {
|
|
37
|
+
|res|
|
|
38
|
+
update( extract_cookies( res ), res )
|
|
39
|
+
}
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def update( cookies, res )
|
|
43
|
+
return if cookies.empty? || !update?( cookies )
|
|
44
|
+
|
|
45
|
+
@cookies << {
|
|
46
|
+
:time => Time.now,
|
|
47
|
+
:res => res.to_hash,
|
|
48
|
+
:cookies => cookies
|
|
49
|
+
}
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def update?( cookies )
|
|
53
|
+
return true if @cookies.empty?
|
|
54
|
+
|
|
55
|
+
cookies.each_pair {
|
|
56
|
+
|k, v|
|
|
57
|
+
return true if @cookies.last[:cookies][k] != v
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return false
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def extract_cookies( res )
|
|
64
|
+
cookies = {}
|
|
65
|
+
|
|
66
|
+
Arachni::Parser.new( @framework.opts, res ).run.cookies.each {
|
|
67
|
+
|cookie|
|
|
68
|
+
cookies.merge!( cookie.simple )
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return cookies
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def clean_up
|
|
75
|
+
while( @framework.running? )
|
|
76
|
+
::IO.select( nil, nil, nil, 1 )
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
register_results( @cookies )
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def self.info
|
|
84
|
+
{
|
|
85
|
+
:name => 'Cookie collector',
|
|
86
|
+
:description => %q{Monitors and collects cookies while establishing a timeline of changes.
|
|
87
|
+
|
|
88
|
+
WARNING: Highly discouraged when the audit includes cookies.
|
|
89
|
+
It will log thousands of results leading to a huge report,
|
|
90
|
+
highly increased memory and CPU usage.},
|
|
91
|
+
:author => 'Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>',
|
|
92
|
+
:version => '0.1',
|
|
93
|
+
}
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
Arachni
|
|
3
|
+
Copyright (c) 2010-2011 Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
|
4
|
+
|
|
5
|
+
This is free software; you can copy and distribute and modify
|
|
6
|
+
this program under the term of the GPL v2.0 License
|
|
7
|
+
(See LICENSE file for details)
|
|
8
|
+
|
|
9
|
+
=end
|
|
10
|
+
|
|
11
|
+
module Arachni
|
|
12
|
+
module Plugins
|
|
13
|
+
|
|
14
|
+
#
|
|
15
|
+
# @author: Tasos "Zapotek" Laskos
|
|
16
|
+
# <tasos.laskos@gmail.com>
|
|
17
|
+
# <zapotek@segfault.gr>
|
|
18
|
+
# @version: 0.1
|
|
19
|
+
#
|
|
20
|
+
class FormDicattack < Arachni::Plugin::Base
|
|
21
|
+
|
|
22
|
+
attr_accessor :http
|
|
23
|
+
|
|
24
|
+
#
|
|
25
|
+
# @param [Arachni::Framework] framework
|
|
26
|
+
# @param [Hash] options options passed to the plugin
|
|
27
|
+
#
|
|
28
|
+
def initialize( framework, options )
|
|
29
|
+
@framework = framework
|
|
30
|
+
@options = options
|
|
31
|
+
|
|
32
|
+
# disable spidering and the subsequent audit
|
|
33
|
+
# @framework.opts.link_count_limit = 0
|
|
34
|
+
|
|
35
|
+
# don't scan the website just yet
|
|
36
|
+
@framework.pause!
|
|
37
|
+
print_info( "System paused." )
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def prepare
|
|
41
|
+
@url = @framework.opts.url.to_s
|
|
42
|
+
@users = File.read( @options['username_list'] ).split( "\n" )
|
|
43
|
+
@passwds = File.read( @options['password_list'] ).split( "\n" )
|
|
44
|
+
@user_field = @options['username_field']
|
|
45
|
+
@passwd_field = @options['password_field']
|
|
46
|
+
@verifier = Regexp.new( @options['login_verifier'] )
|
|
47
|
+
|
|
48
|
+
# we need to declare this in order to pass ourselves
|
|
49
|
+
# as the auditor to the form later in order to submit it.
|
|
50
|
+
@http = @framework.http
|
|
51
|
+
|
|
52
|
+
@found = false
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def run( )
|
|
56
|
+
|
|
57
|
+
if !form = login_form
|
|
58
|
+
print_error( 'Could not find a form suiting the provided params at: ' +
|
|
59
|
+
@url )
|
|
60
|
+
return
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
name = form.raw['attrs']['name'] ? form.raw['attrs']['name'] : '<n/a>'
|
|
64
|
+
print_status( "Found log-in form with name: " + name )
|
|
65
|
+
|
|
66
|
+
print_status( "Building the request queue..." )
|
|
67
|
+
|
|
68
|
+
total_req = @users.size * @passwds.size
|
|
69
|
+
print_status( "Number of requests to be transmitted: #{total_req}" )
|
|
70
|
+
|
|
71
|
+
# register us as the auditor
|
|
72
|
+
form.auditor( self )
|
|
73
|
+
@users.each {
|
|
74
|
+
|user|
|
|
75
|
+
@passwds.each {
|
|
76
|
+
|pass|
|
|
77
|
+
|
|
78
|
+
params = {
|
|
79
|
+
@user_field => user,
|
|
80
|
+
@passwd_field => pass
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
# merge the input fields of the form with our own params
|
|
84
|
+
form.auditable.merge!( params.dup )
|
|
85
|
+
|
|
86
|
+
# we need a clean cookie slate for each request
|
|
87
|
+
opts = {
|
|
88
|
+
:headers => {
|
|
89
|
+
'cookie' => ''
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
form.submit( opts ).on_complete {
|
|
93
|
+
|res|
|
|
94
|
+
|
|
95
|
+
next if @found
|
|
96
|
+
|
|
97
|
+
print_status( "#{@user_field}: '#{res.request.params[@user_field]}'" +
|
|
98
|
+
" -- #{@passwd_field}: '#{res.request.params[@passwd_field]}'" )
|
|
99
|
+
|
|
100
|
+
next if !res.body.match( @verifier )
|
|
101
|
+
|
|
102
|
+
@found = true
|
|
103
|
+
|
|
104
|
+
print_ok( "Found a match. #{@user_field}: '#{res.request.params[@user_field]}'" +
|
|
105
|
+
" -- #{@passwd_field}: '#{res.request.params[@passwd_field]}'" )
|
|
106
|
+
|
|
107
|
+
# register our findings...
|
|
108
|
+
register_results( { :username => user, :password => pass } )
|
|
109
|
+
clean_up( )
|
|
110
|
+
|
|
111
|
+
raise "Stopping the attack."
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
print_status( "Waiting for the requests to complete..." )
|
|
118
|
+
@http.run
|
|
119
|
+
print_error( "Couldn't find a match." )
|
|
120
|
+
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def clean_up
|
|
124
|
+
# abort the rest of the queued requests
|
|
125
|
+
@http.abort
|
|
126
|
+
|
|
127
|
+
# continue with the scan
|
|
128
|
+
@framework.resume!
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def login_form
|
|
132
|
+
# grab the page containing the login form
|
|
133
|
+
res = @http.get( @url, :async => false ).response
|
|
134
|
+
|
|
135
|
+
# parse the response as a Page object
|
|
136
|
+
page = Arachni::Parser.new( @framework.opts, res ).run
|
|
137
|
+
|
|
138
|
+
# find the login form
|
|
139
|
+
form = nil
|
|
140
|
+
page.forms.each {
|
|
141
|
+
|cform|
|
|
142
|
+
form = cform if login_form?( cform )
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return form
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def login_form?( form )
|
|
150
|
+
avail = form.auditable.keys
|
|
151
|
+
provided = [ @user_field, @passwd_field ]
|
|
152
|
+
|
|
153
|
+
provided.each {
|
|
154
|
+
|name|
|
|
155
|
+
return false if !avail.include?( name )
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return true
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def self.info
|
|
163
|
+
{
|
|
164
|
+
:name => 'Form dictionary attacker',
|
|
165
|
+
:description => %q{Uses wordlists to crack login forms.
|
|
166
|
+
If the cracking process is successful the found credentials will be set
|
|
167
|
+
framework-wide and used for the duration of the audit.
|
|
168
|
+
If that's not what you want set the crawler's link-count limit to "0".},
|
|
169
|
+
:author => 'Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>',
|
|
170
|
+
:version => '0.1',
|
|
171
|
+
:options => [
|
|
172
|
+
Arachni::OptPath.new( 'username_list', [ true, 'File with a list of usernames (newline separated).' ] ),
|
|
173
|
+
Arachni::OptPath.new( 'password_list', [ true, 'File with a list of passwords (newline separated).' ] ),
|
|
174
|
+
Arachni::OptString.new( 'username_field', [ true, 'The name of the username form field.'] ),
|
|
175
|
+
Arachni::OptString.new( 'password_field', [ true, 'The name of the password form field.'] ),
|
|
176
|
+
Arachni::OptString.new( 'login_verifier', [ true, 'A string that will be used to verify a successful login.
|
|
177
|
+
For example, if a logout link only appears when a user is logged in then it can be a perfect choice.'] ),
|
|
178
|
+
]
|
|
179
|
+
}
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
end
|
|
185
|
+
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
Arachni
|
|
3
|
+
Copyright (c) 2010-2011 Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
|
4
|
+
|
|
5
|
+
This is free software; you can copy and distribute and modify
|
|
6
|
+
this program under the term of the GPL v2.0 License
|
|
7
|
+
(See LICENSE file for details)
|
|
8
|
+
|
|
9
|
+
=end
|
|
10
|
+
|
|
11
|
+
module Arachni
|
|
12
|
+
module Plugins
|
|
13
|
+
|
|
14
|
+
#
|
|
15
|
+
# Generates a simple list of safe/unsafe URLs.
|
|
16
|
+
#
|
|
17
|
+
# @author: Tasos "Zapotek" Laskos
|
|
18
|
+
# <tasos.laskos@gmail.com>
|
|
19
|
+
# <zapotek@segfault.gr>
|
|
20
|
+
# @version: 0.1
|
|
21
|
+
#
|
|
22
|
+
class HealthMap < Arachni::Plugin::Base
|
|
23
|
+
|
|
24
|
+
include Arachni::Module::Utilities
|
|
25
|
+
|
|
26
|
+
#
|
|
27
|
+
# @param [Arachni::Framework] framework
|
|
28
|
+
# @param [Hash] options options passed to the plugin
|
|
29
|
+
#
|
|
30
|
+
def initialize( framework, options )
|
|
31
|
+
@framework = framework
|
|
32
|
+
@options = options
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def prepare
|
|
36
|
+
while( @framework.running? )
|
|
37
|
+
::IO.select( nil, nil, nil, 1 )
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
@audit_store = @framework.audit_store( true )
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def run( )
|
|
44
|
+
|
|
45
|
+
sitemap = @audit_store.sitemap.map{ |url| normalize( url ) }.uniq
|
|
46
|
+
sitemap |= issue_urls = @audit_store.issues.map { |issue| issue.url }.uniq
|
|
47
|
+
|
|
48
|
+
return if sitemap.size == 0
|
|
49
|
+
|
|
50
|
+
issue = 0
|
|
51
|
+
map = []
|
|
52
|
+
sitemap.each {
|
|
53
|
+
|url|
|
|
54
|
+
|
|
55
|
+
next if !url
|
|
56
|
+
|
|
57
|
+
if issue_urls.include?( url )
|
|
58
|
+
map << { :unsafe => url }
|
|
59
|
+
issue += 1
|
|
60
|
+
else
|
|
61
|
+
map << { :safe => url }
|
|
62
|
+
end
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
register_results( {
|
|
66
|
+
:map => map,
|
|
67
|
+
:total => map.size,
|
|
68
|
+
:safe => map.size - issue,
|
|
69
|
+
:unsafe => issue,
|
|
70
|
+
:issue_percentage => ( ( Float( issue ) / map.size ) * 100 ).round
|
|
71
|
+
} )
|
|
72
|
+
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def normalize( url )
|
|
76
|
+
query = URI( normalize_url( url ) ).query
|
|
77
|
+
return url if !query
|
|
78
|
+
|
|
79
|
+
url.gsub( '?' + query, '' )
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def self.info
|
|
83
|
+
{
|
|
84
|
+
:name => 'Health map',
|
|
85
|
+
:description => %q{Generates a simple list of safe/unsafe URLs.},
|
|
86
|
+
:author => 'Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>',
|
|
87
|
+
:version => '0.1',
|
|
88
|
+
}
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
Arachni
|
|
3
|
+
Copyright (c) 2010-2011 Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
|
4
|
+
|
|
5
|
+
This is free software; you can copy and distribute and modify
|
|
6
|
+
this program under the term of the GPL v2.0 License
|
|
7
|
+
(See LICENSE file for details)
|
|
8
|
+
|
|
9
|
+
=end
|
|
10
|
+
|
|
11
|
+
module Arachni
|
|
12
|
+
module Plugins
|
|
13
|
+
|
|
14
|
+
#
|
|
15
|
+
# @author: Tasos "Zapotek" Laskos
|
|
16
|
+
# <tasos.laskos@gmail.com>
|
|
17
|
+
# <zapotek@segfault.gr>
|
|
18
|
+
# @version: 0.1
|
|
19
|
+
#
|
|
20
|
+
class HTTPDicattack < Arachni::Plugin::Base
|
|
21
|
+
|
|
22
|
+
#
|
|
23
|
+
# @param [Arachni::Framework] framework
|
|
24
|
+
# @param [Hash] options options passed to the plugin
|
|
25
|
+
#
|
|
26
|
+
def initialize( framework, options )
|
|
27
|
+
@framework = framework
|
|
28
|
+
@options = options
|
|
29
|
+
|
|
30
|
+
# disable spidering and the subsequent audit
|
|
31
|
+
# @framework.opts.link_count_limit = 0
|
|
32
|
+
|
|
33
|
+
# don't scan the website just yet
|
|
34
|
+
@framework.pause!
|
|
35
|
+
print_info( "System paused." )
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def prepare
|
|
39
|
+
@url = @framework.opts.url.to_s
|
|
40
|
+
@users = File.read( @options['username_list'] ).split( "\n" )
|
|
41
|
+
@passwds = File.read( @options['password_list'] ).split( "\n" )
|
|
42
|
+
|
|
43
|
+
@found = false
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def run( )
|
|
47
|
+
|
|
48
|
+
if !protected?( @url )
|
|
49
|
+
print_info( "The URL you provided doesn't seem to be protected." )
|
|
50
|
+
print_info( "Aborting..." )
|
|
51
|
+
return
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
url = URI( @url )
|
|
55
|
+
|
|
56
|
+
print_status( "Building the request queue..." )
|
|
57
|
+
|
|
58
|
+
total_req = @users.size * @passwds.size
|
|
59
|
+
print_status( "Number of requests to be transmitted: #{total_req}" )
|
|
60
|
+
|
|
61
|
+
@users.each {
|
|
62
|
+
|user|
|
|
63
|
+
|
|
64
|
+
url.user = user
|
|
65
|
+
@passwds.each {
|
|
66
|
+
|pass|
|
|
67
|
+
|
|
68
|
+
url.password = pass
|
|
69
|
+
@framework.http.get( url.to_s ).on_complete {
|
|
70
|
+
|res|
|
|
71
|
+
|
|
72
|
+
next if @found
|
|
73
|
+
|
|
74
|
+
print_status( "Username: '#{user}' -- Password: '#{pass}'" )
|
|
75
|
+
next if res.code != 200
|
|
76
|
+
|
|
77
|
+
@found = true
|
|
78
|
+
|
|
79
|
+
print_ok( "Found a match. Username: '#{user}' -- Password: '#{pass}'" )
|
|
80
|
+
print_info( "URL: #{res.effective_url}" )
|
|
81
|
+
|
|
82
|
+
@framework.opts.url = res.effective_url
|
|
83
|
+
|
|
84
|
+
# register our findings...
|
|
85
|
+
register_results( { :username => user, :password => pass } )
|
|
86
|
+
clean_up
|
|
87
|
+
|
|
88
|
+
raise "Stopping the attack."
|
|
89
|
+
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
print_status( "Waiting for the requests to complete..." )
|
|
96
|
+
@framework.http.run
|
|
97
|
+
print_error( "Couldn't find a match." )
|
|
98
|
+
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def clean_up
|
|
102
|
+
# abort the rest of the queued requests
|
|
103
|
+
@framework.http.abort
|
|
104
|
+
|
|
105
|
+
# continue with the scan
|
|
106
|
+
@framework.resume!
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def protected?( url )
|
|
111
|
+
@framework.http.get( url, :async => false ).response.code == 401
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def self.info
|
|
115
|
+
{
|
|
116
|
+
:name => 'HTTP dictionary attacker',
|
|
117
|
+
:description => %q{Uses wordlists to crack password protected directories.
|
|
118
|
+
If the cracking process is successful the found credentials will be set
|
|
119
|
+
framework-wide and used for the duration of the audit.
|
|
120
|
+
If that's not what you want set the crawler's link-count limit to "0".},
|
|
121
|
+
:author => 'Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>',
|
|
122
|
+
:version => '0.1',
|
|
123
|
+
:options => [
|
|
124
|
+
Arachni::OptPath.new( 'username_list', [ true, 'File with a list of usernames (newline separated).' ] ),
|
|
125
|
+
Arachni::OptPath.new( 'password_list', [ true, 'File with a list of passwords (newline separated).' ] )
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
end
|
|
133
|
+
end
|