Class: Arachni::Reporters::XML

Inherits:
Arachni::Reporter::Base show all
Defined in:
components/reporters/plugin_formatters/xml/vector_collector.rb,
components/reporters/plugin_formatters/xml/uncommon_headers.rb,
components/reporters/plugin_formatters/xml/cookie_collector.rb,
components/reporters/plugin_formatters/xml/http_dicattack.rb,
components/reporters/plugin_formatters/xml/form_dicattack.rb,
components/reporters/plugin_formatters/xml/content_types.rb,
components/reporters/plugin_formatters/xml/waf_detector.rb,
components/reporters/plugin_formatters/xml/login_script.rb,
components/reporters/plugin_formatters/xml/uniformity.rb,
components/reporters/plugin_formatters/xml/healthmap.rb,
components/reporters/plugin_formatters/xml/autologin.rb,
components/reporters/plugin_formatters/xml/metrics.rb,
components/reporters/plugin_formatters/xml/exec.rb,
components/reporters/xml.rb

Overview

Creates an XML report of the audit.

Author:

Constant Summary collapse

LOCAL_SCHEMA =
File.dirname( __FILE__ ) + '/xml/schema.xsd'
REMOTE_SCHEMA =
'https://raw.githubusercontent.com/Arachni/arachni/' <<
"v#{Arachni::VERSION}/components/reporters/xml/schema.xsd"
NULL =
'[ARACHNI_NULL]'

Constants inherited from Arachni::Reporter::Base

Arachni::Reporter::Base::REPORT_FP

Constants included from Arachni

BANNER, Cookie, Form, Header, JSON, Link, LinkTemplate, NestedCookie, Severity, UIForm, UIInput, VERSION, WEBSITE, WIKI, XML

Instance Attribute Summary

Attributes inherited from Arachni::Reporter::Base

#options, #report

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Arachni::Reporter::Base

#format_plugin_results, #has_outfile?, has_outfile?, #initialize, #outfile, outfile_option, #skip_responses?

Methods inherited from Component::Base

author, description, fullname, #shortname, shortname, shortname=, version

Methods included from Component::Output

#depersonalize_output, #depersonalize_output?, #intercept_print_message

Methods included from UI::Output

#caller_location, #debug?, #debug_level, #debug_level_1?, #debug_level_2?, #debug_level_3?, #debug_level_4?, #debug_off, #debug_on, #disable_only_positives, #error_buffer, #error_log_fd, #error_logfile, #has_error_log?, #included, #log_error, #mute, #muted?, #only_positives, #only_positives?, #print_bad, #print_debug, #print_debug_backtrace, #print_debug_exception, #print_debug_level_1, #print_debug_level_2, #print_debug_level_3, #print_debug_level_4, #print_error, #print_error_backtrace, #print_exception, #print_info, #print_line, #print_ok, #print_status, #print_verbose, #reroute_to_file, #reroute_to_file?, reset_output_options, #set_error_logfile, #unmute, #verbose?, #verbose_off, #verbose_on

Methods included from Component::Utilities

#read_file

Methods included from Utilities

#available_port, available_port_mutex, #bytes_to_kilobytes, #bytes_to_megabytes, #caller_name, #caller_path, #cookie_decode, #cookie_encode, #cookies_from_file, #cookies_from_parser, #cookies_from_response, #exception_jail, #exclude_path?, #follow_protocol?, #form_decode, #form_encode, #forms_from_parser, #forms_from_response, #full_and_absolute_url?, #generate_token, #get_path, #hms_to_seconds, #html_decode, #html_encode, #include_path?, #links_from_parser, #links_from_response, #normalize_url, #page_from_response, #page_from_url, #parse_set_cookie, #path_in_domain?, #path_too_deep?, #port_available?, #rand_port, #random_seed, #redundant_path?, #regexp_array_match, #remove_constants, #request_parse_body, #seconds_to_hms, #skip_page?, #skip_path?, #skip_resource?, #skip_response?, #to_absolute, #uri_decode, #uri_encode, #uri_parse, #uri_parse_query, #uri_parser, #uri_rewrite

Methods included from Arachni

URI, collect_young_objects, #get_long_win32_filename, jruby?, null_device, profile?, windows?

Constructor Details

This class inherits a constructor from Arachni::Reporter::Base

