#!/usr/bin/env ruby require 'bundler' require 'json' require 'terminal-table' require 'justify' require 'dawnscanner' APPNAME = File.basename($0) LIST_KNOWN_FRAMEWORK = %w(rails sinatra padrino) VALID_OUTPUT_FORMAT = %w(console json csv html) # Datamapper stuff #DataMapper.setup(:default, "sqlite3://#{Dawn::Core.registry_db_name}") #DataMapper::Logger.new(Dawn::Core.sql_log_name, :debug) #DataMapper.finalize #DataMapper.auto_upgrade! require 'logger' $logger = Logger.new(STDOUT) $logger.datetime_format = '%Y-%m-%d %H:%M:%S' engine = nil $debug=false $verbose=false options = Dawn::Core.read_conf(Dawn::Core.find_conf(true)) check = "" guess = {:name=>"", :version=>"", :connected_gems=>[]} Dawn::Cli::DawnCli.start $logger.bye Kernel.exit(0) ############################################################################### # CLI argument start. # # Refactoring is necessary here ############################################################################### begin opts.each do |opt, val| case opt when '--version' puts "#{Dawn::VERSION} [#{Dawn::CODENAME}]" Kernel.exit(0) when '--config-file' options = Dawn::Core.read_conf(val) when '--disable-cve-bulletins' options[:enabled_checks].delete(:bulletin) when '--disable-code-quality' options[:enabled_checks].delete(:code_quality) when '--disable-code-style' options[:enabled_checks].delete(:code_style) when '--disable-owasp-ror-cheatsheet' options[:enabled_checks].delete(:owasp_ror_cheatsheet) when '--disable-owasp-top-10' options[:enabled_checks].delete(:owasp_top_10_1) options[:enabled_checks].delete(:owasp_top_10_2) options[:enabled_checks].delete(:owasp_top_10_3) options[:enabled_checks].delete(:owasp_top_10_4) options[:enabled_checks].delete(:owasp_top_10_5) options[:enabled_checks].delete(:owasp_top_10_6) options[:enabled_checks].delete(:owasp_top_10_7) options[:enabled_checks].delete(:owasp_top_10_8) options[:enabled_checks].delete(:owasp_top_10_9) options[:enabled_checks].delete(:owasp_top_10_10) when '--list-known-families' printf "Dawn supports following check families:\n\n" puts Dawn::Kb::BasicCheck.families Kernel.exit(0) when '--json' options[:output] = "json" when '--console' options[:output] = "console" when '--tabular' options[:output] = "tabular" when '--ascii-tabular-report' $logger.warn "--ascii-tabular-report' it has been deprecated. It will be removed in version 2.0.0. Please use '--tabular' instead" options[:output] = "tabular" when '--html' options[:output] = "html" when '--file' options[:filename] = val when '--gem-lock' options[:gemfile_scan] = true $logger.warn "--gem-lock flag it has been deprecated. It will be removed in version 2.0.0. Please use '--dependencies' instead" unless val.empty? options[:gemfile_name] = val guess = Dawn::Core.guess_mvc(val) end when '--dependencies' options[:gemfile_scan] = true unless val.empty? options[:gemfile_name] = val guess = Dawn::Core.guess_mvc(val) end when '--verbose' options[:verbose]=true when '--count-only' options[:output] = "count" when '--debug' options[:debug] = true when '--exit-on-warn' options[:exit_on_warn] = true when '--search-knowledge-base' found = Dawn::KnowledgeBase.find(nil, val) puts "#{val} found in knowledgebase." if found puts "#{val} not found in knowledgebase" if ! found Kernel.exit(0) when '--list-scan-registry' puts "#{APPNAME} scan registry\n\n" Dawn::Registry.dump Kernel.exit(0) when '--list-knowledge-base' Dawn::KnowledgeBase.dump(options[:verbose]) Kernel.exit(0) when '--list-known-framework' puts "Ruby MVC framework supported by #{APPNAME}:" LIST_KNOWN_FRAMEWORK.each do |mvc| puts "* #{mvc}" end Kernel.exit(0) when '--help' Kernel.exit(Dawn::Core.help) end end rescue GetoptLong::InvalidOption => e $logger.helo APPNAME, Dawn::VERSION $logger.error e.message Kernel.exit(Dawn::Core.help) end ############################################################################### # CLI argument stop ############################################################################### target=ARGV.shift target = File.expand_path(".") if target == "." ## It will be migrated to active record in 2019 # r = Dawn::Registry.new # unless Dir.exist?(Dawn::Core.registry_db_folder) # FileUtils.mkdir_p(Dawn::Core.registry_db_folder) # $logger.info "#{Dawn::Core.registry_db_folder} created" if Dir.exist?(Dawn::Core.registry_db_folder) # end trap("INT") { $logger.die('[INTERRUPTED]') } $logger.die("missing target") if target.nil? && options[:gemfile_name].empty? $logger.die("invalid directory (#{target})") if options[:gemfile_name].empty? &&! Dawn::Core.is_good_target?(target) $logger.debug("security check enabled: #{options[:enabled_checks]}") if options[:debug] ## MVC auto detect. # Skipping MVC autodetect if it's already been done by guess_mvc when choosing # Gemfile.lock scan unless options[:gemfile_scan] begin engine = Dawn::Core.detect_mvc(target) $logger.debug("using #{engine.class.name} engine via autodect") if options[:debug] rescue ArgumentError => e # r.do_save({:target=>File.basename(target), :scan_started=>DateTime.now, :scan_duration => 0, :issues_found=> -1, :output_dir=> "", :message=>e.message, :scan_status=>:failed}) $logger.die(e.message) end else engine = Dawn::GemfileLock.new(target, options[:gemfile_name], guess) # if options[:gemfile_scan] end if engine.nil? $logger.error("MVC detection failure. Please open an issue at https://github.com/thesp0nge/dawnscanner/issues") # r.do_save({:target=>File.basename(target), :message=>"MVC detection failure. Please open an issue at https://github.com/thesp0nge/dawnscanner/issues", :scan_status=>:failed}) $logger.die('ruby framework auto detect failed.') end ## end MVC auto detect. if options[:exit_on_warn] Kernel.at_exit do if engine.count_vulnerabilities != 0 Kernel.exit(engine.count_vulnerabilities) end end end if options[:debug] $logger.warn "putting engine in debug mode" engine.debug = true end $logger.warn "this is a development Dawn version" if Dawn::RELEASE == "(development)" if engine.nil? # r.do_save({:target=>File.basename(target), :message=>"missing target framework option", :scan_status=>:failed}) $logger.die "missing target framework option" end if ! options[:gemfile_scan] && ! engine.can_apply? # r.do_save({:target=>File.basename(target), :message=>"nothing to do on #{target}", :scan_status=>:failed}) $logger.die "nothing to do on #{target}" end engine.load_knowledge_base(options[:enabled_checks]) ret = engine.apply_all if options[:output] == "count" STDERR.puts (ret)? engine.vulnerabilities.count : "-1" unless options[:output] == "json" STDERR.puts (ret)? {:status=>"OK", :vulnerabilities_count=>engine.count_vulnerabilities}.to_json : {:status=>"KO", :vulnerabilities_count=>-1}.to_json if options[:output] == "json" # r.do_save({:target=>engine.target, :scan_started=>engine.scan_start, :scan_duration => engine.scan_time.round(3), :issues_found=>engine.vulnerabilities.count, :output_dir=>engine.output_dir_name, :scan_status=>:completed}) $logger.bye Kernel.exit(0) end Dawn::Reporter.new({:engine=>engine, :apply_all_code=>ret, :format=>options[:output].to_sym, :filename=>options[:filename]}).report #if (r.do_save({:target=>File.basename(engine.target), # :scan_started=>engine.scan_start, # :scan_duration => engine.scan_time.round(3), # :issues_found=>engine.vulnerabilities.count, # :output_dir=>engine.output_dir_name, # :scan_status=>:completed})) # $logger.info "#{Dawn::Core.registry_db_name} updated with scan infos" #else # r.errors.each do |error| # $logger.error error # end #end