dorothy2 1.0.9 → 1.1.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.
data/README.md CHANGED
@@ -4,6 +4,7 @@ A malware/botnet analysis framework written in Ruby.
4
4
 
5
5
  For a perfect view of this document (images and links), open it through the project's [code repository](https://github.com/m4rco-/dorothy2/blob/master/README.md).
6
6
 
7
+ For any issue, use our [Redmine](https://redmine.honeynet.it/projects/dorothy2)
7
8
  ##Introduction
8
9
 
9
10
  Dorothy2 is a framework created for mass malware analysis. Currently, it is mainly based on analyzing the network behavior of a virtual machine where a suspicious executable was executed.
@@ -108,7 +109,7 @@ It is recommended to follow this step2step process:
108
109
 
109
110
  #visudo
110
111
  add the following line:
111
- dorothy ALL = NOPASSWD: /usr/sbin/tcpdump, /bin/kill
112
+ dorothy ALL = NOPASSWD: /usr/sbin/tcpdump, /bin/kill, /usr/bin/killall
112
113
 
113
114
  * If you want to install pcapr on this machine (if you want to use dorohy from a MacOSX machine, you have to do it) install also these packages (refer to this blog [post](https://github.com/pcapr-local/pcapr-local) for a detailed howto). However, if you are installing Dorothy into a Linux machine, I recommended you to install pcapr on the same machine where the Dorothy gem was installed.
114
115
 
@@ -283,7 +284,7 @@ Below there are some tips about how understand the root-cause of your crash.
283
284
 
284
285
  > $dorothy_start -v -s malwarefolder
285
286
 
286
- 3. Drop an email to info at honeynet.it with the output of your errors :)
287
+ 3. If any error occours, go to our Redmine and raise a [bug-ticket](https://redmine.honeynet.it/projects/dorothy2/)!
287
288
 
288
289
  ------------------------------------------
289
290
 
data/UPDATE CHANGED
@@ -1,8 +1,8 @@
1
1
  #######################################
2
- #Updating from Dorothy 1.0.x to 1.1.0##
2
+ #Updating from Dorothy 1.0.x to >= 1.0.9##
3
3
  #######################################
4
4
 
5
- Dorothy 1.1.0 introduces several features that improve the overall framework.
5
+ Dorothy 1.0.9 introduces several features that improve the overall framework.
6
6
  Below, the recommended steps needed to update your Dorothy environment.
7
7
 
8
8
  a) Remove the Dorothy configuration file
@@ -120,9 +120,9 @@ LOGGER.sev_threshold = DoroSettings.env[:loglevel]
120
120
 
121
121
 
122
122
  if opts[:baseline]
123
- puts "[DOROTHY]".yellow + "Creating a new process baseline."
123
+ puts "[" + "+".red + "] " + "[DOROTHY]".yellow + "Creating a new process baseline."
124
124
  Dorothy.run_baseline
125
- puts "[WARNING]".red + "Baseline run finished."
125
+ puts "[" + "+".red + "] " + "[WARNING]".red + "Baseline run finished."
126
126
  exit(0)
127
127
  end
128
128
 
@@ -140,7 +140,7 @@ baseline_procs = home + '/etc/baseline_processes.yml'
140
140
 
141
141
  if opts[:DorothiveInit]
142
142
  Util.init_db(opts[:DorothiveInit])
143
- puts "[Dorothy]".yellow + " Database loaded, now you can restart Dorothy!"
143
+ puts "[" + "+".red + "] " + "[Dorothy]".yellow + " Database loaded, now you can restart Dorothy!"
144
144
  exit(0)
145
145
  end
146
146
 
@@ -149,12 +149,12 @@ begin
149
149
  db = Insertdb.new
150
150
  rescue => e
151
151
  if e.inspect =~ /exist/
152
- puts "WARNING".yellow + " The database doesn't exist yet. Press Enter to load the ddl into the DB"
152
+ puts "[" + "+".red + "] " + "WARNING".yellow + " The database doesn't exist yet. Press Enter to load the ddl into the DB"
153
153
  gets
154
154
  Util.init_db(DoroSettings.dorothive[:ddl])
155
155
  exit(0)
156
156
  else
157
- puts "ERROR".red + " Can't connect to the database"
157
+ puts "[" + "+".red + "] " + "ERROR".red + " Can't connect to the database"
158
158
  puts e
159
159
  exit(0)
160
160
  end
@@ -162,9 +162,9 @@ end
162
162
 
163
163
 
164
164
  if opts[:SandboxUpdate]
165
- puts "[Dorothy]".yellow + " Loading #{sboxfile} into Dorothive"
165
+ puts "[" + "+".red + "] " + "[Dorothy]".yellow + " Loading #{sboxfile} into Dorothive"
166
166
  DoroConfig.init_sandbox(sboxfile)
167
- puts "[Dorothy]".yellow + " Done."
167
+ puts "[" + "+".red + "] " + "[Dorothy]".yellow + " Done."
168
168
  exit(0)
169
169
  end
170
170
 
@@ -178,20 +178,20 @@ if Util.exists?(sfile)
178
178
  end
179
179
  end
180
180
  else
181
- puts "[WARNING]".red + " A source file doesn't exist, please crate one into #{home}/etc. See the example file in #{HOME}/etc/sources.yml.example"
181
+ puts "[" + "+".red + "] " + "[WARNING]".red + " A source file doesn't exist, please crate one into #{home}/etc. See the example file in #{HOME}/etc/sources.yml.example"
182
182
  exit(0)
183
183
  end
184
184
 
185
185
  unless Util.exists?(sboxfile)
186
- puts "[WARNING]".red + " There is no sandbox configured yet. Please do it now."
186
+ puts "[" + "+".red + "] " + "[WARNING]".red + " There is no sandbox configured yet. Please do it now."
187
187
  DoroConfig.create_sandbox(sboxfile)
188
188
  DoroConfig.init_sandbox(sboxfile)
189
189
  end
190
190
 
191
191
  unless Util.exists?(baseline_procs)
192
- puts "[WARNING]".red + " There is no process-baseline file yet, Dorothy is going to create one."
192
+ puts "[" + "+".red + "] " + "[WARNING]".red + " There is no process-baseline file yet, Dorothy is going to create one."
193
193
  Dorothy.run_baseline
194
- puts "[WARNING]".red + "Baseline run finished."
194
+ puts "[" + "+".red + "] " + "[WARNING]".red + " Baseline run finished."
195
195
  exit(0)
196
196
  end
197
197
 
@@ -199,13 +199,13 @@ BASELINE_PROCS = YAML.load_file(baseline_procs)
199
199
 
200
200
  #Check DB sandbox data
201
201
  if db.table_empty?("sandboxes")
202
- puts "[WARNING]".red + " No sandbox found in Dorothive, the DB will be filled with " + sboxfile
202
+ puts "[" + "+".red + "] " + "[WARNING]".red + " No sandbox found in Dorothive, the DB will be filled with " + sboxfile
203
203
  DoroConfig.init_sandbox(sboxfile)
204
204
  end
205
205
 
206
206
  if opts[:source] && !sources.key?(opts[:source])
207
- puts "[WARNING]".red + " The selected source is not yet configured.\nThe available sources are: "
208
- puts sources.keys
207
+ puts "[" + "+".red + "] " + "[WARNING]".red + " The selected source is not yet configured.\nThe available sources are: "
208
+ puts "[" + "+".red + "] " + sources.keys
209
209
  exit(0)
210
210
  end
211
211
 
@@ -213,9 +213,11 @@ db.close
213
213
 
214
214
  begin
215
215
  Dorothy.start sources[opts[:source]], daemon
216
+ rescue SignalException
217
+ Dorothy.stop_running_analyses
216
218
  rescue => e
217
- puts "[Dorothy]".yellow + " An error occurred: ".red + $!
218
- puts "[Dorothy]".yellow + " For more information check the logfile" + $! if daemon
219
+ puts "[" + "+".red + "] " + "[Dorothy]".yellow + " An error occurred: ".red + $!
220
+ puts "[" + "+".red + "] " + "[Dorothy]".yellow + " For more information check the logfile" + $! if daemon
219
221
  LOGGER.error "Dorothy", "An error occurred: " + $!
220
222
  LOGGER.debug "Dorothy", "#{e.inspect} --BACKTRACE: #{e.backtrace}"
221
223
  LOGGER.info "Dorothy", "Dorothy has been stopped"
@@ -17,7 +17,7 @@ dll:
17
17
  prog_path: C:\windows\system32\rundll32.exe
18
18
  prog_args:
19
19
 
20
- html:
20
+ html: # c:\Program Files\Internet Explorer\iexplore.exe" -new
21
21
  prog_name: Microsoft Explorer IEXPLORE.EXE
22
22
  prog_path: C:\windows\system32\cmd.exe
23
23
  prog_args: /C start "C:\\Programmi\\Internet Explorer\\IEXPLORE.EXE"
@@ -51,8 +51,6 @@ module DoroParser
51
51
 
52
52
  def search_irc(streamdata)
53
53
 
54
- util = Util.new
55
-
56
54
  ircvalues = []
57
55
  streamdata.each do |m|
58
56
  # if m[1] == 0 #we fetch only outgoing traffic
@@ -44,6 +44,7 @@ module Dorothy
44
44
 
45
45
 
46
46
  def start_analysis(bins)
47
+ #Create a mutex for monitoring the access to the methods
47
48
  @binum = bins.size
48
49
  bins.each do |bin|
49
50
  next unless check_support(bin)
@@ -157,7 +158,7 @@ module Dorothy
157
158
  LOGGER.info "VSM",vm_log_header + "Copying #{bin.md5} to VM"
158
159
 
159
160
  filecontent = File.open(bin.binpath, "rb") { |byte| byte.read } #load filebinary
160
- vsm.copy_file(bin.filename,filecontent)
161
+ vsm.copy_file(bin.full_filename,filecontent) #Using full_filename, we do want to be sure that it has an extension
161
162
 
162
163
  #Start Sniffer
163
164
  dumpname = anal_id.to_s + "-" + bin.md5
@@ -170,20 +171,22 @@ module Dorothy
170
171
  @screenshots = Array.new
171
172
 
172
173
  #Execute File into VM
173
- LOGGER.info "VSM",vm_log_header + "Executing #{bin.md5} with #{EXTENSIONS["prog_args"]}"
174
+ LOGGER.info "VSM",vm_log_header + "Executing #{bin.full_filename} with #{EXTENSIONS[bin.extension]["prog_name"]}"
174
175
 
175
176
  if MANUAL
176
177
  LOGGER.debug "VSM",vm_log_header + " MANUAL mode detected. You can now logon to rdp:// "
177
178
 
178
- LOGGER.info "MANUAL-MODE",vm_log_header + "
179
+ menu="
179
180
 
180
181
  Choose your next action:
181
182
  1) Take Screenshot
182
183
  2) Take ProcessList
