nexpose 0.1.13 → 0.1.14

Sign up to get free protection for your applications and to get access to all the features.
@@ -72,6 +72,7 @@ require 'nexpose/connection'
72
72
  require 'nexpose/role'
73
73
  require 'nexpose/common'
74
74
  require 'nexpose/group'
75
+ require 'nexpose/alert'
75
76
 
76
77
  module Nexpose
77
78
 
@@ -0,0 +1,239 @@
1
+ module Nexpose
2
+
3
+ # Alert parent object.
4
+ # The three alert types should be wrapped in this object to store data.
5
+ #
6
+ class Alert
7
+
8
+ # Name for this alert.
9
+ attr_accessor :name
10
+
11
+ # Whether or not this alert is currently active.
12
+ attr_accessor :enabled
13
+
14
+ # Send at most this many alerts per scan.
15
+ attr_accessor :max_alerts
16
+
17
+ # Send alerts based upon scan status.
18
+ attr_accessor :scan_filter
19
+
20
+ # Send alerts based upon vulnerability finding status.
21
+ attr_accessor :vuln_filter
22
+
23
+ # Alert type and its configuration. One of SMTPAlert, SyslogAlert, SNMPAlert
24
+ attr_accessor :alert
25
+
26
+ def initialize(name, enabled = 1, max_alerts = -1)
27
+ @name, @enabled, @max_alerts = name, enabled, max_alerts
28
+ end
29
+
30
+ def to_xml
31
+ xml = '<Alert'
32
+ xml << %Q( name="#{@name}")
33
+ xml << %Q( enabled="#{@enabled}")
34
+ xml << %Q( maxAlerts="#{@max_alerts}")
35
+ xml << '>'
36
+ xml << scan_filter.to_xml
37
+ xml << vuln_filter.to_xml
38
+ xml << alert.to_xml
39
+ xml << '</Alert>'
40
+ end
41
+
42
+ # Parse a response from a Nexpose console into a valid Alert object.
43
+ #
44
+ # @param [REXML::Document] rexml XML document to parse.
45
+ # @return [Alert] Alert object represented by the XML.
46
+ #
47
+ def self.parse(rexml)
48
+ name = rexml.attributes['name']
49
+ rexml.elements.each("//Alert[@name='#{name}']") do |xml|
50
+ alert = new(name,
51
+ xml.attributes['enabled'].to_i,
52
+ xml.attributes['maxAlerts'].to_i)
53
+ alert.scan_filter = ScanFilter.parse(REXML::XPath.first(xml, "//Alert[@name='#{name}']/scanFilter"))
54
+ alert.vuln_filter = VulnFilter.parse(REXML::XPath.first(xml, "//Alert[@name='#{name}']/vulnFilter"))
55
+ if (type = REXML::XPath.first(xml, "//Alert[@name='#{name}']/smtpAlert"))
56
+ alert.alert = SMTPAlert.parse(type)
57
+ elsif (type = REXML::XPath.first(xml, "//Alert[@name='#{name}']/syslogAlert"))
58
+ alert.alert = SyslogAlert.parse(type)
59
+ elsif (type = REXML::XPath.first(xml, "//Alert[@name='#{name}']/snmpAlert"))
60
+ alert.alert = SNMPAlert.parse(type)
61
+ end
62
+ return alert
63
+ end
64
+ nil
65
+ end
66
+ end
67
+
68
+ # Scan filter for alerting.
69
+ # Set values to 1 to enable and 0 to disable.
70
+ #
71
+ class ScanFilter
72
+ # Scan events to alert on.
73
+ attr_accessor :start, :stop, :fail, :resume, :pause
74
+
75
+ def initialize(start = 0, stop = 0, fail = 0, resume = 0, pause = 0)
76
+ @start, @stop, @fail, @resume, @pause = start, stop, fail, resume, pause
77
+ end
78
+
79
+ def to_xml
80
+ xml = '<scanFilter'
81
+ xml << %Q( scanStart="#{@start}")
82
+ xml << %Q( scanStop="#{@stop}")
83
+ xml << %Q( scanFailed="#{@fail}")
84
+ xml << %Q( scanResumed="#{@resume}")
85
+ xml << %Q( scanPaused="#{@pause}")
86
+ xml << '/>'
87
+ end
88
+
89
+ def self.parse(xml)
90
+ new(xml.attributes['scanStart'].to_i,
91
+ xml.attributes['scanStop'].to_i,
92
+ xml.attributes['scanFailed'].to_i,
93
+ xml.attributes['scanResumed'].to_i,
94
+ xml.attributes['scanPaused'].to_i)
95
+ end
96
+ end
97
+
98
+ # Vulnerability filtering for alerting.
99
+ # Set values to 1 to enable and 0 to disable.
100
+ #
101
+ class VulnFilter
102
+ # Only alert on vulnerability findings with a severity level greater than this level.
103
+ # Range is 0 to 10.
104
+ # Values in the UI correspond as follows:
105
+ # Any severity: 1
106
+ # Severe and critical: 4
107
+ # Only critical: 8
108
+ attr_accessor :severity
109
+
110
+ # Vulnerability events to alert on.
111
+ attr_accessor :confirmed, :unconfirmed, :potential
112
+
113
+ def initialize(severity = 1, confirmed = 1, unconfirmed = 1, potential = 1)
114
+ @severity, @confirmed, @unconfirmed, @potential = severity, confirmed, unconfirmed, potential
115
+ end
116
+
117
+ def to_xml
118
+ xml = '<vulnFilter'
119
+ xml << %Q( severityThreshold="#{@severity}")
120
+ xml << %Q( confirmed="#{@confirmed}")
121
+ xml << %Q( unconfirmed="#{@unconfirmed}")
122
+ xml << %Q( potential="#{@potential}")
123
+ xml << '/>'
124
+ end
125
+
126
+ def self.parse(xml)
127
+ new(xml.attributes['severityThreshold'].to_i,
128
+ xml.attributes['confirmed'].to_i,
129
+ xml.attributes['unconfirmed'].to_i,
130
+ xml.attributes['potential'].to_i)
131
+ end
132
+ end
133
+
134
+ # Syslog Alert
135
+ # This class should only exist as an element of an Alert.
136
+ #
137
+ class SyslogAlert
138
+
139
+ # The server to sent this alert to.
140
+ attr_accessor :server
141
+
142
+ def initialize(server)
143
+ @server = server
144
+ end
145
+
146
+ def self.parse(xml)
147
+ new(xml.attributes['server'])
148
+ end
149
+
150
+ include Sanitize
151
+
152
+ def to_xml
153
+ xml = '<syslogAlert'
154
+ xml << %Q( server="#{replace_entities(server)}">)
155
+ xml << '</syslogAlert>'
156
+ end
157
+ end
158
+
159
+ # SNMP Alert
160
+ # This class should only exist as an element of an Alert.
161
+ #
162
+ class SNMPAlert
163
+
164
+ # The community string
165
+ attr_accessor :community
166
+
167
+ # The server to sent this alert
168
+ attr_accessor :server
169
+
170
+ def initialize(community, server)
171
+ @community = community
172
+ @server = server
173
+ end
174
+
175
+ def self.parse(xml)
176
+ new(xml.attributes['community'], xml.attributes['server'])
177
+ end
178
+
179
+ include Sanitize
180
+
181
+ def to_xml
182
+ xml = '<snmpAlert'
183
+ xml << %Q( community="#{replace_entities(community)}")
184
+ xml << %Q( server="#{replace_entities(server)}">)
185
+ xml << '</snmpAlert>'
186
+ end
187
+ end
188
+
189
+ # SMTP (e-mail) Alert
190
+ # This class should only exist as an element of an Alert.
191
+ #
192
+ class SMTPAlert
193
+
194
+ # The email address of the sender
195
+ attr_accessor :sender
196
+
197
+ # The server to sent this alert
198
+ attr_accessor :server
199
+
200
+ # Limit the text for mobile devices
201
+ attr_accessor :limit_text
202
+
203
+ # Array of strings with the e-mail addresses of the intended recipients.
204
+ attr_accessor :recipients
205
+
206
+ def initialize(sender, server, limit_text = 0)
207
+ @sender = sender
208
+ @server = server
209
+ @limit_text = limit_text
210
+ @recipients = []
211
+ end
212
+
213
+ # Adds a new Recipient to the recipients array
214
+ def add_recipient(recipient)
215
+ @recipients << recipient
216
+ end
217
+
218
+ include Sanitize
219
+
220
+ def to_xml
221
+ xml = '<smtpAlert'
222
+ xml << %Q( sender="#{replace_entities(sender)}")
223
+ xml << %Q( server="#{replace_entities(server)}")
224
+ xml << %Q( limitText="#{limit_text}">)
225
+ recipients.each do |recpt|
226
+ xml << "<recipient>#{replace_entities(recpt)}</recipient>"
227
+ end
228
+ xml << '</smtpAlert>'
229
+ end
230
+
231
+ def self.parse(xml)
232
+ alert = new(xml.attributes['sender'], xml.attributes['server'], xml.attributes['limitText'].to_i)
233
+ xml.elements.each("//recipient") do |recipient|
234
+ alert.recipients << recipient.text
235
+ end
236
+ alert
237
+ end
238
+ end
239
+ end
@@ -195,6 +195,7 @@ module Nexpose
195
195
  attr_accessor :credentials
