nexpose 0.1.13 → 0.1.14

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.
@@ -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