183
- 3) Execute #{bin.filename}
184
+ 3) Execute #{bin.full_filename}
184
185
  0) Continue and revert the machine.
185
186
 
186
187
  Select a nuber:"
188
+
189
+ LOGGER.info "MANUAL-MODE",vm_log_header + menu
187
190
  answer = gets.chop
188
191
 
189
192
  until answer == "0"
@@ -194,12 +197,15 @@ module Dorothy
194
197
  when "2"
195
198
  @current_procs = vsm.get_running_procs
196
199
  LOGGER.info "MANUAL-MODE",vm_log_header + "Current ProcessList taken"
200
+ @current_procs.each_key do |pid|
201
+ LOGGER.info "MANUAL-MODE", vm_log_header + "[" + "+".red + "]" + " PID: #{pid}, NAME: #{@current_procs[pid]["pname"]}, COMMAND: #{@current_procs[pid]["cmdLine"]}"
202
+ end
197
203
  when "3"
198
- guestpid = vsm.exec_file("C:\\#{bin.filename}",EXTENSIONS[bin.extension])
204
+ guestpid = vsm.exec_file("C:\\#{bin.full_filename}",EXTENSIONS[bin.extension])
199
205
  LOGGER.debug "MANUAL-MODE",vm_log_header + "Program executed with PID #{guestpid}"
