nexpose 0.1.13 → 0.1.14
Sign up to get free protection for your applications and to get access to all the features.
- 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
|