dap 0.0.8 → 0.0.9

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: f74b17e0330d6261df8774f00b69b6e80375a2b1
4
- data.tar.gz: d6a82f589b94862ebfbf50f06632e8f694cf51ac
3
+ metadata.gz: 487ec0ed128ac49a84730159ed2561cc0abe5a0b
4
+ data.tar.gz: 4709517322ef8b40ea7527ff852b7f664a256d19
5
5
  SHA512:
6
- metadata.gz: 70aa78c8471a4fc77d72bc00024cbbe8450233aae4e2cfdbf873c008b9d1ea564fb92479ca0868e9272b6d1241e91132403db27f4800c127fd4954e95ef73bc4
7
- data.tar.gz: b716811bb124e3b2a3c37947972d4db4bf1317bdd64c261d4576b87df8b65d144a11ef37e46d222ec6776c443415c57a5dbbbe0e555cae409437d2944910bb83
6
+ metadata.gz: 102e072962fc919016d7261e26c1b05c85c3017006810216761202dc0109b4d40ac72db361325058fa1e76798d27c2f38bd474aff386760621aebac5e306693e
7
+ data.tar.gz: d7667a595feeb261c0109f94d304097f1bcad3b47e70d7dd655cdbf3efa829d806c209f5b4807f92a5f69bd762b41115c07b021321dc26830506d498e0998518
data/.rspec CHANGED
@@ -1,2 +1,3 @@
1
1
  --colour
2
2
  --format d
3
+ --require spec_helper
data/lib/dap/filter.rb CHANGED
@@ -9,3 +9,4 @@ require 'dap/filter/recog'
9
9
  require 'dap/filter/vulnmatch'
10
10
  require 'dap/filter/ssh_keyscan'
11
11
  require 'dap/filter/smbclient'