200
206
  #when "x" then -- More interactive actions to add
201
207
  else
202
- LOGGER.info "MANUAL-MODE",vm_log_header + "Please select a number"
208
+ LOGGER.info "MANUAL-MODE",vm_log_header + menu
203
209
  end
204
210
  answer = gets.chop
205
211
  end
@@ -208,7 +214,7 @@ module Dorothy
208
214
 
209
215
 
210
216
  else
211
- guestpid = vsm.exec_file("C:\\#{bin.filename}",EXTENSIONS[bin.extension])
217
+ guestpid = vsm.exec_file("C:\\#{bin.full_filename}",EXTENSIONS[bin.extension])
212
218
  LOGGER.debug "VSM",vm_log_header + "Program executed with PID #{guestpid}" if VERBOSE
213
219
  sleep 1
214
220
  returncode = vsm.get_status(guestpid)
@@ -231,7 +237,7 @@ module Dorothy
231
237
 
232
238
 
233
239
  #Stop Sniffer, revert the VM
234
- stop_nam_revertvm(@nam, pid, vsm, guestvm[0], reverted, vm_log_header)
240
+ stop_nam_revertvm(@nam, pid, vsm, reverted, vm_log_header)
235
241
 
236
242
  vsm.revert_vm
237
243
  reverted = true
@@ -338,9 +344,9 @@ module Dorothy
338
344
  FileUtils.rm(bin.binpath)
339
345
  LOGGER.info "VSM", vm_log_header + "Process compleated successfully"
340
346
 
341
- rescue SignalException
347
+ rescue SignalException, RuntimeError
342
348
  LOGGER.warn "DOROTHY", "SIGINT".red + " Catched, exiting gracefully."
