dvash 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +674 -0
- data/bin/dvash +0 -2
- data/dvash.gemspec +12 -23
- data/lib/dvash.rb +12 -21
- data/lib/dvash/application.rb +32 -49
- data/lib/dvash/core.rb +96 -116
- data/lib/dvash/honeyports/ipv4/http.rb +26 -37
- data/lib/dvash/honeyports/ipv4/rdp.rb +26 -37
- data/lib/dvash/honeyports/ipv4/ssh.rb +26 -37
- data/lib/dvash/honeyports/ipv4/telnet.rb +26 -37
- data/lib/dvash/honeyports/ipv6/http.rb +26 -37
- data/lib/dvash/honeyports/ipv6/rdp.rb +26 -37
- data/lib/dvash/honeyports/ipv6/ssh.rb +26 -37
- data/lib/dvash/os/linux.rb +42 -64
- data/lib/dvash/os/mac.rb +24 -28
- data/lib/dvash/os/windows.rb +23 -24
- metadata +5 -21
- data/etc/dvash-baseline.conf +0 -48
data/bin/dvash
CHANGED
data/dvash.gemspec
CHANGED
@@ -1,34 +1,23 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
|
+
# Variables:
|
4
5
|
s.name = "dvash"
|
5
|
-
s.version = "0.1.
|
6
|
-
|
7
|
-
s.
|
8
|
-
s.authors = ["Ari Mizrahi"]
|
9
|
-
s.date = "2013-05-02"
|
6
|
+
s.version = "0.1.1"
|
7
|
+
s.authors = "Ari Mizrahi"
|
8
|
+
s.date = "2013-07-21"
|
10
9
|
s.description = "Part honeypot, part defense system. Opens up ports and simulates services in order to look like an attractive target. Hosts that try to connect to the fake services are considered attackers and blocked from all access."
|
10
|
+
s.summary = "Honeypot defense system"
|
11
11
|
s.email = "codemunchies@gmail.com"
|
12
|
-
s.executables = ["dvash"]
|
13
|
-
s.files = ["etc/dvash-baseline.conf", "lib/dvash/honeyports/ipv4/http.rb", "lib/dvash/honeyports/ipv4/rdp.rb", "lib/dvash/honeyports/ipv4/ssh.rb", "lib/dvash/honeyports/ipv4/telnet.rb", "lib/dvash/honeyports/ipv6/http.rb", "lib/dvash/honeyports/ipv6/rdp.rb", "lib/dvash/honeyports/ipv6/ssh.rb", "lib/dvash/os/linux.rb", "lib/dvash/os/mac.rb", "lib/dvash/os/windows.rb", "lib/dvash/application.rb", "lib/dvash/core.rb", "lib/dvash.rb", "dvash.gemspec", "Gemfile", "README.md"]
|
14
12
|
s.homepage = "http://github.com/codemunchies/dvash"
|
15
|
-
s.require_paths = ["lib"]
|
16
|
-
s.rubygems_version = "1.8.25"
|
17
|
-
s.summary = "Honeypot defense system"
|
18
13
|
s.license = "GPL-3"
|
19
14
|
|
20
|
-
|
21
|
-
|
15
|
+
# Pragmatically Gathered
|
16
|
+
s.executables = "dvash"
|
17
|
+
s.files = Dir["{lib,bin}/**/*"]
|
18
|
+
s.files += [File.basename(__FILE__), "Gemfile", "README.md", "LICENSE"]
|
19
|
+
s.require_paths = ["lib"]
|
22
20
|
|
23
|
-
|
24
|
-
|
25
|
-
s.add_runtime_dependency(%q<bundler>, ["~> 1.3"])
|
26
|
-
else
|
27
|
-
s.add_dependency(%q<parseconfig>, ["~> 1.0"])
|
28
|
-
s.add_dependency(%q<bundler>, ["~> 1.3"])
|
29
|
-
end
|
30
|
-
else
|
31
|
-
s.add_dependency(%q<parseconfig>, ["~> 1.0"])
|
32
|
-
s.add_dependency(%q<bundler>, ["~> 1.3"])
|
33
|
-
end
|
21
|
+
# Dependencies
|
22
|
+
s.add_dependency("parseconfig", "~> 1.0")
|
34
23
|
end
|
data/lib/dvash.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'dvash/application'
|
2
|
-
|
3
2
|
require 'optparse'
|
4
3
|
|
5
4
|
#
|
@@ -20,48 +19,40 @@ require 'optparse'
|
|
20
19
|
#
|
21
20
|
|
22
21
|
module Dvash
|
23
|
-
|
22
|
+
# Start the CLI and instantiate [Dvash]
|
23
|
+
# @params [Hash] instantiate paths to set default config values
|
24
24
|
def self.start(paths={})
|
25
25
|
|
26
|
-
#
|
27
26
|
# Set default path to config and log files
|
28
|
-
# TODO: These settings assume Linux default paths, should determine the
|
29
|
-
#
|
27
|
+
# TODO: These settings assume Linux default paths, it should determine the
|
28
|
+
# operating system then configure accordingly
|
30
29
|
paths[:config_path] = '/etc/dvash.conf'
|
31
30
|
paths[:log_path] = '/var/log/dvash.conf'
|
32
31
|
|
33
|
-
#
|
34
|
-
# A command-line interface using OptionParser
|
35
|
-
#
|
32
|
+
# Command-line interface
|
36
33
|
OptionParser.new do |opts|
|
37
|
-
|
34
|
+
# Banner information
|
35
|
+
opts.banner = "Dvash 0.1.1 ( http://www.github.com/codemunchies/dvash )\n"
|
38
36
|
opts.banner += "Usage: dvash [options]"
|
39
|
-
#
|
40
|
-
# Option to set an alternate configuration file
|
41
|
-
#
|
37
|
+
# Set an alternate configuration file
|
42
38
|
opts.on("--config-file [PATH]", "Set path to config file") do |arg|
|
43
39
|
paths[:config_path] = arg
|
44
40
|
end
|
45
|
-
#
|
46
|
-
# Option to set an alternate log file destination and filename
|
47
|
-
#
|
41
|
+
# Set an alternate log file destination and filename
|
48
42
|
opts.on("--log-file [PATH]", "Set path to log file") do |arg|
|
49
43
|
paths[:log_path] = arg
|
50
44
|
end
|
51
45
|
end.parse!
|
52
46
|
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
47
|
+
# Create and start an application instance on Dvash
|
48
|
+
# @return [Dvash] application instance
|
56
49
|
begin
|
57
50
|
application = Dvash::Application.new(paths)
|
58
51
|
application.start
|
59
52
|
rescue
|
60
|
-
# TODO: Use
|
53
|
+
# TODO: Use [logger] gem to output debug information
|
61
54
|
puts "couldn't start application"
|
62
55
|
exit
|
63
56
|
end
|
64
|
-
|
65
|
-
|
66
57
|
end
|
67
58
|
end
|
data/lib/dvash/application.rb
CHANGED
@@ -1,57 +1,40 @@
|
|
1
1
|
require 'dvash/core'
|
2
|
-
|
3
2
|
require 'parseconfig'
|
4
3
|
|
5
4
|
module Dvash
|
5
|
+
#
|
6
|
+
# Main application methods, the glue that holds it all together
|
7
|
+
#
|
8
|
+
class Application < Core
|
6
9
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
#
|
20
|
-
# Load passed Array paths into @paths for use in the class
|
21
|
-
#
|
22
|
-
@paths = paths
|
23
|
-
#
|
24
|
-
# Call method to load the configuration file
|
25
|
-
#
|
26
|
-
load_conf
|
27
|
-
#
|
28
|
-
# Call method to validate the operating system and load necessary Dvash methods
|
29
|
-
#
|
30
|
-
validate_os
|
31
|
-
end
|
32
|
-
|
33
|
-
#
|
34
|
-
# Fire in the hole!
|
35
|
-
#
|
36
|
-
def start
|
37
|
-
#
|
38
|
-
# Make sure we are running with elevated privileges
|
39
|
-
#
|
40
|
-
unless valid_user?
|
41
|
-
# TODO: Use 'logger' gem to output debug information
|
42
|
-
puts "invalid user"
|
43
|
-
exit
|
44
|
-
end
|
10
|
+
# Methods that should run when [Dvash] is created
|
11
|
+
# @params [Hash] includes paths to config and log file
|
12
|
+
def initialize(paths)
|
13
|
+
# Instantiate @honey_threads [Array] to hold all honeyport threads
|
14
|
+
@honey_threads = Array.new
|
15
|
+
# Load passed [paths]
|
16
|
+
@paths = paths
|
17
|
+
# Load the configuration file
|
18
|
+
load_conf
|
19
|
+
# Validate the operating system and load necessary [Dvash] methods
|
20
|
+
validate_os
|
21
|
+
end
|
45
22
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
23
|
+
# Fire in the hole!
|
24
|
+
def start
|
25
|
+
# Make sure we are running with elevated privileges
|
26
|
+
unless valid_user?
|
27
|
+
# TODO: Use [logger] gem to output debug information
|
28
|
+
puts "invalid user"
|
29
|
+
exit
|
30
|
+
end
|
31
|
+
# Load all honeyports set true in the configuration file
|
32
|
+
load_honeyport
|
33
|
+
# Let the user know we're running
|
34
|
+
puts "Dvash is running..."
|
35
|
+
# Start all loaded threads
|
36
|
+
@honey_threads.each { |thr| thr.join }
|
37
|
+
end
|
55
38
|
|
56
|
-
|
39
|
+
end
|
57
40
|
end
|
data/lib/dvash/core.rb
CHANGED
@@ -2,128 +2,108 @@ require 'ipaddr'
|
|
2
2
|
require 'securerandom'
|
3
3
|
|
4
4
|
module Dvash
|
5
|
+
#
|
6
|
+
# Core class contains methods all other classes depend on to function properly.
|
7
|
+
#
|
8
|
+
class Core
|
5
9
|
|
6
|
-
|
10
|
+
# Validates user
|
11
|
+
# We must be root to create entries in the firewall
|
12
|
+
# @return [Boolean] true|false
|
13
|
+
def valid_user?
|
14
|
+
Process.uid == 0
|
15
|
+
end
|
7
16
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
17
|
+
# Validates an IP address
|
18
|
+
# IP Address should be valid IPv4 or IPv6 addresses
|
19
|
+
# @return [Boolean] true|false
|
20
|
+
def valid_ip?(address)
|
21
|
+
begin
|
22
|
+
IPAddr.new("#{address}")
|
23
|
+
true
|
24
|
+
rescue
|
25
|
+
false
|
26
|
+
end
|
27
|
+
end
|
14
28
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
29
|
+
# Validates the operating system
|
30
|
+
# OS must be Windows 7+, OS X, or Linux
|
31
|
+
# Creates a new instance of the operating system specific Dvash libraries
|
32
|
+
# required to block IP addresses properly, @@os is used as a class variable
|
33
|
+
# to call its methods from within a Honeyport
|
34
|
+
def validate_os
|
35
|
+
# Rubygems platform data
|
36
|
+
system = RUBY_PLATFORM
|
37
|
+
# Use regular expressions to determine operating system
|
38
|
+
case system
|
39
|
+
# WINDOWS
|
40
|
+
when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
41
|
+
# Create Dvash Windows object for use within 'honeyports' modules
|
42
|
+
require 'dvash/os/windows'
|
43
|
+
@@os = Dvash::Windows.new
|
44
|
+
# MAC OS X
|
45
|
+
when /darwin|mac os/
|
46
|
+
# Create Dvash Mac OS X object for use within 'honeyports' modules
|
47
|
+
require 'dvash/os/mac'
|
48
|
+
@@os = Dvash::Mac.new
|
49
|
+
# LINUX
|
50
|
+
when /linux/
|
51
|
+
# Create Dvash Linux object for use within 'honeyports' modules
|
52
|
+
require 'dvash/os/linux'
|
53
|
+
@@os = Dvash::Linux.new
|
54
|
+
# BSD
|
55
|
+
when /solaris|bsd/
|
56
|
+
# TODO: BSD support
|
57
|
+
exit
|
58
|
+
else
|
59
|
+
# TODO: Use [logger] gem to output debug information
|
60
|
+
puts "invalid operating system"
|
61
|
+
exit
|
62
|
+
end
|
63
|
+
end
|
26
64
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
#
|
38
|
-
# Use regular expressions to determine operating system
|
39
|
-
#
|
40
|
-
case system
|
41
|
-
# WINDOWS
|
42
|
-
when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
43
|
-
#
|
44
|
-
# Create Dvash Windows object for use within 'honeyports' modules
|
45
|
-
#
|
46
|
-
require 'dvash/os/windows'
|
47
|
-
@@os = Dvash::Windows.new
|
48
|
-
# MAC OS X
|
49
|
-
when /darwin|mac os/
|
50
|
-
#
|
51
|
-
# Create Dvash Mac OS X object for use within 'honeyports' modules
|
52
|
-
#
|
53
|
-
require 'dvash/os/mac'
|
54
|
-
@@os = Dvash::Mac.new
|
55
|
-
# LINUX
|
56
|
-
when /linux/
|
57
|
-
#
|
58
|
-
# Create Dvash Linux object for use within 'honeyports' modules
|
59
|
-
#
|
60
|
-
require 'dvash/os/linux'
|
61
|
-
@@os = Dvash::Linux.new
|
62
|
-
# BSD
|
63
|
-
when /solaris|bsd/
|
64
|
-
# TODO: BSD support
|
65
|
-
exit
|
66
|
-
else
|
67
|
-
# TODO: Use 'logger' gem to output debug information
|
68
|
-
puts "invalid operating system"
|
69
|
-
exit
|
70
|
-
end
|
71
|
-
end
|
65
|
+
# Loads the configuration file using [ParseConfig]
|
66
|
+
def load_conf
|
67
|
+
begin
|
68
|
+
@@cfgfile = ParseConfig.new(@paths[:config_path])
|
69
|
+
rescue
|
70
|
+
# TODO: Use 'logger' gem to output debug information
|
71
|
+
puts "invalid configuration file"
|
72
|
+
exit
|
73
|
+
end
|
74
|
+
end
|
72
75
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
76
|
+
# Load all Honeyports set true in the configuration file
|
77
|
+
def load_honeyport
|
78
|
+
# Read honeyports group in configuration file, parse keys and values
|
79
|
+
@@cfgfile['honeyports'].each do |key, value|
|
80
|
+
if value == 'true' then
|
81
|
+
ipver, proto = key.split("_")
|
82
|
+
# Load methods for all honeyports set true
|
83
|
+
begin
|
84
|
+
require "dvash/honeyports/#{ipver}/#{proto}"
|
85
|
+
rescue
|
86
|
+
# TODO: Use [logger] gem to output debug information
|
87
|
+
puts "couldn't load dvash/honeyports/#{ipver}/#{proto}"
|
88
|
+
exit
|
89
|
+
end
|
90
|
+
# Push the loaded honeyport into a thread
|
91
|
+
@honey_threads << Thread.new { Dvash::Honeyport.new.send(key) }
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
85
95
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
# Read 'honeyports' group in configuration file, parse keys and values
|
92
|
-
#
|
93
|
-
@@cfgfile['honeyports'].each do |key, value|
|
94
|
-
if value == 'true' then
|
95
|
-
ipver, proto = key.split("_")
|
96
|
-
#
|
97
|
-
# Load methods for all 'honeyports' set to 'true'
|
98
|
-
#
|
99
|
-
begin
|
100
|
-
require "dvash/honeyports/#{ipver}/#{proto}"
|
101
|
-
rescue
|
102
|
-
# TODO: Use 'logger' gem to output debug information
|
103
|
-
puts "couldn't load dvash/honeyports/#{ipver}/#{proto}"
|
104
|
-
exit
|
105
|
-
end
|
106
|
-
#
|
107
|
-
# Push the loaded 'honeyport' into a thread
|
108
|
-
#
|
109
|
-
@honey_threads << Thread.new { Dvash::Honeyport.new.send(key) }
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
96
|
+
# Generate a random string 64 bytes long
|
97
|
+
# @return [String] random bytes
|
98
|
+
def random_data
|
99
|
+
SecureRandom.random_bytes(64)
|
100
|
+
end
|
113
101
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
end
|
102
|
+
# Client source IP address in a [TCPServer]
|
103
|
+
# @return [String] client IP
|
104
|
+
def client_ip(client)
|
105
|
+
client.peeraddr[3]
|
106
|
+
end
|
120
107
|
|
121
|
-
|
122
|
-
# Return the client source IP address from a TCPServer object
|
123
|
-
#
|
124
|
-
def client_ip(client)
|
125
|
-
client.peeraddr[3]
|
126
|
-
end
|
127
|
-
|
128
|
-
end
|
108
|
+
end
|
129
109
|
end
|
@@ -9,43 +9,32 @@
|
|
9
9
|
#
|
10
10
|
###############################################################################
|
11
11
|
module Dvash
|
12
|
+
#
|
13
|
+
# Main Honeyport class to simulate daemons
|
14
|
+
#
|
15
|
+
class Honeyport < Core
|
12
16
|
|
13
|
-
|
17
|
+
def ipv4_http
|
18
|
+
# IPv4 TCPServer object
|
19
|
+
# @return [TCPServer] tcp/80 HTTPd
|
20
|
+
server = TCPServer.new(80)
|
21
|
+
# Infinite listening loop
|
22
|
+
loop do
|
23
|
+
# Fork a new instance of [TCPServer] when a client connects
|
24
|
+
Thread.fork(server.accept) do |client|
|
25
|
+
# Validate client has a valid IP address
|
26
|
+
# @return [Boolean] true|false
|
27
|
+
if valid_ip?(client_ip(client)) then
|
28
|
+
# Send the connected client junk data
|
29
|
+
client.puts(random_data)
|
30
|
+
# Block the IP address
|
31
|
+
@@os.block_ip(client_ip(client))
|
32
|
+
end
|
33
|
+
# Close the connection to the client and kill the forked process
|
34
|
+
client.close
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
14
38
|
|
15
|
-
|
16
|
-
#
|
17
|
-
# Create a new IPv4 TCPServer object
|
18
|
-
#
|
19
|
-
server = TCPServer.new(80)
|
20
|
-
#
|
21
|
-
# Infinite loop listens on port 80 pretending to be an HTTP server
|
22
|
-
#
|
23
|
-
loop do
|
24
|
-
#
|
25
|
-
# Fork a new instance of the TCPServer object when a client connects
|
26
|
-
# TODO: Maybe we should not send junk data until after the client IP has been validated
|
27
|
-
#
|
28
|
-
Thread.fork(server.accept) do |client|
|
29
|
-
#
|
30
|
-
# Send the connected client junk data
|
31
|
-
#
|
32
|
-
client.puts(random_data)
|
33
|
-
#
|
34
|
-
# Make sure the client has a valid IP address
|
35
|
-
#
|
36
|
-
if valid_ip?(client_ip(client)) then
|
37
|
-
#
|
38
|
-
# Block the IP address
|
39
|
-
#
|
40
|
-
@@os.block_ip(client_ip(client))
|
41
|
-
end
|
42
|
-
#
|
43
|
-
# Close the connection to the client and kill the forked process
|
44
|
-
#
|
45
|
-
client.close
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
39
|
+
end
|
51
40
|
end
|