pstream 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2afaa0231c97802387625086c64da95b5ce114c2
4
- data.tar.gz: 6e187acbce7c6c027faafacdcf1cd732f63e9ecf
3
+ metadata.gz: 1ee81e7ea543491338bb800254b0b2cc4c0850c3
4
+ data.tar.gz: d877d6ff3c9deca5cc7b3ef7e07531e9e1f587de
5
5
  SHA512:
6
- metadata.gz: becd5a9ac9389461223797903374a9b4d8d26384748bacd8f2d1bd4dbb512df26ed0b3a6d525d6407f36040dfb15c7230e52f188f5c26b62b2b504a2fcb832e1
7
- data.tar.gz: 3a1f74c8c74442bb8b8a31743bdb2295b31686592d802a5992e5d1fadc4c9fd2d638719d598ddda6c40078f9a591b4c37daa2ac34062433a872160714da8b4d9
6
+ metadata.gz: f65be907ced9b779793e85607d5b0e7a80306d8527dd7981890c0585da482cd4ab35a2de2ede23aa53b5c73b3ed224ec02e20aa76bc6c6a7f4a5a42d23ee5447
7
+ data.tar.gz: 6cace69f3b2e5eaa02ffc81dffb7a90bda72cd9dfe6413547f532f4ed289916fa2ca92558853679a9e442e2858300963e456e7e75eb7e628f351641174f0cdca
data/bin/pstream CHANGED
@@ -92,51 +92,23 @@ end
92
92
  options = parse(ARGV)
93
93
 
94
94
  begin
95
- pstream = PStream.new(options["pcap"])
95
+ pstream = PStream.new(
96
+ options["pcap"],
97
+ !String.disable_colorization
98
+ )
96
99
 
97
100
  if (options["stream"])
98
- pstream.get_stream(
101
+ puts pstream.get_stream(
99
102
  options["stream"].to_i,
100
103
  options["prot"]
101
- ).contents.split("\n").each do |line|
102
- m = line.match(/([0-9A-Fa-f]{8}) (.*) (.{17})/)
103
- puts [
104
- m[1].light_blue,
105
- m[2].light_green,
106
- m[3].white
107
- ].join(" ")
108
- end
104
+ ).to_s
109
105
  elsif (options["ciphers"])
110
- puts pstream.ciphers
111
- else
112
- pstream.to_s.split("\n").each do |line|
113
- case line
114
- when /.*:$/
115
- # Headers
116
- puts line.white
117
- when /<->/
118
- # Streams
119
- m = line.match(/([0-9]+) \| (.+) \| ([0-9]+ Frames)/)
120
- puts [
121
- m[1].light_blue,
122
- m[2].light_green,
123
- m[3].light_white
124
- ].join(" | ")
125
- else
126
- case line
127
- when /Unknown/
128
- puts line.light_yellow
129
- when /NULL|MD5|RC4|anon/
130
- # Bad cipher suites
131
- puts line.light_red
132
- when /E?(EC)?DHE?|AES_256/
133
- # Great cipher suites
134
- puts line.light_green
135
- else
136
- puts line.white
137
- end
138
- end
106
+ pstream.cipher_negotiations.each do |negotiation|
107
+ puts negotiation.to_s
139
108
  end
109
+ else
110
+ # Summarize
111
+ puts pstream.to_s
140
112
  end
141
113
  rescue PStream::Error => e
142
114
  $stderr.puts e.message.red
data/lib/pstream.rb CHANGED
@@ -4,13 +4,115 @@ require "scoobydoo"
4
4
  class PStream
5
5
  attr_reader :streams
6
6
 
7
- def ciphers
7
+ def cipher_negotiations
8
+ negotiations = Hash.new
9
+
8
10
  # List ciphers during ssl handshake
9
11
  out = %x(
10
12
  tshark -r #{@pcap} -Y ssl.handshake.ciphersuite -V 2>&1 \
11
- | \grep -E "Internet Protocol|Hostname:|Cipher Suite"
13
+ | \grep -E "(Handshake|Internet) Prot|Cipher Suite"
12
14
  )
