spamchronic 0.0.2

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/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011-2012 Matt Jezorek
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,14 @@
1
+ # MailPot
2
+
3
+ MailPot is a simple SMTP honeypot that will catch email and save it to a database
4
+ MailPot works to gain some automatic analysis and probe detection
5
+
6
+ ## Features
7
+ * Catches all email and stores it
8
+ * Works with Attachements
9
+ * Runs as a daemon in the background
10
+ * Written in EventMachine
11
+
12
+ ## How
13
+ 1. `gem install mailpot`
14
+ 2. `mailpot`
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.2
data/bin/spamchronic ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ require "rubygems"
3
+ require "bundler/setup"
4
+ require 'mailpot'
5
+ Mailpot.run!
@@ -0,0 +1,4 @@
1
+ require 'eventmachine'
2
+ module Mailpot::Events
3
+ MessageAdded = EventMachine::Channel.new
4
+ end
@@ -0,0 +1,72 @@
1
+ require 'eventmachine'
2
+ require 'yaml'
3
+ require 'base64'
4
+ require 'socket'
5
+ require 'zlib'
6
+ require 'digest/md5'
7
+ require 'aws'
8
+ require 'mail'
9
+ require 'net/smtp'
10
+
11
+ module Mailpot::Mail
12
+ module_function
13
+
14
+ @initialized = false
15
+ # setup connections etc
16
+ def initialize
17
+ config = Mailpot.get_config
18
+ yml = YAML.load_file config[:key_file]
19
+ @bucket = yml['bucket']
20
+ @queue = yml['queue']
21
+ @s3 = AWS::S3.new(yml)
22
+ @sqs = AWS::SQS.new(yml)
23
+ @initialized = true
24
+ end
25
+
26
+ def add_message(message)
27
+ if !@initialized
28
+ initialize
29
+ end
30
+ msg = Hash.new
31
+ msg[:source] = message[:source]
32
+ msg[:sender] = message[:sender]
33
+ msg[:source_ip] = message[:ip]
34
+ msg[:recipients] = message[:recipients]
35
+ msg[:probe] = detect_probe(message)
36
+ # we must at this point detect probes because we need them to be sent
37
+ encoded_message = Base64.encode64(msg.to_json)
38
+ deflate_encoded_message = gzdeflate(encoded_message)
39
+ digest = Digest::MD5.hexdigest(deflate_encoded_message)
40
+ store_message(digest, deflate_encoded_message)
41
+ end
42
+
43
+ def detect_probe(msg)
44
+ config = Mailpot.get_config
45
+ mail = Mail.new(msg[:source])
46
+ # First rule we want to detect is when the ip of the honeypot is in the subject
47
+ if mail.subject.include? config[:smtp_ip]
48
+ return [true, forward_probe(msg)]
49
+ end
50
+ return [false, false]
51
+ end
52
+
53
+ def forward_probe(msg)
54
+ Net::SMTP.start('localhost') do | smtp|
55
+ smtp.send_message msg[:source], msg[:sender], msg[:recipients]
56
+ end
57
+ end
58
+
59
+ def store_message(key, value)
60
+ Thread.new {
61
+ mail = @s3.buckets[@bucket].objects[key]
62
+ mail.write(value)
63
+ q = @sqs.queues[@queue]
64
+ msg = q.send_message(key)
65
+ }
66
+ end
67
+
68
+ def gzdeflate(s)
69
+ Zlib::Deflate.new(nil, -Zlib::MAX_WBITS).deflate(s, Zlib::FINISH)
70
+ end
71
+
72
+ end
@@ -0,0 +1,66 @@
1
+ require 'eventmachine'
2
+ require 'socket'
3
+ require 'yaml'
4
+
5
+ class Mailpot::Smtp < EventMachine::Protocols::SmtpServer
6
+ def current_message
7
+ @current_message ||= {}
8
+ end
9
+
10
+ def receive_reset
11
+ @current_message = nil
12
+ true
13
+ end
14
+
15
+ def get_server_greeting
16
+ c = Mailpot.get_config
17
+ yml = YAML.load_file c[:key_file]
18
+ host = get_server_domain
19
+ t = DateTime.now.strftime('%a, %d %b %Y %H:%M:%S %z')
20
+ banner = yml['banner']
21
+ banner = banner.gsub('{host}', host)
22
+ banner = banner.gsub('{date}', t)
23
+ return banner
24
+ end
25
+
26
+ def get_server_domain
27
+ Socket.gethostbyname(Socket.gethostname).first
28
+ end
29
+
30
+ def receive_sender(sender)
31
+ current_message[:sender] = sender
32
+ end
33
+
34
+ def receive_recipient(recipient)
35
+ current_message[:recipients] ||= []
36
+ current_message[:recipients] << recipient
37
+ true
38
+ end
39
+
40
+ def receive_data_chunk(lines)
41
+ current_message[:source] ||= ""
42
+ current_message[:source] += lines.join("\n")
43
+ true
44
+ end
45
+
46
+ def receive_message
47
+ port, ip = Socket.unpack_sockaddr_in(get_peername)
48
+ current_message[:ip] = ip
49
+ current_message[:port] = port
50
+ Mailpot::Mail.add_message current_message
51
+ puts "==> SMTP: Received message from '#{current_message[:sender]}' (#{current_message[:source].length} bytes)"
52
+ true
53
+ rescue
54
+ puts "*** Error receiving message: #{current_message.inspect}"
55
+ puts " Exception: #{$!}"
56
+ puts " Backtrace:"
57
+ $!.backtrace.each do |line|
58
+ puts " #{line}"
59
+ end
60
+ puts " Please submit this as an issue at https://github.com/mjezorek/Mailpot/issues"
61
+ false
62
+ ensure
63
+ @current_message = nil
64
+ end
65
+
66
+ end
data/lib/mailpot.rb ADDED
@@ -0,0 +1,101 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+ require 'active_support/all'
4
+ require 'eventmachine'
5
+ require 'optparse'
6
+ require 'rbconfig'
7
+
8
+ module Mailpot extend ActiveSupport::Autoload
9
+ autoload :Smtp
10
+ autoload :Mail
11
+
12
+ module_function
13
+
14
+ @@defaults = {
15
+ :smtp_ip => '127.0.0.1',
16
+ :smtp_port => '1025',
17
+ :verbose => false,
18
+ :daemon => true,
19
+ :key_file => '/etc/mailpot/keys.yml',
20
+ :banner => '{host} ESMTP'
21
+ }
22
+
23
+ def parse! arguments=ARGV, defaults=@@defaults
24
+ @@defaults.dup.tap do |options|
25
+ OptionParser.new do |parser|
26
+ parser.banner = "Usage: mailpot [options]"
27
+ parser.version = File.read(File.expand_path("../../VERSION", __FILE__))
28
+
29
+ parser.on("--ip IP", "Set the ip address of the smtp server") do |ip|
30
+ options[:smtp_ip] = ip
31
+ end
32
+
33
+ parser.on("--keys KEYFILE", "Set the key file that contains AWS creds") do |f|
34
+ options[:key_file] = f
35
+ end
36
+
37
+ parser.on("--port PORT", Integer, "Set the port of the smtp server") do |port|
38
+ options[:smtp_port] = port
39
+ end
40
+
41
+ parser.on('-f', '--foreground', 'Run in forground') do
42
+ options[:daemon] = false
43
+ end
44
+
45
+ parser.on('-v', '--verbose', 'Be more verbose') do
46
+ options[:verbose] = true
47
+ end
48
+
49
+ parser.on('-h', '--help', 'Display help information') do
50
+ puts parser
51
+ exit!
52
+ end
53
+ end.parse!
54
+ end
55
+ end
56
+
57
+ def get_config
58
+ options &&= @@defaults.merge options
59
+ options ||= parse!
60
+ end
61
+
62
+ def run! options=nil
63
+ #options &&= @@defaults.merge options
64
+ #options ||= parse!
65
+ #@config = options
66
+ options = get_config
67
+ puts "Starting MailPot"
68
+ EventMachine.run do
69
+ rescue_port options[:smtp_port] do
70
+ EventMachine.start_server options[:smtp_ip], options[:smtp_port], Smtp
71
+ puts "==> smtp://#{options[:smtp_ip]}:#{options[:smtp_port]}"
72
+ end
73
+
74
+ if options[:daemon]
75
+ EventMachine.next_tick do
76
+ puts "*** Mailpot now runs as a daemon by default"
77
+ Process.daemon
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ def quit!
84
+ EventMachine.next_tick {EventMachine.stop_event_loop}
85
+ end
86
+
87
+ protected
88
+ module_function
89
+ def rescue_port port
90
+ begin
91
+ yield
92
+ rescue RuntimeError
93
+ if $!.to_s =~ /\bno acceptor\b/
94
+ puts "~~> ERROR: Somethings using port #{port}. Are you already running MailPot"
95
+ exit -1
96
+ else
97
+ raise
98
+ end
99
+ end
100
+ end
101
+ end
metadata ADDED
@@ -0,0 +1,160 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spamchronic
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 2
10
+ version: 0.0.2
11
+ platform: ruby
12
+ authors:
13
+ - Matt Jezorek
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-02-16 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: activesupport
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ hash: 7
29
+ segments:
30
+ - 3
31
+ - 0
32
+ version: "3.0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: eventmachine
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ hash: 19
44
+ segments:
45
+ - 0
46
+ - 12
47
+ version: "0.12"
48
+ type: :runtime
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: aws-sdk
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ type: :runtime
63
+ version_requirements: *id003
64
+ - !ruby/object:Gem::Dependency
65
+ name: mail
66
+ prerelease: false
67
+ requirement: &id004 !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 3
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ type: :runtime
77
+ version_requirements: *id004
78
+ - !ruby/object:Gem::Dependency
79
+ name: rake
80
+ prerelease: false
81
+ requirement: &id005 !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ hash: 3
87
+ segments:
88
+ - 0
89
+ version: "0"
90
+ type: :development
91
+ version_requirements: *id005
92
+ - !ruby/object:Gem::Dependency
93
+ name: rdoc
94
+ prerelease: false
95
+ requirement: &id006 !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ hash: 3
101
+ segments:
102
+ - 0
103
+ version: "0"
104
+ type: :development
105
+ version_requirements: *id006
106
+ description: " MailPot is a simple SMTP server honeypot that will catch emails and store\n them in S3 and then pop a message into SQS for later processing\n"
107
+ email: mjezorek@gmail.com
108
+ executables:
109
+ - spamchronic
110
+ extensions: []
111
+
112
+ extra_rdoc_files:
113
+ - README.md
114
+ - LICENSE
115
+ files:
116
+ - README.md
117
+ - LICENSE
118
+ - VERSION
119
+ - bin/spamchronic
120
+ - lib/mailpot/events.rb
121
+ - lib/mailpot/mail.rb
122
+ - lib/mailpot/smtp.rb
123
+ - lib/mailpot.rb
124
+ homepage: http://mattjezorek.com/
125
+ licenses: []
126
+
127
+ post_install_message:
128
+ rdoc_options: []
129
+
130
+ require_paths:
131
+ - lib
132
+ required_ruby_version: !ruby/object:Gem::Requirement
133
+ none: false
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ hash: 57
138
+ segments:
139
+ - 1
140
+ - 8
141
+ - 7
142
+ version: 1.8.7
143
+ required_rubygems_version: !ruby/object:Gem::Requirement
144
+ none: false
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ hash: 3
149
+ segments:
150
+ - 0
151
+ version: "0"
152
+ requirements: []
153
+
154
+ rubyforge_project:
155
+ rubygems_version: 1.7.2
156
+ signing_key:
157
+ specification_version: 3
158
+ summary: Runs an SMTP Server and catches emails, will pass probes when identified as a probe
159
+ test_files: []
160
+