343
- stop_nam_revertvm(@nam, pid, vsm, guestvm[0], reverted, vm_log_header)
349
+ stop_nam_revertvm(@nam, pid, vsm, reverted, vm_log_header)
344
350
  LOGGER.debug "VSM", vm_log_header + "Removing working dir"
345
351
  FileUtils.rm_r(sample_home)
346
352
  if in_transaction
@@ -354,7 +360,7 @@ module Dorothy
354
360
 
355
361
  LOGGER.warn "Dorothy", vm_log_header + "Stopping NAM instances if presents, reverting the Sandbox, and removing working directory"
356
362
 
357
- stop_nam_revertvm(@nam, pid, vsm, guestvm[0], reverted, vm_log_header)
363
+ stop_nam_revertvm(@nam, pid, vsm, reverted, vm_log_header)
358
364
  LOGGER.debug "VSM", vm_log_header + "Removing working dir"
359
365
 
360
366
  FileUtils.rm_r(sample_home)
@@ -372,83 +378,90 @@ module Dorothy
372
378
  end
373
379
 
374
380
  #Stop NAM instance and Revert VM
375
- def stop_nam_revertvm(nam, pid, vsm, guestvm, reverted, vm_log_header)
381
+ def stop_nam_revertvm(nam, pid, vsm, reverted, vm_log_header)
376
382
 
377
- if pid
378
- LOGGER.info "VSM", vm_log_header + " Stopping sniffing module " + pid.to_s
379
- nam.stop_sniffer(pid)
380
- end
383
+ if pid
384
+ LOGGER.info "VSM", vm_log_header + " Stopping sniffing module " + pid.to_s
385
+ nam.stop_sniffer(pid)
386
+ end
381
387
 
382
- unless reverted || vsm.nil?
383
- LOGGER.info "VSM", vm_log_header + " Reverting VM"
384
- vsm.revert_vm
385
- sleep 3 #wait some seconds for letting the vm revert..
388
+ unless reverted || vsm.nil?
389
+ LOGGER.info "VSM", vm_log_header + " Reverting VM"
390
+ vsm.revert_vm
391
+ sleep 3 #wait some seconds for letting the vm revert..
392
+ end
386
393
  end
387
- end
388
394
 
389
395
  ###Create Baseline
390
- def run_baseline
396
+ def self.run_baseline
391
397
  db = Insertdb.new
398
+ db.vm_init
392
399
  guestvm = db.find_vm
393
- LOGGER.info "VSM","VM#{guestvm[0]}".red + " Executng the baseline run"
394
- vsm = Doro_VSM::ESX.new(DoroSettings.esx[:host],DoroSettings.esx[:user],DoroSettings.esx[:pass],guestvm[1], guestvm[3], guestvm[4])
395
- vsm.check_internet
396
- LOGGER.info "VSM","VM#{guestvm[0]}".red + " Sleeping #{DoroSettings.sandbox[:sleeptime]} seconds".yellow
397
- sleep DoroSettings.sandbox[:sleeptime]
398
- vsm.get_running_procs(nil, true) #save on file
399
- LOGGER.info "VSM", "VM#{guestvm[0]} ".red + "Reverting VM".yellow
400
- vsm.revert_vm
401
- db.free_vm(guestvm[0])
402
- db.close
403
- rescue => e
404
- LOGGER.error "VSM", "VM#{guestvm[0]} An error occurred while performing the BASELINE run, please retry"
405
- LOGGER.debug "Dorothy" , "#{$!}\n #{e.inspect} \n #{e.backtrace}" if VERBOSE
406
- LOGGER.warn "VSM", "VM#{guestvm[0]} ".red + "[RECOVER] Reverting VM".yellow
407
- vsm.revert_vm
408
- db.free_vm(guestvm[0])
409
- db.close
410
- end
400
+ if guestvm
401
+ begin
402
+ LOGGER.info "VSM","VM#{guestvm[0]}".red + " Executng the baseline run"
403
+ vsm = Doro_VSM::ESX.new(DoroSettings.esx[:host],DoroSettings.esx[:user],DoroSettings.esx[:pass],guestvm[1], guestvm[3], guestvm[4])
404
+ vsm.check_internet
405
+ LOGGER.info "VSM","VM#{guestvm[0]}".red + " Sleeping #{DoroSettings.sandbox[:sleeptime]} seconds".yellow
406
+ sleep DoroSettings.sandbox[:sleeptime]
407
+ vsm.get_running_procs(nil, true) #save on file
408
+ LOGGER.info "VSM", "VM#{guestvm[0]} ".red + "Reverting VM".yellow
409
+ vsm.revert_vm
410
+ db.free_vm(guestvm[0])
411
+ db.close
412
+ rescue => e
413
+ LOGGER.error "VSM", "VM#{guestvm[0]} ".yellow + "An error occurred while performing the BASELINE run, please retry"
414
+ LOGGER.debug "Dorothy" , "VM#{guestvm[0]} ".yellow + "#{$!}\n #{e.inspect} \n #{e.backtrace}" if VERBOSE
415
+ LOGGER.warn "VSM", "VM#{guestvm[0]} ".yellow + "[RECOVER] Reverting VM"
416
+ vsm.revert_vm
417
+ db.free_vm(guestvm[0])
418
+ db.close
419
+ end
420
+ else
421
+ LOGGER.fatal "VSM", "[CRITICAL]".red + " There are no free VM at the moment..how it is possible?"
422
+ end
423
+ end
411
424
 
