dorothy2 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +85 -19
- data/bin/dorothy_start +1 -1
- data/bin/dparser_start +13 -8
- data/lib/doroParser.rb +10 -3
- data/lib/dorothy2.rb +3 -2
- data/lib/dorothy2/{do-parsers.rb → DEM.rb} +0 -0
- data/lib/dorothy2/NAM.rb +40 -0
- data/lib/dorothy2/VSM.rb +131 -0
- data/lib/dorothy2/do-init.rb +12 -5
- data/lib/dorothy2/do-utils.rb +77 -1
- data/lib/dorothy2/version.rb +1 -1
- metadata +6 -5
- data/lib/dorothy2/MAM.rb +0 -239
data/README.md
CHANGED
@@ -2,23 +2,35 @@
|
|
2
2
|
|
3
3
|
A malware/botnet analysis framework written in Ruby.
|
4
4
|
|
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).
|
5
6
|
|
6
7
|
##Introduction
|
7
8
|
|
8
9
|
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.
|
9
10
|
However, static binary analysis and system behavior analysis will be shortly introduced in the next version.
|
10
11
|
|
11
|
-
Dorothy2 is a continuation of my degree's final project ([Dorothy: inside the Storm](https://www.honeynet.it/wp-content/uploads/Dorothy/The_Dorothy_Project.pdf) ) that I presented on Feb 2009.
|
12
|
+
Dorothy2 is a continuation of my Bachelor degree's final project ([Dorothy: inside the Storm](https://www.honeynet.it/wp-content/uploads/Dorothy/The_Dorothy_Project.pdf) ) that I presented on Feb 2009.
|
12
13
|
The main framework's structure remained almost the same, and it has been fully detailed in my degree's final project or in this short [paper](http://www.honeynet.it/wp-content/uploads/Dorothy/EC2ND-Dorothy.pdf). More information about the whole project can be found on the Italian Honeyproject [website](http://www.honeynet.it).
|
13
14
|
|
14
15
|
|
15
16
|
The framework is manly composed by four big elements that can be even executed separately:
|
16
17
|
|
17
|
-
* The Dorothy analysis engine (this gem)
|
18
|
-
|
18
|
+
* The Dorothy analysis engine (included in this gem)
|
19
|
+
|
20
|
+
In charge of executing a binary file into a sandbox, and then storing the generated network traffic and its screenshots into the analysis folder (moreover populating Dorothive with the basic information of the file, and CouchDB with the network pcaps).
|
21
|
+
|
22
|
+
* The (network) Data Extraction Module aka dparser (included in this gem)
|
23
|
+
|
24
|
+
In charge of dissecting the pcaps file, and storing the most relevant information (flows data, GeoIP info, etc) into Dorothive. In addition, it extracts all the files downloaded by the sandbox through HTTP/HTTPS and store them into the binary file's analysis folder.
|
25
|
+
|
19
26
|
* The Webgui (Coded in Rails by Andrea Valerio, and not yet included in this gem)
|
27
|
+
|
28
|
+
(Working in progress) A rails application which allows to have an interactive overview on all the acquired data. For a first glance on Andrea's first PoC take a look [this](http://youtu.be/W4DdMYPp4Ws) video (commented in Italian).
|
29
|
+
|
20
30
|
* The Java Dorothy Drone (Mainly coded by Patrizia Martemucci and Domenico Chiarito, but not part of this gem and not publicly available.)
|
21
31
|
|
32
|
+
Our botnet infiltration module, refers to this [ppt](https://www.honeynet.it/wp-content/uploads/Presentations/JDrone.pptx) presentation for an overview.
|
33
|
+
|
22
34
|
The first three modules are (or will be soon) publicly released under GPL 2/3 license as tribute to the the [Honeynet Project Alliance](http://www.honeynet.org).
|
23
35
|
All the information generated by the framework - i.e. binary info, timestamps, dissected network analysis - are stored into a postgres DB (Dorothive) in order to be used for further analysis.
|
24
36
|
A no-SQL database (CouchDB) is also used to mass strore all the traffic dumps thanks to the [pcapr/xtractr](https://code.google.com/p/pcapr/wiki/Xtractr) technology.
|
@@ -70,26 +82,61 @@ It is recommended to follow this step2step process:
|
|
70
82
|
* Configure a static IP
|
71
83
|
* After configuring everything on the Guest OS, create a snapshot of the sandbox VM from vSphere console. Dorothy will use it when reverting the VM after a binary execution.
|
72
84
|
|
73
|
-
3.
|
74
|
-
* Configure the NIC on the virtual machine that will be used for the network sniffing purpose (NAM).
|
75
|
-
>The vSwitch where the vNIC resides must allow the promisc mode, to enable it from vSphere:
|
76
|
-
|
77
|
-
>Configuration->Networking->Proprieties on the vistualSwitch used for the analysis->Double click on the virtual network used for the analysis->Securiry->Tick "Promiscuous Mode", then select "Accept" from the list menu.
|
85
|
+
3. From vSphere, create a unix VM dedicated to the NAM
|
78
86
|
|
79
87
|
|
80
88
|
* Install tcpdump and sudo
|
81
89
|
|
82
|
-
|
90
|
+
#apt-get install tcpdump sudo
|
83
91
|
|
84
92
|
* Create a dedicated user for dorothy (e.g. "dorothy")
|
85
93
|
|
86
|
-
|
94
|
+
#useradd dorothy
|
95
|
+
|
96
|
+
* Create a directory inside the dorothy user's home where storing the network dumps
|
97
|
+
|
98
|
+
#su dorothy
|
99
|
+
$mkdir /home/dorothy/pcaps
|
87
100
|
|
88
101
|
* Add dorothy's user permission to execute/kill tcpdump to the sudoers file:
|
89
102
|
|
90
|
-
|
91
|
-
|
92
|
-
|
103
|
+
#visudo
|
104
|
+
add the following line:
|
105
|
+
dorothy ALL = NOPASSWD: /usr/sbin/tcpdump, /bin/kill
|
106
|
+
|
107
|
+
* If you want to install pcapr on this machine (recommended) install also these packages (refer to this blog [post](https://github.com/pcapr-local/pcapr-local) for a detailed howto)
|
108
|
+
|
109
|
+
#apt-get install ruby1.8 rubygems tshark zip couchdb
|
110
|
+
|
111
|
+
* Start the couchdb server
|
112
|
+
|
113
|
+
#/etc/init.d/couchdb start
|
114
|
+
|
115
|
+
* Install pcapr-local
|
116
|
+
|
117
|
+
#gem install pcapr-local
|
118
|
+
|
119
|
+
* Start pcapr-local by using the dorothy's account and configure it. When prompted, insert the folder path used to store the network dumps
|
120
|
+
|
121
|
+
$startpcapr
|
122
|
+
....
|
123
|
+
Which directory would you like to scan for indexable pcaps? [/root/pcapr.Local/pcaps]
|
124
|
+
/home/dorothy/pcaps
|
125
|
+
|
126
|
+
In addition, remember to allow pcapr to run on all the interfaces
|
127
|
+
|
128
|
+
What IP address should pcapr.Local run on? Use 0.0.0.0 to listen on all interfaces [127.0.0.1]
|
129
|
+
0.0.0.0
|
130
|
+
|
131
|
+
* If everything went fine, you should be able to browse to
|
132
|
+
|
133
|
+
http//{ip-used-by-NAM}:8000
|
134
|
+
|
135
|
+
4 From vSphere, configure the NIC on the virtual machine that will be used for the network sniffing purpose (NAM).
|
136
|
+
>The vSwitch where the vNIC resides must allow the promisc mode, to enable it from vSphere:
|
137
|
+
|
138
|
+
>Configuration->Networking->Proprieties on the vistualSwitch used for the analysis->Double click on the virtual network used for the analysis->Securiry->Tick "Promiscuous Mode", then select "Accept" from the list menu.
|
139
|
+
|
93
140
|
|
94
141
|
#### * Sample Setups
|
95
142
|
1. Basic setup
|
@@ -114,7 +161,10 @@ or
|
|
114
161
|
|
115
162
|
http://www.postgresql.org/download/
|
116
163
|
|
117
|
-
2. Configure a dedicated postgres user for Dorothy (or use
|
164
|
+
2. Configure a dedicated postgres user for Dorothy (or use the default postgres user instead, up to you :)
|
165
|
+
|
166
|
+
> Note:
|
167
|
+
> If you want to use Postgres "as is", and then configure Dorothy to use "postgres" degault the user, configure a password for this user at least (by default it comes with no password)
|
118
168
|
|
119
169
|
3. Install the following packages
|
120
170
|
|
@@ -125,7 +175,7 @@ or
|
|
125
175
|
$ brew install libmagic
|
126
176
|
$ brew link libmagic
|
127
177
|
|
128
|
-
|
178
|
+
4. Install the xtractr gem, for a detailed howto, go [here](https://code.google.com/p/pcapr/wiki/Xtractr).
|
129
179
|
|
130
180
|
### 3. Install Dorothy gem
|
131
181
|
|
@@ -164,8 +214,9 @@ The first time you execute Dorothy, it will ask you to fill those information in
|
|
164
214
|
|
165
215
|
## Usage
|
166
216
|
|
167
|
-
|
168
|
-
|
217
|
+
### Dorothy usage:
|
218
|
+
|
219
|
+
$dorothy_start [options]
|
169
220
|
where [options] are:
|
170
221
|
--verbose, -v: Enable verbose mode
|
171
222
|
--infoflow, -i: Print the analysis flow
|
@@ -177,9 +228,24 @@ The first time you execute Dorothy, it will ask you to fill those information in
|
|
177
228
|
|
178
229
|
|
179
230
|
>Example
|
231
|
+
>
|
232
|
+
$dorothy_start -v -s malwarefolder
|
233
|
+
|
234
|
+
### DoroParser usage:
|
235
|
+
|
236
|
+
$dparser_start [options]
|
237
|
+
where [options] are:
|
238
|
+
--verbose, -v: Enable verbose mode
|
239
|
+
--nonetbios, -n: Hide Netbios communication
|
240
|
+
--daemon, -d: Stay in the backroud, by constantly pooling datasources
|
241
|
+
--help, -h: Show this message
|
242
|
+
|
243
|
+
>Example
|
244
|
+
>
|
245
|
+
$dparser_start -d start
|
246
|
+
$dparser_stop
|
180
247
|
|
181
|
-
|
182
|
-
> $dorothy_stop
|
248
|
+
If executed in daemon mode, DoroParser will poll the database every X seconds (where X is defined by the "dtimeout:" field in the configuration file) looking for new pcaps that has been inserted.
|
183
249
|
|
184
250
|
###6. Debugging problems
|
185
251
|
|
data/bin/dorothy_start
CHANGED
data/bin/dparser_start
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
# Copyright (C) 2013 marco riccardi.
|
4
|
-
# This file is part of Dorothy - http://www.honeynet.it/
|
4
|
+
# This file is part of Dorothy - http://www.honeynet.it/
|
5
5
|
# See the file 'LICENSE' for copying permission.
|
6
6
|
|
7
7
|
require 'rubygems'
|
@@ -18,17 +18,22 @@ include DoroParser
|
|
18
18
|
|
19
19
|
opts = Trollop.options do
|
20
20
|
banner <<-EOS
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
|
22
|
+
####################################################
|
23
|
+
## ##
|
24
|
+
## The Dorothy Malware Analysis Framework 2.0 ##
|
25
|
+
## ##
|
26
|
+
####################################################
|
27
|
+
|
28
|
+
marco.riccardi@honeynet.it
|
29
|
+
www.honeynet.it/dorothy
|
30
|
+
|
31
|
+
|
26
32
|
Usage:
|
27
|
-
|
33
|
+
dparser_start [options]
|
28
34
|
where [options] are:
|
29
35
|
EOS
|
30
36
|
|
31
|
-
|
32
37
|
opt :verbose, "Enable verbose mode"
|
33
38
|
opt :nonetbios, "Hide Netbios communication"
|
34
39
|
opt :daemon, "Stay in the backroud, by constantly pooling datasources"
|
data/lib/doroParser.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Copyright (C) 2010-2013 marco riccardi.
|
2
|
-
# This file is part of Dorothy - http://www.honeynet.it/
|
2
|
+
# This file is part of Dorothy - http://www.honeynet.it/
|
3
3
|
# See the file 'LICENSE' for copying permission.
|
4
4
|
|
5
5
|
#!/usr/local/bin/ruby
|
@@ -8,6 +8,14 @@
|
|
8
8
|
|
9
9
|
#Install mu/xtractr from svn checkout http://pcapr.googlecode.com/svn/trunk/ pcapr-read-only
|
10
10
|
|
11
|
+
|
12
|
+
|
13
|
+
############################
|
14
|
+
## Dorothy ##
|
15
|
+
## Data Definition Module ##
|
16
|
+
############################
|
17
|
+
|
18
|
+
|
11
19
|
require 'rubygems'
|
12
20
|
require 'mu/xtractr'
|
13
21
|
require 'md5'
|
@@ -17,7 +25,6 @@ require 'net/dns'
|
|
17
25
|
require 'net/dns/packet'
|
18
26
|
require 'ipaddr'
|
19
27
|
require 'colored'
|
20
|
-
require 'trollop'
|
21
28
|
require 'ftools'
|
22
29
|
require 'filemagic' #require 'pcaplet'
|
23
30
|
require 'geoip'
|
@@ -27,7 +34,7 @@ require 'tmail'
|
|
27
34
|
require 'ipaddr'
|
28
35
|
|
29
36
|
require File.dirname(__FILE__) + '/dorothy2/environment'
|
30
|
-
require File.dirname(__FILE__) + '/dorothy2/
|
37
|
+
require File.dirname(__FILE__) + '/dorothy2/DEM'
|
31
38
|
require File.dirname(__FILE__) + '/dorothy2/do-utils'
|
32
39
|
require File.dirname(__FILE__) + '/dorothy2/do-logger'
|
33
40
|
require File.dirname(__FILE__) + '/dorothy2/deep_symbolize'
|
data/lib/dorothy2.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Copyright (C) 2010-2013 marco riccardi.
|
2
|
-
# This file is part of Dorothy - http://www.honeynet.it/
|
2
|
+
# This file is part of Dorothy - http://www.honeynet.it/
|
3
3
|
# See the file 'LICENSE' for copying permission.
|
4
4
|
|
5
5
|
##for irb debug:
|
@@ -29,7 +29,8 @@ require File.dirname(__FILE__) + '/dorothy2/Settings'
|
|
29
29
|
require File.dirname(__FILE__) + '/dorothy2/deep_symbolize'
|
30
30
|
require File.dirname(__FILE__) + '/dorothy2/environment'
|
31
31
|
require File.dirname(__FILE__) + '/dorothy2/vtotal'
|
32
|
-
require File.dirname(__FILE__) + '/dorothy2/
|
32
|
+
require File.dirname(__FILE__) + '/dorothy2/VSM'
|
33
|
+
require File.dirname(__FILE__) + '/dorothy2/NAM'
|
33
34
|
require File.dirname(__FILE__) + '/dorothy2/BFM'
|
34
35
|
require File.dirname(__FILE__) + '/dorothy2/do-utils'
|
35
36
|
require File.dirname(__FILE__) + '/dorothy2/do-logger'
|
File without changes
|
data/lib/dorothy2/NAM.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# Copyright (C) 2010-2013 marco riccardi.
|
2
|
+
# This file is part of Dorothy - http://www.honeynet.it/
|
3
|
+
# See the file 'LICENSE' for copying permission.
|
4
|
+
|
5
|
+
module Dorothy
|
6
|
+
|
7
|
+
#Dorothy module-class for controlling the network sniffers i.e. tcpdump instances
|
8
|
+
class Doro_NAM
|
9
|
+
|
10
|
+
#Create a dotothy user in the NSM machine, and add this line to the sudoers :
|
11
|
+
# dorothy ALL = NOPASSWD: /usr/sbin/tcpdump, /bin/kill
|
12
|
+
#
|
13
|
+
|
14
|
+
def initialize(namdata)
|
15
|
+
@server = namdata[:host]
|
16
|
+
@user= namdata[:user]
|
17
|
+
@pass= namdata[:pass]
|
18
|
+
@port = namdata[:port]
|
19
|
+
end
|
20
|
+
|
21
|
+
def start_sniffer(vmaddress, interface, name, pcaphome)
|
22
|
+
Net::SSH.start(@server, @user, :password => @pass, :port =>@port) do |@ssh|
|
23
|
+
# @ssh.exec "nohup sudo tcpdump -i eth0 -s 1514 -w ~/pcaps/#{name}.pcap host #{vmaddress} > blah.log 2>&1 & "
|
24
|
+
@ssh.exec "nohup sudo tcpdump -i #{interface} -s 1514 -w #{pcaphome}/#{name}.pcap host #{vmaddress} > log.tmp 2>&1 & "
|
25
|
+
t = @ssh.exec!"ps aux |grep #{vmaddress}|grep -v grep|grep -v bash"
|
26
|
+
pid = t.split(" ")[1]
|
27
|
+
return pid.to_i
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def stop_sniffer(pid)
|
32
|
+
Net::SSH.start(@server, @user, :password => @pass, :port =>@port) do |ssh|
|
33
|
+
ssh.exec "sudo kill -2 #{pid}"
|
34
|
+
#LOGGER.info "[NAM]".yellow + "Tcpdump instance #{pid} stopped"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
data/lib/dorothy2/VSM.rb
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
# Copyright (C) 2010-2013 marco riccardi.
|
2
|
+
# This file is part of Dorothy - http://www.honeynet.it/
|
3
|
+
# See the file 'LICENSE' for copying permission.
|
4
|
+
|
5
|
+
module Dorothy
|
6
|
+
|
7
|
+
#Dorothy module-class for managig the virtual sandboxes
|
8
|
+
class Doro_VSM
|
9
|
+
|
10
|
+
#ESX5 interface
|
11
|
+
class ESX
|
12
|
+
|
13
|
+
#Creates a new instance for communicating with ESX through the vSpere5's API
|
14
|
+
def initialize(server,user,pass,vmname,guestuser,guestpass)
|
15
|
+
|
16
|
+
begin
|
17
|
+
vim = RbVmomi::VIM.connect(:host => server , :user => user, :password=> pass, :insecure => true)
|
18
|
+
rescue Timeout::Error
|
19
|
+
raise "Fail to connect to the ESXi server #{server} - TimeOut (Are you sure that is the right address?)"
|
20
|
+
end
|
21
|
+
|
22
|
+
@server = server
|
23
|
+
dc = vim.serviceInstance.find_datacenter
|
24
|
+
@vm = dc.find_vm(vmname)
|
25
|
+
|
26
|
+
raise "Virtual Machine #{vmname} not present within ESX!!" if @vm.nil?
|
27
|
+
|
28
|
+
om = vim.serviceContent.guestOperationsManager
|
29
|
+
am = om.authManager
|
30
|
+
@pm = om.processManager
|
31
|
+
@fm = om.fileManager
|
32
|
+
|
33
|
+
#AUTHENTICATION
|
34
|
+
guestauth = {:interactiveSession => false, :username => guestuser, :password => guestpass}
|
35
|
+
@auth=RbVmomi::VIM::NamePasswordAuthentication(guestauth)
|
36
|
+
abort if am.ValidateCredentialsInGuest(:vm => @vm, :auth => @auth) != nil
|
37
|
+
end
|
38
|
+
|
39
|
+
def revert_vm
|
40
|
+
@vm.RevertToCurrentSnapshot_Task
|
41
|
+
end
|
42
|
+
|
43
|
+
def copy_file(filename,file)
|
44
|
+
filepath = "C:\\#{filename}" #put md5 hash
|
45
|
+
|
46
|
+
begin
|
47
|
+
url = @fm.InitiateFileTransferToGuest(:vm => @vm, :auth=> @auth, :guestFilePath=> filepath, :fileSize => file.size, :fileAttributes => '', :overwrite => true).sub('*:443', @server)
|
48
|
+
|
49
|
+
RestClient.put(url, file)
|
50
|
+
|
51
|
+
rescue RbVmomi::Fault
|
52
|
+
LOGGER.error "VSM", "Fail to copy the file #{file} to #{@vm}: #{$!}"
|
53
|
+
abort
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
def exec_file(filename, arguments="")
|
59
|
+
filepath = "C:\\#{filename}"
|
60
|
+
|
61
|
+
if File.extname(filename) == ".dll"
|
62
|
+
cmd = { :programPath => "C:\\windows\\system32\\rundll32.exe", :arguments => filepath}
|
63
|
+
LOGGER.info "VSM", ".:: Executing dll #{filename}"
|
64
|
+
|
65
|
+
else
|
66
|
+
cmd = { :programPath => filepath, :arguments => arguments }
|
67
|
+
end
|
68
|
+
|
69
|
+
pid = @pm.StartProgramInGuest(:vm => @vm , :auth => @auth, :spec => cmd )
|
70
|
+
pid.to_i
|
71
|
+
end
|
72
|
+
|
73
|
+
def check_internet
|
74
|
+
exec_file("windows\\system32\\ping.exe", "-n 1 www.google.com") #make www.google.com customizable, move to doroconf
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
def get_status(pid)
|
79
|
+
p = @pm.ListProcessesInGuest(:vm => @vm , :auth => @auth, :pids => Array(pid) ).inspect
|
80
|
+
status = (p =~ /exitCode=>([0-9])/ ? $1.to_i : nil )
|
81
|
+
return status
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
def screenshot
|
86
|
+
a = @vm.CreateScreenshot_Task.wait_for_completion.split(" ")
|
87
|
+
ds = @vm.datastore.find { |ds| ds.name == a[0].delete("[]")}
|
88
|
+
screenpath = "/vmfs/volumes/" + a[0].delete("[]") + "/" + a[1]
|
89
|
+
return screenpath
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
#Empty method for showing how it could be easy to extend the dorothy's VSM with another virtual manager.
|
94
|
+
class VirtualBox
|
95
|
+
def initialize
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
def revert_vm
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
def copy_file
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
def exec_file
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
def check_internet
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
def get_status
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
def screenshot
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
|
131
|
+
|
data/lib/dorothy2/do-init.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Copyright (C) 2010-2013 marco riccardi.
|
2
|
-
# This file is part of Dorothy - http://www.honeynet.it/
|
2
|
+
# This file is part of Dorothy - http://www.honeynet.it/
|
3
3
|
# See the file 'LICENSE' for copying permission.
|
4
4
|
|
5
5
|
module Dorothy
|
@@ -80,9 +80,6 @@ module Dorothy
|
|
80
80
|
conf["env"]["loglevel"] = 0
|
81
81
|
conf["env"]["logage"] = "weekly"
|
82
82
|
|
83
|
-
conf["env"]["testmode"] = true
|
84
|
-
|
85
|
-
|
86
83
|
|
87
84
|
######################################################
|
88
85
|
###DOROTHIVE
|
@@ -104,7 +101,6 @@ module Dorothy
|
|
104
101
|
|
105
102
|
conf["dorothive"]["ddl"] = "#{HOME}/etc/ddl/dorothive.ddl"
|
106
103
|
|
107
|
-
|
108
104
|
######################################################
|
109
105
|
###ESX
|
110
106
|
######################################################
|
@@ -182,6 +178,17 @@ module Dorothy
|
|
182
178
|
puts "In order to retrieve Virus signatures, Dorothy needs to contact VirusTotal,\n please enter your VT API key here, if you don't have one yet, go here (or press enter):\nhttps://www.virustotal.com/en/#dlg-join "
|
183
179
|
conf["virustotal"]["vtapikey"] = gets.chop
|
184
180
|
|
181
|
+
puts "Enable test mode? In test mode dorothy will avoid to poll Virustotal [y]"
|
182
|
+
|
183
|
+
t = gets.chop
|
184
|
+
if t.empty? || t == "y" || t == "yes"
|
185
|
+
conf["env"]["testmode"] = true
|
186
|
+
else
|
187
|
+
conf["env"]["testmode"] = false
|
188
|
+
end
|
189
|
+
|
190
|
+
##########CONF FINISHED##################
|
191
|
+
|
185
192
|
puts "\n######### [" + " Configuration finished ".yellow + "] #########"
|
186
193
|
puts "Confirm? [y]"
|
187
194
|
|
data/lib/dorothy2/do-utils.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Copyright (C) 2010-2013 marco riccardi.
|
2
|
-
# This file is part of Dorothy - http://www.honeynet.it/
|
2
|
+
# This file is part of Dorothy - http://www.honeynet.it/
|
3
3
|
# See the file 'LICENSE' for copying permission.
|
4
4
|
|
5
5
|
module Dorothy
|
@@ -220,4 +220,80 @@ module Dorothy
|
|
220
220
|
|
221
221
|
end
|
222
222
|
|
223
|
+
class Loadmalw
|
224
|
+
attr_reader :pcaprid
|
225
|
+
attr_reader :type
|
226
|
+
attr_reader :dbtype
|
227
|
+
attr_accessor :sha
|
228
|
+
attr_reader :md5
|
229
|
+
attr_reader :binpath
|
230
|
+
attr_reader :filename
|
231
|
+
attr_reader :ctime
|
232
|
+
attr_reader :size
|
233
|
+
attr_reader :pcapsize
|
234
|
+
attr_reader :extension
|
235
|
+
attr_accessor :sourceinfo #used for storing info about where the binary come from (if needed)
|
236
|
+
|
237
|
+
# attr_accessor :dir_home
|
238
|
+
attr_accessor :dir_pcap
|
239
|
+
attr_accessor :dir_bin
|
240
|
+
attr_accessor :dir_screens
|
241
|
+
attr_accessor :dir_downloads
|
242
|
+
|
243
|
+
def initialize(file)
|
244
|
+
|
245
|
+
fm = FileMagic.new
|
246
|
+
sha = Digest::SHA2.new
|
247
|
+
md5 = Digest::MD5.new
|
248
|
+
@binpath = file
|
249
|
+
@filename = File.basename file
|
250
|
+
@extension = File.extname file
|
251
|
+
@dbtype = "null" #TODO: remove type column in sample table
|
252
|
+
|
253
|
+
File.open(file, 'rb') do |fh1|
|
254
|
+
while buffer1 = fh1.read(1024)
|
255
|
+
@sha = sha << buffer1
|
256
|
+
@md5 = md5 << buffer1
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
@sha = @sha.to_s
|
261
|
+
@md5 = @md5.to_s.rstrip
|
262
|
+
@sourceinfo = nil
|
263
|
+
|
264
|
+
timetmp = File.ctime(file)
|
265
|
+
@ctime= timetmp.strftime("%m/%d/%y %H:%M:%S")
|
266
|
+
@type = fm.file(file)
|
267
|
+
|
268
|
+
if @extension.empty? #no extension, trying to put the right one..
|
269
|
+
case @type
|
270
|
+
when /^PE32/ then
|
271
|
+
@extension = (@type =~ /DLL/ ? ".dll" : ".exe")
|
272
|
+
when /^MS-DOS/ then
|
273
|
+
@extension = ".bat"
|
274
|
+
when /^HTML/ then
|
275
|
+
@extension = ".html"
|
276
|
+
else
|
277
|
+
@extension = nil
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
|
282
|
+
@size = File.size(file)
|
283
|
+
end
|
284
|
+
|
285
|
+
|
286
|
+
|
287
|
+
def self.calc_pcaprid(file, size)
|
288
|
+
#t = file.split('/')
|
289
|
+
#dumpname = t[t.length - 1]
|
290
|
+
@pcaprid = Digest::MD5.new
|
291
|
+
@pcaprid << "#{file}:#{size}"
|
292
|
+
@pcaprid = @pcaprid.dup.to_s.rstrip
|
293
|
+
end
|
294
|
+
|
295
|
+
|
296
|
+
end
|
297
|
+
|
298
|
+
|
223
299
|
end
|
data/lib/dorothy2/version.rb
CHANGED
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:
|
4
|
+
hash: 25
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 3
|
10
|
+
version: 0.0.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- marco riccardi
|
@@ -257,12 +257,13 @@ files:
|
|
257
257
|
- lib/doroParser.rb
|
258
258
|
- lib/dorothy2.rb
|
259
259
|
- lib/dorothy2/BFM.rb
|
260
|
-
- lib/dorothy2/
|
260
|
+
- lib/dorothy2/DEM.rb
|
261
|
+
- lib/dorothy2/NAM.rb
|
261
262
|
- lib/dorothy2/Settings.rb
|
263
|
+
- lib/dorothy2/VSM.rb
|
262
264
|
- lib/dorothy2/deep_symbolize.rb
|
263
265
|
- lib/dorothy2/do-init.rb
|
264
266
|
- lib/dorothy2/do-logger.rb
|
265
|
-
- lib/dorothy2/do-parsers.rb
|
266
267
|
- lib/dorothy2/do-utils.rb
|
267
268
|
- lib/dorothy2/environment.rb
|
268
269
|
- lib/dorothy2/version.rb
|
data/lib/dorothy2/MAM.rb
DELETED
@@ -1,239 +0,0 @@
|
|
1
|
-
# Copyright (C) 2010-2013 marco riccardi.
|
2
|
-
# This file is part of Dorothy - http://www.honeynet.it/dorothy
|
3
|
-
# See the file 'LICENSE' for copying permission.
|
4
|
-
|
5
|
-
module Dorothy
|
6
|
-
|
7
|
-
class Doro_VSM
|
8
|
-
|
9
|
-
#Creates a new instance for communicating with ESX through the vSpere5's API
|
10
|
-
class ESX
|
11
|
-
|
12
|
-
def initialize(server,user,pass,vmname,guestuser,guestpass)
|
13
|
-
|
14
|
-
begin
|
15
|
-
vim = RbVmomi::VIM.connect(:host => server , :user => user, :password=> pass, :insecure => true)
|
16
|
-
rescue Timeout::Error
|
17
|
-
raise "Fail to connect to the ESXi server #{server} - TimeOut (Are you sure that is the right address?)"
|
18
|
-
end
|
19
|
-
|
20
|
-
@server = server
|
21
|
-
dc = vim.serviceInstance.find_datacenter
|
22
|
-
@vm = dc.find_vm(vmname)
|
23
|
-
|
24
|
-
raise "Virtual Machine #{vmname} not present within ESX!!" if @vm.nil?
|
25
|
-
|
26
|
-
om = vim.serviceContent.guestOperationsManager
|
27
|
-
am = om.authManager
|
28
|
-
@pm = om.processManager
|
29
|
-
@fm = om.fileManager
|
30
|
-
|
31
|
-
#AUTHENTICATION
|
32
|
-
guestauth = {:interactiveSession => false, :username => guestuser, :password => guestpass}
|
33
|
-
@auth=RbVmomi::VIM::NamePasswordAuthentication(guestauth)
|
34
|
-
abort if am.ValidateCredentialsInGuest(:vm => @vm, :auth => @auth) != nil
|
35
|
-
end
|
36
|
-
|
37
|
-
def revert_vm
|
38
|
-
@vm.RevertToCurrentSnapshot_Task
|
39
|
-
end
|
40
|
-
|
41
|
-
def copy_file(filename,file)
|
42
|
-
filepath = "C:\\#{filename}" #put md5 hash
|
43
|
-
|
44
|
-
begin
|
45
|
-
url = @fm.InitiateFileTransferToGuest(:vm => @vm, :auth=> @auth, :guestFilePath=> filepath, :fileSize => file.size, :fileAttributes => '', :overwrite => true).sub('*:443', @server)
|
46
|
-
|
47
|
-
RestClient.put(url, file)
|
48
|
-
|
49
|
-
rescue RbVmomi::Fault
|
50
|
-
LOGGER.error "VSM", "Fail to copy the file #{file} to #{@vm}: #{$!}"
|
51
|
-
abort
|
52
|
-
end
|
53
|
-
|
54
|
-
end
|
55
|
-
|
56
|
-
def exec_file(filename, arguments="")
|
57
|
-
filepath = "C:\\#{filename}"
|
58
|
-
|
59
|
-
if File.extname(filename) == ".dll"
|
60
|
-
cmd = { :programPath => "C:\\windows\\system32\\rundll32.exe", :arguments => filepath}
|
61
|
-
LOGGER.info "VSM", ".:: Executing dll #{filename}"
|
62
|
-
|
63
|
-
else
|
64
|
-
cmd = { :programPath => filepath, :arguments => arguments }
|
65
|
-
end
|
66
|
-
|
67
|
-
pid = @pm.StartProgramInGuest(:vm => @vm , :auth => @auth, :spec => cmd )
|
68
|
-
pid.to_i
|
69
|
-
end
|
70
|
-
|
71
|
-
def check_internet
|
72
|
-
exec_file("windows\\system32\\ping.exe", "-n 1 www.google.com") #make www.google.com customizable, move to doroconf
|
73
|
-
end
|
74
|
-
|
75
|
-
|
76
|
-
def get_status(pid)
|
77
|
-
p = @pm.ListProcessesInGuest(:vm => @vm , :auth => @auth, :pids => Array(pid) ).inspect
|
78
|
-
status = (p =~ /exitCode=>([0-9])/ ? $1.to_i : nil )
|
79
|
-
return status
|
80
|
-
end
|
81
|
-
|
82
|
-
|
83
|
-
def screenshot
|
84
|
-
a = @vm.CreateScreenshot_Task.wait_for_completion.split(" ")
|
85
|
-
ds = @vm.datastore.find { |ds| ds.name == a[0].delete("[]")}
|
86
|
-
screenpath = "/vmfs/volumes/" + a[0].delete("[]") + "/" + a[1]
|
87
|
-
return screenpath
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
#TODO. Example of how a new VSM´s structure should look like
|
92
|
-
class VirtualBox
|
93
|
-
def initialize
|
94
|
-
|
95
|
-
end
|
96
|
-
|
97
|
-
def revert_vm
|
98
|
-
|
99
|
-
end
|
100
|
-
|
101
|
-
def copy_file
|
102
|
-
|
103
|
-
end
|
104
|
-
|
105
|
-
def exec_file
|
106
|
-
|
107
|
-
end
|
108
|
-
|
109
|
-
def check_internet
|
110
|
-
|
111
|
-
end
|
112
|
-
|
113
|
-
def get_status
|
114
|
-
|
115
|
-
end
|
116
|
-
|
117
|
-
def screenshot
|
118
|
-
|
119
|
-
end
|
120
|
-
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
class Loadmalw
|
125
|
-
attr_reader :pcaprid
|
126
|
-
attr_reader :type
|
127
|
-
attr_reader :dbtype
|
128
|
-
attr_accessor :sha
|
129
|
-
attr_reader :md5
|
130
|
-
attr_reader :binpath
|
131
|
-
attr_reader :filename
|
132
|
-
attr_reader :ctime
|
133
|
-
attr_reader :size
|
134
|
-
attr_reader :pcapsize
|
135
|
-
attr_reader :extension
|
136
|
-
attr_accessor :sourceinfo #used for storing info about where the binary come from (if needed)
|
137
|
-
|
138
|
-
# attr_accessor :dir_home
|
139
|
-
attr_accessor :dir_pcap
|
140
|
-
attr_accessor :dir_bin
|
141
|
-
attr_accessor :dir_screens
|
142
|
-
attr_accessor :dir_downloads
|
143
|
-
|
144
|
-
def initialize(file)
|
145
|
-
|
146
|
-
fm = FileMagic.new
|
147
|
-
sha = Digest::SHA2.new
|
148
|
-
md5 = Digest::MD5.new
|
149
|
-
@binpath = file
|
150
|
-
@filename = File.basename file
|
151
|
-
@extension = File.extname file
|
152
|
-
@dbtype = "null" #TODO: remove type column in sample table
|
153
|
-
|
154
|
-
File.open(file, 'rb') do |fh1|
|
155
|
-
while buffer1 = fh1.read(1024)
|
156
|
-
@sha = sha << buffer1
|
157
|
-
@md5 = md5 << buffer1
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
@sha = @sha.to_s
|
162
|
-
@md5 = @md5.to_s.rstrip
|
163
|
-
@sourceinfo = nil
|
164
|
-
|
165
|
-
timetmp = File.ctime(file)
|
166
|
-
@ctime= timetmp.strftime("%m/%d/%y %H:%M:%S")
|
167
|
-
@type = fm.file(file)
|
168
|
-
|
169
|
-
if @extension.empty? #no extension, trying to put the right one..
|
170
|
-
case @type
|
171
|
-
when /^PE32/ then
|
172
|
-
@extension = (@type =~ /DLL/ ? ".dll" : ".exe")
|
173
|
-
when /^MS-DOS/ then
|
174
|
-
@extension = ".bat"
|
175
|
-
when /^HTML/ then
|
176
|
-
@extension = ".html"
|
177
|
-
else
|
178
|
-
@extension = nil
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
|
183
|
-
@size = File.size(file)
|
184
|
-
# @dir_pcap = "#{ANALYSIS_DIR}/#{@md5}/pcap/"
|
185
|
-
# @dir_bin = "#{ANALYSIS_DIR}/#{@md5}/bin/"
|
186
|
-
# @dir_screens = "#{ANALYSIS_DIR}/#{@md5}/screens/"
|
187
|
-
# @dir_downloads = "#{ANALYSIS_DIR}/#{@md5}/downloads/"
|
188
|
-
end
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
def self.calc_pcaprid(file, size)
|
193
|
-
#t = file.split('/')
|
194
|
-
#dumpname = t[t.length - 1]
|
195
|
-
@pcaprid = Digest::MD5.new
|
196
|
-
@pcaprid << "#{file}:#{size}"
|
197
|
-
@pcaprid = @pcaprid.dup.to_s.rstrip
|
198
|
-
end
|
199
|
-
|
200
|
-
|
201
|
-
end
|
202
|
-
|
203
|
-
class Doro_NAM
|
204
|
-
|
205
|
-
#Create a dotothy user in the NSM machine, and add this line to the sudoers :
|
206
|
-
# dorothy ALL = NOPASSWD: /usr/sbin/tcpdump, /bin/kill
|
207
|
-
#
|
208
|
-
|
209
|
-
def initialize(namdata)
|
210
|
-
@server = namdata[:host]
|
211
|
-
@user= namdata[:user]
|
212
|
-
@pass= namdata[:pass]
|
213
|
-
@port = namdata[:port]
|
214
|
-
end
|
215
|
-
|
216
|
-
def start_sniffer(vmaddress, interface, name, pcaphome)
|
217
|
-
Net::SSH.start(@server, @user, :password => @pass, :port =>@port) do |@ssh|
|
218
|
-
# @ssh.exec "nohup sudo tcpdump -i eth0 -s 1514 -w ~/pcaps/#{name}.pcap host #{vmaddress} > blah.log 2>&1 & "
|
219
|
-
@ssh.exec "nohup sudo tcpdump -i #{interface} -s 1514 -w #{pcaphome}/#{name}.pcap host #{vmaddress} > log.tmp 2>&1 & "
|
220
|
-
t = @ssh.exec!"ps aux |grep #{vmaddress}|grep -v grep|grep -v bash"
|
221
|
-
pid = t.split(" ")[1]
|
222
|
-
return pid.to_i
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
def stop_sniffer(pid)
|
227
|
-
Net::SSH.start(@server, @user, :password => @pass, :port =>@port) do |ssh|
|
228
|
-
ssh.exec "sudo kill -2 #{pid}"
|
229
|
-
#LOGGER.info "[NAM]".yellow + "Tcpdump instance #{pid} stopped"
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
|
-
end
|
234
|
-
|
235
|
-
end
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|