recog 2.0.15 → 2.0.16

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: 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