12
+ require 'dap/filter/ldap'
@@ -0,0 +1,55 @@
1
+ module Dap
2
+ module Filter
3
+
4
+ require 'openssl'
5
+
6
+ require 'dap/proto/ldap'
7
+
8
+ #
9
+ # Decode an LDAP SearchRequest probe response
10
+ #
11
+ class FilterDecodeLdapSearchResult
12
+ include BaseDecoder
13
+
14
+ #
15
+ # Decode an LDAP SearchRequest probe response
16
+ #
17
+ # @param data [String] Binary string containing raw response from server
18
+ # @return [Hash] Hash containing all LDAP responses
19
+ #
20
+ def decode(data)
21
+ info = {}
22
+
23
+ # RFC 4511 - 4.5.2 SearchResult contains zero or more SearchResultEntry or
24
+ # SearchResultReference messages followed by a single SearchResultDone
25
+ # message. OpenSSL::ASN1.decode doesn't handle the back to back Sequences
26
+ # well, so identify the lengths and split them into individual ASN1 elements
27
+ messages = Dap::Proto::LDAP.split_messages(data)
28
+
29
+ if messages.empty?
30
+ err_msg = 'FilterDecodeLdapSearchResult - Unable to parse response'
31
+ info['Error'] = { 'errorMessage' => err_msg }
32
+ end
33
+
34
+
35
+ messages.each do |element|
36
+ begin
37
+ elem_decoded = OpenSSL::ASN1.decode(element)
38
+ rescue Exception => e
39
+ err_msg = 'FilterDecodeLdapSearchResult - Unable to decode ANS1 element'
40
+ $stderr.puts "#{err_msg}: #{e}"
41
+ $stderr.puts e.backtrace
42
+ info['Error'] = { 'errorMessage' => err_msg }
43
+ next
44
+ end
45
+ parsed_type, parsed_data = Dap::Proto::LDAP.parse_message(elem_decoded)
46
+ info[parsed_type] = parsed_data if parsed_type && parsed_data
47
+ end
48
+
49
+ info
50
+ end
51
+
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,127 @@
1
+ module Dap
2
+ module Proto
3
+ class LDAP
4
+
5
+
6
+ #
7
+ # Parse ASN1 element and extract the length.
8
+ # See The BER length section here:
9
+ # https://blogs.oracle.com/directorymanager/entry/a_quick_introduction_to_asn
10
+ #
11
+ # @param data [String] Binary string containing ASN1 element(s)
12
+ # @return [Fixnum, nil] Total length of of the ASN1 element, nil on error
13
+ #
14
+ def self.decode_elem_length(data)
15
+ return unless data.length > 2
16
+
17
+ # Length of element starts counting after the length
18
+ elem_start = 2
19
+
20
+ # Unpack the second byte as an integer
21
+ length = data.byteslice(1).unpack('C')[0]
22
+
23
+ if length > 127
24
+ # Length will take more than one byte to store
25
+ len_bytes = length - 128
26
+ return unless data.length > len_bytes + 2
27
+
28
+ if len_bytes == 2
29
+ length = data.byteslice(2, len_bytes).unpack('S>')[0]
30
+ else
31
+ length = data.byteslice(2, len_bytes).unpack('L>')[0]
32
+ end
33
+ elem_start += len_bytes
34
+ end
35
+
36
+ elem_start + length
37
+ end
38
+
39
+ #
40
+ # Split binary string into ASN1 elements.
41
+ #
42
+ # @param data [String] Binary string containing raw response from LDAP server
43
+ # @return [Array] Array of binary strings containing ASN1 elements
44
+ #
45
+ def self.split_messages(data)
46
+ messages = []
47
+ return messages unless data.length > 2
48
+ pos = 0
49
+ while pos < data.length
50
+ break unless data.byteslice(pos) == '0'
51
+ elem_len = Dap::Proto::LDAP.decode_elem_length(data.byteslice(pos..data.length - 1))
52
+ break unless elem_len
53
+
54
+ # Sanity check and then carve out the current element
55
+ if data.length >= elem_len + pos
56
+ current_elem = data.byteslice(pos, elem_len)
57
+ messages.push(current_elem)
58
+ end
59
+ pos += elem_len
60
+ end
61
+ messages
62
+ end
63
+
64
+ #
65
+ # Parse an LDAP SearchResult entry.
66
+ #
67
+ # @param data [OpenSSL::ASN1::Sequence] LDAP message to parse
68
+ # @return [Array] Array containing
69
+ # result_type - Message type (SearchResultEntry, SearchResultDone, etc.)
70
+ # results - Hash containing nested decoded LDAP response
71
+ #
72
+ def self.parse_message(data)
73
+ # RFC 4511 - Section 4.5.2
74
+
75
+ result_type = ''
76
+ results = {}
77
+
78
+ unless data.class == OpenSSL::ASN1::Sequence
79
+ result_type = 'Error'
80
+ results['errorMessage'] = 'parse_message: Message is not of type OpenSSL::ASN1::Sequence'
81
+ return [result_type, results]
82
+ end
83
+
84
+ if data.value[1].tag == 4
85
+ # SearchResultEntry found..
86
+ result_type = 'SearchResultEntry'
87
+ if data.value[1].value[0].tag == 4
88
+ results['objectName'] = data.value[1].value[0].value
89
+ end
90
+
91
+ attrib_hash = {}
92
+
93
+ # Handle PartialAttributeValues
94
+ data.value[1].value[1].each do |partial_attrib|
95
+
96
+ value_array = []
97
+ attrib_type = partial_attrib.value[0].value
98
+
99
+ partial_attrib.value[1].each do |part_attrib_value|
100
+ value_array.push(part_attrib_value.value)
101
+ end
102
+
103
+ attrib_hash[attrib_type] = value_array
104
+ end
105
+
106
+ results['PartialAttributes'] = attrib_hash
107
+
108
+ elsif data.value[1].tag == 5
109
+ # SearchResultDone found..
110
+ result_type = 'SearchResultDone'
111
+ results['resultCode'] = data.value[1].value[0].value.to_i if data.value[1].value[0].value
112
+ results['resultMatchedDN'] = data.value[1].value[1].value if data.value[1].value[1].value
113
+ results['resultdiagMessage'] = data.value[1].value[2].value if data.value[1].value[2].value
114
+ else
115
+ # Unhandled tag
116
+ result_type = 'UnhandledTag'
117
+ results['tagNumber'] = data.value[1].tag.to_i if data.value[1].tag
118
+ end
119
+
120
+ [result_type, results]
121
+ end
122
+
123
+
124
+ end
125
+
126
+ end
127
+ end
data/lib/dap/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Dap
2
- VERSION = "0.0.8"
2
+ VERSION = "0.0.9"
3
3
  end
