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.
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,204 @@
1
+ require 'xmlrpc/client'
2
+ require 'openssl'
3
+ require 'terminal-table/import'
4
+
5
+ module Arachni
6
+
7
+ require Options.instance.dir['lib'] + 'rpc/xml/client/dispatcher'
8
+ require Options.instance.dir['lib'] + 'ui/cli/output'
9
+
10
+ module UI
11
+
12
+ #
13
+ #
14
+ # @author: Tasos "Zapotek" Laskos
15
+ # <tasos.laskos@gmail.com>
16
+ # <zapotek@segfault.gr>
17
+ # @version: 0.1.2
18
+ #
19
+ class DispatcherMonitor
20
+
21
+ include Arachni::UI::Output
22
+
23
+ def initialize( opts )
24
+
25
+ @opts = opts
26
+
27
+ debug! if @opts.debug
28
+
29
+ # print banner message
30
+ banner
31
+
32
+ # if the user needs help, output it and exit
33
+ if opts.help
34
+ usage
35
+ exit 0
36
+ end
37
+
38
+ begin
39
+ # start the XMLRPC client
40
+ @dispatcher = Arachni::RPC::XML::Client::Dispatcher.new( @opts, @opts.url.to_s )
41
+
42
+ # it seems like the XMLRPC client will connect us on the first
43
+ # call...so make sure that it *can* actually connect
44
+ @dispatcher.jobs
45
+ rescue Exception => e
46
+ print_error( "Could not connect to server." )
47
+ print_error( "Error: #{e.to_s}." )
48
+ print_debug_backtrace( e )
49
+ exit 0
50
+ end
51
+
52
+ # trap interupts and exit cleanly when required
53
+ trap( 'HUP' ) { exit 0 }
54
+ trap( 'INT' ) { exit 0 }
55
+
56
+ end
57
+
58
+ def run
59
+
60
+ print_line
61
+
62
+ # grab the XMLRPC server output while a scan is running
63
+ while( 1 )
64
+ stats = @dispatcher.stats
65
+ running_jobs = stats['running_jobs']
66
+ clear_screen
67
+
68
+ banner
69
+ print_stats( stats )
70
+
71
+ print_line
72
+
73
+ print_job_table( running_jobs )
74
+
75
+ # things will get crazy if we don't block a bit I think...
76
+ # we'll see...
77
+ ::IO::select( nil, nil, nil, 1 )
78
+ end
79
+
80
+ end
81
+
82
+ private
83
+
84
+ def print_job_table( jobs )
85
+
86
+ headings = [ 'Parent PID', 'PID', 'Port', 'Owner', 'Birthdate (Server-side)',
87
+ 'Start time (Server-side)', 'Current time (Server-side)', 'Age',
88
+ 'Run-time', 'Memory', 'Priority', 'State' ]
89
+
90
+ rows = []
91
+ jobs.each {
92
+ |job|
93
+ rows << [ job['proc']['ppid'], job['pid'], job['port'], job['owner'],
94
+ job['birthdate'].to_time, job['starttime'].to_time, job['currtime'].to_time,
95
+ secs_to_hms( job['age'] ), secs_to_hms( job['runtime'] ),
96
+ proc_mem( job['proc']['rss'] ), job['proc']['priority'],
97
+ proc_state( job['proc']['state'] ) ]
98
+ }
99
+
100
+ return if rows.empty?
101
+
102
+ print_line( table( headings, *rows ) )
103
+ end
104
+
105
+ def print_stats( stats )
106
+ print_info( 'Number of finished instances: ' + stats['finished_jobs'].size.to_s )
107
+ print_info( 'Number of running instances: ' + stats['running_jobs'].size.to_s )
108
+ print_info( 'Initial pool size: ' + stats['init_pool_size'].to_s )
109
+ print_info( 'Current pool size: ' + stats['curr_pool_size'].to_s )
110
+ end
111
+
112
+ def clear_screen
113
+ puts "\e[H\e[2J"
114
+ end
115
+
116
+ def proc_mem( rss )
117
+ # we assume a page size of 4096
118
+ (rss.to_i * 4096 / 1024 / 1024).to_s + 'MB'
119
+ end
120
+
121
+ def proc_state( state )
122
+ case state
123
+ when 'S'
124
+ return 'Sleeping'
125
+
126
+ when 'D'
127
+ return 'Disk Sleep'
128
+
129
+ when 'Z'
130
+ return 'Zombie'
131
+
132
+ when 'T'
133
+ return 'Traced/Stoped'
134
+
135
+ when 'W'
136
+ return 'Paging'
137
+ end
138
+ end
139
+
140
+ def secs_to_hms( secs )
141
+ secs = secs.to_i
142
+ return [secs/3600, secs/60 % 60, secs % 60].map {
143
+ |t|
144
+ t.to_s.rjust( 2, '0' )
145
+ }.join(':')
146
+ end
147
+
148
+
149
+ #
150
+ # Outputs Arachni banner.<br/>
151
+ # Displays version number, revision number, author details etc.
152
+ #
153
+ # @see VERSION
154
+ # @see REVISION
155
+ #
156
+ # @return [void]
157
+ #
158
+ def banner
159
+ print_line 'Arachni - Web Application Security Scanner Framework
160
+ Author: Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
161
+ <zapotek@segfault.gr>
162
+ (With the support of the community and the Arachni Team.)
163
+
164
+ Website: http://github.com/Zapotek/arachni
165
+ Documentation: http://github.com/Zapotek/arachni/wiki'
166
+ print_line
167
+ print_line
168
+
169
+ end
170
+
171
+ #
172
+ # Outputs help/usage information.<br/>
173
+ # Displays supported options and parameters.
174
+ #
175
+ # @return [void]
176
+ #
177
+ def usage
178
+ print_line <<USAGE
179
+ Usage: arachni_xmlrpcd_monitor [server address]
180
+
181
+ Supported options:
182
+
183
+
184
+ SSL --------------------------
185
+
186
+ --ssl use SSL?
187
+ (If you want encryption without authentication
188
+ you can skip rest of the SSL options.)
189
+
190
+ --ssl-pkey <file> location of the SSL private key (.pem)
191
+ (Used to verify the the client to the servers.)
192
+
193
+ --ssl-cert <file> location of the SSL certificate (.pem)
194
+ (Used to verify the the client to the servers.)
195
+
196
+ --ssl-ca <file> location of the CA certificate (.pem)
197
+ (Used to verify the servers to the client.)
198
+ USAGE
199
+ end
200
+
201
+ end
202
+
203
+ end
204
+ end
@@ -0,0 +1,843 @@
1
+ require 'xmlrpc/client'
2
+ require 'openssl'
3
+
4
+ module Arachni
5
+
6
+ require Options.instance.dir['lib'] + 'rpc/xml/client/dispatcher'
7
+ require Options.instance.dir['lib'] + 'rpc/xml/client/instance'
8
+
9
+ require Options.instance.dir['lib'] + 'module/utilities'
10
+ require Options.instance.dir['lib'] + 'ui/cli/output'
11
+ require Options.instance.dir['lib'] + 'framework'
12
+
13
+ module UI
14
+
15
+ #
16
+ # Arachni::UI:XMLRPC class
17
+ #
18
+ # Provides an self sufficient Arachni XML-RPC client.
19
+ #
20
+ # It mimics the standard CLI interface's functionality
21
+ # albeit in a client-server fashion.
22
+ #
23
+ # This should be your first stop when looking into creating your own XMLRPC client. <br/>
24
+ # Of course you don't need to instantiate the framework or any other Arachni related classes
25
+ # in your own client, this is just to provide some other info to the user.
26
+ #
27
+ #
28
+ # @author: Tasos "Zapotek" Laskos
29
+ # <tasos.laskos@gmail.com>
30
+ # <zapotek@segfault.gr>
31
+ # @version: 0.1.2
32
+ #
33
+ class XMLRPC
34
+
35
+ include Arachni::UI::Output
36
+ include Arachni::Module::Utilities
37
+
38
+ def initialize( opts )
39
+
40
+ @opts = opts
41
+
42
+ # if we have a load profile load it and merge it with the
43
+ # user supplied options
44
+ if( @opts.load_profile )
45
+ load_profile( @opts.load_profile )
46
+ end
47
+
48
+ debug! if @opts.debug
49
+
50
+ # we don't need the framework for much,
51
+ # in this case only for report generation, version number etc.
52
+ @framework = Arachni::Framework.new( @opts )
53
+
54
+ # print banner message
55
+ banner
56
+
57
+ # if the user needs help, output it and exit
58
+ if opts.help
59
+ usage
60
+ exit 0
61
+ end
62
+
63
+ # if the user wants to see the available reports, output them and exit
64
+ if !opts.lsrep.empty?
65
+ lsrep
66
+ exit
67
+ end
68
+
69
+ if opts.show_profile
70
+ print_profile( )
71
+ exit 0
72
+ end
73
+
74
+ if opts.save_profile
75
+ exception_jail{ save_profile( opts.save_profile ) }
76
+ exit 0
77
+ end
78
+
79
+
80
+ # Check for missing url
81
+ if( !@opts.url && !@opts.lsmod )
82
+ print_error( "Missing url argument." )
83
+ exit 0
84
+ end
85
+
86
+ begin
87
+
88
+ @dispatcher = Arachni::RPC::XML::Client::Dispatcher.new( @opts, @opts.server )
89
+
90
+ # get a new instance and assign the url we're going to audit as the
91
+ # 'owner'
92
+ @instance = @dispatcher.dispatch( @opts.url.to_s )
93
+
94
+ instance_url = URI( @opts.server.to_s )
95
+ instance_url.port = @instance['port']
96
+
97
+ # start the XMLRPC client
98
+ @server = Arachni::RPC::XML::Client::Instance.new( @opts, instance_url.to_s )
99
+ rescue Exception => e
100
+ print_error( "Could not connect to server." )
101
+ print_error( "Error: #{e.to_s}." )
102
+ print_debug_backtrace( e )
103
+ exit 0
104
+ end
105
+
106
+ # if the user wants to see the available reports, output them and exit
107
+ if !opts.lsplug.empty?
108
+ lsplug( @server.framework.lsplug )
109
+ shutdown
110
+ exit
111
+ end
112
+
113
+ # if the user wants to see the available modules
114
+ # grab them from the server, output them, exit and shutdown the server.
115
+ if !opts.lsmod.empty?
116
+ lsmod( @server.framework.lsmod )
117
+ shutdown
118
+ exit
119
+ end
120
+
121
+ #
122
+ # we could just execute pause() upon an interrupt but XMLRPC I/O
123
+ # needs to be synchronized otherwise we'll get an HTTP exception
124
+ #
125
+ @pause = false
126
+ trap( 'INT' ){ @pause = true }
127
+
128
+ begin
129
+ parse_opts
130
+ rescue Exception => e
131
+ print_error( 'Error: ' + e.to_s )
132
+ print_debug_backtrace( e )
133
+ begin
134
+ shutdown
135
+ rescue
136
+ end
137
+ exit
138
+ end
139
+ end
140
+
141
+ def run
142
+
143
+ exception_jail {
144
+ print_status 'Running framework...'
145
+ @server.framework.run
146
+
147
+ print_line
148
+
149
+ # grab the XMLRPC server output while a scan is running
150
+ while( @server.framework.busy? )
151
+ output
152
+
153
+ pause if @pause
154
+
155
+ # things will get crazy if we don't block a bit I think...
156
+ # we'll see...
157
+ ::IO::select( nil, nil, nil, 0.3 )
158
+ end
159
+
160
+ puts
161
+ }
162
+
163
+ report
164
+ shutdown
165
+ end
166
+
167
+ private
168
+
169
+ #
170
+ # Loads an Arachni Framework Profile file and merges it with the
171
+ # user supplied options.
172
+ #
173
+ # @param [String] filename the file to load
174
+ #
175
+ def load_profile( profiles )
176
+ exception_jail{
177
+ @opts.load_profile = nil
178
+ profiles.each {
179
+ |filename|
180
+ @opts.merge!( YAML::load( IO.read( filename ) ) )
181
+ }
182
+ }
183
+ end
184
+
185
+ #
186
+ # Saves options to an Arachni Framework Profile file.<br/>
187
+ # The file will be appended with the {PROFILE_EXT} extension.
188
+ #
189
+ # @param [String] filename
190
+ #
191
+ def save_profile( filename )
192
+
193
+ if filename = @opts.save( filename )
194
+ print_status( "Saved profile in '#{filename}'." )
195
+ print_line( )
196
+ else
197
+ banner( )
198
+ print_error( 'Could not save profile.' )
199
+ exit 0
200
+ end
201
+ end
202
+
203
+ #
204
+ # Grabs the output from the XMLRPC server and routes it to the proper output method.
205
+ #
206
+ def output
207
+ @server.service.output.each {
208
+ |out|
209
+ type = out.keys[0]
210
+ msg = out.values[0]
211
+ begin
212
+ self.send( "print_#{type}", msg )
213
+ rescue
214
+ print_line( msg )
215
+ end
216
+ }
217
+ end
218
+
219
+ #
220
+ # Handles Ctrl+C interrupts
221
+ #
222
+ # Once an interrupt has been trapped the system pauses and waits
223
+ # for user input. <br/>
224
+ # The user can either continue or exit.
225
+ #
226
+ # The interrupt will be handled after a module has finished.
227
+ #
228
+ def pause( )
229
+
230
+ print_status( 'Paused...' )
231
+ @server.framework.pause!
232
+
233
+ print_line
234
+ print_info( 'Results thus far:' )
235
+
236
+ #
237
+ # make it easier on the user, grab the report to have something
238
+ # to show him while the scan is paused.
239
+ #
240
+ begin
241
+ print_issues( YAML.load( @server.framework.report ) )
242
+ rescue Exception => e
243
+ exception_jail{ raise e }
244
+ exit 0
245
+ end
246
+
247
+ print_info( 'Arachni was interrupted,' +
248
+ ' do you want to continue?' )
249
+
250
+ print_info( 'Continue? (hit \'enter\' to continue, \'e\' to exit)' )
251
+
252
+ if gets[0] == 'e'
253
+ print_status( 'Aborting scan...' )
254
+ @server.framework.abort!
255
+ report
256
+ shutdown
257
+ print_info( 'Exiting...' )
258
+ exit 0
259
+ end
260
+
261
+ @pause = false
262
+ @server.framework.resume!
263
+
264
+ end
265
+
266
+ #
267
+ # Laconically output the discovered issues
268
+ #
269
+ # This method is used during a pause.
270
+ #
271
+ def print_issues( audit_store )
272
+
273
+ print_line( )
274
+ print_info( audit_store['issues'].size.to_s +
275
+ ' issues have been detected.' )
276
+
277
+ print_line( )
278
+ audit_store['issues'].each {
279
+ |issue|
280
+
281
+ print_ok( "#{issue['name']} (In #{issue['elem']} variable '#{issue['var']}'" +
282
+ " - Severity: #{issue['severity']} - Variations: #{issue['variations'].size.to_s})" )
283
+
284
+ print_info( issue['variations'][0]['url'] )
285
+
286
+ print_line( )
287
+ }
288
+
289
+ print_line( )
290
+
291
+ end
292
+
293
+ #
294
+ # Parses, sets and sends options to the XMLRPC server.
295
+ #
296
+ def parse_opts
297
+
298
+ #
299
+ # No modules have been specified, set the mods to '*' (all).
300
+ #
301
+ if( !@opts.mods || @opts.mods.empty? )
302
+ print_info( "No modules were specified." )
303
+ print_info( " -> Will run all mods." )
304
+
305
+ @opts.mods = ['*']
306
+ end
307
+
308
+ #
309
+ # The user hasn't selected any elements to audit, set it to audit links, forms and cookies.
310
+ #
311
+ if( !@opts.audit_links &&
312
+ !@opts.audit_forms &&
313
+ !@opts.audit_cookies &&
314
+ !@opts.audit_headers
315
+ )
316
+ print_info( "No audit options were specified." )
317
+ print_info( " -> Will audit links, forms and cookies." )
318
+
319
+ @opts.audit_links = true
320
+ @opts.audit_forms = true
321
+ @opts.audit_cookies = true
322
+ end
323
+
324
+ # do not send these options over the wire
325
+ illegal = [
326
+ # this is bad, do not override the server's directory structure
327
+ 'dir',
328
+
329
+ # this is of no use to the server is a local option for this UI
330
+ 'server',
331
+
332
+ # profiles are not to be sent over the wire
333
+ 'load_profile',
334
+
335
+ # report options should remain local
336
+ # If you send this to the server it will cause a Ruby segfault.
337
+ 'repopts',
338
+ 'repsave',
339
+
340
+ # do not automatically send this options over
341
+ # we'll take care of this ourselves as soon as we get to the 'cookie_jar'
342
+ # option.
343
+ 'cookies'
344
+ ]
345
+
346
+ @server.plugins.load(
347
+ {
348
+ 'content_types' => {},
349
+ 'healthmap' => {},
350
+ 'metamodules' => {},
351
+ }
352
+ )
353
+ @opts.to_h.each {
354
+ |opt, arg|
355
+
356
+ next if !arg
357
+ next if illegal.include? opt
358
+
359
+ case opt
360
+
361
+ when "arachni_verbose"
362
+ print_status "Enabling verbosity."
363
+ verbose!
364
+ @server.framework.verbose_on
365
+
366
+ when 'redundant'
367
+ print_status 'Setting redundancy rules.'
368
+
369
+ redundant = []
370
+ arg.each {
371
+ |rule|
372
+ rule['regexp'] = rule['regexp'].to_s
373
+ redundant << rule
374
+ }
375
+ @server.opts.redundant( redundant )
376
+
377
+ when 'exclude', 'include'
378
+ print_status "Setting #{opt} rules."
379
+ @server.call( "opts.#{opt}=", arg.map{ |rule| rule.to_s } )
380
+
381
+ when 'url'
382
+ print_status 'Setting url: ' + @server.call( "opts.url=", arg.to_s )
383
+
384
+ when 'cookie_jar'
385
+ print_status 'Setting cookies:'
386
+ @server.opts.cookies( parse_cookie_jar( arg ) ).each_pair {
387
+ |k, v|
388
+ print_info ' * ' + k + ' => ' + v
389
+ }
390
+
391
+ when 'mods'
392
+ print_status 'Loading modules:'
393
+ @server.modules.load( arg ).each {
394
+ |mod|
395
+ print_info ' * ' + mod
396
+ }
397
+
398
+ when 'plugins'
399
+ next if arg.empty?
400
+
401
+ ap arg
402
+ print_status 'Loading plug-ins:'
403
+ @server.plugins.load( arg ).each {
404
+ |mod|
405
+ print_info ' * ' + mod
406
+ }
407
+
408
+ when "http_req_limit"
409
+ print_status 'Setting HTTP request limit: ' +
410
+ @server.opts.http_req_limit( arg ).to_s
411
+
412
+ when 'reports'
413
+ arg['stdout'] = {}
414
+ exception_jail{ @framework.reports.load( arg.keys ) }
415
+
416
+ else
417
+ print_status "Setting #{opt}."
418
+ @server.call( "opts.#{opt}=", arg )
419
+
420
+ end
421
+ }
422
+
423
+ end
424
+
425
+ #
426
+ # Remote kill-switch, shuts down the server
427
+ #
428
+ def shutdown
429
+ print_status "Shutting down the server..."
430
+ @server.service.shutdown
431
+ end
432
+
433
+ #
434
+ # Grabs the report from the XMLRPC server and runs the selected Arachni report module.
435
+ #
436
+ def report
437
+ print_status "Grabbing scan report..."
438
+
439
+ # this will return the AuditStore as a hash
440
+ # ap @server.call( "framework.report" )
441
+
442
+ # this will return the AuditStore as a string in YAML format
443
+ audit_store = YAML.load( @server.framework.auditstore )
444
+
445
+ # run the loaded reports and get the generated filename
446
+ @framework.reports.run( audit_store )
447
+
448
+ print_status "Grabbing stats..."
449
+
450
+ stats = @server.framework.stats
451
+ print_line
452
+ print_info( "Sent #{stats['requests']} requests." )
453
+ print_info( "Received and analyzed #{stats['responses']} responses." )
454
+ print_info( 'In ' + stats['time'] )
455
+
456
+ avg = 'Average: ' + stats['avg'] + ' requests/second.'
457
+ print_info( avg )
458
+
459
+ print_line
460
+
461
+ end
462
+
463
+ def parse_cookie_jar( jar )
464
+ # make sure that the provided cookie-jar file exists
465
+ if !File.exist?( jar )
466
+ raise( Arachni::Exceptions::NoCookieJar,
467
+ 'Cookie-jar \'' + jar + '\' doesn\'t exist.' )
468
+ end
469
+
470
+ return Arachni::Module::HTTP.parse_cookiejar( jar )
471
+ end
472
+
473
+ #
474
+ # Outputs all available modules and their info.
475
+ #
476
+ def lsmod( mods )
477
+
478
+ i = 0
479
+ print_info( 'Available modules:' )
480
+ print_line
481
+
482
+ mods.each {
483
+ |info|
484
+
485
+ print_status( "#{info['mod_name']}:" )
486
+ print_line( "--------------------" )
487
+
488
+ print_line( "Name:\t\t" + info['name'] )
489
+ print_line( "Description:\t" + info['description'] )
490
+
491
+ if( info['elements'] && info['elements'].size > 0 )
492
+ print_line( "Elements:\t" +
493
+ info['elements'].join( ', ' ).downcase )
494
+ end
495
+
496
+ if( info['dependencies'] )
497
+ print_line( "Dependencies:\t" +
498
+ info['dependencies'].join( ', ' ).downcase )
499
+ end
500
+
501
+ print_line( "Author:\t\t" + info['author'] )
502
+ print_line( "Version:\t" + info['version'] )
503
+
504
+ print_line( "References:" )
505
+ if info['references'].is_a?( Hash )
506
+ info['references'].keys.each {
507
+ |key|
508
+ print_info( key + "\t\t" + info['references'][key] )
509
+ }
510
+ end
511
+
512
+ print_line( "Targets:" )
513
+ info['targets'].keys.each {
514
+ |key|
515
+ print_info( key + "\t\t" + info['targets'][key] )
516
+ }
517
+
518
+ if( info['issue'] &&
519
+ ( sploit = info['issue']['metasploitable'] ) )
520
+ print_line( "Metasploitable:\t" + sploit )
521
+ end
522
+
523
+ print_line( "Path:\t" + info['path'] )
524
+
525
+ i+=1
526
+
527
+ # pause every 3 modules to give the user time to read
528
+ # (cheers to aungkhant@yehg.net for suggesting it)
529
+ if( i % 3 == 0 && i != mods.size )
530
+ print_line
531
+ print_line( 'Hit <space> <enter> to continue, any other key to exit. ' )
532
+
533
+ if gets[0] != " "
534
+ print_line
535
+ return
536
+ end
537
+
538
+ end
539
+
540
+ print_line
541
+ }
542
+
543
+ end
544
+
545
+ #
546
+ # Outputs all available reports and their info.
547
+ #
548
+ def lsrep
549
+ i = 0
550
+ print_info( 'Available reports:' )
551
+ print_line
552
+
553
+ @framework.lsrep().each {
554
+ |info|
555
+
556
+ print_status( "#{info[:rep_name]}:" )
557
+ print_line( "--------------------" )
558
+
559
+ print_line( "Name:\t\t" + info[:name] )
560
+ print_line( "Description:\t" + info[:description] )
561
+
562
+ if( info[:options] && info[:options].size > 0 )
563
+ print_line( "Options:\t" )
564
+
565
+ info[:options].each {
566
+ |option|
567
+ print_info( "\t#{option.name} - #{option.desc}" )
568
+ print_info( "\tType: #{option.type}" )
569
+ print_info( "\tDefault: #{option.default}" )
570
+ print_info( "\tRequired?: #{option.required?}" )
571
+
572
+ print_line( )
573
+ }
574
+ end
575
+
576
+ print_line( "Author:\t\t" + info[:author] )
577
+ print_line( "Version:\t" + info[:version] )
578
+ print_line( "Path:\t" + info[:path] )
579
+
580
+ i+=1
581
+
582
+ print_line
583
+ }
584
+
585
+ end
586
+
587
+ #
588
+ # Outputs all available reports and their info.
589
+ #
590
+ def lsplug( plugins )
591
+ print_line
592
+ print_line
593
+ print_info( 'Available plugins:' )
594
+ print_line
595
+
596
+ plugins.each {
597
+ |info|
598
+
599
+ print_status( "#{info['plug_name']}:" )
600
+ print_line( "--------------------" )
601
+
602
+ print_line( "Name:\t\t" + info['name'] )
603
+ print_line( "Description:\t" + info['description'] )
604
+
605
+ if( info['options'] && !info['options'].empty? )
606
+ print_line( "Options:\t" )
607
+
608
+ info['options'].each {
609
+ |option|
610
+ print_info( "\t#{option['name']} - #{option['desc']}" )
611
+ print_info( "\tType: #{option['type']}" )
612
+ print_info( "\tDefault: #{option['default']}" )
613
+ print_info( "\tRequired?: #{option['required']}" )
614
+
615
+ print_line( )
616
+ }
617
+ end
618
+
619
+ print_line( "Author:\t\t" + info['author'] )
620
+ print_line( "Version:\t" + info['version'] )
621
+ print_line( "Path:\t" + info['path'] )
622
+
623
+ print_line
624
+ }
625
+
626
+ end
627
+
628
+
629
+ #
630
+ # Outputs Arachni banner.<br/>
631
+ # Displays version number, revision number, author details etc.
632
+ #
633
+ # @see VERSION
634
+ # @see REVISION
635
+ #
636
+ # @return [void]
637
+ #
638
+ def banner
639
+ print_line 'Arachni - Web Application Security Scanner Framework v' +
640
+ @framework.version + ' [' + @framework.revision + ']
641
+ Author: Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
642
+ <zapotek@segfault.gr>
643
+ (With the support of the community and the Arachni Team.)
644
+
645
+ Website: http://github.com/Zapotek/arachni
646
+ Documentation: http://github.com/Zapotek/arachni/wiki'
647
+ print_line
648
+ print_line
649
+
650
+ end
651
+
652
+ def print_profile( )
653
+ print_info( 'Running profile:' )
654
+ print_info( @opts.to_args )
655
+ end
656
+
657
+ #
658
+ # Outputs help/usage information.<br/>
659
+ # Displays supported options and parameters.
660
+ #
661
+ # @return [void]
662
+ #
663
+ def usage
664
+ print_line <<USAGE
665
+ Usage: arachni_xmlrpc --server http[s]://host:port/ \[options\] url
666
+
667
+ Supported options:
668
+
669
+
670
+ SSL --------------------------
671
+ (Do *not* use encrypted keys!)
672
+
673
+ --ssl use SSL?
674
+ (If you want encryption without authentication
675
+ you can skip rest of the SSL options.)
676
+
677
+ --ssl-pkey <file> location of the SSL private key (.pem)
678
+ (Used to verify the the client to the servers.)
679
+
680
+ --ssl-cert <file> location of the SSL certificate (.pem)
681
+ (Used to verify the the client to the servers.)
682
+
683
+ --ssl-ca <file> location of the CA certificate (.pem)
684
+ (Used to verify the servers to the client.)
685
+
686
+
687
+ General ----------------------
688
+
689
+ -h
690
+ --help output this
691
+
692
+ -v be verbose
693
+
694
+ --debug show what is happening internally
695
+ (You should give it a shot sometime ;) )
696
+
697
+ --only-positives echo positive results *only*
698
+
699
+ --http-req-limit concurent HTTP requests limit
700
+ (Be carefull not to kill your server.)
701
+ (Default: 60)
702
+ (*NOTE*: If your scan seems unresponsive try lowering the limit.)
703
+
704
+ --http-harvest-last build up the HTTP request queue of the audit for the whole site
705
+ and harvest the HTTP responses at the end of the crawl.
706
+ (In some test cases this option has split the scan time in half.)
707
+ (Default: responses will be harvested for each page)
708
+ (*NOTE*: If you are scanning a high-end server and
709
+ you are using a powerful machine with enough bandwidth
710
+ *and* you feel dangerous you can use
711
+ this flag with an increased '--http-req-limit'
712
+ to get maximum performance out of your scan.)
713
+ (*WARNING*: When scanning large websites with hundreads
714
+ of pages this could eat up all your memory pretty quickly.)
715
+
716
+ --cookie-jar=<cookiejar> netscape HTTP cookie file, use curl to create it
717
+
718
+
719
+ --user-agent=<user agent> specify user agent
720
+
721
+ --authed-by=<who> who authorized the scan, include name and e-mail address
722
+ (It'll make it easier on the sys-admins during log reviews.)
723
+ (Will be appended to the user-agent string.)
724
+
725
+
726
+ Profiles -----------------------
727
+
728
+ --save-profile=<file> save the current run profile/options to <file>
729
+
730
+ --load-profile=<file> load a run profile from <file>
731
+ (Can be used multiple times.)
732
+ (You can complement it with more options, except for:
733
+ * --mods
734
+ * --redundant)
735
+
736
+ --show-profile will output the running profile as CLI arguments
737
+
738
+
739
+ Crawler -----------------------
740
+
741
+ -e <regex>
742
+ --exclude=<regex> exclude urls matching regex
743
+ (Can be used multiple times.)
744
+
745
+ -i <regex>
746
+ --include=<regex> include urls matching this regex only
747
+ (Can be used multiple times.)
748
+
749
+ --redundant=<regex>:<count> limit crawl on redundant pages like galleries or catalogs
750
+ (URLs matching <regex> will be crawled <count> links deep.)
751
+ (Can be used multiple times.)
752
+
753
+ -f
754
+ --follow-subdomains follow links to subdomains (default: off)
755
+
756
+ --obey-robots-txt obey robots.txt file (default: off)
757
+
758
+ --depth=<number> depth limit (default: inf)
759
+ (How deep Arachni should go into the site structure.)
760
+
761
+ --link-count=<number> how many links to follow (default: inf)
762
+
763
+ --redirect-limit=<number> how many redirects to follow (default: inf)
764
+
765
+ --spider-first spider first, audit later
766
+
767
+
768
+ Auditor ------------------------
769
+
770
+ -g
771
+ --audit-links audit link variables (GET)
772
+
773
+ -p
774
+ --audit-forms audit form variables
775
+ (usually POST, can also be GET)
776
+
777
+ -c
778
+ --audit-cookies audit cookies (COOKIE)
779
+
780
+ --exclude-cookie=<name> cookies not to audit
781
+ (You should exclude session cookies.)
782
+ (Can be used multiple times.)
783
+
784
+ --audit-headers audit HTTP headers
785
+ (*NOTE*: Header audits use brute force.
786
+ Almost all valid HTTP request headers will be audited
787
+ even if there's no indication that the web app uses them.)
788
+ (*WARNING*: Enabling this option will result in increased requests,
789
+ maybe by an order of magnitude.)
790
+
791
+
792
+ Modules ------------------------
793
+
794
+ --lsmod=<regexp> list available modules based on the provided regular expression
795
+ (If no regexp is provided all modules will be listed.)
796
+ (Can be used multiple times.)
797
+
798
+
799
+ -m <modname,modname..>
800
+ --mods=<modname,modname..> comma separated list of modules to deploy
801
+ (Use '*' as a module name to deploy all modules or inside module names like so:
802
+ xss_* to load all xss modules
803
+ sqli_* to load all sql injection modules
804
+ etc.
805
+
806
+ You can exclude modules by prefixing their name with a dash:
807
+ --mods=*,-backup_files,-xss
808
+ The above will load all modules except for the 'backup_files' and 'xss' modules.
809
+
810
+ Or mix and match:
811
+ -xss_* to unload all xss modules. )
812
+
813
+
814
+ Reports ------------------------
815
+
816
+ --lsrep list available reports
817
+
818
+ --repload=<file> load audit results from an .afr file
819
+ (Allows you to create new reports from finished scans.)
820
+
821
+ --report='<report>:<optname>=<val>,<optname2>=<val2>,...'
822
+
823
+ <report>: the name of the report as displayed by '--lsrep'
824
+ (Default: stdout)
825
+ (Can be used multiple times.)
826
+
827
+
828
+ Plugins ------------------------
829
+
830
+ --lsplug list available plugins
831
+
832
+ --plugin='<plugin>:<optname>=<val>,<optname2>=<val2>,...'
833
+
834
+ <plugin>: the name of the plugin as displayed by '--lsplug'
835
+ (Can be used multiple times.)
836
+
837
+ USAGE
838
+ end
839
+
840
+ end
841
+
842
+ end
843
+ end