class Rex::Proto::Http::Request
HTTP request class.
Constants
- PostRequests
Attributes
add junk directories
add junk end of URI
add junk start of params
add junk params
add junk pipeline requests
add junk self referring directories (aka /././././)
add junk slashes
The method being used for the request (e.g. GET).
The protocol to be sent with the request.
The raw URI being requested, before any mucking gets to it
The resource path relative to the root of a server mount point.
encoding uri
The split up parts of the URI.
Public Class Methods
Initializes an instance of an HTTP request with the supplied method, URI, and protocol.
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
# 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
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
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 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
# 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
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
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
Returns the resource that is being requested.
# File lib/rex/proto/http/request.rb, line 239 def resource self.uri_parts['Resource'] end
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
Returns a request packet
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
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
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
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
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