196
196
 
197
197
  # [Array] Collection of real-time alerts.
198
+ # @see Alert
198
199
  # @see SMTPAlert
199
200
  # @see SNMPAlert
200
201
  # @see SyslogAlert
@@ -332,9 +333,11 @@ module Nexpose
332
333
  xml << assets.reduce('') { |acc, host| acc << host.to_xml }
333
334
  xml << '</Hosts>'
334
335
 
335
- xml << '<ExcludedHosts>'
336
- xml << exclude.reduce('') { |acc, host| acc << host.to_xml }
337
- xml << '</ExcludedHosts>'
336
+ unless exclude.empty?
337
+ xml << '<ExcludedHosts>'
338
+ xml << exclude.reduce('') { |acc, host| acc << host.to_xml }
339
+ xml << '</ExcludedHosts>'
340
+ end
338
341
 
339
342
  unless credentials.empty?
340
343
  xml << '<Credentials>'
@@ -411,43 +414,8 @@ module Nexpose
411
414
  end
412
415
  end
413
416
 
414
- s.elements.each('Alerting/Alert') do |a|
415
- a.elements.each('smtpAlert') do |smtp|
416
- smtp_alert = SMTPAlert.new(a.attributes['name'], smtp.attributes['sender'], smtp.attributes['limitText'], a.attributes['enabled'])
417
-
418
- smtp.elements.each('recipient') do |recipient|
419
- smtp_alert.add_recipient(recipient.text)
420
- end
421
- site.alerts << smtp_alert
422
- end
423
-
424
- a.elements.each('snmpAlert') do |snmp|
425
- snmp_alert = SNMPAlert.new(a.attributes['name'], snmp.attributes['community'], snmp.attributes['server'], a.attributes['enabled'])
426
- site.alerts << snmp_alert
427
- end
428
-
429
- a.elements.each('syslogAlert') do |syslog|
430
- syslog_alert = SyslogAlert.new(a.attributes['name'], syslog.attributes['server'], a.attributes['enabled'])
431
- site.alerts << syslog_alert
432
- end
433
-
434
- #a.elements.each('vuln_filter') do |vulnFilter|
435
- # vulnfilter = new VulnFilter.new(a.attributes["typemask"], a.attributes["severityThreshold"], $attrs["MAXALERTS"])
436
- # Pop off the top alert on the stack
437
- # $alert = @alerts.pop()
438
- # Add the new recipient string to the Alert Object
439
- # $alert.setVulnFilter($vulnfilter)
440
- # Push the alert back on to the alert stack
441
- # array_push($this->alerts, $alert)
442
- #end
443
-
444
- #a.elements.each('scanFilter') do |scanFilter|
445
- # <scanFilter scanStop='0' scanFailed='0' scanStart='1'/>
446
- # scanfilter = ScanFilter.new(scanFilter.attributes['scanStop'],scanFilter.attributes['scanFailed'],scanFilter.attributes['scanStart'])
447
- # alert = @alerts.pop()
448
- # alert.setScanFilter(scanfilter)
449
- # @alerts.push(alert)
450
- #end
417
+ s.elements.each('Alerting/Alert') do |alert|
418
+ site.alerts << Alert.parse(alert)
451
419
  end
