dorothy2 1.2.0 → 2.0.0
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.
- checksums.yaml +8 -8
- data/CHANGELOG +39 -14
- data/README.md +80 -62
- data/UPDATE +6 -14
- data/bin/dorothy2 +472 -0
- data/dorothy2.gemspec +22 -16
- data/etc/ddl/dorothive.ddl +619 -373
- data/etc/sources.yml.example +27 -2
- data/lib/doroGUI.rb +232 -0
- data/lib/doroParser.rb +34 -78
- data/lib/dorothy2.rb +288 -248
- data/lib/dorothy2/BFM.rb +114 -61
- data/lib/dorothy2/DEM.rb +3 -1
- data/lib/dorothy2/NAM.rb +2 -2
- data/lib/dorothy2/Settings.rb +2 -1
- data/lib/dorothy2/VSM.rb +2 -1
- data/lib/dorothy2/deep_symbolize.rb +2 -7
- data/lib/dorothy2/do-init.rb +286 -19
- data/lib/dorothy2/do-logger.rb +1 -1
- data/lib/dorothy2/do-utils.rb +382 -33
- data/lib/dorothy2/version.rb +1 -1
- data/lib/dorothy2/vtotal.rb +30 -20
- data/lib/mu/xtractr.rb +11 -11
- data/lib/mu/xtractr/stream.rb +1 -1
- data/lib/www/public/reset.css +153 -0
- data/lib/www/public/style.css +65 -0
- data/lib/www/views/analyses.erb +28 -0
- data/lib/www/views/email.erb +63 -0
- data/lib/www/views/flows.erb +30 -0
- data/lib/www/views/layout.erb +27 -0
- data/lib/www/views/profile.erb +49 -0
- data/lib/www/views/queue.erb +28 -0
- data/lib/www/views/resume.erb +135 -0
- data/lib/www/views/resume.erb~ +88 -0
- data/lib/www/views/samples.erb +20 -0
- data/lib/www/views/upload.erb +154 -0
- data/share/img/The_big_picture.pdf +0 -0
- data/test/tc_dorothy_full.rb +3 -0
- metadata +169 -70
- data/TODO +0 -27
- data/bin/dorothy_start +0 -225
- data/bin/dorothy_stop +0 -28
- data/bin/dparser_start +0 -94
- data/bin/dparser_stop +0 -31
- data/etc/dorothy copy.yml.example +0 -39
- data/etc/extensions.yml +0 -41
- data/share/update-dorothive.sql +0 -19
data/lib/dorothy2/do-logger.rb
CHANGED
data/lib/dorothy2/do-utils.rb
CHANGED
@@ -14,10 +14,83 @@ module Dorothy
|
|
14
14
|
File.open(file , 'w') {|f| f.write(string) }
|
15
15
|
end
|
16
16
|
|
17
|
+
def get_time(local=Time.new)
|
18
|
+
time = local
|
19
|
+
case local.class.to_s
|
20
|
+
when 'Time'
|
21
|
+
time.utc.strftime("%Y-%m-%d %H:%M:%S")
|
22
|
+
when 'DateTime'
|
23
|
+
time.strftime("%Y-%m-%d %H:%M:%S")
|
24
|
+
else
|
25
|
+
time
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
17
29
|
def exists?(file)
|
18
30
|
File.exist?(file)
|
19
31
|
end
|
20
32
|
|
33
|
+
|
34
|
+
def load_profile(p_name)
|
35
|
+
p = YAML.load_file(DoroSettings.env[:home] + '/etc/profiles.yml').select {|k| k == p_name}.first
|
36
|
+
|
37
|
+
if p.nil?
|
38
|
+
LOGGER.warn "PROFILE", "Warning, the profile specified (#{p_name}) doesn't exist in profiles.yml. Skipping"
|
39
|
+
false
|
40
|
+
else
|
41
|
+
p
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
def check_pid_file(file)
|
47
|
+
if File.exist? file
|
48
|
+
# If we get Errno::ESRCH then process does not exist and
|
49
|
+
# we can safely cleanup the pid file.
|
50
|
+
pid = File.read(file).to_i
|
51
|
+
begin
|
52
|
+
Process.kill(0, pid)
|
53
|
+
rescue Errno::ESRCH
|
54
|
+
stale_pid = true
|
55
|
+
end
|
56
|
+
|
57
|
+
unless stale_pid
|
58
|
+
puts "[" + "+".red + "] " + "[Dorothy]".yellow + " Dorothy is already running (pid=#{pid})"
|
59
|
+
false
|
60
|
+
end
|
61
|
+
true
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def create_pid_file(file, pid)
|
66
|
+
File.open(file, "w") { |f| f.puts pid }
|
67
|
+
|
68
|
+
## Sends SIGTERM to process in pidfile. Server should trap this
|
69
|
+
# and shutdown cleanly.
|
70
|
+
at_exit do
|
71
|
+
if File.exist? file
|
72
|
+
File.unlink file
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def stop_process(doro_module)
|
78
|
+
|
79
|
+
pid_file = DoroSettings.env[:pidfiles] + '/' + doro_module + '.pid'
|
80
|
+
|
81
|
+
doro_module.upcase!
|
82
|
+
|
83
|
+
puts "[" + "+".red + "]" + " The #{doro_module} module is shutting now.."
|
84
|
+
|
85
|
+
if pid_file and File.exist? pid_file
|
86
|
+
pid = Integer(File.read(pid_file))
|
87
|
+
Process.kill(-2,-pid)
|
88
|
+
puts "[" + "+".red + "]" + " The #{doro_module} module (PID #{pid}) was terminated"
|
89
|
+
else
|
90
|
+
puts "[" + "+".red + "]" + "Can't find PID file, is #{doro_module} really running?"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
21
94
|
def init_db(ddl=DoroSettings.dorothive[:ddl], force=false)
|
22
95
|
LOGGER.warn "DB", "The database is going to be initialized with the file #{ddl}. If the Dorothive is already present, " + "all its data will be lost".red + ". Continue?(write yes)"
|
23
96
|
answ = "yes"
|
@@ -26,7 +99,14 @@ module Dorothy
|
|
26
99
|
if answ == "yes"
|
27
100
|
begin
|
28
101
|
#ugly, I know, but couldn't find a better and easier way..
|
29
|
-
|
102
|
+
LOGGER.info "DB", "Creating DB #{DoroSettings.dorothive[:dbname]}"
|
103
|
+
if system "sh -c 'createdb -h #{DoroSettings.dorothive[:dbhost]} -U #{DoroSettings.dorothive[:dbuser]} -e #{DoroSettings.dorothive[:dbname]} 1> /dev/null'"
|
104
|
+
LOGGER.info "DB", "Importing the dorothive DDL from #{ddl}"
|
105
|
+
system "sh -c 'psql -d #{DoroSettings.dorothive[:dbname]} -h #{DoroSettings.dorothive[:dbhost]} -U #{DoroSettings.dorothive[:dbuser]} -f #{ddl} 1> /dev/null'"
|
106
|
+
else
|
107
|
+
raise 'An error occurred'
|
108
|
+
end
|
109
|
+
|
30
110
|
LOGGER.info "DB", "Database correctly initialized. Now you can restart Dorothy!"
|
31
111
|
rescue => e
|
32
112
|
LOGGER.error "DB", $!
|
@@ -37,6 +117,7 @@ module Dorothy
|
|
37
117
|
end
|
38
118
|
end
|
39
119
|
|
120
|
+
|
40
121
|
end
|
41
122
|
|
42
123
|
module Ssh
|
@@ -50,6 +131,73 @@ module Dorothy
|
|
50
131
|
end
|
51
132
|
end
|
52
133
|
|
134
|
+
module QueueManager
|
135
|
+
extend self
|
136
|
+
|
137
|
+
def add(f, sourceinfo, profile, priority, mail_id=nil)
|
138
|
+
|
139
|
+
bin = Loadmalw.new(f)
|
140
|
+
|
141
|
+
if bin.size == 0 || bin.sha.empty?
|
142
|
+
LOGGER.warn "BFM", "Warning - Empty file #{bin.filename}, deleting and skipping.."
|
143
|
+
FileUtils.rm bin.binpath
|
144
|
+
return false
|
145
|
+
end
|
146
|
+
|
147
|
+
begin
|
148
|
+
push_malw(bin, sourceinfo, profile, priority, mail_id)
|
149
|
+
rescue => e
|
150
|
+
LOGGER.error "DB", $!
|
151
|
+
LOGGER.debug "DB", e.backtrace
|
152
|
+
raise e
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
#push the binary meta info into the DB
|
158
|
+
def push_malw(bin, sourceinfo, profile, priority, mail_id)
|
159
|
+
|
160
|
+
db = Insertdb.new
|
161
|
+
db.begin_t
|
162
|
+
|
163
|
+
unless db.select("samples", "sha256", bin.sha).one? #is bin.sha already present in my db?
|
164
|
+
samplevalues = [bin.sha, bin.size, bin.binpath_repo, bin.filename, bin.md5, bin.type ]
|
165
|
+
|
166
|
+
if db.insert("samples", samplevalues) #no it isn't, insert it
|
167
|
+
#Move the binary to the bin repo
|
168
|
+
LOGGER.debug "BFM", "Moving file from the source's directory to the Dorothy's repository"
|
169
|
+
FileUtils.mv(bin.binpath,bin.binpath_repo, :force => true)
|
170
|
+
else
|
171
|
+
raise "A DB error occurred"
|
172
|
+
end
|
173
|
+
|
174
|
+
else #yes it is, don't insert in sample table
|
175
|
+
date = db.select("sightings", "sample", bin.sha).first["date"]
|
176
|
+
LOGGER.warn "BFM", "The binary #{bin.sha} was already added on #{date}"
|
177
|
+
FileUtils.rm bin.binpath
|
178
|
+
end
|
179
|
+
|
180
|
+
|
181
|
+
#Add to sighting
|
182
|
+
sigh_id = db.get_sighting_id
|
183
|
+
sighvalues = [bin.sha, db.check_source_db(sourceinfo)["id"], bin.ctime, sigh_id, mail_id]
|
184
|
+
raise "A DB error occurred" unless db.insert("sightings", sighvalues)
|
185
|
+
|
186
|
+
# explanation: I don't want to insert the same malware twice but I do want to
|
187
|
+
# insert the sighting value anyway ("the malware X has been downloaded 1 time but
|
188
|
+
# has been spoted 32 times")
|
189
|
+
|
190
|
+
#Add to the queue
|
191
|
+
@id = db.analysis_queue_add(bin.sha, sourceinfo, bin.filename, profile, priority, nil, sigh_id )
|
192
|
+
|
193
|
+
db.commit
|
194
|
+
db.close
|
195
|
+
|
196
|
+
@id
|
197
|
+
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
53
201
|
class Insertdb
|
54
202
|
|
55
203
|
def initialize
|
@@ -87,6 +235,8 @@ module Dorothy
|
|
87
235
|
value1 = value
|
88
236
|
elsif value == "null"
|
89
237
|
value1 = value
|
238
|
+
elsif value == nil
|
239
|
+
value1 = "null"
|
90
240
|
elsif value == "lastval()"
|
91
241
|
value1 = value
|
92
242
|
elsif value =~ /currval/
|
@@ -110,9 +260,8 @@ module Dorothy
|
|
110
260
|
|
111
261
|
begin
|
112
262
|
@db.exec("INSERT into dorothy.#{table} values (#{@sqlstring})")
|
113
|
-
rescue =>
|
114
|
-
LOGGER.
|
115
|
-
LOGGER.debug "DB", e.inspect
|
263
|
+
rescue PG::Error => err
|
264
|
+
LOGGER.error "DB", err.result.error_field( PG::Result::PG_DIAG_MESSAGE_PRIMARY )
|
116
265
|
#self.rollback
|
117
266
|
return false
|
118
267
|
#exit 1
|
@@ -125,8 +274,8 @@ module Dorothy
|
|
125
274
|
def raw_insert(table, data)
|
126
275
|
begin
|
127
276
|
@db.exec("INSERT into dorothy.#{table} values (#{data})")
|
128
|
-
rescue
|
129
|
-
LOGGER.error "DB",
|
277
|
+
rescue PG::Error => err
|
278
|
+
LOGGER.error "DB", err.result.error_field( PG::Result::PG_DIAG_MESSAGE_PRIMARY )
|
130
279
|
#self.rollback
|
131
280
|
return false
|
132
281
|
#exit 1
|
@@ -144,6 +293,19 @@ module Dorothy
|
|
144
293
|
@db.exec("SELECT nextval('dorothy.analyses_id_seq')").first["nextval"].to_i
|
145
294
|
end
|
146
295
|
|
296
|
+
def get_email_id
|
297
|
+
@db.exec("SELECT nextval('dorothy.emails_id_seq')").first["nextval"].to_i
|
298
|
+
end
|
299
|
+
|
300
|
+
def get_sighting_id
|
301
|
+
@db.exec("SELECT nextval('dorothy.sightings_id_seq')").first["nextval"].to_i
|
302
|
+
end
|
303
|
+
|
304
|
+
def get_curr_queue_id
|
305
|
+
@db.exec("SELECT currval('dorothy.queue_id_seq')").first["currval"].to_i
|
306
|
+
end
|
307
|
+
|
308
|
+
|
147
309
|
def self.escape_bytea(data)
|
148
310
|
escaped = PGconn.escape_bytea data
|
149
311
|
return escaped
|
@@ -154,7 +316,7 @@ module Dorothy
|
|
154
316
|
end
|
155
317
|
|
156
318
|
def update_sample_path(sample, path)
|
157
|
-
@db.exec("UPDATE dorothy.samples set path = '#{path}' where sha256 = #{sample}")
|
319
|
+
@db.exec("UPDATE dorothy.samples set path = '#{path}' where sha256 = '#{sample}'")
|
158
320
|
end
|
159
321
|
|
160
322
|
def set_analyzed(hash)
|
@@ -174,25 +336,170 @@ module Dorothy
|
|
174
336
|
@db.exec("SELECT samples.sha256 FROM dorothy.samples").each do |q|
|
175
337
|
malwares.push q
|
176
338
|
end
|
177
|
-
|
339
|
+
malwares
|
178
340
|
end
|
179
341
|
|
342
|
+
def push_email_data(m, forwarded_by='null')
|
343
|
+
#m is a message object from the Mail class
|
344
|
+
id = get_email_id
|
345
|
+
values = " '#{m.from[0]}', E'#{m.subject}', E'#{Insertdb.escape_bytea(m.raw_source)}', '#{id}', null, null, null, null, null, '#{Util.get_time(m.date)}', '#{m.message_id}', '#{m.has_attachments?}', '#{m.charset}', '#{Digest::SHA2.hexdigest(m.body.raw_source)}', #{forwarded_by}"
|
346
|
+
raise "A DB error occurred while adding data into the emails table" unless raw_insert('emails', values)
|
347
|
+
|
348
|
+
#adding receivers
|
349
|
+
#TO
|
350
|
+
m.to_addrs.each {|addr| raise "A DB error occurred while adding data into the emails_receivers table" unless insert('email_receivers', [addr, id, 'to'])}
|
351
|
+
#CC
|
352
|
+
m.cc_addrs.each {|addr| raise "A DB error occurred while adding data into the emails_receivers table" unless insert('email_receivers', [addr, id, 'cc'])}
|
353
|
+
|
354
|
+
|
355
|
+
id
|
356
|
+
end
|
357
|
+
|
358
|
+
def analysis_queue_add(bin, source, filename, profile='default', priority=0, user='system', sigh_id)
|
359
|
+
id = "default"
|
360
|
+
time = Util.get_time
|
361
|
+
values = [id, time, bin, priority, profile, check_source_db(source)["id"], user, filename, "pending", sigh_id.to_i]
|
362
|
+
|
363
|
+
raise "A DB error occurred while adding data into the anaylsis_queue table" unless insert("analysis_queue", values)
|
364
|
+
|
365
|
+
@id = get_curr_queue_id #race condition?
|
366
|
+
end
|
367
|
+
|
368
|
+
def analysis_queue_mark(id,status)
|
369
|
+
begin
|
370
|
+
@db.exec("UPDATE dorothy.analysis_queue set status = '#{status}' where id = '#{id}'")
|
371
|
+
end
|
372
|
+
rescue PG::Error => err
|
373
|
+
LOGGER.error "DB","Error while updating analysis_queue_mark_analysed table: " + err.result.error_field( PG::Result::PG_DIAG_MESSAGE_PRIMARY )
|
374
|
+
raise err
|
375
|
+
end
|
376
|
+
|
377
|
+
def analysis_queue_pull
|
378
|
+
@bins = []
|
379
|
+
begin
|
380
|
+
@db.exec("SELECT analysis_queue.id, analysis_queue.binary, samples.path, analysis_queue.filename, analysis_queue.priority, analysis_queue.profile, analysis_queue.source, analysis_queue.date FROM dorothy.analysis_queue, dorothy.samples WHERE analysis_queue.binary = samples.sha256 AND analysis_queue.status = 'pending' ORDER BY analysis_queue.priority DESC, analysis_queue.id ASC").each do |q|
|
381
|
+
@bins.push q
|
382
|
+
end
|
383
|
+
rescue PG::Error => err
|
384
|
+
LOGGER.error "DB","Error while fetching traffic_dumps table " + err.result.error_field( PG::Result::PG_DIAG_MESSAGE_PRIMARY )
|
385
|
+
end
|
386
|
+
@bins
|
387
|
+
end
|
388
|
+
|
389
|
+
#Mark all the pending analyses as analyzed
|
390
|
+
def analysis_queue_mark_all
|
391
|
+
analysis_queue_pull.each do |qentry|
|
392
|
+
analysis_queue_mark(qentry["id"], "analysed")
|
393
|
+
end
|
394
|
+
LOGGER.debug "DB", "Pending analyses removed from the queue"
|
395
|
+
end
|
396
|
+
|
397
|
+
#List pending analyses
|
398
|
+
def analysis_queue_view
|
399
|
+
LOGGER.info "QUEUE", "Pending analyses:"
|
400
|
+
puts "\n[" + "-".red + "] " + "\tID\tAdded\t\t\tSource\tFilename"
|
401
|
+
puts "[" + "-".red + "] " + "\t--\t-----\t\t\t------\t--------\n"
|
402
|
+
|
403
|
+
analysis_queue_pull.each do |qentry|
|
404
|
+
puts "[" + "*".red + "] " + "\t#{qentry["id"]}\t#{qentry["date"]}\t#{qentry["source"]}\t#{qentry["filename"]}"
|
405
|
+
puts ""
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
def find_last_conf_chksum(conf)
|
410
|
+
begin
|
411
|
+
r = @db.exec("SELECT cfg_chk.md5_chksum FROM dorothy.cfg_chk WHERE cfg_chk.conf_file = '#{conf}' ORDER BY cfg_chk.id DESC LIMIT 1")
|
412
|
+
r.first.nil? ? nil : r.first["md5_chksum"]
|
413
|
+
rescue PG::Error => err
|
414
|
+
LOGGER.error "DB","Error while fetching conf_chk table " + err.result.error_field( PG::Result::PG_DIAG_MESSAGE_PRIMARY )
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
def disable_source_db(id)
|
419
|
+
begin
|
420
|
+
@db.exec("UPDATE dorothy.sources set disabled = true, last_modified = '#{Util.get_time}'where id = '#{id}'")
|
421
|
+
true
|
422
|
+
rescue PG::Error => err
|
423
|
+
LOGGER.error "DB", "An error occurred while adding data into sources table " + err.result.error_field( PG::Result::PG_DIAG_MESSAGE_PRIMARY )
|
424
|
+
false
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
def check_source_db(source)
|
429
|
+
begin
|
430
|
+
r = @db.exec("SELECT sources.id, sources.sname, sources.stype, sources.host, sources.localdir FROM dorothy.sources WHERE sources.disabled = FALSE AND sources.sname = '#{source}'")
|
431
|
+
r.first.nil? ? nil : r.first
|
432
|
+
rescue PG::Error => err
|
433
|
+
LOGGER.error "DB", "An error occurred while accessing sources table" + err.result.error_field( PG::Result::PG_DIAG_MESSAGE_PRIMARY )
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
def enabled_sources_db
|
438
|
+
begin
|
439
|
+
r = @db.exec("SELECT sources.id, sources.sname, sources.stype, sources.host, sources.localdir FROM dorothy.sources WHERE sources.disabled = FALSE")
|
440
|
+
r.first.nil? ? nil : r
|
441
|
+
rescue PG::Error => err
|
442
|
+
LOGGER.error "DB", "An error occurred while accessing sources table" + err.result.error_field( PG::Result::PG_DIAG_MESSAGE_PRIMARY )
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
|
447
|
+
def check_sources_modifications(source)
|
448
|
+
|
449
|
+
db_sources = enabled_sources_db
|
450
|
+
|
451
|
+
unless db_sources.nil?
|
452
|
+
db_sources.each do |s|
|
453
|
+
unless source.has_key?(s["sname"])
|
454
|
+
LOGGER.warn "CheckCONF", "#{s["sname"]} was removed, disabling"
|
455
|
+
disable_source_db(s["id"])
|
456
|
+
end
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
|
461
|
+
source.each do |k,v|
|
462
|
+
values = ['default', k, v["type"], 'default', v["host"], 0, Util.get_time, Util.get_time, v["localdir"]]
|
463
|
+
|
464
|
+
db_source = check_source_db(k)
|
465
|
+
if db_source.nil?
|
466
|
+
LOGGER.warn "CheckCONF", "#{k} Added"
|
467
|
+
insert("sources", values)
|
468
|
+
elsif v["type"] != db_source["stype"] || v["host"] != db_source["host"] || v["localdir"] != db_source["localdir"]
|
469
|
+
|
470
|
+
LOGGER.warn "CheckCONF", "#{k} MODIFIED"
|
471
|
+
|
472
|
+
disable_source_db(db_source["id"])
|
473
|
+
LOGGER.warn "CheckCONF", "#{k} DISABLED"
|
474
|
+
|
475
|
+
insert("sources", values)
|
476
|
+
LOGGER.warn "CheckCONF", "#{k} ADDED"
|
477
|
+
end
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
|
482
|
+
|
180
483
|
def find_pcap
|
181
484
|
@pcaps = []
|
182
485
|
begin
|
183
486
|
@db.exec("SELECT traffic_dumps.sha256, traffic_dumps.pcapr_id, traffic_dumps.size, traffic_dumps.binary, traffic_dumps.parsed, samples.md5 as \"sample\", analyses.date as \"date\", analyses.id as \"anal_id\" FROM dorothy.traffic_dumps, dorothy.samples, dorothy.analyses WHERE analyses.traffic_dump = traffic_dumps.sha256 AND analyses.sample = samples.sha256 AND traffic_dumps.parsed = false").each do |q|
|
184
487
|
@pcaps.push q
|
185
488
|
end
|
186
|
-
rescue
|
187
|
-
LOGGER.error "DB","Error while fetching traffic_dumps table
|
489
|
+
rescue PG::Error => err
|
490
|
+
LOGGER.error "DB","Error while fetching traffic_dumps table " + err.result.error_field( PG::Result::PG_DIAG_MESSAGE_PRIMARY )
|
188
491
|
end
|
189
492
|
|
190
493
|
end
|
191
494
|
|
192
|
-
def
|
193
|
-
|
495
|
+
def get_curr_malwares_id
|
496
|
+
@db.exec("SELECT nextval('dorothy.malwares_id_seq')").first["nextval"].to_i
|
497
|
+
end
|
498
|
+
|
499
|
+
def find_vm(os_type, os_version, os_lang)
|
500
|
+
vm = @db.exec("SELECT id, hostname, ipaddress, username, password FROM dorothy.sandboxes where os = '#{os_type}' AND version = '#{os_version}' AND os_lang = '#{os_lang}' AND is_available is true").first
|
194
501
|
if vm.nil?
|
195
|
-
LOGGER.debug "DB","At this time there are no free VM available" if VERBOSE
|
502
|
+
LOGGER.debug "DB","At this time there are no free VM available that matches the selected profile" if VERBOSE
|
196
503
|
return false
|
197
504
|
else
|
198
505
|
@db.exec("UPDATE dorothy.sandboxes set is_available = false where id = '#{vm["id"]}'")
|
@@ -207,9 +514,8 @@ module Dorothy
|
|
207
514
|
@db.exec("UPDATE dorothy.sandboxes set is_available = true where id = '#{vmid}'")
|
208
515
|
LOGGER.info "DB", "VM #{vmid} succesfully released"
|
209
516
|
return true
|
210
|
-
rescue
|
211
|
-
LOGGER.error "DB", "An error occurred while releasing the VM"
|
212
|
-
LOGGER.debug "DB", $!
|
517
|
+
rescue PG::Error => err
|
518
|
+
LOGGER.error "DB", "An error occurred while releasing the VM " + err.result.error_field( PG::Result::PG_DIAG_MESSAGE_PRIMARY )
|
213
519
|
return false
|
214
520
|
end
|
215
521
|
else
|
@@ -226,6 +532,44 @@ module Dorothy
|
|
226
532
|
|
227
533
|
end
|
228
534
|
|
535
|
+
##CLASS MAILER FROM SALVATORE
|
536
|
+
class Mailer
|
537
|
+
attr_reader :n_emails
|
538
|
+
attr_reader :delete_once_downloaded
|
539
|
+
|
540
|
+
def initialize(account)
|
541
|
+
|
542
|
+
@n_emails = account[:n_emails]
|
543
|
+
@delete_once_downloaded = account[:delete_once_downloaded]
|
544
|
+
|
545
|
+
@mailbox = Mail.defaults do
|
546
|
+
retriever_method :pop3,
|
547
|
+
:address => account[:address],
|
548
|
+
:user_name => account[:username],
|
549
|
+
:password => account[:password],
|
550
|
+
:port => account[:port],
|
551
|
+
:enable_ssl => account[:ssl]
|
552
|
+
end
|
553
|
+
end
|
554
|
+
|
555
|
+
def read_from_string(string)
|
556
|
+
Mail.read_from_string(string)
|
557
|
+
end
|
558
|
+
|
559
|
+
|
560
|
+
def get_emails
|
561
|
+
begin
|
562
|
+
@emails = @mailbox.find(:what => :first, :count => @n_emails, :order => :asc, :delete_after_find => @delete_once_downloaded)
|
563
|
+
rescue Net::POPError => e
|
564
|
+
LOGGER.error "MAIL", e.message
|
565
|
+
raise
|
566
|
+
end
|
567
|
+
|
568
|
+
end
|
569
|
+
|
570
|
+
|
571
|
+
end
|
572
|
+
|
229
573
|
class Loadmalw
|
230
574
|
attr_reader :pcaprid
|
231
575
|
attr_reader :type
|
@@ -234,39 +578,44 @@ module Dorothy
|
|
234
578
|
attr_reader :md5
|
235
579
|
attr_reader :binpath
|
236
580
|
attr_reader :filename
|
237
|
-
|
581
|
+
|
582
|
+
#Here i'm sure that the file has an extension and can be executed by windows
|
583
|
+
attr_reader :full_filename
|
238
584
|
attr_reader :ctime
|
239
585
|
attr_reader :size
|
240
586
|
attr_reader :pcapsize
|
241
587
|
attr_reader :extension
|
242
|
-
attr_accessor :sourceinfo #used for storing info about where the binary come from (if needed)
|
243
588
|
|
244
|
-
#
|
589
|
+
#Used for storing info about where the binary comes from (if needed)
|
590
|
+
attr_accessor :sourceinfo
|
591
|
+
|
592
|
+
#binaries' repository where all the samples go.
|
593
|
+
attr_reader :binpath_repo
|
594
|
+
|
595
|
+
#Analysis folder where the files will be created
|
245
596
|
attr_accessor :dir_pcap
|
246
597
|
attr_accessor :dir_bin
|
247
598
|
attr_accessor :dir_screens
|
248
599
|
attr_accessor :dir_downloads
|
249
600
|
|
250
|
-
def initialize(file)
|
601
|
+
def initialize(file, change_filename=nil)
|
251
602
|
|
252
603
|
fm = FileMagic.new
|
253
|
-
sha = Digest::SHA2.new
|
254
|
-
md5 = Digest::MD5.new
|
255
604
|
@binpath = file
|
256
|
-
|
257
|
-
|
605
|
+
change_filename ||= File.basename(file).strip
|
606
|
+
|
607
|
+
@filename = change_filename
|
608
|
+
@extension = File.extname(change_filename)[1..-1]
|
609
|
+
|
610
|
+
|
611
|
+
@md5 = Digest::MD5.hexdigest(File.read(file))
|
612
|
+
@sha = Digest::SHA2.hexdigest(File.read(file))
|
258
613
|
|
259
|
-
File.open(file, 'rb') do |fh1|
|
260
|
-
while buffer1 = fh1.read(1024)
|
261
|
-
@sha = sha << buffer1
|
262
|
-
@md5 = md5 << buffer1
|
263
|
-
end
|
264
|
-
end
|
265
614
|
|
266
|
-
@sha = @sha.to_s
|
267
|
-
@md5 = @md5.to_s.rstrip
|
268
615
|
@sourceinfo = nil
|
269
616
|
|
617
|
+
@binpath_repo = DoroSettings.env[:bins_repository] + '/' + @md5
|
618
|
+
|
270
619
|
timetmp = File.ctime(file)
|
271
620
|
@ctime= timetmp.strftime("%m/%d/%y %H:%M:%S")
|
272
621
|
@type = fm.file(file)
|
@@ -307,4 +656,4 @@ module Dorothy
|
|
307
656
|
end
|
308
657
|
|
309
658
|
|
310
|
-
end
|
659
|
+
end
|