lib/rex/proto/http/request.rb in librex-0.0.68 vs lib/rex/proto/http/request.rb in librex-0.0.70

- old
+ new

@@ -11,345 +11,342 @@ # HTTP request class. # ### class Request < Packet - PostRequests = ['POST', 'SEARCH'] + PostRequests = ['POST', 'SEARCH'] - ## - # - # Some individual request types. - # - ## + ## + # + # Some individual request types. + # + ## - # - # HTTP GET request class wrapper. - # - class Get < Request - def initialize(uri = '/', proto = DefaultProtocol) - super('GET', uri, proto) - end - end + # + # HTTP GET request class wrapper. + # + class Get < Request + def initialize(uri = '/', proto = DefaultProtocol) + super('GET', uri, proto) + end + end - # - # HTTP POST request class wrapper. - # - class Post < Request - def initialize(uri = '/', proto = DefaultProtocol) - super('POST', uri, proto) - end - end + # + # HTTP POST request class wrapper. + # + class Post < Request + def initialize(uri = '/', proto = DefaultProtocol) + super('POST', uri, proto) + end + end - # - # HTTP PUT request class wrapper. - # - class Put < Request - def initialize(uri = '/', proto = DefaultProtocol) - super('PUT', uri, proto) - end - end + # + # HTTP PUT request class wrapper. + # + class Put < Request + def initialize(uri = '/', proto = DefaultProtocol) + super('PUT', uri, proto) + end + end - # - # Initializes an instance of an HTTP request with the supplied method, URI, - # and protocol. - # - def initialize(method = 'GET', uri = '/', proto = DefaultProtocol) - super() + # + # Initializes an instance of an HTTP request with the supplied method, URI, + # and protocol. + # + 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' + 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 + update_uri_parts + end - # - # Updates the command parts for this specific packet type. - # - 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] + # + # Updates the command parts for this specific packet type. + # + 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 + else + raise RuntimeError, "Invalid request command string", caller + end + end - # - # 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. - 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 + # + # 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. + 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 + self.normalize!(resource) + # Set the relative resource to the actual resource. + self.relative_resource = resource + end - # normalize out multiple slashes, directory traversal, and self referrential directories - def normalize!(str) - i = 0 - while (str.gsub!(/(\/\.\/|\/\w+\/\.\.\/|\/\/)/,'/')); i += 1; end - i - end + # normalize out multiple slashes, directory traversal, and self referrential directories + def normalize!(str) + i = 0 + while (str.gsub!(/(\/\.\/|\/\w+\/\.\.\/|\/\/)/,'/')); i += 1; end + i + end - # Puts a URI back together based on the URI parts - def uri - str = self.uri_parts['Resource'].dup || '/' + # Puts a URI back together based on the URI parts + def uri + str = self.uri_parts['Resource'].dup || '/' - # /././././ - if self.junk_self_referring_directories - str.gsub!(/\//) { - '/.' * (rand(3) + 1) + '/' - } - end + # /././././ + 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 + # /%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 + # /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 + # //// + # + # 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 + # /%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) + 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 + if !PostRequests.include?(self.method) + if param_string.size > 0 + str << '?' + param_string + end + end + str + end - 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| + 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 - } + } + 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 + # 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 - # Updates the underlying URI structure - def uri=(str) - self.raw_uri = str - update_uri_parts - end + # Updates the underlying URI structure + def uri=(str) + self.raw_uri = str + update_uri_parts + end - # Returns a request packet - 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 + # Returns a request packet + 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 - def body - str = super || '' - if str.length > 0 - return str - end + def body + str = super || '' + if str.length > 0 + return str + end - if PostRequests.include?(self.method) - return param_string - end - '' - end + if PostRequests.include?(self.method) + return param_string + end + '' + end - # - # Returns the command string derived from the three values. - # - def cmd_string - proto_str = (self.proto =~ /^\d/) ? "HTTP/#{self.proto}" : self.proto + # + # Returns the command string derived from the three values. + # + def cmd_string + proto_str = (self.proto =~ /^\d/) ? "HTTP/#{self.proto}" : self.proto - "#{self.method} #{self.uri} #{proto_str}\r\n" - end + "#{self.method} #{self.uri} #{proto_str}\r\n" + end - # - # Returns the resource that is being requested. - # - def resource - self.uri_parts['Resource'] - end + # + # Returns the resource that is being requested. + # + def resource + self.uri_parts['Resource'] + end - # - # 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 + # + # 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 - # - # 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. - # - def qstring - self.uri_parts['QueryString'] - 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. + # + def qstring + self.uri_parts['QueryString'] + end - # - # Returns a hash of variables that contain information about the request, - # such as the remote host information. - # - # TODO - # - def meta_vars - end + # + # Returns a hash of variables that contain information about the request, + # such as the remote host information. + # + # TODO + # + def meta_vars + end - # - # The method being used for the request (e.g. GET). - # - attr_accessor :method - # - # The raw URI being requested, before any mucking gets to it - # - attr_accessor :raw_uri + # + # The method being used for the request (e.g. GET). + # + attr_accessor :method + # + # The raw URI being requested, before any mucking gets to it + # + attr_accessor :raw_uri - # - # The split up parts of the URI. - # - attr_accessor :uri_parts - # - # The protocol to be sent with the request. - # - attr_accessor :proto + # + # The split up parts of the URI. + # + attr_accessor :uri_parts + # + # The protocol to be sent with the request. + # + attr_accessor :proto - # - # The resource path relative to the root of a server mount point. - # - attr_accessor :relative_resource + # + # The resource path relative to the root of a server mount point. + # + attr_accessor :relative_resource - # add junk directories - attr_accessor :junk_directories + # add junk directories + attr_accessor :junk_directories - # add junk slashes - attr_accessor :junk_slashes + # add junk slashes + attr_accessor :junk_slashes - # add junk self referring directories (aka /././././) - attr_accessor :junk_self_referring_directories + # add junk self referring directories (aka /././././) + attr_accessor :junk_self_referring_directories - # add junk params - attr_accessor :junk_params + # add junk params + attr_accessor :junk_params - # add junk pipeline requests - attr_accessor :junk_pipeline + # add junk pipeline requests + attr_accessor :junk_pipeline - # add junk start of params - attr_accessor :junk_param_start + # add junk start of params + attr_accessor :junk_param_start - # add junk end of URI - attr_accessor :junk_end_of_uri + # add junk end of URI + attr_accessor :junk_end_of_uri - # encoding uri - attr_accessor :uri_encode_mode + # encoding uri + attr_accessor :uri_encode_mode + # + # Parses a CGI query string into the var/val combinations. + # + def parse_cgi_qstring(str) + qstring = {} -protected + # Delimit on each variable + str.split(/[;&]/).each { |vv| + var = vv + val = '' - # - # Parses a CGI query string into the var/val combinations. - # - def parse_cgi_qstring(str) - qstring = {} + if (md = vv.match(/(.+?)=(.*)/)) + var = md[1] + val = md[2] + end - # Delimit on each variable - str.split(/[;&]/).each { |vv| - var = vv - val = '' + # 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 + } - 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 + return qstring + end end end end