dap 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.
Files changed (54) hide show
  1. data/.gitignore +6 -0
  2. data/.rspec +2 -0
  3. data/Gemfile +15 -0
  4. data/Gemfile.lock +55 -0
  5. data/LICENSE +20 -0
  6. data/README.md +15 -0
  7. data/bin/dap +137 -0
  8. data/dap.gemspec +42 -0
  9. data/data/.gitkeep +0 -0
  10. data/lib/dap.rb +101 -0
  11. data/lib/dap/filter.rb +8 -0
  12. data/lib/dap/filter/base.rb +37 -0
  13. data/lib/dap/filter/geoip.rb +72 -0
  14. data/lib/dap/filter/http.rb +173 -0
  15. data/lib/dap/filter/names.rb +151 -0
  16. data/lib/dap/filter/openssl.rb +53 -0
  17. data/lib/dap/filter/recog.rb +23 -0
  18. data/lib/dap/filter/simple.rb +340 -0
  19. data/lib/dap/filter/udp.rb +401 -0
  20. data/lib/dap/input.rb +74 -0
  21. data/lib/dap/input/csv.rb +60 -0
  22. data/lib/dap/input/warc.rb +81 -0
  23. data/lib/dap/output.rb +117 -0
  24. data/lib/dap/proto/addp.rb +0 -0
  25. data/lib/dap/proto/dtls.rb +21 -0
  26. data/lib/dap/proto/ipmi.rb +94 -0
  27. data/lib/dap/proto/natpmp.rb +19 -0
  28. data/lib/dap/proto/wdbrpc.rb +58 -0
  29. data/lib/dap/utils/oui.rb +16586 -0
  30. data/lib/dap/version.rb +3 -0
  31. data/samples/http_get_reply.ic12.bz2 +0 -0
  32. data/samples/http_get_reply.ic12.sh +1 -0
  33. data/samples/http_get_reply_iframes.json.bz2 +0 -0
  34. data/samples/http_get_reply_iframes.json.sh +1 -0
  35. data/samples/http_get_reply_links.json.sh +1 -0
  36. data/samples/iawide.warc.bz2 +0 -0
  37. data/samples/iawide_warc.sh +1 -0
  38. data/samples/ipmi_chan_auth_replies.crd.bz2 +0 -0
  39. data/samples/ipmi_chan_auth_replies.sh +1 -0
  40. data/samples/ssl_certs.bz2 +0 -0
  41. data/samples/ssl_certs_geo.sh +1 -0
  42. data/samples/ssl_certs_names.sh +1 -0
  43. data/samples/ssl_certs_names_expanded.sh +1 -0
  44. data/samples/ssl_certs_org.sh +1 -0
  45. data/samples/udp-netbios.csv.bz2 +0 -0
  46. data/samples/udp-netbios.sh +1 -0
  47. data/spec/dap/proto/ipmi_spec.rb +19 -0
  48. data/tools/geo-ip-summary.rb +149 -0
  49. data/tools/ipmi-vulns.rb +27 -0
  50. data/tools/json-summarize.rb +81 -0
  51. data/tools/netbios-counts.rb +271 -0
  52. data/tools/upnp-vulns.rb +35 -0
  53. data/tools/value-counts-to-md-table.rb +23 -0
  54. metadata +264 -0