412
425
  ########################
413
426
  ## VTOTAL SCAN ####
414
427
  ########################
415
- private
416
- def scan(bin)
417
- #puts "TOTAL", "Forking for VTOTAL"
418
- @vtotal_threads << Thread.new(bin.sha) {
419
- LOGGER.info "VTOTAL", "Scanning file #{bin.md5}".yellow
428
+ private
429
+ def scan(bin)
430
+ #puts "TOTAL", "Forking for VTOTAL"
431
+ @vtotal_threads << Thread.new(bin.sha) {
432
+ LOGGER.info "VTOTAL", "Scanning file #{bin.md5}".yellow
420
433
 
421
- vt = Vtotal.new
422
- id = vt.analyze_file(bin.binpath)
434
+ vt = Vtotal.new
435
+ id = vt.analyze_file(bin.binpath)
423
436
 
424
- LOGGER.debug "VTOTAL", "Sleeping"
437
+ LOGGER.debug "VTOTAL", "Sleeping"
425
438
 
426
- sleep 15
439
+ sleep 15
427
440
 
428
- until vt.get_report(id)
429
- LOGGER.info "VTOTAL", "Waiting a while and keep retring..."
430
- sleep 30
431
- end
441
+ until vt.get_report(id)
442
+ LOGGER.info "VTOTAL", "Waiting a while and keep retring..."
443
+ sleep 30
444
+ end
432
445
 
433
- LOGGER.info "VTOTAL", "#{bin.md5} Detection Rate: #{vt.rate}"
434
- LOGGER.info "VTOTAL", "#{bin.md5} Family by McAfee: #{vt.family}"
446
+ LOGGER.info "VTOTAL", "#{bin.md5} Detection Rate: #{vt.rate}"
447
+ LOGGER.info "VTOTAL", "#{bin.md5} Family by McAfee: #{vt.family}"
435
448
 
436
- LOGGER.info "VTOTAL", "Updating DB"
437
- vtvalues = [bin.sha, vt.family, vt.vendor, vt.version, vt.rate, vt.updated, vt.detected]
438
- db = Insertdb.new
439
- db.begin
440
- begin
441
- db.insert("malwares", vtvalues)
442
- db.close
443
- rescue
444
- db.rollback
445
- LOGGER.error "VTOTAL", "Error while inserting values in malware table"
446
- end
449
+ LOGGER.info "VTOTAL", "Updating DB"
450
+ vtvalues = [bin.sha, vt.family, vt.vendor, vt.version, vt.rate, vt.updated, vt.detected]
451
+ db = Insertdb.new
452
+ db.begin
453
+ begin
454
+ db.insert("malwares", vtvalues)
455
+ db.close
456
+ rescue
457
+ db.rollback
458
+ LOGGER.error "VTOTAL", "Error while inserting values in malware table"
459
+ end
447
460
 
448
- #TODO upload evidence to RT
449
- }
461
+ #TODO upload evidence to RT
462
+ }
450
463
 
451
- end
464
+ end
452
465
 
453
466
 
454
467
 
@@ -456,118 +469,129 @@ end
456
469
  ## MAIN #
457
470
  #########################
458
471
 
459
- def self.start(source=nil, daemon=nil)
472
+ def self.start(source=nil, daemon=nil)
460
473
 
461
- @db = Insertdb.new
462
- daemon ||= false
474
+ @db = Insertdb.new
475
+ daemon ||= false
463
476
 
464
- puts "[Dorothy]".yellow + " Process Started"
477
+ puts "[" + "+".red + "] " + "[Dorothy]".yellow + " Process Started"
465
478
 
466
479
 
467
- LOGGER.info "Dorothy", "Started".yellow
480
+ LOGGER.info "Dorothy", "Started".yellow
468
481
 