452
420
 
453
421
  return site
@@ -563,142 +531,6 @@ module Nexpose
563
531
  end
564
532
  end
565
533
 
566
- # === Description
567
- # Object that represents a Syslog Alert.
568
- #
569
- class SyslogAlert
570
-
571
- # A unique name for this alert
572
- attr_reader :name
573
- # If this alert is enabled or not
574
- attr_reader :enabled
575
- # The Syslog server to sent this alert
576
- attr_reader :server
577
- # The vulnerability filter to trigger the alert
578
- attr_accessor :vuln_filter
579
- # The alert type
580
- attr_reader :type
581
-
582
- def initialize(name, server, enabled = 1)
583
- @type = :syslog
584
- @name = name
585
- @server = server
586
- @enabled = enabled
587
- # Sets default vuln filter - All Events
588
- @vuln_filter = VulnFilter.new('50790400', 1)
589
-
590
- end
591
-
592
- include Sanitize
593
-
594
- def to_xml
595
- xml = '<syslogAlert'
596
- xml << %Q{ name="#{replace_entities(name)}"}
597
- xml << %Q{ enabled="#{replace_entities(enabled)}"}
598
- xml << %Q{ server="#{replace_entities(server)}">}
599
- xml << vuln_filter.to_xml
600
- xml << '</syslogAlert>'
601
- xml
602
- end
603
-
604
- end
605
-
606
- # === Description
607
- # Object that represents an SNMP Alert.
608
- #
609
- class SNMPAlert
610
- include Sanitize
611
-
612
- # A unique name for this alert
613
- attr_reader :name
614
- # If this alert is enabled or not
615
- attr_reader :enabled
616
- # The community string
617
- attr_reader :community
618
- # The SNMP server to sent this alert
619
- attr_reader :server
620
- # The vulnerability filter to trigger the alert
621
- attr_reader :vuln_filter
622
- # The alert type
623
- attr_reader :type
624
-
625
- def initialize(name, community, server, enabled = 1)
626
- @type = :snmp
627
- @name = name
628
- @community = community
629
- @server = server
630
- @enabled = enabled
631
- # Sets default vuln filter - All Events
632
- @vuln_filter = VulnFilter.new('50790400', 1)
633
- end
634
-
635
- def to_xml
636
- xml = '<snmpAlert'
637
- xml << %Q{ name="#{replace_entities(name)}"}
638
- xml << %Q{ enabled="#{replace_entities(enabled)}"}
639
- xml << %Q{ community="#{replace_entities(community)}"}
640
- xml << %Q{ server="#{replace_entities(server)}">}
641
- xml << vuln_filter.to_xml
642
- xml << '</snmpAlert>'
643
- xml
644
- end
645
-
646
- end
647
-
648
- # === Description
649
- # Object that represents an SMTP (Email) Alert.
650
- #
651
- class SMTPAlert
652
- # A unique name for this alert
653
- attr_reader :name
654
- # If this alert is enabled or not
655
- attr_reader :enabled
656
- # The email address of the sender
657
- attr_reader :sender
658
- # Limit the text for mobile devices
659
- attr_reader :limit_text
660
- # Array containing Strings of email addresses
661
- # Array of strings with the email addresses of the intended recipients
662
- attr_reader :recipients
663
- # The vulnerability filter to trigger the alert
664
- attr_accessor :vuln_filter
665
- # The alert type
666
- attr_reader :type
667
-
668
- def initialize(name, sender, limit_text, enabled = 1)
669
- @type = :smtp
670
- @name = name
671
- @sender = sender
672
- @enabled = enabled
673
- @limit_text = limit_text
674
- @recipients = []
675
- # Sets default vuln filter - All Events
676
- @vuln_filter = VulnFilter.new('50790400', 1)
677
- end
678
-
679
- # Adds a new Recipient to the recipients array
680
- def add_recipient(recipient)
681
- @recipients.push(recipient)
682
- end
683
-
684
- include Sanitize
685
-
686
- def to_xml
687
- xml = '<smtpAlert'
688
- xml << %Q{ name="#{replace_entities(name)}"}
689
- xml << %Q{ enabled="#{replace_entities(enabled)}"}
690
- xml << %Q{ sender="#{replace_entities(sender)}"}
691
- xml << %Q{ limitText="#{replace_entities(limit_text)}">}
692
- recipients.each do |recpt|
693
- xml << "<recipient>#{replace_entities(recpt)}</recipient>"
694
- end
695
- xml << vuln_filter.to_xml
696
- xml << '</smtpAlert>'
697
- xml
698
- end
699
- end
700
-
701
- # === Description
702
534
  # Object that represents a hostname to be added to a site.