13
- return out
15
+
16
+ negotiation = nil
17
+ hello = nil
18
+ out.split("\n").each do |line|
19
+ case line.gsub(/^ +/, "")
20
+ when /^Cipher Suite:/
21
+ m = line.match(/Cipher Suite: ([^ ]+) (.*)$/)
22
+ case hello
23
+ when "Client"
24
+ case m[1]
25
+ when "Unknown"
26
+ negotiation.suites.push("#{m[1]} #{m[2]}")
27
+ else
28
+ negotiation.suites.push(m[1])
29
+ end
30
+ when "Server"
31
+ id = "#{negotiation.dst} <-> #{negotiation.src}"
32
+ # Ignore partial handshakes that are server side
33
+ # only
34
+ if (negotiations[id])
35
+ case m[1]
36
+ when "Unknown"
37
+ negotiations[id].suite = "#{m[1]} #{m[2]}"
38
+ else
39
+ negotiations[id].suite = m[1]
40
+ end
41
+ end
42
+ negotiation = nil
43
+ end
44
+ when /^Cipher Suites Length:/
45
+ m = line.match(/Cipher Suites Length: ([0-9]+)$/)
46
+ negotiation.length = m[1].to_i
47
+ when /^Handshake Protocol:/
48
+ m = line.match(/Handshake Protocol: ([^ ]+) Hello$/)
49
+ hello = m[1]
50
+ when /^Internet Protocol Version/
51
+ if (negotiation)
52
+ id = "#{negotiation.src} <-> #{negotiation.dst}"
53
+ negotiations[id] = negotiation
54
+ end
55
+
56
+ m = line.gsub("Internet Protocol Version", "").match(
57
+ /(4|6), Src: ([^,]+), Dst: (.*)$/
58
+ )
59
+
60
+ ipv = m[1]
61
+ src = m[2]
62
+ dst = m[3]
63
+
64
+ negotiation = PStream::CipherNegotiation.new(
65
+ self,
66
+ ipv,
67
+ src,
68
+ dst,
69
+ @colorize
70
+ )
71
+ end
72
+ end
73
+
74
+ # Keep parital handshakes that are client side only
75
+ if (negotiation)
76
+ id = "#{negotiation.src} <-> #{negotiation.dst}"
77
+ negotiations[id] = negotiation
78
+ end
79
+
80
+ return negotiations.values
81
+ end
82
+
83
+ def colorize_cipher_suite(suite)
84
+ return suite if (!@colorize)
85
+
86
+ case suite
87
+ when /Unknown/
88
+ # Unknown
89
+ return suite.light_yellow
90
+ when /NULL|MD5|RC4|anon/
91
+ # Bad cipher suites
92
+ return suite.light_red
93
+ when /E?(EC)?DHE?|AES_256/
94
+ # Great cipher suites
95
+ return suite.light_green
96
+ else
97
+ # Maybe OK
98
+ return suite.light_white
99
+ end
100
+ end
101
+
102
+ def colorize_header(header)
103
+ return header if (!@colorize)
104
+ return header.light_cyan
105
+ end
106
+
107
+ def colorize_stream(stream)
108
+ if (!@colorize)
109
+ return "#{stream.id} | #{stream.desc} | #{stream.frames}"
110
+ end
111
+ return [
112
+ "#{stream.id}".light_blue,
113
+ stream.desc.light_green,
114
+ stream.frames.light_white
115
+ ].join(" | ")
14
116
  end
15
117
 
16
118
  def get_stream(stream, prot = "tcp")
@@ -60,7 +162,16 @@ class PStream
60
162
  count = 0
61
163
  out.split("\n").each do |line|
62
164
  desc, frames = line.split(" | ")
63
- streams.push(Stream.new(@pcap, prot, count, desc, frames))
165
+ streams.push(
166
+ Stream.new(
167
+ @pcap,
168
+ prot,
169
+ count,
170
+ desc,
171
+ frames,
172
+ @colorize
173
+ )
174
+ )
64
175
  count += 1
65
176
  end
66
177
 
@@ -68,7 +179,9 @@ class PStream
68
179
  end
69
180
  private :get_streams
70
181
 
71
- def initialize(pcap)
182
+ def initialize(pcap, colorize = false)
183
+ @colorize = colorize
184
+
72
185
  if (ScoobyDoo.where_are_you("tshark").nil?)
73
186
  raise PStream::Error::TsharkNotFound.new
74
187
  end
@@ -87,31 +200,23 @@ class PStream
87
200
  end
88
201
  end
89
202
 
90
- def negotiated_ciphers
91
- f = "ssl.handshake.ciphersuite && ssl.handshake.type == 2"
92
- out = %x(
93
- tshark -r #{@pcap} -Y "#{f}" -V 2>&1 | \
94
- \grep -E "Cipher Suite:" | \
95
- sed -r "s|^ +Cipher Suite: ||g" | sort -u
96
- )
97
- return out.split("\n")
98
- end
99
-
100
203
  def summary
101
204
  ret = Array.new
102
205
 
103
206
  # List streams
104
207
  ["tcp", "udp"].each do |prot|
105
- ret.push("#{prot} streams:")
106
- @streams[prot].each do |s|
107
- ret.push("#{s.id} | #{s.desc} | #{s.frames}")
208
+ ret.push(colorize_header("#{prot} streams:"))
209
+ @streams[prot].each do |stream|
210
+ ret.push(colorize_stream(stream))
108
211
  end
109
212
  ret.push("")
110
213
  end
111
214
 
112
215
  # List ciphers that were actually selected
