arachni 0.2.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (262) hide show
  1. data/ACKNOWLEDGMENTS.md +14 -0
  2. data/AUTHORS.md +6 -0
  3. data/CHANGELOG.md +162 -0
  4. data/CONTRIBUTORS.md +10 -0
  5. data/EXPLOITATION.md +429 -0
  6. data/HACKING.md +101 -0
  7. data/LICENSE.md +341 -0
  8. data/README.md +350 -0
  9. data/Rakefile +86 -0
  10. data/bin/arachni +22 -0
  11. data/bin/arachni_web +77 -0
  12. data/bin/arachni_xmlrpc +21 -0
  13. data/bin/arachni_xmlrpcd +82 -0
  14. data/bin/arachni_xmlrpcd_monitor +74 -0
  15. data/conf/README.webui.yaml.txt +44 -0
  16. data/conf/webui.yaml +11 -0
  17. data/external/metasploit/LICENSE +24 -0
  18. data/external/metasploit/modules/exploits/unix/webapp/arachni_exec.rb +142 -0
  19. data/external/metasploit/modules/exploits/unix/webapp/arachni_path_traversal.rb +113 -0
  20. data/external/metasploit/modules/exploits/unix/webapp/arachni_php_eval.rb +150 -0
  21. data/external/metasploit/modules/exploits/unix/webapp/arachni_php_include.rb +141 -0
  22. data/external/metasploit/modules/exploits/unix/webapp/arachni_sqlmap.rb +92 -0
  23. data/external/metasploit/plugins/arachni.rb +536 -0
  24. data/getoptslong.rb +241 -0
  25. data/lib/anemone.rb +2 -0
  26. data/lib/anemone/cookie_store.rb +35 -0
  27. data/lib/anemone/core.rb +371 -0
  28. data/lib/anemone/exceptions.rb +5 -0
  29. data/lib/anemone/http.rb +144 -0
  30. data/lib/anemone/page.rb +337 -0
  31. data/lib/anemone/page_store.rb +160 -0
  32. data/lib/anemone/storage.rb +34 -0
  33. data/lib/anemone/storage/base.rb +75 -0
  34. data/lib/anemone/storage/exceptions.rb +15 -0
  35. data/lib/anemone/storage/mongodb.rb +89 -0
  36. data/lib/anemone/storage/pstore.rb +50 -0
  37. data/lib/anemone/storage/redis.rb +90 -0
  38. data/lib/anemone/storage/tokyo_cabinet.rb +57 -0
  39. data/lib/anemone/tentacle.rb +40 -0
  40. data/lib/arachni.rb +16 -0
  41. data/lib/audit_store.rb +346 -0
  42. data/lib/component_manager.rb +293 -0
  43. data/lib/component_options.rb +395 -0
  44. data/lib/exceptions.rb +76 -0
  45. data/lib/framework.rb +637 -0
  46. data/lib/http.rb +809 -0
  47. data/lib/issue.rb +302 -0
  48. data/lib/module.rb +4 -0
  49. data/lib/module/auditor.rb +455 -0
  50. data/lib/module/base.rb +188 -0
  51. data/lib/module/element_db.rb +158 -0
  52. data/lib/module/key_filler.rb +87 -0
  53. data/lib/module/manager.rb +87 -0
  54. data/lib/module/output.rb +68 -0
  55. data/lib/module/trainer.rb +240 -0
  56. data/lib/module/utilities.rb +110 -0
  57. data/lib/options.rb +547 -0
  58. data/lib/parser.rb +2 -0
  59. data/lib/parser/auditable.rb +522 -0
  60. data/lib/parser/elements.rb +296 -0
  61. data/lib/parser/page.rb +149 -0
  62. data/lib/parser/parser.rb +717 -0
  63. data/lib/plugin.rb +4 -0
  64. data/lib/plugin/base.rb +110 -0
  65. data/lib/plugin/manager.rb +162 -0
  66. data/lib/report.rb +4 -0
  67. data/lib/report/base.rb +119 -0
  68. data/lib/report/manager.rb +92 -0
  69. data/lib/rpc/xml/client/base.rb +71 -0
  70. data/lib/rpc/xml/client/dispatcher.rb +49 -0
  71. data/lib/rpc/xml/client/instance.rb +88 -0
  72. data/lib/rpc/xml/server/base.rb +90 -0
  73. data/lib/rpc/xml/server/dispatcher.rb +357 -0
  74. data/lib/rpc/xml/server/framework.rb +206 -0
  75. data/lib/rpc/xml/server/instance.rb +191 -0
  76. data/lib/rpc/xml/server/module/manager.rb +46 -0
  77. data/lib/rpc/xml/server/options.rb +124 -0
  78. data/lib/rpc/xml/server/output.rb +299 -0
  79. data/lib/rpc/xml/server/plugin/manager.rb +58 -0
  80. data/lib/ruby.rb +5 -0
  81. data/lib/ruby/object.rb +32 -0
  82. data/lib/ruby/string.rb +74 -0
  83. data/lib/ruby/xmlrpc/server.rb +27 -0
  84. data/lib/spider.rb +200 -0
  85. data/lib/typhoeus/request.rb +91 -0
  86. data/lib/typhoeus/response.rb +34 -0
  87. data/lib/ui/cli/cli.rb +744 -0
  88. data/lib/ui/cli/output.rb +279 -0
  89. data/lib/ui/web/log.rb +82 -0
  90. data/lib/ui/web/output_stream.rb +94 -0
  91. data/lib/ui/web/report_manager.rb +222 -0
  92. data/lib/ui/web/server.rb +903 -0
  93. data/lib/ui/web/server/db/placeholder +0 -0
  94. data/lib/ui/web/server/public/banner.png +0 -0
  95. data/lib/ui/web/server/public/bodybg-small.png +0 -0
  96. data/lib/ui/web/server/public/bodybg.png +0 -0
  97. data/lib/ui/web/server/public/css/smoothness/images/pbar-ani.gif +0 -0
  98. data/lib/ui/web/server/public/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  99. data/lib/ui/web/server/public/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  100. data/lib/ui/web/server/public/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  101. data/lib/ui/web/server/public/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  102. data/lib/ui/web/server/public/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  103. data/lib/ui/web/server/public/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  104. data/lib/ui/web/server/public/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  105. data/lib/ui/web/server/public/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  106. data/lib/ui/web/server/public/css/smoothness/images/ui-icons_222222_256x240.png +0 -0
  107. data/lib/ui/web/server/public/css/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  108. data/lib/ui/web/server/public/css/smoothness/images/ui-icons_454545_256x240.png +0 -0
  109. data/lib/ui/web/server/public/css/smoothness/images/ui-icons_888888_256x240.png +0 -0
  110. data/lib/ui/web/server/public/css/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  111. data/lib/ui/web/server/public/css/smoothness/jquery-ui-1.8.9.custom.css +573 -0
  112. data/lib/ui/web/server/public/favicon.ico +0 -0
  113. data/lib/ui/web/server/public/footer.jpg +0 -0
  114. data/lib/ui/web/server/public/icons/error.png +0 -0
  115. data/lib/ui/web/server/public/icons/info.png +0 -0
  116. data/lib/ui/web/server/public/icons/ok.png +0 -0
  117. data/lib/ui/web/server/public/icons/status.png +0 -0
  118. data/lib/ui/web/server/public/js/jquery-1.4.4.min.js +167 -0
  119. data/lib/ui/web/server/public/js/jquery-ui-1.8.9.custom.min.js +781 -0
  120. data/lib/ui/web/server/public/logo.png +0 -0
  121. data/lib/ui/web/server/public/nav-left.jpg +0 -0
  122. data/lib/ui/web/server/public/nav-right.jpg +0 -0
  123. data/lib/ui/web/server/public/nav-selected-left.jpg +0 -0
  124. data/lib/ui/web/server/public/nav-selected-right.jpg +0 -0
  125. data/lib/ui/web/server/public/reports/placeholder +1 -0
  126. data/lib/ui/web/server/public/sidebar-bottom.jpg +0 -0
  127. data/lib/ui/web/server/public/sidebar-h4.jpg +0 -0
  128. data/lib/ui/web/server/public/sidebar-top.jpg +0 -0
  129. data/lib/ui/web/server/public/spider.png +0 -0
  130. data/lib/ui/web/server/public/style.css +604 -0
  131. data/lib/ui/web/server/tmp/placeholder +0 -0
  132. data/lib/ui/web/server/views/dispatcher.erb +85 -0
  133. data/lib/ui/web/server/views/dispatcher_error.erb +14 -0
  134. data/lib/ui/web/server/views/error.erb +1 -0
  135. data/lib/ui/web/server/views/flash.erb +18 -0
  136. data/lib/ui/web/server/views/home.erb +14 -0
  137. data/lib/ui/web/server/views/instance.erb +213 -0
  138. data/lib/ui/web/server/views/layout.erb +95 -0
  139. data/lib/ui/web/server/views/log.erb +40 -0
  140. data/lib/ui/web/server/views/modules.erb +71 -0
  141. data/lib/ui/web/server/views/options.erb +23 -0
  142. data/lib/ui/web/server/views/output_results.erb +51 -0
  143. data/lib/ui/web/server/views/plugins.erb +42 -0
  144. data/lib/ui/web/server/views/report_formats.erb +30 -0
  145. data/lib/ui/web/server/views/reports.erb +55 -0
  146. data/lib/ui/web/server/views/settings.erb +120 -0
  147. data/lib/ui/web/server/views/welcome.erb +38 -0
  148. data/lib/ui/xmlrpc/dispatcher_monitor.rb +204 -0
  149. data/lib/ui/xmlrpc/xmlrpc.rb +843 -0
  150. data/logs/placeholder +0 -0
  151. data/metamodules/autothrottle.rb +74 -0
  152. data/metamodules/timeout_notice.rb +118 -0
  153. data/metamodules/uniformity.rb +98 -0
  154. data/modules/audit/code_injection.rb +136 -0
  155. data/modules/audit/code_injection_timing.rb +115 -0
  156. data/modules/audit/code_injection_timing/payloads.txt +4 -0
  157. data/modules/audit/csrf.rb +301 -0
  158. data/modules/audit/ldapi.rb +103 -0
  159. data/modules/audit/ldapi/errors.txt +26 -0
  160. data/modules/audit/os_cmd_injection.rb +103 -0
  161. data/modules/audit/os_cmd_injection/payloads.txt +2 -0
  162. data/modules/audit/os_cmd_injection_timing.rb +104 -0
  163. data/modules/audit/os_cmd_injection_timing/payloads.txt +3 -0
  164. data/modules/audit/path_traversal.rb +141 -0
  165. data/modules/audit/response_splitting.rb +105 -0
  166. data/modules/audit/rfi.rb +193 -0
  167. data/modules/audit/sqli.rb +120 -0
  168. data/modules/audit/sqli/regexp_ids.txt +90 -0
  169. data/modules/audit/sqli_blind_rdiff.rb +321 -0
  170. data/modules/audit/sqli_blind_timing.rb +103 -0
  171. data/modules/audit/sqli_blind_timing/payloads.txt +51 -0
  172. data/modules/audit/trainer.rb +89 -0
  173. data/modules/audit/unvalidated_redirect.rb +90 -0
  174. data/modules/audit/xpath.rb +104 -0
  175. data/modules/audit/xpath/errors.txt +26 -0
  176. data/modules/audit/xss.rb +99 -0
  177. data/modules/audit/xss_event.rb +134 -0
  178. data/modules/audit/xss_path.rb +125 -0
  179. data/modules/audit/xss_script_tag.rb +112 -0
  180. data/modules/audit/xss_tag.rb +112 -0
  181. data/modules/audit/xss_uri.rb +125 -0
  182. data/modules/recon/allowed_methods.rb +104 -0
  183. data/modules/recon/backdoors.rb +131 -0
  184. data/modules/recon/backdoors/filenames.txt +16 -0
  185. data/modules/recon/backup_files.rb +177 -0
  186. data/modules/recon/backup_files/extensions.txt +28 -0
  187. data/modules/recon/common_directories.rb +138 -0
  188. data/modules/recon/common_directories/directories.txt +265 -0
  189. data/modules/recon/common_files.rb +138 -0
  190. data/modules/recon/common_files/filenames.txt +17 -0
  191. data/modules/recon/directory_listing.rb +171 -0
  192. data/modules/recon/grep/captcha.rb +62 -0
  193. data/modules/recon/grep/credit_card.rb +85 -0
  194. data/modules/recon/grep/cvs_svn_users.rb +73 -0
  195. data/modules/recon/grep/emails.rb +59 -0
  196. data/modules/recon/grep/html_objects.rb +53 -0
  197. data/modules/recon/grep/private_ip.rb +54 -0
  198. data/modules/recon/grep/ssn.rb +53 -0
  199. data/modules/recon/htaccess_limit.rb +82 -0
  200. data/modules/recon/http_put.rb +95 -0
  201. data/modules/recon/interesting_responses.rb +118 -0
  202. data/modules/recon/unencrypted_password_forms.rb +119 -0
  203. data/modules/recon/webdav.rb +126 -0
  204. data/modules/recon/xst.rb +107 -0
  205. data/path_extractors/anchors.rb +35 -0
  206. data/path_extractors/forms.rb +35 -0
  207. data/path_extractors/frames.rb +38 -0
  208. data/path_extractors/generic.rb +39 -0
  209. data/path_extractors/links.rb +35 -0
  210. data/path_extractors/meta_refresh.rb +39 -0
  211. data/path_extractors/scripts.rb +37 -0
  212. data/path_extractors/sitemap.rb +31 -0
  213. data/plugins/autologin.rb +137 -0
  214. data/plugins/content_types.rb +90 -0
  215. data/plugins/cookie_collector.rb +99 -0
  216. data/plugins/form_dicattack.rb +185 -0
  217. data/plugins/healthmap.rb +94 -0
  218. data/plugins/http_dicattack.rb +133 -0
  219. data/plugins/metamodules.rb +118 -0
  220. data/plugins/proxy.rb +248 -0
  221. data/plugins/proxy/server.rb +66 -0
  222. data/plugins/waf_detector.rb +184 -0
  223. data/profiles/comprehensive.afp +74 -0
  224. data/profiles/full.afp +75 -0
  225. data/reports/afr.rb +59 -0
  226. data/reports/ap.rb +55 -0
  227. data/reports/html.rb +179 -0
  228. data/reports/html/default.erb +967 -0
  229. data/reports/metareport.rb +139 -0
  230. data/reports/metareport/arachni_metareport.rb +174 -0
  231. data/reports/plugin_formatters/html/content_types.rb +82 -0
  232. data/reports/plugin_formatters/html/cookie_collector.rb +66 -0
  233. data/reports/plugin_formatters/html/form_dicattack.rb +54 -0
  234. data/reports/plugin_formatters/html/healthmap.rb +76 -0
  235. data/reports/plugin_formatters/html/http_dicattack.rb +54 -0
  236. data/reports/plugin_formatters/html/metaformatters/timeout_notice.rb +65 -0
  237. data/reports/plugin_formatters/html/metaformatters/uniformity.rb +71 -0
  238. data/reports/plugin_formatters/html/metamodules.rb +93 -0
  239. data/reports/plugin_formatters/html/waf_detector.rb +54 -0
  240. data/reports/plugin_formatters/stdout/content_types.rb +73 -0
  241. data/reports/plugin_formatters/stdout/cookie_collector.rb +61 -0
  242. data/reports/plugin_formatters/stdout/form_dicattack.rb +52 -0
  243. data/reports/plugin_formatters/stdout/healthmap.rb +72 -0
  244. data/reports/plugin_formatters/stdout/http_dicattack.rb +53 -0
  245. data/reports/plugin_formatters/stdout/metaformatters/timeout_notice.rb +55 -0
  246. data/reports/plugin_formatters/stdout/metaformatters/uniformity.rb +68 -0
  247. data/reports/plugin_formatters/stdout/metamodules.rb +89 -0
  248. data/reports/plugin_formatters/stdout/waf_detector.rb +48 -0
  249. data/reports/plugin_formatters/xml/content_types.rb +91 -0
  250. data/reports/plugin_formatters/xml/cookie_collector.rb +70 -0
  251. data/reports/plugin_formatters/xml/form_dicattack.rb +57 -0
  252. data/reports/plugin_formatters/xml/healthmap.rb +82 -0
  253. data/reports/plugin_formatters/xml/http_dicattack.rb +57 -0
  254. data/reports/plugin_formatters/xml/metaformatters/timeout_notice.rb +67 -0
  255. data/reports/plugin_formatters/xml/metaformatters/uniformity.rb +82 -0
  256. data/reports/plugin_formatters/xml/metamodules.rb +91 -0
  257. data/reports/plugin_formatters/xml/waf_detector.rb +58 -0
  258. data/reports/stdout.rb +182 -0
  259. data/reports/txt.rb +77 -0
  260. data/reports/xml.rb +231 -0
  261. data/reports/xml/buffer.rb +98 -0
  262. metadata +516 -0
