Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Services

  • Loading branch information...
commit 066007551d8ff60e39eb880fc8194d7b96eb7e14 1 parent bd2a0de
Josep M. Bach authored
1  .gitignore
... ... @@ -1,3 +1,4 @@
1 1 pkg/*
2 2 *.gem
3 3 .bundle
  4 +*.log
12 bin/micetrap
... ... @@ -1,6 +1,7 @@
1 1 #!/usr/bin/env ruby -w
2 2 $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
3 3
  4 +require 'trollop' unless defined?(Trollop)
4 5 require 'micetrap'
5 6 require 'micetrap/version'
6 7
@@ -32,19 +33,20 @@ opts = Trollop::options do
32 33 Running it with sudo will allow you to use default, unsuspicious ports,
33 34 which may give you advantage at tricking a smart attacker.
34 35
35   - The available options are are:
36   - #{SERVICES.join('\n')}
  36 + The available services are are:
  37 + #{SERVICES.join(', ')}
37 38
38 39 Usage:
39 40 [sudo] micetrap <service> [options]
40 41
41 42 where [options] are:
42 43 EOS
43   - opt :port, "A specific port to use", :default => nil
  44 + opt :port, "A specific port to use", :default => nil, :type => :integer
44 45 stop_on SERVICES
45 46 end
46 47
47   -service = ARGV.shift
  48 +puts opts.inspect
  49 +service = ARGV.shift.to_sym
48 50 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)
49 51
50   -Micetrap::Server.new(opts).fire!
  52 +Micetrap::Server.new(opts.update(:service => service)).fire!
7 lib/micetrap.rb
... ... @@ -1,12 +1,17 @@
1 1 require 'micetrap/services/exceptions'
2 2 require 'micetrap/services/base'
  3 +
3 4 require 'micetrap/logger'
4 5 require 'micetrap/server'
5 6
6 7 module Micetrap
7 8 class << self
8 9 def services
9   - []
  10 + [:ftp, :torrent, :samba, :http, :mysql]
10 11 end
11 12 end
12 13 end
  14 +
  15 +Micetrap.services.each do |service|
  16 + require "micetrap/services/#{service}"
  17 +end
16 lib/micetrap/logger.rb
@@ -13,15 +13,23 @@ def initialize(service_name)
13 13 end
14 14
15 15 def file
16   - @file ||= File.open(@filename, 'w')
  16 + @file ||= File.new(@filename, 'a')
17 17 end
18 18
19   - def log_probe(line, addr, remote_host, remote_port)
20   - file.write "\n#{Time.now} Recorded a probe coming from #{remote_host} - #{addr}:#{remote_port} containing the following:\n\t\t#{line}"
  19 + def log_probe(line, remote_host, remote_port)
  20 + logged = "\n#{Time.now} Recorded a probe coming from #{remote_host}:#{remote_port} containing the following:\n\t\t#{line}"
  21 + puts "About to write there"
  22 + file.write logged
  23 + puts "wrote to #{file.inspect}"
  24 + puts logged
21 25 end
22 26
23 27 def log_message(line)
24   - file.write "\n#{Time.now} ::: #{line} :::"
  28 + logged = "\n#{Time.now} ::: #{line} :::"
  29 + puts "About to write there"
  30 + file.write logged
  31 + puts "wrote to #{file.inspect}"
  32 + puts logged
25 33 end
26 34
27 35 end
2  lib/micetrap/server.rb
@@ -10,7 +10,7 @@ def initialize(options)
10 10 @service =
11 11 eval("Micetrap::Services::#{options[:service].to_s.capitalize}").new
12 12 @port = options[:port] # Optional
13   - rescue NameError
  13 + rescue NameError=>e
14 14 raise Services::UnrecognizedServiceException.new("Service #{options[:service].to_s.capitalize} is not recognized")
15 15 end
16 16
26 lib/micetrap/services/base.rb
@@ -7,23 +7,33 @@ class ClientQuitError < RuntimeError; end
7 7 attr_reader :logger
8 8
9 9 def initialize
10   - @logger = Logger.new self.class.name.downcase.to_sym
  10 + @logger = Logger.new self.name.downcase.to_sym
11 11 end
12 12
13 13 def fire port = nil
14   - server = TCPServer.open(port || default_ports.sample || 0)
  14 + port = port.to_i if port
  15 + begin
  16 + server = TCPServer.open(port || default_ports.sample || 0)
  17 + rescue Errno::EACCES
  18 + puts "Seems that you are trying to use a system port, for which you need root privileges.\n\nRun micetrap with a custom port if you don't want to sudo!\n"
  19 + exit(1)
  20 + end
15 21 @port = server.addr[1]
16 22 @addrs = server.addr[2..-1].uniq
17 23
18   - logger.log_message "#{@name} micetrap listening on #{@addrs.collect{|a|"#{a}:#{port}"}.join(' ')}"
  24 + logger.log_message "#{name} micetrap listening on #{@addrs.collect{|a|"#{a}:#{port}"}.join(' ')}"
  25 + listen(server)
  26 + end
19 27
  28 + def listen(server)
20 29 # Handle Ctrl-C to exit!
21 30 interrupted = false
22 31 trap("INT") { interrupted = true }
23 32
24 33 while not interrupted do
  34 + socket = server.accept
25 35 Thread.start do
26   - read_from(server.accept)
  36 + read_from(socket)
27 37 end
28 38 end
29 39 end
@@ -39,13 +49,13 @@ def read_from(socket)
39 49 while line = s.gets # read a line at a time
40 50 raise ClientQuitError if line =~ /^die\r?$/
41 51
42   - logger.log_probe line, addr, name, port
  52 + logger.log_probe line, name, port
43 53
44 54 if line.strip == ""
45 55 s.write response
46 56 logger.log_message "Responded misleadingly: let's drive those hackers nuts!"
47 57 s.close
48   - exit(0)
  58 + Kernel.exit(0)
49 59 end
50 60 end
51 61 rescue ClientQuitError
@@ -60,6 +70,10 @@ def read_from(socket)
60 70 def default_ports; []; end;
61 71 def response; ""; end;
62 72
  73 + def name
  74 + self.class.name.split('::').last
  75 + end
  76 +
63 77 end
64 78 end
65 79 end
22 lib/micetrap/services/ftp.rb
... ... @@ -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
20 lib/micetrap/services/http.rb
... ... @@ -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
20 lib/micetrap/services/mysql.rb
... ... @@ -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
20 lib/micetrap/services/samba.rb
... ... @@ -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
20 lib/micetrap/services/torrent.rb
... ... @@ -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
10 spec/micetrap/logger_spec.rb
@@ -20,7 +20,7 @@ module Micetrap
20 20 describe "#file" do
21 21 it 'returns the log file' do
22 22 file = double('file')
23   - File.stub(:open).and_return file
  23 + File.stub(:new).and_return file
24 24 subject.file.should be(file)
25 25 end
26 26 end
@@ -30,14 +30,14 @@ module Micetrap
30 30 file = double('file')
31 31 now = Time.now
32 32 Time.stub(:now).and_return now
33   - File.stub(:open).and_return file
  33 + File.stub(:new).and_return file
34 34
35   - expected_string = "\n#{now} Recorded a probe coming from hackerz.com - 234.43.14.35:5978 containing the following:\n\t\t###EVILPROBE###"
  35 + expected_string = "\n#{now} Recorded a probe coming from hackerz.com:5978 containing the following:\n\t\t###EVILPROBE###"
36 36
37 37 subject.file.should_receive(:write)
38 38 .with expected_string
39 39
40   - subject.log_probe "###EVILPROBE###", "234.43.14.35", "hackerz.com", 5978
  40 + subject.log_probe "###EVILPROBE###", "hackerz.com", 5978
41 41 end
42 42 end
43 43
@@ -46,7 +46,7 @@ module Micetrap
46 46 file = double('file')
47 47 now = Time.now
48 48 Time.stub(:now).and_return now
49   - File.stub(:open).and_return file
  49 + File.stub(:new).and_return file
50 50
51 51 expected_string = "\n#{now} ::: Warning! :::"
52 52
88 spec/micetrap/services/base_spec.rb
@@ -4,34 +4,108 @@ module Micetrap
4 4 module Services
5 5 describe Base do
6 6 describe "#fire" do
  7 +
  8 + before(:each) do
  9 + subject.stub(:listen)
  10 + end
  11 +
7 12 context 'when given a port' do
8 13 it 'fires up the service on that port' do
9   -
  14 + server = double('server', :addr => [1,2,3])
  15 + TCPServer.should_receive(:open).with(5900).and_return server
  16 + subject.fire 5900
10 17 end
11 18 end
12 19 context 'when port is nil' do
13 20 it 'fires up the service on one of the default ports' do
14   -
  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
15 26 end
16 27 context 'but when no default ports are specified' do
17 28 it 'uses the port 0' do
18   -
  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
19 34 end
20 35 end
21 36 end
22 37 it 'logs a message telling the trap is listening' do
23   -
  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 micetrap listening')
  42 + end
  43 + subject.fire
24 44 end
  45 + end
  46 + describe "#listen", :blocking => true do
25 47 it 'calls read_from every time a connection is accepted' do
26 48 connection = double('connection')
27 49 server = double('server', :addr => [1,2,3], :accept => connection)
28   - TCPServer.should_receive(:open).and_return server
29   - subject.logger.stub(:log)
30 50
31 51 subject.should_receive(:read_from).with(connection).any_number_of_times
32 52 puts "Press Ctrl-C to resume specs! Don't worry, it's all under control :)"
33   - subject.fire
  53 + subject.listen(server)
  54 + end
  55 + end
  56 + describe "#read_from" do
  57 + let(:peeraddr) { [ nil, 4983, 'hackerz.com', '293.13.23.32'] }
  58 + let(:socket) do
  59 + double :socket, :peeraddr => peeraddr
  60 + end
  61 + before(:each) do
  62 + socket.should_receive(:close).any_number_of_times
34 63 end
  64 +
  65 + context 'when the socket contains a line with die' do
  66 + it 'dies' do
  67 + socket.should_receive(:gets).and_return 'die'
  68 + subject.logger.should_not_receive(:log_probe)
  69 + subject.logger.should_receive(:log_message).with("hackerz.com:4983 disconnected")
  70 +
  71 + subject.read_from(socket)
  72 + end
  73 + end
  74 +
  75 + context 'otherwise' do
  76 + it 'logs the probe' do
  77 + socket.should_receive(:gets).and_return 'some probe', nil
  78 + subject.logger.should_receive(:log_probe).with 'some probe', 'hackerz.com', 4983
  79 +
  80 + subject.read_from(socket)
  81 + end
  82 + context 'when the line is blank' do
  83 + it 'does respond with the appropriate response' do
  84 + Kernel.stub(:exit)
  85 + socket.should_receive(:gets).and_return '', nil
  86 + subject.logger.stub(:log_probe)
  87 + appropriate_response = double :response
  88 + subject.should_receive(:response).and_return appropriate_response
  89 +
  90 + socket.should_receive(:write).with(appropriate_response)
  91 + subject.logger.should_receive(:log_message)
  92 +
  93 + subject.read_from(socket)
  94 + end
  95 + end
  96 + context 'when the line contains any other thing' do
  97 + it 'does not respond' do
  98 + socket.should_receive(:gets).and_return 'some evil probe', nil
  99 + subject.logger.stub(:log_probe)
  100 +
  101 + subject.should_not_receive(:response)
  102 + socket.should_not_receive(:write)
  103 +
  104 + subject.read_from(socket)
  105 + end
  106 + end
  107 + end
  108 +
35 109 end
36 110 end
37 111 end
24 spec/micetrap/services/ftp_spec.rb
... ... @@ -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
24 spec/micetrap/services/http_spec.rb
... ... @@ -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
24 spec/micetrap/services/mysql_spec.rb
... ... @@ -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
24 spec/micetrap/services/samba_spec.rb
... ... @@ -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
24 spec/micetrap/services/torrent_spec.rb
... ... @@ -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 comments on commit 0660075

Please sign in to comment.
Something went wrong with that request. Please try again.