oober 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +5 -0
- data/Guardfile +55 -0
- data/README.md +87 -0
- data/Rakefile +6 -0
- data/bin/oober +12 -0
- data/lib/oober.rb +22 -0
- data/lib/oober/cef_logger.rb +68 -0
- data/lib/oober/cli.rb +113 -0
- data/lib/oober/extractor/stix.rb +50 -0
- data/lib/oober/version.rb +3 -0
- data/oober.gemspec +35 -0
- data/samples/hail-a-taxii.json +168 -0
- data/samples/logstash.conf +10 -0
- metadata +216 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 106071adcf657c015f8581464b25d729e1108484
|
4
|
+
data.tar.gz: 5aefffa324bcce20b8ba80c53c35345edf515bba
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f16b4e6da2ed97bad77b35c620b41fb7b20132e53f0e36b75351160d53572989c851acfda1dcd17afd100a4528c4a614aa84e665680d856ff8ea75889e2d034c
|
7
|
+
data.tar.gz: c779fdf9e0a51f413bdaae2c5a8ceb57e289229fd895674278c4e0e9ba8dd073d47eb8ce43158e885aca3440ed18a9695a8ac0ec9aa7e719f6dcf840db566a3f
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
## Uncomment and set this to only include directories you want to watch
|
5
|
+
# directories %w(app lib config test spec features) \
|
6
|
+
# .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
|
7
|
+
|
8
|
+
## Note: if you are using the `directories` clause above and you are not
|
9
|
+
## watching the project directory ('.'), then you will want to move
|
10
|
+
## the Guardfile to a watched dir and symlink it back, e.g.
|
11
|
+
#
|
12
|
+
# $ mkdir config
|
13
|
+
# $ mv Guardfile config/
|
14
|
+
# $ ln -s config/Guardfile .
|
15
|
+
#
|
16
|
+
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"
|
17
|
+
|
18
|
+
guard :bundler do
|
19
|
+
require 'guard/bundler'
|
20
|
+
require 'guard/bundler/verify'
|
21
|
+
helper = Guard::Bundler::Verify.new
|
22
|
+
|
23
|
+
files = ['Gemfile','oober.gemspec']
|
24
|
+
#files += Dir['*.gemspec'] if files.any? { |f| helper.uses_gemspec?(f) }
|
25
|
+
|
26
|
+
# Assume files are symlinked from somewhere
|
27
|
+
files.each { |file| watch(helper.real_path(file)) }
|
28
|
+
end
|
29
|
+
|
30
|
+
# Note: The cmd option is now required due to the increasing number of ways
|
31
|
+
# rspec may be run, below are examples of the most common uses.
|
32
|
+
# * bundler: 'bundle exec rspec'
|
33
|
+
# * bundler binstubs: 'bin/rspec'
|
34
|
+
# * spring: 'bin/rspec' (This will use spring if running and you have
|
35
|
+
# installed the spring binstubs per the docs)
|
36
|
+
# * zeus: 'zeus rspec' (requires the server to be started separately)
|
37
|
+
# * 'just' rspec: 'rspec'
|
38
|
+
|
39
|
+
guard :rspec, cmd: "bundle exec rspec" do
|
40
|
+
require "guard/rspec/dsl"
|
41
|
+
dsl = Guard::RSpec::Dsl.new(self)
|
42
|
+
|
43
|
+
# Feel free to open issues for suggestions and improvements
|
44
|
+
|
45
|
+
# RSpec files
|
46
|
+
rspec = dsl.rspec
|
47
|
+
watch(rspec.spec_helper) { rspec.spec_dir }
|
48
|
+
watch(rspec.spec_support) { rspec.spec_dir }
|
49
|
+
watch(rspec.spec_files)
|
50
|
+
|
51
|
+
# Ruby files
|
52
|
+
ruby = dsl.ruby
|
53
|
+
dsl.watch_spec_files_for(ruby.lib_files)
|
54
|
+
|
55
|
+
end
|
data/README.md
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
# Oober
|
2
|
+
|
3
|
+
Oober is a simplified [TAXII](https://taxiiproject.github.io/) client for extracting and exporting structured cyber threat intelligence.
|
4
|
+
|
5
|
+
Oober currently supports extracting data from [STIX](https://stixproject.github.io/)-formatted messages and exporting them via [CEF](https://protect724.hp.com/docs/DOC-1072) to a syslog receiver (and potentially ArcSight if you're into that sort of thing).
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
you can install the gem and executables to your current ruby runtime with:
|
10
|
+
|
11
|
+
$ gem install oober
|
12
|
+
|
13
|
+
If you plan on wrapping your own clients, adding extractors (it's super easy!), or starting a threat-polling repo, add the following to your 'Gemfile'
|
14
|
+
|
15
|
+
gem 'oober'
|
16
|
+
|
17
|
+
and then
|
18
|
+
|
19
|
+
$ bundle install
|
20
|
+
|
21
|
+
If you want to hack on oober, check the DEVELOPMENT section below
|
22
|
+
|
23
|
+
## Configuration
|
24
|
+
Oober currently is pretty configurable, but currently only supports extracting STIX messages from an http/basic_auth TAXII endpoint and transforming those into CEF-formatted syslog messages. If that's what you want to do, you're in luck.
|
25
|
+
|
26
|
+
In the config, you specify the TAXII discovery endpoint, the credentials and feed name you'd like to poll. Then you describe what items to select/iterate over out of that feed, what data elements to extract from those items, and how you'd like to store the results. Finally, you can provide the address/port of a syslog server to send your extracted messages. Sample configurations in the 'samples/' directory.
|
27
|
+
|
28
|
+
Element selection is specified in extractor_configs[]/select. This should be an XPath query of the deepest element you would like to iterate over.
|
29
|
+
|
30
|
+
Extractions are specified as XPath queries under extractor_configs[]/extractions[]. Each extraction has an "origin" XPath and a "target". Data elements are extracted from the "origin" expression and emitted as hash values under the key name specified in "target". The whole message/content block should be available from the starting path of the 'select' node.
|
31
|
+
|
32
|
+
Default hash key/values can be specified under extractor_configs[]/defaults. These defaults will be merged over in extraction, so you could potentially overwrite an extracted value if there is a key collision.
|
33
|
+
|
34
|
+
There's a logstash.conf in the samples/ directory for running a syslog receiver on localhost:1999 if you'd like to inspect things as they would be sent over the wire. If you'd like to go a little deeper into logstash specifically, there's a CEF codec available from the logstash plugins repository. A JSON/tcp exporter is also on the horizon.
|
35
|
+
|
36
|
+
## CLI Usage
|
37
|
+
The CLI will automatically load a config file from ~/.oober.json unless you specify another file with the --config option.
|
38
|
+
|
39
|
+
Command line help is documented with Thor. To access the help info:
|
40
|
+
|
41
|
+
$ oober help <command>
|
42
|
+
|
43
|
+
To poll a feed:
|
44
|
+
|
45
|
+
$ oober poll --config /path/to/some.json
|
46
|
+
|
47
|
+
To download raw messages (useful for developing configs):
|
48
|
+
|
49
|
+
$ oober download --dir /path/to/output/dir
|
50
|
+
|
51
|
+
You can interactively test xpath queries against those downloaded messages with:
|
52
|
+
|
53
|
+
$ oober xpath /path/to/some/files*xml
|
54
|
+
|
55
|
+
And for convenience purposes, there's an interactive pry console. The console will instantiate your client in the 'client' local variable.
|
56
|
+
|
57
|
+
$ oober console
|
58
|
+
|
59
|
+
## Library Usage
|
60
|
+
Oober can be used in your code as a client library/interface.
|
61
|
+
|
62
|
+
- Oober.configure('filename.json') will instantiate a client with your extractor/exporter config
|
63
|
+
- '#get_blocks' will download message blocks
|
64
|
+
- '#extract_blocks' will extract hashes from the content blocks (but not transform them into the specified target format)
|
65
|
+
- '#transform_extracts' will pass your extracted hashes and create instances of your target format
|
66
|
+
|
67
|
+
## Development
|
68
|
+
|
69
|
+
Other extractors should be pretty easy to implement. I plan on taking a swing at IODEF at some point.
|
70
|
+
|
71
|
+
Other exporters should also be pretty easy to implement. This could be used to dump data into another webservice, database, file format, etc. JSON/tcp is probably next priority to make use of a logstash/elk stack. I think this will probably break some things at the outermost API layer, so please lock your versions while we're still in 0.X semver territory.
|
72
|
+
|
73
|
+
Work on the TAXII protocol bindings themselves will happen in the 'ruby-taxii' gem. If there's breakage for different server types, then I'll handle it over there. Oober will remain scoped to what's within the TAXII Content_Block.
|
74
|
+
|
75
|
+
## Security
|
76
|
+
|
77
|
+
Please be advised - there's nothing (currently) in the extractor framework preventing you from doing unsafe things in your xpath queries. You will be running these queries against content packages provided by third parties, some of which could be dangerous. This inherent vulnerability is also exacerbated by the fact that only HTTP/basic is currently supported in ruby-taxii, but even when that gets resolved, you're still interacting with potentially hostile content in a murky context. It is HIGHLY recommended that you lock down the system/network access environment as much as possible.
|
78
|
+
|
79
|
+
The config was intended to be used in a stateless manner, so you should be able to run from ephemeral instances just fine.
|
80
|
+
|
81
|
+
## Contributing
|
82
|
+
|
83
|
+
Unit tests and docs mostly missing. Need to try things out before I get more opinionated.
|
84
|
+
|
85
|
+
I'll take pull requests on the development branch. Otherwise, open an issue and I'll try to get to it.
|
86
|
+
|
87
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/ryanbreed/oober.
|
data/Rakefile
ADDED
data/bin/oober
ADDED
data/lib/oober.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'ipaddr'
|
2
|
+
require 'hashie'
|
3
|
+
require 'taxii'
|
4
|
+
require 'cef'
|
5
|
+
require 'json'
|
6
|
+
require 'thor'
|
7
|
+
|
8
|
+
require 'oober/version'
|
9
|
+
require 'oober/cef_logger'
|
10
|
+
require 'oober/extractor/stix'
|
11
|
+
|
12
|
+
module Oober
|
13
|
+
def self.configure(path=File.join(ENV['HOME'],'.oober.json'))
|
14
|
+
configuration = JSON.parse(File.read(path))
|
15
|
+
export_klass = Module.const_get(configuration.delete('exporter'))
|
16
|
+
extractor_klass = Module.const_get(configuration.delete('extractor'))
|
17
|
+
export_klass.new(
|
18
|
+
Hashie.symbolize_keys(configuration)
|
19
|
+
.merge( extractor: extractor_klass)
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Oober
|
2
|
+
class CefLogger < Hashie::Dash
|
3
|
+
property :feed_name
|
4
|
+
|
5
|
+
property :exporter
|
6
|
+
property :extractor
|
7
|
+
|
8
|
+
property :extractor_configs, default: []
|
9
|
+
|
10
|
+
property :export_config,
|
11
|
+
required: true,
|
12
|
+
message: 'needs to point to a valid CEF config'
|
13
|
+
property :taxii_config,
|
14
|
+
required: true,
|
15
|
+
message: 'needs to point to a valid ruby-taxii PollClient config'
|
16
|
+
|
17
|
+
def event_defaults
|
18
|
+
@event_defaults ||= {
|
19
|
+
name: self.feed_name,
|
20
|
+
deviceProduct: self.class.name,
|
21
|
+
deviceVersion: Oober::VERSION,
|
22
|
+
receiptTime: Time.new
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
def cef
|
27
|
+
@cef ||= CEF.logger(export_config)
|
28
|
+
end
|
29
|
+
|
30
|
+
def taxii
|
31
|
+
@taxii ||= Taxii::PollClient.new(taxii_config)
|
32
|
+
end
|
33
|
+
|
34
|
+
def get_blocks
|
35
|
+
taxii.get_content_blocks(self.request_message)
|
36
|
+
end
|
37
|
+
|
38
|
+
def extractor_pipeline(blocks=get_blocks)
|
39
|
+
extractors = blocks.flat_map do |block|
|
40
|
+
extractor_configs.map { |conf| extractor.new(conf.merge(data: block)) }
|
41
|
+
end
|
42
|
+
extractors.reject {|ext| ext.selected.empty? }
|
43
|
+
end
|
44
|
+
|
45
|
+
def extract_blocks(blocks=get_blocks)
|
46
|
+
extractor_pipeline(blocks).flat_map(&:extract)
|
47
|
+
.map {|extracted| extracted.merge(event_defaults)}
|
48
|
+
end
|
49
|
+
|
50
|
+
def transform_extracts(events=extract_blocks)
|
51
|
+
events.map {|event| CEF::Event.new(event) }
|
52
|
+
end
|
53
|
+
|
54
|
+
def poll_messages
|
55
|
+
transform_extracts(extract_blocks).each do |transformed_event|
|
56
|
+
cef.emit(transformed_event)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def request_message
|
61
|
+
full_results = Taxii::Messages::Parameters::Poll.new(response_type: 'FULL')
|
62
|
+
req = Taxii::Messages::PollRequest.new(collection_name: feed_name, poll_parameters: full_results)
|
63
|
+
req.to_xml
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
data/lib/oober/cli.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
def list_children(node)
|
2
|
+
puts 'Children: '
|
3
|
+
grouped = node.children.group_by {|n| name_of(n)}
|
4
|
+
puts grouped.map {|n,c| format('%s: %d',n,c.size) }.join(', ')
|
5
|
+
end
|
6
|
+
|
7
|
+
def name_of(node)
|
8
|
+
format('%s:%s',node.namespace.prefix, node.name)
|
9
|
+
end
|
10
|
+
|
11
|
+
module Oober
|
12
|
+
class Cli < Thor
|
13
|
+
class_option :config, default: File.join(ENV['HOME'],'.oober.json')
|
14
|
+
|
15
|
+
desc 'poll_feed', 'poll a feed/exporter configuration'
|
16
|
+
option :warn, type: :boolean, default: false
|
17
|
+
def poll_feed
|
18
|
+
oob=Oober.configure(options[:config])
|
19
|
+
errored_blocks = []
|
20
|
+
oob.extract_blocks.each do |extracted_hash|
|
21
|
+
begin
|
22
|
+
event = CEF::Event.new(extracted_hash)
|
23
|
+
oob.cef.emit(event)
|
24
|
+
rescue Exception => exception
|
25
|
+
if options[:warn]
|
26
|
+
errored_blocks.push([extracted_hash,exception])
|
27
|
+
end
|
28
|
+
else
|
29
|
+
puts event.to_cef
|
30
|
+
end
|
31
|
+
errored_blocks.each do |blk|
|
32
|
+
event, error = blk
|
33
|
+
STDERR.puts "ERROR: #{error.to_s}"
|
34
|
+
STDERR.puts "ERRORED MESSAGE: #{JSON.pretty_generate(event)}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
desc 'download_feed', 'download raw data for a feed/exporter config'
|
40
|
+
option :dir, default: 'tmp'
|
41
|
+
def download_feed
|
42
|
+
oob=Oober.configure(options[:config])
|
43
|
+
data_blocks = oob.get_blocks
|
44
|
+
data_blocks.each_with_index do |block,index|
|
45
|
+
filename = format('%s_%08d.%08d.xml',
|
46
|
+
oob.feed_name,
|
47
|
+
Time.new.to_i,
|
48
|
+
index)
|
49
|
+
file_path = File.join(options[:dir],filename)
|
50
|
+
FileUtils.mkdir_p(options[:dir]) unless Dir.exist?(options[:dir])
|
51
|
+
File.open(file_path, 'w') do |file|
|
52
|
+
file.puts(block)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
desc 'console', 'interactive pry session'
|
58
|
+
def console
|
59
|
+
if File.exist?(options[:config])
|
60
|
+
begin
|
61
|
+
client = Oober.configure(options[:config])
|
62
|
+
puts 'your oober client is in the local variable "client"'
|
63
|
+
rescue JSON::ParserError => e
|
64
|
+
puts "invalid config #{options[:config]}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
binding.pry
|
68
|
+
end
|
69
|
+
|
70
|
+
desc 'xpath FILE(s)', 'interactively test XPath queries against FILE(s)'
|
71
|
+
option :dir, default: 'tmp'
|
72
|
+
option :separator, type: :string, default: '----%s/%d----'
|
73
|
+
def xpath(*files)
|
74
|
+
xmls=files.map do |filename|
|
75
|
+
filedata = File.read(filename)
|
76
|
+
Nokogiri::XML(filedata,nil,nil,Nokogiri::XML::ParseOptions::DEFAULT_XML|Nokogiri::XML::ParseOptions::NOBLANKS)
|
77
|
+
end
|
78
|
+
|
79
|
+
file_xmls=Hash[files.zip(xmls)]
|
80
|
+
|
81
|
+
while query = Readline.readline(format('XPath Query[%d]> ',files.size), true)
|
82
|
+
if matched = query.match(%r{\A(children|save) (.*)})
|
83
|
+
cmd = matched[1]
|
84
|
+
query = matched[2]
|
85
|
+
else
|
86
|
+
q = query
|
87
|
+
cmd = nil
|
88
|
+
end
|
89
|
+
|
90
|
+
file_xmls.each do |filename, xml|
|
91
|
+
begin
|
92
|
+
[*xml.xpath(q)].each_with_index do |node,index|
|
93
|
+
puts format(options[:separator],filename,index)
|
94
|
+
case cmd
|
95
|
+
when nil
|
96
|
+
puts node.to_s
|
97
|
+
when /save/
|
98
|
+
fname = File.join(options[:dir],format('saved_%012d.xml',index))
|
99
|
+
File.open(fname,'w') {|f| f.puts node.children.first.to_s }
|
100
|
+
when /children/
|
101
|
+
list_children(node)
|
102
|
+
else
|
103
|
+
puts "unknown operation: #{cmd}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
rescue Nokogiri::XML::XPath::SyntaxError => e
|
107
|
+
#puts "could not get #{q}"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Oober
|
2
|
+
module Extractor
|
3
|
+
class Stix < Hashie::Dash
|
4
|
+
|
5
|
+
property :data
|
6
|
+
property :select, default: '/'
|
7
|
+
property :extractions, default: []
|
8
|
+
property :defaults, default: {}
|
9
|
+
property :description, default: ""
|
10
|
+
|
11
|
+
def xml
|
12
|
+
@xml ||= Nokogiri::XML(data,nil,nil,parse_options)
|
13
|
+
end
|
14
|
+
|
15
|
+
def selected
|
16
|
+
@selected ||= begin
|
17
|
+
xml.xpath(self.select).to_a
|
18
|
+
rescue Nokogiri::XML::XPath::SyntaxError => e
|
19
|
+
[]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse_options
|
24
|
+
@parse_options ||= Nokogiri::XML::ParseOptions::DEFAULT_XML|Nokogiri::XML::ParseOptions::NOBLANKS
|
25
|
+
end
|
26
|
+
|
27
|
+
def extract
|
28
|
+
selected.map {|node| extract_selection(node)}
|
29
|
+
end
|
30
|
+
|
31
|
+
def extract_selection(node)
|
32
|
+
mapped_values = extractions.map {|extraction| extract_value(extraction.merge(node: node)) }
|
33
|
+
Hash[*mapped_values.flatten].merge(defaults)
|
34
|
+
end
|
35
|
+
|
36
|
+
def extract_value(node: nil, origin: nil, target: nil)
|
37
|
+
target_key = target.to_sym
|
38
|
+
target_val = ''
|
39
|
+
begin
|
40
|
+
target_val = [*node.xpath(origin)].first.to_s.strip
|
41
|
+
rescue Exception => e
|
42
|
+
STDERR.puts "FAILED TO EXTRACT #{origin}"
|
43
|
+
STDERR.puts e.backtrace
|
44
|
+
STDERR.puts e
|
45
|
+
end
|
46
|
+
[target_key, target_val]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/oober.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'oober/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'oober'
|
8
|
+
spec.version = Oober::VERSION
|
9
|
+
spec.authors = ['Ryan Breed']
|
10
|
+
spec.email = ['opensource@breed.org']
|
11
|
+
|
12
|
+
spec.summary = %q{ simplified interface for polling TAXII services and exporting structured data }
|
13
|
+
spec.description = %q{ flexible TAXII client for integrating cyber threat information with all your stuff }
|
14
|
+
spec.homepage = 'https://github.com/ryanbreed/oober'
|
15
|
+
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = 'bin'
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ['lib']
|
21
|
+
|
22
|
+
spec.add_dependency 'hashie', '~> 3.4'
|
23
|
+
spec.add_dependency 'thor', '~> 0.19'
|
24
|
+
spec.add_dependency 'cef', '2.1.1.pre'
|
25
|
+
spec.add_dependency 'ruby-taxii', '0.3.1'
|
26
|
+
|
27
|
+
spec.add_development_dependency 'bundler', '~> 1.10'
|
28
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
29
|
+
spec.add_development_dependency 'rspec'
|
30
|
+
spec.add_development_dependency 'guard'
|
31
|
+
spec.add_development_dependency 'guard-bundler'
|
32
|
+
spec.add_development_dependency 'guard-rspec'
|
33
|
+
spec.add_development_dependency 'simplecov'
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
{
|
2
|
+
"feed_name" : "guest.MalwareDomainList_Hostlist",
|
3
|
+
"exporter" : "Oober::CefLogger",
|
4
|
+
"extractor" : "Oober::Extractor::Stix",
|
5
|
+
"export_config" : {
|
6
|
+
"type" : "CEF::Loggers::SyslogUdp",
|
7
|
+
"config" : {
|
8
|
+
"receiver" : "127.0.0.1",
|
9
|
+
"port" : 1999
|
10
|
+
}
|
11
|
+
},
|
12
|
+
"taxii_config" : {
|
13
|
+
"user" : "guest",
|
14
|
+
"pass" : "guest",
|
15
|
+
"url" : "http://hailataxii.com/taxii-discovery-service"
|
16
|
+
},
|
17
|
+
"extractor_configs" : [
|
18
|
+
{
|
19
|
+
"description" : "Malware Domain List IP Addresses",
|
20
|
+
"select" : "/stix:STIX_Package/stix:Observables/cybox:Observable/cybox:Object/cybox:Properties[@xsi:type=\"AddressObj:AddressObjectType\"][@category=\"ipv4-addr\"]",
|
21
|
+
"defaults" : {
|
22
|
+
"deviceCustomString1Label" : "TLP",
|
23
|
+
"deviceEventCategory" : "stix:Observables",
|
24
|
+
"deviceCustomString3Label" : "Obervable ID"
|
25
|
+
},
|
26
|
+
"extractions" : [
|
27
|
+
{
|
28
|
+
"origin" : "/stix:STIX_Package/stix:STIX_Header/stix:Handling/marking:Marking/marking:Marking_Structure[@xsi:type=\"tlpMarking:TLPMarkingStructureType\"]/@color",
|
29
|
+
"target" : "deviceCustomString1"
|
30
|
+
},
|
31
|
+
{
|
32
|
+
"origin" : "@xsi:type",
|
33
|
+
"target" : "deviceEventClassId"
|
34
|
+
},
|
35
|
+
{
|
36
|
+
"origin" : "@category",
|
37
|
+
"target" : "fileType"
|
38
|
+
},
|
39
|
+
{
|
40
|
+
"origin" : "../../cybox:Description/text()",
|
41
|
+
"target" : "message"
|
42
|
+
},
|
43
|
+
{
|
44
|
+
"origin" : "../../../cybox:Observable/@id",
|
45
|
+
"target" : "deviceCustomString3"
|
46
|
+
},
|
47
|
+
{
|
48
|
+
"origin" : "AddressObj:Address_Value/text()",
|
49
|
+
"target" : "sourceAddress"
|
50
|
+
}
|
51
|
+
]
|
52
|
+
},
|
53
|
+
{
|
54
|
+
"description" : "Malware Domain List URLs",
|
55
|
+
"select" : "/stix:STIX_Package/stix:Observables/cybox:Observable/cybox:Object/cybox:Properties[@xsi:type=\"URIObj:URIObjectType\"][@type=\"URL\"]/URIObj:Value[@condition=\"Equals\"]/..",
|
56
|
+
"defaults" : {
|
57
|
+
"deviceCustomString1Label" : "TLP",
|
58
|
+
"deviceEventCategory" : "stix:Observables",
|
59
|
+
"deviceCustomString3Label" : "Obervable ID"
|
60
|
+
},
|
61
|
+
"extractions" : [
|
62
|
+
{
|
63
|
+
"origin" : "/stix:STIX_Package/stix:STIX_Header/stix:Handling/marking:Marking/marking:Marking_Structure[@xsi:type=\"tlpMarking:TLPMarkingStructureType\"]/@color",
|
64
|
+
"target" : "deviceCustomString1"
|
65
|
+
},
|
66
|
+
{
|
67
|
+
"origin" : "@xsi:type",
|
68
|
+
"target" : "deviceEventClassId"
|
69
|
+
},
|
70
|
+
{
|
71
|
+
"origin" : "@type",
|
72
|
+
"target" : "fileType"
|
73
|
+
},
|
74
|
+
{
|
75
|
+
"origin" : "../../cybox:Description/text()",
|
76
|
+
"target" : "message"
|
77
|
+
},
|
78
|
+
{
|
79
|
+
"origin" : "../../../cybox:Observable/@id",
|
80
|
+
"target" : "deviceCustomString3"
|
81
|
+
},
|
82
|
+
{
|
83
|
+
"origin" : "URIObj:Value/text()",
|
84
|
+
"target" : "requestURL"
|
85
|
+
}
|
86
|
+
]
|
87
|
+
},
|
88
|
+
{
|
89
|
+
"description" : "Malware Domain List Domain Names",
|
90
|
+
"select" : "/stix:STIX_Package/stix:Observables/cybox:Observable/cybox:Object/cybox:Properties[@xsi:type=\"DomainNameObj:DomainNameObjectType\"]/DomainNameObj:Value[@condition=\"Equals\"]/..",
|
91
|
+
"defaults" : {
|
92
|
+
"deviceCustomString1Label" : "TLP",
|
93
|
+
"deviceCustomString3Label" : "Obervable ID",
|
94
|
+
"deviceEventCategory" : "stix:Observables",
|
95
|
+
"fileType" : "DNS Domain"
|
96
|
+
},
|
97
|
+
"extractions" : [
|
98
|
+
{
|
99
|
+
"origin" : "/stix:STIX_Package/stix:STIX_Header/stix:Handling/marking:Marking/marking:Marking_Structure[@xsi:type=\"tlpMarking:TLPMarkingStructureType\"]/@color",
|
100
|
+
"target" : "deviceCustomString1"
|
101
|
+
},
|
102
|
+
{
|
103
|
+
"origin" : "@xsi:type",
|
104
|
+
"target" : "deviceEventClassId"
|
105
|
+
},
|
106
|
+
{
|
107
|
+
"origin" : "../../cybox:Description/text()",
|
108
|
+
"target" : "message"
|
109
|
+
},
|
110
|
+
{
|
111
|
+
"origin" : "../../../cybox:Observable/@id",
|
112
|
+
"target" : "deviceCustomString3"
|
113
|
+
},
|
114
|
+
{
|
115
|
+
"origin" : "DomainNameObj:Value/text()",
|
116
|
+
"target" : "sourceDnsDomain"
|
117
|
+
}
|
118
|
+
]
|
119
|
+
},
|
120
|
+
{
|
121
|
+
"select" : "/stix:STIX_Package/stix:Indicators",
|
122
|
+
"defaults" : {
|
123
|
+
"deviceEventCategory" : "stix:Indicators",
|
124
|
+
"deviceCustomString1Label" : "TLP",
|
125
|
+
"deviceCustomString2Label" : "Indicated TTP",
|
126
|
+
"deviceCustomString3Label" : "Observable ID"
|
127
|
+
},
|
128
|
+
"extractions" : [
|
129
|
+
{
|
130
|
+
"origin" : "descendant::indicator:Producer/stixCommon:Identity/stixCommon:Name/text()",
|
131
|
+
"target" : "deviceProcessName"
|
132
|
+
},
|
133
|
+
{
|
134
|
+
"origin" : "/stix:STIX_Package/@id",
|
135
|
+
"target" : "devicePayloadId"
|
136
|
+
},
|
137
|
+
{
|
138
|
+
"origin" : "/stix:STIX_Package/stix:STIX_Header/stix:Handling/marking:Marking/marking:Marking_Structure[@xsi:type=\"tlpMarking:TLPMarkingStructureType\"]/@color",
|
139
|
+
"target" : "deviceCustomString1"
|
140
|
+
},
|
141
|
+
{
|
142
|
+
"origin" : "descendant::stixCommon:TTP[@xsi:type=\"ttp:TTPType\"]/@idref",
|
143
|
+
"target" : "deviceCustomString2"
|
144
|
+
},
|
145
|
+
{
|
146
|
+
"origin" : "descendant::indicator:Observable/@idref",
|
147
|
+
"target" : "deviceCustomString3"
|
148
|
+
},
|
149
|
+
{
|
150
|
+
"origin" : "/stix:STIX_Package/@timestamp",
|
151
|
+
"target" : "endTime"
|
152
|
+
},
|
153
|
+
{
|
154
|
+
"origin" : "descendant::stix:Indicator/@id",
|
155
|
+
"target" : "externalId"
|
156
|
+
},
|
157
|
+
{
|
158
|
+
"origin" : "descendant::indicator:Description/text()",
|
159
|
+
"target" : "message"
|
160
|
+
},
|
161
|
+
{
|
162
|
+
"origin" : "descendant::indicator:Title/text()",
|
163
|
+
"target" : "reason"
|
164
|
+
}
|
165
|
+
]
|
166
|
+
}
|
167
|
+
]
|
168
|
+
}
|
metadata
ADDED
@@ -0,0 +1,216 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: oober
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ryan Breed
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-10-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: hashie
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.4'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.4'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: thor
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.19'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.19'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: cef
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 2.1.1.pre
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.1.1.pre
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: ruby-taxii
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.3.1
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.3.1
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: bundler
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.10'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.10'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '10.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '10.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: guard
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: guard-bundler
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: guard-rspec
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: simplecov
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
description: " flexible TAXII client for integrating cyber threat information with
|
168
|
+
all your stuff "
|
169
|
+
email:
|
170
|
+
- opensource@breed.org
|
171
|
+
executables:
|
172
|
+
- oober
|
173
|
+
extensions: []
|
174
|
+
extra_rdoc_files: []
|
175
|
+
files:
|
176
|
+
- ".gitignore"
|
177
|
+
- ".rspec"
|
178
|
+
- ".travis.yml"
|
179
|
+
- Gemfile
|
180
|
+
- Guardfile
|
181
|
+
- README.md
|
182
|
+
- Rakefile
|
183
|
+
- bin/oober
|
184
|
+
- lib/oober.rb
|
185
|
+
- lib/oober/cef_logger.rb
|
186
|
+
- lib/oober/cli.rb
|
187
|
+
- lib/oober/extractor/stix.rb
|
188
|
+
- lib/oober/version.rb
|
189
|
+
- oober.gemspec
|
190
|
+
- samples/hail-a-taxii.json
|
191
|
+
- samples/logstash.conf
|
192
|
+
homepage: https://github.com/ryanbreed/oober
|
193
|
+
licenses: []
|
194
|
+
metadata: {}
|
195
|
+
post_install_message:
|
196
|
+
rdoc_options: []
|
197
|
+
require_paths:
|
198
|
+
- lib
|
199
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
200
|
+
requirements:
|
201
|
+
- - ">="
|
202
|
+
- !ruby/object:Gem::Version
|
203
|
+
version: '0'
|
204
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ">="
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '0'
|
209
|
+
requirements: []
|
210
|
+
rubyforge_project:
|
211
|
+
rubygems_version: 2.4.5.1
|
212
|
+
signing_key:
|
213
|
+
specification_version: 4
|
214
|
+
summary: simplified interface for polling TAXII services and exporting structured
|
215
|
+
data
|
216
|
+
test_files: []
|