pstream 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 49d303c1bea9a3531778ce20c6fb023bf20109b4
4
+ data.tar.gz: ec4f4c2aa67ccd3266cadda652cbef2b938634b4
5
+ SHA512:
6
+ metadata.gz: 952f3f520e597628ae22b6890c002357d2dd84d3e17ff1ed44c193d19db7f37e3dcedeabc8f95042cc28562c293a1b29b7cca6ed33f9b3a6666a4eb6b99ef84f
7
+ data.tar.gz: a30dee7152071b7da0b1428c384b17ad6ba917fc22ce7e25cc62863101303880fa9c69d5048c0105844553125392f0cc2f885c29aa4682660d4d825cb2662107
data/bin/pstream ADDED
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "optparse"
4
+ require "pstream"
5
+ require "string"
6
+
7
+ class PStreamExit
8
+ GOOD = 0
9
+ INVALID_OPTION = 1
10
+ INVALID_ARGUMENT = 2
11
+ MISSING_ARGUMENT = 3
12
+ EXTRA_ARGUMENTS = 4
13
+ EXCEPTION = 5
14
+ end
15
+
16
+ def parse(args)
17
+ options = Hash.new
18
+ options["ciphers"] = false
19
+ options["prot"] = "tcp"
20
+ options["stream"] = nil
21
+
22
+ info = "Analyze pcap files. Can view tcp/udp streams or " \
23
+ "ciphersuites in use."
24
+
25
+ parser = OptionParser.new do |opts|
26
+ opts.banner = "Usage: #{File.basename($0)} [OPTIONS] <pcap>"
27
+
28
+ opts.on(
29
+ "-c",
30
+ "--ciphersuites",
31
+ "Show ciphersuite negotiation from ssl handshakes"
32
+ ) do
33
+ options["ciphers"] = true
34
+ end
35
+
36
+ opts.on("-h", "--help", "Display this help message") do
37
+ puts opts
38
+ exit PStreamExit::GOOD
39
+ end
40
+
41
+ opts.on("-s", "--stream=NUM", "Show specified stream") do |s|
42
+ options["stream"] = s.to_i
43
+ end
44
+
45
+ opts.on("-u", "--udp", "Use UDP") do
46
+ options["prot"] = "udp"
47
+ end
48
+
49
+ opts.on("", info.word_wrap(80))
50
+ end
51
+
52
+ begin
53
+ parser.parse!
54
+ rescue OptionParser::InvalidOption => e
55
+ puts e.message
56
+ puts parser
57
+ exit PStreamExit::INVALID_OPTION
58
+ rescue OptionParser::InvalidArgument => e
59
+ puts e.message
60
+ puts parser
61
+ exit PStreamExit::INVALID_ARGUMENT
62
+ rescue OptionParser::MissingArgument => e
63
+ puts e.message
64
+ puts parser
65
+ exit PStreamExit::MISSING_ARGUMENT
66
+ end
67
+
68
+ if (args.length != 1)
69
+ puts parser
70
+ exit PStreamExit::EXTRA_ARGUMENTS
71
+ end
72
+
73
+ options["pcap"] = args[0]
74
+ return options
75
+ end
76
+
77
+ options = parse(ARGV)
78
+
79
+ begin
80
+ pstream = PStream.new(options["pcap"])
81
+
82
+ if (options["stream"])
83
+ case options["prot"]
84
+ when "tcp"
85
+ puts pstream.tcp_streams[options["stream"]].contents
86
+ when "udp"
87
+ puts pstream.udp_streams[options["stream"]].contents
88
+ end
89
+ elsif (options["ciphers"])
90
+ puts pstream.ciphers
91
+ else
92
+ puts pstream.summary
93
+ end
94
+ rescue PStream::Error => e
95
+ puts e.message
96
+ exit PStreamExit::EXCEPTION
97
+ end
98
+ exit PStreamExit::GOOD
@@ -0,0 +1,5 @@
1
+ class PStream::Error::PcapNotFound < PStream::Error
2
+ def initialize(pcap)
3
+ super("File not found: #{pcap}")
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class PStream::Error::PcapNotReadable < PStream::Error
2
+ def initialize(pcap)
3
+ super("File not readable: #{pcap}")
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class PStream::Error::TsharkNotFound < PStream::Error
2
+ def initialize
3
+ super("Please install tshark!")
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ class PStream::Error < RuntimeError
2
+ end
3
+
4
+ require "pstream/error/pcap_not_found"
5
+ require "pstream/error/pcap_not_readable"
6
+ require "pstream/error/tshark_not_found"
@@ -0,0 +1,25 @@
1
+ class PStream::Stream
2
+ attr_accessor :desc
3
+ attr_accessor :frames
4
+ attr_accessor :id
5
+
6
+ def contents
7
+ out = %x(
8
+ tshark -r #{@pcap} -z follow,#{@prot},hex,#{@id} | \
9
+ sed "s|^ ||" | \grep -E "^[0-9A-Fa-f]{8}"
10
+ )
11
+ return out
12
+ end
13
+
14
+ def initialize(pcap, prot, id, desc, frames)
15
+ @desc = desc
16
+ @frames = frames
17
+ @id = id
18
+ @pcap = pcap
19
+ @prot = prot
20
+ end
21
+
22
+ def to_s()
23
+ return contents
24
+ end
25
+ end
data/lib/pstream.rb ADDED
@@ -0,0 +1,97 @@
1
+ require "pathname"
2
+ require "scoobydoo"
3
+
4
+ class PStream
5
+ attr_accessor :tcp_streams
6
+ attr_accessor :udp_streams
7
+
8
+ def ciphers
9
+ # List ciphers during ssl handshake
10
+ out = %x(
11
+ tshark -r #{@pcap} -Y ssl.handshake.ciphersuite -V | \
12
+ \grep -E "Internet Protocol|Hostname:|Cipher Suite"
13
+ )
14
+ return out
15
+ end
16
+
17
+ def get_streams(prot)
18
+ streams = Array.new
19
+
20
+ out = %x(
21
+ tshark -r #{@pcap} -z conv,#{prot} | \grep -E "<->" | \
22
+ awk '{print $1, $2, $3, "|", $8, "Frames"}'
23
+ )
24
+
25
+ count = 0
26
+ out.split("\n").each do |line|
27
+ desc, frames = line.split(" | ")
28
+
29
+ id = count
30
+ id = desc.gsub(" <-> ", ",") if (prot == "udp")
31
+
32
+ streams.push(Stream.new(@pcap, prot, id, desc, frames))
33
+ count += 1
34
+ end
35
+
36
+ return streams
37
+ end
38
+ private :get_streams
39
+
40
+ def initialize(pcap)
41
+ if (ScoobyDoo.where_are_you("tshark").nil?)
42
+ raise PStream::Error::TsharkNotFound.new
43
+ end
44
+
45
+ @pcap = Pathname.new(pcap).expand_path
46
+
47
+ if (!@pcap.exist?)
48
+ raise PStream::Error::PcapNotFound.new(@pcap)
49
+ elsif (!@pcap.readable?)
50
+ raise PStream::Error::PcapNotReadable.new(@pcap)
51
+ end
52
+
53
+ @tcp_streams = get_streams("tcp")
54
+ @udp_streams = get_streams("udp")
55
+ end
56
+
57
+ def summary
58
+ ret = Array.new
59
+
60
+ # List TCP streams
61
+ ret.push("TCP Streams:")
62
+ count = 0
63
+ @tcp_streams.each do |stream|
64
+ ret.push("#{count} | #{stream.desc} | #{stream.frames}")
65
+ count += 1
66
+ end
67
+ ret.push("")
68
+
69
+ # List UDP streams
70
+ ret.push("UDP Streams:")
71
+ count = 0
72
+ @udp_streams.each do |stream|
73
+ ret.push("#{count} | #{stream.desc} | #{stream.frames}")
74
+ count += 1
75
+ end
76
+ ret.push("")
77
+
78
+ # List ciphers that were actually selected
79
+ ret.push("Ciphers in use:")
80
+ f = "ssl.handshake.ciphersuite && ssl.handshake.type == 2"
81
+ out = %x(
82
+ tshark -r #{@pcap} -Y "#{f}" -V | \
83
+ \grep -E "Cipher Suite:" | \
84
+ sed -r "s|^ +Cipher Suite: ||g" | sort -u
85
+ )
86
+ ret.concat(out.split("\n"))
87
+
88
+ return ret.join("\n")
89
+ end
90
+
91
+ def to_s
92
+ return summary
93
+ end
94
+ end
95
+
96
+ require "pstream/error"
97
+ require "pstream/stream"
data/lib/string.rb ADDED
@@ -0,0 +1,32 @@
1
+ # Redefine String class to allow for colorizing, rsplit, and word wrap
2
+ class String
3
+ def blue
4
+ return colorize(36)
5
+ end
6
+
7
+ def colorize(color)
8
+ return "\e[#{color}m#{self}\e[0m"
9
+ end
10
+
11
+ def green
12
+ return colorize(32)
13
+ end
14
+
15
+ def red
16
+ return colorize(31)
17
+ end
18
+
19
+ def rsplit(pattern)
20
+ ret = rpartition(pattern)
21
+ ret.delete_at(1)
22
+ return ret
23
+ end
24
+
25
+ def white
26
+ return colorize(37)
27
+ end
28
+
29
+ def word_wrap(width = 70)
30
+ return scan(/\S.{0,#{width}}\S(?=\s|$)|\S+/).join("\n")
31
+ end
32
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pstream
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Miles Whittaker
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-11-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: scoobydoo
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.1'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.1.1
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '0.1'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.1.1
33
+ description: ''
34
+ email: mjwhitta@gmail.com
35
+ executables:
36
+ - pstream
37
+ extensions: []
38
+ extra_rdoc_files: []
39
+ files:
40
+ - bin/pstream
41
+ - lib/pstream.rb
42
+ - lib/pstream/error.rb
43
+ - lib/pstream/error/pcap_not_found.rb
44
+ - lib/pstream/error/pcap_not_readable.rb
45
+ - lib/pstream/error/tshark_not_found.rb
46
+ - lib/pstream/stream.rb
47
+ - lib/string.rb
48
+ homepage: http://mjwhitta.github.io/pstream
49
+ licenses:
50
+ - GPL-3.0
51
+ metadata: {}
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project:
68
+ rubygems_version: 2.4.5.1
69
+ signing_key:
70
+ specification_version: 4
71
+ summary: ''
72
+ test_files: []