class Rex::Proto::Http::Request

HTTP request class.

Constants

PostRequests

Attributes

junk_directories[RW]

add junk directories

junk_end_of_uri[RW]

add junk end of URI

junk_param_start[RW]

add junk start of params

junk_params[RW]

add junk params

junk_pipeline[RW]

add junk pipeline requests

junk_self_referring_directories[RW]

add junk self referring directories (aka /././././)

junk_slashes[RW]

add junk slashes

method[RW]

The method being used for the request (e.g. GET).

proto[RW]

The protocol to be sent with the request.

raw_uri[RW]

The raw URI being requested, before any mucking gets to it

relative_resource[RW]

The resource path relative to the root of a server mount point.

uri_encode_mode[RW]

encoding uri

uri_parts[RW]

The split up parts of the URI.

Public Class Methods

new(method = 'GET', uri = '/', proto = DefaultProtocol) click to toggle source

Initializes an instance of an HTTP request with the supplied method, URI, and protocol.

Calls superclass method Rex::Proto::Http::Packet::new
# File lib/rex/proto/http/request.rb, line 54
def initialize(method = 'GET', uri = '/', proto = DefaultProtocol)
  super()

  self.method    = method
  self.raw_uri   = uri
  self.uri_parts = {}
  self.proto     = proto || DefaultProtocol
  self.chunk_min_size = 1
  self.chunk_max_size = 10
  self.uri_encode_mode = 'hex-normal'

  update_uri_parts
end

Public Instance Methods

body() click to toggle source
Calls superclass method
# File lib/rex/proto/http/request.rb, line 215
def body
  str = super || ''
  if str.length > 0
    return str
  end

  if PostRequests.include?(self.method)
    return param_string
  end
  ''
end
cmd_string() click to toggle source

Returns the command string derived from the three values.

# File lib/rex/proto/http/request.rb, line 230
def cmd_string
  proto_str = (self.proto =~ /^\d/) ? "HTTP/#{self.proto}" : self.proto

  "#{self.method} #{self.uri} #{proto_str}\r\n"
end
meta_vars() click to toggle source

Returns a hash of variables that contain information about the request, such as the remote host information.

TODO

# File lib/rex/proto/http/request.rb, line 266
def meta_vars
end
normalize!(str) click to toggle source

normalize out multiple slashes, directory traversal, and self referrential directories

# File lib/rex/proto/http/request.rb, line 104
def normalize!(str)
  i = 0
  while (str.gsub!(/(\/\.\/|\/\w+\/\.\.\/|\/\/)/,'/')); i += 1; end
  i
end
param_string() click to toggle source
# File lib/rex/proto/http/request.rb, line 164
def param_string
  params=[]
  self.uri_parts['QueryString'].each_pair { |param, value|
    # inject a random number of params in between each param
    if self.junk_params
      rand(10)+5.times {
        params.push(Rex::Text.rand_text_alpha(rand(16) + 5) + '=' + Rex::Text.rand_text_alpha(rand(10) + 1))
      }
    end
    if value.kind_of?(Array)
      value.each { |subvalue|
                              params.push(Rex::Text.uri_encode(param, self.uri_encode_mode) + '=' + Rex::Text.uri_encode(subvalue, self.uri_encode_mode))
      }
    else
      if !value.nil?
        params.push(Rex::Text.uri_encode(param, self.uri_encode_mode) + '=' + Rex::Text.uri_encode(value, self.uri_encode_mode))
      else
        params.push(Rex::Text.uri_encode(param, self.uri_encode_mode))
      end
    end
  }

  # inject some junk params at the end of the param list, just to be sure :P
  if self.junk_params
    rand(10)+5.times {
      params.push(Rex::Text.rand_text_alpha(rand(32) + 5) + '=' + Rex::Text.rand_text_alpha(rand(64) + 5))
    }
  end
  params.join('&')
end
parse_cgi_qstring(str) click to toggle source

Parses a CGI query string into the var/val combinations.

# File lib/rex/proto/http/request.rb, line 319
def parse_cgi_qstring(str)
  qstring = {}

  # Delimit on each variable
  str.split(/[;&]/).each { |vv|
    var = vv
    val = ''

    if (md = vv.match(/(.+?)=(.*)/))
      var = md[1]
      val = md[2]
    end

    # Add the item to the hash with logic to convert values to an array
    # if so desired.
    if (qstring.include?(var))
      if (qstring[var].kind_of?(Array))
        qstring[var] << val
      else
        curr = self.qstring[var]
        qstring[var] = [ curr, val ]
      end
    else
      qstring[var] = val
    end
  }

  return qstring
