thm 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
data/lib/thm.rb ADDED
@@ -0,0 +1,49 @@
1
+ ########################################################################
2
+ #
3
+ # Author: Brian Hood
4
+ #
5
+ # Description: Threatmonitor Producer
6
+ #
7
+ # Producer / Consumer controller module
8
+ #
9
+ ########################################################################
10
+
11
+ require 'rubygems'
12
+ require 'amqp'
13
+ require 'bunny'
14
+ require 'eventmachine'
15
+ require 'guid'
16
+ require 'yaml'
17
+ require 'pcaplet'
18
+ require 'pcaprub' # For Live capture / write
19
+ #require '../datalayerlight.rb'
20
+ require File.expand_path(File.join(
21
+ File.dirname(__FILE__),
22
+ "../datalayerlight.rb"))
23
+ include Pcap
24
+
25
+ # TODO
26
+ #
27
+ # Create def's for that packet SQL / Refactor to provent code duplication
28
+ # Create def's for Hash table YAML same idea as above.
29
+
30
+ module Tools
31
+
32
+ class << self
33
+
34
+ def guid
35
+ guid = Guid.new # Generate GUID
36
+ end
37
+
38
+ end
39
+
40
+ end
41
+
42
+ # Load Datasources
43
+ require "#{File.dirname(__FILE__)}/thm/dataservices.rb"
44
+ require "#{File.dirname(__FILE__)}/thm/producer.rb"
45
+ require "#{File.dirname(__FILE__)}/thm/consumer.rb"
46
+ require "#{File.dirname(__FILE__)}/thm/localmachine.rb"
47
+ require "#{File.dirname(__FILE__)}/thm/version.rb"
48
+
49
+
@@ -0,0 +1,228 @@
1
+
2
+ trap("INT") {
3
+
4
+ if EM.reactor_running? == true
5
+ puts "Exiting Reactor thread ..."
6
+ EventMachine.stop
7
+ end
8
+ exit
9
+ }
10
+
11
+ module Thm
12
+
13
+ # Bulk load from queue YAML into Database
14
+
15
+ class Consumer < DataServices
16
+
17
+ def from_mq_to_db
18
+ # TODO: Test this.
19
+ # Process ippacket queue first.
20
+ n = 0
21
+ # Using AMQP Gem here as Bunny never exits the thread so i can't move on to TCP / UDP probably migrate all to this gem.
22
+ banner = "\e[1;34mStage 1: Load IP Packet data \e[0m\ \n"
23
+ banner << "\e[1;34m=================================\e[0m\ \n"
24
+ puts banner
25
+ EM.run do
26
+ connection = AMQP.connect(:host => "#{@mqhost}", :user => "#{@mquser}", :pass => "#{@mqpass}", :vhost => "#{@mqvhost}")
27
+ puts "Connected to AMQP broker. Running #{AMQP::VERSION}"
28
+ channel = AMQP::Channel.new(connection)
29
+ puts "Queue: #{@queueprefix}_ippacket"
30
+ queue = channel.queue("#{@queueprefix}_ippacket")
31
+ exchange = channel.direct("")
32
+ t = 0
33
+ queue.bind("#{@queueprefix}_ippacket").subscribe do |metadata, body|
34
+ #puts "MSGID: [#{n}] Received #{body}"
35
+ ipdata = YAML.load(body).to_a
36
+ ipdatadim = ipdata[0][1]
37
+ ip_packet = "INSERT INTO #{@tblname_ippacket} "
38
+ ip_packet << "(guid, recv_date, ip_df, ip_dst, ip_hlen, ip_id, ip_len, ip_mf, ip_off, ip_proto, ip_src, ip_sum, ip_tos, ip_ttl, ip_ver) "
39
+ ip_packet << "VALUES ("
40
+ ip_packet << "'#{ipdatadim["guid"]}',"
41
+ ip_packet << "'#{ipdatadim["recv_date"]}',"
42
+ ip_df = ipdatadim["ip_df"].to_s # Due to TrueClass issues will have a look later
43
+ if ip_df == "true"
44
+ ip_packet << "'Y',"
45
+ else
46
+ ip_packet << "'N',"
47
+ end
48
+ ip_packet << "'#{ipdatadim["ip_dst"]}',"
49
+ ip_packet << "'#{ipdatadim["ip_hlen"]}',"
50
+ ip_packet << "'#{ipdatadim["ip_id"]}',"
51
+ ip_packet << "'#{ipdatadim["ip_len"]}',"
52
+ ip_mf = ipdatadim["ip_mf"].to_s
53
+ if ip_mf == "true"
54
+ ip_packet << "'Y',"
55
+ else
56
+ ip_packet << "'N',"
57
+ end
58
+ ip_packet << "'#{ipdatadim["ip_off"]}',"
59
+ ip_packet << "'#{ipdatadim["ip_proto"]}',"
60
+ ip_packet << "'#{ipdatadim["ip_src"]}',"
61
+ ip_packet << "'#{ipdatadim["ip_sum"]}',"
62
+ ip_packet << "'#{ipdatadim["ip_tos"]}',"
63
+ ip_packet << "'#{ipdatadim["ip_ttl"]}',"
64
+ ip_packet << "'#{ipdatadim["ip_ver"]}');"
65
+ if t == 50
66
+ puts "\e[1;32m\ MSGID:\e[0m\ [#{n}] \e[1;32m\Generated SQL:\e[0m\ #{ip_packet}"
67
+ t = 0
68
+ end
69
+ t = t + 1 unless t == 50
70
+ res = @conn.query("#{ip_packet}")
71
+ @conn.save
72
+ n = n + 1
73
+ connection.close { EventMachine.stop }
74
+ end
75
+ end
76
+ ipcount = n
77
+ @conn.release
78
+ @conn.commit
79
+
80
+ # TCP Packet
81
+ n = 0
82
+ banner = "\e[1;34mStage 2: Load TCP Packet data \e[0m\ \n"
83
+ banner << "\e[1;34m=================================\e[0m\ \n"
84
+ puts banner
85
+ EM.run do
86
+ connection = AMQP.connect(:host => "#{@mqhost}", :user => "#{@mquser}", :pass => "#{@mqpass}", :vhost => "#{@mqvhost}")
87
+ puts "Connected to AMQP broker. Running #{AMQP::VERSION}"
88
+ channel = AMQP::Channel.new(connection)
89
+ puts "Queue: #{@queueprefix}_tcppacket"
90
+ queue = channel.queue("#{@queueprefix}_tcppacket")
91
+ exchange = channel.direct("")
92
+ t = 0
93
+ queue.bind("#{@queueprefix}_tcppacket").subscribe do |metadata, body|
94
+ #puts "MSGID: [#{n}] Received #{body}"
95
+ tcpdata = YAML.load(body).to_a
96
+ tcpdatadim = tcpdata[0][1]
97
+ tcp_packet = "INSERT INTO #{@tblname_tcppacket} "
98
+ tcp_packet << "(guid, recv_date, tcp_data_len, tcp_dport, tcp_ack, tcp_fin, tcp_syn, tcp_rst, tcp_psh, tcp_urg, tcp_off, tcp_hlen, tcp_seq, tcp_sum, tcp_sport, tcp_urp, "
99
+ tcp_packet << "tcp_win) "
100
+ tcp_packet << "VALUES ("
101
+ tcp_packet << "'#{tcpdatadim["guid"]}',"
102
+ tcp_packet << "'#{tcpdatadim["recv_date"]}', "
103
+ tcp_packet << "#{tcpdatadim["tcp_data_len"]},"
104
+ tcp_packet << "#{tcpdatadim["tcp_dport"]},"
105
+ tcp_ack = tcpdatadim["tcp_ack"].to_s
106
+ if tcp_ack == "true"
107
+ tcp_packet << "'Y',"
108
+ else
109
+ tcp_packet << "'N',"
110
+ end
111
+ tcp_fin = tcpdatadim["tcp_fin"].to_s
112
+ if tcp_fin == "true"
113
+ tcp_packet << "'Y',"
114
+ else
115
+ tcp_packet << "'N',"
116
+ end
117
+ tcp_syn = tcpdatadim["tcp_syn"].to_s
118
+ if tcp_syn == "true"
119
+ tcp_packet << "'Y',"
120
+ else
121
+ tcp_packet << "'N',"
122
+ end
123
+ tcp_rst = tcpdatadim["tcp_rst"].to_s
124
+ if tcp_rst == "true"
125
+ tcp_packet << "'Y',"
126
+ else
127
+ tcp_packet << "'N',"
128
+ end
129
+ tcp_psh = tcpdatadim["tcp_psh"].to_s
130
+ if tcp_psh == "true"
131
+ tcp_packet << "'Y',"
132
+ else
133
+ tcp_packet << "'N',"
134
+ end
135
+ tcp_urg = tcpdatadim["tcp_urg"].to_s
136
+ if tcp_urg == "true"
137
+ tcp_packet << "'Y',"
138
+ else
139
+ tcp_packet << "'N',"
140
+ end
141
+ tcp_packet << "#{tcpdatadim["tcp_off"]}, #{tcpdatadim["tcp_hlen"]}, #{tcpdatadim["tcp_seq"]}, #{tcpdatadim["tcp_sum"]}, #{tcpdatadim["tcp_sport"]}, #{tcpdatadim["tcp_urp"]}, #{tcpdatadim["tcp_win"]});"
142
+ if t == 50
143
+ puts "\e[1;32m\ MSGID:\e[0m\ [#{n}] \e[1;32m\Generated SQL:\e[0m\ #{tcp_packet}"
144
+ t = 0
145
+ end
146
+ t = t + 1 unless t == 50
147
+ res = @conn.query("#{tcp_packet}")
148
+ @conn.save
149
+ n = n + 1
150
+ connection.close { EventMachine.stop }
151
+ end
152
+ end
153
+ tcpcount = n
154
+ @conn.release
155
+ @conn.commit
156
+
157
+ # UDP Packet
158
+ n = 0
159
+ banner = "\e[1;34mStage 2: Load UDP Packet data \e[0m\ \n"
160
+ banner << "\e[1;34m=================================\e[0m\ \n"
161
+ puts banner
162
+ EM.run do
163
+ connection = AMQP.connect(:host => "#{@mqhost}", :user => "#{@mquser}", :pass => "#{@mqpass}", :vhost => "#{@mqvhost}")
164
+ puts "Connected to AMQP broker. Running #{AMQP::VERSION}"
165
+ channel = AMQP::Channel.new(connection)
166
+ puts "Queue: #{@queueprefix}_udppacket"
167
+ queue = channel.queue("#{@queueprefix}_udppacket")
168
+ exchange = channel.direct("")
169
+ t = 0
170
+ queue.bind("#{@queueprefix}_udppacket").subscribe do |metadata, body|
171
+ #puts "MSGID: [#{n}] Received #{body}"
172
+ udpdata = YAML.load(body).to_a
173
+ udpdatadim = udpdata[0][1]
174
+ udp_packet = "INSERT INTO #{@tblname_udppacket} "
175
+ udp_packet << "(guid,"
176
+ udp_packet << "recv_date,"
177
+ udp_packet << "udp_dport,"
178
+ udp_packet << "udp_len,"
179
+ udp_packet << "udp_sum,"
180
+ udp_packet << "udp_sport) "
181
+ udp_packet << "VALUES ("
182
+ udp_packet << "'#{udpdatadim["guid"]}',"
183
+ udp_packet << "'#{udpdatadim["recv_date"]}',"
184
+ udp_packet << "'#{udpdatadim["udp_dport"]}',"
185
+ udp_packet << "'#{udpdatadim["udp_len"]}',"
186
+ udp_packet << "'#{udpdatadim["udp_sum"]}',"
187
+ udp_packet << "'#{udpdatadim["udp_sport"]}');"
188
+ if t == 50
189
+ puts "\e[1;32m\ MSGID:\e[0m\ [#{n}] \e[1;32m\Generated SQL:\e[0m\ #{udp_packet}"
190
+ t = 0
191
+ end
192
+ t = t + 1 unless t == 50
193
+ res = @conn.query("#{udp_packet}")
194
+ @conn.save
195
+ n = n + 1
196
+ connection.close { EventMachine.stop }
197
+ end
198
+ end
199
+ udpcount = n
200
+ @conn.release
201
+ @conn.commit
202
+ totals = "\e[1;31m=======================================================================\e[0m\ \n"
203
+ totals << "\e[1;31mPackets Total | IP: #{ipcount} | TCP: #{tcpcount} | UDP: #{udpcount}\e[0m\ \n"
204
+ totals << "\e[1;31m======================================================================\e[0m\ \n"
205
+ puts totals
206
+
207
+ end
208
+
209
+ def infinite
210
+ puts "\e[1;31mStarting Consumer in infinite mode"
211
+ puts "\e[1;31m==================================\n"
212
+ puts "NOTE: Only should be used for live captures\n"
213
+ loop {
214
+ from_mq_to_db
215
+ }
216
+ end
217
+
218
+ def passes(passes)
219
+ puts "\e[1;31mStarting Consumer for #{passes} passes"
220
+ puts "\e[1;31m======================================="
221
+ passes.times {
222
+ from_mq_to_db
223
+ }
224
+ end
225
+
226
+ end
227
+
228
+ end
@@ -0,0 +1,73 @@
1
+ module Thm
2
+
3
+ class DataServices
4
+
5
+ # This class provides all the core functionality to the lower level DatalayerLight
6
+ #
7
+ # Example variables
8
+ #
9
+ # obj = Thm::Producer.new
10
+ # obj.mqhost = "127.0.0.1"
11
+ # obj.mquser = "test"
12
+ # obj.mqpass = "setone"
13
+ # obj.mqconnect
14
+ # obj.dbconnect
15
+
16
+ attr_accessor :datastore, :mqhost, :mquser, :mqpass, :mqvhost, :dbhost, :dbuser, :dbpass, :dbname, :queueprefix, :tblname_ippacket, :tblname_tcppacket, :tblname_udppacket
17
+
18
+ def initialize
19
+ @datastore = "monetdb"
20
+ @mqhost = "127.0.0.1"
21
+ @mquser = "traffic"
22
+ @mqpass = "dk3rbi9l"
23
+ @mqvhost = "/"
24
+ @dbhost = "127.0.0.1"
25
+ @dbuser = "threatmonitor"
26
+ @dbpass = "dk3rbi9l"
27
+ @dbname = "threatmonitor"
28
+ @queueprefix = "cactus" # Queue names will be come prefixed with cactus_ippacket etc ..
29
+ # Implement tblname for table freedom
30
+ @tblname_ippacket = "ippacket"
31
+ @tblname_tcppacket = "tcppacket"
32
+ @tblname_udppacket = "udppacket"
33
+ @mqconn = Bunny.new(:hostname => "#{@mqhost}", :user => "#{@mquser}", :pass => "#{@mqpass}", :vhost => "#{@mqvhost}")
34
+ end
35
+
36
+ def mqconnect
37
+ @mqconn.start
38
+ @ch = @mqconn.create_channel
39
+ end
40
+
41
+ def mqclose
42
+ @conn.close
43
+ end
44
+
45
+ def dbconnect
46
+ if @datastore == "mysql"
47
+ @conn = DatalayerLight::MySQLDrv.new
48
+ puts "Using MySQL Datasource"
49
+ elsif @datastore == "monetdb"
50
+ @conn = DatalayerLight::MonetDBDrv.new
51
+ puts "Using MonetDB Datasource"
52
+ end
53
+ @conn.hostname = @dbhost
54
+ @conn.username = @dbuser
55
+ @conn.password = @dbpass
56
+ @conn.dbname = @dbname
57
+ @conn.autocommit = false
58
+ begin
59
+ @conn.connect
60
+ rescue Errno::ECONNREFUSED
61
+ puts "Database not running!"
62
+ puts "Bye!"
63
+ exit
64
+ end
65
+ end
66
+
67
+ def query(sql)
68
+ res = @conn.query("#{sql}")
69
+ end
70
+
71
+ end
72
+
73
+ end
@@ -0,0 +1,170 @@
1
+
2
+ module Thm
3
+
4
+ # Process data from / to local files.
5
+
6
+ class Localmachine < DataServices
7
+
8
+ # We have to use a different Gem here called pcaprub that supports live interface / dumping mode.
9
+
10
+ def from_pcap_to_disk(interface, dumpfile)
11
+ puts "Capturing Live data... "
12
+ begin
13
+ capture = PCAPRUB::Pcap.open_live("#{interface}", 65535, true, 0)
14
+ puts "Writing to file ..."
15
+ puts "Press CTRL+C to exit ..."
16
+ dumper = capture.dump_open("#{dumpfile}")
17
+ capture_packets = 100
18
+ capture.each {|pkt|
19
+ capture.dump(pkt.length, pkt.length, pkt)
20
+ }
21
+ capture.dump_close
22
+ rescue
23
+ puts "Make sure the interface name is correct and you have enough disk space"
24
+ exit
25
+ end
26
+ end
27
+
28
+ # We can inject packets into an interface DANGEROUS !!!
29
+
30
+ def from_pcap_to_interface_injection(interface, inputdumpfile)
31
+ # NOTES
32
+ # Src / Dst rewriting ip_src, ip_dst
33
+ end
34
+
35
+ # From Pcap file to Datastore
36
+
37
+ def from_pcap_db(pcapfile)
38
+ t, n, s, v, x, z = 0, 0, 0, 0, 0, 0
39
+ ipcount, tcpcount, udpcount = 0, 0, 0
40
+ inp = Pcap::Capture.open_offline(pcapfile)
41
+ inp.each_packet do |pkt|
42
+ guid = Tools::guid # IP / TCP / UDP relationship
43
+ dtime = Time.now
44
+ # IP Packet
45
+ if pkt.ip?
46
+ ip_packet = "INSERT INTO #{@tblname_ippacket} "
47
+ ip_packet << "(guid, recv_date, ip_df, ip_dst, ip_hlen, ip_id, ip_len, ip_mf, ip_off, ip_proto, ip_src, ip_sum, ip_tos, ip_ttl, ip_ver) "
48
+ ip_packet << "VALUES ("
49
+ ip_packet << "'#{guid}',"
50
+ ip_packet << "'#{dtime}',"
51
+ if pkt.ip_df? == true
52
+ ip_packet << "'Y',"
53
+ else
54
+ ip_packet << "'N',"
55
+ end
56
+ ip_packet << "'#{pkt.ip_dst}',"
57
+ ip_packet << "'#{pkt.ip_hlen}',"
58
+ ip_packet << "'#{pkt.ip_id}',"
59
+ ip_packet << "'#{pkt.ip_len}',"
60
+ if pkt.ip_mf? == true
61
+ ip_packet << "'Y',"
62
+ else
63
+ ip_packet << "'N',"
64
+ end
65
+ ip_packet << "'#{pkt.ip_off}',"
66
+ ip_packet << "'#{pkt.ip_proto}',"
67
+ ip_packet << "'#{pkt.ip_src}',"
68
+ ip_packet << "'#{pkt.ip_sum}',"
69
+ ip_packet << "'#{pkt.ip_tos}',"
70
+ ip_packet << "'#{pkt.ip_ttl}',"
71
+ ip_packet << "'#{pkt.ip_ver}');"
72
+ if t == 50
73
+ puts "\e[1;32m\ MSGID:\e[0m\ [#{n}] \e[1;32m\Generated SQL:\e[0m\ #{ip_packet}"
74
+ t = 0
75
+ end
76
+ t = t + 1 unless t == 50
77
+ res = @conn.query("#{ip_packet}")
78
+ @conn.save
79
+ n = n + 1
80
+ end
81
+ # TCP Packet
82
+ if pkt.tcp?
83
+ tcp_packet = "INSERT INTO #{@tblname_tcppacket} "
84
+ tcp_packet << "(guid, recv_date, tcp_data_len, tcp_dport, tcp_ack, tcp_fin, tcp_syn, tcp_rst, tcp_psh, tcp_urg, tcp_off, tcp_hlen, tcp_seq, tcp_sum, tcp_sport, tcp_urp, "
85
+ tcp_packet << "tcp_win) "
86
+ tcp_packet << "VALUES ("
87
+ tcp_packet << "'#{guid}',"
88
+ tcp_packet << "'#{dtime}', "
89
+ tcp_packet << "#{pkt.tcp_data_len},"
90
+ tcp_packet << "#{pkt.tcp_dport},"
91
+ if pkt.tcp_ack? == true
92
+ tcp_packet << "'Y',"
93
+ else
94
+ tcp_packet << "'N',"
95
+ end
96
+ if pkt.tcp_fin? == true
97
+ tcp_packet << "'Y',"
98
+ else
99
+ tcp_packet << "'N',"
100
+ end
101
+ if pkt.tcp_syn? == true
102
+ tcp_packet << "'Y',"
103
+ else
104
+ tcp_packet << "'N',"
105
+ end
106
+ if pkt.tcp_rst? == true
107
+ tcp_packet << "'Y',"
108
+ else
109
+ tcp_packet << "'N',"
110
+ end
111
+ if pkt.tcp_psh? == true
112
+ tcp_packet << "'Y',"
113
+ else
114
+ tcp_packet << "'N',"
115
+ end
116
+ if pkt.tcp_urg? == true
117
+ tcp_packet << "'Y',"
118
+ else
119
+ tcp_packet << "'N',"
120
+ end
121
+ tcp_packet << "#{pkt.tcp_off}, #{pkt.tcp_hlen}, #{pkt.tcp_seq}, #{pkt.tcp_sum}, #{pkt.tcp_sport}, #{pkt.tcp_urp}, #{pkt.tcp_win});"
122
+ if s == 50
123
+ puts "\e[1;32m\ MSGID:\e[0m\ [#{v}] \e[1;32m\Generated SQL:\e[0m\ #{tcp_packet}"
124
+ s = 0
125
+ end
126
+ s = s + 1 unless s == 50
127
+ res = @conn.query("#{tcp_packet}")
128
+ @conn.save
129
+ v = v + 1
130
+ end
131
+ # UDP Packet
132
+ if pkt.udp?
133
+ udp_packet = "INSERT INTO #{@tblname_udppacket} "
134
+ udp_packet << "(guid,"
135
+ udp_packet << "recv_date,"
136
+ udp_packet << "udp_dport,"
137
+ udp_packet << "udp_len,"
138
+ udp_packet << "udp_sum,"
139
+ udp_packet << "udp_sport) "
140
+ udp_packet << "VALUES ("
141
+ udp_packet << "'#{guid}',"
142
+ udp_packet << "'#{dtime}',"
143
+ udp_packet << "'#{pkt.udp_dport}',"
144
+ udp_packet << "'#{pkt.udp_len}',"
145
+ udp_packet << "'#{pkt.udp_sum}',"
146
+ udp_packet << "'#{pkt.udp_sport}');"
147
+ if x == 50
148
+ puts "\e[1;32m\ MSGID:\e[0m\ [#{z}] \e[1;32m\Generated SQL:\e[0m\ #{udp_packet}"
149
+ x = 0
150
+ end
151
+ x = x + 1 unless x == 50
152
+ res = @conn.query("#{udp_packet}")
153
+ @conn.save
154
+ z = z + 1
155
+ end
156
+ ipcount = n
157
+ tcpcount = v
158
+ udpcount = z
159
+ end
160
+ @conn.release
161
+ @conn.commit
162
+ totals = "\e[1;31m=======================================================================\e[0m\ \n"
163
+ totals << "\e[1;31mPackets Total | IP: #{ipcount} | TCP: #{tcpcount} | UDP: #{udpcount}\e[0m\ \n"
164
+ totals << "\e[1;31m======================================================================\e[0m\ \n"
165
+ puts totals
166
+ end
167
+
168
+ end
169
+
170
+ end