class Rex::Proto::Http::ClientRequest

Constants

DefaultConfig
DefaultUserAgent

Attributes

opts[R]

Public Class Methods

new(opts={}) click to toggle source
# File lib/rex/proto/http/client_request.rb, line 87
def initialize(opts={})
  @opts = DefaultConfig.merge(opts)
  @opts['headers'] ||= {}
end

Public Instance Methods

to_s() click to toggle source
# File lib/rex/proto/http/client_request.rb, line 92
def to_s

  # Start GET query string
  qstr = opts['query'] ? opts['query'].dup : ""

  # Start POST data string
  pstr = opts['data'] ? opts['data'].dup : ""

  if opts['cgi']
    uri_str = set_uri

    if (opts['pad_get_params'])
      1.upto(opts['pad_get_params_count'].to_i) do |i|
        qstr << '&' if qstr.length > 0
        qstr << set_encode_uri(Rex::Text.rand_text_alphanumeric(rand(32)+1))
        qstr << '='
        qstr << set_encode_uri(Rex::Text.rand_text_alphanumeric(rand(32)+1))
      end
    end

    opts['vars_get'].each_pair do |var,val|
      var = var.to_s

      qstr << '&' if qstr.length > 0
      qstr << (opts['encode_params'] ? set_encode_uri(var) : var)
      # support get parameter without value
      # Example: uri?parameter
      if val
        val = val.to_s
        qstr << '='
        qstr << (opts['encode_params'] ? set_encode_uri(val) : val)
      end
    end

    if (opts['pad_post_params'])
      1.upto(opts['pad_post_params_count'].to_i) do |i|
        rand_var = Rex::Text.rand_text_alphanumeric(rand(32)+1)
        rand_val = Rex::Text.rand_text_alphanumeric(rand(32)+1)
        pstr << '&' if pstr.length > 0
        pstr << (opts['encode_params'] ? set_encode_uri(rand_var) : rand_var)
        pstr << '='
        pstr << (opts['encode_params'] ? set_encode_uri(rand_val) : rand_val)
      end
    end

    opts['vars_post'].each_pair do |var,val|
      var = var.to_s
      val = val.to_s

      pstr << '&' if pstr.length > 0
      pstr << (opts['encode_params'] ? set_encode_uri(var) : var)
      pstr << '='
      pstr << (opts['encode_params'] ? set_encode_uri(val) : val)
    end
  else
    if opts['encode']
      qstr = set_encode_uri(qstr)
    end
    uri_str = set_uri
  end

  req = ''
  req << set_method
  req << set_method_uri_spacer()
  req << set_uri_prepend()

  if opts['encode']
    req << set_encode_uri(uri_str)
  else
    req << uri_str
  end


  if (qstr.length > 0)
    req << '?'
    req << qstr
  end

  req << set_path_info
  req << set_uri_append()
  req << set_uri_version_spacer()
  req << set_version
  req << set_host_header

  # If an explicit User-Agent header is set, then use that instead of
  # the default
  unless opts['headers'] and opts['headers'].keys.map{|x| x.downcase }.include?('user-agent')
    req << set_agent_header
  end

  # Similar to user-agent, only add an automatic auth header if a
  # manual one hasn't been provided
  unless opts['headers'] and opts['headers'].keys.map{|x| x.downcase }.include?('authorization')
    req << set_auth_header
  end

  req << set_cookie_header
  req << set_connection_header
  req << set_extra_headers

  req << set_content_type_header
  req << set_content_len_header(pstr.length)
  req << set_chunked_header()
  req << opts['raw_headers']
  req << set_body(pstr)
end

Protected Instance Methods

set_agent_header() click to toggle source

Return the HTTP agent header

# File lib/rex/proto/http/client_request.rb, line 367
def set_agent_header
  opts['agent'] ? set_formatted_header("User-Agent", opts['agent']) : ""
end
set_auth_header() click to toggle source
# File lib/rex/proto/http/client_request.rb, line 371
def set_auth_header
  opts['authorization'] ? set_formatted_header("Authorization", opts['authorization']) : ""
end
set_body(bdata) click to toggle source

Return the HTTP seperator and body string

# File lib/rex/proto/http/client_request.rb, line 453
def set_body(bdata)
  return "\r\n" + bdata if opts['chunked_size'] == 0
  str = bdata.dup
  chunked = ''
  while str.size > 0
    chunk = str.slice!(0,rand(opts['chunked_size']) + 1)
    chunked << sprintf("%x", chunk.size) + "\r\n" + chunk + "\r\n"
  end
  "\r\n" + chunked + "0\r\n\r\n"
end
set_chunked_header() click to toggle source
# File lib/rex/proto/http/client_request.rb, line 445
def set_chunked_header
  return "" if opts['chunked_size'] == 0
  set_formatted_header('Transfer-Encoding', 'chunked')
end
set_connection_header() click to toggle source

Return the HTTP connection header

# File lib/rex/proto/http/client_request.rb, line 385
def set_connection_header
  opts['connection'] ? set_formatted_header("Connection", opts['connection']) : ""
end
set_content_len_header(clen) click to toggle source

Return the content length header

# File lib/rex/proto/http/client_request.rb, line 398
def set_content_len_header(clen)
  return "" if opts['chunked_size'] > 0
  set_formatted_header("Content-Length", clen)
end
set_content_type_header() click to toggle source

Return the content type header

# File lib/rex/proto/http/client_request.rb, line 392
def set_content_type_header
  opts['ctype'] ? set_formatted_header("Content-Type", opts['ctype']) : ""