703
535
  class HostName
704
536
  # Named host (usually DNS or Netbios name).
@@ -1,13 +1,7 @@
1
1
  module Nexpose
2
2
  module Sanitize
3
3
  def replace_entities(str)
4
- ret = str.dup
5
- ret.gsub!(/&/, '&amp;')
6
- ret.gsub!(/'/, '&apos;')
7
- ret.gsub!(/"/, '&quot;')
8
- ret.gsub!(/</, '&lt;')
9
- ret.gsub!(/>/, '&gt;')
10
- ret
4
+ str.to_s.gsub(/&/, '&amp;').gsub(/'/, '&apos;').gsub(/"/, '&quot;').gsub(/</, '&lt;').gsub(/>/, '&gt;')
11
5
  end
12
6
  end
13
7
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nexpose
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.13
4
+ version: 0.1.14
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2013-04-19 00:00:00.000000000 Z
14
+ date: 2013-04-22 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: librex
@@ -72,6 +72,7 @@ files:
72
72
  - lib/nexpose/vuln.rb
73
73
  - lib/nexpose/util.rb
74
74
  - lib/nexpose/site.rb
75
+ - lib/nexpose/alert.rb
75
76
  - lib/nexpose/silo.rb
76
77
  - lib/nexpose/user.rb
77
78
  - lib/nexpose/connection.rb