469
- if daemon
470
- check_pid_file DoroSettings.env[:pidfile]
471
- puts "[Dorothy]".yellow + " Going in backround with pid #{Process.pid}"
472
- puts "[Dorothy]".yellow + " Logging on #{DoroSettings.env[:logfile]}"
473
- Process.daemon
474
- create_pid_file DoroSettings.env[:pidfile]
475
- puts "[Dorothy]".yellow + " Going in backround with pid #{Process.pid}"
476
- end
482
+ if daemon
483
+ check_pid_file DoroSettings.env[:pidfile]
484
+ puts "[" + "+".red + "] " + "[Dorothy]".yellow + " Going in backround with pid #{Process.pid}"
485
+ puts "[" + "+".red + "] " + "[Dorothy]".yellow + " Logging on #{DoroSettings.env[:logfile]}"
486
+ Process.daemon
487
+ create_pid_file DoroSettings.env[:pidfile]
488
+ puts "[" + "+".red + "] " + "[Dorothy]".yellow + " Going in backround with pid #{Process.pid}"
489
+ end
477
490
 
478
- #Creating a new NAM object for managing the sniffer
479
- @nam = Doro_NAM.new(DoroSettings.nam)
491
+ #Creating a new NAM object for managing the sniffer
492
+ @nam = Doro_NAM.new(DoroSettings.nam)
493
+ #Be sure that there are no open tcpdump instances opened
494
+ @nam.init_sniffer
480
495
 
481
- @vtotal_threads = []
482
- @vtotal_threads = []
483
- @analysis_threads = []
496
+ @vtotal_threads = []
497
+ @vtotal_threads = []
498
+ @analysis_threads = []
484
499
 
485
- infinite = true
500
+ infinite = true
486
501
 
487
- #be sure that all the vm are available by forcing their release
488
- @db.vm_init
502
+ #be sure that all the vm are available by forcing their release
503
+ @db.vm_init
489
504
 
490
- if source # a source has been specified
491
- while infinite #infinite loop
492
- dfm = DorothyFetcher.new(source)
493
- start_analysis(dfm.bins)
494
- infinite = daemon #exit if wasn't set
495
- wait_end
496
- LOGGER.info "Dorothy", "SLEEPING" if daemon
497
- sleep DoroSettings.env[:dtimeout] if daemon # Sleeping a while if -d wasn't set, then quit.
498
- end
499
- else # no sources specified, analyze all of them
500
- while infinite #infinite loop
501
- sources = YAML.load_file(DoroSettings.env[:home] + '/etc/sources.yml')
502
- sources.keys.each do |sname|
503
- dfm = DorothyFetcher.new(sources[sname])
505
+ if source # a source has been specified
506
+ while infinite #infinite loop
507
+ dfm = DorothyFetcher.new(source)
504
508
  start_analysis(dfm.bins)
509
+ infinite = daemon #exit if wasn't set
510
+ wait_end
511
+ LOGGER.info "Dorothy", "SLEEPING" if daemon
512
+ sleep DoroSettings.env[:dtimeout] if daemon # Sleeping a while if -d wasn't set, then quit.
513
+ end
514
+ else # no sources specified, analyze all of them
515
+ while infinite #infinite loop
516
+ sources = YAML.load_file(DoroSettings.env[:home] + '/etc/sources.yml')
517
+ sources.keys.each do |sname|
518
+ dfm = DorothyFetcher.new(sources[sname])
519
+ start_analysis(dfm.bins)
520
+ end
521
+ infinite = daemon #exit if wasn't set
522
+ wait_end
523
+ LOGGER.info "Dorothy", "SLEEPING" if daemon
524
+ sleep DoroSettings.env[:dtimeout].to_i if daemon # Sleeping a while if -d wasn't set, then quit.
505
525
  end
506
- infinite = daemon #exit if wasn't set
507
- wait_end
508
- LOGGER.info "Dorothy", "SLEEPING" if daemon
509
- sleep DoroSettings.env[:dtimeout].to_i if daemon # Sleeping a while if -d wasn't set, then quit.
510
526
  end
511
- end
512
527
 
513
- @db.close
528
+ @db.close
514
529
 
515
- end
530
+ end
516
531
 
517
- def wait_end
532
+ def wait_end
518
533
 
519
- unless @vtotal_threads.empty?
520
- @vtotal_threads.each { |aThread| aThread.join}
521
- LOGGER.info "VTOTAL","Process compleated successfully"
522
- end
534
+ unless @vtotal_threads.empty?
535
+ @vtotal_threads.each { |aThread| aThread.join}
536
+ LOGGER.info "VTOTAL","Process compleated successfully"
537
+ end
523
538
 
