dorothy2 1.0.9 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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