end
set_encode_uri(str) click to toggle source
# File lib/rex/proto/http/client_request.rb, line 231
def set_encode_uri(str)
  a = str.to_s.dup
  opts['uri_encode_count'].times {
    a = Rex::Text.uri_encode(a, opts['uri_encode_mode'])
  }
  return a
end
set_extra_headers() click to toggle source

Return a string of formatted extra headers

# File lib/rex/proto/http/client_request.rb, line 426
def set_extra_headers
  buf = ''

  if (opts['pad_fake_headers'])
    1.upto(opts['pad_fake_headers_count'].to_i) do |i|
      buf << set_formatted_header(
        Rex::Text.rand_text_alphanumeric(rand(32)+1),
        Rex::Text.rand_text_alphanumeric(rand(32)+1)
      )
    end
  end

  opts['headers'].each_pair do |var,val|
    buf << set_formatted_header(var, val)
  end

  buf
end
set_formatted_header(var, val) click to toggle source

Return a formatted header string

# File lib/rex/proto/http/client_request.rb, line 356
def set_formatted_header(var, val)
  if (self.opts['header_folding'])
    "#{var}:\r\n\t#{val}\r\n"
  else
    "#{var}: #{val}\r\n"
  end
end
set_host_header() click to toggle source

Return the HTTP Host header

# File lib/rex/proto/http/client_request.rb, line 406
def set_host_header
  return "" if opts['uri_full_url']
  host = opts['vhost']

  # IPv6 addresses must be placed in brackets
  if Rex::Socket.is_ipv6?(host)
    host = "[#{host}]"
  end

  # The port should be appended if non-standard
  if not [80,443].include?(opts['port'])
    host = host + ":#{opts['port']}"
  end

  set_formatted_header("Host", host)
end
set_method() click to toggle source
# File lib/rex/proto/http/client_request.rb, line 239
def set_method
  ret = opts['method'].dup

  if (opts['method_random_valid'])
    ret = ['GET', 'POST', 'HEAD'][rand(3)]
  end

  if (opts['method_random_invalid'])
    ret = Rex::Text.rand_text_alpha(rand(20)+1)
  end

  if (opts['method_random_case'])
    ret = Rex::Text.to_rand_case(ret)
  end

  ret
end
set_method_uri_spacer() click to toggle source
# File lib/rex/proto/http/client_request.rb, line 257
def set_method_uri_spacer
  len = opts['pad_method_uri_count'].to_i
  set = " "
  buf = ""

  case opts['pad_method_uri_type']
  when 'tab'
    set = "\t"
  when 'apache'
    set = "\t \x0b\x0c\x0d"
  end

  while(buf.length < len)
    buf << set[ rand(set.length) ]
  end

  return buf
end
set_path_info() click to toggle source

Return the HTTP path info TODO:

* Encode path information
# File lib/rex/proto/http/client_request.rb, line 297
def set_path_info
  opts['path_info'] ? opts['path_info'] : ''
end
set_uri() click to toggle source
# File lib/rex/proto/http/client_request.rb, line 201
def set_uri
  uri_str = opts['uri'].dup
  if (opts['uri_dir_self_reference'])
    uri_str.gsub!('/', '/./')
  end

  if (opts['uri_dir_fake_relative'])
    buf = ""
    uri_str.split('/',-1).each do |part|
      cnt = rand(8)+2
      1.upto(cnt) { |idx|
        buf << "/" + Rex::Text.rand_text_alphanumeric(rand(32)+1)
      }
      buf << ("/.." * cnt)
      buf << "/" + part
    end
    uri_str = buf
  end

  if (opts['uri_full_url'])
    url = opts['ssl'] ? "https://" : "http://"
    url << opts['vhost']
    url << ((opts['port'] == 80) ? "" : ":#{opts['port']}")
    url << uri_str
    url
  else
    uri_str
  end
end
set_uri_append() click to toggle source

Return the padding to place before the uri

# File lib/rex/proto/http/client_request.rb, line 304
def set_uri_append
  # TODO:
  #  * Support different padding types
  ""
end
set_uri_prepend() click to toggle source

Return the padding to place before the uri

# File lib/rex/proto/http/client_request.rb, line 279
def set_uri_prepend
  prefix = ""

  if (opts['uri_fake_params_start'])
    prefix << '/%3fa=b/../'
  end

  if (opts['uri_fake_end'])
    prefix << '/%20HTTP/1.0/../../'
  end

  prefix
end
set_uri_version_spacer() click to toggle source

Return the spacing between the uri and the version

# File lib/rex/proto/http/client_request.rb, line 313
def set_uri_version_spacer
  len = opts['pad_uri_version_count'].to_i
  set = " "
  buf = ""

  case opts['pad_uri_version_type']
  when 'tab'
    set = "\t"
  when 'apache'
    set = "\t \x0b\x0c\x0d"
  end

  while(buf.length < len)
    buf << set[ rand(set.length) ]
  end

  return buf
end
set_version() click to toggle source

Return the HTTP version string

# File lib/rex/proto/http/client_request.rb, line 335
def set_version
  ret = opts['proto'] + "/" + opts['version']

  if (opts['version_random_valid'])
    ret = opts['proto'] + "/" +  ['1.0', '1.1'][rand(2)]
  end

  if (opts['version_random_invalid'])
    ret = Rex::Text.rand_text_alphanumeric(rand(20)+1)
  end

  if (opts['version_random_case'])
    ret = Rex::Text.to_rand_case(ret)
  end

  ret << "\r\n"
end