Class: Arachni::Checks::BackupFiles

Inherits:
Arachni::Check::Base show all
Defined in:
components/checks/passive/backup_files.rb

Overview

Backup file discovery check.

Author:

Constant Summary collapse

IGNORE_MIME_TYPES =
{
    image: %w(
        gif bmp tif tiff jpg jpeg jpe pjpeg png ico psd xcf 3dm max svg eps
        drw ai
    ),
    video: %w(asf rm mpg mpeg mpe 3gp 3g2  avi flv mov mp4 swf vob wmv),
    audio: %w(aif mp3 mpa ra wav wma mid m4a ogg flac),
    font:  %w(ttf otf woff woff2 fon fnt)
}
IGNORE_EXTENSIONS =
Set.new( IGNORE_MIME_TYPES.values.flatten )

Constants included from Arachni::Check::Auditor

Arachni::Check::Auditor::DOM_ELEMENTS_WITH_INPUTS, Arachni::Check::Auditor::ELEMENTS_WITH_INPUTS, Arachni::Check::Auditor::FILE_SIGNATURES, Arachni::Check::Auditor::FILE_SIGNATURES_PER_PLATFORM, Arachni::Check::Auditor::Format, Arachni::Check::Auditor::SOURCE_CODE_SIGNATURES_PER_PLATFORM

Constants included from Arachni

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

Instance Attribute Summary

Attributes included from Arachni::Check::Auditor

#framework, #page

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Arachni::Check::Base

#browser_cluster, #clean_up, elements, exempt_platforms, has_exempt_platforms?, has_platforms?, #initialize, platforms, #plugins, prefer, #preferred, preferred, #prepare, #session, supports_platforms?

Methods included from Arachni::Check::Auditor

#audit, #audit_differential, #audit_signature, #audit_timeout, #audited, #audited?, #buffered_audit, #each_candidate_dom_element, #each_candidate_element, has_timeout_candidates?, #http, #initialize, #log, #log_issue, #log_remote_file, #log_remote_file_if_exists, #match_and_log, #max_issues, #preferred, reset, #skip?, timeout_audit_run, #trace_taint, #with_browser, #with_browser_cluster

Methods inherited from Arachni::Component::Base

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

Methods included from Arachni::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 Arachni::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::Check::Base

Class Method Details

.formatsObject


26
27
28
# File 'components/checks/passive/backup_files.rb', line 26

def self.formats
    @formats ||= read_file( 'formats.txt' )
end

.infoObject


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
# File 'components/checks/passive/backup_files.rb', line 82

def self.info
    {
        name:             'Backup files',
        description:      %q{Tries to identify backup files.},
        elements:         [ Element::Server ],
        author:           'Tasos "Zapotek" Laskos <[email protected]> ',
        version:          '0.3.3',
        exempt_platforms: Arachni::Platform::Manager::FRAMEWORKS,

        issue:       {
            name:            %q{Backup file},
            description:     %q{
A common practice when administering web applications is to create a copy/backup
of a particular file or directory prior to making any modification to the file.
Another common practice is to add an extension or change the name of the original
file to signify that it is a backup (examples include `.bak`, `.orig`, `.backup`,
etc.).

During the initial recon stages of an attack, cyber-criminals will attempt to
locate backup files by adding common extensions onto files already discovered on
the webserver. By analysing the response headers from the server they are able to
determine if the backup file exists.
These backup files can then assist in the compromise of the web application.

By utilising the same method, Arachni was able to discover a possible backup file.
},
            references: {
                'WebAppSec' => 'http://www.webappsec.org/projects/threat/classes/information_leakage.shtml'
            },
            tags:            %w(path backup file discovery),
            cwe:             530,
            severity:        Severity::MEDIUM,
            remedy_guidance: %q{
Do not keep obsolete versions of files under the virtual web server root.

When updating the site, delete or move the files to a directory outside the
virtual root, edit them there, and move (or copy) the files back to the virtual
root.
Make sure that only the files that are actually in use reside under the virtual root.

Preventing access without authentication may also be an option and stop a client
being able to view the contents of a file, however it is still likely that the
filenames will be able to be discovered.

Using obscure filenames is only implementing security through obscurity and is
not a recommended option.
}
        }

    }
end

Instance Method Details

#runObject


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
# File 'components/checks/passive/backup_files.rb', line 30

def run
    return if page.code != 200

    ct = page.response.headers.content_type.to_s
    IGNORE_MIME_TYPES.each do |type, _|
        return if ct.start_with?( "#{type}/" )
    end

    return if IGNORE_EXTENSIONS.include?(
        page.parsed_url.resource_extension.to_s.downcase
    )

    resource = page.parsed_url.without_query
    return if audited?( resource )

    if page.parsed_url.path.to_s.empty? || page.parsed_url.path.end_with?( '/' )
        print_info "Backing out, couldn't extract filename from: #{page.url}"
        return
    end

    up_to_path = page.parsed_url.up_to_path
    name       = File.basename( page.parsed_url.path ).split( '.' ).first.to_s
    extension  = page.parsed_url.resource_extension.to_s

    self.class.formats.each do |format|
        # Add format to the Issue remarks and some helpful message to let
        # the user know how Arachni got to the resulting filename.
        filename = format.gsub( '[name]', name ).gsub( '[extension]', extension )
        url = up_to_path + filename

        # If there's no extension we'll end up with '..' in URLs.
        url.gsub!( '..', '.' )

        next if audited?( url )

        remark = 'Identified by converting the original filename of ' <<
            "'#{page.parsed_url.resource_name}' to '#{filename}' using " <<
            "format '#{format}'."

        log_remote_file_if_exists(
            url,
            false,
            remarks: {
                check: [ remark ]
            }
        )
        audited( url )
    end

    audited( resource )
end