micetrap 0.1.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.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
4
+ *.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm --create use ruby-1.9.2@micetrap
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in micetrap.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,43 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ micetrap (0.0.1)
5
+ trollop
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ configuration (1.2.0)
11
+ diff-lcs (1.1.2)
12
+ guard (0.2.2)
13
+ open_gem (~> 1.4.2)
14
+ thor (~> 0.14.3)
15
+ guard-rspec (0.1.9)
16
+ guard (>= 0.2.2)
17
+ launchy (0.3.7)
18
+ configuration (>= 0.0.5)
19
+ rake (>= 0.8.1)
20
+ open_gem (1.4.2)
21
+ launchy (~> 0.3.5)
22
+ rake (0.8.7)
23
+ rspec (2.3.0)
24
+ rspec-core (~> 2.3.0)
25
+ rspec-expectations (~> 2.3.0)
26
+ rspec-mocks (~> 2.3.0)
27
+ rspec-core (2.3.1)
28
+ rspec-expectations (2.3.0)
29
+ diff-lcs (~> 1.1.2)
30
+ rspec-mocks (2.3.0)
31
+ thor (0.14.6)
32
+ trollop (1.16.2)
33
+
34
+ PLATFORMS
35
+ ruby
36
+
37
+ DEPENDENCIES
38
+ bundler (~> 1.0.7)
39
+ guard
40
+ guard-rspec
41
+ micetrap!
42
+ rspec (~> 2.3.0)
43
+ trollop
data/Guardfile ADDED
@@ -0,0 +1,8 @@
1
+ # A sample Guardfile
2
+ # More info at http://github.com/guard/guard#readme
3
+
4
+ guard 'rspec', :version => 2 do
5
+ watch('^spec/(.*)_spec.rb')
6
+ watch('^lib/(.*)\.rb') { |m| "spec/#{m[1]}_spec.rb" }
7
+ watch('^spec/spec_helper.rb') { "spec" }
8
+ end
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core'
5
+ require 'rspec/core/rake_task'
6
+ RSpec::Core::RakeTask.new(:spec) do |spec|
7
+ spec.pattern = FileList['spec/**/*_spec.rb']
8
+ end
9
+
10
+ task :default => :spec
data/Readme.md ADDED
@@ -0,0 +1,114 @@
1
+ #micetrap
2
+ ___
3
+ _.-| | |\__/,| (`\
4
+ { | | |o o |__ _) )
5
+ "-.|___| _.( T ) ` /
6
+ .--'-`-. _((_ `^--' /_< \
7
+ .+|______|__.-||__)`-'(((/ (((/
8
+
9
+ Catch hackers on the fly with micetrap!
10
+
11
+ Micetrap opens a server on either a given or random port, emulating fake
12
+ vulnerable services. Port scanners such as Nmap, when fingerprinting ports
13
+ to discover service names and versions, will get apparently legitimate
14
+ responses from common services such as FTP, HTTP or MySQL servers,
15
+ therefore misleading potential attackers with false information.
16
+
17
+ Depending on the operating system you are using, micetrap will try its best
18
+ to +look feasible+ by choosing the appropriate fake services and versions
19
+ to emulate. Whenever possible, micetrap will provide a bit outdated versions
20
+ which are more likely to be vulnerable, and thus making the attacker focus
21
+ on those ports. While the attacker tries to exploit these ports, she is
22
+ essentially sending certain packets -- which get properly captured and
23
+ logged by micetrap. This information might be useful to discover what kind
24
+ of attacks are being tried against your machine, therefore giving you time
25
+ and the opportunity to defend appropriately.
26
+
27
+ Running micetrap with sudo will allow it to use default, unsuspicious ports,
28
+ which may give you advantage at tricking a smart attacker.
29
+
30
+ ##Install
31
+
32
+ gem install micetrap
33
+
34
+ ...or, if you want to be able to use it with sudo:
35
+
36
+ sudo gem install micetrap
37
+
38
+ Micetrap currently runs on Ruby versions 1.8.7 and 1.9.2.
39
+
40
+ ##Usage
41
+
42
+ Just fire up the server with some fake service, such an ftp server:
43
+
44
+ micetrap ftp --port 8765
45
+
46
+ If everything is ok, you will see something like this:
47
+
48
+ (some timestamp) ::: Ftp trap listening on ::ffff:0.0.0.0:8765 :::
49
+
50
+ TL;DR: Most port scanners such as _nmap_ have some kind of fingerprinting
51
+ capabilities. This means that, in order to discover which services and
52
+ versions run behind a specific port, they send special packets or _probes_
53
+ which make different services and versions react differently. By capturing
54
+ the response and matching against with a database, most of the time they
55
+ can reliably determine what service and version is running behind that port.
56
+
57
+ Port scanners usually start by sending a blank probe, since many servers
58
+ respond with a welcome banner telling interesting stuff about them. Micetrap
59
+ only responds to those early blank probes. Let's try to port-scan this fake
60
+ ftp service with nmap fingerprinting:
61
+
62
+ nmap 127.0.0.1 -p 8765 -A
63
+
64
+ We are scanning localhost, port 8765, and -A means service version detection
65
+ and OS guessing. After a while, in our micetrap server terminal we see:
66
+
67
+ (timestamp) Recorded a probe coming from ::ffff:127.0.0.1:51082 containing
68
+ the following: (empty line)
69
+
70
+ (timestamp) ::: Responded misleadingly: let's drive those hackers nuts! :::
71
+
72
+ These gets logged inside a .log file within the current directory.
73
+ And in the nmap terminal:
74
+
75
+ Starting Nmap 5.35DC1 ( http://nmap.org ) at (timestamp)
76
+ Nmap scan report for localhost (127.0.0.1)
77
+ Host is up (0.00017s latency).
78
+ PORT STATE SERVICE VERSION
79
+ 8765/tcp open ftp Mac OS X Server ftpd
80
+
81
+ The faked service/version is random (you can start an ftp server which looks
82
+ like lukemftpd, Mac OS X server ftpd or PureFTPd for example), but it is
83
+ consistent within the same server, so that every scan reports the same service
84
+ and version.
85
+
86
+ ## U mad? Evil hackers
87
+
88
+ Probably.
89
+
90
+ ##Available services
91
+
92
+ For now there are a bunch of ftp, http, torrent, mysql and samba services,
93
+ mostly Mac-ish.
94
+
95
+ ##Contribute!
96
+
97
+ If you want to contribute with more services and versions to empower micetrap
98
+ and be a superhero, you shall follow these steps:
99
+
100
+ * Fork the project.
101
+ * Install _nmap_ and look for a file called nmap-service-probes in your system.
102
+ This file contains regexes used to match responses from scanned services.
103
+ * You only have to devise a string which fits in one of this regexes and then
104
+ add it in the corresponding service file (in lib/micetrap/services/ftp.rb for
105
+ example if it's an ftp server).
106
+ * Commit, do not mess with rakefile, version, or history.
107
+ If you want to have your own version, that is fine but bump version
108
+ in a commit by itself I can ignore when I pull.
109
+ * Send me a pull request. Bonus points for topic branches.
110
+ * Profit!
111
+
112
+ ## Copyright
113
+
114
+ Copyright (c) 2011 Josep M. Bach. See LICENSE for details.
data/bin/micetrap ADDED
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
3
+
4
+ require 'trollop' unless defined?(Trollop)
5
+ require 'micetrap'
6
+ require 'micetrap/version'
7
+
8
+ SERVICES = Micetrap.services
9
+
10
+ opts = Trollop::options do
11
+ version "micetrap #{Micetrap::VERSION} (c) 2011 Josep M. Bach"
12
+ banner <<-EOS
13
+ Micetrap opens a server on either a given or random port, emulating fake
14
+ vulnerable services. Port scanners such as Nmap, when fingerprinting ports
15
+ to discover service names and versions, will get apparently legitimate
16
+ responses from common services such as FTP, HTTP or MySQL servers,
17
+ therefore misleading potential attackers with false information.
18
+
19
+ Depending on the operating system you are using, micetrap will try its best
20
+ to +look feasible+ by choosing the appropriate fake services and versions
21
+ to emulate. Whenever possible, micetrap will provide a bit outdated versions
22
+ which are more likely to be vulnerable, and thus making the attacker focus
23
+ on those ports. While the attacker tries to exploit these ports, she is
24
+ essentially sending certain packets -- which get properly captured and
25
+ logged my micetrap. This information might be useful to discover what kind
26
+ of attacks are being tried against your machine, therefore giving you time
27
+ and the opportunity to defend appropriately.
28
+
29
+ Fire up a simple ftp micetrap like this:
30
+
31
+ sudo micetrap ftp
32
+
33
+ Running it with sudo will allow you to use default, unsuspicious ports,
34
+ which may give you advantage at tricking a smart attacker.
35
+
36
+ If you don't want to use system ports, you can run micetrap without having
37
+ root privileges like this:
38
+
39
+ micetrap ftp --port 9999 (or whatever non-system port you like)
40
+
41
+ The available services are are:
42
+ #{SERVICES.join(', ')}
43
+
44
+ Usage:
45
+ [sudo] micetrap <service> [options]
46
+
47
+ where [options] are:
48
+ EOS
49
+ opt :port, "A specific port to use", :default => nil, :type => :integer
50
+ stop_on SERVICES
51
+ end
52
+
53
+ service = ARGV.shift.to_sym
54
+ Trollop::die "You need to specify a service, which must be one of the following: #{SERVICES.join(', ')}\n\nMaybe you just feel a bit lost.." unless SERVICES.include?(service)
55
+
56
+ # Show a nice banner
57
+ ANSI = {:RESET=>"\e[0m", :BOLD=>"\e[1m", :UNDERLINE=>"\e[4m", :LGRAY=>"\e[0;37m", :GRAY=>"\e[1;30m", :RED=>"\e[31m", :GREEN=>"\e[32m", :YELLOW=>"\e[33m", :BLUE=>"\e[34m", :MAGENTA=>"\e[35m", :CYAN=>"\e[36m", :WHITE=>"\e[37m"}
58
+
59
+ puts "Starting #{ANSI[:BOLD]}Micetrap#{ANSI[:RESET]}..."
60
+ puts "Loading fake #{ANSI[:RED]}#{service}#{ANSI[:RESET]} server... (press Ctrl-C to exit)\n"
61
+ Micetrap::Server.new(opts.update(:service => service)).fire!
@@ -0,0 +1,5 @@
1
+ if RUBY_VERSION =~ /1\.8/
2
+ class Array
3
+ alias :sample :choice
4
+ end
5
+ end
data/lib/micetrap.rb ADDED
@@ -0,0 +1,19 @@
1
+ require 'core_ext/array'
2
+
3
+ require 'micetrap/services/exceptions'
4
+ require 'micetrap/services/base'
5
+
6
+ require 'micetrap/logger'
7
+ require 'micetrap/server'
8
+
9
+ module Micetrap
10
+ class << self
11
+ def services
12
+ [:ftp, :torrent, :samba, :http, :mysql]
13
+ end
14
+ end
15
+ end
16
+
17
+ Micetrap.services.each do |service|
18
+ require "micetrap/services/#{service}"
19
+ end
@@ -0,0 +1,37 @@
1
+ module Micetrap
2
+ class Logger
3
+ TIMESTAMP_FORMAT = "%Y-%m-%d__%H-%M"
4
+
5
+ attr_reader :filename
6
+
7
+ def initialize(service_name)
8
+ @service_name = service_name
9
+ @filename = ['micetrap',
10
+ service_name,
11
+ Time.now.strftime(TIMESTAMP_FORMAT)
12
+ ].join('_') + '.log'
13
+ end
14
+
15
+ def file
16
+ @file ||= File.new(@filename, 'a')
17
+ end
18
+
19
+ def log_probe(line, remote_host, remote_port)
20
+ content = line.strip.length > 0 ? line : '(empty line)'
21
+ logged = "\n#{Time.now} Recorded a probe coming from #{remote_host}:#{remote_port} containing the following: #{content}"
22
+ File.open(@filename, 'a') do |f|
23
+ f.write logged
24
+ end
25
+ puts logged
26
+ end
27
+
28
+ def log_message(line)
29
+ logged = "\n#{Time.now} ::: #{line} :::"
30
+ File.open(@filename, 'a') do |f|
31
+ f.write logged
32
+ end
33
+ puts logged
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,22 @@
1
+ require 'socket'
2
+
3
+ module Micetrap
4
+ class Server
5
+ attr_reader :service
6
+ attr_reader :port
7
+
8
+ def initialize(options)
9
+ raise StandardError.new("Service cannot be empty!") unless options[:service]
10
+ @service =
11
+ eval("Micetrap::Services::#{options[:service].to_s.capitalize}").new
12
+ @port = options[:port] # Optional
13
+ rescue NameError=>e
14
+ raise Services::UnrecognizedServiceException.new("Service #{options[:service].to_s.capitalize} is not recognized")
15
+ end
16
+
17
+ def fire!
18
+ @service.fire port
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,83 @@
1
+ module Micetrap
2
+ module Services
3
+ class Base
4
+
5
+ class ClientQuitError < RuntimeError; end
6
+
7
+ attr_reader :logger
8
+
9
+ def initialize
10
+ @logger = Logger.new self.name.downcase.to_sym
11
+ end
12
+
13
+ def fire port = nil
14
+ port = port ? port.to_i : default_ports.sample
15
+ begin
16
+ server = TCPServer.open(port || 0)
17
+ rescue Errno::EACCES
18
+ puts "Looks like you are trying to use a system port, for which you need root privileges.\nRun micetrap with another port if you don't want to sudo!\n"
19
+ exit(1)
20
+ end
21
+ @port = server.addr[1]
22
+ @addrs = server.addr[2..-1].uniq
23
+
24
+ logger.log_message "#{name} trap listening on #{@addrs.collect{|a|"#{a}:#{port}"}.join(' ')}"
25
+ listen(server)
26
+ end
27
+
28
+ def listen(server)
29
+ # Handle Ctrl-C to exit!
30
+ interrupted = false
31
+ trap("INT") do
32
+ puts "Gracefully exiting...";
33
+ interrupted = true;
34
+ Kernel.exit(0)
35
+ end
36
+
37
+ while not interrupted do
38
+ socket = server.accept
39
+ Thread.start do
40
+ read_from(socket)
41
+ end
42
+ end
43
+ end
44
+
45
+ def read_from(socket)
46
+ s = socket
47
+
48
+ port = s.peeraddr[1]
49
+ name = s.peeraddr[2]
50
+ addr = s.peeraddr[3]
51
+
52
+ begin
53
+ while line = s.gets # read a line at a time
54
+ raise ClientQuitError if line =~ /^die\r?$/
55
+
56
+ logger.log_probe line, name, port
57
+
58
+ if line.strip == ""
59
+ s.write response
60
+ logger.log_message "Responded misleadingly: let's drive those hackers nuts!"
61
+ s.close
62
+ Kernel.exit(0)
63
+ end
64
+ end
65
+ rescue ClientQuitError
66
+ logger.log_message "#{name}:#{port} disconnected"
67
+ ensure
68
+ s.close # close socket on error
69
+ end
70
+ end
71
+
72
+ protected
73
+
74
+ def default_ports; []; end;
75
+ def response; ""; end;
76
+
77
+ def name
78
+ self.class.name.split('::').last
79
+ end
80
+
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,5 @@
1
+ module Micetrap
2
+ module Services
3
+ class UnrecognizedServiceException < StandardError; end;
4
+ end
5
+ end
@@ -0,0 +1,22 @@
1
+ module Micetrap
2
+ module Services
3
+ class Ftp < Base
4
+
5
+ protected
6
+
7
+ def default_ports
8
+ [21]
9
+ end
10
+
11
+ def response
12
+ @response ||=
13
+ [
14
+ "220-FTP server (lukemftpd 1.1) ready.\r\n",
15
+ "220 Welcome to Pure-FTPd 1.8\r\n",
16
+ "220--------------------------------------------------------------------------------\r\n220-This is the \"Banner\" message for the Mac OS X Server's FTP server process.\r\n",
17
+ ].sample
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,20 @@
1
+ module Micetrap
2
+ module Services
3
+ class Http < Base
4
+
5
+ protected
6
+
7
+ def default_ports
8
+ [80, 8080]
9
+ end
10
+
11
+ def response
12
+ @response ||=
13
+ [
14
+ "HTTP/1\.0 200 OK\r\nContent-Type: text/html\r\n\r\n<html>\n<body>\n<ul><li>\n<i>com\.apple\.KernelEventAgent</i>\n",
15
+ ].sample
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module Micetrap
2
+ module Services
3
+ class Mysql < Base
4
+
5
+ protected
6
+
7
+ def default_ports
8
+ [3306]
9
+ end
10
+
11
+ def response
12
+ @response ||=
13
+ [
14
+ ".\0\0\0\n4.0.13\0...\0",
15
+ ].sample
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module Micetrap
2
+ module Services
3
+ class Samba < Base
4
+
5
+ protected
6
+
7
+ def default_ports
8
+ [135, 139, 445]
9
+ end
10
+
11
+ def response
12
+ @response ||=
13
+ [
14
+ "smbd: error while loading shared libraries: libattr.so.1: cannot open shared object file: No such file or directory\n",
15
+ ].sample
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module Micetrap
2
+ module Services
3
+ class Torrent < Base
4
+
5
+ protected
6
+
7
+ def default_ports
8
+ []
9
+ end
10
+
11
+ def response
12
+ @response ||=
13
+ [
14
+ "\x13BitTorrent protocol\0\0\0\0\0\0\0\0",
15
+ ].sample
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ module Micetrap
2
+ VERSION = "0.1.0"
3
+ end
data/micetrap.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "micetrap/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "micetrap"
7
+ s.version = Micetrap::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Josep M. Bach"]
10
+ s.email = ["josep.m.bach@gmail.com"]
11
+ s.homepage = "http://github.com/txus/micetrap"
12
+ s.summary = %q{Catch evil hackers on the fly by placing open-port traps emulating fake vulnerable services!}
13
+ s.description = %q{Catch evil hackers on the fly by placing open-port traps emulating fake vulnerable services!}
14
+
15
+ s.rubyforge_project = "micetrap"
16
+
17
+ s.add_runtime_dependency 'trollop'
18
+ s.default_executable = "micetrap"
19
+
20
+ s.add_development_dependency 'bundler', '~> 1.0.7'
21
+ s.add_development_dependency 'rspec', '~> 2.3.0'
22
+ s.add_development_dependency 'guard'
23
+ s.add_development_dependency 'guard-rspec'
24
+
25
+ s.files = `git ls-files`.split("\n")
26
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
27
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
28
+ s.require_paths = ["lib"]
29
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ module Micetrap
4
+
5
+ describe Logger do
6
+
7
+ describe "#initialize" do
8
+ it 'initializes the filename' do
9
+ Time.stub_chain('now.strftime').and_return "2011-01-03__20-30"
10
+ logger = Logger.new :ftp
11
+ logger.filename.should == "micetrap_ftp_2011-01-03__20-30.log"
12
+ end
13
+ end
14
+
15
+ describe "instance methods" do
16
+
17
+ subject { Logger.new :ftp }
18
+
19
+ describe "#file" do
20
+ it 'returns the log file' do
21
+ file = double('file')
22
+ File.stub(:new).and_return file
23
+ subject.file.should be(file)
24
+ end
25
+ end
26
+
27
+ describe "#log_probe" do
28
+ it 'logs a scanned service along with the scanner info' do
29
+ file = double('file')
30
+ now = Time.now
31
+ Time.stub(:now).and_return now
32
+ File.stub(:new).and_return file
33
+
34
+ expected_string = "\n#{now} Recorded a probe coming from hackerz.com:5978 containing the following: ###EVILPROBE###"
35
+
36
+ File.should_receive(:open).and_yield file
37
+ file.should_receive(:write).with expected_string
38
+
39
+ subject.log_probe "###EVILPROBE###", "hackerz.com", 5978
40
+ end
41
+ end
42
+
43
+ describe "#log_message" do
44
+ it 'logs a misc messagescanned service along with the scanner info' do
45
+ file = double('file')
46
+ now = Time.now
47
+ Time.stub(:now).and_return now
48
+ File.stub(:new).and_return file
49
+
50
+ expected_string = "\n#{now} ::: Warning! :::"
51
+
52
+ File.should_receive(:open).and_yield file
53
+ file.should_receive(:write).with expected_string
54
+
55
+ subject.log_message "Warning!"
56
+ end
57
+ end
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ module Micetrap
4
+
5
+ module Services
6
+ class Test
7
+ end
8
+ end
9
+
10
+ describe Server do
11
+ describe "#initialize" do
12
+ it 'initializes the service' do
13
+ server = Server.new :service => :test
14
+ server.service.should be_a(Services::Test)
15
+ end
16
+ it 'assigns a custom port if given' do
17
+ server = Server.new :service => :test,
18
+ :port => 80
19
+ server.port.should be(80)
20
+ end
21
+
22
+ context 'when given an invalid service' do
23
+ it 'raises' do
24
+ expect {
25
+ Server.new :service => :foo
26
+ }.to raise_error(Services::UnrecognizedServiceException)
27
+ end
28
+ end
29
+ context 'when service is blank' do
30
+ it 'raises' do
31
+ expect {
32
+ Server.new :service => nil
33
+ }.to raise_error(StandardError, "Service cannot be empty!")
34
+ end
35
+ end
36
+ end
37
+
38
+ describe "#fire!" do
39
+ it 'fires the service' do
40
+ test_service = double('service')
41
+ Services::Test.should_receive(:new).and_return test_service
42
+ server = Server.new :service => :test
43
+ server.stub(:port).and_return 80
44
+ test_service.should_receive(:fire).with(80)
45
+
46
+ server.fire!
47
+ end
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,113 @@
1
+ require 'spec_helper'
2
+
3
+ module Micetrap
4
+ module Services
5
+ describe Base do
6
+ describe "#fire" do
7
+
8
+ before(:each) do
9
+ subject.stub(:listen)
10
+ end
11
+
12
+ context 'when given a port' do
13
+ it 'fires up the service on that port' do
14
+ server = double('server', :addr => [1,2,3])
15
+ TCPServer.should_receive(:open).with(5900).and_return server
16
+ subject.fire 5900
17
+ end
18
+ end
19
+ context 'when port is nil' do
20
+ it 'fires up the service on one of the default ports' do
21
+ server = double('server', :addr => [1,2,3])
22
+ subject.stub_chain('default_ports.sample') { 445 }
23
+ TCPServer.should_receive(:open).with(445).and_return server
24
+
25
+ subject.fire
26
+ end
27
+ context 'but when no default ports are specified' do
28
+ it 'uses the port 0' do
29
+ server = double('server', :addr => [1,2,3])
30
+ subject.stub(:default_ports) { [] }
31
+ TCPServer.should_receive(:open).with(0).and_return server
32
+
33
+ subject.fire
34
+ end
35
+ end
36
+ end
37
+ it 'logs a message telling the trap is listening' do
38
+ server = double('server', :addr => [1,2,3])
39
+ TCPServer.stub(:open).and_return server
40
+ subject.logger.should_receive(:log_message).with do |arg|
41
+ arg.should include('Base trap listening')
42
+ end
43
+ subject.fire
44
+ end
45
+ end
46
+ describe "#listen", :blocking => true do
47
+ it 'calls read_from every time a connection is accepted' do
48
+ Kernel.stub(:exit)
49
+ connection = double('connection')
50
+ server = double('server', :addr => [1,2,3], :accept => connection)
51
+
52
+ subject.should_receive(:read_from).with(connection).any_number_of_times
53
+ puts "Press Ctrl-C to resume specs! Don't worry, it's all under control :)"
54
+ subject.listen(server)
55
+ end
56
+ end
57
+ describe "#read_from" do
58
+ let(:peeraddr) { [ nil, 4983, 'hackerz.com', '293.13.23.32'] }
59
+ let(:socket) do
60
+ double :socket, :peeraddr => peeraddr
61
+ end
62
+ before(:each) do
63
+ socket.should_receive(:close).any_number_of_times
64
+ end
65
+
66
+ context 'when the socket contains a line with die' do
67
+ it 'dies' do
68
+ socket.should_receive(:gets).and_return 'die'
69
+ subject.logger.should_not_receive(:log_probe)
70
+ subject.logger.should_receive(:log_message).with("hackerz.com:4983 disconnected")
71
+
72
+ subject.read_from(socket)
73
+ end
74
+ end
75
+
76
+ context 'otherwise' do
77
+ it 'logs the probe' do
78
+ socket.should_receive(:gets).and_return 'some probe', nil
79
+ subject.logger.should_receive(:log_probe).with 'some probe', 'hackerz.com', 4983
80
+
81
+ subject.read_from(socket)
82
+ end
83
+ context 'when the line is blank' do
84
+ it 'does respond with the appropriate response' do
85
+ Kernel.stub(:exit)
86
+ socket.should_receive(:gets).and_return '', nil
87
+ subject.logger.stub(:log_probe)
88
+ appropriate_response = double :response
89
+ subject.should_receive(:response).and_return appropriate_response
90
+
91
+ socket.should_receive(:write).with(appropriate_response)
92
+ subject.logger.should_receive(:log_message)
93
+
94
+ subject.read_from(socket)
95
+ end
96
+ end
97
+ context 'when the line contains any other thing' do
98
+ it 'does not respond' do
99
+ socket.should_receive(:gets).and_return 'some evil probe', nil
100
+ subject.logger.stub(:log_probe)
101
+
102
+ subject.should_not_receive(:response)
103
+ socket.should_not_receive(:write)
104
+
105
+ subject.read_from(socket)
106
+ end
107
+ end
108
+ end
109
+
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ module Micetrap
4
+ module Services
5
+ describe Ftp do
6
+
7
+ describe "#default_ports" do
8
+ it 'returns the default ports' do
9
+ Ftp.new.send(:default_ports).should include(21)
10
+ end
11
+ end
12
+ describe "#response" do
13
+ it 'returns a response' do
14
+ Ftp.new.send(:response).should be_a(String)
15
+ end
16
+ it 'caches the response for cohesion' do
17
+ service = Ftp.new
18
+ response = service.send(:response)
19
+ service.instance_variable_get(:@response).should == response
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ module Micetrap
4
+ module Services
5
+ describe Http do
6
+
7
+ describe "#default_ports" do
8
+ it 'returns the default ports' do
9
+ Http.new.send(:default_ports).should =~ [80, 8080]
10
+ end
11
+ end
12
+ describe "#response" do
13
+ it 'returns a response' do
14
+ Http.new.send(:response).should be_a(String)
15
+ end
16
+ it 'caches the response for cohesion' do
17
+ service = Http.new
18
+ response = service.send(:response)
19
+ service.instance_variable_get(:@response).should == response
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ module Micetrap
4
+ module Services
5
+ describe Mysql do
6
+
7
+ describe "#default_ports" do
8
+ it 'returns the default ports' do
9
+ Mysql.new.send(:default_ports).should include(3306)
10
+ end
11
+ end
12
+ describe "#response" do
13
+ it 'returns a response' do
14
+ Mysql.new.send(:response).should be_a(String)
15
+ end
16
+ it 'caches the response for cohesion' do
17
+ service = Mysql.new
18
+ response = service.send(:response)
19
+ service.instance_variable_get(:@response).should == response
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ module Micetrap
4
+ module Services
5
+ describe Samba do
6
+
7
+ describe "#default_ports" do
8
+ it 'returns the default ports' do
9
+ Samba.new.send(:default_ports).should =~ [135, 139, 445]
10
+ end
11
+ end
12
+ describe "#response" do
13
+ it 'returns a response' do
14
+ Samba.new.send(:response).should be_a(String)
15
+ end
16
+ it 'caches the response for cohesion' do
17
+ service = Samba.new
18
+ response = service.send(:response)
19
+ service.instance_variable_get(:@response).should == response
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ module Micetrap
4
+ module Services
5
+ describe Torrent do
6
+
7
+ describe "#default_ports" do
8
+ it 'returns the default ports' do
9
+ Torrent.new.send(:default_ports).should == []
10
+ end
11
+ end
12
+ describe "#response" do
13
+ it 'returns a response' do
14
+ Torrent.new.send(:response).should be_a(String)
15
+ end
16
+ it 'caches the response for cohesion' do
17
+ service = Torrent.new
18
+ response = service.send(:response)
19
+ service.instance_variable_get(:@response).should == response
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,17 @@
1
+ require 'bundler'
2
+ begin
3
+ Bundler.setup(:default, :development)
4
+ rescue Bundler::BundlerError => e
5
+ $stderr.puts e.message
6
+ $stderr.puts "Run `bundle install` to install missing gems"
7
+ exit e.status_code
8
+ end
9
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
10
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
11
+
12
+ require 'micetrap'
13
+ require 'rspec'
14
+
15
+ # Requires supporting files with custom matchers and macros, etc,
16
+ # in ./support/ and its subdirectories.
17
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
metadata ADDED
@@ -0,0 +1,171 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: micetrap
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Josep M. Bach
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-01-06 00:00:00 +01:00
18
+ default_executable: micetrap
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: trollop
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: bundler
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ~>
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 1
43
+ - 0
44
+ - 7
45
+ version: 1.0.7
46
+ type: :development
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: rspec
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ~>
55
+ - !ruby/object:Gem::Version
56
+ segments:
57
+ - 2
58
+ - 3
59
+ - 0
60
+ version: 2.3.0
61
+ type: :development
62
+ version_requirements: *id003
63
+ - !ruby/object:Gem::Dependency
64
+ name: guard
65
+ prerelease: false
66
+ requirement: &id004 !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ segments:
72
+ - 0
73
+ version: "0"
74
+ type: :development
75
+ version_requirements: *id004
76
+ - !ruby/object:Gem::Dependency
77
+ name: guard-rspec
78
+ prerelease: false
79
+ requirement: &id005 !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ segments:
85
+ - 0
86
+ version: "0"
87
+ type: :development
88
+ version_requirements: *id005
89
+ description: Catch evil hackers on the fly by placing open-port traps emulating fake vulnerable services!
90
+ email:
91
+ - josep.m.bach@gmail.com
92
+ executables:
93
+ - micetrap
94
+ extensions: []
95
+
96
+ extra_rdoc_files: []
97
+
98
+ files:
99
+ - .gitignore
100
+ - .rspec
101
+ - .rvmrc
102
+ - Gemfile
103
+ - Gemfile.lock
104
+ - Guardfile
105
+ - Rakefile
106
+ - Readme.md
107
+ - bin/micetrap
108
+ - lib/core_ext/array.rb
109
+ - lib/micetrap.rb
110
+ - lib/micetrap/logger.rb
111
+ - lib/micetrap/server.rb
112
+ - lib/micetrap/services/base.rb
113
+ - lib/micetrap/services/exceptions.rb
114
+ - lib/micetrap/services/ftp.rb
115
+ - lib/micetrap/services/http.rb
116
+ - lib/micetrap/services/mysql.rb
117
+ - lib/micetrap/services/samba.rb
118
+ - lib/micetrap/services/torrent.rb
119
+ - lib/micetrap/version.rb
120
+ - micetrap.gemspec
121
+ - spec/micetrap/logger_spec.rb
122
+ - spec/micetrap/server_spec.rb
123
+ - spec/micetrap/services/base_spec.rb
124
+ - spec/micetrap/services/ftp_spec.rb
125
+ - spec/micetrap/services/http_spec.rb
126
+ - spec/micetrap/services/mysql_spec.rb
127
+ - spec/micetrap/services/samba_spec.rb
128
+ - spec/micetrap/services/torrent_spec.rb
129
+ - spec/spec_helper.rb
130
+ has_rdoc: true
131
+ homepage: http://github.com/txus/micetrap
132
+ licenses: []
133
+
134
+ post_install_message:
135
+ rdoc_options: []
136
+
137
+ require_paths:
138
+ - lib
139
+ required_ruby_version: !ruby/object:Gem::Requirement
140
+ none: false
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ segments:
145
+ - 0
146
+ version: "0"
147
+ required_rubygems_version: !ruby/object:Gem::Requirement
148
+ none: false
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ segments:
153
+ - 0
154
+ version: "0"
155
+ requirements: []
156
+
157
+ rubyforge_project: micetrap
158
+ rubygems_version: 1.3.7
159
+ signing_key:
160
+ specification_version: 3
161
+ summary: Catch evil hackers on the fly by placing open-port traps emulating fake vulnerable services!
162
+ test_files:
163
+ - spec/micetrap/logger_spec.rb
164
+ - spec/micetrap/server_spec.rb
165
+ - spec/micetrap/services/base_spec.rb
166
+ - spec/micetrap/services/ftp_spec.rb
167
+ - spec/micetrap/services/http_spec.rb
168
+ - spec/micetrap/services/mysql_spec.rb
169
+ - spec/micetrap/services/samba_spec.rb
170
+ - spec/micetrap/services/torrent_spec.rb
171
+ - spec/spec_helper.rb