mu 5.7.23 → 5.7.24
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/mu/api/muapi.rb +98 -7
- data/lib/mu/api/scale.rb +9 -5
- data/lib/mu/command/cmd_muapi.rb +79 -2
- data/lib/mu/command/cmd_runanalysis.rb +376 -0
- data/lib/mu/helper.rb +17 -0
- data/version.rb +1 -1
- metadata +83 -90
data/lib/mu/api/muapi.rb
CHANGED
@@ -2,7 +2,7 @@ class Mu
|
|
2
2
|
class Muapi
|
3
3
|
include Helper
|
4
4
|
|
5
|
-
attr_accessor :host, :docroot, :posted_uuid, :run_uuid, :job_id, :username, :password, :params, :expected_error
|
5
|
+
attr_accessor :host, :docroot, :posted_uuid, :run_uuid, :job_id, :username, :password, :params, :expected_error, :filepath
|
6
6
|
|
7
7
|
def initialize(host=ENV['MU_IP'], username=ENV['MU_ADMIN_USER'], password=ENV['MU_ADMIN_PASS'])
|
8
8
|
@host = host
|
@@ -56,6 +56,49 @@ class Muapi
|
|
56
56
|
end
|
57
57
|
return @run_uuid
|
58
58
|
end
|
59
|
+
|
60
|
+
# starts a test from a template file
|
61
|
+
# * template = the path and name of the template file that contains a single Test template
|
62
|
+
def run_from_template(template, rename="")
|
63
|
+
response = import_templates(template)
|
64
|
+
msg response, Logger::DEBUG
|
65
|
+
doc = make_xml(response)
|
66
|
+
uuid = ""
|
67
|
+
unless doc.xpath("//uuid").empty?
|
68
|
+
node = doc.at_xpath("//uuid")
|
69
|
+
uuid = node.content()
|
70
|
+
end
|
71
|
+
msg uuid, Logger::DEBUG
|
72
|
+
req = "analysis/run?uuid=#{uuid}"
|
73
|
+
unless rename.empty?
|
74
|
+
req = "#{req}&rename=#{rename}"
|
75
|
+
end
|
76
|
+
msg req, Logger::DEBUG
|
77
|
+
doc = @http.get_xml(req)
|
78
|
+
unless doc.xpath("//analysis").empty?
|
79
|
+
@run_uuid = doc.xpath("//analysis")[0].attribute('uuid')
|
80
|
+
return @run_uuid
|
81
|
+
end
|
82
|
+
return @run_uuid
|
83
|
+
end
|
84
|
+
|
85
|
+
# import templates from a file
|
86
|
+
# * template = the path and name of the template file that contains a single Test template
|
87
|
+
def import_templates(template)
|
88
|
+
# open the file and pull the contents for posting
|
89
|
+
begin
|
90
|
+
data = File.open(template,'r') {|f| f.read }
|
91
|
+
rescue Exception => e
|
92
|
+
msg "File read error for #{template}: #{e}"
|
93
|
+
return
|
94
|
+
end
|
95
|
+
|
96
|
+
# post the contents of the file
|
97
|
+
response = @http.post("templates/import",whole_file)
|
98
|
+
msg response, Logger::DEBUG
|
99
|
+
|
100
|
+
return response
|
101
|
+
end
|
59
102
|
|
60
103
|
# stops a running test
|
61
104
|
# * uuid = the uuid of the test
|
@@ -104,9 +147,9 @@ class Muapi
|
|
104
147
|
# returns a list of faults from the specified test
|
105
148
|
# * uuid = the uuid of the test
|
106
149
|
def get_faults(uuid=@run_uuid)
|
107
|
-
doc = @http.get_xml("
|
150
|
+
doc = @http.get_xml("analysis/status?uuid=#{uuid}")
|
108
151
|
unless doc.xpath("//analysis").empty?
|
109
|
-
faults = @http.get_xml("analysis/getFaultList?uuid=#{uuid}"
|
152
|
+
faults = @http.get_xml("analysis/getFaultList?uuid=#{uuid}")
|
110
153
|
return faults
|
111
154
|
end
|
112
155
|
return "error: no analysis with uuid: #{uuid} found"
|
@@ -149,16 +192,64 @@ class Muapi
|
|
149
192
|
return @http.get_xml("templates/export?uuid=#{uuid}")
|
150
193
|
end
|
151
194
|
|
152
|
-
|
195
|
+
# performs archive operations
|
153
196
|
# * command=run to create a test archive
|
154
197
|
# * command=status to view the status of a test archive job
|
155
198
|
# * command=get to download a test archive job
|
156
199
|
# * uuid = the uuid of the test
|
157
|
-
|
200
|
+
# * title = string to include as title if not empty
|
201
|
+
# * notes = string to add to notes field if not empty
|
202
|
+
# * evts = boolean to include evts, default is true
|
203
|
+
# * pcaps = boolean to include pcaps, default is true
|
204
|
+
# * samples = boolean to include samples, default is false
|
205
|
+
# * logo = boolean to include logo, default is false
|
206
|
+
# * audit = boolean to include audit, default is false
|
207
|
+
# * sign = boolean to perform sign, default is false
|
208
|
+
def archive(command="run", id=@run_uuid, filepath='.', title="", notes="", evts=true, pcaps=true, samples=false, logo=false, audit=false, sign=false)
|
158
209
|
case command
|
159
210
|
when 'run'
|
160
211
|
request_string = "archive/run?uuid=#{id}"
|
161
|
-
|
212
|
+
# not sure where the hell whis is set so I'm commenting out and running my way
|
213
|
+
#request_string += @params unless @params.nil?
|
214
|
+
# need to set title is not empty
|
215
|
+
if title != "" and title != nil
|
216
|
+
# replace all spaces with %20 and add
|
217
|
+
request_string += "&title=" + URI.encode(title)
|
218
|
+
end
|
219
|
+
# need to set notes if not empty
|
220
|
+
if notes != "" and notes != nil
|
221
|
+
# replace all spaces with %20 and add
|
222
|
+
request_string += "¬es=" + URI.encode(notes)
|
223
|
+
end
|
224
|
+
tmpS = ""
|
225
|
+
# do we need to add evts
|
226
|
+
if evts
|
227
|
+
tmpS += "evts,"
|
228
|
+
end
|
229
|
+
# do we need need to add pcaps
|
230
|
+
if pcaps
|
231
|
+
tmpS += "pcaps,"
|
232
|
+
end
|
233
|
+
# do we need need to add sample pcaps
|
234
|
+
if samples
|
235
|
+
tmpS += "samples,"
|
236
|
+
end
|
237
|
+
# do we need need to add logo
|
238
|
+
if logo
|
239
|
+
tmpS += "logo,"
|
240
|
+
end
|
241
|
+
# do we need need to add audit
|
242
|
+
if audit
|
243
|
+
tmpS += "audit"
|
244
|
+
end
|
245
|
+
if tmpS != ""
|
246
|
+
request_string += "&include="+tmpS
|
247
|
+
end
|
248
|
+
# do we need need to sign
|
249
|
+
if sign
|
250
|
+
request_string += "&sign"
|
251
|
+
end
|
252
|
+
msg request_string, Logger::DEBUG
|
162
253
|
doc = @http.get_xml(request_string)
|
163
254
|
unless doc.xpath("//job").empty?
|
164
255
|
@job_id = doc.xpath("//job")[0].attribute('id')
|
@@ -178,7 +269,7 @@ class Muapi
|
|
178
269
|
end
|
179
270
|
return false
|
180
271
|
end
|
181
|
-
|
272
|
+
|
182
273
|
# performs backup operations
|
183
274
|
# * command=run to create a system backup file.
|
184
275
|
# * command=status to view the status of a backup job. If no backup job is running, gets the date of the most recent backup.
|
data/lib/mu/api/scale.rb
CHANGED
@@ -55,11 +55,15 @@ class Scale
|
|
55
55
|
# * param = the parameter to configure (e.g. volume)
|
56
56
|
# * value = the parameter's value ( e.g. 100)
|
57
57
|
def configure(param, value)
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
58
|
+
begin
|
59
|
+
if param == "pattern" and value.is_a?(String)
|
60
|
+
value = JSON.parse(value)
|
61
|
+
end
|
62
|
+
@configuration[param] = value
|
63
|
+
File.open(@config_file,'w'){|f| f.write(JSON.pretty_generate(@configuration))}
|
64
|
+
rescue => e
|
65
|
+
raise "Something is wrong with the JSON parsing or generation:#{e} backtrace:#{e.backtrace}"
|
66
|
+
end
|
63
67
|
end
|
64
68
|
|
65
69
|
# starts a scale test with the class @configuration object
|
data/lib/mu/command/cmd_muapi.rb
CHANGED
@@ -53,6 +53,33 @@ class Cmd_muapi < Command
|
|
53
53
|
msg response
|
54
54
|
return response
|
55
55
|
end
|
56
|
+
|
57
|
+
# runs an analysis, reference is the posted uuid
|
58
|
+
# ex: cmd_run_template("/path/my_template_file.xml", "my_new_name_for_test")
|
59
|
+
# * argv = command-line arguments, requires a template file (-f) and an optional name such that each successive run of the same uuid yields a new name
|
60
|
+
def cmd_run_template argv
|
61
|
+
setup argv
|
62
|
+
filepath = @hash['filepath']
|
63
|
+
if @hash['boolean'].nil?
|
64
|
+
rename = ""
|
65
|
+
else
|
66
|
+
rename = @hash['boolean']
|
67
|
+
end
|
68
|
+
response = @api.run_from_template(filepath, rename)
|
69
|
+
msg response
|
70
|
+
return response
|
71
|
+
end
|
72
|
+
|
73
|
+
# imports xml templates,
|
74
|
+
# ex: import_templates("/path/my_template_file.xml")
|
75
|
+
# * argv = command-line arguments, requires a template file (-f)
|
76
|
+
def cmd_import_templates argv
|
77
|
+
setup argv
|
78
|
+
template_file = @hash['filepath']
|
79
|
+
response = @api.import_templates(template_file)
|
80
|
+
msg response
|
81
|
+
return response
|
82
|
+
end
|
56
83
|
|
57
84
|
# aborts a running analysis. the next queued analysis will start
|
58
85
|
# * argv = command-line arguments, requires a uuid (-u) argument specifying the test
|
@@ -178,7 +205,43 @@ class Cmd_muapi < Command
|
|
178
205
|
setup argv
|
179
206
|
command = @hash['command']
|
180
207
|
job_id = @hash['uuid']
|
181
|
-
|
208
|
+
includes = @hash['include']
|
209
|
+
filepath = @hash['filepath']
|
210
|
+
if filepath==nil
|
211
|
+
filepath = "."
|
212
|
+
end
|
213
|
+
notes,title=""
|
214
|
+
pcaps,evts = true
|
215
|
+
sign,logo,samples,audit = false
|
216
|
+
if includes!=nil
|
217
|
+
pcaps,evts = false
|
218
|
+
includes.split(",").each do | option |
|
219
|
+
if option=="pcaps"
|
220
|
+
pcaps=true
|
221
|
+
elsif option=="evts"
|
222
|
+
evts = true
|
223
|
+
elsif option=="sign"
|
224
|
+
sign = true
|
225
|
+
elsif option=="logo"
|
226
|
+
logo = true
|
227
|
+
elsif option=="samples"
|
228
|
+
samples = true
|
229
|
+
elsif option=="audit"
|
230
|
+
audit = true
|
231
|
+
elsif option.match(/^notes=/)
|
232
|
+
matches = option.match(/^notes=(.+)/)
|
233
|
+
if matches!=nil
|
234
|
+
notes = matches[1]
|
235
|
+
end
|
236
|
+
elsif option.match(/^title=/)
|
237
|
+
matches = option.match(/^title=(.+)/)
|
238
|
+
if matches!=nil
|
239
|
+
title = matches[1]
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
response = @api.archive(command, job_id, filepath, title, notes, evts, pcaps, samples, logo, audit, sign)
|
182
245
|
msg response
|
183
246
|
return response
|
184
247
|
end
|
@@ -254,6 +317,11 @@ private
|
|
254
317
|
help
|
255
318
|
exit
|
256
319
|
end
|
320
|
+
|
321
|
+
if [ '-i', '--include' ].member? k
|
322
|
+
@hash['include'] = shift(k, argv)
|
323
|
+
next
|
324
|
+
end
|
257
325
|
|
258
326
|
if [ '-m', '--mu_string' ].member? k
|
259
327
|
mu_string = shift(k, argv)
|
@@ -294,6 +362,11 @@ private
|
|
294
362
|
@hash['uuid'] = shift(k, argv)
|
295
363
|
next
|
296
364
|
end
|
365
|
+
|
366
|
+
if [ '-f', '--filepath' ].member? k
|
367
|
+
@hash['filepath'] = shift(k, argv)
|
368
|
+
next
|
369
|
+
end
|
297
370
|
|
298
371
|
if [ '-v', '--verbose' ].member? k
|
299
372
|
$log.level = Logger::DEBUG
|
@@ -308,7 +381,9 @@ private
|
|
308
381
|
helps = [
|
309
382
|
{ :short => '-b', :long => '--boolean', :value => '<string>', :help => 'boolean arg' },
|
310
383
|
{ :short => '-c', :long => '--command', :value => '<string>', :help => 'e.g. run|get|status' },
|
384
|
+
{ :short => '-f', :long => '--filepath', :value => '', :help => 'the template file to run' },
|
311
385
|
{ :short => '-h', :long => '--help', :value => '', :help => 'help on command line options' },
|
386
|
+
{ :short => '-i', :long => '--include', :value => '<string>', :help => 'comma separated list of options to include' },
|
312
387
|
{ :short => '-m', :long => '--mu_string', :value => '<string>', :help => 'user, password, mu_ip in the form of admin:admin@10.9.8.7' },
|
313
388
|
{ :short => '-n', :long => '--name', :value => '<string>', :help => 'name for filtering' },
|
314
389
|
{ :short => '-o', :long => '--output', :value => '<string>', :help => 'output logging to this file' },
|
@@ -320,7 +395,7 @@ private
|
|
320
395
|
]
|
321
396
|
|
322
397
|
cmds = [
|
323
|
-
"mu cmd_muapi:archive -c <command> -u <uuid>",
|
398
|
+
"mu cmd_muapi:archive -c <command> -u <uuid> -i <notes=\"my notes\",title=\"my title\",pcaps,evts,samples,audit,logo,sign>",
|
324
399
|
"mu cmd_muapi:backup -c <command> [-n <name>]",
|
325
400
|
"mu cmd_muapi:capture -c <command> -p <port> [-u <uuid>]",
|
326
401
|
"mu cmd_muapi:delete -u <uuid>",
|
@@ -329,11 +404,13 @@ private
|
|
329
404
|
"mu cmd_muapi:get_faults -u <uuid>",
|
330
405
|
"mu cmd_muapi:get_name -u <uuid>",
|
331
406
|
"mu cmd_muapi:help",
|
407
|
+
"mu cmd_muapi:import_templates -f <my_template_file>",
|
332
408
|
"mu cmd_muapi:list -t <type>",
|
333
409
|
"mu cmd_muapi:list_by_status -s <status>",
|
334
410
|
"mu cmd_muapi:pause -u <uuid>",
|
335
411
|
"mu cmd_muapi:resume -u <uuid>",
|
336
412
|
"mu cmd_muapi:run -u <uuid> [-b rename]",
|
413
|
+
"mu cmd_muapi:run_template -f <filepath> [-b rename]",
|
337
414
|
"mu cmd_muapi:status -u <uuid>",
|
338
415
|
"mu cmd_muapi:stop -u <uuid>",
|
339
416
|
"mu cmd_muapi:types",
|
@@ -0,0 +1,376 @@
|
|
1
|
+
# Use these commands to access the legacy REST API for Test Runs (Protocol Mutation, Scenario Mutation).
|
2
|
+
|
3
|
+
require 'mu/api/muapi'
|
4
|
+
class Mu
|
5
|
+
class Command
|
6
|
+
class Cmd_runfuzz < Command
|
7
|
+
|
8
|
+
attr_accessor :host, :username, :password, :api, :docroot
|
9
|
+
|
10
|
+
# displays command-line help
|
11
|
+
# * argv = command-line arguments
|
12
|
+
def cmd_help argv
|
13
|
+
help
|
14
|
+
end
|
15
|
+
|
16
|
+
# capture has a set of three commands that are used to generate
|
17
|
+
# packet captures, poll the status and return the resulting file
|
18
|
+
# ex:
|
19
|
+
# * argv = command-line arguments, requires a command (-c) argument
|
20
|
+
# * command=run returns the job_id
|
21
|
+
# * command=status (called after 'run'), requires the job_id (-u) argument
|
22
|
+
# * command=get (called when status returns "Finished"), requires the job_id (-u) argument
|
23
|
+
# * port = the Mu interface on which to capture packets
|
24
|
+
def cmd_run argv
|
25
|
+
setup argv
|
26
|
+
# set all aparms
|
27
|
+
archive = @hash['archive']
|
28
|
+
directory = @hash['directory']
|
29
|
+
force = @hash['force']
|
30
|
+
interval = @hash['interval']
|
31
|
+
output = @hash['output']
|
32
|
+
prepend = @hash['prepend']
|
33
|
+
template = @hash['template']
|
34
|
+
uuid = @hash['uuid']
|
35
|
+
|
36
|
+
# set any timers to minimum non psychotic numbers
|
37
|
+
sleeptime = 10 # 10 sec
|
38
|
+
if force != nil
|
39
|
+
force = Integer(force)
|
40
|
+
if force < 1
|
41
|
+
force = 1
|
42
|
+
end
|
43
|
+
else
|
44
|
+
force = 0
|
45
|
+
end
|
46
|
+
if interval != nil
|
47
|
+
interval = Integer(interval)
|
48
|
+
if interval < 5
|
49
|
+
interval = 5
|
50
|
+
end
|
51
|
+
if interval < sleeptime
|
52
|
+
sleeptime = interval
|
53
|
+
end
|
54
|
+
else
|
55
|
+
interval = 0
|
56
|
+
end
|
57
|
+
|
58
|
+
# my_uuid_hash is a hash that will contain the name, and uuid of the test to run my_name => my_uuid
|
59
|
+
my_uuid_hash = {}
|
60
|
+
|
61
|
+
# determine proper execution path: uuid, template, or directory
|
62
|
+
if directory != nil
|
63
|
+
# load all xml files in directory and add uuids to execution list
|
64
|
+
files = Dir.glob(File.join(@hash["directory"],"","*.xml"))
|
65
|
+
files.each do | file |
|
66
|
+
response = @api.import_templates(file)
|
67
|
+
msg response, Logger::DEBUG
|
68
|
+
doc = make_xml(response)
|
69
|
+
unless doc.xpath("//model_object").empty?
|
70
|
+
doc.xpath("//model_object").each do |node|
|
71
|
+
my_uuid = node.xpath("uuid").text
|
72
|
+
my_name = node.xpath("name").text
|
73
|
+
my_type = node.xpath("type").text
|
74
|
+
if my_type=="Analysis"
|
75
|
+
msg "type = #{my_type} uuid = #{my_uuid} name = #{my_name}", Logger::DEBUG
|
76
|
+
my_uuid_hash[my_uuid] = my_name
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
if template != nil
|
83
|
+
# import template file into mu and add all uuids to list
|
84
|
+
response = @api.import_templates(template)
|
85
|
+
msg response, Logger::DEBUG
|
86
|
+
doc = make_xml(response)
|
87
|
+
unless doc.xpath("//model_object").empty?
|
88
|
+
doc.xpath("//model_object").each do |node|
|
89
|
+
my_uuid = node.xpath("uuid").text
|
90
|
+
my_name = node.xpath("name").text
|
91
|
+
my_type = node.xpath("type").text
|
92
|
+
if my_type=="Analysis"
|
93
|
+
msg "type = #{my_type} uuid = #{my_uuid} name = #{my_name}", Logger::DEBUG
|
94
|
+
my_uuid_hash[my_uuid] = my_name
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
if uuid != nil
|
100
|
+
# add all uuids to list
|
101
|
+
if uuid =~ /,/
|
102
|
+
list = uuid.split(",")
|
103
|
+
list.each do | my_uuid |
|
104
|
+
response = @api.get_name(my_uuid)
|
105
|
+
my_uuid_hash[my_uuid] = response
|
106
|
+
end
|
107
|
+
else
|
108
|
+
# add single uuid to list
|
109
|
+
response = @api.get_name(uuid)
|
110
|
+
my_uuid_hash[uuid] = response
|
111
|
+
end
|
112
|
+
end
|
113
|
+
if my_uuid_hash.empty?
|
114
|
+
msg "no valid test option selected, please specify directory, template file, or uuid"
|
115
|
+
help
|
116
|
+
exit
|
117
|
+
end
|
118
|
+
|
119
|
+
# now we run all the tests
|
120
|
+
#msg "RUNNING"
|
121
|
+
results = {}
|
122
|
+
map = my_uuid_hash.each_pair do |key,value|
|
123
|
+
t1 = Time.now.localtime.tv_sec
|
124
|
+
confidence_level_5,confidence_level_4,confidence_level_3,confidence_level_2,confidence_level_1 = 0, 0, 0, 0, 0
|
125
|
+
suspend_time = t1
|
126
|
+
polling_time = t1
|
127
|
+
if prepend != nil
|
128
|
+
name = "#{prepend} #{value}"
|
129
|
+
else
|
130
|
+
name = value
|
131
|
+
end
|
132
|
+
msg "my name = #{name} with uuid = #{key}"
|
133
|
+
run = true
|
134
|
+
run_uuid = @api.run(key, URI.encode(name))
|
135
|
+
while run
|
136
|
+
sleep(sleeptime)
|
137
|
+
status = @api.status(run_uuid)
|
138
|
+
msg status
|
139
|
+
t2 = Time.now.localtime.tv_sec
|
140
|
+
msg t2-t1
|
141
|
+
if interval > 0
|
142
|
+
if t2-polling_time > interval
|
143
|
+
faults = @api.get_faults(run_uuid)
|
144
|
+
msg faults, Logger::DEBUG
|
145
|
+
# faults should be an xml doc already
|
146
|
+
unless faults.xpath("//fault_list_summary").empty?
|
147
|
+
count = 0
|
148
|
+
confidence_level_5,confidence_level_4,confidence_level_3,confidence_level_2,confidence_level_1 = 0, 0, 0, 0, 0
|
149
|
+
faults.xpath("//tba_fault").each do | node |
|
150
|
+
count += 1
|
151
|
+
confidence_level = node.xpath("confidence_level").text
|
152
|
+
title = node.xpath("title").text
|
153
|
+
fault_detection = node.xpath("fault_detection").text
|
154
|
+
fault_isolation = node.xpath("fault_isolation").text
|
155
|
+
attack_type = node.xpath("attack_type").text
|
156
|
+
if confidence_level =~ /5/
|
157
|
+
confidence_level_5 += 1
|
158
|
+
elsif confidence_level =~ /4/
|
159
|
+
confidence_level_4 += 1
|
160
|
+
elsif confidence_level =~ /3/
|
161
|
+
confidence_level_3 += 1
|
162
|
+
elsif confidence_level =~ /2/
|
163
|
+
confidence_level_2 += 1
|
164
|
+
elsif confidence_level =~ /1/
|
165
|
+
confidence_level_1 += 1
|
166
|
+
end
|
167
|
+
end
|
168
|
+
msg "Current fault count: #{count}, confidence_level 5: #{confidence_level_5}"+
|
169
|
+
", confidence_level 4: #{confidence_level_4}, confidence_level 3: #{confidence_level_3}"+
|
170
|
+
", confidence_level 2: #{confidence_level_2}, confidence_level 1: #{confidence_level_1}"
|
171
|
+
end
|
172
|
+
polling_time = Time.now.localtime.tv_sec
|
173
|
+
end
|
174
|
+
end
|
175
|
+
if status =~ /ABORTED/ or status =~ /FINISHED/ or status =~ /FAILED/
|
176
|
+
run = false
|
177
|
+
elsif status =~ /SUSPENDED/
|
178
|
+
msg "SUSPEND--->"
|
179
|
+
if t2-suspend_time > force*60
|
180
|
+
response = @api.resume(run_uuid)
|
181
|
+
msg response
|
182
|
+
suspend_time = Time.now.localtime.tv_sec
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
# now we pull results for run and tabulate fault list
|
187
|
+
job_id = @api.archive("run",run_uuid,"",name,"Run via Mu Ruby Gem API #{Time.now}",true,true,true,false,false,false)
|
188
|
+
job = true
|
189
|
+
count = 0
|
190
|
+
while job
|
191
|
+
job_status = @api.archive("status", job_id)
|
192
|
+
msg "job_status = #{job_status}"
|
193
|
+
if job_status =~ /Finished/
|
194
|
+
job = false
|
195
|
+
end
|
196
|
+
sleep(sleeptime)
|
197
|
+
count += 1
|
198
|
+
if count > 30
|
199
|
+
job = false
|
200
|
+
end
|
201
|
+
end
|
202
|
+
if Dir[name] == nil
|
203
|
+
Dir.mkdir(name)
|
204
|
+
end
|
205
|
+
response = @api.archive("get",job_id,name)
|
206
|
+
faults = @api.get_faults(run_uuid)
|
207
|
+
msg faults, Logger::DEBUG
|
208
|
+
# faults should be an xml doc already
|
209
|
+
unless faults.xpath("//fault_list_summary").empty?
|
210
|
+
count = 0
|
211
|
+
confidence_level_5,confidence_level_4,confidence_level_3,confidence_level_2,confidence_level_1 = 0, 0, 0, 0, 0
|
212
|
+
faults.xpath("//tba_fault").each do | node |
|
213
|
+
count += 1
|
214
|
+
confidence_level = node.xpath("confidence_level").text
|
215
|
+
title = node.xpath("title").text
|
216
|
+
fault_detection = node.xpath("fault_detection").text
|
217
|
+
fault_isolation = node.xpath("fault_isolation").text
|
218
|
+
attack_type = node.xpath("attack_type").text
|
219
|
+
if confidence_level =~ /5/
|
220
|
+
confidence_level_5 += 1
|
221
|
+
elsif confidence_level =~ /4/
|
222
|
+
confidence_level_4 += 1
|
223
|
+
elsif confidence_level =~ /3/
|
224
|
+
confidence_level_3 += 1
|
225
|
+
elsif confidence_level =~ /2/
|
226
|
+
confidence_level_2 += 1
|
227
|
+
elsif confidence_level =~ /1/
|
228
|
+
confidence_level_1 += 1
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
msg "Ending fault countfor #{name}: #{count}, confidence_level 5: #{confidence_level_5}"+
|
233
|
+
", confidence_level 4: #{confidence_level_4}, confidence_level 3: #{confidence_level_3}"+
|
234
|
+
", confidence_level 2: #{confidence_level_2}, confidence_level 1: #{confidence_level_1}"
|
235
|
+
end
|
236
|
+
end
|
237
|
+
#response = @api.capture(command, port, job_id)
|
238
|
+
|
239
|
+
return "RUN"
|
240
|
+
end
|
241
|
+
|
242
|
+
private
|
243
|
+
|
244
|
+
|
245
|
+
def setup argv
|
246
|
+
parse_cli argv
|
247
|
+
@host = (@@mu_ip.nil?) ? "127.0.0.1" : @@mu_ip
|
248
|
+
@username = (@@mu_admin_user.nil?) ? "admin" : @@mu_admin_user
|
249
|
+
@password = (@@mu_admin_pass.nil?) ? "admin" : @@mu_admin_pass
|
250
|
+
@docroot = "/api/v3"
|
251
|
+
@params = nil
|
252
|
+
@expected_error = nil
|
253
|
+
@api = Muapi.new(@host, @username, @password)
|
254
|
+
msg "Created API object to :#{@host}", Logger::DEBUG
|
255
|
+
end
|
256
|
+
|
257
|
+
def parse_cli argv
|
258
|
+
args = Array.new
|
259
|
+
@hash = Hash.new
|
260
|
+
while not argv.empty?
|
261
|
+
args << argv.shift if argv.first[0,1] != '-'
|
262
|
+
|
263
|
+
k = argv.shift
|
264
|
+
|
265
|
+
if [ '-a', '--archive' ].member? k
|
266
|
+
@hash['archive'] = shift(k, argv)
|
267
|
+
next
|
268
|
+
end
|
269
|
+
|
270
|
+
if [ '-d', '--dir' ].member? k
|
271
|
+
@hash['directory'] = shift(k, argv)
|
272
|
+
next
|
273
|
+
end
|
274
|
+
|
275
|
+
if [ '-f', '--force' ].member? k
|
276
|
+
@hash['force'] = shift(k, argv)
|
277
|
+
next
|
278
|
+
end
|
279
|
+
|
280
|
+
if [ '-h', '--help' ].member? k
|
281
|
+
help
|
282
|
+
exit
|
283
|
+
end
|
284
|
+
|
285
|
+
if [ '-i', '--interval' ].member? k
|
286
|
+
@hash['interval'] = shift(k, argv)
|
287
|
+
next
|
288
|
+
end
|
289
|
+
|
290
|
+
if [ '-m', '--mu_string' ].member? k
|
291
|
+
mu_string = shift(k, argv)
|
292
|
+
if mu_string =~ /(.+?):(.+?)@(.*)/
|
293
|
+
@@mu_admin_user = $1
|
294
|
+
@@mu_admin_pass = $2
|
295
|
+
@@mu_ip = $3
|
296
|
+
end
|
297
|
+
next
|
298
|
+
end
|
299
|
+
|
300
|
+
if [ '-n', '--name' ].member? k
|
301
|
+
@hash['name'] = shift(k, argv)
|
302
|
+
next
|
303
|
+
end
|
304
|
+
|
305
|
+
if [ '-o', '--output' ].member? k
|
306
|
+
$stdout.reopen(shift(k, argv), "w")
|
307
|
+
next
|
308
|
+
end
|
309
|
+
|
310
|
+
if [ '-p', '--prepend' ].member? k
|
311
|
+
@hash['prepend'] = shift(k, argv)
|
312
|
+
next
|
313
|
+
end
|
314
|
+
|
315
|
+
if [ '-t', '--template' ].member? k
|
316
|
+
@hash['template'] = shift(k, argv)
|
317
|
+
next
|
318
|
+
end
|
319
|
+
|
320
|
+
if [ '-u', '--uuid' ].member? k
|
321
|
+
@hash['uuid'] = shift(k, argv)
|
322
|
+
next
|
323
|
+
end
|
324
|
+
|
325
|
+
if [ '-v', '--verbose' ].member? k
|
326
|
+
$log.level = Logger::DEBUG
|
327
|
+
next
|
328
|
+
end
|
329
|
+
msg "Unknown argument #{k}"
|
330
|
+
help
|
331
|
+
exit
|
332
|
+
|
333
|
+
end
|
334
|
+
|
335
|
+
args
|
336
|
+
end
|
337
|
+
|
338
|
+
def help
|
339
|
+
helps = [
|
340
|
+
{ :short => '-a', :long => '--archive', :value => '<string>', :help => 'collect all archive result files with comma separated options list, pcaps and evts on by default' },
|
341
|
+
{ :short => '-d', :long => '--dir', :value => '<string>', :help => 'directory containing the scenario files' },
|
342
|
+
{ :short => '-f', :long => '--force', :value => '<integer>', :help => 'force resume on pause after time elapse in min' },
|
343
|
+
{ :short => '-h', :long => '--help', :value => '', :help => 'help on command line options' },
|
344
|
+
{ :short => '-i', :long => '--interval', :value => '<integer>', :help => 'execute fault status update at intervalin seconds. minimum = 5' },
|
345
|
+
{ :short => '-m', :long => '--mu_string', :value => '<string>', :help => 'user, password, mu_ip in the form of admin:admin@10.9.8.7' },
|
346
|
+
{ :short => '-o', :long => '--output', :value => '<string>', :help => 'output logging to this file' },
|
347
|
+
{ :short => '-p', :long => '--prepend', :value => '<string>', :help => 'prepend test name with <string>' },
|
348
|
+
{ :short => '-t', :long => '--template', :value => '', :help => 'the template file to run' },
|
349
|
+
{ :short => '-u', :long => '--uuid', :value => '<string>', :help => 'comma seperated uuid list of template uuids' },
|
350
|
+
{ :short => '-v', :long => '--verbose', :value => '', :help => 'set Logger::DEBUG level' }
|
351
|
+
]
|
352
|
+
|
353
|
+
cmds = [
|
354
|
+
"mu cmd_runfuzz:run -f <string /path/my-template-name.xml> -p <string> -a <string pcaps,evts,samples,logo,audit,sign ",
|
355
|
+
]
|
356
|
+
|
357
|
+
max_long_size = helps.inject(0) { |memo, obj| [ obj[:long].size, memo ].max }
|
358
|
+
max_value_size = helps.inject(0) { |memo, obj| [ obj[:value].size, memo ].max }
|
359
|
+
puts
|
360
|
+
puts "Usage: mu cmd_runfuzz <options>"
|
361
|
+
puts
|
362
|
+
helps.each do |h|
|
363
|
+
puts "%-*s %*s %-*s %s" % [max_long_size, h[:long], 2, h[:short], max_value_size, h[:value], h[:help]]
|
364
|
+
end
|
365
|
+
puts
|
366
|
+
puts "Available Commands"
|
367
|
+
puts
|
368
|
+
cmds.each do | c |
|
369
|
+
puts c
|
370
|
+
end
|
371
|
+
puts
|
372
|
+
end
|
373
|
+
|
374
|
+
end
|
375
|
+
end # Command
|
376
|
+
end # Mu
|
data/lib/mu/helper.rb
CHANGED
@@ -51,5 +51,22 @@ module Helper
|
|
51
51
|
return arr
|
52
52
|
end
|
53
53
|
|
54
|
+
def make_xml(resp)
|
55
|
+
begin
|
56
|
+
if (/<.+>/).match(resp)
|
57
|
+
xmldoc = Nokogiri::XML(resp)
|
58
|
+
else
|
59
|
+
err_node = Nokogiri::XML::Node.new('err_node', xmldoc)
|
60
|
+
err_node.content = resp
|
61
|
+
xmldoc.root << err_node
|
62
|
+
end
|
63
|
+
rescue => e
|
64
|
+
msg "Error parsing XML " + e.to_s, Logger::DEBUG
|
65
|
+
ensure
|
66
|
+
msg xmldoc, Logger::DEBUG
|
67
|
+
return xmldoc
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
54
71
|
end
|
55
72
|
end # Mu
|
data/version.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
VERSION='5.7.
|
1
|
+
VERSION='5.7.24'
|
metadata
CHANGED
@@ -1,125 +1,122 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: mu
|
3
|
-
version: !ruby/object:Gem::Version
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 5.7.24
|
4
5
|
prerelease:
|
5
|
-
version: 5.7.23
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
7
|
+
authors:
|
8
8
|
- MuEng
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
|
13
|
-
date: 2011-05-13 00:00:00 -07:00
|
12
|
+
date: 2011-05-16 00:00:00.000000000 -07:00
|
14
13
|
default_executable:
|
15
|
-
dependencies:
|
16
|
-
- !ruby/object:Gem::Dependency
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
17
16
|
name: nokogiri
|
18
|
-
|
19
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
17
|
+
requirement: &21267240 !ruby/object:Gem::Requirement
|
20
18
|
none: false
|
21
|
-
requirements:
|
22
|
-
- -
|
23
|
-
- !ruby/object:Gem::Version
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
24
22
|
version: 1.4.4
|
25
23
|
type: :runtime
|
26
|
-
version_requirements: *id001
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: rest-client
|
29
24
|
prerelease: false
|
30
|
-
|
25
|
+
version_requirements: *21267240
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: rest-client
|
28
|
+
requirement: &21266780 !ruby/object:Gem::Requirement
|
31
29
|
none: false
|
32
|
-
requirements:
|
33
|
-
- -
|
34
|
-
- !ruby/object:Gem::Version
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
35
33
|
version: 1.6.1
|
36
34
|
type: :runtime
|
37
|
-
version_requirements: *id002
|
38
|
-
- !ruby/object:Gem::Dependency
|
39
|
-
name: mime-types
|
40
35
|
prerelease: false
|
41
|
-
|
36
|
+
version_requirements: *21266780
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: mime-types
|
39
|
+
requirement: &21266320 !ruby/object:Gem::Requirement
|
42
40
|
none: false
|
43
|
-
requirements:
|
44
|
-
- -
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version:
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '1.16'
|
47
45
|
type: :runtime
|
48
|
-
version_requirements: *id003
|
49
|
-
- !ruby/object:Gem::Dependency
|
50
|
-
name: json
|
51
46
|
prerelease: false
|
52
|
-
|
47
|
+
version_requirements: *21266320
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: json
|
50
|
+
requirement: &21265940 !ruby/object:Gem::Requirement
|
53
51
|
none: false
|
54
|
-
requirements:
|
55
|
-
- -
|
56
|
-
- !ruby/object:Gem::Version
|
57
|
-
version:
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
58
56
|
type: :runtime
|
59
|
-
version_requirements: *id004
|
60
|
-
- !ruby/object:Gem::Dependency
|
61
|
-
name: hexy
|
62
57
|
prerelease: false
|
63
|
-
|
58
|
+
version_requirements: *21265940
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: hexy
|
61
|
+
requirement: &21295160 !ruby/object:Gem::Requirement
|
64
62
|
none: false
|
65
|
-
requirements:
|
66
|
-
- -
|
67
|
-
- !ruby/object:Gem::Version
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
68
66
|
version: 0.1.1
|
69
67
|
type: :runtime
|
70
|
-
version_requirements: *id005
|
71
|
-
- !ruby/object:Gem::Dependency
|
72
|
-
name: uuid
|
73
68
|
prerelease: false
|
74
|
-
|
69
|
+
version_requirements: *21295160
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: uuid
|
72
|
+
requirement: &21294660 !ruby/object:Gem::Requirement
|
75
73
|
none: false
|
76
|
-
requirements:
|
77
|
-
- -
|
78
|
-
- !ruby/object:Gem::Version
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
79
77
|
version: 2.0.2
|
80
78
|
type: :runtime
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
email:
|
79
|
+
prerelease: false
|
80
|
+
version_requirements: *21294660
|
81
|
+
description: ! "The Mu gem allows users to include mu libraries within scripts\n that
|
82
|
+
interact with mu appliance software. The gem also supplies command line interfaces\n
|
83
|
+
\ to many of these same libraries"
|
84
|
+
email:
|
87
85
|
- info@mudynamics.com
|
88
|
-
executables:
|
86
|
+
executables:
|
89
87
|
- mu
|
90
88
|
extensions: []
|
91
|
-
|
92
89
|
extra_rdoc_files: []
|
93
|
-
|
94
|
-
|
95
|
-
- lib/mu/
|
96
|
-
- lib/mu/
|
97
|
-
- lib/mu/
|
90
|
+
files:
|
91
|
+
- lib/mu.rb
|
92
|
+
- lib/mu/har.rb
|
93
|
+
- lib/mu/http_helper.rb
|
94
|
+
- lib/mu/client.rb
|
98
95
|
- lib/mu/api/netconfig.rb
|
99
|
-
- lib/mu/api/
|
96
|
+
- lib/mu/api/muapi.rb
|
97
|
+
- lib/mu/api/homepage.rb
|
100
98
|
- lib/mu/api/system.rb
|
101
|
-
- lib/mu/
|
99
|
+
- lib/mu/api/scale.rb
|
100
|
+
- lib/mu/api/ddt.rb
|
101
|
+
- lib/mu/helper.rb
|
102
|
+
- lib/mu/maker.rb
|
103
|
+
- lib/mu/command/cmd_homepage.rb
|
102
104
|
- lib/mu/command/api.rb
|
103
105
|
- lib/mu/command/cmd_ddt.rb
|
104
|
-
- lib/mu/command/
|
106
|
+
- lib/mu/command/cmd_scale.rb
|
107
|
+
- lib/mu/command/curl.rb
|
105
108
|
- lib/mu/command/cmd_muapi.rb
|
109
|
+
- lib/mu/command/help.rb
|
106
110
|
- lib/mu/command/cmd_musl.rb
|
107
|
-
- lib/mu/command/
|
111
|
+
- lib/mu/command/cmd_system.rb
|
108
112
|
- lib/mu/command/cmd_runscale.rb
|
109
113
|
- lib/mu/command/cmd_runscenario.rb
|
114
|
+
- lib/mu/command/cmd_runanalysis.rb
|
115
|
+
- lib/mu/command/cmd_netconfig.rb
|
110
116
|
- lib/mu/command/cmd_runverify.rb
|
111
|
-
- lib/mu/command/cmd_scale.rb
|
112
|
-
- lib/mu/command/cmd_system.rb
|
113
|
-
- lib/mu/command/curl.rb
|
114
|
-
- lib/mu/command/help.rb
|
115
117
|
- lib/mu/command.rb
|
116
118
|
- lib/mu/curl/error.rb
|
117
119
|
- lib/mu/curl/verify.rb
|
118
|
-
- lib/mu/har.rb
|
119
|
-
- lib/mu/helper.rb
|
120
|
-
- lib/mu/http_helper.rb
|
121
|
-
- lib/mu/maker.rb
|
122
|
-
- lib/mu.rb
|
123
120
|
- bin/mu
|
124
121
|
- Mu_Gem.html
|
125
122
|
- version.rb
|
@@ -128,30 +125,26 @@ files:
|
|
128
125
|
has_rdoc: true
|
129
126
|
homepage: http://www.mudynamics.com
|
130
127
|
licenses: []
|
131
|
-
|
132
128
|
post_install_message:
|
133
129
|
rdoc_options: []
|
134
|
-
|
135
|
-
require_paths:
|
130
|
+
require_paths:
|
136
131
|
- lib
|
137
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
132
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
138
133
|
none: false
|
139
|
-
requirements:
|
140
|
-
- -
|
141
|
-
- !ruby/object:Gem::Version
|
134
|
+
requirements:
|
135
|
+
- - ! '>='
|
136
|
+
- !ruby/object:Gem::Version
|
142
137
|
version: 1.8.7
|
143
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
144
139
|
none: false
|
145
|
-
requirements:
|
146
|
-
- -
|
147
|
-
- !ruby/object:Gem::Version
|
148
|
-
version:
|
140
|
+
requirements:
|
141
|
+
- - ! '>='
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
149
144
|
requirements: []
|
150
|
-
|
151
145
|
rubyforge_project:
|
152
146
|
rubygems_version: 1.6.2
|
153
147
|
signing_key:
|
154
148
|
specification_version: 3
|
155
149
|
summary: Mu Dynamics General Purpose Library and Command Line Tool
|
156
150
|
test_files: []
|
157
|
-
|