end
qstring() click to toggle source

If there were CGI parameters in the URI, this will hold a hash of each variable to value. If there is more than one value for a given variable, an array of each value is returned.

# File lib/rex/proto/http/request.rb, line 256
def qstring
  self.uri_parts['QueryString']
end
resource() click to toggle source

Returns the resource that is being requested.

# File lib/rex/proto/http/request.rb, line 239
def resource
  self.uri_parts['Resource']
end
resource=(rsrc) click to toggle source

Changes the resource URI. This is used when making a request relative to a given mount point.

# File lib/rex/proto/http/request.rb, line 247
def resource=(rsrc)
  self.uri_parts['Resource'] = rsrc
end
to_s() click to toggle source

Returns a request packet

Calls superclass method Rex::Proto::Http::Packet#to_s
# File lib/rex/proto/http/request.rb, line 202
def to_s
  str = ''
  if self.junk_pipeline
    host = ''
    if self.headers['Host']
      host = "Host: #{self.headers['Host']}\r\n"
    end
    str << "GET / HTTP/1.1\r\n#{host}Connection: Keep-Alive\r\n\r\n" * self.junk_pipeline
    self.headers['Connection'] = 'Closed'
  end
  str + super
end
update_cmd_parts(str) click to toggle source

Updates the command parts for this specific packet type.

# File lib/rex/proto/http/request.rb, line 71
def update_cmd_parts(str)
  if (md = str.match(/^(.+?)\s+(.+?)\s+HTTP\/(.+?)\r?\n?$/))
    self.method  = md[1]
    self.raw_uri = URI.decode(md[2])
    self.proto   = md[3]

    update_uri_parts
  else
    raise RuntimeError, "Invalid request command string", caller
  end
end
update_uri_parts() click to toggle source

Split the URI into the resource being requested and its query string.

# File lib/rex/proto/http/request.rb, line 86
def update_uri_parts
  # If it has a query string, get the parts.
  if ((self.raw_uri) and (md = self.raw_uri.match(/(.+?)\?(.*)$/)))
    self.uri_parts['QueryString'] = parse_cgi_qstring(md[2])
    self.uri_parts['Resource']    = md[1]
  # Otherwise, just assume that the URI is equal to the resource being
  # requested.
  else
    self.uri_parts['QueryString'] = {}
    self.uri_parts['Resource']    = self.raw_uri
  end

  self.normalize!(resource)
  # Set the relative resource to the actual resource.
  self.relative_resource = resource
end
uri() click to toggle source

Puts a URI back together based on the URI parts

# File lib/rex/proto/http/request.rb, line 111
def uri
  str = self.uri_parts['Resource'].dup || '/'

  # /././././
  if self.junk_self_referring_directories
    str.gsub!(/\//) {
      '/.' * (rand(3) + 1) + '/'
    }
  end

  # /%3faaa=bbbbb
  # which could possibly decode to "/?aaa=bbbbb", which if the IDS normalizes first, then splits the URI on ?, then it can be bypassed
  if self.junk_param_start
    str.sub!(/\//, '/%3f' + Rex::Text.rand_text_alpha(rand(5) + 1) + '=' + Rex::Text.rand_text_alpha(rand(10) + 1) + '/../')
  end

  # /RAND/../RAND../
  if self.junk_directories
    str.gsub!(/\//) {
      dirs = ''
      (rand(5)+5).times {
        dirs << '/' + Rex::Text.rand_text_alpha(rand(5) + 1) + '/..'
      }
      dirs + '/'
    }
  end

  # ////
  #
  # NOTE: this must be done after all other odd directory junk, since they would cancel this out, except junk_end_of_uri, since that a specific slash in a specific place
  if self.junk_slashes
    str.gsub!(/\//) {
      '/' * (rand(3) + 2)
    }
    str.sub!(/^[\/]+/, '/') # only one beginning slash!
  end

  # /%20HTTP/1.0%0d%0a/../../
  # which decodes to "/ HTTP/1.0\r\n"
  if self.junk_end_of_uri
    str.sub!(/^\//, '/%20HTTP/1.0%0d%0a/../../')
  end

  Rex::Text.uri_encode(str, self.uri_encode_mode)

  if !PostRequests.include?(self.method)
    if param_string.size > 0
      str << '?' + param_string
    end
  end
  str
end
uri=(str) click to toggle source

Updates the underlying URI structure

# File lib/rex/proto/http/request.rb, line 196
def uri=(str)
  self.raw_uri = str
  update_uri_parts
end