nexpose 0.0.98 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +17 -7
- data/Rakefile +17 -22
- data/lib/README.md +5 -0
- data/lib/nexpose.rb +104 -130
- data/lib/nexpose/api_request.rb +133 -144
- data/lib/nexpose/common.rb +138 -0
- data/lib/nexpose/connection.rb +117 -106
- data/lib/nexpose/creds.rb +292 -279
- data/lib/nexpose/error.rb +21 -21
- data/lib/nexpose/manage.rb +83 -0
- data/lib/nexpose/misc.rb +85 -122
- data/lib/nexpose/report.rb +783 -603
- data/lib/nexpose/role.rb +27 -0
- data/lib/nexpose/scan.rb +264 -285
- data/lib/nexpose/scan_engine.rb +344 -350
- data/lib/nexpose/silo.rb +348 -347
- data/lib/nexpose/site.rb +826 -898
- data/lib/nexpose/ticket.rb +108 -108
- data/lib/nexpose/user.rb +223 -221
- data/lib/nexpose/util.rb +36 -36
- data/lib/nexpose/vuln.rb +510 -520
- metadata +37 -23
- data/README +0 -0
- data/nexpose.gemspec +0 -20
data/lib/nexpose/site.rb
CHANGED
@@ -1,898 +1,826 @@
|
|
1
|
-
module Nexpose
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
# Adds a new Recipient to the recipients array
|
829
|
-
def addRecipient(recipient)
|
830
|
-
@recipients.push(recipient)
|
831
|
-
end
|
832
|
-
|
833
|
-
# Sets the Vulnerability Filter for this alert.
|
834
|
-
def setVulnFilter(vulnFilter)
|
835
|
-
@vulnFilter = vulnFilter
|
836
|
-
end
|
837
|
-
|
838
|
-
include Sanitize
|
839
|
-
|
840
|
-
def to_xml
|
841
|
-
xml = "<smtpAlert"
|
842
|
-
xml << %Q{ name="#{replace_entities(name)}"}
|
843
|
-
xml << %Q{ enabled="#{replace_entities(enabled)}"}
|
844
|
-
xml << %Q{ sender="#{replace_entities(sender)}"}
|
845
|
-
xml << %Q{ limitText="#{replace_entities(limitText)}">}
|
846
|
-
recipients.each do |recpt|
|
847
|
-
xml << "<recipient>#{replace_entities(recpt)}</recipient>"
|
848
|
-
end
|
849
|
-
xml << vulnFilter.to_xml
|
850
|
-
xml << "</smtpAlert>"
|
851
|
-
xml
|
852
|
-
end
|
853
|
-
end
|
854
|
-
|
855
|
-
# === Description
|
856
|
-
# Object that represents a hostname to be added to a site.
|
857
|
-
class HostName
|
858
|
-
|
859
|
-
# The hostname
|
860
|
-
attr_reader :hostname
|
861
|
-
|
862
|
-
def initialize(hostname)
|
863
|
-
@hostname = hostname
|
864
|
-
end
|
865
|
-
|
866
|
-
include Sanitize
|
867
|
-
|
868
|
-
def to_xml
|
869
|
-
"<host>#{replace_entities(hostname)}</host>"
|
870
|
-
end
|
871
|
-
end
|
872
|
-
|
873
|
-
# === Description
|
874
|
-
# Object that represents a single IP address or an inclusive range of IP addresses.
|
875
|
-
# If to is nil then the from field will be used to specify a single IP Address only.
|
876
|
-
#
|
877
|
-
class IPRange
|
878
|
-
# Start of Range *Required
|
879
|
-
attr_reader :from
|
880
|
-
# End of Range *Optional (If Null then IPRange is a single IP Address)
|
881
|
-
attr_reader :to
|
882
|
-
|
883
|
-
def initialize(from, to = nil)
|
884
|
-
@from = from
|
885
|
-
@to = to
|
886
|
-
end
|
887
|
-
|
888
|
-
include Sanitize
|
889
|
-
|
890
|
-
def to_xml
|
891
|
-
if (to and not to.empty?)
|
892
|
-
return %Q{<range from="#{from}" to="#{to}"/>}
|
893
|
-
else
|
894
|
-
return %Q{<range from="#{from}"/>}
|
895
|
-
end
|
896
|
-
end
|
897
|
-
end
|
898
|
-
end
|
1
|
+
module Nexpose
|
2
|
+
module NexposeAPI
|
3
|
+
include XMLUtils
|
4
|
+
|
5
|
+
#
|
6
|
+
#
|
7
|
+
#
|
8
|
+
def site_device_listing(site_id)
|
9
|
+
r = execute(make_xml('SiteDeviceListingRequest', {'site-id' => site_id.to_s}))
|
10
|
+
|
11
|
+
if (r.success)
|
12
|
+
res = []
|
13
|
+
r.res.elements.each("//device") do |device|
|
14
|
+
res << {
|
15
|
+
:device_id => device.attributes['id'].to_i,
|
16
|
+
# TODO Covert to using?
|
17
|
+
# :address => IPAddr.new(device.attributes['address']),
|
18
|
+
:address => device.attributes['address'].to_s,
|
19
|
+
:risk_factor => device.attributes['riskfactor'].to_f,
|
20
|
+
:risk_score => device.attributes['riskscore'].to_f,
|
21
|
+
}
|
22
|
+
end
|
23
|
+
res
|
24
|
+
else
|
25
|
+
false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
#
|
31
|
+
#
|
32
|
+
def site_delete(param)
|
33
|
+
r = execute(make_xml('SiteDeleteRequest', {'site-id' => param}))
|
34
|
+
r.success
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
#
|
39
|
+
# TODO Should just return empty array if doesn't work?
|
40
|
+
def site_listing
|
41
|
+
r = execute(make_xml('SiteListingRequest', {}))
|
42
|
+
|
43
|
+
if (r.success)
|
44
|
+
res = []
|
45
|
+
r.res.elements.each("//SiteSummary") do |site|
|
46
|
+
res << {
|
47
|
+
:site_id => site.attributes['id'].to_i,
|
48
|
+
:name => site.attributes['name'].to_s,
|
49
|
+
:risk_factor => site.attributes['riskfactor'].to_f,
|
50
|
+
:risk_score => site.attributes['riskscore'].to_f,
|
51
|
+
}
|
52
|
+
end
|
53
|
+
res
|
54
|
+
else
|
55
|
+
false
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
#-----------------------------------------------------------------------
|
60
|
+
# TODO: Needs to be expanded to included details
|
61
|
+
# Also confusing. Name clashes with field on Site
|
62
|
+
#-----------------------------------------------------------------------
|
63
|
+
def site_scan_history(site_id)
|
64
|
+
r = execute(make_xml('SiteScanHistoryRequest', {'site-id' => site_id.to_s}))
|
65
|
+
|
66
|
+
if (r.success)
|
67
|
+
res = []
|
68
|
+
r.res.elements.each("//ScanSummary") do |site_scan_history|
|
69
|
+
res << {
|
70
|
+
:site_id => site_scan_history.attributes['site-id'].to_i,
|
71
|
+
:scan_id => site_scan_history.attributes['scan-id'].to_i,
|
72
|
+
:engine_id => site_scan_history.attributes['engine-id'].to_i,
|
73
|
+
:start_time => site_scan_history.attributes['startTime'].to_s,
|
74
|
+
:end_time => site_scan_history.attributes['endTime'].to_s
|
75
|
+
}
|
76
|
+
end
|
77
|
+
res
|
78
|
+
else
|
79
|
+
false
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
#-----------------------------------------------------------------------
|
84
|
+
# Starts device specific site scanning.
|
85
|
+
#
|
86
|
+
# devices - An Array of device IDs
|
87
|
+
# hosts - An Array of Hashes [o]=>{:range=>"to,from"} [1]=>{:host=>host}
|
88
|
+
#-----------------------------------------------------------------------
|
89
|
+
def site_device_scan_start(site_id, devices, hosts)
|
90
|
+
|
91
|
+
if hosts == nil and devices == nil
|
92
|
+
raise ArgumentError.new("Both the device and host list is nil")
|
93
|
+
end
|
94
|
+
|
95
|
+
xml = make_xml('SiteDevicesScanRequest', {'site-id' => site_id})
|
96
|
+
|
97
|
+
if devices != nil
|
98
|
+
inner_xml = REXML::Element.new 'Devices'
|
99
|
+
for device_id in devices
|
100
|
+
inner_xml.add_element 'device', {'id' => "#{device_id}"}
|
101
|
+
end
|
102
|
+
xml.add_element inner_xml
|
103
|
+
end
|
104
|
+
|
105
|
+
if hosts
|
106
|
+
inner_xml = REXML::Element.new 'Hosts'
|
107
|
+
hosts.each_index do |x|
|
108
|
+
if hosts[x].key? :range
|
109
|
+
to = hosts[x][:range].split(',')[0]
|
110
|
+
from = hosts[x][:range].split(',')[1]
|
111
|
+
inner_xml.add_element 'range', {'to' => "#{to}", 'from' => "#{from}"}
|
112
|
+
end
|
113
|
+
if hosts[x].key? :host
|
114
|
+
host_element = REXML::Element.new 'host'
|
115
|
+
host_element.text = "#{hosts[x][:host]}"
|
116
|
+
inner_xml.add_element host_element
|
117
|
+
end
|
118
|
+
end
|
119
|
+
xml.add_element inner_xml
|
120
|
+
end
|
121
|
+
|
122
|
+
r = execute xml
|
123
|
+
if r.success
|
124
|
+
r.res.elements.each('//Scan') do |scan_info|
|
125
|
+
return {
|
126
|
+
:scan_id => scan_info.attributes['scan-id'].to_i,
|
127
|
+
:engine_id => scan_info.attributes['engine-id'].to_i
|
128
|
+
}
|
129
|
+
end
|
130
|
+
else
|
131
|
+
false
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Configuration object representing a Nexpose site.
|
137
|
+
#
|
138
|
+
# For a basic walk-through, see {https://github.com/rapid7/nexpose-client/wiki/Using-Sites}
|
139
|
+
class Site
|
140
|
+
|
141
|
+
# The site ID. An ID of -1 is used to designate a site that has not been
|
142
|
+
# saved to a Nexpose console.
|
143
|
+
attr_accessor :id
|
144
|
+
|
145
|
+
# Unique name of the site. Required.
|
146
|
+
attr_accessor :name
|
147
|
+
|
148
|
+
# Description of the site.
|
149
|
+
attr_accessor :description
|
150
|
+
|
151
|
+
# [Array] Collection of assets. May be IPv4, IPv6, or DNS names.
|
152
|
+
# @see HostName
|
153
|
+
# @see IPRange
|
154
|
+
attr_accessor :assets
|
155
|
+
|
156
|
+
# Scan template to use when starting a scan job. Default: full-audit
|
157
|
+
attr_accessor :scan_template
|
158
|
+
|
159
|
+
# Friendly name of scan template to use when starting a scan job.
|
160
|
+
# Value is populated when a site is saved or loaded from a console.
|
161
|
+
attr_accessor :scan_template_name
|
162
|
+
|
163
|
+
# Scan Engine to use. Will use the default engine if nil or -1.
|
164
|
+
attr_accessor :engine
|
165
|
+
|
166
|
+
# [Array] Schedule starting dates and times for scans, and set their frequency.
|
167
|
+
attr_accessor :schedules
|
168
|
+
|
169
|
+
# The risk factor associated with this site. Default: 1.0
|
170
|
+
attr_accessor :risk_factor
|
171
|
+
|
172
|
+
# [Array] Collection of credentials associated with this site.
|
173
|
+
attr_accessor :credentials
|
174
|
+
|
175
|
+
# [Array] Collection of real-time alerts.
|
176
|
+
# @see SMTPAlert
|
177
|
+
# @see SNMPAlert
|
178
|
+
# @see SyslogAlert
|
179
|
+
attr_accessor :alerts
|
180
|
+
|
181
|
+
# Configuration version. Default: 3
|
182
|
+
attr_accessor :config_version
|
183
|
+
|
184
|
+
# Whether or not this site is dynamic.
|
185
|
+
# Dynamic sites are created through Asset Discovery Connections.
|
186
|
+
# Modifying their behavior through the API is not recommended.
|
187
|
+
attr_accessor :is_dynamic
|
188
|
+
|
189
|
+
# Site constructor. Both arguments are optional.
|
190
|
+
#
|
191
|
+
# @param [String] name Unique name of the site.
|
192
|
+
# @param [String] scan_template ID of the scan template to use.
|
193
|
+
def initialize(name = nil, scan_template = 'full-audit')
|
194
|
+
@name = name;
|
195
|
+
@scan_template = scan_template
|
196
|
+
|
197
|
+
@id = -1
|
198
|
+
@risk_factor = 1.0
|
199
|
+
@config_version = 3
|
200
|
+
@is_dynamic = false
|
201
|
+
@assets = []
|
202
|
+
@schedules = []
|
203
|
+
@credentials = []
|
204
|
+
@alerts = []
|
205
|
+
end
|
206
|
+
|
207
|
+
# Returns true when the site is dynamic.
|
208
|
+
def dynamic?
|
209
|
+
is_dynamic
|
210
|
+
end
|
211
|
+
|
212
|
+
# Load an existing configuration from a Nexpose instance.
|
213
|
+
#
|
214
|
+
# @param [Connection] connection Connection to console where scan will be launched.
|
215
|
+
# @param [Fixnum] id Site ID of an existing site.
|
216
|
+
# @return [Site] Site configuration loaded from a Nexpose console.
|
217
|
+
def self.load(connection, id)
|
218
|
+
r = APIRequest.execute(connection.url, %Q(<SiteConfigRequest session-id="#{connection.session_id}" site-id="#{id}"/>))
|
219
|
+
parse(r.res)
|
220
|
+
end
|
221
|
+
|
222
|
+
# Copy an existing configuration from a Nexpose instance.
|
223
|
+
#
|
224
|
+
# @param [Connection] connection Connection to console where scan will be launched.
|
225
|
+
# @param [Fixnum] id Site ID of an existing site.
|
226
|
+
# @return [Site] Site configuration loaded from a Nexpose console.
|
227
|
+
def self.copy(connection, id)
|
228
|
+
site = self.load(connection, id)
|
229
|
+
site.id = -1
|
230
|
+
site.name = "#{site.name} Copy"
|
231
|
+
site
|
232
|
+
end
|
233
|
+
|
234
|
+
# Saves this site to a Nexpose console.
|
235
|
+
#
|
236
|
+
# @param [Connection] connection Connection to console where this site will be saved.
|
237
|
+
# @return [Fixnum] Site ID assigned to this configuration, if successful.
|
238
|
+
def save(connection)
|
239
|
+
r = connection.execute('<SiteSaveRequest session-id="' + connection.session_id + '">' + to_xml + ' </SiteSaveRequest>')
|
240
|
+
if (r.success)
|
241
|
+
@id = r.attributes['site-id']
|
242
|
+
return @id
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
# Delete this site from a Nexpose console.
|
247
|
+
#
|
248
|
+
# @param [Connection] connection Connection to console where this site will be saved.
|
249
|
+
# @return [Boolean] Whether or not the site was successfully deleted.
|
250
|
+
def delete(connection)
|
251
|
+
r = connection.execute(%Q{<SiteDeleteRequest session-id="#{connection.session_id}" site-id="#@id"/>})
|
252
|
+
r.success
|
253
|
+
end
|
254
|
+
|
255
|
+
# Scan this site.
|
256
|
+
#
|
257
|
+
# @param [Connection] connection Connection to console where scan will be launched.
|
258
|
+
# @param [String] sync_id Optional syncronization token.
|
259
|
+
# @return [Fixnum, Fixnum] Scan ID and engine ID where the scan was launched.
|
260
|
+
def scan(connection, sync_id = nil)
|
261
|
+
xml = REXML::Element.new('SiteScanRequest')
|
262
|
+
xml.add_attributes({'session-id' => connection.session_id,
|
263
|
+
'site-id' => id,
|
264
|
+
'sync-id' => sync_id})
|
265
|
+
|
266
|
+
response = connection.execute(xml)
|
267
|
+
if response.success
|
268
|
+
response.res.elements.each('/SiteScanResponse/Scan/') do |scan|
|
269
|
+
return [scan.attributes['scan-id'].to_i, scan.attributes['engine-id'].to_i]
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
# Generate an XML representation of this site configuration
|
275
|
+
# @return [String] XML valid for submission as part of other requests.
|
276
|
+
def to_xml
|
277
|
+
xml = %Q(<Site id='#{id}' name='#{name}' description='#{description}' riskfactor='#{risk_factor}'>)
|
278
|
+
|
279
|
+
xml << '<Hosts>'
|
280
|
+
xml << assets.reduce('') { |acc, host| acc << host.to_xml }
|
281
|
+
xml << '</Hosts>'
|
282
|
+
|
283
|
+
unless credentials.empty?
|
284
|
+
xml << '<Credentials>'
|
285
|
+
credentials.each do |c|
|
286
|
+
xml << c.to_xml if c.respond_to? :to_xml
|
287
|
+
end
|
288
|
+
xml << '</Credentials>'
|
289
|
+
end
|
290
|
+
|
291
|
+
unless alerts.empty?
|
292
|
+
xml << '<Alerting>'
|
293
|
+
alerts.each do |a|
|
294
|
+
xml << a.to_xml if a.respond_to? :to_xml
|
295
|
+
end
|
296
|
+
xml << '</Alerting>'
|
297
|
+
end
|
298
|
+
|
299
|
+
xml << %Q(<ScanConfig configID="#{@id}" name="#{@scan_template_name || @scan_template}" templateID="#{@scan_template}" configVersion="#{@config_version || 3}" engineID="#{@engine}">)
|
300
|
+
|
301
|
+
xml << '<Schedules>'
|
302
|
+
@schedules.each do |sched|
|
303
|
+
xml << %Q{<Schedule enabled="#{sched.enabled ? 1 : 0}" type="#{sched.type}" interval="#{sched.interval}" start="#{sched.start}" />}
|
304
|
+
end
|
305
|
+
xml << '</Schedules>'
|
306
|
+
xml << '</ScanConfig>'
|
307
|
+
xml << '</Site>'
|
308
|
+
end
|
309
|
+
|
310
|
+
# Parse a response from a Nexpose console into a valid Site object.
|
311
|
+
#
|
312
|
+
# @param [REXML::Document] rexml XML document to parse.
|
313
|
+
# @return [Site] Site object represented by the XML.
|
314
|
+
# ## TODO What is returned on failure?
|
315
|
+
def self.parse(rexml)
|
316
|
+
rexml.elements.each('SiteConfigResponse/Site') do |s|
|
317
|
+
site = Site.new(s.attributes['name'])
|
318
|
+
site.id = s.attributes['id'].to_i
|
319
|
+
site.description = s.attributes['description']
|
320
|
+
site.risk_factor = s.attributes['riskfactor'] || 1.0
|
321
|
+
site.is_dynamic = true if s.attributes['isDynamic'] == '1'
|
322
|
+
|
323
|
+
s.elements.each('Hosts/range') do |r|
|
324
|
+
site.assets << IPRange.new(r.attributes['from'], r.attributes['to'])
|
325
|
+
end
|
326
|
+
s.elements.each('Hosts/host') do |host|
|
327
|
+
site.assets << HostName.new(host.text)
|
328
|
+
end
|
329
|
+
|
330
|
+
s.elements.each('ScanConfig') do |scan_config|
|
331
|
+
site.scan_template_name = scan_config.attributes['name']
|
332
|
+
site.scan_template = scan_config.attributes['templateID']
|
333
|
+
site.config_version = scan_config.attributes['configVersion'].to_i
|
334
|
+
site.engine = scan_config.attributes['engineID'].to_i
|
335
|
+
scan_config.elements.each('Schedules/Schedule') do |sched|
|
336
|
+
schedule = Schedule.new(sched.attributes['type'],
|
337
|
+
sched.attributes['interval'],
|
338
|
+
sched.attributes['start'],
|
339
|
+
sched.attributes['enabled'])
|
340
|
+
site.schedules << schedule
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
s.elements.each('Credentials') do |cred|
|
345
|
+
# TODO
|
346
|
+
end
|
347
|
+
|
348
|
+
s.elements.each('Alerting/Alert') do |a|
|
349
|
+
a.elements.each('smtpAlert') do |smtp|
|
350
|
+
smtp_alert = SMTPAlert.new(a.attributes['name'], smtp.attributes['sender'], smtp.attributes['limitText'], a.attributes['enabled'])
|
351
|
+
|
352
|
+
smtp.elements.each('recipient') do |recipient|
|
353
|
+
smtp_alert.addRecipient(recipient.text)
|
354
|
+
end
|
355
|
+
site.alerts << smtp_alert
|
356
|
+
end
|
357
|
+
|
358
|
+
a.elements.each('snmpAlert') do |snmp|
|
359
|
+
snmp_alert = SNMPAlert.new(a.attributes['name'], snmp.attributes['community'], snmp.attributes['server'], a.attributes['enabled'])
|
360
|
+
site.alerts << snmp_alert
|
361
|
+
end
|
362
|
+
|
363
|
+
a.elements.each('syslogAlert') do |syslog|
|
364
|
+
syslog_alert = SyslogAlert.new(a.attributes['name'], syslog.attributes['server'], a.attributes['enabled'])
|
365
|
+
site.alerts << syslog_alert
|
366
|
+
end
|
367
|
+
|
368
|
+
a.elements.each('vulnFilter') do |vulnFilter|
|
369
|
+
|
370
|
+
#vulnfilter = new VulnFilter.new(a.attributes["typemask"], a.attributes["severityThreshold"], $attrs["MAXALERTS"])
|
371
|
+
# Pop off the top alert on the stack
|
372
|
+
#$alert = @alerts.pop()
|
373
|
+
# Add the new recipient string to the Alert Object
|
374
|
+
#$alert.setVulnFilter($vulnfilter)
|
375
|
+
# Push the alert back on to the alert stack
|
376
|
+
#array_push($this->alerts, $alert)
|
377
|
+
end
|
378
|
+
|
379
|
+
a.elements.each('scanFilter') do |scanFilter|
|
380
|
+
#<scanFilter scanStop='0' scanFailed='0' scanStart='1'/>
|
381
|
+
#scanfilter = ScanFilter.new(scanFilter.attributes['scanStop'],scanFilter.attributes['scanFailed'],scanFilter.attributes['scanStart'])
|
382
|
+
#alert = @alerts.pop()
|
383
|
+
#alert.setScanFilter(scanfilter)
|
384
|
+
#@alerts.push(alert)
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
return site
|
389
|
+
end
|
390
|
+
nil
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
# === Description
|
395
|
+
# Object that represents a listing of all of the sites available on an NSC.
|
396
|
+
#
|
397
|
+
# === Example
|
398
|
+
# # Create a new Nexpose Connection on the default port and Login
|
399
|
+
# nsc = Connection.new("10.1.40.10","nxadmin","password")
|
400
|
+
# nsc->login;
|
401
|
+
#
|
402
|
+
# # Get Site Listing
|
403
|
+
# sitelisting = SiteListing.new(nsc)
|
404
|
+
#
|
405
|
+
# # Enumerate through all of the SiteSummaries
|
406
|
+
# sitelisting.sites.each do |sitesummary|
|
407
|
+
# # Do some operation on each site
|
408
|
+
# end
|
409
|
+
#
|
410
|
+
class SiteListing
|
411
|
+
# true if an error condition exists; false otherwise
|
412
|
+
attr_reader :error
|
413
|
+
# Error message string
|
414
|
+
attr_reader :error_msg
|
415
|
+
# The last XML request sent by this object
|
416
|
+
attr_reader :request_xml
|
417
|
+
# The last XML response received by this object
|
418
|
+
attr_reader :response_xml
|
419
|
+
# The NSC Connection associated with this object
|
420
|
+
attr_reader :connection
|
421
|
+
# Array containing SiteSummary objects for each site in the connection
|
422
|
+
attr_reader :sites
|
423
|
+
# The number of sites
|
424
|
+
attr_reader :site_count
|
425
|
+
|
426
|
+
# Constructor
|
427
|
+
# SiteListing (connection)
|
428
|
+
def initialize(connection)
|
429
|
+
@sites = []
|
430
|
+
|
431
|
+
@connection = connection
|
432
|
+
|
433
|
+
r = @connection.execute('<SiteListingRequest session-id="' + @connection.session_id.to_s + '"/>')
|
434
|
+
|
435
|
+
if (r.success)
|
436
|
+
parse(r.res)
|
437
|
+
else
|
438
|
+
raise APIError.new(r, "Failed to get site listing")
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
def parse(r)
|
443
|
+
r.elements.each('SiteListingResponse/SiteSummary') do |s|
|
444
|
+
site_summary = SiteSummary.new(
|
445
|
+
s.attributes['id'].to_s,
|
446
|
+
s.attributes['name'].to_s,
|
447
|
+
s.attributes['description'].to_s,
|
448
|
+
s.attributes['riskfactor'].to_s
|
449
|
+
)
|
450
|
+
@sites.push(site_summary)
|
451
|
+
end
|
452
|
+
@site_count = @sites.length
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
# === Description
|
457
|
+
# Object that represents the summary of a Nexpose Site.
|
458
|
+
#
|
459
|
+
class SiteSummary
|
460
|
+
# The Site ID
|
461
|
+
attr_reader :id
|
462
|
+
# The Site Name
|
463
|
+
attr_reader :site_name
|
464
|
+
# A Description of the Site
|
465
|
+
attr_reader :description
|
466
|
+
# User assigned risk multiplier
|
467
|
+
attr_reader :riskfactor
|
468
|
+
|
469
|
+
# Constructor
|
470
|
+
# SiteSummary(id, site_name, description, riskfactor = 1)
|
471
|
+
def initialize(id, site_name, description, riskfactor = 1.0)
|
472
|
+
@id = id
|
473
|
+
@site_name = site_name
|
474
|
+
@description = description
|
475
|
+
@riskfactor = riskfactor
|
476
|
+
end
|
477
|
+
|
478
|
+
def _set_id(id)
|
479
|
+
@id = id
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
483
|
+
# === Description
|
484
|
+
# Object that represents the scan history of a site.
|
485
|
+
#
|
486
|
+
class SiteScanHistory
|
487
|
+
# true if an error condition exists; false otherwise
|
488
|
+
attr_reader :error
|
489
|
+
# Error message string
|
490
|
+
attr_reader :error_msg
|
491
|
+
# The last XML request sent by this object
|
492
|
+
attr_reader :request_xml
|
493
|
+
# The last response received by this object
|
494
|
+
attr_reader :response
|
495
|
+
# The NSC Connection associated with this object
|
496
|
+
attr_reader :connection
|
497
|
+
# The Site ID
|
498
|
+
attr_reader :site_id
|
499
|
+
# //Array containing (ScanSummary*)
|
500
|
+
attr_reader :scan_summaries
|
501
|
+
|
502
|
+
def initialize(connection, id)
|
503
|
+
@site_id = id
|
504
|
+
@error = false
|
505
|
+
@connection = connection
|
506
|
+
@scan_summaries = []
|
507
|
+
|
508
|
+
@request_xml = '<SiteScanHistoryRequest' + ' session-id="' + @connection.session_id + '" site-id="' + "#{@site_id}" + '"/>'
|
509
|
+
r = @connection.execute(@request_xml)
|
510
|
+
@response = r
|
511
|
+
|
512
|
+
if r and r.success
|
513
|
+
r.res.elements.each('//ScanSummary') do |summary|
|
514
|
+
scan_id=summary.attributes['scan-id'].to_i
|
515
|
+
engine_id=summary.attributes['engine-id'].to_i
|
516
|
+
name=summary.attributes['name'].to_s
|
517
|
+
start_time=summary.attributes['startTime'].to_s
|
518
|
+
end_time=summary.attributes['endTime'].to_s
|
519
|
+
status=summary.attributes['status'].to_s
|
520
|
+
scan_summary = ScanSummary.new(scan_id, engine_id, name, start_time, end_time, status)
|
521
|
+
scan_summaries << scan_summary
|
522
|
+
end
|
523
|
+
end
|
524
|
+
end
|
525
|
+
end
|
526
|
+
|
527
|
+
# === Description
|
528
|
+
# Object that represents a listing of devices for a site or the entire NSC. Note that only devices which are accessible to the account used to create the connection object will be returned. This object is created and populated automatically with the instantiation of a new Site object.
|
529
|
+
#
|
530
|
+
class SiteDeviceListing
|
531
|
+
|
532
|
+
# true if an error condition exists; false otherwise
|
533
|
+
attr_reader :error
|
534
|
+
# Error message string
|
535
|
+
attr_reader :error_msg
|
536
|
+
# The last XML request sent by this object
|
537
|
+
attr_reader :request_xml
|
538
|
+
# The last XML response received by this object
|
539
|
+
attr_reader :response_xml
|
540
|
+
# The NSC Connection associated with this object
|
541
|
+
attr_reader :connection
|
542
|
+
# The Site ID. 0 if all sites are specified.
|
543
|
+
attr_reader :site_id
|
544
|
+
# //Array of (Device)*
|
545
|
+
attr_reader :devices
|
546
|
+
|
547
|
+
def initialize(connection, site_id = 0)
|
548
|
+
|
549
|
+
@site_id = site_id
|
550
|
+
@error = false
|
551
|
+
@connection = connection
|
552
|
+
@devices = []
|
553
|
+
|
554
|
+
r = nil
|
555
|
+
if (@site_id)
|
556
|
+
r = @connection.execute('<SiteDeviceListingRequest session-id="' + connection.session_id + '" site-id="' + "#{@site_id}" + '"/>')
|
557
|
+
if r.success
|
558
|
+
r.res.elements.each('SiteDeviceListingResponse/SiteDevices/device') do |d|
|
559
|
+
@devices.push(Device.new(d.attributes['id'], @site_id, d.attributes["address"], d.attributes["riskfactor"], d.attributes["riskscore"]))
|
560
|
+
end
|
561
|
+
end
|
562
|
+
else
|
563
|
+
r = @connection.execute('<SiteDeviceListingRequest session-id="' + connection.session_id + '"/>')
|
564
|
+
if r.success
|
565
|
+
r.res.elements.each('SiteDeviceListingResponse/SiteDevices') do |rr|
|
566
|
+
@sid = rr.attribute("site-id")
|
567
|
+
rr.elements.each('device') do |d|
|
568
|
+
@devices.push(Device.new(d.attributes['id'], @sid, d.attributes["address"], d.attributes['riskfactor'], d.attributes['riskscore']))
|
569
|
+
end
|
570
|
+
end
|
571
|
+
end
|
572
|
+
end
|
573
|
+
end
|
574
|
+
end
|
575
|
+
|
576
|
+
# === Description
|
577
|
+
# Object that represents a single device in an NSC.
|
578
|
+
#
|
579
|
+
class Device
|
580
|
+
|
581
|
+
# A unique device ID (assigned by the NSC)
|
582
|
+
attr_reader :id
|
583
|
+
# The site ID of this devices site
|
584
|
+
attr_reader :site_id
|
585
|
+
# IP Address or Hostname of this device
|
586
|
+
attr_reader :address
|
587
|
+
# User assigned risk multiplier
|
588
|
+
attr_reader :riskfactor
|
589
|
+
# Nexpose risk score
|
590
|
+
attr_reader :riskscore
|
591
|
+
|
592
|
+
def initialize(id, site_id, address, riskfactor=1, riskscore=0)
|
593
|
+
@id = id
|
594
|
+
@site_id = site_id
|
595
|
+
@address = address
|
596
|
+
@riskfactor = riskfactor
|
597
|
+
@riskscore = riskscore
|
598
|
+
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
602
|
+
# === Description
|
603
|
+
# Object that represents a Syslog Alert.
|
604
|
+
#
|
605
|
+
class SyslogAlert
|
606
|
+
|
607
|
+
# A unique name for this alert
|
608
|
+
attr_reader :name
|
609
|
+
# If this alert is enabled or not
|
610
|
+
attr_reader :enabled
|
611
|
+
# The Syslog server to sent this alert
|
612
|
+
attr_reader :server
|
613
|
+
# The vulnerability filter to trigger the alert
|
614
|
+
attr_reader :vulnFilter
|
615
|
+
# The alert type
|
616
|
+
attr_reader :type
|
617
|
+
|
618
|
+
def initialize(name, server, enabled = 1)
|
619
|
+
@type = :syslog
|
620
|
+
@name = name
|
621
|
+
@server = server
|
622
|
+
@enabled = enabled
|
623
|
+
# Sets default vuln filter - All Events
|
624
|
+
setVulnFilter(VulnFilter.new("50790400", 1))
|
625
|
+
|
626
|
+
end
|
627
|
+
|
628
|
+
# Sets the Vulnerability Filter for this alert.
|
629
|
+
def setVulnFilter(vulnFilter)
|
630
|
+
@vulnFilter = vulnFilter
|
631
|
+
end
|
632
|
+
|
633
|
+
include Sanitize
|
634
|
+
|
635
|
+
def to_xml
|
636
|
+
xml = "<syslogAlert"
|
637
|
+
xml << %Q{ name="#{replace_entities(name)}"}
|
638
|
+
xml << %Q{ enabled="#{replace_entities(enabled)}"}
|
639
|
+
xml << %Q{ server="#{replace_entities(server)}">}
|
640
|
+
xml << vulnFilter.to_xml
|
641
|
+
xml << "</syslogAlert>"
|
642
|
+
xml
|
643
|
+
end
|
644
|
+
|
645
|
+
end
|
646
|
+
|
647
|
+
# === Description
|
648
|
+
# Object that represents an SNMP Alert.
|
649
|
+
#
|
650
|
+
class SNMPAlert
|
651
|
+
include Sanitize
|
652
|
+
|
653
|
+
# A unique name for this alert
|
654
|
+
attr_reader :name
|
655
|
+
# If this alert is enabled or not
|
656
|
+
attr_reader :enabled
|
657
|
+
# The community string
|
658
|
+
attr_reader :community
|
659
|
+
# The SNMP server to sent this alert
|
660
|
+
attr_reader :server
|
661
|
+
# The vulnerability filter to trigger the alert
|
662
|
+
attr_reader :vulnFilter
|
663
|
+
# The alert type
|
664
|
+
attr_reader :type
|
665
|
+
|
666
|
+
def initialize(name, community, server, enabled = 1)
|
667
|
+
@type = :snmp
|
668
|
+
@name = name
|
669
|
+
@community = community
|
670
|
+
@server = server
|
671
|
+
@enabled = enabled
|
672
|
+
# Sets default vuln filter - All Events
|
673
|
+
setVulnFilter(VulnFilter.new("50790400", 1))
|
674
|
+
end
|
675
|
+
|
676
|
+
# Sets the Vulnerability Filter for this alert.
|
677
|
+
def setVulnFilter(vulnFilter)
|
678
|
+
@vulnFilter = vulnFilter
|
679
|
+
end
|
680
|
+
|
681
|
+
def to_xml
|
682
|
+
xml = "<snmpAlert"
|
683
|
+
xml << %Q{ name="#{replace_entities(name)}"}
|
684
|
+
xml << %Q{ enabled="#{replace_entities(enabled)}"}
|
685
|
+
xml << %Q{ community="#{replace_entities(community)}"}
|
686
|
+
xml << %Q{ server="#{replace_entities(server)}">}
|
687
|
+
xml << vulnFilter.to_xml
|
688
|
+
xml << "</snmpAlert>"
|
689
|
+
xml
|
690
|
+
end
|
691
|
+
|
692
|
+
end
|
693
|
+
|
694
|
+
# === Description
|
695
|
+
# Object that represents an SMTP (Email) Alert.
|
696
|
+
#
|
697
|
+
class SMTPAlert
|
698
|
+
# A unique name for this alert
|
699
|
+
attr_reader :name
|
700
|
+
# If this alert is enabled or not
|
701
|
+
attr_reader :enabled
|
702
|
+
# The email address of the sender
|
703
|
+
attr_reader :sender
|
704
|
+
# Limit the text for mobile devices
|
705
|
+
attr_reader :limitText
|
706
|
+
# Array containing Strings of email addresses
|
707
|
+
# Array of strings with the email addresses of the intended recipients
|
708
|
+
attr_reader :recipients
|
709
|
+
# The vulnerability filter to trigger the alert
|
710
|
+
attr_reader :vulnFilter
|
711
|
+
# The alert type
|
712
|
+
attr_reader :type
|
713
|
+
|
714
|
+
def initialize(name, sender, limitText, enabled = 1)
|
715
|
+
@type = :smtp
|
716
|
+
@name = name
|
717
|
+
@sender = sender
|
718
|
+
@enabled = enabled
|
719
|
+
@limitText = limitText
|
720
|
+
@recipients = []
|
721
|
+
# Sets default vuln filter - All Events
|
722
|
+
setVulnFilter(VulnFilter.new("50790400", 1))
|
723
|
+
end
|
724
|
+
|
725
|
+
# Adds a new Recipient to the recipients array
|
726
|
+
def addRecipient(recipient)
|
727
|
+
@recipients.push(recipient)
|
728
|
+
end
|
729
|
+
|
730
|
+
# Sets the Vulnerability Filter for this alert.
|
731
|
+
def setVulnFilter(vulnFilter)
|
732
|
+
@vulnFilter = vulnFilter
|
733
|
+
end
|
734
|
+
|
735
|
+
include Sanitize
|
736
|
+
|
737
|
+
def to_xml
|
738
|
+
xml = "<smtpAlert"
|
739
|
+
xml << %Q{ name="#{replace_entities(name)}"}
|
740
|
+
xml << %Q{ enabled="#{replace_entities(enabled)}"}
|
741
|
+
xml << %Q{ sender="#{replace_entities(sender)}"}
|
742
|
+
xml << %Q{ limitText="#{replace_entities(limitText)}">}
|
743
|
+
recipients.each do |recpt|
|
744
|
+
xml << "<recipient>#{replace_entities(recpt)}</recipient>"
|
745
|
+
end
|
746
|
+
xml << vulnFilter.to_xml
|
747
|
+
xml << "</smtpAlert>"
|
748
|
+
xml
|
749
|
+
end
|
750
|
+
end
|
751
|
+
|
752
|
+
# === Description
|
753
|
+
# Object that represents a hostname to be added to a site.
|
754
|
+
class HostName
|
755
|
+
# Named host (usually DNS or Netbios name).
|
756
|
+
attr_accessor :host
|
757
|
+
|
758
|
+
def initialize(hostname)
|
759
|
+
@host = hostname
|
760
|
+
end
|
761
|
+
|
762
|
+
include Comparable
|
763
|
+
|
764
|
+
def <=>(other)
|
765
|
+
to_xml <=> other.to_xml
|
766
|
+
end
|
767
|
+
|
768
|
+
def eql?(other)
|
769
|
+
to_xml == other.to_xml
|
770
|
+
end
|
771
|
+
|
772
|
+
def hash
|
773
|
+
to_xml.hash
|
774
|
+
end
|
775
|
+
|
776
|
+
def to_xml_elem
|
777
|
+
xml = REXML::Element.new('host')
|
778
|
+
xml.text = @host
|
779
|
+
xml
|
780
|
+
end
|
781
|
+
|
782
|
+
def to_xml
|
783
|
+
to_xml_elem.to_s
|
784
|
+
end
|
785
|
+
end
|
786
|
+
|
787
|
+
# === Description
|
788
|
+
# Object that represents a single IP address or an inclusive range of IP addresses.
|
789
|
+
# If to is nil then the from field will be used to specify a single IP Address only.
|
790
|
+
class IPRange
|
791
|
+
|
792
|
+
# Start of range *Required
|
793
|
+
attr_accessor :from
|
794
|
+
# End of range *Optional (If nil then IPRange is a single IP Address)
|
795
|
+
attr_accessor :to
|
796
|
+
|
797
|
+
def initialize(from, to = nil)
|
798
|
+
@from = IPAddr.new(from)
|
799
|
+
@to = IPAddr.new(to) if to
|
800
|
+
end
|
801
|
+
|
802
|
+
include Comparable
|
803
|
+
|
804
|
+
def <=>(other)
|
805
|
+
to_xml <=> other.to_xml
|
806
|
+
end
|
807
|
+
|
808
|
+
def eql?(other)
|
809
|
+
to_xml == other.to_xml
|
810
|
+
end
|
811
|
+
|
812
|
+
def hash
|
813
|
+
to_xml.hash
|
814
|
+
end
|
815
|
+
|
816
|
+
def to_xml_elem
|
817
|
+
xml = REXML::Element.new('range')
|
818
|
+
xml.add_attributes({'from' => @from, 'to' => @to})
|
819
|
+
xml
|
820
|
+
end
|
821
|
+
|
822
|
+
def to_xml
|
823
|
+
to_xml_elem.to_s
|
824
|
+
end
|
825
|
+
end
|
826
|
+
end
|