113
- ret.push("Ciphers in use:")
114
- ret.concat(negotiated_ciphers)
216
+ ret.push(colorize_header("Ciphers in use:"))
217
+ cipher_negotiations.each do |negotiation|
218
+ ret.push(colorize_cipher_suite(negotiation.suite))
219
+ end
115
220
 
116
221
  return ret.join("\n")
117
222
  end
@@ -122,5 +227,6 @@ class PStream
122
227
  end
123
228
  end
124
229
 
230
+ require "pstream/cipher_negotiation"
125
231
  require "pstream/error"
126
232
  require "pstream/stream"
@@ -0,0 +1,56 @@
1
+ class PStream::CipherNegotiation
2
+ attr_accessor :length
3
+ attr_accessor :suite
4
+ attr_accessor :suites
5
+
6
+ attr_reader :dst
7
+ attr_reader :ipv
8
+ attr_reader :pstream
9
+ attr_reader :src
10
+
11
+ def colorize_hosts(src, dst)
12
+ return "#{src} <-> #{dst}" if (!@colorize)
13
+ return "#{src} <-> #{dst}".light_cyan
14
+ end
15
+
16
+ def colorize_ipv(ipv)
17
+ return "IPv#{ipv}" if (!@colorize)
18
+ return "IPv#{ipv}".light_cyan
19
+ end
20
+
21
+ def colorize_selected_suite(suite)
22
+ return [
23
+ "Selected".light_blue,
24
+ @pstream.colorize_cipher_suite(suite),
25
+ "from:".light_blue
26
+ ].join(" ")
27
+ end
28
+
29
+ def initialize(pstream, ipv, src, dst, colorize)
30
+ @colorize = colorize
31
+ @dst = dst
32
+ @ipv = ipv
33
+ @length = nil
34
+ @pstream = pstream
35
+ @src = src
36
+ @suite = nil
37
+ @suites = Array.new
38
+ end
39
+
40
+ def summary
41
+ ret = Array.new
42
+ ret.push(
43
+ "#{colorize_ipv(@ipv)} #{colorize_hosts(@src, @dst)}"
44
+ )
45
+ ret.push(" #{colorize_selected_suite(@suite)}") if (@suite)
46
+ @suites.each do |suite|
47
+ ret.push(" #{@pstream.colorize_cipher_suite(suite)}")
48
+ end
49
+
50
+ return ret.join("\n")
51
+ end
52
+
53
+ def to_s
54
+ return summary
55
+ end
56
+ end
@@ -3,24 +3,51 @@ class PStream::Stream
3
3
  attr_reader :frames
4
4
  attr_reader :id
5
5
 
6
+ def colorize_address(address)
7
+ return address if (!@colorize)
8
+ return address.light_blue
9
+ end
10
+
11
+ def colorize_ascii(ascii)
12
+ return ascii if (!@colorize)
13
+ return ascii.light_white
14
+ end
15
+
16
+ def colorize_hex(hex)
17
+ return hex if (!@colorize)
18
+ return hex.light_green
19
+ end
20
+
6
21
  def contents
7
22
  case @prot
8
23
  when /^tcp$/i
9
- id=@id
24
+ stream=@id
10
25
  when /^udp$/i
11
- id=@desc.gsub(" <-> ", ",")
26
+ stream=@desc.gsub(" <-> ", ",")
12
27
  else
13
28
  raise PStream::Error::ProtocolNotSupported.new(@prot)
14
29
  end
15
30
 
16
- out = %x(
17
- tshark -r #{@pcap} -z follow,#{@prot},hex,#{id} | \
31
+ ret = Array.new
32
+ %x(
33
+ tshark -r #{@pcap} -z follow,#{@prot},hex,#{stream} | \
18
34
  sed "s|^ ||" | \grep -E "^[0-9A-Fa-f]{8}"
19
- )
20
- return out
35
+ ).split("\n").each do |line|
36
+ m = line.match(/([0-9A-Fa-f]{8}) (.*) (.{17})/)
37
+ ret.push(
38
+ [
39
+ colorize_address(m[1]),
40
+ colorize_hex(m[2]),
41
+ colorize_ascii(m[3])
42
+ ].join(" ")
43
+ )
44
+ end
45
+
46
+ return ret.join("\n")
21
47
  end
22
48
 
23
- def initialize(pcap, prot, id, desc, frames)
49
+ def initialize(pcap, prot, id, desc, frames, colorize = false)
50
+ @colorize = colorize
24
51
  @desc = desc
25
52
  @frames = frames
26
53
  @id = id
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pstream
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miles Whittaker
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-04 00:00:00.000000000 Z
11
+ date: 2016-03-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -59,6 +59,7 @@ extra_rdoc_files: []
59
59
  files:
60
60
  - bin/pstream
61
61
  - lib/pstream.rb
62
+ - lib/pstream/cipher_negotiation.rb
62
63
  - lib/pstream/error.rb
63
64
  - lib/pstream/error/pcap_not_found.rb
64
65
  - lib/pstream/error/pcap_not_readable.rb