def parse_qs( url_encoded_string, ignoreExceptions=True ): ''' Parse a url encoded string (a=b&c=d) into a queryString object. @param url_encoded_string: The string to parse @return: A queryString object (a dict wrapper). >>> parse_qs('id=3') {'id': ['3']} >>> parse_qs('id=3&id=4') {'id': ['3', '4']} >>> parse_qs('id=3&ff=4&id=5') {'id': ['3', '5'], 'ff': ['4']} ''' parsed_qs = None result = queryString() if url_encoded_string: try: parsed_qs = cgi.parse_qs( url_encoded_string ,keep_blank_values=True,strict_parsing=False) except Exception, e: if not ignoreExceptions: raise w3afException('Strange things found when parsing query string: "' + url_encoded_string + '"') else: # # Before we had something like this: # #for i in parsed_qs.keys(): # result[ i ] = parsed_qs[ i ][0] # # But with that, we fail to handle web applications that use "duplicated parameter # names". For example: http://host.tld/abc?sp=1&sp=2&sp=3 # # (please note the lack of [0]) , and that if the value isn't a list... # I create an artificial list for p, v in parsed_qs.iteritems(): if type(v) is not list: v = [v] result[p] = v
def getQueryString( url, ignoreExceptions=True ): ''' Parses the query string and returns a dict. @parameter url: The url with the query string to parse. @return: A QueryString Object, example : - input url : http://localhost/foo.asp?xx=yy&bb=dd - output dict : { xx:yy , bb:dd } ''' parsedQs = None result = queryString() scheme, domain, path, params, qs, fragment = _uparse.urlparse( url ) if qs: try: parsedQs = cgi.parse_qs( qs ,keep_blank_values=True,strict_parsing=False) except Exception, e: if not ignoreExceptions: raise w3afException('Strange things found when parsing query string: "' + qs + '"') else: # # Before we had something like this: # #for i in parsedQs.keys(): # result[ i ] = parsedQs[ i ][0] # # But with that, we fail to handle web applications that use "duplicated parameter # names". For example: http://host.tld/abc?sp=1&sp=2&sp=3 # # (please note the lack of [0]) , and that if the value isn't a list... # I create an artificial list for i in parsedQs.keys(): if isinstance( parsedQs[ i ], list ): result[ i ] = parsedQs[ i ] else: result[ i ] = [parsedQs[ i ], ]
def createFuzzableRequestRaw(method, url, postData, headers): ''' Creates a fuzzable request based on a query sent FROM the browser. This is used in plugins like spiderMan. @parameter method: A string that represents the method ('GET', 'POST', etc) @parameter url: An url_object that represents the URL @parameter postData: A string that represents the postdata, if its a GET request, set to None. @parameter headers: A dict that holds the headers ''' if not isinstance(url, url_object): msg = 'The "url" parameter of createFuzzableRequestRaw @ frFactory' msg += ' must be of urlParser.url_object type.' raise ValueError( msg ) # # Just a query string request ! no postdata # if not postData: qsr = httpQsRequest.httpQsRequest() qsr.setURL(url) qsr.setMethod(method) qsr.setHeaders(headers) dc = url.getQueryString() qsr.setDc(dc) return qsr # # Seems to be something that has post data # pdr = httpPostDataRequest.httpPostDataRequest() pdr.setURL(url) pdr.setMethod(method) for header_name in headers.keys(): if header_name.lower() == 'content-length': del headers[header_name] pdr.setHeaders(headers) # # Parse the content # Case #1, multipart form data # conttype = headers.get('content-type', '') if conttype and conttype.startswith('multipart/form-data'): tmp, pdict = cgi.parse_header(conttype) try: dc = cgi.parse_multipart(StringIO(postData), pdict) except: om.out.debug('Multipart form data is invalid, the browser sent something weird.') else: resultDc = queryString() for i in dc.keys(): resultDc[i] = dc[i] # We process multipart requests as x-www-form-urlencoded # TODO We need native support of multipart requests! headers['content-type'] = 'application/x-www-form-urlencoded' pdr.setDc(resultDc) pdr.setHeaders(headers) return pdr # # Case #2, JSON request # try: dc = json.loads(postData) except: pass else: # It's json! welcome to the party dude! pdr = jsonPostDataRequest.jsonPostDataRequest() pdr.setURL(url) pdr.setMethod(method) pdr.setHeaders(headers) pdr.setDc(dc) return pdr # # Case #3, XMLRPC request # postDataLower = postData.lower() stopWords = [ '<methodcall>', '<methodname>', '<params>', '</methodcall>', '</methodname>', '</params>' ] allStopWords = True for word in stopWords: if word not in postDataLower: allStopWords = False if allStopWords: xmlrpc_request = xmlrpcRequest.xmlrpcRequest(postData) xmlrpc_request.setURL( url ) xmlrpc_request.setMethod( method ) xmlrpc_request.setHeaders( headers ) return xmlrpc_request # # Case #4, the "default". # # NOT a JSON or XMLRPC request!, let's try the simple url encoded post data... # try: dc = parse_qs(postData) pdr.setDc( dc ) except: om.out.debug('Failed to create a data container that can store this data: "' + postData + '".') else: return pdr
def createFuzzableRequestRaw(method, url, postData, headers): """ Creates a fuzzable request based on a query sent FROM the browser. This is used in plugins like spiderMan. @parameter method: A string that represents the method ('GET', 'POST', etc) @parameter url: A string that represents the URL @parameter postData: A string that represents the postdata, if its a GET request, set to None. @parameter headers: A dict that holds the headers """ # # Just a query string request ! no postdata # if not postData: qsr = httpQsRequest.httpQsRequest() qsr.setURL(url) qsr.setMethod(method) qsr.setHeaders(headers) dc = urlParser.getQueryString(url) qsr.setDc(dc) return qsr # # Seems to be something that has post data # pdr = httpPostDataRequest.httpPostDataRequest() pdr.setURL(url) pdr.setMethod(method) for header_name in headers.keys(): if header_name.lower() == "content-length": del headers[header_name] pdr.setHeaders(headers) # # Parse the content # Case #1, multipart form data # if "content-type" in headers.keys() and headers["content-type"].startswith("multipart/form-data"): tmp, pdict = cgi.parse_header(headers["content-type"]) try: dc = cgi.parse_multipart(StringIO(postData), pdict) except: om.out.debug("Multipart form data is invalid, the browser sent something wierd.") else: resultDc = queryString() for i in dc.keys(): resultDc[i] = dc[i] # We process multipart requests as x-www-form-urlencoded # TODO We need native support of multipart requests! headers["content-type"] = "application/x-www-form-urlencoded" pdr.setDc(resultDc) pdr.setHeaders(headers) return pdr # # Case #2, JSON request # try: dc = json.loads(postData) except: pass else: # It's json! welcome to the party dude! pdr = jsonPostDataRequest.jsonPostDataRequest() pdr.setURL(url) pdr.setMethod(method) pdr.setHeaders(headers) pdr.setDc(dc) return pdr # # Case #3, XMLRPC request # postDataLower = postData.lower() stopWords = ["<methodcall>", "<methodname>", "<params>", "</methodcall>", "</methodname>", "</params>"] allStopWords = True for word in stopWords: if word not in postDataLower: allStopWords = False if allStopWords: xmlrpc_request = xmlrpcRequest.xmlrpcRequest(postData) xmlrpc_request.setURL(url) xmlrpc_request.setMethod(method) xmlrpc_request.setHeaders(headers) return xmlrpc_request # # Case #4, the "default". # # NOT a JSON or XMLRPC request!, let's try the simple url encoded post data... # try: dc = urlParser.getQueryString("http://w3af/?" + postData) pdr.setDc(dc) except: om.out.debug('Failed to create a data container that can store this data: "' + postData + '".') else: return pdr