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.
- data/lib/nexpose.rb +1 -0
- data/lib/nexpose/alert.rb +239 -0
- data/lib/nexpose/site.rb +8 -176
- data/lib/nexpose/util.rb +1 -7
- metadata +3 -2
data/lib/nexpose.rb
CHANGED
@@ -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
|
data/lib/nexpose/site.rb
CHANGED
@@ -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
|
-
|
336
|
-
|
337
|
-
|
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 |
|
415
|
-
|
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).
|
data/lib/nexpose/util.rb
CHANGED
@@ -1,13 +1,7 @@
|
|
1
1
|
module Nexpose
|
2
2
|
module Sanitize
|
3
3
|
def replace_entities(str)
|
4
|
-
|
5
|
-
ret.gsub!(/&/, '&')
|
6
|
-
ret.gsub!(/'/, ''')
|
7
|
-
ret.gsub!(/"/, '"')
|
8
|
-
ret.gsub!(/</, '<')
|
9
|
-
ret.gsub!(/>/, '>')
|
10
|
-
ret
|
4
|
+
str.to_s.gsub(/&/, '&').gsub(/'/, ''').gsub(/"/, '"').gsub(/</, '<').gsub(/>/, '>')
|
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.
|
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-
|
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
|