logstash-input-sdee 0.6.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2e5c47c9f0d817a1e1d1fbb697e896ffc7fe0ef4
4
+ data.tar.gz: 6df5bb5d6942b4554216a032379a4ecf00989573
5
+ SHA512:
6
+ metadata.gz: 5ef8b0e84db55e36509d00af50cd6134b642ee4ee051c3a07f102cdf86af3dd74fcc217d5877e5451e6251b76a8e1ccb41d14135860955bd7c7fab174540f082
7
+ data.tar.gz: de12fddd14935ebd9b8e377cd64b605f544ec5b9f8dc354999d7414b1496e8c4a9f76c8116db1a00691723a6866629146d3b3b31c43a04c39e5b37665794488d
data/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ * 0.6.9
2
+ - making it ready for RubyGems
3
+ * 0.4.0
4
+ - msec timestamp precision
5
+ - SSL notes
6
+ - config example
7
+ - multiple hosts support
8
+ - tempfiles generated per host
9
+ * 0.3.0
10
+ - pre Alpha release
11
+ * 0.1.0
12
+ - Initial release
data/CONTRIBUTORS ADDED
@@ -0,0 +1,10 @@
1
+ The following is a list of people who have contributed ideas, code, bug
2
+ reports, or in general have helped logstash-input-sdee along its way.
3
+
4
+ Contributors:
5
+ * Me (roootik@gmail.com)
6
+
7
+ Note: If you've sent me patches, bug reports, or otherwise contributed to
8
+ logstash, and you aren't on the list above and want to be, please let me know
9
+ and I'll make sure you're here. Contributions from folks like you are what make
10
+ open source awesome.
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2014–2016 rootik <roootik@gmail.com>
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,190 @@
1
+ # Logstash Cisco SDEE/CIDEE input plugin
2
+
3
+ This plugin is based off [logstash-input-http_poller](https://github.com/logstash-plugins/logstash-input-http_poller) by @maximede.
4
+
5
+ This [Logstash](https://github.com/elasticsearch/logstash) input plugin allows you to call a Cisco SDEE/CIDEE HTTP API, decode the output of it into event(s), and send them on their merry way.
6
+
7
+ The idea behind this plugins came from a need to gather events from Cisco security devices and feed them to ELK stack.
8
+
9
+ This plugin is tested on:
10
+ * Hardware: Cisco ASA 5585-X IPS SSP-10
11
+ * IPS Version: 7.3(2)E4
12
+ * logstash 2.0.0-beta1
13
+ * Java JRE 1.8.0-60
14
+
15
+ It is fully free and fully open source. The license is Apache 2.0, meaning you are pretty much free to use it however you want in whatever way.
16
+
17
+ ## TODO
18
+ - Add request options like minThreatRating and maxThreatRating, virtualSensors, errorSeverities, includeStatusCategories, excludeStatusCategories and so on.
19
+ - Gather sensor status and health events
20
+
21
+ ## Config Example
22
+
23
+ For config examples see `sdee.conf` in `examples` in this repo.
24
+
25
+ ## SSL notes
26
+
27
+ You need to import host SSL certificate in Java trust store to be able to connect to Cisco IPS device.
28
+ I have had no luck with `truststore` nor `ssl_certificate_validation` configuration options with Java 1.8.0-60 like mentioned in [logstash-mixin-http_client](https://github.com/logstash-plugins/logstash-mixin-http_client) documentation,
29
+ so I'm using system trustStore - `$JAVA_HOME/lib/security/cacerts`. Note, default Java trustStore password is `changeit`.
30
+ Take the following steps:
31
+
32
+ * Get server certificate from IPS device:
33
+ ```sh
34
+ echo | openssl s_client -connect ciscoips:443 2>&1 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > cert.pem
35
+ ```
36
+
37
+ * Import it into Java cacerts:
38
+ ```sh
39
+ $JAVA_HOME/bin/keytool -keystore $JAVA_HOME/lib/security/cacerts -importcert -alias ciscoips -file cert.pem
40
+ ```
41
+
42
+ * Verify if import was successful:
43
+ ```sh
44
+ $JAVA_HOME/bin/keytool -keystore $JAVA_HOME/lib/security/cacerts -list
45
+ ```
46
+
47
+ * Modify your logstash input config for SSL connection:
48
+ ```ruby
49
+ input {
50
+ sdee {
51
+ interval => 60
52
+ http => {
53
+ truststore_password => "changeit"
54
+ url => "https://10.0.2.1"
55
+ auth => {
56
+ user => "cisco"
57
+ password => "p@ssw0rd"
58
+ }
59
+ }
60
+ }
61
+ }
62
+ ```
63
+
64
+ * Test logstash
65
+
66
+ ## Documentation
67
+
68
+ Logstash provides infrastructure to automatically generate documentation for this plugin. We use the asciidoc format to write documentation so any comments in the source code will be first converted into asciidoc and then into html. All plugin documentation are placed under one [central location](http://www.elasticsearch.org/guide/en/logstash/current/).
69
+
70
+ - For formatting code or config example, you can use the asciidoc `[source,ruby]` directive
71
+ - For more asciidoc formatting tips, see the excellent reference here https://github.com/elasticsearch/docs#asciidoc-guide
72
+
73
+ ## Need Help?
74
+
75
+ Need help? Try #logstash on freenode IRC or the https://discuss.elastic.co/c/logstash discussion forum.
76
+
77
+ ## Developing
78
+
79
+ ### 1. Plugin Developement and Testing
80
+
81
+ #### Code
82
+ - To get started, you'll need JRuby with the Bundler gem installed.
83
+
84
+ - Create a new plugin or clone and existing from the GitHub [logstash-plugins](https://github.com/logstash-plugins) organization. We also provide [example plugins](https://github.com/logstash-plugins?query=example).
85
+
86
+ - Install dependencies
87
+ ```sh
88
+ bundle install
89
+ ```
90
+
91
+ #### Test
92
+
93
+ - Update your dependencies
94
+
95
+ ```sh
96
+ bundle install
97
+ ```
98
+
99
+ - Run tests
100
+
101
+ ```sh
102
+ bundle exec rspec
103
+ ```
104
+
105
+ ### 2. Running your unpublished Plugin in Logstash
106
+
107
+ #### 2.1 Run in a local Logstash clone
108
+
109
+ - Edit Logstash `Gemfile` and add the local plugin path, for example:
110
+ ```ruby
111
+ gem "logstash-input-sdee", :path => "/your/local/logstash-input-sdee"
112
+ ```
113
+ - Install plugin
114
+ ```sh
115
+ bin/plugin install --no-verify
116
+ ```
117
+ - Run Logstash with your plugin
118
+ ```sh
119
+ bin/logstash -e 'input {sdee { interval => 60 http => { url => "http://ciscoips" auth => {user => "cisco" password => "p@ssw0rd"}} session_file => "/tmp/session.db" }}'
120
+ ```
121
+ At this point any modifications to the plugin code will be applied to this local Logstash setup. After modifying the plugin, simply rerun Logstash.
122
+
123
+ Enable signature 2000 (ICMP Echo Reply) on your Cisco IPS device and ping some host on a network, monitored by IPS.
124
+ You should see output like this:
125
+
126
+ ```ruby
127
+ {
128
+ "@timestamp" => "2015-09-21T12:21:26.000Z",
129
+ "timezone" => "EEST",
130
+ "tz_offset" => "180",
131
+ "event_id" => "6824288790867",
132
+ "severity" => "informational",
133
+ "vendor" => "Cisco",
134
+ "host_id" => "sensor1",
135
+ "app_name" => "sensorApp",
136
+ "app_instance_id" => "26957",
137
+ "description" => "ICMP Echo Reply",
138
+ "sig_id" => "2000",
139
+ "sig_version" => "S666",
140
+ "sig_type" => "other",
141
+ "sig_created" => "20001127",
142
+ "subsig_id" => "0",
143
+ "sig_details" => "ICMP Echo Reply",
144
+ "interface_group" => "vs0",
145
+ "vlan" => "0",
146
+ "attacker_addr" => "10.0.0.1",
147
+ "attacker_locality" => "OUT",
148
+ "target_addr" => "10.0.1.1",
149
+ "target_os_source" => "learned",
150
+ "target_os_type" => "windows-nt-2k-xp",
151
+ "target_os_relevance" => "relevant",
152
+ "alert_details" => "InterfaceAttributes: context='single_vf' physical='Unknown' backplane='PortChannel0/0' ; ",
153
+ "risk_rating" => "35",
154
+ "risk_target" => "medium",
155
+ "risk_attacker" => "relevant",
156
+ "threat_rating" => "35",
157
+ "interface" => "PortChannel0/0",
158
+ "host" => "10.0.2.1",
159
+ "tags" => "SDEE",
160
+ "message" => "IdsAlert: 'ICMP Echo Reply' Attacker: '10.0.0.1' Target: '10.0.1.1' SigId: '2000'",
161
+ "@version" => "1"
162
+ }
163
+ ```
164
+
165
+ #### 2.2 Run in an installed Logstash
166
+
167
+ You can use the same **2.1** method to run your plugin in an installed Logstash by editing its `Gemfile` and pointing the `:path` to your local plugin development directory or you can build the gem and install it using:
168
+
169
+ - Build your plugin gem
170
+ ```sh
171
+ gem build logstash-input-sdee.gemspec
172
+ ```
173
+ - Install the plugin from the Logstash home
174
+ ```sh
175
+ bin/plugin install /your/local/plugin/logstash-input-sdee.gem
176
+ ```
177
+ - Start Logstash and proceed to test the plugin
178
+
179
+ ## Contributing
180
+
181
+ All contributions are welcome: ideas, patches, documentation, bug reports, complaints, and even something you drew up on a napkin.
182
+
183
+ Programming is not a required skill. Whatever you've seen about open source and maintainers or community members saying "send patches or die" - you will not see that here.
184
+
185
+ It is more important to the community that you are able to contribute.
186
+
187
+ For more information about contributing, see the [CONTRIBUTING](https://github.com/elasticsearch/logstash/blob/master/CONTRIBUTING.md) file.
188
+
189
+ ## Reference
190
+ [Cisco Intrusion Detection Event Exchange (CIDEE) Specification](http://www.cisco.com/c/en/us/td/docs/security/ips/specs/CIDEE_Specification.html)
@@ -0,0 +1,79 @@
1
+ #== Cisco ASA ==
2
+ HOSTNAME \b(?:[_0-9A-Za-z][_0-9A-Za-z-]{0,62})(?:\.(?:[_0-9A-Za-z][_0-9A-Za-z-]{0,62}))*(\.?|\b)
3
+ CTIMESTAMP %{YEAR}-%{MONTHNUM2}-%{MONTHDAY}[T ]%{HOUR}:?%{MINUTE}(?::?%{SECOND})?%{ISO8601_TIMEZONE}?
4
+ CISCO_TAGGED %{CTIMESTAMP:ctimestamp}( %{SYSLOGHOST:sysloghost})? %{CISCO_TAG:ciscotag}:
5
+ CISCO_TAG %[A-Z0-9]+-%{INT:cisco_severity}-(?:[A-Z0-9_]+)|WLC[0-9]+
6
+ # Common Particles
7
+ CISCO_ASA_ACTION Built|Teardown|Deny|Denied|denied|requested|permitted|received|denied by ACL|discarded|est-allowed|Dropping|created|deleted|SENDING|RECEIVED|monitored|dropped
8
+ CISCO_ASA_REASON Duplicate TCP SYN|TCP Reset\-O|Failed to locate egress interface|Invalid transport field|No matching connection|DNS Response|DNS Query|(?:%{WORD}\s*)*
9
+ CISCO_ASA_DIRECTION Inbound|inbound|Outbound|outbound
10
+ CISCO_ASA_INTERVAL first hit|%{INT}-second interval
11
+ CISCO_ASA_XLATE_TYPE static|dynamic
12
+ # ASA-2-106001
13
+ CISCOASA106001 %{CISCO_ASA_DIRECTION:direction} %{WORD:protocol} connection %{CISCO_ASA_ACTION:action} from %{IP:src_ip}/%{INT:src_port} to %{IP:dst_ip}/%{INT:dst_port} flags %{GREEDYDATA:tcp_flags} on interface %{GREEDYDATA:interface}
14
+ # ASA-2-106006, ASA-2-106007, ASA-2-106010
15
+ CISCOASA106006_106007_106010 %{CISCO_ASA_ACTION:action} %{CISCO_ASA_DIRECTION:direction} %{WORD:protocol} (?:from|src) %{IP:src_ip}/%{INT:src_port}(\(%{DATA:src_fwuser}\))? (?:to|dst) %{IP:dst_ip}/%{INT:dst_port}(\(%{DATA:dst_fwuser}\))? (?:on interface %{DATA:interface}|due to %{CISCO_ASA_REASON:reason})
16
+ # ASA-3-106014
17
+ CISCOASA106014 %{CISCO_ASA_ACTION:action} %{CISCO_ASA_DIRECTION:direction} %{WORD:protocol} src %{DATA:src_interface}:%{IP:src_ip}(\(%{DATA:src_fwuser}\))? dst %{DATA:dst_interface}:%{IP:dst_ip}(\(%{DATA:dst_fwuser}\))? \(type %{INT:icmp_type}, code %{INT:icmp_code}\)
18
+ # ASA-6-106015
19
+ CISCOASA106015 %{CISCO_ASA_ACTION:action} %{WORD:protocol} \(%{DATA:policy_id}\) from %{IPORHOST:src_ip}/%{INT:src_port} to %{IPORHOST:dst_ip}/%{INT:dst_port} flags %{DATA:tcp_flags} on interface %{GREEDYDATA:interface}
20
+ # ASA-1-106021
21
+ CISCOASA106021 %{CISCO_ASA_ACTION:action} %{WORD:protocol} reverse path check from %{IP:src_ip} to %{IP:dst_ip} on interface %{GREEDYDATA:interface}
22
+ # ASA-4-106023
23
+ CISCOASA106023 %{CISCO_ASA_ACTION:action} %{WORD:protocol} src %{DATA:src_interface}:%{IPORHOST:src_ip}(/%{INT:src_port})?(\(%{DATA:src_fwuser}\))? dst %{DATA:dst_interface}:%{IPORHOST:dst_ip}(/%{INT:dst_port})?(\(%{DATA:dst_fwuser}\))?( \(type %{INT:icmp_type}, code %{INT:icmp_code}\))? by access-group %{DATA:policy_id} \[%{DATA:hashcode1}, %{DATA:hashcode2}\]
24
+ # ASA-5-106100
25
+ CISCOASA106100 access-list %{WORD:policy_id} %{CISCO_ASA_ACTION:action} %{WORD:protocol} %{DATA:src_interface}/%{IP:src_ip}\(%{INT:src_port}\)(\(%{DATA:src_fwuser}\))? -> %{DATA:dst_interface}/%{IP:dst_ip}\(%{INT:dst_port}\)(\(%{DATA:src_fwuser}\))? hit-cnt %{INT:hit_count} %{CISCO_ASA_INTERVAL:interval} \[%{DATA:hashcode1}, %{DATA:hashcode2}\]
26
+ # ASA-6-110002
27
+ CISCOASA110002 %{CISCO_ASA_REASON:reason} for %{WORD:protocol} from %{DATA:src_interface}:%{IPORHOST:src_ip}/%{INT:src_port} to %{IP:dst_ip}/%{INT:dst_port}
28
+ # ASA-5-111008
29
+ CISCOASA111008 User \'%{DATA:src_fwuser}\' executed the \'%{GREEDYDATA:cmd}\' command\.
30
+ # ASA-7-111009
31
+ CISCOASA111009 User \'%{DATA:src_fwuser}\' executed cmd: %{GREEDYDATA:cmd}
32
+ # ASA-5-111010
33
+ CISCOASA111010 User \'%{DATA:src_fwuser}\', running \'CLI\' from IP %{IPORHOST:src_ip}, executed \'%{GREEDYDATA:cmd}\'
34
+ # ASA-6-302010
35
+ CISCOASA302010 %{INT:connection_count} in use, %{INT:connection_count_max} most used
36
+ # ASA-6-302013, ASA-6-302014, ASA-6-302015, ASA-6-302016
37
+ CISCOASA302013_302014_302015_302016 %{CISCO_ASA_ACTION:action}(?: %{CISCO_ASA_DIRECTION:direction})? %{WORD:protocol} connection %{INT:connection_id} for %{DATA:src_interface}:%{IPORHOST:src_ip}/%{INT:src_port}( \(%{IPORHOST:src_mapped_ip}/%{INT:src_mapped_port}\))?(\(%{DATA:src_fwuser}\))? to %{DATA:dst_interface}:%{IPORHOST:dst_ip}/%{INT:dst_port}( \(%{IPORHOST:dst_mapped_ip}/%{INT:dst_mapped_port}\))?(\(%{DATA:dst_fwuser}\))?( duration %{TIME:duration} bytes %{INT:bytes})?(?: %{CISCO_ASA_REASON:reason})?( \(%{DATA:user}\))?
38
+ # ASA-6-302020, ASA-6-302021
39
+ CISCOASA302020_302021 %{CISCO_ASA_ACTION:action}(?: %{CISCO_ASA_DIRECTION:direction})? %{WORD:protocol} connection for faddr %{IPORHOST:dst_ip}/%{INT:icmp_seq_num}(?:\(%{DATA:fwuser}\))? gaddr %{IPORHOST:src_xlated_ip}/%{INT:icmp_code_xlated} laddr %{IPORHOST:src_ip}/%{INT:icmp_code}( \(%{DATA:user}\))?
40
+ # ASA-3-305006
41
+ CISCOASA305006 regular translation creation failed for %{WORD:protocol} src %{DATA:src_interface}:%{IPORHOST:src_ip}(/%{INT:src_port})? dst %{DATA:dst_interface}:%{IPORHOST:dst_ip}(/%{INT:dst_port})?(?: \(type %{INT:icmp_type}, code %{INT:icmp_code}\))?
42
+ # ASA-6-305011
43
+ CISCOASA305011 %{CISCO_ASA_ACTION:action} %{CISCO_ASA_XLATE_TYPE:xlate_type} %{WORD:protocol} translation from %{DATA:src_interface}:%{IPORHOST:src_ip}(/%{INT:src_port})?(\(%{DATA:src_fwuser}\))? to %{DATA:src_xlated_interface}:%{IPORHOST:src_xlated_ip}/%{DATA:src_xlated_port}
44
+ # ASA-5-305013
45
+ CISCOASA305013 Asymmetric NAT rules matched for forward and reverse flows; Connection for %{WORD:protocol} src %{DATA:src_interface}:%{IPORHOST:src_ip}(/%{INT:src_port})? dst %{DATA:dst_interface}:%{IPORHOST:dst_ip}(/%{INT:dst_port})? %{CISCO_ASA_ACTION:action} due to NAT reverse path failure
46
+ # ASA-3-313001, ASA-3-313004, ASA-3-313008
47
+ CISCOASA313001_313004_313008 %{CISCO_ASA_ACTION:action} %{WORD:protocol} type=%{INT:icmp_type}, code=%{INT:icmp_code} from %{IP:src_ip} on interface %{DATA:interface}( to %{IP:dst_ip})?
48
+ # ASA-4-313005
49
+ CISCOASA313005 %{CISCO_ASA_REASON:reason} for %{WORD:protocol} error message: %{WORD:err_protocol} src %{DATA:err_src_interface}:%{IPORHOST:err_src_ip}(\(%{DATA:err_src_fwuser}\))? dst %{DATA:err_dst_interface}:%{IPORHOST:err_dst_ip}(\(%{DATA:err_dst_fwuser}\))? \(type %{INT:err_icmp_type}, code %{INT:err_icmp_code}\) on %{DATA:interface} interface\. Original IP payload: %{WORD:protocol} src %{IPORHOST:orig_src_ip}/%{INT:orig_src_port}(\(%{DATA:orig_src_fwuser}\))? dst %{IPORHOST:orig_dst_ip}/%{INT:orig_dst_port}(\(%{DATA:orig_dst_fwuser}\))?
50
+ # ASA-4-338004, ASA-4-338008
51
+ CISCOASA338004_338008 Dynamic Filter %{CISCO_ASA_ACTION:action} blacklisted %{WORD:protocol} traffic from %{DATA:src_interface}:%{IPORHOST:src_ip}(/%{INT:src_port})?( \(%{IPORHOST:src_mapped_ip}/%{INT:src_mapped_port}\))? to %{DATA:dst_interface}:%{IPORHOST:dst_ip}(/%{INT:dst_port})?( \(%{IPORHOST:dst_mapped_ip}/%{INT:dst_mapped_port}\))?, destination %{IPORHOST:blacklisted_ip} resolved from local list: %{IPORHOST:blacklisted_ip}/%{IPORHOST:blacklisted_netmask}, threat-level: %{DATA:threat_level}, category: %{DATA:category}
52
+ # ASA-4-338008 Dynamic Filter %{CISCO_ASA_ACTION:action} blacklisted %{WORD:protocol} traffic from %{DATA:src_interface}:%{IPORHOST:src_ip}(/%{INT:src_port})?( \(%{IPORHOST:src_mapped_ip}/%{INT:src_mapped_port}\))? to %{DATA:dst_interface}:%{IPORHOST:dst_ip}(/%{INT:dst_port})?( \(%{IPORHOST:dst_mapped_ip}/%{INT:dst_mapped_port}\))?, destination %{IPORHOST:blacklisted_ip} resolved from local list: 221.204.186.0/255.255.255.0, threat-level: very-high, category: admin-added
53
+ # ASA-4-402117
54
+ CISCOASA402117 %{WORD:protocol}: Received a non-IPSec packet \(protocol= %{WORD:orig_protocol}\) from %{IP:src_ip} to %{IP:dst_ip}
55
+ # ASA-4-402119
56
+ CISCOASA402119 %{WORD:protocol}: Received an %{WORD:orig_protocol} packet \(SPI= %{DATA:spi}, sequence number= %{DATA:seq_num}\) from %{IP:src_ip} \(user= %{DATA:user}\) to %{IP:dst_ip} that failed anti-replay checking
57
+ # ASA-4-419001
58
+ CISCOASA419001 %{CISCO_ASA_ACTION:action} %{WORD:protocol} packet from %{DATA:src_interface}:%{IP:src_ip}/%{INT:src_port} to %{DATA:dst_interface}:%{IP:dst_ip}/%{INT:dst_port}, reason: %{GREEDYDATA:reason}
59
+ # ASA-4-419002
60
+ CISCOASA419002 %{CISCO_ASA_REASON:reason} from %{DATA:src_interface}:%{IPORHOST:src_ip}/%{INT:src_port} to %{DATA:dst_interface}:%{IPORHOST:dst_ip}/%{INT:dst_port} with different initial sequence number
61
+ # ASA-4-500004
62
+ CISCOASA500004 %{CISCO_ASA_REASON:reason} for protocol=%{WORD:protocol}, from %{IP:src_ip}/%{INT:src_port} to %{IP:dst_ip}/%{INT:dst_port}
63
+ # ASA-6-602303, ASA-6-602304
64
+ CISCOASA602303_602304 %{WORD:protocol}: An %{CISCO_ASA_DIRECTION:direction} %{GREEDYDATA:tunnel_type} SA \(SPI= %{DATA:spi}\) between %{IP:src_ip} and %{IP:dst_ip} \(user= %{DATA:user}\) has been %{CISCO_ASA_ACTION:action}
65
+ # ASA-7-609001, ASA-7-609002
66
+ CISCOASA609001_609002 %{CISCO_ASA_ACTION:action} local-host %{DATA:src_interface}:%{IPORHOST:src_ip}(?: duration %{TIME:duration})?
67
+ # ASA-7-710001, ASA-7-710002, ASA-7-710003, ASA-7-710005, ASA-7-710006
68
+ CISCOASA710001_710002_710003_710005_710006_710007 %{WORD:protocol} (?:request|access|keepalive) %{CISCO_ASA_ACTION:action} from %{IPORHOST:src_ip}/%{INT:src_port} to %{DATA:dst_interface}:%{IPORHOST:dst_ip}/%{DATA:dst_port}
69
+ # ASA-6-713172
70
+ CISCOASA713172 Group = %{GREEDYDATA:group}, IP = %{IP:src_ip}, Automatic NAT Detection Status:\s+Remote end\s*%{DATA:is_remote_natted}\s*behind a NAT device\s+This\s+end\s*%{DATA:is_local_natted}\s*behind a NAT device
71
+ # ASA-7-713236
72
+ CISCOASA713236 IP = %{IPORHOST:src_ip}, IKE_DECODE %{CISCO_ASA_ACTION} Message \(msgid=%{DATA:msgid}\) with payloads : %{GREEDYDATA:payload} total length : %{INT:length}
73
+ # ASA-7-713906
74
+ CISCOASA713906 IKE Receiver: Packet received on %{IPORHOST:dst_ip}:%{INT:dst_port} from %{IPORHOST:src_ip}:%{INT:src_port}
75
+ # ASA-7-715046
76
+ CISCOASA715036_715046_715047_715075 Group = %{GREEDYDATA:group},(?: Username = %{DATA:src_fwuser},)? IP = %{IP:src_ip},%{GREEDYDATA:vpn_action}
77
+ # ASA-4-733100
78
+ CISCOASA733100 \[\s*%{DATA:drop_type}\s*\] drop %{DATA:drop_rate_id} exceeded. Current burst rate is %{INT:drop_rate_current_burst} per second, max configured rate is %{INT:drop_rate_max_burst}; Current average rate is %{INT:drop_rate_current_avg} per second, max configured rate is %{INT:drop_rate_max_avg}; Cumulative total count is %{INT:drop_total_count}
79
+ #== End Cisco ASA ==
@@ -0,0 +1,35 @@
1
+ input {
2
+
3
+ sdee {
4
+ type => "sdee"
5
+ interval => 60
6
+ http => {
7
+ url => "http://ciscoips1"
8
+ auth => {
9
+ user => "cisco"
10
+ password => "p@ssw0rd"
11
+ }
12
+ }
13
+ }
14
+
15
+ sdee {
16
+ type => "sdee"
17
+ interval => 60
18
+ http => {
19
+ url => "https://ciscoips2"
20
+ # do not forget, you must add your device or CA certificate to Java trustStore. See README.md
21
+ truststore_password => "changeit"
22
+ auth => {
23
+ user => "cisco"
24
+ password => "p@ssw0rd"
25
+ }
26
+ }
27
+ }
28
+
29
+ }
30
+
31
+ output {
32
+ stdout {
33
+ codec => rubydebug
34
+ }
35
+ }
@@ -0,0 +1,354 @@
1
+ # encoding: utf-8
2
+ require "logstash/inputs/base"
3
+ require "logstash/namespace"
4
+ require "logstash/plugin_mixins/http_client"
5
+
6
+ require "yaml"
7
+ require "uri"
8
+ require "pathname"
9
+ require "time"
10
+ require "rexml/document"
11
+ require "socket" # for Socket.gethostname
12
+ require "manticore"
13
+ include REXML
14
+
15
+ class LogStash::Inputs::SDEE < LogStash::Inputs::Base
16
+ include LogStash::PluginMixins::HttpClient
17
+
18
+ config_name "sdee"
19
+ # Do we really need a codec?
20
+ # default :codec, "plain"
21
+
22
+ # A Hash of urls in this format : "name" => "url"
23
+ # The name and the url will be passed in the outputed event
24
+ #
25
+ config :http, :validate => :hash, :required => true
26
+
27
+ # How often (in seconds) the urls will be called
28
+ config :interval, :validate => :number, :required => true
29
+
30
+ # If you'd like to work with the request/response metadata
31
+ # Set this value to the name of the field you'd like to store a nested
32
+ # hash of metadata.
33
+ config :metadata_target, :validate => :string, :default => '@metadata'
34
+ #, :default => '@metadata'
35
+
36
+ # A path to store tempfile with SDEE SubscriptionID and SessionID
37
+ config :session_path, :validate => :string, :default => '/tmp'
38
+
39
+ public
40
+ def register
41
+ @host = Socket.gethostname.force_encoding(Encoding::UTF_8)
42
+ @session_file = Pathname.new(@session_path) + "temp#{URI.parse(@http["url"]).host}.db"
43
+ @remaining = 0
44
+ setup_request!(@http)
45
+
46
+ @logger.info("Registering SDEE Input", :type => @type,
47
+ :http => @http, :interval => @interval, :timeout => @timeout)
48
+
49
+ #subscribe to SDEE and store session data
50
+ @session = subscribe(@request)
51
+
52
+ newurl = URI.join(@http["url"], "cgi-bin/sdee-server?subscriptionId=#{@session[:subscriptionid]}&confirm=yes&maxNbrOfEvents=150&timeout=5&sessionId=#{@session[:sessionid]}")
53
+
54
+ @request[1] = newurl.to_s
55
+ rescue StandardError, java.lang.Exception => e
56
+ @logger.error? && @logger.error("SDEE subscription error!",
57
+ :exception => e,
58
+ :exception_message => e.message,
59
+ :exeption_backtrace => e.backtrace
60
+ )
61
+
62
+ end
63
+
64
+ private
65
+ def subscribe(request)
66
+ # recover from ungraceful shutdown first
67
+ if @session_file.exist?
68
+ yaml = YAML.load_file(@session_file)
69
+ if (defined?(yaml) && yaml != nil)
70
+ unsubscribe(request,yaml)
71
+ end
72
+ end
73
+
74
+ url = URI.join(@http["url"], "cgi-bin/sdee-server?action=open&evIdsAlert&force=yes")
75
+ request[1] = url.to_s
76
+ session = Hash.new
77
+ method, *request_opts = request
78
+ client.async.send(method, *request_opts).
79
+ on_success {|response| session = handle_subscription(request, response)}.
80
+ on_failure {|exception| http_error(request, exception)}
81
+ client.execute!
82
+ raise LogStash::ConfigurationError, "SDEE subscription Error! Check your configuration for host url,user,password." unless session
83
+ session
84
+ end
85
+
86
+ private
87
+ def handle_subscription(request, response)
88
+ body = response.body
89
+ xml = REXML::Document.new body.to_s
90
+ session = Hash.new
91
+ sessionid = REXML::XPath.first(xml, "//sd:sessionId")
92
+ subscriptionid = REXML::XPath.first(xml, "//sd:subscriptionId")
93
+ session[:sessionid] = sessionid.text if sessionid
94
+ session[:subscriptionid] = subscriptionid.text if subscriptionid
95
+ File.open(@session_file, 'w') {|f| f.write session.to_yaml}
96
+ session
97
+ end
98
+
99
+ private
100
+ def http_error(request, exeption)
101
+ @logger.error? && @logger.error("Cannot read URL or send the error as an event! Check your configuration for host url,user,password.",
102
+ :request => structure_request(request),
103
+ :exception => exeption.to_s,
104
+ :exception_backtrace => exeption.backtrace
105
+ )
106
+ end
107
+
108
+ private
109
+ def unsubscribe(request,session)
110
+ #unsubscribe and remove session data file
111
+ url = URI.join(@http["url"], "cgi-bin/sdee-server?action=close&subscriptionId=#{session[:subscriptionid]}&sessionId=#{session[:sessionid]}")
112
+ request[1] = url.to_s
113
+ method, *request_opts = request
114
+ client.async.send(method, *request_opts).
115
+ on_success {|response| remove_session}.
116
+ on_failure {|exception| http_error(request, exception)}
117
+ client.execute!
118
+ end
119
+
120
+ private
121
+ def remove_session
122
+ if @session_file.exist?
123
+ @session_file.unlink
124
+ end
125
+ end
126
+
127
+ private
128
+ def setup_request!(http)
129
+ @request = normalize_request(http)
130
+ end
131
+
132
+ private
133
+ def normalize_request(http)
134
+ if http.is_a?(Hash)
135
+ # The client will expect keys / values
136
+ spec = Hash[http.clone.map {|k,v| [k.to_sym, v] }] # symbolize keys
137
+
138
+ # method and url aren't really part of the options, so we pull them out
139
+ method = (spec.delete(:method) || :get).to_sym.downcase
140
+ url = spec.delete(:url)
141
+
142
+ # We need these strings to be keywords!
143
+ spec[:auth] = {user: spec[:auth]["user"], pass: spec[:auth]["password"]} if spec[:auth]
144
+ res = [method, url, spec]
145
+ else
146
+ raise LogStash::ConfigurationError, "Invalid request spec: '#{http}', expected a Hash!"
147
+ end
148
+
149
+ validate_request!(http, res)
150
+ res
151
+ end
152
+
153
+ private
154
+ def validate_request!(http, request)
155
+ method, url, spec = request
156
+
157
+ raise LogStash::ConfigurationError, "No URL provided for request! #{http}" unless url
158
+ if spec && spec[:auth]
159
+ if !spec[:auth][:user]
160
+ raise LogStash::ConfigurationError, "Auth was specified, but 'user' was not!"
161
+ end
162
+ if !spec[:auth][:pass]
163
+ raise LogStash::ConfigurationError, "Auth was specified, but 'password' was not!"
164
+ end
165
+ end
166
+
167
+ request
168
+ end
169
+
170
+ public
171
+ def run(queue)
172
+ while true
173
+ begin
174
+ Stud.interval(@interval) do
175
+ begin
176
+ run_once(queue)
177
+ end while (@remaining > 0)
178
+ end
179
+ rescue EOFError, LogStash::ShutdownSignal
180
+ break
181
+ end
182
+ end
183
+ end
184
+
185
+ public
186
+ def teardown
187
+ @logger.debug? && @logger.debug("SDEE shutting down")
188
+ unsubscribe(@request,@session) rescue nil
189
+ finished
190
+ end # def teardown
191
+
192
+ private
193
+ def run_once(queue)
194
+ request_async(queue, @request)
195
+ client.execute!
196
+ end
197
+
198
+ private
199
+ def request_async(queue, request)
200
+ @logger.debug? && @logger.debug("Fetching URL", :url => request)
201
+ started = Time.now
202
+
203
+ method, *request_opts = request
204
+ client.async.send(method, *request_opts).
205
+ on_success {|response| handle_success(queue, request, response, Time.now - started)}.
206
+ on_failure {|exception| handle_failure(queue, request, exception, Time.now - started)
207
+ }
208
+ end
209
+
210
+ private
211
+ def handle_success(queue, request, response, execution_time)
212
+ decode(response.body).each_pair do |id,decoded|
213
+ event = LogStash::Event.new(decoded)
214
+ handle_decoded_event(queue, request, response, event, execution_time)
215
+ end
216
+ end
217
+
218
+ private
219
+ def handle_decoded_event(queue, request, response, event, execution_time)
220
+ apply_metadata(event, request, response, execution_time) if @metadata_target
221
+ decorate(event)
222
+ queue << event
223
+ rescue StandardError, java.lang.Exception => e
224
+ @logger.error? && @logger.error("Error eventifying response!",
225
+ :exception => e,
226
+ :exception_message => e.message,
227
+ :exeption_backtrace => e.backtrace,
228
+ :url => request,
229
+ :response => response
230
+ )
231
+ end
232
+
233
+ private
234
+ # Beware, on old versions of manticore some uncommon failures are not handled
235
+ def handle_failure(queue, request, exception, execution_time)
236
+ event = LogStash::Event.new
237
+ apply_metadata(event, request)
238
+
239
+ event.tag("_sdee_failure")
240
+
241
+ # This is also in the metadata, but we send it anyone because we want this
242
+ # persisted by default, whereas metadata isn't. People don't like mysterious errors
243
+ event["sdee_failure"] = {
244
+ "request" => structure_request(request),
245
+ "error" => exception.to_s,
246
+ "backtrace" => exception.backtrace,
247
+ "runtime_seconds" => execution_time
248
+ }
249
+
250
+ queue << event
251
+ rescue StandardError, java.lang.Exception => e
252
+ @logger.error? && @logger.error("Cannot read URL or send the error as an event!",
253
+ :exception => e,
254
+ :exception_message => e.message,
255
+ :exception_backtrace => e.backtrace,
256
+ :url => request
257
+ )
258
+ end
259
+
260
+ private
261
+ def apply_metadata(event, request, response=nil, execution_time=nil)
262
+ #return unless @metadata_target
263
+ event[@metadata_target] = event_metadata(request, response, execution_time)
264
+ end
265
+
266
+ private
267
+ def event_metadata(request, response=nil, execution_time=nil)
268
+ m = {
269
+ "host" => @host,
270
+ "request" => structure_request(request),
271
+ }
272
+
273
+ m["runtime_seconds"] = execution_time
274
+
275
+ if response
276
+ m["code"] = response.code
277
+ m["response_headers"] = response.headers
278
+ m["response_message"] = response.message
279
+ m["times_retried"] = response.times_retried
280
+ end
281
+ m
282
+ end
283
+
284
+ private
285
+ # Turn [method, url, spec] requests into a hash for friendlier logging / ES indexing
286
+ def structure_request(request)
287
+ method, url, spec = request
288
+ # Flatten everything into the 'spec' hash, also stringify any keys to normalize
289
+ Hash[(spec||{}).merge({
290
+ "method" => method.to_s,
291
+ "url" => url,
292
+ }).map {|k,v| [k.to_s,v] }]
293
+ end
294
+
295
+ private
296
+ def decode(body)
297
+ events = Hash.new
298
+ xml = REXML::Document.new body.to_s
299
+ err = REXML::XPath.first(xml, "//env:Reason") if REXML::XPath.first(xml, "//env:Fault")
300
+ err = err.text.to_s if err
301
+ if err && err == "Subscription does not exist"
302
+ subscribe(@request)
303
+ end
304
+ rem = REXML::XPath.first(xml, "//sd:remaining-events")
305
+ @remaining = rem.text.to_i if rem
306
+ # We use own XML parsing to keep things simple to the user
307
+ xml.elements.each("*/env:Body/sd:events/sd:evIdsAlert") do |element|
308
+ eid = element.attributes["eventId"]
309
+ # Get timestamp in nsec from sensor
310
+ timestamp=REXML::XPath.first(element,"./sd:time").text.to_i(10)
311
+ events[eid] = {
312
+ "@timestamp" => Time.at(timestamp/10**9,((timestamp%10**9)/1000).to_f).iso8601(3),
313
+ "timezone" => REXML::XPath.first(element,"./sd:time").attributes["timeZone"],
314
+ "tz_offset" => REXML::XPath.first(element,"./sd:time").attributes["offset"],
315
+ "event_id" => eid.to_s,
316
+ "severity" => element.attributes["severity"].to_s.capitalize,
317
+ "vendor" => element.attributes["vendor"].to_s,
318
+ "host_id" => REXML::XPath.first(element,"./sd:originator/sd:hostId").text,
319
+ "app_name" => REXML::XPath.first(element,"./sd:originator/cid:appName").text,
320
+ "app_instance_id" => REXML::XPath.first(element,"./sd:originator/cid:appInstanceId").text,
321
+ "description" => REXML::XPath.first(element,"./sd:signature").attributes["description"],
322
+ "sig_id" => REXML::XPath.first(element,"./sd:signature").attributes["id"],
323
+ "sig_version" => REXML::XPath.first(element,"./sd:signature").attributes["cid:version"],
324
+ "sig_type" => REXML::XPath.first(element,"./sd:signature").attributes["cid:type"],
325
+ "sig_created" => REXML::XPath.first(element,"./sd:signature").attributes["created"],
326
+ "subsig_id" => REXML::XPath.first(element,"./sd:signature/cid:subsigId").text,
327
+ "sig_details" => REXML::XPath.first(element,"./sd:signature/cid:sigDetails").text,
328
+ "interface_group" => REXML::XPath.first(element,"./sd:interfaceGroup").text,
329
+ "vlan" => REXML::XPath.first(element,"./sd:vlan").text,
330
+ "attacker_addr" => REXML::XPath.first(element,"./sd:participants/sd:attacker/sd:addr").text,
331
+ "attacker_locality" => REXML::XPath.first(element,"./sd:participants/sd:attacker/sd:addr").attributes["locality"],
332
+ "target_addr" => REXML::XPath.first(element,"./sd:participants/sd:target/sd:addr").text,
333
+ "targed_locality" => REXML::XPath.first(element,"./sd:participants/sd:target/sd:addr").attributes["locality"],
334
+ "target_os_source" => REXML::XPath.first(element,"./sd:participants/sd:target/cid:os").attributes["idSource"],
335
+ "target_os_type" => REXML::XPath.first(element,"./sd:participants/sd:target/cid:os").attributes["type"],
336
+ "target_os_relevance" => REXML::XPath.first(element,"./sd:participants/sd:target/cid:os").attributes["relevance"],
337
+ # Need? to parse <cid:summary cid:final='true' cid:initialAlert='6824288769384' cid:summaryType='Regular'>2</cid:summary>
338
+ "alert_details" => REXML::XPath.first(element,"./cid:alertDetails").text.tr('\\"', '\''),
339
+ "risk_rating" => REXML::XPath.first(element,"./cid:riskRatingValue").text,
340
+ "risk_target" => REXML::XPath.first(element,"./cid:riskRatingValue").attributes["targetValueRating"],
341
+ "risk_attacker" => REXML::XPath.first(element,"./cid:riskRatingValue").attributes["attackRelevanceRating"],
342
+ "threat_rating" => REXML::XPath.first(element,"./cid:threatRatingValue").text,
343
+ "interface" => REXML::XPath.first(element,"./cid:interface").text,
344
+ "host" => URI.parse(@http["url"]).host,
345
+ "device" => "IPS",
346
+ "tags" => "SDEE"
347
+ }
348
+ events[eid].merge!({"attacker_port" => REXML::XPath.first(element,"./sd:participants/sd:attacker/sd:port").text}) if REXML::XPath.first(element,"./sd:participants/sd:attacker/sd:port")
349
+ events[eid].merge!({"target_port" => REXML::XPath.first(element,"./sd:participants/sd:target/sd:port").text}) if REXML::XPath.first(element,"./sd:participants/sd:target/sd:port")
350
+ events[eid].merge!({"message" => "IdsAlert: '#{events[eid]["description"]}' Attacker: '#{events[eid]["attacker_addr"]}' Target: '#{events[eid]["target_addr"]}' SigId: '#{events[eid]["sig_id"]}'"})
351
+ end
352
+ events
353
+ end
354
+ end
@@ -0,0 +1,21 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'logstash-input-sdee'
3
+ s.version = '0.6.9'
4
+ s.date = '2016-08-14'
5
+ s.summary = "Logstah SDEE input from Cisco ASA"
6
+ s.description = "This Logstash input plugin allows you to call a Cisco SDEE/CIDEE HTTP API, decode the output of it into event(s), and send them on their merry way."
7
+ s.authors = ["rootik"]
8
+ s.email = 'roootik@gmail.com'
9
+ s.require_paths = ['lib']
10
+
11
+ s.files = Dir['lib/**/*', 'examples/**/*', '*.gemspec', 'LICENSE', 'Gemfile', 'README.md', 'CHANGELOG.md', 'CONTRIBUTORS']
12
+ s.homepage =
13
+ 'http://rubygems.org/gems/logstash-input-sdee'
14
+ s.metadata = { "logstash_plugin" => "true", "logstash_group" => "input" }
15
+ s.license = 'Apache-2.0'
16
+ s.metadata = { "logstash_plugin" => "true", "logstash_group" => "input" }
17
+ s.add_runtime_dependency 'logstash-core', '>= 1.4.0', '<= 2.99'
18
+ s.add_runtime_dependency 'logstash-core-plugin-api', '>= 0.60', '<= 2.99'
19
+ s.add_runtime_dependency 'logstash-mixin-http_client', '>= 1.0.0', '<= 6.0.0'
20
+ s.add_runtime_dependency 'rubysl-rexml', '>= 2.0.0', '<= 3.0.0'
21
+ end
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: logstash-input-sdee
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.9
5
+ platform: ruby
6
+ authors:
7
+ - rootik
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-08-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: logstash-core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.4.0
20
+ - - <=
21
+ - !ruby/object:Gem::Version
22
+ version: '2.99'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.4.0
30
+ - - <=
31
+ - !ruby/object:Gem::Version
32
+ version: '2.99'
33
+ - !ruby/object:Gem::Dependency
34
+ name: logstash-core-plugin-api
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - '>='
38
+ - !ruby/object:Gem::Version
39
+ version: '0.60'
40
+ - - <=
41
+ - !ruby/object:Gem::Version
42
+ version: '2.99'
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - '>='
48
+ - !ruby/object:Gem::Version
49
+ version: '0.60'
50
+ - - <=
51
+ - !ruby/object:Gem::Version
52
+ version: '2.99'
53
+ - !ruby/object:Gem::Dependency
54
+ name: logstash-mixin-http_client
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - '>='
58
+ - !ruby/object:Gem::Version
59
+ version: 1.0.0
60
+ - - <=
61
+ - !ruby/object:Gem::Version
62
+ version: 6.0.0
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - '>='
68
+ - !ruby/object:Gem::Version
69
+ version: 1.0.0
70
+ - - <=
71
+ - !ruby/object:Gem::Version
72
+ version: 6.0.0
73
+ - !ruby/object:Gem::Dependency
74
+ name: rubysl-rexml
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - '>='
78
+ - !ruby/object:Gem::Version
79
+ version: 2.0.0
80
+ - - <=
81
+ - !ruby/object:Gem::Version
82
+ version: 3.0.0
83
+ type: :runtime
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: 2.0.0
90
+ - - <=
91
+ - !ruby/object:Gem::Version
92
+ version: 3.0.0
93
+ description: This Logstash input plugin allows you to call a Cisco SDEE/CIDEE HTTP
94
+ API, decode the output of it into event(s), and send them on their merry way.
95
+ email: roootik@gmail.com
96
+ executables: []
97
+ extensions: []
98
+ extra_rdoc_files: []
99
+ files:
100
+ - CHANGELOG.md
101
+ - CONTRIBUTORS
102
+ - Gemfile
103
+ - LICENSE
104
+ - README.md
105
+ - examples/patterns/cisco
106
+ - examples/sdee.conf
107
+ - lib/logstash/inputs/sdee.rb
108
+ - logstash-input-sdee.gemspec
109
+ homepage: http://rubygems.org/gems/logstash-input-sdee
110
+ licenses:
111
+ - Apache-2.0
112
+ metadata:
113
+ logstash_plugin: 'true'
114
+ logstash_group: input
115
+ post_install_message:
116
+ rdoc_options: []
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - '>='
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - '>='
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubyforge_project:
131
+ rubygems_version: 2.6.6
132
+ signing_key:
133
+ specification_version: 4
134
+ summary: Logstah SDEE input from Cisco ASA
135
+ test_files: []