recog 2.0.15 → 2.0.16

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 81ca81c5892d0fb7882afdb14f8c6e0324196cbb
4
- data.tar.gz: 793218a1570ce08ee7e3c0895b1c5822e5f49922
3
+ metadata.gz: ebf510b58ac33138c4fdcf5ee549e8a357f705af
4
+ data.tar.gz: d66456b16899f7af045ab574181bc344ac67a7f6
5
5
  SHA512:
6
- metadata.gz: fa6edf956ca223ea34ebd8c39a6a2e4a471b3f225d9642ba83e4e945ce4135f0691b64b67b767d48b557df83c474563ccf7ff28f11e77bac5007a6607cc81272
7
- data.tar.gz: 9e9045604f3a260422e0002bf63d565ebedad35ab1a2afb99775a2bb28bf70d459ed9330feba2742c1f1b118daf421c2965b7c11498c30de02c406dc967a4831
6
+ metadata.gz: 86f98b254c38d880fa44c03a2be7d5ba5264163b6b119890fc4a91b40e37b1958e4a201ed84a8b47b5e1ee33a2be52db9920ecfedb243a271f80c6043c978309
7
+ data.tar.gz: b81423e03118c816b4402c1fc69e42732d5907996889b95d1e28fda0f8cd9dbb945b1fbe4e06a756b0e2bdd54d59d587c44941caa4282a84b88525ab0d8fc5e5
data/.gitignore CHANGED
@@ -2,7 +2,7 @@
2
2
  coverage/
3
3
  doc/
4
4
  pkg/
5
-
5
+ .idea/
6
6
  /Gemfile.lock
7
7
 
8
8
  # ignore rvm files
data/bin/recog_match CHANGED
@@ -6,7 +6,7 @@ require 'ostruct'
6
6
  require 'recog'
7
7
  require 'recog/matcher_factory'
8
8
 
9
- options = OpenStruct.new(color: false, detail: false, fail_fast: false)
9
+ options = OpenStruct.new(color: false, detail: false, fail_fast: false, multi_match: false)
10
10
 
11
11
  option_parser = OptionParser.new do |opts|
12
12
  opts.banner = "Usage: #{$0} [options] XML_FINGERPRINT_FILE [BANNERS_FILE]"
@@ -33,6 +33,10 @@ option_parser = OptionParser.new do |opts|
33
33
  options.color = true
34
34
  end
35
35
 
36
+ opts.on("--[no-]multi-match", "Enable or disable multiple matches (defaults to disabled)") do |o|
37
+ options.multi_match = o
38
+ end
39
+
36
40
  opts.on("-h", "--help", "Show this message.") do
37
41
  puts opts
38
42
  exit
@@ -0,0 +1,30 @@
1
+ <?xml version="1.0"?>
2
+ <fingerprints>
3
+ <fingerprint pattern="FTP">
4
+ <example>---- FTP Stuff ----</example>
5
+ <example>FTP server</example>
6
+ <description>Generic FTP,
7
+ Checks for the existence of the word FTP in the line
8
+ </description>
9
+ <!-- Asserting nothing -->
10
+ </fingerprint>
11
+ <fingerprint pattern="^-{10} Welcome to Pure-FTPd (.*)-{10}$">
12
+ <example>---------- Welcome to Pure-FTPd ----------</example>
13
+ <description>Pure-FTPd
14
+ Config data can be zero or more of: [privsep] [TLS]
15
+ </description>
16
+ <param pos="1" name="pureftpd.config"/>
17
+ <param pos="0" name="service.family" value="Pure-FTPd"/>
18
+ <param pos="0" name="service.product" value="Pure-FTPd"/>
19
+ </fingerprint>
20
+ <fingerprint pattern="^(\S+) FTP Server \(SunOS (\S+)\) ready\.?$" flags="REG_ICASE">
21
+ <description>SunOS/Solaris</description>
22
+ <example>example.com FTP server (SunOS 5.7) ready.</example>
23
+ <param pos="0" name="os.vendor" value="Sun"/>
24
+ <param pos="0" name="os.family" value="Solaris"/>
25
+ <param pos="0" name="os.product" value="Solaris"/>
26
+ <param pos="0" name="os.device" value="General"/>
27
+ <param pos="1" name="host.name"/>
28
+ <param pos="2" name="os.version"/>
29
+ </fingerprint>
30
+ </fingerprints>
@@ -14,3 +14,19 @@ Feature: Match
14
14
  FAIL: ---------- Welcome to Pure-FTPd [privsep] [TLS] ----------
