mailpot 0.0.1
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 +20 -0
- data/README.md +14 -0
- data/VERSION +1 -0
- data/bin/mailpot +5 -0
- data/lib/mailpot.rb +100 -0
- data/lib/mailpot/events.rb +4 -0
- data/lib/mailpot/mail.rb +54 -0
- data/lib/mailpot/smtp.rb +57 -0
- metadata +146 -0
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.1
|
data/bin/mailpot
ADDED
data/lib/mailpot.rb
ADDED
@@ -0,0 +1,100 @@
|
|
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
|
+
}
|
21
|
+
|
22
|
+
def parse! arguments=ARGV, defaults=@@defaults
|
23
|
+
@@defaults.dup.tap do |options|
|
24
|
+
OptionParser.new do |parser|
|
25
|
+
parser.banner = "Usage: mailpot [options]"
|
26
|
+
parser.version = File.read(File.expand_path("../../VERSION", __FILE__))
|
27
|
+
|
28
|
+
parser.on("--ip IP", "Set the ip address of the smtp server") do |ip|
|
29
|
+
options[:smtp_ip] = ip
|
30
|
+
end
|
31
|
+
|
32
|
+
parser.on("--keys KEYFILE", "Set the key file that contains AWS creds") do |f|
|
33
|
+
options[:key_file] = f
|
34
|
+
end
|
35
|
+
|
36
|
+
parser.on("--port PORT", Integer, "Set the port of the smtp server") do |port|
|
37
|
+
options[:smtp_port] = port
|
38
|
+
end
|
39
|
+
|
40
|
+
parser.on('-f', '--foreground', 'Run in forground') do
|
41
|
+
options[:daemon] = false
|
42
|
+
end
|
43
|
+
|
44
|
+
parser.on('-v', '--verbose', 'Be more verbose') do
|
45
|
+
options[:verbose] = true
|
46
|
+
end
|
47
|
+
|
48
|
+
parser.on('-h', '--help', 'Display help information') do
|
49
|
+
puts parser
|
50
|
+
exit!
|
51
|
+
end
|
52
|
+
end.parse!
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def get_config
|
57
|
+
options &&= @@defaults.merge options
|
58
|
+
options ||= parse!
|
59
|
+
end
|
60
|
+
|
61
|
+
def run! options=nil
|
62
|
+
#options &&= @@defaults.merge options
|
63
|
+
#options ||= parse!
|
64
|
+
#@config = options
|
65
|
+
options = get_config
|
66
|
+
puts "Starting MailPot"
|
67
|
+
EventMachine.run do
|
68
|
+
rescue_port options[:smtp_port] do
|
69
|
+
EventMachine.start_server options[:smtp_ip], options[:smtp_port], Smtp
|
70
|
+
puts "==> smtp://#{options[:smtp_ip]}:#{options[:smtp_port]}"
|
71
|
+
end
|
72
|
+
|
73
|
+
if options[:daemon]
|
74
|
+
EventMachine.next_tick do
|
75
|
+
puts "*** Mailpot now runs as a daemon by default"
|
76
|
+
Process.daemon
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def quit!
|
83
|
+
EventMachine.next_tick {EventMachine.stop_event_loop}
|
84
|
+
end
|
85
|
+
|
86
|
+
protected
|
87
|
+
module_function
|
88
|
+
def rescue_port port
|
89
|
+
begin
|
90
|
+
yield
|
91
|
+
rescue RuntimeError
|
92
|
+
if $!.to_s =~ /\bno acceptor\b/
|
93
|
+
puts "~~> ERROR: Somethings using port #{port}. Are you already running MailPot"
|
94
|
+
exit -1
|
95
|
+
else
|
96
|
+
raise
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
data/lib/mailpot/mail.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'yaml'
|
3
|
+
require 'base64'
|
4
|
+
require 'socket'
|
5
|
+
require 'zlib'
|
6
|
+
require 'digest/md5'
|
7
|
+
require 'aws'
|
8
|
+
|
9
|
+
module Mailpot::Mail
|
10
|
+
module_function
|
11
|
+
|
12
|
+
@initialized = false
|
13
|
+
# setup connections etc
|
14
|
+
def initialize
|
15
|
+
config = Mailpot.get_config
|
16
|
+
yml = YAML.load_file config[:key_file]
|
17
|
+
@bucket = yml['bucket']
|
18
|
+
@queue = yml['queue']
|
19
|
+
@s3 = AWS::S3.new(yml)
|
20
|
+
@sqs = AWS::SQS.new(yml)
|
21
|
+
@initialized = true
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_message(message)
|
25
|
+
if !@initialized
|
26
|
+
initialize
|
27
|
+
end
|
28
|
+
msg = Hash.new
|
29
|
+
msg[:source] = message[:source]
|
30
|
+
msg[:sender] = message[:sender]
|
31
|
+
msg[:source_ip] = message[:ip]
|
32
|
+
msg[:recipients] = message[:recipients]
|
33
|
+
# worried about dedupe here and need to come up with a way at 1M messages
|
34
|
+
# a day this could be a lot of storage
|
35
|
+
encoded_message = Base64.encode64(msg.to_json)
|
36
|
+
deflate_encoded_message = gzdeflate(encoded_message)
|
37
|
+
digest = Digest::MD5.hexdigest(deflate_encoded_message)
|
38
|
+
store_message(digest, deflate_encoded_message)
|
39
|
+
end
|
40
|
+
|
41
|
+
def store_message(key, value)
|
42
|
+
Thread.new {
|
43
|
+
mail = @s3.buckets[@bucket].objects[key]
|
44
|
+
mail.write(value)
|
45
|
+
q = @sqs.queues[@queue]
|
46
|
+
msg = q.send_message(key)
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
def gzdeflate(s)
|
51
|
+
Zlib::Deflate.new(nil, -Zlib::MAX_WBITS).deflate(s, Zlib::FINISH)
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
data/lib/mailpot/smtp.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'socket'
|
3
|
+
class Mailpot::Smtp < EventMachine::Protocols::SmtpServer
|
4
|
+
def current_message
|
5
|
+
@current_message ||= {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def receive_reset
|
9
|
+
@current_message = nil
|
10
|
+
true
|
11
|
+
end
|
12
|
+
|
13
|
+
def get_server_greeting
|
14
|
+
"ESMTP Sendmail 8.12.9/8.12.9;"
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_server_domain
|
18
|
+
Socket.gethostbyname(Socket.gethostname).first
|
19
|
+
end
|
20
|
+
|
21
|
+
def receive_sender(sender)
|
22
|
+
current_message[:sender] = sender
|
23
|
+
end
|
24
|
+
|
25
|
+
def receive_recipient(recipient)
|
26
|
+
current_message[:recipients] ||= []
|
27
|
+
current_message[:recipients] << recipient
|
28
|
+
true
|
29
|
+
end
|
30
|
+
|
31
|
+
def receive_data_chunk(lines)
|
32
|
+
current_message[:source] ||= ""
|
33
|
+
current_message[:source] += lines.join("\n")
|
34
|
+
true
|
35
|
+
end
|
36
|
+
|
37
|
+
def receive_message
|
38
|
+
port, ip = Socket.unpack_sockaddr_in(get_peername)
|
39
|
+
current_message[:ip] = ip
|
40
|
+
current_message[:port] = port
|
41
|
+
Mailpot::Mail.add_message current_message
|
42
|
+
puts "==> SMTP: Received message from '#{current_message[:sender]}' (#{current_message[:source].length} bytes)"
|
43
|
+
true
|
44
|
+
rescue
|
45
|
+
puts "*** Error receiving message: #{current_message.inspect}"
|
46
|
+
puts " Exception: #{$!}"
|
47
|
+
puts " Backtrace:"
|
48
|
+
$!.backtrace.each do |line|
|
49
|
+
puts " #{line}"
|
50
|
+
end
|
51
|
+
puts " Please submit this as an issue at https://github.com/mjezorek/Mailpot/issues"
|
52
|
+
false
|
53
|
+
ensure
|
54
|
+
@current_message = nil
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
metadata
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mailpot
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Matt Jezorek
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-02-15 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: rake
|
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: :development
|
77
|
+
version_requirements: *id004
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rdoc
|
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
|
+
description: " MailPot is a simple SMTP server honeypot that will catch emails and store\n them deduplicated in a database. This will extract links from emails and do \n other analysis on it. Once probes can be identified they will be passed.\n"
|
93
|
+
email: mjezorek@gmail.com
|
94
|
+
executables:
|
95
|
+
- mailpot
|
96
|
+
extensions: []
|
97
|
+
|
98
|
+
extra_rdoc_files:
|
99
|
+
- README.md
|
100
|
+
- LICENSE
|
101
|
+
files:
|
102
|
+
- README.md
|
103
|
+
- LICENSE
|
104
|
+
- VERSION
|
105
|
+
- bin/mailpot
|
106
|
+
- lib/mailpot/events.rb
|
107
|
+
- lib/mailpot/mail.rb
|
108
|
+
- lib/mailpot/smtp.rb
|
109
|
+
- lib/mailpot.rb
|
110
|
+
homepage: http://mattjezorek.com/
|
111
|
+
licenses: []
|
112
|
+
|
113
|
+
post_install_message:
|
114
|
+
rdoc_options: []
|
115
|
+
|
116
|
+
require_paths:
|
117
|
+
- lib
|
118
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
119
|
+
none: false
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
hash: 57
|
124
|
+
segments:
|
125
|
+
- 1
|
126
|
+
- 8
|
127
|
+
- 7
|
128
|
+
version: 1.8.7
|
129
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
130
|
+
none: false
|
131
|
+
requirements:
|
132
|
+
- - ">="
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
hash: 3
|
135
|
+
segments:
|
136
|
+
- 0
|
137
|
+
version: "0"
|
138
|
+
requirements: []
|
139
|
+
|
140
|
+
rubyforge_project:
|
141
|
+
rubygems_version: 1.7.2
|
142
|
+
signing_key:
|
143
|
+
specification_version: 3
|
144
|
+
summary: Runs an SMTP Server and catches emails, will pass probes when identified as a probe
|
145
|
+
test_files: []
|
146
|
+
|