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/BFM.rb
CHANGED
@@ -3,35 +3,43 @@
|
|
3
3
|
# See the file 'LICENSE' for copying permission.
|
4
4
|
|
5
5
|
|
6
|
-
|
7
|
-
###BINARY FETCHER MODULE###
|
8
|
-
|
9
|
-
|
6
|
+
#############################
|
7
|
+
### BINARY FETCHER MODULE ###
|
8
|
+
#############################
|
9
|
+
|
10
10
|
#The BFM module is in charge of retreiving the binary from the sources configured in the sources.yml file.
|
11
11
|
#It receive the source hash, and return the downloaded binaries objects.
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
|
16
|
+
|
12
17
|
module Dorothy
|
13
18
|
|
14
19
|
class DorothyFetcher
|
15
|
-
attr_reader :
|
20
|
+
attr_reader :added
|
16
21
|
|
17
|
-
#
|
18
|
-
def initialize(
|
22
|
+
#Source_arr is an array e.g.: ["webgui", {"type"=>"system", "localdir"=>"/Users/akira/Downloads/doroth2_1.9.3_mail/opt/bins/webgui", "typeid"=>1}]
|
23
|
+
def initialize(source_arr)
|
19
24
|
ndownloaded = 0
|
20
25
|
|
21
|
-
@
|
22
|
-
|
26
|
+
@added = Hash.new
|
27
|
+
source = source_arr[1] #source_arr[1] is a hash
|
28
|
+
|
29
|
+
source["priority"] ||= 0
|
30
|
+
source["profile"] ||= "default"
|
31
|
+
|
23
32
|
|
24
33
|
case source["type"]
|
25
34
|
|
26
35
|
when "ssh" then
|
27
|
-
LOGGER.info "BFM", " Fetching trojan from > Honeypot"
|
28
36
|
#file = "/opt/dionaea/var/dionaea/binaries/"
|
29
37
|
#puts "Start to download malware"
|
30
38
|
|
31
39
|
files = []
|
32
40
|
|
33
41
|
begin
|
34
|
-
Net::SSH.start(source["ip"], source["
|
42
|
+
Net::SSH.start(source["ip"], source["username"], :password => source["pass"], :port => source["port"]) do |ssh|
|
35
43
|
ssh.scp.download!(source["remotedir"],source["localdir"], :recursive => true) do |ch, name, sent, total|
|
36
44
|
unless files.include? "#{source["localdir"]}/" + File.basename(name)
|
37
45
|
ndownloaded += 1
|
@@ -55,7 +63,7 @@ module Dorothy
|
|
55
63
|
|
56
64
|
begin
|
57
65
|
unless DoroSettings.env[:testmode]
|
58
|
-
Net::SSH.start(source["
|
66
|
+
Net::SSH.start(source["host"], source["user"], :password => source["pass"], :port => source["port"]) do |ssh|
|
59
67
|
ssh.exec "mv #{source["remotedir"]}/* #{source["remotedir"]}/../analyzed "
|
60
68
|
end
|
61
69
|
end
|
@@ -64,78 +72,123 @@ module Dorothy
|
|
64
72
|
end
|
65
73
|
|
66
74
|
files.each do |f|
|
67
|
-
|
75
|
+
begin
|
76
|
+
@added = QueueManager.add(f, source_arr[0], source["profile"], source["priority"])
|
77
|
+
rescue
|
78
|
+
LOGGER.error "BFM", "Error while adding the bin to the queue, skipping."
|
79
|
+
LOGGER.debug "BFM", $!
|
80
|
+
next
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
#Thanks to Salvatore Gervino who made the first PoC of this source-module: http://www.honeynet.it/wp-content/uploads/Mentored_Projects/salvatore_gervino-dorothy2_email.pdf
|
86
|
+
when "mail" then
|
87
|
+
|
88
|
+
@db = Insertdb.new
|
89
|
+
|
90
|
+
account = {:address=>source["host"], :username=>source["username"],
|
91
|
+
:password=>source["password"], :port=>source["port"], :ssl=>source["enable_ssl"], :n_emails => source["n_emails"] , :delete_once_downloaded => source["delete_once_downloaded"]}
|
92
|
+
|
93
|
+
|
94
|
+
mailer = Dorothy::Mailer.new(account)
|
95
|
+
begin
|
96
|
+
emails = mailer.get_emails
|
97
|
+
|
98
|
+
emails.each do |email|
|
99
|
+
|
100
|
+
LOGGER.debug "BFM", "Analyzing email: #{email.date} - #{email.from_addrs[0]} - #{email.subject} - #{email.to_addrs[0]}"
|
101
|
+
|
102
|
+
|
103
|
+
unless email.attachments.empty?
|
104
|
+
mail_id = @db.push_email_data(email)
|
105
|
+
|
106
|
+
attachment_content_type = Mail::ContentTypeElement.new(email.attachments.first.content_type)
|
107
|
+
#if the attachment is a forwarded email, treat the attachment as the original email
|
108
|
+
if attachment_content_type.main_type == 'message'
|
109
|
+
|
110
|
+
LOGGER.info "BFM", "Forwarded email from #{email.from.first} found"
|
111
|
+
email = mailer.read_from_string email.attachments.first.body.decoded
|
112
|
+
mail_id = @db.push_email_data(email, mail_id)
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
email.attachments.each do | attachment |
|
118
|
+
LOGGER.info "BFM", "Attachment found: #{attachment.filename} "
|
119
|
+
bin = source["localdir"] + "/" + Digest::MD5.hexdigest(attachment.body.decoded) + "_" + attachment.filename
|
120
|
+
Util.write( bin, attachment.body.decoded)
|
121
|
+
id = QueueManager.add(bin, source_arr[0],source["profile"], source["priority"], mail_id)
|
122
|
+
@added.store(id,[bin, source["priority"], source["profile"], source_arr[0]])
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
end #end for
|
127
|
+
@db.close
|
128
|
+
LOGGER.debug "BFM", "Analyzing email: End "
|
129
|
+
rescue => e
|
130
|
+
LOGGER.error "BFM", "Error while adding the bin to the queue, skipping. #{$!}"
|
131
|
+
LOGGER.debug "DB", e.backtrace
|
68
132
|
end
|
69
133
|
|
70
134
|
when "system" then
|
71
|
-
LOGGER.info "BFM", "Fetching trojan from > filesystem: " + source["localdir"]
|
72
135
|
empty = true
|
73
136
|
Dir.foreach(source["localdir"]) do |file|
|
74
137
|
bin = source["localdir"] + "/" + file
|
75
|
-
next if File.directory?(bin)
|
76
|
-
|
138
|
+
next if File.directory?(bin)
|
139
|
+
|
140
|
+
begin
|
141
|
+
id = QueueManager.add(bin, source_arr[0], source["profile"], source["priority"])
|
142
|
+
empty = false
|
143
|
+
@added.store(id,[bin, source["priority"], source["profile"], source_arr[0]])
|
144
|
+
|
145
|
+
rescue
|
146
|
+
LOGGER.error "BFM", "Error while adding the bin to the queue, skipping."
|
147
|
+
LOGGER.debug "BFM", $!
|
148
|
+
next
|
149
|
+
end
|
150
|
+
|
77
151
|
end
|
78
|
-
LOGGER.
|
152
|
+
LOGGER.debug "BFM", "No binaries were found in the selected source" if empty
|
79
153
|
else
|
80
|
-
LOGGER.fatal "BFM", "Source #{
|
154
|
+
LOGGER.fatal "BFM", "Source type #{source["type"]} is not yet configured"
|
81
155
|
end
|
82
156
|
end
|
83
157
|
|
84
|
-
|
85
|
-
def
|
158
|
+
#Expects an Hash as input
|
159
|
+
def self.loader(sources, daemon=false)
|
86
160
|
|
87
|
-
|
88
|
-
bin = Loadmalw.new(f)
|
89
|
-
if bin.size == 0 || bin.sha.empty?
|
90
|
-
LOGGER.warn "BFM", "Warning - Empty file #{filename}, deleting and skipping.."
|
91
|
-
FileUtils.rm bin.binpath
|
92
|
-
return false
|
93
|
-
end
|
161
|
+
infinite = true
|
94
162
|
|
95
|
-
samplevalues = [bin.sha, bin.size, bin.dir_bin, filename, bin.md5, bin.type ]
|
96
|
-
sighvalues = [bin.sha, typeid, bin.ctime, "null"]
|
97
163
|
|
98
164
|
begin
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
return false
|
104
|
-
end
|
105
|
-
|
106
|
-
#FileUtils.rm(bin.binpath)
|
107
|
-
@bins.push bin
|
108
|
-
end
|
109
|
-
|
165
|
+
while infinite #infinite loop
|
166
|
+
sources.each do |sname|
|
167
|
+
#skip if it is webgui
|
168
|
+
next if sname.first == 'webgui'
|
110
169
|
|
170
|
+
LOGGER.debug "BFM", "Start to fetch binaries from #{sname.first.yellow} @ #{sname[1]["localdir"]}"
|
111
171
|
|
112
|
-
|
172
|
+
added = self.new(sname).added
|
173
|
+
LOGGER.info "BFM", "#{added.size.to_s.yellow} binaries retreived from #{sname.first.yellow}"
|
113
174
|
|
114
|
-
|
115
|
-
|
175
|
+
added.each do |b|
|
176
|
+
LOGGER.debug "BFM", "#{b[0]}\t#{File.basename(b[1][0])}\t#{b[1][3]}"
|
177
|
+
end
|
116
178
|
|
117
|
-
|
118
|
-
|
179
|
+
end
|
180
|
+
if daemon
|
181
|
+
LOGGER.info "BFM", "SLEEPING 10"
|
182
|
+
sleep DoroSettings.bfm[:sleeptime].to_i
|
183
|
+
end
|
184
|
+
infinite = daemon
|
185
|
+
end
|
119
186
|
|
120
|
-
|
121
|
-
|
122
|
-
LOGGER.warn "BFM", " The binary #{samplevalues[0]} has been already added on #{date}"
|
187
|
+
rescue SignalException #, RuntimeError
|
188
|
+
LOGGER.warn "BFM", "SIGINT".red + " Catched [1], exiting gracefully."
|
123
189
|
end
|
124
|
-
|
125
|
-
raise "A DB error occurred" unless db.insert("sightings", sighvalues)
|
126
|
-
|
127
|
-
# explanation: I don't want to insert/analyze the same malware but I do want to
|
128
|
-
# insert the sighting value anyway ("the malware X has been downloaded 1 time but
|
129
|
-
# has been spoted 32 times")
|
130
|
-
|
131
|
-
db.commit
|
132
|
-
db.close
|
133
|
-
true
|
134
|
-
|
135
190
|
end
|
136
191
|
|
137
|
-
|
138
|
-
|
139
192
|
end
|
140
193
|
|
141
194
|
end
|
data/lib/dorothy2/DEM.rb
CHANGED
@@ -54,12 +54,14 @@ module DoroParser
|
|
54
54
|
|
55
55
|
|
56
56
|
|
57
|
-
class SMTP #todo to redo
|
57
|
+
class SMTP #todo to redo ##NEW PARSER CODED BY SALVATORE
|
58
58
|
attr_reader :hcmd
|
59
59
|
attr_reader :hcont
|
60
60
|
attr_accessor :body
|
61
61
|
attr_accessor :rdata
|
62
62
|
|
63
|
+
|
64
|
+
|
63
65
|
def self.body(data)
|
64
66
|
email = TMail::Mail.parse(data)
|
65
67
|
return email
|
data/lib/dorothy2/NAM.rb
CHANGED
@@ -43,14 +43,14 @@ module Dorothy
|
|
43
43
|
|
44
44
|
def init_sniffer
|
45
45
|
Net::SSH.start(@server, @user, :password => @pass, :port =>@port) do |ssh|
|
46
|
-
ssh.exec "sudo killall tcpdump"
|
46
|
+
ssh.exec "nohup sudo killall tcpdump 2>/dev/null"
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
50
|
def stop_sniffer(pid)
|
51
51
|
Net::SSH.start(@server, @user, :password => @pass, :port =>@port) do |ssh|
|
52
52
|
ssh.exec "sudo kill -2 #{pid}"
|
53
|
-
|
53
|
+
LOGGER.debug "NAM", "Tcpdump instance #{pid} stopped"
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
data/lib/dorothy2/Settings.rb
CHANGED
@@ -10,7 +10,8 @@ module Dorothy
|
|
10
10
|
attr_reader :_settings
|
11
11
|
|
12
12
|
def load!(filename, options = {})
|
13
|
-
|
13
|
+
t = YAML::load_file(filename).extend DeepSymbolizable
|
14
|
+
newsets = t.deep_symbolize
|
14
15
|
newsets = newsets[options[:env].to_sym] if \
|
15
16
|
options[:env] && \
|
16
17
|
newsets[options[:env].to_sym]
|
data/lib/dorothy2/VSM.rb
CHANGED
@@ -106,7 +106,8 @@ module Dorothy
|
|
106
106
|
@pp2
|
107
107
|
end
|
108
108
|
|
109
|
-
def get_new_procs(current_procs,
|
109
|
+
def get_new_procs(current_procs, original_procs_file)
|
110
|
+
original_procs = YAML.load_file(original_procs_file)
|
110
111
|
@new_procs = Hash.new
|
111
112
|
current_procs.each_key {|pid|
|
112
113
|
@new_procs.merge!(Hash[pid, current_procs[pid]]) unless original_procs.has_key?(pid)
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# From https://gist.github.com/morhekil/998709
|
1
2
|
# Symbolizes all of hash's keys and subkeys.
|
2
3
|
# Also allows for custom pre-processing of keys (e.g. downcasing, etc)
|
3
4
|
# if the block is given:
|
@@ -13,10 +14,6 @@
|
|
13
14
|
|
14
15
|
module DeepSymbolizable
|
15
16
|
|
16
|
-
class Hash
|
17
|
-
include DeepSymbolizable
|
18
|
-
end
|
19
|
-
|
20
17
|
def deep_symbolize(&block)
|
21
18
|
method = self.class.to_s.downcase.to_sym
|
22
19
|
syms = DeepSymbolizable::Symbolizers
|
@@ -62,6 +59,4 @@ module DeepSymbolizable
|
|
62
59
|
end
|
63
60
|
end
|
64
61
|
|
65
|
-
end
|
66
|
-
|
67
|
-
class Hash; include DeepSymbolizable; end
|
62
|
+
end
|
data/lib/dorothy2/do-init.rb
CHANGED
@@ -19,6 +19,7 @@ module Dorothy
|
|
19
19
|
Dir.mkdir("#{home}/opt")
|
20
20
|
Dir.mkdir("#{home}/opt/bins")
|
21
21
|
Dir.mkdir("#{home}/opt/analyzed")
|
22
|
+
Dir.mkdir("#{home}/opt/analyzed/bins")
|
22
23
|
end
|
23
24
|
unless Util.exists?("#{home}/etc")
|
24
25
|
Dir.mkdir("#{home}/etc")
|
@@ -50,6 +51,8 @@ module Dorothy
|
|
50
51
|
conf["virustotal"] = Hash.new
|
51
52
|
conf["esx"] = Hash.new
|
52
53
|
conf["pcapr"] = Hash.new
|
54
|
+
conf["wgui"] = Hash.new
|
55
|
+
conf["bfm"] = Hash.new
|
53
56
|
|
54
57
|
|
55
58
|
################################################
|
@@ -64,14 +67,15 @@ module Dorothy
|
|
64
67
|
|
65
68
|
puts "The Dorothy home directory is #{home}"
|
66
69
|
|
67
|
-
conf["env"]["
|
70
|
+
conf["env"]["pidfiles"] = "#{home}/var"
|
68
71
|
conf["env"]["pidfile_parser"] = "#{home}/var/doroParser.pid"
|
69
72
|
conf["env"]["analysis_dir"] = "#{home}/opt/analyzed"
|
73
|
+
conf["env"]["bins_repository"] = "#{home}/opt/analyzed/bins"
|
70
74
|
conf["env"]["geoip"] = "#{home}/etc/geo/GeoLiteCity.dat"
|
71
75
|
conf["env"]["geoasn"] = "#{home}/etc/geo/GeoIPASNum.dat"
|
72
76
|
conf["env"]["geoisp"] = "#{home}/etc/geo/GeoIPISP.dat"
|
73
77
|
|
74
|
-
conf["env"]["
|
78
|
+
conf["env"]["sleeptime"] = 5
|
75
79
|
|
76
80
|
conf["env"]["logfile"] = "#{home}/var/log/dorothy.log"
|
77
81
|
conf["env"]["logfile_parser"] = "#{home}/var/log/parser.log"
|
@@ -120,19 +124,7 @@ module Dorothy
|
|
120
124
|
|
121
125
|
puts "\n######### [" + " Sandbox configuration settings ".red + "] #########"
|
122
126
|
|
123
|
-
puts "Insert the time (seconds) that the Sandbox should be run before it's reverted [60]"
|
124
|
-
conf["sandbox"]["sleeptime"] = (t = gets.chop).empty? ? 60 : t
|
125
127
|
|
126
|
-
puts "Insert how many screenshots do you want to take [1]"
|
127
|
-
conf["sandbox"]["num_screenshots"] = (t = gets.chop).empty? ? 1 : t.to_i
|
128
|
-
|
129
|
-
if conf["sandbox"]["num_screenshots"] > 1
|
130
|
-
puts "Insert the time interval (seconds) between each screenshot [5] "
|
131
|
-
conf["sandbox"]["screen2time"] = (t = gets.chop).empty? ? 5 : t
|
132
|
-
end
|
133
|
-
|
134
|
-
puts "After how many seconds do you want to take the first screenshot? [1]"
|
135
|
-
conf["sandbox"]["screen1time"] = (t = gets.chop).empty? ? 1 : t
|
136
128
|
|
137
129
|
puts "Which is the sandox's network? [10.10.10.0/0]"
|
138
130
|
conf["sandbox"]["network"] = (t = gets.chop).empty? ? "10.10.10.0/0" : t
|
@@ -158,7 +150,7 @@ module Dorothy
|
|
158
150
|
conf["nam"]["pass"] = gets.chop
|
159
151
|
|
160
152
|
puts "SSH Port [22] :"
|
161
|
-
conf["nam"]["port"] = (t = gets.chop).empty? ? 22 : t
|
153
|
+
conf["nam"]["port"] = (t = gets.chop).empty? ? 22 : t.to_i
|
162
154
|
|
163
155
|
puts "Folder where to store PCAP files [/home/#{conf["nam"]["user"]}/pcaps]"
|
164
156
|
conf["nam"]["pcaphome"] = (t = gets.chop).empty? ? "/home/#{conf["nam"]["user"]}/pcaps" : t
|
@@ -183,7 +175,30 @@ module Dorothy
|
|
183
175
|
end
|
184
176
|
|
185
177
|
puts "Pcapr HTTP Port [8080]:"
|
186
|
-
conf["pcapr"]["port"] = (t = gets.chop).empty? ? 8080 : t
|
178
|
+
conf["pcapr"]["port"] = (t = gets.chop).empty? ? 8080 : t.to_i
|
179
|
+
|
180
|
+
|
181
|
+
######################################################
|
182
|
+
###WebGUI
|
183
|
+
######################################################
|
184
|
+
puts "\n######### [" + " Web GUI configuration ".red + "] #########"
|
185
|
+
|
186
|
+
puts "IP Address used for listening. Use 0.0.0.0 to allow remote connections [localhost]:"
|
187
|
+
conf["wgui"]["host"] = (t = gets.chop).empty? ? 'localhost' : t.to_s
|
188
|
+
|
189
|
+
puts "TCP port [3435]:"
|
190
|
+
conf["wgui"]["port"] = (t = gets.chop).empty? ? 3435 : t.to_i
|
191
|
+
|
192
|
+
conf["wgui"]["environment"] = "production"
|
193
|
+
conf["wgui"]["logfile"] = "#{home}/var/log/webgui.log"
|
194
|
+
|
195
|
+
######################################################
|
196
|
+
###Binaries Fetcher Module
|
197
|
+
######################################################
|
198
|
+
puts "\n######### [" + " Binaries Fetcher Module ".red + "] #########"
|
199
|
+
|
200
|
+
puts "How often the BFM should pool all the resources (sec)? [60]"
|
201
|
+
conf["bfm"]["sleeptime"] = (t = gets.chop).empty? ? 60 : t.to_i
|
187
202
|
|
188
203
|
|
189
204
|
######################################################
|
@@ -212,8 +227,6 @@ module Dorothy
|
|
212
227
|
File.open("#{File.expand_path("~")}/.dorothy.yml", 'w+') {|f| f.write(conf.to_yaml) }
|
213
228
|
FileUtils.ln_s("#{File.expand_path("~")}/.dorothy.yml", "#{home}/etc/dorothy.yml") unless Util.exists?("#{home}/etc/dorothy.yml")
|
214
229
|
|
215
|
-
#copy the default extension file to the user-defined home
|
216
|
-
FileUtils.cp("#{HOME}/etc/extensions.yml", "#{home}/etc/extensions.yml")
|
217
230
|
correct = true
|
218
231
|
puts "Configuration file has been saved in ~/.dorothy.conf and a symlink has been created in\n#{home}/etc/dorothy.yml for an easier edit."
|
219
232
|
puts "\n######### [" + " Now you can restart dorothy, enjoy! ".yellow + "] #########"
|
@@ -231,6 +244,131 @@ module Dorothy
|
|
231
244
|
|
232
245
|
end
|
233
246
|
|
247
|
+
|
248
|
+
def create_profiles(filename, sandbox=false, vtotal=nil)
|
249
|
+
|
250
|
+
correct = false
|
251
|
+
conf = Hash.new
|
252
|
+
if sandbox
|
253
|
+
|
254
|
+
conf['default'] = {}
|
255
|
+
|
256
|
+
conf['default']['sleeptime'] = 60
|
257
|
+
vtotal ? conf['default']['vtotal_query'] = true : conf['default']['vtotal_query'] = false
|
258
|
+
|
259
|
+
|
260
|
+
conf['default']['screenshots'] = {}
|
261
|
+
conf['default']['screenshots']['number'] = 2
|
262
|
+
conf['default']['screenshots']['delay_first'] = 1
|
263
|
+
conf['default']['screenshots']['delay_inbetween'] = 30
|
264
|
+
|
265
|
+
|
266
|
+
|
267
|
+
conf['default']['OS'] = {}
|
268
|
+
conf['default']['OS']['type'] = sandbox['os']
|
269
|
+
conf['default']['OS']['version'] = sandbox['version']
|
270
|
+
conf['default']['OS']['lang'] = sandbox['os_lang']
|
271
|
+
|
272
|
+
|
273
|
+
|
274
|
+
conf['default']['extensions'] = {}
|
275
|
+
|
276
|
+
%w(exe bat html rtf).each do |ext|
|
277
|
+
conf['default']['extensions'][ext] = Hash.new
|
278
|
+
conf['default']['extensions'][ext]['prog_name'] = 'Windows CMD.exe'
|
279
|
+
conf['default']['extensions'][ext]['prog_path'] = 'C:\windows\system32\cmd.exe'
|
280
|
+
conf['default']['extensions'][ext]['prog_args'] = '/C'
|
281
|
+
end
|
282
|
+
|
283
|
+
|
284
|
+
File.open(filename, 'w+') {|f| f.write(conf.to_yaml) }
|
285
|
+
puts "Profiles have been saved in #{filename}\nYou can either modify such file directly. Enjoy!"
|
286
|
+
|
287
|
+
else
|
288
|
+
until correct
|
289
|
+
|
290
|
+
finished = false
|
291
|
+
|
292
|
+
until finished
|
293
|
+
|
294
|
+
puts "\n######### [" + " Profiles configuration ".red + "] #########"
|
295
|
+
|
296
|
+
puts "Please insert the unique name for this profile"
|
297
|
+
pname = gets.chop
|
298
|
+
|
299
|
+
conf[pname] = {}
|
300
|
+
conf[pname]['OS'] = {}
|
301
|
+
conf[pname]['screenshots'] = {}
|
302
|
+
conf[pname]['extensions'] = {}
|
303
|
+
|
304
|
+
puts "Please insert the information on the OS you want to associate with this profile. This info must reflect the one inserted into the sandboxes.yml file"
|
305
|
+
puts "OS Type (Windows|Linux) [Windows] "
|
306
|
+
conf[pname]["OS"]['type'] = (t = gets.chop).empty? ? 'Windows' : t
|
307
|
+
puts "OS Version: (e.g. XP SP3) [XP SP3]"
|
308
|
+
conf[pname]["OS"]['version'] = (t = gets.chop).empty? ? 'XP SP3' : t
|
309
|
+
puts "OS Language: [eng]"
|
310
|
+
conf[pname]["OS"]['lang'] = (t = gets.chop).empty? ? 'eng' : t
|
311
|
+
|
312
|
+
puts "Sandbox parameters"
|
313
|
+
puts "Insert the time (seconds) that the Sandbox should be run before it's reverted [60]"
|
314
|
+
conf[pname]["sleeptime"] = (t = gets.chop).empty? ? 60 : t
|
315
|
+
|
316
|
+
puts "Insert how many screenshots do you want to take [1]"
|
317
|
+
conf[pname]['screenshots']["number"] = (t = gets.chop).empty? ? 1 : t.to_i
|
318
|
+
|
319
|
+
if conf[pname]["num_screenshots"] > 1
|
320
|
+
puts "Insert the time interval (seconds) between each screenshot [5] "
|
321
|
+
conf[pname]["screenshots"]['delay_inbetween'] = (t = gets.chop).empty? ? 5 : t.to_i
|
322
|
+
end
|
323
|
+
|
324
|
+
puts "After how many seconds do you want to take the first screenshot? [1]"
|
325
|
+
conf[pname]["screenshots"]['delay_first'] = (t = gets.chop).empty? ? 1 : t.to_i
|
326
|
+
|
327
|
+
|
328
|
+
puts "Enable Virus Total queries? VT API key must be in .dorothy.yml [y]"
|
329
|
+
t = gets.chop
|
330
|
+
(t.empty? || t == "y" || t == "yes") ? conf[pname]["vtotal_query"] = true : conf[pname]["vtotal_query"] = false
|
331
|
+
|
332
|
+
puts "Adding basic extensions (exe, bat, html, rtf)"
|
333
|
+
|
334
|
+
%w(exe bat html rtf).each do |ext|
|
335
|
+
conf[pname]['extensions'][ext] = Hash.new
|
336
|
+
conf[pname]['extensions'][ext]['prog_name'] = 'Windows CMD.exe'
|
337
|
+
conf[pname]['extensions'][ext]['prog_name'] = 'C:\windows\system32\cmd.exe'
|
338
|
+
conf[pname]['extensions'][ext]['prog_name'] = '/C'
|
339
|
+
end
|
340
|
+
|
341
|
+
puts "Profiles configured. Want you to configure another one? [n]"
|
342
|
+
t = gets.chop
|
343
|
+
|
344
|
+
if t == "y" || t == "yes"
|
345
|
+
finished = false
|
346
|
+
else
|
347
|
+
finished = true
|
348
|
+
end
|
349
|
+
|
350
|
+
end
|
351
|
+
|
352
|
+
puts "Configuration finished"
|
353
|
+
puts "Confirm? [y]"
|
354
|
+
t = gets.chop
|
355
|
+
puts t
|
356
|
+
|
357
|
+
if t.empty? || t == "y" || t == "yes"
|
358
|
+
File.open(filename, 'w+') {|f| f.write(conf.to_yaml) }
|
359
|
+
correct = true
|
360
|
+
puts "Profiles have been saved in #{filename}\nYou can either modify such file directly. Enjoy!"
|
361
|
+
else
|
362
|
+
puts "Please reinsert the info"
|
363
|
+
correct = false
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
|
370
|
+
|
371
|
+
|
234
372
|
#Creates the sandbox configuration file
|
235
373
|
def create_sandbox(sboxfile)
|
236
374
|
|
@@ -305,6 +443,135 @@ module Dorothy
|
|
305
443
|
end
|
306
444
|
end
|
307
445
|
|
446
|
+
|
447
|
+
|
448
|
+
#Creates the Source configuration file
|
449
|
+
def create_sources(sourcesfile = DoroSettings.env[:home] + '/etc/sources.yml')
|
450
|
+
|
451
|
+
correct = false
|
452
|
+
|
453
|
+
until correct
|
454
|
+
|
455
|
+
conf = Hash.new
|
456
|
+
|
457
|
+
#Add WGUI as default source
|
458
|
+
|
459
|
+
conf['webgui'] = Hash.new
|
460
|
+
conf['webgui']["type"] = 'web'
|
461
|
+
conf['webgui']["typeid"] = 1
|
462
|
+
conf['webgui']["localdir"] = DoroSettings.env[:home] + '/opt/bins/webgui'
|
463
|
+
conf['webgui']["priority"] = 3
|
464
|
+
conf['webgui']["profile"] = 'default'
|
465
|
+
|
466
|
+
finished = false
|
467
|
+
|
468
|
+
until finished
|
469
|
+
puts "Please insert a unique name for the binary source you want to add"
|
470
|
+
sname = gets.chop
|
471
|
+
|
472
|
+
conf[sname] = Hash.new
|
473
|
+
|
474
|
+
puts "Please specify the binary source type (system|ssh|mail) [system]"
|
475
|
+
conf[sname]["type"] = (t = gets.chop).empty? ? "system" : t
|
476
|
+
puts ">" + conf[sname]["type"]
|
477
|
+
|
478
|
+
case conf[sname]["type"]
|
479
|
+
when "system" then
|
480
|
+
puts "Please specify the system folder where are located the binaries [#{DoroSettings.env[:home]}/opt/bins/#{sname}]"
|
481
|
+
conf[sname]["localdir"] = (t = gets.chop).empty? ? "#{DoroSettings.env[:home]}/opt/bins/#{sname}" : t
|
482
|
+
when "mail" then
|
483
|
+
puts "Please specify the IP address/hostname of the mail server (e.g. pop-mail.outlook.com)"
|
484
|
+
conf[sname]["address"] = gets.chop
|
485
|
+
|
486
|
+
puts "Please specify the username used for the authentication"
|
487
|
+
conf[sname]["username"] = gets.chop
|
488
|
+
|
489
|
+
puts "Please specify the password used for the authentication"
|
490
|
+
conf[sname]["password"] = gets.chop
|
491
|
+
|
492
|
+
puts "Please specify the TCP port used by the mailserver [993]"
|
493
|
+
conf[sname]["port"] = (t = gets.chop).empty? ? 993 : t.to_i
|
494
|
+
puts ">" + conf[sname]["port"].to_s
|
495
|
+
|
496
|
+
puts "Is SSL required for this mailbox (true|false)? [true]"
|
497
|
+
t = (gets.chop == "false" ? false : true)
|
498
|
+
conf[sname]["enable_ssl"] = t
|
499
|
+
puts ">" + conf[sname]["enable_ssl"].to_s
|
500
|
+
|
501
|
+
puts "How many emails do you want to retreive during every request? [3]"
|
502
|
+
conf[sname]["n_emails"] = (t = gets.chop).empty? ? 3 : t.to_i
|
503
|
+
puts ">" + conf[sname]["n_emails"].to_s
|
504
|
+
|
505
|
+
puts "Do you want to delete the emails from the server once downloaded? [true] (Warning, if false, Dorothy wont understand which email is new. Put false only for development/testing)"
|
506
|
+
t = (gets.chop == "false" ? false : true)
|
507
|
+
conf[sname]["delete_once_downloaded"] = t
|
508
|
+
puts ">" + conf[sname]["delete_once_downloaded"].to_s
|
509
|
+
|
510
|
+
puts "Please specify the system folder where the attachments will be temporaly copied into [#{DoroSettings.env[:home]}/opt/bins/#{sname}]"
|
511
|
+
conf[sname]["localdir"] = (t = gets.chop).empty? ? "#{DoroSettings.env[:home]}/opt/bins/#{sname}" : t
|
512
|
+
|
513
|
+
when "ssh" then
|
514
|
+
puts "Please specify the IP address/hostname of the remote server"
|
515
|
+
conf[sname]["host"] = gets.chop
|
516
|
+
|
517
|
+
puts "Please specify the ssh TCP port of the remote server [22]"
|
518
|
+
conf[sname]["port"] = (t = gets.chop).empty? ? 22 : t.to_i
|
519
|
+
puts ">" + conf[sname]["port"].to_s
|
520
|
+
|
521
|
+
puts "Please specify the username used for the authentication"
|
522
|
+
conf[sname]["username"] = gets.chop
|
523
|
+
|
524
|
+
puts "Please specify the password used for the authentication"
|
525
|
+
conf[sname]["password"] = gets.chop
|
526
|
+
|
527
|
+
puts "Please specify the remote path where the binaries are"
|
528
|
+
conf[sname]["remotedir"] = gets.chop
|
529
|
+
|
530
|
+
puts "Please specify the system folder where the binaries will be temporaly copied into [#{DoroSettings.env[:home]}/opt/bins/#{sname}]"
|
531
|
+
conf[sname]["localdir"] = (t = gets.chop).empty? ? "#{DoroSettings.env[:home]}/opt/bins/#{sname}" : t
|
532
|
+
end
|
533
|
+
|
534
|
+
|
535
|
+
puts "Please specify the priority of this source. 1 is the lowest [1]"
|
536
|
+
conf[sname]["priority"] = (t = gets.chop).empty? ? 1 : t.to_i
|
537
|
+
puts ">" + conf[sname]["priority"].to_s
|
538
|
+
|
539
|
+
puts "Please specify which analysis profile you want to associate with this source. [default]"
|
540
|
+
conf[sname]["profile"] = (t = gets.chop).empty? ? "default" : t
|
541
|
+
puts ">" + conf[sname]["profile"]
|
542
|
+
|
543
|
+
|
544
|
+
puts "Binary source added. Do you want to add another one? [n]"
|
545
|
+
t = gets.chop
|
546
|
+
|
547
|
+
if t == "y" || t == "yes"
|
548
|
+
finished = false
|
549
|
+
else
|
550
|
+
finished = true
|
551
|
+
end
|
552
|
+
|
553
|
+
|
554
|
+
end
|
555
|
+
|
556
|
+
puts "Configuration finished"
|
557
|
+
puts "Confirm? [y]"
|
558
|
+
t = gets.chop
|
559
|
+
puts t
|
560
|
+
|
561
|
+
if t.empty? || t == "y" || t == "yes"
|
562
|
+
File.open(sourcesfile, 'w+') {|f| f.write(conf.to_yaml) }
|
563
|
+
correct = true
|
564
|
+
puts "Configuration file has been saved in #{sourcesfile}\nYou can either modify such file directly. Enjoy!"
|
565
|
+
else
|
566
|
+
puts "Please reinsert the info"
|
567
|
+
correct = false
|
568
|
+
end
|
569
|
+
|
570
|
+
end
|
571
|
+
end
|
572
|
+
|
573
|
+
|
574
|
+
|
308
575
|
#This method will populate the dorothive table sandboxes
|
309
576
|
def init_sandbox(file="../etc/sandboxes.yml")
|
310
577
|
conf = YAML.load_file(file)
|
@@ -312,7 +579,7 @@ module Dorothy
|
|
312
579
|
db = Insertdb.new
|
313
580
|
db.begin_t
|
314
581
|
|
315
|
-
LOGGER.warn "INIT", "
|
582
|
+
LOGGER.warn "INIT", "Warning, the SandBox table is gonna be flushed, and updated with the new file"
|
316
583
|
db.flush_table("sandboxes")
|
317
584
|
|
318
585
|
conf.each_key do |sbox|
|