@@ -0,0 +1,68 @@
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
+
12
+ module Arachni
13
+ module Module
14
+
15
+
16
+ #
17
+ # Provides output functionality to the modules via the {Arachni::UI::Output}<br/>
18
+ # prepending the module name to the output message.
19
+ #
20
+ # @author: Tasos "Zapotek" Laskos
21
+ # <tasos.laskos@gmail.com>
22
+ # <zapotek@segfault.gr>
23
+ # @version: 0.1
24
+ #
25
+ module Output
26
+
27
+ include Arachni::UI::Output
28
+
29
+ alias :o_print_error :print_error
30
+ alias :o_print_status :print_status
31
+ alias :o_print_info :print_info
32
+ alias :o_print_ok :print_ok
33
+ alias :o_print_debug :print_debug
34
+ alias :o_print_verbose :print_verbose
35
+ alias :o_print_line :print_line
36
+
37
+ def print_error( str = '' )
38
+ o_print_error( self.class.info[:name] + ": " + str )
39
+ end
40
+
41
+ def print_status( str = '' )
42
+ o_print_status( self.class.info[:name] + ": " + str )
43
+ end
44
+
45
+ def print_info( str = '' )
46
+ o_print_info( self.class.info[:name] + ": " + str )
47
+ end
48
+
49
+ def print_ok( str = '' )
50
+ o_print_ok( self.class.info[:name] + ": " + str )
51
+ end
52
+
53
+ def print_debug( str = '' )
54
+ o_print_debug( self.class.info[:name] + ": " + str )
55
+ end
56
+
57
+ def print_verbose( str = '' )
58
+ o_print_verbose( self.class.info[:name] + ": " + str )
59
+ end
60
+
61
+ def print_line( str = '' )
62
+ o_print_line( self.class.info[:name] + ": " + str )
63
+ end
64
+
65
+ end
66
+
67
+ end
68
+ end
@@ -0,0 +1,240 @@
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
+ require Arachni::Options.instance.dir['lib'] + 'module/element_db'
12
+ require Arachni::Options.instance.dir['lib'] + 'module/output'
13
+
14
+ module Arachni
15
+ module Module
16
+
17
+ #
18
+ # Trainer class
19
+ #
20
+ # Analyzes all HTTP responses looking for new auditable elements.
21
+ #
22
+ # <tasos.laskos@gmail.com>
23
+ # <zapotek@segfault.gr>
24
+ # @version: 0.2.1
25
+ #
26
+ class Trainer
27
+
28
+ include Output
29
+ include ElementDB
30
+
31
+ attr_writer :page
32
+ attr_accessor :http
33
+ attr_accessor :parser
34
+
35
+ def initialize
36
+ @opts = Options.instance
37
+ @updated = false
38
+ end
39
+
40
+ #
41
+ # Passes the reponse to {#analyze} for analysis
42
+ #
43
+ # @param [Typhoeus::Response] res
44
+ # @param [Bool] redir was the response forcing a redirection?
45
+ #
46
+ def add_response( res, redir = false )
47
+
48
+ # non text files won't contain any auditable elements
49
+ type = @http.class.content_type( res.headers_hash )
50
+ if type.is_a?( String) && !type.substring?( 'text' )
51
+ return false
52
+ end
53
+
54
+ @parser = Parser.new( Options.instance, res )
55
+ @parser.url = @page.url
56
+
57
+ begin
58
+ url = res.effective_url
59
+ url = URI( to_absolute( url ) )
60
+
61
+ return if !follow?( url )
62
+ return if ( redir && !follow?( url ) )
63
+
64
+ analyze( [ res, redir ] )
65
+
66
+ rescue Exception => e
67
+ print_error( "Invalid URL, probably broken redirection. Ignoring..." )
68
+ raise e
69
+ end
70
+
71
+ end
72
+
73
+ #
74
+ # Decodes URLs to reverse multiple encodes and removes NULL characters
75
+ #
76
+ def url_sanitize( url )
77
+
78
+ while( url =~ /%/ )
79
+ url = ( URI.decode( url ).to_s.unpack( 'A*' )[0] )
80
+ end
81
+
82
+ return URI.encode( url )
83
+ end
84
+
85
+ def follow?( url )
86
+ @parser.url = @page.url
87
+
88
+ return false if !@parser.in_domain?( url )
89
+ return false if @parser.exclude?( url )
90
+ return false if !@parser.include?( url )
91
+ return true
92
+ end
93
+
94
+ #
95
+ # Returns an updated {Arachni::Parser::Page} object or nil if there waere no updates
96
+ #
97
+ # @return [Page]
98
+ #
99
+ def page
100
+ if( @updated )
101
+ @updated = false
102
+ return @page
103
+ else
104
+ return nil
105
+ end
106
+ end
107
+
108
+
109
+ #
110
+ # Analyzes a response looking for new links, forms and cookies.
111
+ #
112
+ # @param [Typhoeus::Response, Bool] res
113
+ #
114
+ def analyze( res )
115
+
116
+ print_debug( 'Started for response with request ID: #' +
117
+ res[0].request.id.to_s )
118
+
119
+ @parser.url = res[0].effective_url.clone
120
+
121
+ train_cookies( res[0] )
122
+
123
+ # if the response body is the same as the page body and
124
+ # no new cookies have appeared there's no reason to analyze the page
125
+ if( res[0].body == @page.html && !@updated )
126
+ print_debug( 'Page hasn\'t changed, skipping...' )
127
+ return
128
+ end
129
+
130
+ train_forms( res[0] )
131
+ train_links( res[0], res[1] )
132
+
133
+ if( @updated )
134
+ @page.html = res[0].body.dup
135
+
136
+ begin
137
+ url = res[0].request.url
138
+ # prepare the page url
139
+ @parser.url = to_absolute( url )
140
+ rescue Exception => e
141
+ print_error( "Invalid URL, probably broken redirection. Ignoring..." )
142
+ # raise e
143
+ end
144
+
145
+ @page.response_headers = res[0].headers_hash
146
+ @page.query_vars = @parser.link_vars( @parser.url ).dup
147
+ @page.url = @parser.url.dup
148
+ @page.code = res[0].code
149
+ @page.method = res[0].request.method.to_s.upcase
150
+
151
+ end
152
+
153
+ print_debug( 'Training complete.' )
154
+ end
155
+
156
+ private
157
+
158
+ def to_absolute( url )
159
+ effective_url = url_sanitize( url )
160
+ @page.url = url_sanitize( @page.url )
161
+
162
+ begin
163
+ # prepare the page url
164
+ return (URI.parse( @page.url ).merge( URI( effective_url ) )).to_s.dup
165
+ rescue
166
+ # worst case scenario
167
+ return @page.url
168
+ end
169
+ end
170
+
171
+ def train_forms( res )
172
+ return [], 0 if !@opts.audit_forms
173
+
174
+ # @parser.url = res.effective_url.clone
175
+ forms = @parser.forms( ).clone
176
+ cforms, form_cnt = update_forms( forms )
177
+
178
+ if ( form_cnt > 0 )
179
+ @page.forms = cforms.flatten
180
+ @updated = true
181
+
182
+ print_debug( 'Found ' + form_cnt.to_s + ' new forms.' )
183
+ else
184
+ @page.forms = forms
185
+ end
186
+
187
+ end
188
+
189
+ def train_links( res, redir = false )
190
+ return [], 0 if !@opts.audit_links
191
+
192
+ # @parser.url = res.effective_url.clone
193
+
194
+ links = @parser.links.clone
195
+
196
+ if( redir )
197
+ url = to_absolute( res.effective_url )
198
+ links << Arachni::Parser::Element::Link.new( url, {
199
+ 'href' => url,
200
+ 'vars' => @parser.link_vars( url )
201
+ } )
202
+ end
203
+
204
+ clinks, link_cnt = update_links( links )
205
+
206
+ if ( link_cnt > 0 )
207
+ @page.links = clinks.flatten
208
+ @updated = true
209
+
210
+ print_debug( 'Found ' + link_cnt.to_s + ' new links.' )
211
+ else
212
+ @page.links = links
213
+ end
214
+
215
+ end
216
+
217
+ def train_cookies( res )
218
+
219
+ cookies = @parser.cookies.clone
220
+ ccookies, cookie_cnt = update_cookies( cookies )
221
+
222
+ if ( cookie_cnt > 0 )
223
+ @page.cookies = ccookies.flatten
224
+ @updated = true
225
+
226
+ print_debug( 'Found ' + cookie_cnt.to_s + ' new cookies.' )
227
+ else
228
+ @page.cookies = cookies
229
+ end
230
+
231
+ end
232
+
233
+
234
+ def self.info
235
+ { :name => 'Trainer' }
236
+ end
237
+
238
+ end
239
+ end
240
+ end
@@ -0,0 +1,110 @@
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 Module
13
+
14
+
15
+ #
16
+ # Utilities class
17
+ #
18
+ # Includes some useful methods for the system, the modules etc...
19
+ #
20
+ # @author: Tasos "Zapotek" Laskos
21
+ # <tasos.laskos@gmail.com>
22
+ # <zapotek@segfault.gr>
23
+ # @version: 0.1.1
24
+ #
25
+ module Utilities
26
+
27
+ #
28
+ # Gets path from URL
29
+ #
30
+ # @param [String] url
31
+ #
32
+ # @return [String] path
33
+ #
34
+ def get_path( url )
35
+
36
+ uri = URI( URI.escape( url ) )
37
+ path = uri.path
38
+
39
+ if !File.extname( path ).empty?
40
+ path = File.dirname( path )
41
+ end
42
+
43
+ path << '/' if path[-1] != '/'
44
+ return uri.scheme + "://" + uri.host + path
45
+ end
46
+
47
+ def seed
48
+ @@seed ||= Digest::SHA2.hexdigest( srand( 1000 ).to_s )
49
+ end
50
+
51
+ def normalize_url( url )
52
+ begin
53
+ return URI.encode( URI.decode( url.to_s ) ).to_s.gsub( '[', '%5B' ).gsub( ']', '%5D' )
54
+ rescue
55
+ begin
56
+ return URI.encode( URI.decode( url.to_s ) ).to_s
57
+ rescue
58
+ return url
59
+ end
60
+ end
61
+ end
62
+
63
+ #
64
+ # Gets module data files from 'modules/[modtype]/[modname]/[filename]'
65
+ #
66
+ # @param [String] filename filename, without the path
67
+ # @param [Block] the block to be passed each line as it's read
68
+ #
69
+ def read_file( filename, &block )
70
+
71
+ # the path of the module that called us
72
+ mod_path = block.source_location[0]
73
+
74
+ # the name of the module that called us
75
+ mod_name = File.basename( mod_path, ".rb")
76
+
77
+ # the path to the module's data file directory
78
+ path = File.expand_path( File.dirname( mod_path ) ) +
79
+ '/' + mod_name + '/'
80
+
81
+ file = File.open( path + '/' + filename ).each {
82
+ |line|
83
+ yield line.strip
84
+ }
85
+
86
+ file.close
87
+
88
+ end
89
+
90
+ #
91
+ # Wraps the "block" in exception handling code and runs it.
92
+ #
93
+ # @param [Block]
94
+ #
95
+ def exception_jail( &block )
96
+ begin
97
+ block.call
98
+ rescue Exception => e
99
+ print_error( e.to_s )
100
+ print_debug_backtrace( e )
101
+ raise e
102
+ end
103
+ end
104
+
105
+ extend self
106
+
107
+ end
108
+
109
+ end
110
+ end
@@ -0,0 +1,547 @@
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
+ require 'singleton'
12
+
13
+ module Arachni
14
+
15
+ #
16
+ # Options class.
17
+ #
18
+ # Implements the Singleton pattern and formaly defines
19
+ # all of Arachni's runtime options.
20
+ #
21
+ # @author: Tasos "Zapotek" Laskos
22
+ # <tasos.laskos@gmail.com>
23
+ # <zapotek@segfault.gr>
24
+ # @version: 0.1.1
25
+ #
26
+ class Options
27
+
28
+ include Singleton
29
+
30
+ #
31
+ # The extension of the profile files.
32
+ #
33
+ # @return [String]
34
+ #
35
+ PROFILE_EXT = '.afp'
36
+
37
+ #
38
+ # Holds absolute paths for the directory structure of the framework
39
+ #
40
+ # @return [Hash]
41
+ #
42
+ attr_accessor :dir
43
+
44
+ #
45
+ # The URL to audit
46
+ #
47
+ # @return [String,URI]
48
+ #
49
+ attr_accessor :url
50
+
51
+ #
52
+ # Show help?
53
+ #
54
+ # @return [Bool]
55
+ #
56
+ attr_accessor :help
57
+
58
+ #
59
+ # Output only positive results during the audit?
60
+ #
61
+ # @return [Bool]
62
+ #
63
+ attr_accessor :only_positives
64
+
65
+ #
66
+ # Be verbose?
67
+ #
68
+ # @return [Bool]
69
+ #
70
+ attr_accessor :arachni_verbose
71
+
72
+ #
73
+ # Output debugging messages?
74
+ #
75
+ # @return [Bool]
76
+ #
77
+ attr_accessor :debug
78
+
79
+ #
80
+ # Filters for redundant links
81
+ #
82
+ # @return [Array]
83
+ #
84
+ attr_accessor :redundant
85
+
86
+ #
87
+ # Should the crawler obery robots.txt files?
88
+ #
89
+ # @return [Bool]
90
+ #
91
+ attr_accessor :obey_robots_txt
92
+
93
+ #
94
+ # How deep to go in the site structure?<br/>
95
+ # If nil, depth_limit = inf
96
+ #
97
+ # @return [Integer]
98
+ #
99
+ attr_accessor :depth_limit
100
+
101
+ #
102
+ # How many links to follow?
103
+ # If nil, link_count_limit = inf
104
+ #
105
+ # @return [Integer]
106
+ #
107
+ attr_accessor :link_count_limit
108
+
109
+ #
110
+ # How many redirects to follow?
111
+ # If nil, redirect_limit = inf
112
+ #
113
+ # @return [Integer]
114
+ #
115
+ attr_accessor :redirect_limit
116
+
117
+ #
118
+ # List modules, based on regexps, and exit?
119
+ #
120
+ # @return [Array<Regexp>]
121
+ #
122
+ attr_accessor :lsmod
123
+
124
+ #
125
+ # List reports and exit?
126
+ #
127
+ # @return [Bool]
128
+ #
129
+ attr_accessor :lsrep
130
+
131
+ #
132
+ # How many concurrent HTTP requests?
133
+ #
134
+ # @return [Integer]
135
+ #
136
+ attr_accessor :http_req_limit
137
+
138
+ #
139
+ # Should Arachni audit links?
140
+ #
141
+ # @return [Bool]
142
+ #
143
+ attr_accessor :audit_links
144
+
145
+ #
146
+ # Should Arachni audit forms?
147
+ #
148
+ # @return [Bool]
149
+ #
150
+ attr_accessor :audit_forms
151
+
152
+ #
153
+ # Should Arachni audit cookies?
154
+ #
155
+ # @return [Bool]
156
+ #
157
+ attr_accessor :audit_cookies
158
+
159
+ #
160
+ # Should Arachni audit HTTP headers?
161
+ #
162
+ # @return [Bool]
163
+ #
164
+ attr_accessor :audit_headers
165
+
166
+ #
167
+ # Array of modules to load
168
+ #
169
+ # @return [Array]
170
+ #
171
+ attr_accessor :mods
172
+
173
+ #
174
+ # Array of reports to load
175
+ #
176
+ # @return [Array]
177
+ #
178
+ attr_accessor :reports
179
+
180
+ #
181
+ # Location of an Arachni Framework Report (.afr) file to load
182
+ #
183
+ # @return [String]
184
+ #
185
+ attr_accessor :repload
186
+
187
+ #
188
+ # Where to save the Arachni Framework Profile (.afp) file
189
+ #
190
+ # @return [String]
191
+ #
192
+ attr_accessor :save_profile
193
+
194
+ #
195
+ # Location of Arachni Framework Profile (.afp) files to load
196
+ #
197
+ # @return [Array]
198
+ #
199
+ attr_accessor :load_profile
200
+
201
+
202
+ attr_accessor :show_profile
203
+
204
+ #
205
+ # The person that authorized the scan<br/>
206
+ # It will be added to the HTTP "user-agent" and "from" headers.
207
+ #
208
+ # @return [String]
209
+ #
210
+ attr_accessor :authed_by
211
+
212
+ #
213
+ # The address of the proxy server
214
+ #
215
+ # @return [String]
216
+ #
217
+ attr_accessor :proxy_addr
218
+
219
+ #
220
+ # The port to connect on the proxy server
221
+ #
222
+ # @return [String]
223
+ #
224
+ attr_accessor :proxy_port
225
+
226
+ #
227
+ # The proxy password
228
+ #
229
+ # @return [String]
230
+ #
231
+ attr_accessor :proxy_pass
232
+
233
+ #
234
+ # The proxy user
235
+ #
236
+ # @return [String]
237
+ #
238
+ attr_accessor :proxy_user
239
+
240
+ #
241
+ # The proxy type
242
+ #
243
+ # @return [String] [http, socks]
244
+ #
245
+ attr_accessor :proxy_type
246
+
247
+ #
248
+ # To be populated by the framework
249
+ #
250
+ # Parsed cookiejar cookies
251
+ #
252
+ # @return [Hash] name=>value pairs
253
+ #
254
+ attr_accessor :cookies
255
+
256
+ #
257
+ # Location of the cookiejar
258
+ #
259
+ # @return [String]
260
+ #
261
+ attr_accessor :cookie_jar
262
+
263
+ #
264
+ # The HTTP user-agent to use
265
+ #
266
+ # @return [String]
267
+ #
268
+ attr_accessor :user_agent
269
+
270
+ #
271
+ # Exclude filters <br/>
272
+ # URL matching any of these patterns won't be followed
273
+ #
274
+ # @return [Array]
275
+ #
276
+ attr_accessor :exclude
277
+
278
+ #
279
+ # Cookies to exclude from audit<br/>
280
+ #
281
+ # @return [Array]
282
+ #
283
+ attr_accessor :exclude_cookies
284
+
285
+ #
286
+ # Include filters <br/>
287
+ # Only URLs that match any of these patterns will be followed
288
+ #
289
+ # @return [Array]
290
+ #
291
+ attr_accessor :include
292
+
293
+ #
294
+ # Should the crawler follow subdomains?
295
+ #
296
+ # @return [Bool]
297
+ #
298
+ attr_accessor :follow_subdomains
299
+
300
+ #
301
+ # Harvest the HTTP responses for the whole site at the end or
302
+ # for each page?
303
+ #
304
+ # @return [Bool]
305
+ #
306
+ attr_accessor :http_harvest_last
307
+
308
+ # to be populated by the framework
309
+ attr_accessor :start_datetime
310
+ # to be populated by the framework
311
+ attr_accessor :finish_datetime
312
+ # to be populated by the framework
313
+ attr_accessor :delta_time
314
+
315
+ attr_accessor :lsplug
316
+ attr_accessor :plugins
317
+
318
+ attr_accessor :spider_first
319
+
320
+ attr_accessor :rpc_port
321
+ attr_accessor :ssl
322
+ attr_accessor :ssl_pkey
323
+ attr_accessor :ssl_cert
324
+ attr_accessor :ssl_ca
325
+
326
+ attr_accessor :server
327
+
328
+ attr_accessor :reroute_to_logfile
329
+ attr_accessor :pool_size
330
+
331
+
332
+ def initialize( )
333
+
334
+ # nil everything out
335
+ self.instance_variables.each {
336
+ |var|
337
+ instance_variable_set( var.to_s, nil )
338
+ }
339
+
340
+ @exclude = []
341
+ @include = []
342
+ @redundant = []
343
+
344
+ @reports = {}
345
+ @lsrep = []
346
+
347
+ @lsmod = []
348
+ @dir = Hash.new
349
+ @exclude_cookies = []
350
+ @load_profile = []
351
+
352
+ @plugins = {}
353
+ @lsplug = []
354
+
355
+ # set some defaults
356
+ @redirect_limit = 20
357
+
358
+ # relatively low but will give good performance without bottleneck
359
+ # on low bandwidth conections
360
+ @http_req_limit = 20
361
+
362
+ end
363
+
364
+ #
365
+ # Saves 'self' to file
366
+ #
367
+ # @param [String] file
368
+ #
369
+ def save( file )
370
+
371
+ dir = @dir.clone
372
+ load_profile = @load_profile.clone if @load_profile
373
+ save_profile = @save_profile.clone if @save_profile
374
+ authed_by = @authed_by.clone if @authed_by
375
+
376
+ @dir = nil
377
+ @load_profile = nil
378
+ @save_profile = nil
379
+ @authed_by = nil
380
+
381
+ begin
382
+ f = File.open( file + PROFILE_EXT, 'w' )
383
+ YAML.dump( self, f )
384
+ rescue
385
+ return
386
+ ensure
387
+ f.close
388
+
389
+ @dir = dir
390
+ @load_profile = load_profile
391
+ @save_profile = save_profile
392
+ @authed_by = authed_by
393
+ end
394
+
395
+ return f.path
396
+ end
397
+
398
+ def url=( str )
399
+ return if !str
400
+
401
+ require 'uri'
402
+ require self.dir['lib'] + 'exceptions'
403
+ require self.dir['lib'] + 'module/utilities'
404
+
405
+ begin
406
+ @url = URI( Arachni::Module::Utilities.normalize_url( str.to_s ) )
407
+ rescue
408
+ raise( Arachni::Exceptions::InvalidURL, "Invalid URL argument." )
409
+ end
410
+
411
+ return str
412
+ end
413
+
414
+ #
415
+ # Converts the Options object to hash
416
+ #
417
+ # @return [Hash]
418
+ #
419
+ def to_h
420
+ hash = Hash.new
421
+ self.instance_variables.each {
422
+ |var|
423
+ hash[normalize_name( var )] = self.instance_variable_get( var )
424
+ }
425
+ hash
426
+ end
427
+
428
+ #
429
+ # Merges self with the object in 'options'
430
+ #
431
+ # @param [Options]
432
+ #
433
+ def merge!( options )
434
+ options.to_h.each_pair {
435
+ |k, v|
436
+
437
+ next if ( v.is_a?( Array ) || v.is_a?( Hash ) ) && v.empty?
438
+ send( "#{k}=", v ) if v
439
+ }
440
+ end
441
+
442
+ def to_args
443
+
444
+ cli_args = ''
445
+
446
+ self.to_h.keys.each {
447
+ |key|
448
+
449
+ arg = self.to_arg( key )
450
+
451
+ cli_args += " #{arg.to_s}" if arg
452
+ }
453
+
454
+ return cli_args += " #{self.url}"
455
+ end
456
+
457
+ def to_arg( key )
458
+
459
+ var = self.instance_variable_get( "@#{key}" )
460
+
461
+ return if !var
462
+ return if ( var.is_a?( Array ) || var.is_a?( Hash ) ) && var.empty?
463
+ return if key == 'show_profile'
464
+ return if key == 'url'
465
+ return if key == 'dir'
466
+ return if key == 'include' && var == [/.*/]
467
+ return if key == 'reports' && var == ['stdout']
468
+
469
+ key = 'exclude_cookie' if key == 'exclude_cookies'
470
+ key = 'report' if key == 'reports'
471
+
472
+ key = key.gsub( '_', '-' )
473
+
474
+ arg = ''
475
+
476
+ case key
477
+
478
+ when 'mods'
479
+ var = var.join( ',' )
480
+
481
+ when 'arachni-verbose'
482
+ key = 'verbosity'
483
+
484
+ when 'redundant'
485
+ var.each {
486
+ |rule|
487
+ arg += " --#{key}=#{rule['regexp'].source}:#{rule['count']}"
488
+ }
489
+ return arg
490
+
491
+ when 'plugins','report'
492
+ arg = ''
493
+ var.each {
494
+ |opt, val|
495
+ arg += " --#{key.chomp( 's' )}=#{opt}"
496
+ arg += ':' if !val.empty?
497
+
498
+ val.each {
499
+ |k, v|
500
+ arg += "#{k}=#{v},"
501
+ }
502
+
503
+ arg.chomp!( ',' )
504
+ }
505
+ return arg
506
+
507
+ when 'proxy-port'
508
+ return
509
+
510
+ when 'proxy-addr'
511
+ return "--proxy=#{self.proxy_addr}:#{self.proxy_port}"
512
+
513
+
514
+ end
515
+
516
+ if( var.is_a?( TrueClass ) )
517
+ arg = "--#{key}"
518
+ end
519
+
520
+ if( var.is_a?( String ) || var.is_a?( Fixnum ) )
521
+ arg = "--#{key}=#{var.to_s}"
522
+ end
523
+
524
+ if( var.is_a?( Array ) )
525
+
526
+ var.each {
527
+ |i|
528
+
529
+ i = i.source if i.is_a?( Regexp )
530
+
531
+ arg += " --#{key}=#{i}"
532
+ }
533
+
534
+ end
535
+
536
+ return arg
537
+ end
538
+
539
+ private
540
+
541
+ def normalize_name( name )
542
+ name.to_s.gsub( '@', '' )
543
+ end
544
+
545
+
546
+ end
547
+ end