/
dawn
executable file
·168 lines (140 loc) · 5.68 KB
/
dawn
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#!/usr/bin/env ruby
require 'getoptlong'
require 'json'
require 'terminal-table'
require 'justify'
require 'codesake-commons'
require 'codesake-dawn'
APPNAME = File.basename($0)
LIST_KNOWN_FRAMEWORK = %w(rails sinatra padrino)
VALID_OUTPUT_FORMAT = %w(console json csv html)
$logger = Codesake::Commons::Logging.instance
opts = GetoptLong.new(
# report formatting options
[ '--ascii-tabular-report', '-a', GetoptLong::NO_ARGUMENT],
[ '--json', '-j', GetoptLong::NO_ARGUMENT],
[ '--html', '-H', GetoptLong::NO_ARGUMENT],
# MVC forcing
[ '--rails', '-r', GetoptLong::NO_ARGUMENT],
[ '--sinatra', '-s', GetoptLong::NO_ARGUMENT],
[ '--padrino', '-p', GetoptLong::NO_ARGUMENT],
[ '--gem-lock', '-G', GetoptLong::REQUIRED_ARGUMENT],
[ '--list-knowledgebase', '-k', GetoptLong::OPTIONAL_ARGUMENT],
[ '--count-only', '-C', GetoptLong::NO_ARGUMENT],
[ '--exit-on-warn', '-z', GetoptLong::NO_ARGUMENT],
[ '--list-known-framework', GetoptLong::NO_ARGUMENT],
[ '--list-known-families', GetoptLong::NO_ARGUMENT],
# please save output to file
[ '--file', '-F', GetoptLong::REQUIRED_ARGUMENT],
# service options
[ '--verbose', '-V', GetoptLong::NO_ARGUMENT],
[ '--debug', '-D', GetoptLong::NO_ARGUMENT],
[ '--version', '-v', GetoptLong::NO_ARGUMENT],
[ '--help', '-h', GetoptLong::NO_ARGUMENT]
)
engine = nil
options = {:verbose=>false, :output=>"console", :dump_kb=>false, :mvc=>"", :gemfile_scan=>false, :gemfile_name=>"", :filename=>nil, :debug=>false, :exit_on_warn => false}
check = ""
guess = {:name=>"", :version=>"", :connected_gems=>[]}
opts.each do |opt, val|
case opt
when '--version'
puts "#{Codesake::Dawn::VERSION} [#{Codesake::Dawn::CODENAME}]"
Kernel.exit(0)
when '--list-known-families'
puts 'here'
Kernel.exit(0)
when '--json'
options[:output] = "json"
when '--ascii-tabular-report'
options[:output] = "tabular"
when '--html'
options[:output] = "html"
when '--rails'
options[:mvc]=:rails
when '--sinatra'
options[:mvc]=:sinatra
when '--padrino'
options[:mvc]=:padrino
when '--file'
options[:filename] = val
when '--gem-lock'
options[:gemfile_scan] = true
unless val.empty?
options[:gemfile_name] = val
guess = Codesake::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 '--list-knowledgebase'
options[:dump_kb]=true
check = val unless val.nil?
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(Codesake::Dawn::Core.help)
end
end
if options[:dump_kb]
puts Codesake::Dawn::Core.dump_knowledge_base(options[:verbose]) if check.empty?
if ! check.empty?
found = Codesake::Dawn::KnowledgeBase.find(nil, check)
puts "#{check} found in knowledgebase." if found
puts "#{check} not found in knowledgebase" if ! found
end
Kernel.exit(0)
end
target=ARGV.shift
$logger.helo APPNAME, Codesake::Dawn::VERSION
trap("INT") { $logger.die('[INTERRUPTED]') }
$logger.die("missing target") if target.nil? && options[:gemfile_name].nil?
$logger.die("invalid directory (#{target})") if options[:gemfile_name].nil? &&! Codesake::Dawn::Core.is_good_target?(target)
$logger.die("if scanning Gemfile.lock file you must not force target MVC using one from -r, -s or -p flag") if ! options[:mvc].empty? && options[:gemfile_scan]
## 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 = Codesake::Dawn::Core.detect_mvc(target) if options[:mvc].empty?
rescue ArgumentError => e
$logger.die(e.message)
end
else
engine = Codesake::Dawn::GemfileLock.new(target, options[:gemfile_name], guess) # if options[:gemfile_scan]
end
engine = Codesake::Dawn::Rails.new(target) if options[:mvc] == :rails && options[:gemfile_scan].nil?
engine = Codesake::Dawn::Sinatra.new(target) if options[:mvc] == :sinatra && options[:gemfile_scan].nil?
engine = Codesake::Dawn::Padrino.new(target) if options[:mvc] == :padrino && options[:gemfile_scan].nil?
$logger.die("ruby framework auto detect failed. Please force if rails, sinatra or padrino with -r, -s or -p flags") if engine.nil?
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.die "missing target framework option" if engine.nil?
$logger.warn "this is a development Codesake::Dawn version" if Codesake::Dawn::RELEASE == "(development)"
$logger.die "nothing to do on #{target}" if ! options[:gemfile_scan] && ! engine.can_apply?
engine.load_knowledge_base
ret = engine.apply_all
if options[:output] == "count"
puts (ret)? engine.vulnerabilities.count : "-1" unless options[:output] == "json"
puts (ret)? {:status=>"OK", :vulnerabilities_count=>engine.count_vulnerabilities}.to_json : {:status=>"KO", :vulnerabilities_count=>-1}.to_json
Kernel.exit(0)
end
Codesake::Dawn::Reporter.new({:engine=>engine, :apply_all_code=>ret, :format=>options[:output].to_sym, :filename=>options[:filename]}).report
$logger.bye