524
- @analysis_threads.each { |aThread| aThread.join }
525
- LOGGER.info "Dorothy", "Process finished"
539
+ @analysis_threads.each { |aThread| aThread.join }
540
+ LOGGER.info "Dorothy", "Process finished"
526
541
 
527
- end
542
+ end
528
543
 
529
- def check_pid_file(file)
530
- if File.exist? file
531
- # If we get Errno::ESRCH then process does not exist and
532
- # we can safely cleanup the pid file.
533
- pid = File.read(file).to_i
534
- begin
535
- Process.kill(0, pid)
536
- rescue Errno::ESRCH
537
- stale_pid = true
538
- end
544
+ def check_pid_file(file)
545
+ if File.exist? file
546
+ # If we get Errno::ESRCH then process does not exist and
547
+ # we can safely cleanup the pid file.
548
+ pid = File.read(file).to_i
549
+ begin
550
+ Process.kill(0, pid)
551
+ rescue Errno::ESRCH
552
+ stale_pid = true
553
+ end
539
554
 
540
- unless stale_pid
541
- puts "[Dorothy]".yellow + " Dorothy is already running (pid=#{pid})"
542
- exit(1)
555
+ unless stale_pid
556
+ puts "[" + "+".red + "] " + "[Dorothy]".yellow + " Dorothy is already running (pid=#{pid})"
557
+ exit(1)
558
+ end
543
559
  end
544
560
  end
545
- end
546
561
 
547
- def create_pid_file(file)
548
- File.open(file, "w") { |f| f.puts Process.pid }
562
+ def create_pid_file(file)
563
+ File.open(file, "w") { |f| f.puts Process.pid }
549
564
 
550
- # Remove pid file during shutdown
551
- at_exit do
552
- Logger.info "Dorothy", "Shutting down." rescue nil
553
- if File.exist? file
554
- File.unlink file
565
+ # Remove pid file during shutdown
566
+ at_exit do
567
+ LOGGER.info "Dorothy", "Shutting down." rescue nil
568
+ if File.exist? file
569
+ File.unlink file
570
+ end
555
571
  end
556
572
  end
557
- end
558
573
 
574
+ def self.stop_running_analyses
575
+ LOGGER.info "Dorothy", "Killing curent live analysis threads.."
576
+ @analysis_threads.each { |aThread|
577
+ aThread.raise
578
+ aThread.join
579
+ }
580
+ end
559
581
  ## Sends SIGTERM to process in pidfile. Server should trap this
560
582
  # and shutdown cleanly.
561
- def self.stop
562
- LOGGER.info "Dorothy", "Shutting down."
563
- pid_file = DoroSettings.env[:pidfile]
564
- if pid_file and File.exist? pid_file
565
- pid = Integer(File.read(pid_file))
566
- Process.kill(-15, -pid)
567
- LOGGER.info "Dorothy", "Process #{pid} terminated"
568
- else
569
- LOGGER.info "Dorothy", "Can't find PID file, is Dorothy really running?"
583
+ def self.stop
584
+ puts "[" + "+".red + "]" + " Dorothy is shutting now.."
585
+ LOGGER.info "Dorothy", "Shutting down."
586
+ pid_file = DoroSettings.env[:pidfile]
587
+ if pid_file and File.exist? pid_file
588
+ pid = Integer(File.read(pid_file))
589
+ Process.kill(-2,-pid)
590
+ LOGGER.info "Dorothy", "Process #{pid} terminated"
591
+ puts "[" + "+".red + "]" + " Dorothy Process #{pid} terminated"
592
+ else
593
+ LOGGER.info "Dorothy", "Can't find PID file, is Dorothy really running?"
594
+ end
570
595
  end
571
- end
572
596
 
573
- end
597
+ end
@@ -22,12 +22,31 @@ module Dorothy
22
22
  Net::SSH.start(@server, @user, :password => @pass, :port =>@port) do |@ssh|
23
23
  MANUAL ? not_rdp = "and not port 3389" : not_rdp = ""
24
24
  @ssh.exec "nohup sudo tcpdump -i #{interface} -s 1514 -w #{pcaphome}/#{name}.pcap host #{vmaddress} #{not_rdp} 2> log.tmp & "
25
- t = @ssh.exec!"ps aux |grep #{vmaddress}|grep -v grep|grep -v bash"
26
- pid = t.split(" ")[1]
25
+
26
+ begin
27
+ t = @ssh.exec!"ps aux |grep #{name}|grep -v grep|grep -v bash"
28
+ pid = t.split(" ")[1]
29
+ rescue
30
+ r = 0
31
+ if r <= 2
32
+ r = r+1
33
+ LOGGER.warn "NSM", " NAM has failed to catch the Tcpdump PID, retry n. #{r}/3"
34
+ sleep 2
35
+ retry
36
+ end
37
+ LOGGER.warn "NSM", " NAM has failed to catch the Tcpdump PID, retry n. #{r}/3"
38
+ raise
39
+ end
27
40
  return pid.to_i