Class Method Details

.infoObject



178
179
180
181
182
183
184
185
186
187
# File 'components/reporters/xml.rb', line 178

def self.info
    {
        name:         'XML',
        description:  %q{Exports the audit results as an XML (.xml) file.},
        content_type: 'text/xml',
        author:       'Tasos "Zapotek" Laskos <[email protected]>',
        version:      '0.3.8',
        options:      [ Options.outfile( '.xml' ) ]
    }
end

.replace_nulls(s) ⇒ Object



189
190
191
# File 'components/reporters/xml.rb', line 189

def self.replace_nulls( s )
    s.to_s.gsub( "\0", NULL )
end

Instance Method Details

#add_function(xml, function) ⇒ Object



308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'components/reporters/xml.rb', line 308

def add_function( xml, function )
    xml.function {
        xml.name function.name
        xml.source function.source
        xml.arguments {
            if function.arguments
                function.arguments.each do |argument|
                    xml.argument argument.inspect
                end
            end
        }
    }
end

#add_headers(xml, headers) ⇒ Object



205
206
207
208
209
210
211
# File 'components/reporters/xml.rb', line 205

def add_headers( xml, headers )
    xml.headers {
        headers.each do |k, v|
            xml.header( name: replace_nulls( k ), value: replace_nulls( v ) )
        end
    }
end

#add_inputs(xml, inputs, name = :inputs) ⇒ Object



197
198
199
200
201
202
203
# File 'components/reporters/xml.rb', line 197

def add_inputs( xml, inputs, name = :inputs )
    xml.send( name ) {
        inputs.each do |k, v|
            xml.input( name: replace_nulls( k ), value: replace_nulls( v ) )
        end
    }
end

#add_page(xml, page, name = :page) ⇒ Object



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
# File 'components/reporters/xml.rb', line 221

def add_page( xml, page, name = :page )
    xml.send( name ) {
        xml.body replace_nulls( page.body )

        request = page.request
        xml.request {
            xml.url replace_nulls( request.url )
            xml.method_ request.method

            add_parameters( xml, request.parameters )
            add_headers( xml, request.headers )

            xml.body replace_nulls( request.effective_body )
            xml.raw replace_nulls( request )
        }

        response = page.response
        xml.response {
            xml.url replace_nulls( response.url )
            xml.code response.code
            xml.ip_address response.ip_address
            xml.time response.time.round( 4 )
            xml.return_code response.return_code
            xml.return_message response.return_message

            add_headers( xml, response.headers )

            xml.body replace_nulls( response.body )
            xml.raw_headers replace_nulls( response.headers_string )
        }

        dom = page.dom
        xml.dom {
            xml.url replace_nulls( dom.url )

            xml.transitions {
                dom.transitions.each do |transition|
                    xml.transition {
                        xml.element transition.element
                        xml.event transition.event
                        xml.time transition.time.to_f.round( 4 )
                    }
                end
            }

            xml.data_flow_sinks {
                dom.data_flow_sinks.each do |sink|
                    xml.data_flow_sink {
                        xml.object sink.object
                        xml.tainted_argument_index sink.tainted_argument_index
                        xml.tainted_value replace_nulls( sink.tainted_value )
                        xml.taint_ replace_nulls( sink.taint )

                        add_function( xml, sink.function )
                        add_trace( xml, sink.trace )
                    }
                end
            }

            xml.execution_flow_sinks {
                dom.execution_flow_sinks.each do |sink|
                    xml.execution_flow_sink {
                        add_trace( xml, sink.trace )
                    }
                end
            }
        }
    }
end

#add_parameters(xml, parameters) ⇒ Object



213
214
215
216
217
218
219
# File 'components/reporters/xml.rb', line 213

def add_parameters( xml, parameters )
    xml.parameters {
        parameters.each do |k, v|
            xml.parameter( name: replace_nulls( k ), value: replace_nulls( v ) )
        end
    }
end

#add_trace(xml, trace) ⇒ Object



291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
# File 'components/reporters/xml.rb', line 291

def add_trace( xml, trace )
    xml.trace {
        trace.each do |frame|
            xml.frame {
                add_function( xml, frame.function )
                line = xml.line( frame.line )

                if frame.line.nil?
                    line['xsi:nil'] = true
                end

                xml.url frame.url
            }
        end
    }