@@ -0,0 +1,45 @@
1
+ describe Dap::Filter::FilterDecodeLdapSearchResult do
2
+ describe '.decode' do
3
+
4
+ original = ['3030020107642b040030273025040b6f626a656374436c61'\
5
+ '737331160403746f70040f4f70656e4c444150726f6f7444'\
6
+ '5345300c02010765070a010004000400']
7
+
8
+ data = original.pack('H*')
9
+
10
+ let(:filter) { described_class.new(['data']) }
11
+
12
+ context 'testing full ldap response message' do
13
+ let(:decode) { filter.decode(data) }
14
+ it 'returns Hash as expected' do
15
+ expect(decode.class).to eq(::Hash)
16
+ end
17
+
18
+ it 'returns expected value' do
19
+ test_val = { 'SearchResultDone' => {
20
+ 'resultCode' => 0,
21
+ 'resultMatchedDN' => '',
22
+ 'resultdiagMessage' => ''
23
+ },
24
+ 'SearchResultEntry' => {
25
+ 'objectName' => '',
26
+ 'PartialAttributes' => {
27
+ 'objectClass' => ['top', 'OpenLDAProotDSE']
28
+ }
29
+ } }
30
+
31
+ expect(decode).to eq(test_val)
32
+ end
33
+ end
34
+
35
+ context 'testing invalid ldap response message' do
36
+ let(:decode) { filter.decode('303030303030') }
37
+ it 'returns error message as expected' do
38
+ test_val = { 'Error' => {
39
+ 'errorMessage' =>
40
+ 'FilterDecodeLdapSearchResult - Unable to parse response' } }
41
+ expect(decode).to eq(test_val)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -1,19 +1,20 @@
1
- require 'bit-struct'
2
- require_relative '../../../lib/dap/proto/ipmi'
1
+ describe Dap::Proto::IPMI::Channel_Auth_Reply do
2
+ describe '.valid?' do
3
3
 
4
- module Dap
5
- module Proto
6
- module IPMI
4
+ context 'testing with valid rmcp version and message length' do
5
+ it 'returns true as expected' do
6
+ expect(described_class.new(rmcp_version: 6).valid?).to be false
7
+ expect(described_class.new(message_length: 16).valid?).to be false
8
+ expect(described_class.new(rmcp_version: 6, message_length: 16).valid?).to be true
9
+ end
10
+ end
7
11
 
8
- describe Channel_Auth_Reply do
9
- it "valid with the proper rmcp version and message length" do
10
- expect(subject.valid?).to be false
11
- expect(Channel_Auth_Reply.new(rmcp_version: 6).valid?).to be false
12
- expect(Channel_Auth_Reply.new(message_length: 16).valid?).to be false
13
- expect(Channel_Auth_Reply.new(rmcp_version: 6, message_length: 16).valid?).to be true
14
- end
15
- end
12
+ context 'testing with invalid data' do
13
+ let(:reply) { described_class.new }
16
14
 
17
- end
18
- end
15
+ it 'returns false as expected' do
16
+ expect(reply.valid?).to be false
17
+ end
18
+ end
19
+ end
19
20
  end
