dvash 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/dvash.gemspec +2 -2
- data/lib/dvash.rb +23 -8
- data/lib/dvash/application.rb +33 -4
- data/lib/dvash/{validation.rb → core.rb} +37 -3
- data/lib/dvash/honeyports/ipv4/http.rb +23 -2
- data/lib/dvash/honeyports/ipv6/http.rb +24 -3
- data/lib/dvash/os/linux.rb +36 -10
- data/lib/dvash/os/mac.rb +9 -1
- data/lib/dvash/os/windows.rb +6 -3
- metadata +2 -2
data/dvash.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "dvash"
|
5
|
-
s.version = "0.0.
|
5
|
+
s.version = "0.0.4"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Ari Mizrahi"]
|
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
|
|
10
10
|
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."
|
11
11
|
s.email = "codemunchies@gmail.com"
|
12
12
|
s.executables = ["dvash"]
|
13
|
-
s.files = ["etc/dvash-baseline.conf", "lib/dvash/honeyports/ipv4/http.rb", "lib/dvash/honeyports/ipv6/http.rb", "lib/dvash/os/linux.rb", "lib/dvash/os/mac.rb", "lib/dvash/os/windows.rb", "lib/dvash/application.rb", "lib/dvash/
|
13
|
+
s.files = ["etc/dvash-baseline.conf", "lib/dvash/honeyports/ipv4/http.rb", "lib/dvash/honeyports/ipv6/http.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"]
|
14
14
|
s.homepage = "http://github.com/codemunchies/dvash"
|
15
15
|
s.require_paths = ["lib"]
|
16
16
|
s.rubygems_version = "1.8.25"
|
data/lib/dvash.rb
CHANGED
@@ -2,6 +2,7 @@ require 'dvash/application'
|
|
2
2
|
|
3
3
|
require 'optparse'
|
4
4
|
|
5
|
+
#
|
5
6
|
# Dvash Defense
|
6
7
|
#
|
7
8
|
# Written By: Ari Mizrahi
|
@@ -12,37 +13,51 @@ require 'optparse'
|
|
12
13
|
#
|
13
14
|
# Heavily inspired by The Artillery Project by Dave Kennedy (ReL1K) with a
|
14
15
|
# passion for ruby and a thirst for knowledge.
|
16
|
+
#
|
15
17
|
|
16
18
|
module Dvash
|
17
19
|
|
18
|
-
# Start a new Dvash instance
|
19
20
|
def self.start(paths={})
|
20
21
|
|
21
|
-
#
|
22
|
+
#
|
23
|
+
# Set default path to config and log files
|
24
|
+
# TODO: These settings assume Linux default paths, should determine the operating system then configure accordingly
|
25
|
+
#
|
22
26
|
paths[:config_path] = '/etc/dvash.conf'
|
23
27
|
paths[:log_path] = '/var/log/dvash.conf'
|
24
28
|
|
25
|
-
#
|
29
|
+
#
|
30
|
+
# A command-line interface using OptionParser
|
31
|
+
#
|
26
32
|
OptionParser.new do |opts|
|
27
33
|
opts.banner = "Usage: #{__FILE__} [options]"
|
28
34
|
|
35
|
+
#
|
36
|
+
# Option to set an alternate configuration file
|
37
|
+
#
|
29
38
|
opts.on("--config-file [PATH]", "Set path to config file") do |arg|
|
30
39
|
paths[:config_path] = arg
|
31
40
|
end
|
32
41
|
|
42
|
+
#
|
43
|
+
# Option to set an alternate log file destination and filename
|
44
|
+
#
|
33
45
|
opts.on("--log-file [PATH]", "Set path to log file") do |arg|
|
34
46
|
paths[:log_path] = arg
|
35
47
|
end
|
36
48
|
end.parse!
|
37
49
|
|
50
|
+
#
|
38
51
|
# Create and start an Application instance
|
39
|
-
#
|
52
|
+
#
|
53
|
+
begin
|
40
54
|
application = Dvash::Application.new(paths)
|
41
55
|
application.start
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
56
|
+
rescue
|
57
|
+
# TODO: Use 'logger' gem to output debug information
|
58
|
+
puts "couldn't start application"
|
59
|
+
exit
|
60
|
+
end
|
46
61
|
|
47
62
|
|
48
63
|
end
|
data/lib/dvash/application.rb
CHANGED
@@ -1,26 +1,55 @@
|
|
1
|
-
require 'dvash/
|
1
|
+
require 'dvash/core'
|
2
2
|
|
3
3
|
require 'parseconfig'
|
4
4
|
|
5
5
|
module Dvash
|
6
6
|
|
7
|
-
class Application <
|
7
|
+
class Application < Core
|
8
8
|
|
9
|
+
#
|
10
|
+
# Methods that should run when the Dvash Application object is created
|
11
|
+
# Requires one argument of type Array including paths to configuration
|
12
|
+
# file and destination for log file
|
13
|
+
#
|
9
14
|
def initialize(paths)
|
15
|
+
#
|
16
|
+
# Create @honey_threads Array to hold all 'honeyport' threads
|
17
|
+
#
|
10
18
|
@honey_threads = Array.new
|
19
|
+
#
|
20
|
+
# Load passed Array paths into @paths for use in the class
|
21
|
+
#
|
11
22
|
@paths = paths
|
12
|
-
|
23
|
+
#
|
24
|
+
# Call method to load the configuration file
|
25
|
+
#
|
13
26
|
load_conf
|
27
|
+
#
|
28
|
+
# Call method to validate the operating system and load necessary Dvash methods
|
29
|
+
#
|
14
30
|
validate_os
|
15
31
|
end
|
16
32
|
|
33
|
+
#
|
34
|
+
# Fire in the hole!
|
35
|
+
#
|
17
36
|
def start
|
37
|
+
#
|
38
|
+
# Make sure we are running with elevated privileges
|
39
|
+
#
|
18
40
|
unless valid_user?
|
19
|
-
|
41
|
+
# TODO: Use 'logger' gem to output debug information
|
42
|
+
puts "invalid user"
|
20
43
|
exit
|
21
44
|
end
|
22
45
|
|
46
|
+
#
|
47
|
+
# Call method to load all 'honeyports' set as 'true' in the configuration file
|
48
|
+
#
|
23
49
|
load_honeyport
|
50
|
+
#
|
51
|
+
# Start all loaded threads
|
52
|
+
#
|
24
53
|
@honey_threads.each { |thr| thr.join }
|
25
54
|
end
|
26
55
|
|
@@ -3,12 +3,18 @@ require 'securerandom'
|
|
3
3
|
|
4
4
|
module Dvash
|
5
5
|
|
6
|
-
class
|
6
|
+
class Core
|
7
7
|
|
8
|
+
#
|
9
|
+
# Validates user, must be root
|
10
|
+
#
|
8
11
|
def valid_user?
|
9
12
|
Process.uid == 0
|
10
13
|
end
|
11
14
|
|
15
|
+
#
|
16
|
+
# Validates an IP address, must be valid IPv4 or IPv6 address
|
17
|
+
#
|
12
18
|
def valid_ip?(address)
|
13
19
|
begin
|
14
20
|
IPAddr.new("#{address}")
|
@@ -18,6 +24,11 @@ module Dvash
|
|
18
24
|
end
|
19
25
|
end
|
20
26
|
|
27
|
+
#
|
28
|
+
# Validates the operating system, must be windows, os x, or linux
|
29
|
+
# Creates a new instance the operating system specific Dvash libraries required to block IP addresses properly
|
30
|
+
# @@os is used as a class variable to call its methods from within a Honeyport
|
31
|
+
#
|
21
32
|
def validate_os
|
22
33
|
system = RUBY_PLATFORM
|
23
34
|
case system
|
@@ -34,34 +45,57 @@ module Dvash
|
|
34
45
|
# TODO: BSD support
|
35
46
|
exit
|
36
47
|
else
|
37
|
-
|
48
|
+
# TODO: Use 'logger' gem to output debug information
|
49
|
+
puts "invalid operating system"
|
38
50
|
exit
|
39
51
|
end
|
40
52
|
end
|
41
53
|
|
54
|
+
#
|
55
|
+
# Loads the configuration file using ParseConfig
|
56
|
+
#
|
42
57
|
def load_conf
|
43
58
|
begin
|
44
59
|
@@cfgfile = ParseConfig.new(@paths[:config_path])
|
45
60
|
rescue
|
46
|
-
|
61
|
+
# TODO: Use 'logger' gem to output debug information
|
62
|
+
puts "invalid configuration file"
|
47
63
|
exit
|
48
64
|
end
|
49
65
|
end
|
50
66
|
|
67
|
+
#
|
68
|
+
# Load all Honeyports set 'true' in the configuration file
|
69
|
+
#
|
51
70
|
def load_honeyport
|
71
|
+
#
|
72
|
+
# Read 'honeyports' group in configuration file, parse keys and values
|
73
|
+
#
|
52
74
|
@@cfgfile['honeyports'].each do |key, value|
|
53
75
|
if value == 'true' then
|
54
76
|
ipver, proto = key.split("_")
|
77
|
+
#
|
78
|
+
# Load methods for all 'honeyports' set to 'true'
|
79
|
+
#
|
55
80
|
require "dvash/honeyports/#{ipver}/#{proto}"
|
81
|
+
#
|
82
|
+
# Push the loaded 'honeyport' into a thread
|
83
|
+
#
|
56
84
|
@honey_threads << Thread.new { Dvash::Honeyport.new.send(key) }
|
57
85
|
end
|
58
86
|
end
|
59
87
|
end
|
60
88
|
|
89
|
+
#
|
90
|
+
# Return a string of random characters 64 bytes long
|
91
|
+
#
|
61
92
|
def random_data
|
62
93
|
SecureRandom.random_bytes(64)
|
63
94
|
end
|
64
95
|
|
96
|
+
#
|
97
|
+
# Return the client source IP address from a TCPServer object
|
98
|
+
#
|
65
99
|
def client_ip(client)
|
66
100
|
client.peeraddr[3]
|
67
101
|
end
|
@@ -10,17 +10,38 @@
|
|
10
10
|
###############################################################################
|
11
11
|
module Dvash
|
12
12
|
|
13
|
-
class Honeyport <
|
13
|
+
class Honeyport < Core
|
14
14
|
|
15
15
|
def ipv4_http
|
16
|
+
#
|
17
|
+
# Create a new IPv4 TCPServer object
|
18
|
+
#
|
16
19
|
server = TCPServer.new(80)
|
20
|
+
#
|
21
|
+
# Infinite loop listens on port 80 pretending to be an HTTP server
|
22
|
+
#
|
17
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
|
+
#
|
18
28
|
Thread.fork(server.accept) do |client|
|
19
|
-
|
29
|
+
#
|
30
|
+
# Send the connected client junk data
|
31
|
+
#
|
20
32
|
client.puts(random_data)
|
33
|
+
#
|
34
|
+
# Make sure the client has a valid IP address
|
35
|
+
#
|
21
36
|
if valid_ip?(client_ip(client)) then
|
37
|
+
#
|
38
|
+
# Block the IP address
|
39
|
+
#
|
22
40
|
@@os.block_ip(client_ip(client))
|
23
41
|
end
|
42
|
+
#
|
43
|
+
# Close the connection to the client and kill the forked process
|
44
|
+
#
|
24
45
|
client.close
|
25
46
|
end
|
26
47
|
end
|
@@ -10,17 +10,38 @@
|
|
10
10
|
###############################################################################
|
11
11
|
module Dvash
|
12
12
|
|
13
|
-
class Honeyport <
|
13
|
+
class Honeyport < Core
|
14
14
|
|
15
|
-
def
|
15
|
+
def ipv6_http
|
16
|
+
#
|
17
|
+
# Create a new IPv6 TCPServer object
|
18
|
+
#
|
16
19
|
server = TCPServer.new('::', 80)
|
20
|
+
#
|
21
|
+
# Infinite loop listens on port 80 pretending to be an HTTP server
|
22
|
+
#
|
17
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
|
+
#
|
18
28
|
Thread.fork(server.accept) do |client|
|
19
|
-
|
29
|
+
#
|
30
|
+
# Send the connected client junk data
|
31
|
+
#
|
20
32
|
client.puts(random_data)
|
33
|
+
#
|
34
|
+
# Make sure the client has a valid IP address
|
35
|
+
#
|
21
36
|
if valid_ip?(client_ip(client)) then
|
37
|
+
#
|
38
|
+
# Block the IP address
|
39
|
+
#
|
22
40
|
@@os.block_ip(client_ip(client))
|
23
41
|
end
|
42
|
+
#
|
43
|
+
# Close the connection to the client and kill the forked process
|
44
|
+
#
|
24
45
|
client.close
|
25
46
|
end
|
26
47
|
end
|
data/lib/dvash/os/linux.rb
CHANGED
@@ -1,40 +1,66 @@
|
|
1
1
|
module Dvash
|
2
2
|
|
3
|
-
class Linux <
|
3
|
+
class Linux < Core
|
4
4
|
|
5
5
|
def initialize
|
6
|
+
#
|
7
|
+
# Check to make sure we have binaries for iptables using the paths
|
8
|
+
# set in the configuration file
|
9
|
+
#
|
6
10
|
unless File.exist?(@@cfgfile['iptables']['ipv4'])
|
11
|
+
# TODO: Use 'logger' gem to output debug information
|
7
12
|
puts "can't find iptables"
|
8
13
|
exit
|
9
14
|
end
|
10
15
|
|
11
|
-
#
|
16
|
+
#
|
17
|
+
# Do not create a new iptables chain if one already exists
|
18
|
+
#
|
12
19
|
unless `"#{@@cfgfile['iptables']['ipv4']}" -L INPUT`.include?('DVASH')
|
13
|
-
#
|
20
|
+
#
|
21
|
+
# Create a new DVASH chain
|
22
|
+
#
|
14
23
|
system("#{@@cfgfile['iptables']['ipv4']} -N DVASH")
|
15
|
-
#
|
24
|
+
#
|
25
|
+
# Flush the DVASH chain
|
26
|
+
#
|
16
27
|
system("#{@@cfgfile['iptables']['ipv4']} -F DVASH")
|
17
|
-
#
|
28
|
+
#
|
29
|
+
# Associate the DVASH chain to INPUT chain
|
30
|
+
#
|
18
31
|
system("#{@cfgfile['iptables']['ipv4']} -I INPUT -j DVASH")
|
19
32
|
end
|
20
33
|
|
21
|
-
#
|
34
|
+
#
|
35
|
+
# Do not create a new ip6tables chain if one already exists
|
36
|
+
#
|
22
37
|
unless `"#{@@cfgfile['iptables']['ipv6']}" -L INPUT`.include?('DVASH')
|
23
|
-
#
|
38
|
+
#
|
39
|
+
# Create a new DVASH chain
|
40
|
+
#
|
24
41
|
system("#{@@cfgfile['iptables']['ipv6']} -N DVASH")
|
25
|
-
#
|
42
|
+
#
|
43
|
+
# Flush the DVASH chain
|
44
|
+
#
|
26
45
|
system("#{@@cfgfile['iptables']['ipv6']} -F DVASH")
|
27
|
-
#
|
46
|
+
#
|
47
|
+
# Associate the DVASH chain to INPUT chain
|
48
|
+
#
|
28
49
|
system("#{@@cfgfile['iptables']['ipv6']} -I INPUT -j DVASH")
|
29
50
|
end
|
30
51
|
end
|
31
52
|
|
32
53
|
def block_ip(address)
|
33
|
-
|
54
|
+
#
|
55
|
+
# Block the client IP address using iptables binaries set in the configuration file
|
56
|
+
#
|
34
57
|
if IPAddr.new("#{address}").ipv4? then
|
35
58
|
system("#{@@cfgfile['iptables']['ipv4']} -I DVASH -s #{address} -j DROP")
|
36
59
|
end
|
37
60
|
|
61
|
+
#
|
62
|
+
# Block the client IP address using ip6tables binaries set in the configuration file
|
63
|
+
#
|
38
64
|
if IPAddr.new("#{address}").ipv6? then
|
39
65
|
system("#{@@cfgfile['iptables']['ipv6']} -I DVASH -s #{address} -j DROP")
|
40
66
|
end
|
data/lib/dvash/os/mac.rb
CHANGED
@@ -1,15 +1,23 @@
|
|
1
1
|
module Dvash
|
2
2
|
|
3
|
-
class Mac <
|
3
|
+
class Mac < Core
|
4
4
|
|
5
5
|
def initialize
|
6
|
+
#
|
7
|
+
# Check to make sure we have binaries for ipfw using the paths
|
8
|
+
# set in the configuration file
|
9
|
+
#
|
6
10
|
unless File.exist?(@@cfgfile['ipfw']['ipfw'])
|
11
|
+
# TODO: Use 'logger' gem to output debug information
|
7
12
|
puts "can't find ipfw"
|
8
13
|
exit
|
9
14
|
end
|
10
15
|
end
|
11
16
|
|
12
17
|
def block_ip(address)
|
18
|
+
#
|
19
|
+
# Block the client IP address using ipfw binaries set in the configuration file
|
20
|
+
#
|
13
21
|
system("#{@@cfgfile['ipfw']['ipfw']} -q add deny src-ip #{address}")
|
14
22
|
end
|
15
23
|
|
data/lib/dvash/os/windows.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
module Dvash
|
2
2
|
|
3
|
-
class Windows
|
3
|
+
class Windows < Core
|
4
4
|
|
5
5
|
def block_ip(address)
|
6
|
-
|
7
|
-
#
|
6
|
+
#
|
7
|
+
# Windows 7 and newer compatible
|
8
|
+
# Blackholes the client IP address by sending traffic to a non-existing gateway
|
9
|
+
#
|
10
|
+
system("route add #{address} mask 255.255.255.255 10.255.255.255 if 1 -p")
|
8
11
|
end
|
9
12
|
|
10
13
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dvash
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -59,7 +59,7 @@ files:
|
|
59
59
|
- lib/dvash/os/mac.rb
|
60
60
|
- lib/dvash/os/windows.rb
|
61
61
|
- lib/dvash/application.rb
|
62
|
-
- lib/dvash/
|
62
|
+
- lib/dvash/core.rb
|
63
63
|
- lib/dvash.rb
|
64
64
|
- dvash.gemspec
|
65
65
|
- Gemfile
|