data/lib/dap/input.rb ADDED
@@ -0,0 +1,74 @@
1
+ module Dap
2
+ module Input
3
+
4
+ require 'oj'
5
+
6
+ #
7
+ # Error codes for failed reads
8
+ #
9
+ module Error
10
+ EOF = :eof
11
+ Empty = :empty
12
+ end
13
+
14
+ module FileSource
15
+
16
+ attr_accessor :fd
17
+
18
+ def open(file_name)
19
+ close
20
+ self.fd = ['-', 'stdin', nil].include?(file_name) ?
21
+ $stdin : ::File.open(file_name, "rb")
22
+ end
23
+
24
+ def close
25
+ self.close if self.fd
26
+ self.fd = nil
27
+ end
28
+ end
29
+
30
+ #
31
+ # Line Input
32
+ #
33
+ class InputLines
34
+
35
+ include FileSource
36
+
37
+ def initialize(args)
38
+ self.open(args.first)
39
+ end
40
+
41
+ def read_record
42
+ line = self.fd.readline rescue nil
43
+ return Error::EOF unless line
44
+ { 'line' => line.chomp("\n") }
45
+ end
46
+
47
+ end
48
+
49
+ #
50
+ # JSON Input (line-delimited records)
51
+ #
52
+ class InputJSON
53
+
54
+ include FileSource
55
+
56
+ def initialize(args)
57
+ self.open(args.first)
58
+ end
59
+
60
+ def read_record
61
+ line = self.fd.readline rescue nil
62
+ return Error::EOF unless line
63
+ json = Oj.load(line.strip) rescue nil
64
+ return Error::Empty unless json
65
+ json
66
+ end
67
+
68
+ end
69
+
70
+ end
71
+ end
72
+
73
+ require 'dap/input/warc'
74
+ require 'dap/input/csv'
@@ -0,0 +1,60 @@
1
+ module Dap
2
+ module Input
3
+
4
+ require 'csv'
5
+
6
+ #
7
+ # CSV
8
+ #
9
+ class InputCSV
10
+
11
+ include FileSource
12
+
13
+ attr_accessor :has_header, :headers
14
+
15
+ def initialize(args)
16
+ self.headers = []
17
+
18
+ fname = args.shift
19
+ self.open(fname)
20
+
21
+ args.each do |arg|
22
+ if arg =~ /^header=(.*)/
23
+ val =$1
24
+ self.has_header = !! (val =~ /^y|t|1/i)
25
+ end
26
+ end
27
+
28
+ if self.has_header
29
+ data = read_record
30
+ unless (data == :eof or data == :empty)
31
+ self.headers = data.values.map{|x| x.to_s.strip }
32
+ end
33
+ end
34
+ end
35
+
36
+ def read_record
37
+ res = {}
38
+ line = self.fd.readline rescue nil
39
+ return Error::EOF unless line
40
+
41
+ # Short-circuit the slow CSV parser if the data does not contain double quotes
42
+ arr = line.index('"') ?
43
+ ( CSV.parse(line) rescue nil ) :
44
+ [ line.split(',').map{|x| x.strip } ]
45
+
46
+ return Error::Empty unless arr
47
+ cnt = 0
48
+ arr.first.each do |x|
49
+ cnt += 1
50
+ if x.to_s.length > 0
51
+ res[headers[cnt-1] || cnt.to_s] = x
52
+ end
53
+ end
54
+ res
55
+ end
56
+
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,81 @@
1
+ module Dap
2
+ module Input
3
+
4
+ #
5
+ # WARC
6
+ #
7
+ class InputWARC
8
+
9
+ include FileSource
10
+
11
+ attr_accessor :header, :info
12
+
13
+ def initialize(args)
14
+ self.open(args.first)
15
+ read_warc_header
16
+ end
17
+
18
+ def read_warc_header
19
+ self.header = read_record
20
+
21
+ if self.header == Error::EOF
22
+ raise RuntimeError, "Invalid WARC header"
23
+ end
24
+
25
+ unless self.header['warc_type'].to_s == "warcinfo"
26
+ raise RuntimeError, "Invalid WARC header (missing warcinfo)"
27
+ end
28
+
29
+ self.info = {}
30
+ self.header['content'].to_s.split("\n").each do |line|
31
+ k, v = line.strip.split(/\s*:\s*/, 2)
32
+ next unless v
33
+ self.info[k] = v
34
+ end
35
+ end
36
+
37
+ def read_record
38
+ begin
39
+
40
+ version = self.fd.readline
41
+ unless version and version =~ /^WARC\/\d+\.\d+/
42
+ return Error::EOF
43
+ end
44
+ warc = {}
45
+
46
+ loop do
47
+ line = self.fd.readline
48
+
49
+ unless line.strip.length == 0
50
+ k, v = line.strip.split(/\s*:\s*/, 2)
51
+ k = k.downcase.gsub('-', '_')
52
+ warc[k] = v.to_s
53
+ next
54
+ end
55
+
56
+ unless warc['content_length']
57
+ return Error::EOF
58
+ end
59
+
60
+ warc['content'] = self.fd.read(warc['content_length'].to_i)
61
+ skip = self.fd.readline
62
+ skip = self.fd.readline
63
+
64
+ unless skip.strip.length == 0
65
+ return Error::EOF
66
+ end
67
+
68
+ break
69
+ end
70
+
71
+ return warc
72
+
73
+ rescue ::EOFError
74
+ return Error::EOF
75
+ end
76
+ end
77
+
78
+ end
79
+
80
+ end
81
+ end
data/lib/dap/output.rb ADDED
@@ -0,0 +1,117 @@
1
+ module Dap
2
+ module Output
3
+
4
+ require 'oj'
5
+
6
+ module FileDestination
7
+
8
+ attr_accessor :fd
9
+
10
+ def open(file_name)
11
+ close
12
+ self.fd = ['-', 'stdout', nil].include?(file_name) ?
13
+ $stdout : ::File.open(file_name, "wb")
14
+ end
15
+
16
+ def close
17
+ self.close if self.fd
18
+ self.fd = nil
19
+ end
20
+
21
+ # Overload this to add headers
22
+ def start
23
+ end
24
+
25
+ # Overload this to add footers
26
+ def stop
27
+ end
28
+
29
+ end
30
+
31
+
32
+ #
33
+ # Line Output (CSV, TSV, etc)
34
+ # XXX: Quoted field handling is not supported, CSV should be a new output type
35
+ #
36
+ class OutputLines
37
+
38
+ attr_accessor :fields, :delimiter
39
+ FIELD_WILDCARD = '_'
40
+
41
+ include FileDestination
42
+
43
+ def initialize(args)
44
+ file = nil
45
+ self.delimiter = ","
46
+ self.fields = FIELD_WILDCARD
47
+
48
+ header = false
49
+
50
+ args.each do |str|
51
+ k,v = str.split('=', 2)
52
+ case k
53
+ when 'file'
54
+ file = v
55
+ when 'header'
56
+ header = ( v =~ /^[ty1]/i ? true : false )
57
+ when 'fields'
58
+ self.fields = v.split(',')
59
+ when 'delimiter'
60
+ self.delimiter =
61
+ case v.to_s
62
+ when 'tab'
63
+ "\t"
64
+ when 'null'
65
+ "\x00"
66
+ else
67
+ v
68
+ end
69
+ end
70
+ end
71
+ self.open(file)
72
+
73
+ if header and not fields.include?(FIELD_WILDCARD)
74
+ self.fd.puts self.fields.join(self.delimiter)
75
+ end
76
+
77
+ end
78
+
79
+ def write_record(doc)
80
+ out = []
81
+
82
+ if self.fields.include?(FIELD_WILDCARD)
83
+ doc.each_pair do |k,v|
84
+ out << v.to_s
85
+ end
86
+ else
87
+ self.fields.each do |k|
88
+ out << doc[k].to_s
89
+ end
90
+ end
91
+
92
+ return unless out.length > 0
93
+
94
+ self.fd.puts out.join(self.delimiter)
95
+ end
96
+
97
+ end
98
+
99
+ #
100
+ # JSON Output (line-delimited records)
101
+ #
102
+ class OutputJSON
103
+
104
+ include FileDestination
105
+
106
+ def initialize(args)
107
+ self.open(args.first)
108
+ end
109
+
110
+ def write_record(doc)
111
+ self.fd.puts Oj.dump(doc)
112
+ end
113
+
114
+ end
115
+
116
+ end
117
+ end
File without changes
@@ -0,0 +1,21 @@
1
+ # -*- coding: binary -*-
2
+ module Dap
3
+ module Proto
4
+ module DTLS
5
+
6
+
7
+ class RecordLayer < BitStruct
8
+ unsigned :content_type, 8, 'Content type'
9
+ unsigned :version, 16, 'Version'
10
+ unsigned :epoch, 16, 'Epoch'
11
+ unsigned :sequence, 48, 'Sequence number'
12
+ unsigned :payload_length, 16, 'Payload length'
13
+ rest :payload
14
+
15
+ def valid?
16
+ payload_length == payload.length
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,94 @@
1
+ # -*- coding: binary -*-
2
+ module Dap
3
+ module Proto
4
+ module IPMI
5
+
6
+ class Channel_Auth_Reply < BitStruct
7
+
8
+ unsigned :rmcp_version, 8, "RMCP Version"
9
+ unsigned :rmcp_padding, 8, "RMCP Padding"
10
+ unsigned :rmcp_sequence, 8, "RMCP Sequence"
11
+ unsigned :rmcp_mtype, 1, "RMCP Message Type"
12
+ unsigned :rmcp_class, 7, "RMCP Message Class"
13
+
14
+ unsigned :session_auth_type, 8, "Session Auth Type"
15
+ unsigned :session_sequence, 32, "Session Sequence Number"
16
+ unsigned :session_id, 32, "Session ID"
17
+ unsigned :message_length, 8, "Message Length"
18
+
19
+ unsigned :ipmi_tgt_address, 8, "IPMI Target Address"
20
+ unsigned :ipmi_tgt_lun, 8, "IPMI Target LUN"
21
+ unsigned :ipmi_header_checksum, 8, "IPMI Header Checksum"
22
+ unsigned :ipmi_src_address, 8, "IPMI Source Address"
23
+ unsigned :ipmi_src_lun, 8, "IPMI Source LUN"
24
+ unsigned :ipmi_command, 8, "IPMI Command"
25
+ unsigned :ipmi_completion_code, 8, "IPMI Completion Code"
26
+
27
+ unsigned :ipmi_channel, 8, "IPMI Channel"
28
+
29
+ unsigned :ipmi_compat_20, 1, "IPMI Version Compatibility: IPMI 2.0+"
30
+ unsigned :ipmi_compat_reserved1, 1, "IPMI Version Compatibility: Reserved 1"
31
+ unsigned :ipmi_compat_oem_auth, 1, "IPMI Version Compatibility: OEM Authentication"
32
+ unsigned :ipmi_compat_password, 1, "IPMI Version Compatibility: Straight Password"
33
+ unsigned :ipmi_compat_reserved2, 1, "IPMI Version Compatibility: Reserved 2"
34
+ unsigned :ipmi_compat_md5, 1, "IPMI Version Compatibility: MD5"
35
+ unsigned :ipmi_compat_md2, 1, "IPMI Version Compatibility: MD2"
36
+ unsigned :ipmi_compat_none, 1, "IPMI Version Compatibility: None"
37
+
38
+ unsigned :ipmi_user_reserved1, 2, "IPMI User Compatibility: Reserved 1"
39
+ unsigned :ipmi_user_kg, 1, "IPMI User Compatibility: KG Set to Default"
40
+ unsigned :ipmi_user_disable_message_auth, 1, "IPMI User Compatibility: Disable Per-Message Authentication"
41
+ unsigned :ipmi_user_disable_user_auth, 1, "IPMI User Compatibility: Disable User-Level Authentication"
42
+ unsigned :ipmi_user_non_null, 1, "IPMI User Compatibility: Non-Null Usernames Enabled"
43
+ unsigned :ipmi_user_null, 1, "IPMI User Compatibility: Null Usernames Enabled"
44
+ unsigned :ipmi_user_anonymous, 1, "IPMI User Compatibility: Anonymous Login Enabled"
45
+
46
+ unsigned :ipmi_conn_reserved1, 6, "IPMI Connection Compatibility: Reserved 1"
47
+ unsigned :ipmi_conn_20, 1, "IPMI Connection Compatibility: 2.0"
48
+ unsigned :ipmi_conn_15, 1, "IPMI Connection Compatibility: 1.5"
49
+
50
+ unsigned :ipmi_oem_id, 24, "IPMI OEM ID", :endian => 'little'
51
+
52
+ rest :ipm_oem_data, "IPMI OEM Data + Checksum Byte"
53
+
54
+
55
+ def valid?
56
+ (rmcp_version == 6) && (message_length == 16)
57
+ end
58
+
59
+ def to_banner
60
+ info = self
61
+ banner = "#{(info.ipmi_compat_20 == 1) ? "IPMI-2.0" : "IPMI-1.5"} "
62
+
63
+ pass_info = []
64
+ pass_info << "oem_auth" if info.ipmi_compat_oem_auth == 1
65
+ pass_info << "password" if info.ipmi_compat_password == 1
66
+ pass_info << "md5" if info.ipmi_compat_md5 == 1
67
+ pass_info << "md2" if info.ipmi_compat_md2 == 1
68
+ pass_info << "null" if info.ipmi_compat_none == 1
69
+
70
+ user_info = []
71
+ user_info << "kg_default" if (info.ipmi_compat_20 == 1 and info.ipmi_user_kg == 1)
72
+ user_info << "auth_msg" unless info.ipmi_user_disable_message_auth == 1
73
+ user_info << "auth_user" unless info.ipmi_user_disable_user_auth == 1
74
+ user_info << "non_null_user" if info.ipmi_user_non_null == 1
75
+ user_info << "null_user" if info.ipmi_user_null == 1
76
+ user_info << "anonymous_user" if info.ipmi_user_anonymous == 1
77
+
78
+ conn_info = []
79
+ conn_info << "1.5" if info.ipmi_conn_15 == 1
80
+ conn_info << "2.0" if info.ipmi_conn_20 == 1
81
+
82
+ if info.ipmi_oem_id != 0
83
+ banner << "OEMID:#{info.ipmi_oem_id} "
84
+ end
85
+
86
+ banner << "UserAuth(#{user_info.join(", ")}) PassAuth(#{pass_info.join(", ")}) Level(#{conn_info.join(", ")}) "
87
+ banner
88
+ end
89
+
90
+ end
91
+
92
+ end
93
+ end
94
+ end