28
41
  end
29
42
  end
30
43
 
44
+ def init_sniffer
45
+ Net::SSH.start(@server, @user, :password => @pass, :port =>@port) do |ssh|
46
+ ssh.exec "sudo killall tcpdump"
47
+ end
48
+ end
49
+
31
50
  def stop_sniffer(pid)
32
51
  Net::SSH.start(@server, @user, :password => @pass, :port =>@port) do |ssh|
33
52
  ssh.exec "sudo kill -2 #{pid}"
@@ -6,7 +6,6 @@ module Dorothy
6
6
 
7
7
  #Dorothy module-class for managig the virtual sandboxes
8
8
  class Doro_VSM
9
-
10
9
  #ESX vSphere5 interface
11
10
  class ESX
12
11
 
@@ -73,7 +72,7 @@ module Dorothy
73
72
 
74
73
  def exec_file(filename, program)
75
74
  program["prog_args"].nil? ? args = "" : args = program["prog_args"]
76
- args << " #{filename}"
75
+ args += " #{filename}"
77
76
  cmd = { :programPath => program["prog_path"], :arguments => args }
78
77
  pid = @pm.StartProgramInGuest(:vm => @vm , :auth => @auth, :spec => cmd )
79
78
  pid.to_i
@@ -100,7 +99,7 @@ module Dorothy
100
99
  @pp2 = Hash.new
101
100
  procs = @pm.ListProcessesInGuest(:vm => @vm , :auth => @auth, :pids => pid )
102
101
  procs.each {|pp2| @pp2.merge! Hash[pp2.pid, Hash["pname", pp2.name, "owner", pp2.owner, "cmdLine", pp2.cmdLine, "startTime", pp2.startTime, "endTime", pp2.endTime, "exitCode", pp2.exitCode]]}
103
- if save_tofile
102
+ if save_tofile
104
103
  Util.write(filename, @pp2.to_yaml)
105
104
  LOGGER.info "VSM", "Current running processes saved to #{filename}"
106
105
  end
@@ -5,7 +5,6 @@
5
5
  module Dorothy
6
6
 
7
7
  module Util
8
-
9
8
  extend self
10
9
 
11
10
  def write(file, string)
@@ -89,6 +88,8 @@ module Dorothy
89
88
  value1 = value
90
89
  elsif value =~ /currval/
91
90
  value1 = value
91
+ elsif table == "sys_procs" #avoiding noising escape-issue for \u
92
+ value1 = "E'#{value.inspect}'"
92
93
  else
93
94
  #if present, remove ""
94
95
  value.gsub! /^"|"$/, '' if values.class.inspect == "String"
@@ -230,6 +231,7 @@ module Dorothy
230
231
  attr_reader :md5
231
232
  attr_reader :binpath
232
233
  attr_reader :filename
234
+ attr_reader :full_filename #here i'm sure that the file has an extension and can be executed by windows
233
235
  attr_reader :ctime
234
236
  attr_reader :size
235
237
  attr_reader :pcapsize
@@ -266,20 +268,25 @@ module Dorothy
266
268
  @ctime= timetmp.strftime("%m/%d/%y %H:%M:%S")
267
269
  @type = fm.file(file)
268
270
 
271
+
269
272
  if @extension.nil? #no extension, trying to put the right one..
270
273
  case @type
271
274
  when /^PE32/ then
272
275
  @extension = (@type =~ /DLL/ ? "dll" : "exe")
276
+ when /^COM/ then
277
+ @extension = "exe"
273
278
  when /^MS-DOS/ then
274
279
  @extension = "bat"
275
280
  when /^HTML/ then
276
281
  @extension = "html"
277
282
  else
278
- @extension = nil
283
+ @extension = "unknown"
279
284
  end
285
+ @full_filename = @filename + "." + @extension
286
+ else
287
+ @full_filename = @filename
280
288
  end
281
289
 
282
-
283
290
  @size = File.size(file)
284
291
  end
285
292
 
@@ -1,3 +1,3 @@
1
1
  module Dorothy
2
- VERSION = "1.0.9"
2
+ VERSION = "1.1.0"
3
3
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dorothy2
3
3
  version: !ruby/object:Gem::Version
4
- hash: 5
4
+ hash: 19
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
+ - 1
8
9
  - 0
9
- - 9
10
- version: 1.0.9
10
+ version: 1.1.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - marco riccardi
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2013-08-11 00:00:00 Z
18
+ date: 2013-09-24 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: net-scp