15
15
  FAIL: polaris FTP server (SunOS 5.8) ready
16
16
  """
17
+
18
+ Scenario: Finds multiple matches
19
+ When I run `recog_match multiple_banners_fingerprints.xml sample_banner.txt --multi-match`
20
+ Then it should pass with:
21
+ """
22
+ MATCHES: {"matched"=>"Generic FTP, Checks for the existence of the word FTP in the line", "data"=>"---------- Welcome to Pure-FTPd [privsep] [TLS] ----------"},{"matched"=>"Pure-FTPd Config data can be zero or more of: [privsep] [TLS]", "pureftpd.config"=>"[privsep] [TLS] ", "service.family"=>"Pure-FTPd", "service.product"=>"Pure-FTPd", "data"=>"---------- Welcome to Pure-FTPd [privsep] [TLS] ----------"}
23
+ MATCHES: {"matched"=>"Generic FTP, Checks for the existence of the word FTP in the line", "data"=>"polaris FTP server (SunOS 5.8) ready."},{"matched"=>"SunOS/Solaris", "os.vendor"=>"Sun", "os.family"=>"Solaris", "os.product"=>"Solaris", "os.device"=>"General", "host.name"=>"polaris", "os.version"=>"5.8", "data"=>"polaris FTP server (SunOS 5.8) ready."}
24
+ """
25
+
26
+ Scenario: Finds first matches using no-multi-match flag
27
+ When I run `recog_match multiple_banners_fingerprints.xml sample_banner.txt --no-multi-match`
28
+ Then it should pass with:
29
+ """
30
+ MATCH: {"matched"=>"Generic FTP, Checks for the existence of the word FTP in the line", "data"=>"---------- Welcome to Pure-FTPd [privsep] [TLS] ----------"}
31
+ MATCH: {"matched"=>"Generic FTP, Checks for the existence of the word FTP in the line", "data"=>"polaris FTP server (SunOS 5.8) ready."}
32
+ """
data/lib/recog/matcher.rb CHANGED
@@ -1,12 +1,17 @@
1
1
  module Recog
2
2
  class Matcher
3
- attr_reader :fingerprints, :reporter
3
+ attr_reader :fingerprints, :reporter, :multi_match
4
4
 
5
- def initialize(fingerprints, reporter)
5
+ # @param fingerprints Array of [Recog::Fingerprint] The list of fingerprints from the Recog DB to find possible matches.
6
+ # @param reporter [Recog::MatchReporter] The reporting structure that holds the matches and fails
7
+ # @param multi_match [Boolean] specifies whether or not to use multi-match (true) or not (false)
8
+ def initialize(fingerprints, reporter, multi_match)
6
9
  @fingerprints = fingerprints
7
10
  @reporter = reporter
11
+ @multi_match = multi_match
8
12
  end
9
13
 
14
+ # @param banners_file [String] The source of banners to attempt to match against the Recog DB.
10
15
  def match_banners(banners_file)
11
16
  reporter.report do
12
17
 
@@ -22,14 +27,26 @@ class Matcher
22
27
  reporter.increment_line_count
23
28
 
24
29
  line = line.to_s.unpack("C*").pack("C*").strip.gsub(/\\[rn]/, '')
25
- extractions = nil
30
+ found_extractions = false
31
+
32
+ all_extractions = []
26
33
  fingerprints.each do |fp|
27
- break if (extractions = fp.match(line))
34
+ extractions = fp.match(line)
35
+ if extractions
36
+ found_extractions = true
37
+ extractions['data'] = line
38
+ if multi_match
39
+ all_extractions << extractions
40
+ else
41
+ reporter.match "MATCH: #{extractions.inspect}"
42
+ break
43
+ end
44
+ end
28
45
  end
29
46
 
30
- if extractions
31
- extractions['data'] = line
32
- reporter.match "MATCH: #{extractions.inspect}"
47
+ if found_extractions
48
+ match_prefix = all_extractions.size > 1 ? 'MATCHES' : 'MATCH'
49
+ reporter.match "#{match_prefix}: #{all_extractions.map(&:inspect).join(',')}" if multi_match
33
50
  else
34
51
  reporter.failure "FAIL: #{line}"
35
52
  end
@@ -37,6 +54,7 @@ class Matcher
37
54
  if reporter.stop?
38
55
  break
39
56
  end
57
+
40
58
  end
41
59
 
42
60
  fd.close if file_source
@@ -8,7 +8,7 @@ module MatcherFactory
8
8
  def self.build(options)
9
9
  formatter = Formatter.new(options, $stdout)
10
10
  reporter = MatchReporter.new(options, formatter)
11
- Matcher.new(options.fingerprints, reporter)
11
+ Matcher.new(options.fingerprints, reporter, options.multi_match)
12
12
  end
13
13
  end
14
14
  end
data/lib/recog/nizer.rb CHANGED
@@ -41,6 +41,24 @@ class Nizer
41
41
  nil
42
42
  end
43
43
 
44
+ def self.multi_match(match_key, match_string)
45
+ match_string = match_string.to_s.unpack("C*").pack("C*")
46
+ @@db_manager ||= Recog::DBManager.new
47
+
48
+ matches = Array.new #array to hold all fingerprint matches
49
+
50
+ @@db_manager.databases.each do |db|
51
+ next unless db.match_key == match_key
52
+
53
+ db.fingerprints.each do |fp|
54
+ m = fp.match(match_string)
55
+ matches.push(m) if m
56
+ end
57
+ end
58
+
59
+ return matches
60
+ end
61
+
44
62
  #
45
63
  # Consider an array of match outputs, choose the best result, taking into
46
64
  # account the granularity of OS vs Version vs SP vs Language. Only consider
data/lib/recog/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Recog
2
- VERSION = '2.0.15'
2
+ VERSION = '2.0.16'
3
3
  end
@@ -26,6 +26,54 @@ describe Recog::Nizer do
26
26
 
27
27
  end
28
28
  end
29
+
30
+ line = 'non-existent'
31
+ context "with non-existent match" do
32
+ let(:match_result) {subject.match('smb.native_os', line) }
33
+ it "returns a nil" do
34
+ expect(match_result).to be_nil
35
+ end
36
+ end
37
+ end
38
+
39
+ describe ".multi_match" do
40
+ File.readlines(File.expand_path(File.join('spec', 'data', 'smb_native_os.txt'))).each do |line|
41
+ data = line.strip
42
+
43
+ context "with smb_native_os:#{data}" do
44
+ let(:match_results) {subject.multi_match('smb.native_os', data) }
45
+
46
+ it "returns an array" do
47
+ expect(match_results.class).to eq(::Array)
48
+ end
49
+
50
+ it "returns at least one successful match" do
51
+ expect(match_results.size).to be > 0
52
+ end
53
+
54
+ it "correctly matches service or os" do
55
+ match_results do |mr|
56
+ if data =~ /^Windows/
57
+ expect(mr['os.product']).to match(/^Windows/)
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ end
64
+
65
+ line = 'non-existent'
66
+ context "with non-existent match" do
67
+ let(:match_results) {subject.multi_match('smb.native_os', line) }
68
+
69
+ it "returns an array" do
70
+ expect(match_results.class).to eq(::Array)
71
+ end
72
+
73
+ it "returns an empty array" do
74
+ expect(match_results).to be_empty
75
+ end
76
+ end
29
77
  end
30
78
 
31
79
  describe ".best_os_match" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: recog
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.15
4
+ version: 2.0.16
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-10-27 00:00:00.000000000 Z
11
+ date: 2015-11-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -136,6 +136,7 @@ files:
136
136
  - bin/recog_verify
137
137
  - features/data/failing_banners_fingerprints.xml
138
138
  - features/data/matching_banners_fingerprints.xml
139
+ - features/data/multiple_banners_fingerprints.xml
139
140
  - features/data/no_tests.xml
140
141
  - features/data/sample_banner.txt
141
142
  - features/data/successful_tests.xml