RubyIOC 0.0.1 → 0.0.2
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.
- data/.gitignore +19 -19
- data/Gemfile +3 -3
- data/Rakefile +7 -7
- data/RubyIOC.gemspec +24 -24
- data/iocaware.iocterms +12 -0
- data/lib/RubyIOC.rb +38 -38
- data/lib/RubyIOC/iocitem/arp_entry_item.rb +86 -1
- data/lib/RubyIOC/iocitem/dns_entry_item.rb +47 -11
- data/lib/RubyIOC/iocitem/event_log_item.rb +49 -0
- data/lib/RubyIOC/iocitem/port_item.rb +117 -0
- data/lib/RubyIOC/iocitem/service_item.rb +100 -0
- data/lib/RubyIOC/iocitem/user_item.rb +1 -1
- data/lib/RubyIOC/iocitem/volume_item.rb +65 -0
- data/lib/RubyIOC/platform.rb +2 -2
- data/lib/RubyIOC/scanner.rb +15 -28
- data/lib/RubyIOC/version.rb +15 -15
- data/test/test_arp_entry_item.ioc +57 -0
- data/test/test_dns_entry_item.ioc +26 -5
- data/test/test_event_log_item.ioc +55 -0
- data/test/test_port_item.ioc +51 -0
- data/test/test_scan.rb +29 -4
- data/test/test_service_item.ioc +143 -0
- data/test/test_user_item.ioc +9 -8
- data/test/test_volume_item.ioc +63 -0
- metadata +16 -5
data/.gitignore
CHANGED
@@ -1,20 +1,20 @@
|
|
1
|
-
*.gem
|
2
|
-
.bundle
|
3
|
-
Gemfile.lock
|
4
|
-
pkg/*
|
5
|
-
*.rbc
|
6
|
-
.config
|
7
|
-
coverage
|
8
|
-
InstalledFiles
|
9
|
-
lib/bundler/man
|
10
|
-
pkg
|
11
|
-
rdoc
|
12
|
-
spec/reports
|
13
|
-
test/tmp
|
14
|
-
test/version_tmp
|
15
|
-
tmp
|
16
|
-
|
17
|
-
# YARD artifacts
|
18
|
-
.yardoc
|
19
|
-
_yardoc
|
1
|
+
*.gem
|
2
|
+
.bundle
|
3
|
+
Gemfile.lock
|
4
|
+
pkg/*
|
5
|
+
*.rbc
|
6
|
+
.config
|
7
|
+
coverage
|
8
|
+
InstalledFiles
|
9
|
+
lib/bundler/man
|
10
|
+
pkg
|
11
|
+
rdoc
|
12
|
+
spec/reports
|
13
|
+
test/tmp
|
14
|
+
test/version_tmp
|
15
|
+
tmp
|
16
|
+
|
17
|
+
# YARD artifacts
|
18
|
+
.yardoc
|
19
|
+
_yardoc
|
20
20
|
doc/
|
data/Gemfile
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
source "http://rubygems.org"
|
2
|
-
# Specify your gem's dependencies in RubyIOC.gemspec
|
3
|
-
gemspec
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Specify your gem's dependencies in RubyIOC.gemspec
|
3
|
+
gemspec
|
data/Rakefile
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
require "bundler/gem_tasks"
|
2
|
-
require "rake/testtask"
|
3
|
-
|
4
|
-
Rake::TestTask.new do |t|
|
5
|
-
t.libs << "test"
|
6
|
-
t.test_files = FileList['test/test*.rb']
|
7
|
-
t.verbose = false
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rake/testtask"
|
3
|
+
|
4
|
+
Rake::TestTask.new do |t|
|
5
|
+
t.libs << "test"
|
6
|
+
t.test_files = FileList['test/test*.rb']
|
7
|
+
t.verbose = false
|
8
8
|
end
|
data/RubyIOC.gemspec
CHANGED
@@ -1,24 +1,24 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
|
-
$:.push File.expand_path("../lib", __FILE__)
|
3
|
-
require "RubyIOC/version"
|
4
|
-
|
5
|
-
Gem::Specification.new do |s|
|
6
|
-
s.name = "RubyIOC"
|
7
|
-
s.version = RubyIOC::VERSION
|
8
|
-
s.authors = ["Matt Jezorek"]
|
9
|
-
s.email = ["mjezorek@gmail.com"]
|
10
|
-
s.homepage = ""
|
11
|
-
s.summary = %q{RubyIOC is a ruby library used for indicators of compromise}
|
12
|
-
s.description = %q{RubyIOC is a ruby library used for indicators of compromise}
|
13
|
-
|
14
|
-
s.rubyforge_project = "RubyIOC"
|
15
|
-
|
16
|
-
s.files = `git ls-files`.split("\n")
|
17
|
-
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
-
s.require_paths = ["lib"]
|
20
|
-
|
21
|
-
# specify any dependencies here; for example:
|
22
|
-
# s.add_development_dependency "rspec"
|
23
|
-
s.add_runtime_dependency "roxml"
|
24
|
-
end
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "RubyIOC/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "RubyIOC"
|
7
|
+
s.version = RubyIOC::VERSION
|
8
|
+
s.authors = ["Matt Jezorek"]
|
9
|
+
s.email = ["mjezorek@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{RubyIOC is a ruby library used for indicators of compromise}
|
12
|
+
s.description = %q{RubyIOC is a ruby library used for indicators of compromise}
|
13
|
+
|
14
|
+
s.rubyforge_project = "RubyIOC"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
s.add_runtime_dependency "roxml"
|
24
|
+
end
|
data/iocaware.iocterms
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
<?xml version="1.0" encoding="us-ascii"?>
|
2
|
+
<ioctermlist xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" last-modified="2013-07-15T21:26:28" description="New IOC Terms File" xmlns="http://schemas.mandiant.com/2010/ioc">
|
3
|
+
<iocterm text="FileItem/Md54ksum" title="File MD54K" data-type="MD5Sum" display-type="md5" term-source="application/iocaware" />
|
4
|
+
<iocterm text="FileItem/Ssdeep" title="File SSDeep" data-type="xs:string" display-type="string" term-source="application/iocaware" />
|
5
|
+
<iocterm text="FileItem/Sha512sum" title="File Sha512sum" data-type="HashSum" display-type="string" term-source="application/iocaware" />
|
6
|
+
<iocterm text="ServiceItem/pathMd54ksum" title="Service Path MD54K" data-type="MD5Sum" display-type="md5" term-source="application/iocaware" />
|
7
|
+
<iocterm text="ServiceItem/pathSsdeep" title="Service Path SSDeep" data-type="xs:string" display-type="string" term-source="application/iocaware" />
|
8
|
+
<iocterm text="ServiceItem/pathSha512sum" title="Service Path Sha512Sum" data-type="HashSum" display-type="string" term-source="application/iocaware" />
|
9
|
+
<iocterm text="ServiceItem/serviceDLLMd54Ksum" title="Service DLL MD54K" data-type="MD5Sum" display-type="md5" term-source="application/iocaware" />
|
10
|
+
<iocterm text="ServiceItem/serviceDLLSsdeep" title="Service DLL SSDeep" data-type="xs:string" display-type="string" term-source="application/iocaware" />
|
11
|
+
<iocterm text="ServiceItem/serviceDLLSha512Sum" title="Service DLL Sha512Sum" data-type="HashSum" display-type="string" term-source="application/iocaware" />
|
12
|
+
</ioctermlist>
|
data/lib/RubyIOC.rb
CHANGED
@@ -1,39 +1,39 @@
|
|
1
|
-
# Copyright (c) 2013 Matt Jezorek
|
2
|
-
#
|
3
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
4
|
-
# to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
5
|
-
# and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
6
|
-
#
|
7
|
-
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
8
|
-
#
|
9
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
10
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
11
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
12
|
-
# IN THE SOFTWARE.
|
13
|
-
require "rexml/document"
|
14
|
-
|
15
|
-
require "RubyIOC/version"
|
16
|
-
require "RubyIOC/platform"
|
17
|
-
require "RubyIOC/iocterm"
|
18
|
-
require "RubyIOC/iocitem"
|
19
|
-
require "RubyIOC/ioc"
|
20
|
-
require "RubyIOC/scanner"
|
21
|
-
|
22
|
-
=begin rdoc
|
23
|
-
RubyIOC is a simple gem that will allow the scanning of a system with indicators of compromise. RubyIOC will not tell you if the machine
|
24
|
-
is compromised or not but it will give you a score and what indicators have been found. Ideally you will want to see 0% and 0 found indicators.
|
25
|
-
However you may come back with 1% ond 2 indicators out of 200. It will also provide you a reference to the found indicators. From here you
|
26
|
-
can investigate whatever machine you wish to investigate.
|
27
|
-
|
28
|
-
Please note that when you use this software you are running on possibly compromised machiens, any credentials you use to facilitate the scan
|
29
|
-
should be considered compromised
|
30
|
-
=end
|
31
|
-
|
32
|
-
|
33
|
-
class String
|
34
|
-
def to_bool
|
35
|
-
return true if self == true || self =~ (/(true|t|yes|y|1)$/i)
|
36
|
-
return false if self == false || self.blank? || self =~ (/(false|f|no|n|0)$/i)
|
37
|
-
raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
|
38
|
-
end
|
1
|
+
# Copyright (c) 2013 Matt Jezorek
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
4
|
+
# to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
5
|
+
# and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
6
|
+
#
|
7
|
+
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
8
|
+
#
|
9
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
10
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
11
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
12
|
+
# IN THE SOFTWARE.
|
13
|
+
require "rexml/document"
|
14
|
+
|
15
|
+
require "RubyIOC/version"
|
16
|
+
require "RubyIOC/platform"
|
17
|
+
require "RubyIOC/iocterm"
|
18
|
+
require "RubyIOC/iocitem"
|
19
|
+
require "RubyIOC/ioc"
|
20
|
+
require "RubyIOC/scanner"
|
21
|
+
|
22
|
+
=begin rdoc
|
23
|
+
RubyIOC is a simple gem that will allow the scanning of a system with indicators of compromise. RubyIOC will not tell you if the machine
|
24
|
+
is compromised or not but it will give you a score and what indicators have been found. Ideally you will want to see 0% and 0 found indicators.
|
25
|
+
However you may come back with 1% ond 2 indicators out of 200. It will also provide you a reference to the found indicators. From here you
|
26
|
+
can investigate whatever machine you wish to investigate.
|
27
|
+
|
28
|
+
Please note that when you use this software you are running on possibly compromised machiens, any credentials you use to facilitate the scan
|
29
|
+
should be considered compromised
|
30
|
+
=end
|
31
|
+
|
32
|
+
|
33
|
+
class String
|
34
|
+
def to_bool
|
35
|
+
return true if self == true || self =~ (/(true|t|yes|y|1)$/i)
|
36
|
+
return false if self == false || self.blank? || self =~ (/(false|f|no|n|0)$/i)
|
37
|
+
raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
|
38
|
+
end
|
39
39
|
end
|
@@ -16,6 +16,89 @@ module RubyIOC
|
|
16
16
|
def get_type
|
17
17
|
"ArpEntryItem"
|
18
18
|
end
|
19
|
+
|
20
|
+
def scan(indicator)
|
21
|
+
if RubyIOC::Platform.windows?
|
22
|
+
return search_windows_arp(indicator)
|
23
|
+
elseif Ruby::Platform::mac?
|
24
|
+
return search_mac_arp(indicator)
|
25
|
+
else
|
26
|
+
puts "Not implemented on this platform yet"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def search_windows_arp(indicator)
|
31
|
+
arp = get_arp_cache
|
32
|
+
|
33
|
+
arp.each_line do |line|
|
34
|
+
indicator.each { |i|
|
35
|
+
content = i[:content]
|
36
|
+
|
37
|
+
case i[:search]
|
38
|
+
when "ArpEntryItem/PhysicalAddress", "ArpEntryItem/CacheType", "ArpEntryItem/IPv4Address"
|
39
|
+
if !(line.downcase.include? "interface") && (line.downcase.gsub("-", ":").include? content.downcase)
|
40
|
+
return true
|
41
|
+
end
|
42
|
+
when "ArpEntryItem/Interface"
|
43
|
+
if (line.downcase.include? "interface") && (line.downcase.include? content.downcase)
|
44
|
+
return true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
}
|
48
|
+
end
|
49
|
+
#puts arp
|
50
|
+
#puts arp.to_yaml
|
51
|
+
return false
|
52
|
+
end
|
53
|
+
|
54
|
+
def search_mac_arp(indicator)
|
55
|
+
arp = get_arp_cache
|
56
|
+
arp.each_line do |line|
|
57
|
+
fields = line.split(' ')
|
58
|
+
ip = fields[1].gsub('(', '').gsub(')', '')
|
59
|
+
physical = fields[3].downcase
|
60
|
+
iface = fields[5].downcase
|
61
|
+
|
62
|
+
indicator.each { |i|
|
63
|
+
content = i[:content].downcase
|
64
|
+
|
65
|
+
case i[:search]
|
66
|
+
when "ArpEntryItem/PhysicalAddress"
|
67
|
+
octets = physical.split(':')
|
68
|
+
i = 0
|
69
|
+
while i < octets.length do
|
70
|
+
if octets[i].length == 1 then
|
71
|
+
octets[i] = '0' + octets[i]
|
72
|
+
end
|
73
|
+
i += 1
|
74
|
+
end
|
75
|
+
physical = octets.join(':')
|
76
|
+
|
77
|
+
if physical == content then
|
78
|
+
return true
|
79
|
+
end
|
80
|
+
when "ArpEntryItem/CacheType"
|
81
|
+
when "ArpEntryItem/IPv4Address"
|
82
|
+
if ip == content then
|
83
|
+
return true
|
84
|
+
end
|
85
|
+
when "ArpEntryItem/Interface"
|
86
|
+
if iface == content then
|
87
|
+
return true
|
88
|
+
end
|
89
|
+
end
|
90
|
+
}
|
91
|
+
end
|
92
|
+
#puts arp
|
93
|
+
#puts arp.to_yaml
|
94
|
+
return false
|
95
|
+
end
|
96
|
+
|
97
|
+
def get_arp_cache
|
98
|
+
arp_cache =`arp -a`
|
99
|
+
|
100
|
+
return arp_cache
|
101
|
+
end
|
19
102
|
end
|
20
103
|
|
21
104
|
class ArpEntryItemFactory < RubyIOC::IOCItem::IOCItemFactory
|
@@ -30,4 +113,6 @@ module RubyIOC
|
|
30
113
|
|
31
114
|
ArpEntryItemFactory.add_factory(ArpEntryItemFactory)
|
32
115
|
end
|
33
|
-
end
|
116
|
+
end
|
117
|
+
|
118
|
+
|
@@ -26,18 +26,16 @@ module RubyIOC
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def search_windows_dns(indicator)
|
29
|
-
|
30
|
-
|
31
|
-
return false
|
32
|
-
end
|
33
|
-
|
34
|
-
def get_windows_dns_cache
|
35
|
-
dns = []
|
36
|
-
dns_cache =`ipconfig /displaydns`
|
29
|
+
dns_cache = get_windows_dns_cache
|
30
|
+
|
37
31
|
blocks = dns_cache.split(/\n\n/)
|
32
|
+
|
38
33
|
blocks.each do | block |
|
39
|
-
|
34
|
+
noblanklines = block.gsub(/^$\n/, '').downcase
|
35
|
+
host = noblanklines.lines.first
|
36
|
+
|
40
37
|
temp = {}
|
38
|
+
temp[:host] = host
|
41
39
|
temp[:record_name] = block.match(/\s*Record Name.*:\s(?<record>.*)/).to_a[1]
|
42
40
|
temp[:record_type] = block.match(/\s*Record Type.*:\s(?<record>.*)/).to_a[1]
|
43
41
|
temp[:time_to_live] = block.match(/\s*Time To Live.*:\s(?<record>.*)/).to_a[1]
|
@@ -45,9 +43,47 @@ module RubyIOC
|
|
45
43
|
temp[:section] = block.match(/\s*Section.*:\s(?<record>.*)/).to_a[1]
|
46
44
|
temp[:a_record] = block.match(/\s*A \(Host\) Record.*:\s(?<record>.*)/).to_a[1]
|
47
45
|
temp[:cname] = block.match(/\s*CNAME Record.*:\s(?<record>.*)/).to_a[1]
|
48
|
-
|
46
|
+
#puts temp
|
47
|
+
indicator.each { |i|
|
48
|
+
content = i[:content].downcase
|
49
|
+
|
50
|
+
case i[:search]
|
51
|
+
when "DnsEntryItem/Host"
|
52
|
+
if !temp[:host].nil? and temp[:host].downcase.strip == content then
|
53
|
+
return true
|
54
|
+
end
|
55
|
+
when "DnsEntryItem/RecordName"
|
56
|
+
if !temp[:record_name].nil? and temp[:record_name].downcase.strip == content then
|
57
|
+
return true
|
58
|
+
end
|
59
|
+
when "DnsEntryItem/RecordType"
|
60
|
+
if !temp[:record_type].nil? and temp[:record_type].downcase.strip == content then
|
61
|
+
return true
|
62
|
+
end
|
63
|
+
when "DnsEntryItem/TimeToLive"
|
64
|
+
if !temp[:time_to_live].nil? and temp[:time_to_live].downcase.strip == content then
|
65
|
+
return true
|
66
|
+
end
|
67
|
+
when "DnsEntryItem/Flags"
|
68
|
+
when "DnsEntryItem/DataLength"
|
69
|
+
if !temp[:data_length].nil? and temp[:data_length].downcase.strip == content then
|
70
|
+
return true
|
71
|
+
end
|
72
|
+
when "DnsEntryItem/RecordData/Host"
|
73
|
+
when "DnsEntryItem/RecordData/IPv4Address"
|
74
|
+
if !temp[:a_record].nil? and temp[:a_record].downcase.strip == content then
|
75
|
+
return true
|
76
|
+
end
|
77
|
+
end
|
78
|
+
}
|
49
79
|
end
|
50
|
-
|
80
|
+
|
81
|
+
return false
|
82
|
+
end
|
83
|
+
|
84
|
+
def get_windows_dns_cache
|
85
|
+
dns_cache =`ipconfig /displaydns`
|
86
|
+
return dns_cache
|
51
87
|
end
|
52
88
|
end
|
53
89
|
|
@@ -10,12 +10,61 @@
|
|
10
10
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
11
11
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
12
12
|
# IN THE SOFTWARE.
|
13
|
+
|
14
|
+
if RubyIOC::Platform.windows?
|
15
|
+
require "win32ole"
|
16
|
+
end
|
17
|
+
|
13
18
|
module RubyIOC
|
14
19
|
module IOCItem
|
15
20
|
class EventLogItem < RubyIOC::IOCTerm
|
16
21
|
def get_type
|
17
22
|
"EventLogItem"
|
18
23
|
end
|
24
|
+
|
25
|
+
def scan(indicator)
|
26
|
+
if RubyIOC::Platform.windows?
|
27
|
+
return search_windows_events(indicator)
|
28
|
+
else
|
29
|
+
puts "Not implemented on this platform yet"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def search_windows_events(indicator)
|
34
|
+
wmi = WIN32OLE.connect("winmgmts:{impersonationLevel=impersonate,(Security)}!\\")
|
35
|
+
query = "Select * from Win32_NTLogEvent where "
|
36
|
+
|
37
|
+
indicator.each { |i|
|
38
|
+
case i[:search]
|
39
|
+
when "EventLogItem/category"
|
40
|
+
query += "CategoryString = '#{i[:content]}' "
|
41
|
+
when "EventLogItem/categoryNum"
|
42
|
+
query += "Category = #{i[:content]} "
|
43
|
+
when "EventLogItem/genTime"
|
44
|
+
when "EventLogItem/EID"
|
45
|
+
query += "EventIdentifier = #{i[:content]} "
|
46
|
+
when "EventLogItem/log"
|
47
|
+
query += "LogFile = '#{i[:content]}' "
|
48
|
+
when "EventLogItem/machine"
|
49
|
+
query += "ComputerName = '#{i[:content]}' "
|
50
|
+
when "EventLogItem/message"
|
51
|
+
query += "Message like '%#{i[:content]}%' "
|
52
|
+
when "EventLogItem/source"
|
53
|
+
query += "SourceName = '#{i[:content]}' "
|
54
|
+
when "EventLogItem/type"
|
55
|
+
query += "Type = '#{i[:content]}' "
|
56
|
+
when "EventLogItem/user"
|
57
|
+
query += "User like '%#{i[:content]}%' "
|
58
|
+
when "EventLogItem/writeTime"
|
59
|
+
end
|
60
|
+
}
|
61
|
+
|
62
|
+
events = wmi.ExecQuery(query)
|
63
|
+
events.each { |e|
|
64
|
+
return true
|
65
|
+
}
|
66
|
+
return false
|
67
|
+
end
|
19
68
|
end
|
20
69
|
|
21
70
|
class EventLogItemFactory < RubyIOC::IOCItem::IOCItemFactory
|
@@ -16,6 +16,123 @@ module RubyIOC
|
|
16
16
|
def get_type
|
17
17
|
"PortItem"
|
18
18
|
end
|
19
|
+
|
20
|
+
def scan(indicator)
|
21
|
+
if RubyIOC::Platform.windows?
|
22
|
+
return search_windows_netstat(indicator)
|
23
|
+
else
|
24
|
+
puts "Not implemented on this platform yet"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def search_windows_netstat(indicator)
|
29
|
+
netstat = get_windows_netstat
|
30
|
+
|
31
|
+
blocks = netstat.split(/\n/)
|
32
|
+
i = 1
|
33
|
+
|
34
|
+
entries = []
|
35
|
+
entry = ""
|
36
|
+
blocks.each do | block |
|
37
|
+
if i<5 then
|
38
|
+
i+=1
|
39
|
+
next
|
40
|
+
end
|
41
|
+
|
42
|
+
line = block.strip.gsub(/[ ]{2,}/, " ")
|
43
|
+
localip = ""
|
44
|
+
localport = ""
|
45
|
+
pid = ""
|
46
|
+
process = ""
|
47
|
+
protocol = ""
|
48
|
+
remoteip = ""
|
49
|
+
remoteport = ""
|
50
|
+
state = ""
|
51
|
+
|
52
|
+
if line.match(/^TCP/) or line.match(/^UDP/) then
|
53
|
+
nsentry = line.downcase.split(' ')
|
54
|
+
protocol = nsentry[0]
|
55
|
+
if nsentry[1].match(/\[/) then
|
56
|
+
localip = nsentry[1].split(']:')[0].gsub(/\[/, '')
|
57
|
+
localport = nsentry[1].split(']:')[1]
|
58
|
+
else
|
59
|
+
localip = nsentry[1].split(':')[0]
|
60
|
+
localport = nsentry[1].split(':')[1]
|
61
|
+
end
|
62
|
+
if nsentry[2].match(/\[/) then
|
63
|
+
remoteip = nsentry[2].split(']:')[0].gsub(/\[/, '')
|
64
|
+
remoteport = nsentry[2].split(']:')[1]
|
65
|
+
else
|
66
|
+
remoteip = nsentry[2].split(':')[0]
|
67
|
+
remoteport = nsentry[2].split(':')[1]
|
68
|
+
end
|
69
|
+
if nsentry.length < 5 then
|
70
|
+
pid = nsentry[3]
|
71
|
+
else
|
72
|
+
state = nsentry[3]
|
73
|
+
pid = nsentry[4]
|
74
|
+
end
|
75
|
+
|
76
|
+
indicator.each { |i|
|
77
|
+
content = i[:content].downcase
|
78
|
+
|
79
|
+
case i[:search]
|
80
|
+
when "PortItem/CreationTime"
|
81
|
+
when "PortItem/localIP"
|
82
|
+
if content == localip then
|
83
|
+
return true
|
84
|
+
end
|
85
|
+
when "PortItem/localPort"
|
86
|
+
if content == localport then
|
87
|
+
return true
|
88
|
+
end
|
89
|
+
when "PortItem/path"
|
90
|
+
when "PortItem/pid"
|
91
|
+
if content == pid then
|
92
|
+
return true
|
93
|
+
end
|
94
|
+
when "PortItem/protocol"
|
95
|
+
if content == protocol then
|
96
|
+
return true
|
97
|
+
end
|
98
|
+
when "PortItem/remoteIP"
|
99
|
+
if content == remoteip then
|
100
|
+
return true
|
101
|
+
end
|
102
|
+
when "PortItem/remotePort"
|
103
|
+
if content == remoteport then
|
104
|
+
return true
|
105
|
+
end
|
106
|
+
when "PortItem/state"
|
107
|
+
if content == state then
|
108
|
+
return true
|
109
|
+
end
|
110
|
+
end
|
111
|
+
}
|
112
|
+
else
|
113
|
+
if line.match(/^\[/)
|
114
|
+
process = line.downcase.gsub("[", "").gsub("]", "")
|
115
|
+
|
116
|
+
indicator.each { |i|
|
117
|
+
content = i[:content].downcase
|
118
|
+
case i[:search]
|
119
|
+
when "PortItem/process"
|
120
|
+
if content == process then
|
121
|
+
return true
|
122
|
+
end
|
123
|
+
end
|
124
|
+
}
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
return false
|
130
|
+
end
|
131
|
+
|
132
|
+
def get_windows_netstat
|
133
|
+
netstat = `netstat -anbo`
|
134
|
+
return netstat
|
135
|
+
end
|
19
136
|
end
|
20
137
|
|
21
138
|
class PortItemFactory < RubyIOC::IOCItem::IOCItemFactory
|