end

#replace_nulls(*args) ⇒ Object



193
194
195
# File 'components/reporters/xml.rb', line 193

def replace_nulls( *args )
    self.class.replace_nulls( *args )
end

#runObject



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
# File 'components/reporters/xml.rb', line 21

def run
    builder = Nokogiri::XML::Builder.new do |xml|
        xml.report(
            'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
            'xsi:noNamespaceSchemaLocation' => REMOTE_SCHEMA
        ) {
            xml.version report.version
            xml.seed report.seed
            xml.options Arachni::Options.hash_to_save_data( report.options )
            xml.start_datetime report.start_datetime.xmlschema
            xml.finish_datetime report.finish_datetime.xmlschema

            xml.sitemap {
                report.sitemap.each do |url, code|
                    xml.entry url: replace_nulls( url ), code: code
                end
            }

            xml.issues {
                report.issues.each do |issue|
                    xml.issue {
                        xml.name issue.name
                        xml.description issue.description
                        xml.remedy_guidance issue.remedy_guidance
                        xml.remedy_code issue.remedy_code
                        xml.severity issue.severity

                        xml.check {
                            %w(name description author version shortname).each do |attr|
                                xml.send( attr, issue.check[attr.to_sym] )
                            end
                        }

                        if issue.cwe
                            xml.cwe issue.cwe
                        end

                        xml.digest issue.digest

                        xml.references {
                            issue.references.each do |title, url|
                                xml.reference title: title, url: url
                            end
                        }

                        vector = issue.vector
                        xml.vector {
                            xml.class_ vector.class
                            xml.type vector.type
                            xml.url replace_nulls( vector.url )
                            xml.action replace_nulls( vector.action )

                            if vector.respond_to? :source
                                xml.source replace_nulls( vector.source )
                            end

                            if vector.respond_to? :seed
                                xml.seed replace_nulls( vector.seed )
                            end

                            if issue.active?
                                xml.method_ vector.method
                            end

                            if vector.respond_to? :affected_input_name
                                xml.affected_input_name replace_nulls( vector.affected_input_name )
                            end

                            if vector.respond_to? :inputs
                                add_inputs( xml, vector.inputs )
                            end

                            if vector.respond_to? :default_inputs
                                add_inputs( xml, vector.default_inputs, :default_inputs  )
                            end
                        }

                        xml.remarks {
                            issue.remarks.each do |commenter, remarks|
                                remarks.each do |remark|
                                    xml.remark {
                                        xml.commenter commenter
                                        xml.text_ remark
                                    }
                                end
                            end
                        }

                        add_page( xml, issue.page )
                        add_page( xml, issue.referring_page, :referring_page )

                        xml.signature issue.signature
                        xml.proof issue.proof
                        xml.trusted issue.trusted
                        xml.platform_type issue.platform_type
                        xml.platform_name issue.platform_name
                    }
                end
            }

            xml.plugins {
                format_plugin_results( false ) do |name, formatter|
                    xml.send( "#{name}_" ) {
                        xml.name report.plugins[name][:name]
                        xml.description report.plugins[name][:description]

                        xml.results { formatter.run xml }
                    }
                end
            }
        }
    end

    xml = builder.to_xml

    xsd = Nokogiri::XML::Schema( IO.read( LOCAL_SCHEMA ) )
    has_errors = false
    xsd.validate( Nokogiri::XML( xml ) ).each do |error|
        puts error.message
        puts " -- Line #{error.line}, column #{error.column}, level #{error.level}."
        puts '-' * 100

        justify = (error.line+10).to_s.size
        lines = xml.lines
        ((error.line-10)..(error.line+10)).each do |i|
            line = lines[i]
            next if i < 0 || !line
            i = i + 1

            printf( "%#{justify}s | %s", i, line )

            if i == error.line
                printf( "%#{justify}s |", i )
                line.size.times.each do |c|
                    print error.column == c ? '^' : '-'
                end
                puts
            end
        end

        puts '-' * 100
        puts

        has_errors = true
    end

    if has_errors
        print_error 'Report could not be validated against the XSD due to the above errors.'
        return
    end

    IO.binwrite( outfile, xml )

    print_info "Null bytes have been replaced with: #{NULL}"
    print_status "Saved in '#{outfile}'."
end