spamchronic 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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
+