@@ -0,0 +1,142 @@
1
+ describe Dap::Proto::LDAP do
2
+ subject { described_class }
3
+
4
+ describe '.decode_elem_length' do
5
+ context 'testing lengths shorter than 128 bits' do
6
+ data = ['301402'].pack('H*')
7
+ let(:decode_len) { subject.decode_elem_length(data) }
8
+ it 'returns a Fixnum' do
9
+ expect(decode_len.class).to eq(::Fixnum)
10
+ end
11
+ it 'returns value correctly' do
12
+ expect(decode_len).to eq(22)
13
+ end
14
+ end
15
+
16
+ context 'testing lengths greater than 128 bits' do
17
+ data = ['308400000bc102010'].pack('H*')
18
+ let(:decode_len) { subject.decode_elem_length(data) }
19
+ it 'returns a Fixnum' do
20
+ expect(decode_len.class).to eq(::Fixnum)
21
+ end
22
+ it 'returns value correctly' do
23
+ expect(decode_len).to eq(3015)
24
+ end
25
+ end
26
+
27
+ context 'testing invalid length' do
28
+ data = ['308400000bc1'].pack('H*')
29
+ let(:decode_len) { subject.decode_elem_length(data) }
30
+ it 'returns nil as expected' do
31
+ expect(decode_len).to eq(nil)
32
+ end
33
+
34
+ end
35
+ end
36
+
37
+ describe '.split_messages' do
38
+
39
+ original = ['3030020107642b040030273025040b6f626a656374436c61'\
40
+ '737331160403746f70040f4f70656e4c444150726f6f7444'\
41
+ '5345300c02010765070a010004000400']
42
+
43
+ data = original.pack('H*')
44
+
45
+ entry = ['3030020107642b040030273025040b6f626a656374436c6173'\
46
+ '7331160403746f70040f4f70656e4c444150726f6f74445345']
47
+
48
+ done = ['300c02010765070a010004000400']
49
+
50
+ context 'testing full message' do
51
+ let(:split_messages) { subject.split_messages(data) }
52
+ it 'returns Array as expected' do
53
+ expect(split_messages.class).to eq(::Array)
54
+ end
55
+
56
+ it 'returns SearchResultEntry value as expected' do
57
+ expect(split_messages[0].unpack('H*')).to eq(entry)
58
+ end
59
+
60
+ it 'returns SearchResultDone value as expected' do
61
+ expect(split_messages[1].unpack('H*')).to eq(done)
62
+ end
63
+ end
64
+
65
+ context 'testing invalid message' do
66
+ let(:split_messages) { subject.split_messages('FF') }
67
+ it 'returns Array as expected' do
68
+ expect(split_messages.class).to eq(::Array)
69
+ end
70
+ end
71
+
72
+ context 'testing short message' do
73
+ let(:split_messages) { subject.split_messages('00') }
74
+ it 'returns Array as expected' do
75
+ expect(split_messages.class).to eq(::Array)
76
+ end
77
+ end
78
+ end
79
+
80
+ describe '.parse_messages' do
81
+
82
+ context 'testing SearchResultEntry' do
83
+ hex = ['3030020107642b040030273025040b6f626a656374436c6173'\
84
+ '7331160403746f70040f4f70656e4c444150726f6f74445345']
85
+ data = OpenSSL::ASN1.decode(hex.pack('H*'))
86
+
87
+ let(:parse_message) { subject.parse_message(data) }
88
+ it 'returns Array as expected' do
89
+ expect(parse_message.class).to eq(::Array)
90
+ end
91
+
92
+ it 'returns SearchResultEntry value as expected' do
93
+ test_val = ['SearchResultEntry', {
94
+ 'objectName' => '',
95
+ 'PartialAttributes' => {
96
+ 'objectClass' => [
97
+ 'top',
98
+ 'OpenLDAProotDSE'
99
+ ]
100
+ }
101
+ }]
102
+ expect(parse_message).to eq(test_val)
103
+ end
104
+ end
105
+
106
+ context 'testing SearchResultDone' do
107
+ hex = ['300c02010765070a010004000400']
108
+ data = OpenSSL::ASN1.decode(hex.pack('H*'))
109
+
110
+ let(:parse_message) { subject.parse_message(data) }
111
+ it 'returns Array as expected' do
112
+ expect(parse_message.class).to eq(::Array)
113
+ end
114
+
115
+ it 'returns SearchResultDone value as expected' do
116
+ test_val = ['SearchResultDone', {
117
+ 'resultCode' => 0,
118
+ 'resultMatchedDN' => '',
119
+ 'resultdiagMessage' => ''
120
+ }]
121
+ expect(parse_message).to eq(test_val)
122
+ end
123
+ end
124
+
125
+ context 'testing UnhandledTag' do
126
+ hex = ['300c02010767070a010004000400']
127
+ data = OpenSSL::ASN1.decode(hex.pack('H*'))
128
+
129
+ let(:parse_message) { subject.parse_message(data) }
130
+ it 'returns Array as expected' do
131
+ expect(parse_message.class).to eq(::Array)
132
+ end
133
+
134
+ it 'returns UnhandledTag value as expected' do
135
+ test_val = ['UnhandledTag', { 'tagNumber' => 7 }]
136
+ expect(parse_message).to eq(test_val)
137
+ end
138
+ end
139
+
140
+ end
141
+
142
+ end
@@ -0,0 +1,91 @@
1
+ require 'dap'
2
+
3
+ # This file was generated by the `rspec --init` command. Conventionally, all
4
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
5
+ # The generated `.rspec` file contains `--require spec_helper` which will cause this
6
+ # file to always be loaded, without a need to explicitly require it in any files.
7
+ #
8
+ # Given that it is always loaded, you are encouraged to keep this file as
9
+ # light-weight as possible. Requiring heavyweight dependencies from this file
10
+ # will add to the boot time of your test suite on EVERY test run, even for an
11
+ # individual file that may not need all of that loaded. Instead, consider making
12
+ # a separate helper file that requires the additional dependencies and performs
13
+ # the additional setup, and require it from the spec files that actually need it.
14
+ #
15
+ # The `.rspec` file also contains a few flags that are not defaults but that
16
+ # users commonly want.
17
+ #
18
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
19
+ RSpec.configure do |config|
20
+ # rspec-expectations config goes here. You can use an alternate
21
+ # assertion/expectation library such as wrong or the stdlib/minitest
22
+ # assertions if you prefer.
23
+ config.expect_with :rspec do |expectations|
24
+ # This option will default to `true` in RSpec 4. It makes the `description`
25
+ # and `failure_message` of custom matchers include text for helper methods
26
+ # defined using `chain`, e.g.:
27
+ # be_bigger_than(2).and_smaller_than(4).description
28
+ # # => "be bigger than 2 and smaller than 4"
29
+ # ...rather than:
30
+ # # => "be bigger than 2"
31
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
32
+ end
33
+
34
+ # rspec-mocks config goes here. You can use an alternate test double
35
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
36
+ config.mock_with :rspec do |mocks|
37
+ # Prevents you from mocking or stubbing a method that does not exist on
38
+ # a real object. This is generally recommended, and will default to
39
+ # `true` in RSpec 4.
40
+ mocks.verify_partial_doubles = true
41
+ end
42
+
43
+ # The settings below are suggested to provide a good initial experience
44
+ # with RSpec, but feel free to customize to your heart's content.
45
+ =begin
46
+ # These two settings work together to allow you to limit a spec run
47
+ # to individual examples or groups you care about by tagging them with
48
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
49
+ # get run.
50
+ config.filter_run :focus
51
+ config.run_all_when_everything_filtered = true
52
+
53
+ # Limits the available syntax to the non-monkey patched syntax that is recommended.
54
+ # For more details, see:
55
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
56
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
57
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
58
+ config.disable_monkey_patching!
59
+
60
+ # This setting enables warnings. It's recommended, but in some cases may
61
+ # be too noisy due to issues in dependencies.
62
+ config.warnings = true
63
+
64
+ # Many RSpec users commonly either run the entire suite or an individual
65
+ # file, and it's useful to allow more verbose output when running an
66
+ # individual spec file.
67
+ if config.files_to_run.one?
68
+ # Use the documentation formatter for detailed output,
69
+ # unless a formatter has already been configured
70
+ # (e.g. via a command-line flag).
71
+ config.default_formatter = 'doc'
72
+ end
73
+
74
+ # Print the 10 slowest examples and example groups at the
75
+ # end of the spec run, to help surface which specs are running
76
+ # particularly slow.
77
+ config.profile_examples = 10
78
+
79
+ # Run specs in random order to surface order dependencies. If you find an
80
+ # order dependency and want to debug it, you can fix the order by providing
81
+ # the seed, which is printed after each run.
82
+ # --seed 1234
83
+ config.order = :random
84
+
85
+ # Seed global randomization in this process using the `--seed` CLI option.
86
+ # Setting this allows you to use `--seed` to deterministically reproduce
87
+ # test failures related to randomization by passing the same `--seed` value
88
+ # as the one that triggered the failure.
89
+ Kernel.srand config.seed
90
+ =end
91
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rapid7 Research
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-28 00:00:00.000000000 Z
11
+ date: 2016-07-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -181,6 +181,7 @@ files:
181
181
  - lib/dap/filter/base.rb
