2005-07-25 02:18:37 +00:00
|
|
|
require 'uri'
|
2005-07-24 20:53:54 +00:00
|
|
|
require 'rex/proto/http'
|
|
|
|
|
|
|
|
module Rex
|
|
|
|
module Proto
|
|
|
|
module Http
|
|
|
|
|
|
|
|
###
|
|
|
|
#
|
|
|
|
# HTTP request class.
|
|
|
|
#
|
|
|
|
###
|
|
|
|
class Request < Packet
|
|
|
|
|
|
|
|
##
|
|
|
|
#
|
|
|
|
# Some individual request types.
|
|
|
|
#
|
|
|
|
##
|
2005-11-15 05:22:13 +00:00
|
|
|
|
|
|
|
#
|
|
|
|
# HTTP GET request class wrapper.
|
|
|
|
#
|
2005-07-24 20:53:54 +00:00
|
|
|
class Get < Request
|
|
|
|
def initialize(uri = '/', proto = DefaultProtocol)
|
|
|
|
super('GET', uri, proto)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2005-11-15 05:22:13 +00:00
|
|
|
#
|
|
|
|
# HTTP POST request class wrapper.
|
|
|
|
#
|
2005-07-24 20:53:54 +00:00
|
|
|
class Post < Request
|
|
|
|
def initialize(uri = '/', proto = DefaultProtocol)
|
|
|
|
super('POST', uri, proto)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2005-11-15 05:22:13 +00:00
|
|
|
#
|
|
|
|
# HTTP PUT request class wrapper.
|
|
|
|
#
|
2005-07-24 20:53:54 +00:00
|
|
|
class Put < Request
|
|
|
|
def initialize(uri = '/', proto = DefaultProtocol)
|
|
|
|
super('PUT', uri, proto)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2005-11-15 05:22:13 +00:00
|
|
|
#
|
|
|
|
# Initializes an instance of an HTTP request with the supplied method, URI,
|
|
|
|
# and protocol.
|
|
|
|
#
|
2005-07-24 20:53:54 +00:00
|
|
|
def initialize(method = 'GET', uri = '/', proto = DefaultProtocol)
|
|
|
|
super()
|
|
|
|
|
2005-07-25 02:18:37 +00:00
|
|
|
self.method = method
|
2006-01-23 21:58:53 +00:00
|
|
|
self.raw_uri = uri
|
2005-07-25 02:18:37 +00:00
|
|
|
self.uri_parts = {}
|
2005-09-15 23:37:38 +00:00
|
|
|
self.proto = proto || DefaultProtocol
|
|
|
|
|
2005-11-24 02:02:10 +00:00
|
|
|
update_uri_parts
|
2005-07-24 20:53:54 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Updates the command parts for this specific packet type.
|
|
|
|
#
|
|
|
|
def update_cmd_parts(str)
|
|
|
|
if (md = str.match(/^(.+?)\s+(.+?)\s+HTTP\/(.+?)\r?\n?$/))
|
2005-07-25 02:18:37 +00:00
|
|
|
self.method = md[1]
|
2006-01-23 21:58:53 +00:00
|
|
|
self.raw_uri = URI.decode(md[2])
|
2005-07-25 02:18:37 +00:00
|
|
|
self.proto = md[3]
|
|
|
|
|
2005-11-24 02:02:10 +00:00
|
|
|
update_uri_parts
|
2005-07-25 02:18:37 +00:00
|
|
|
else
|
|
|
|
raise RuntimeError, "Invalid request command string", caller
|
2005-07-24 20:53:54 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2005-11-24 02:02:10 +00:00
|
|
|
#
|
|
|
|
# Split the URI into the resource being requested and its query string.
|
|
|
|
#
|
|
|
|
def update_uri_parts
|
|
|
|
# If it has a query string, get the parts.
|
2006-01-23 21:58:53 +00:00
|
|
|
if ((self.raw_uri) and (md = self.raw_uri.match(/(.+?)\?(.*)$/)))
|
2005-11-24 02:02:10 +00:00
|
|
|
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
|
2005-11-24 05:13:40 +00:00
|
|
|
self.uri_parts['QueryString'] = {}
|
2006-01-23 21:58:53 +00:00
|
|
|
self.uri_parts['Resource'] = self.raw_uri
|
2005-11-24 02:02:10 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
# Set the relative resource to the actual resource.
|
|
|
|
self.relative_resource = resource
|
|
|
|
end
|
|
|
|
|
2006-01-23 21:58:53 +00:00
|
|
|
# Puts a URI back together based on the URI parts
|
|
|
|
def uri
|
|
|
|
uri = self.uri_parts['Resource'] || '/'
|
2006-01-23 23:57:50 +00:00
|
|
|
|
|
|
|
# /././././
|
|
|
|
if self.junk_self_referring_directories
|
|
|
|
uri.gsub!(/\//) {
|
|
|
|
'/.' * (rand(3) + 1) + '/'
|
|
|
|
}
|
|
|
|
end
|
2006-01-23 21:58:53 +00:00
|
|
|
|
2006-01-23 23:57:50 +00:00
|
|
|
# /RAND/../RAND../
|
2006-01-23 21:58:53 +00:00
|
|
|
if self.junk_directories
|
|
|
|
uri.gsub!(/\//) {
|
|
|
|
dirs = ''
|
2006-01-23 23:57:50 +00:00
|
|
|
rand(5)+5.times {
|
|
|
|
dirs += '/' + Rex::Text.rand_text_alpha(rand(5) + 1) + '/..'
|
2006-01-23 21:58:53 +00:00
|
|
|
}
|
|
|
|
dirs + '/'
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2006-01-23 23:57:50 +00:00
|
|
|
# ////
|
|
|
|
#
|
2006-01-23 21:58:53 +00:00
|
|
|
# NOTE: this must be done after junk directories, since junk_directories would cancel this out
|
|
|
|
if self.junk_slashes
|
|
|
|
uri.gsub!(/\//) {
|
2006-01-23 23:57:50 +00:00
|
|
|
'/' * (rand(3) + 1)
|
2006-01-23 21:58:53 +00:00
|
|
|
}
|
2006-01-23 23:57:50 +00:00
|
|
|
uri.gsub!(/^[\/]+/, '/') # only one beginning slash!
|
2006-01-23 21:58:53 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
if self.method != 'POST'
|
|
|
|
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.nil?
|
|
|
|
params.push(self.escape(param) + '=' + self.escape(value))
|
|
|
|
else
|
|
|
|
params.push(self.escape(param))
|
|
|
|
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
|
|
|
|
|
|
|
|
if params.size > 0
|
|
|
|
uri += '?' + params.join('&')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
uri
|
|
|
|
end
|
|
|
|
|
|
|
|
# Updates the underlying URI structure
|
|
|
|
def uri=(uri)
|
|
|
|
self.raw_uri = uri
|
|
|
|
update_uri_parts
|
|
|
|
end
|
|
|
|
|
|
|
|
# Returns a URI escaped version of the provided string, by providing an additional argument, all characters are escaped
|
|
|
|
def escape(str, all = nil)
|
|
|
|
if all
|
|
|
|
return str.gsub(/./) { |s| Rex::Text.to_hex(s, '%') }
|
|
|
|
else
|
|
|
|
return str.gsub(/[^a-zA-Z1-9]/) { |s| Rex::Text.to_hex(s, '%') }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
2005-07-24 20:53:54 +00:00
|
|
|
#
|
2005-11-15 05:22:13 +00:00
|
|
|
# Returns the command string derived from the three values.
|
2005-07-24 20:53:54 +00:00
|
|
|
#
|
|
|
|
def cmd_string
|
|
|
|
"#{self.method} #{self.uri} HTTP/#{self.proto}\r\n"
|
|
|
|
end
|
|
|
|
|
2005-07-25 02:18:37 +00:00
|
|
|
#
|
|
|
|
# Returns the resource that is being requested.
|
|
|
|
#
|
|
|
|
def resource
|
|
|
|
self.uri_parts['Resource']
|
|
|
|
end
|
|
|
|
|
2005-11-24 02:02:10 +00:00
|
|
|
#
|
|
|
|
# Changes the resource URI. This is used when making a request relative to
|
|
|
|
# a given mount point.
|
|
|
|
#
|
|
|
|
def resource=(rsrc)
|
|
|
|
self.uri_parts['Resource'] = rsrc
|
|
|
|
end
|
|
|
|
|
2005-07-25 02:18:37 +00:00
|
|
|
#
|
|
|
|
# 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,
|
|
|
|
# and array of each value is returned.
|
|
|
|
#
|
|
|
|
def qstring
|
|
|
|
self.uri_parts['QueryString']
|
|
|
|
end
|
|
|
|
|
2005-11-24 02:02:10 +00:00
|
|
|
#
|
|
|
|
# Returns a hash of variables that contain information about the request,
|
|
|
|
# such as the remote host information.
|
|
|
|
#
|
|
|
|
# TODO
|
|
|
|
#
|
|
|
|
def meta_vars
|
|
|
|
end
|
|
|
|
|
2005-11-15 05:22:13 +00:00
|
|
|
#
|
|
|
|
# The method being used for the request (e.g. GET).
|
|
|
|
#
|
2005-07-24 20:53:54 +00:00
|
|
|
attr_accessor :method
|
2005-11-15 05:22:13 +00:00
|
|
|
#
|
2006-01-23 21:58:53 +00:00
|
|
|
# The raw URI being requested, before any mucking gets to it
|
2005-11-15 05:22:13 +00:00
|
|
|
#
|
2006-01-23 21:58:53 +00:00
|
|
|
attr_accessor :raw_uri
|
|
|
|
|
2005-11-15 05:22:13 +00:00
|
|
|
#
|
|
|
|
# The split up parts of the URI.
|
|
|
|
#
|
2005-07-25 02:18:37 +00:00
|
|
|
attr_accessor :uri_parts
|
2005-11-15 05:22:13 +00:00
|
|
|
#
|
|
|
|
# The protocol to be sent with the request.
|
|
|
|
#
|
2005-07-24 20:53:54 +00:00
|
|
|
attr_accessor :proto
|
2005-11-24 02:02:10 +00:00
|
|
|
#
|
|
|
|
# The resource path relative to the root of a server mount point.
|
|
|
|
#
|
|
|
|
attr_accessor :relative_resource
|
2005-07-24 20:53:54 +00:00
|
|
|
|
2006-01-23 21:58:53 +00:00
|
|
|
# add junk directories
|
|
|
|
attr_accessor :junk_directories
|
|
|
|
|
|
|
|
# add junk slashes
|
|
|
|
attr_accessor :junk_slashes
|
2006-01-23 23:57:50 +00:00
|
|
|
|
|
|
|
# add junk self referring directories (aka /././././
|
|
|
|
attr_accessor :junk_self_referring_directories
|
2006-01-23 21:58:53 +00:00
|
|
|
|
|
|
|
# add junk params
|
|
|
|
attr_accessor :junk_params
|
|
|
|
|
2005-07-25 02:18:37 +00:00
|
|
|
protected
|
|
|
|
|
|
|
|
#
|
|
|
|
# Parses a CGI query string into the var/val combinations.
|
|
|
|
#
|
|
|
|
def parse_cgi_qstring(str)
|
|
|
|
qstring = {}
|
|
|
|
|
|
|
|
# Delimit on each variable
|
|
|
|
str.split(/&/).each { |vv|
|
|
|
|
var = vv
|
|
|
|
val = ''
|
|
|
|
|
2005-11-22 03:20:09 +00:00
|
|
|
if (md = vv.match(/(.+?)=(.*)/))
|
2005-07-25 02:18:37 +00:00
|
|
|
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
|
|
|
|
|
2005-07-24 20:53:54 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|