182
182
  - lib/dap/filter/geoip.rb
183
183
  - lib/dap/filter/http.rb
184
+ - lib/dap/filter/ldap.rb
184
185
  - lib/dap/filter/names.rb
185
186
  - lib/dap/filter/openssl.rb
186
187
  - lib/dap/filter/recog.rb
@@ -196,6 +197,7 @@ files:
196
197
  - lib/dap/proto/addp.rb
197
198
  - lib/dap/proto/dtls.rb
198
199
  - lib/dap/proto/ipmi.rb
200
+ - lib/dap/proto/ldap.rb
199
201
  - lib/dap/proto/mssql.rb
200
202
  - lib/dap/proto/natpmp.rb
201
203
  - lib/dap/proto/wdbrpc.rb
@@ -217,7 +219,10 @@ files:
217
219
  - samples/ssl_certs_org.sh
218
220
  - samples/udp-netbios.csv.bz2
219
221
  - samples/udp-netbios.sh
222
+ - spec/dap/filter/ldap_filter_spec.rb
220
223
  - spec/dap/proto/ipmi_spec.rb
224
+ - spec/dap/proto/ldap_proto_spec.rb
225
+ - spec/spec_helper.rb
221
226
  - tools/geo-ip-summary.rb
222
227
  - tools/ipmi-vulns.rb
223
228
  - tools/json-summarize.rb
@@ -243,9 +248,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
243
248
  version: '0'
244
249
  requirements: []
245
250
  rubyforge_project:
246
- rubygems_version: 2.4.5.1
251
+ rubygems_version: 2.5.1
247
252
  signing_key:
248
253
  specification_version: 4
249
254
  summary: 'DAP: The Data Analysis Pipeline'
250
- test_files: []
251
- has_rdoc:
255
+ test_files:
256
+ - spec/dap/filter/ldap_filter_spec.rb
257
+ - spec/dap/proto/ipmi_spec.rb
258
+ - spec/dap/proto/ldap_proto_spec.rb
259
+ - spec/spec_helper.rb