def isJSON(freq): # Only do the JSON stuff if this is really a JSON request... postdata = freq.getData() try: cgi.parse_qs(postdata, keep_blank_values=True, strict_parsing=True) except Exception, e: # We have something that's not URL encoded in the postdata, it could be something # like JSON, XML, or multipart encoding. Let's try with JSON try: jsonPostData = json.loads(postdata) except: # It's not json, maybe XML or multipart, I don't really care ( at least not in this section of the code ) return False else: # Now, fuzz the parsed JSON data... return True
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 _createJSONMutants(freq, mutantClass, mutant_str_list, fuzzableParamList, append): """ @parameter freq: A fuzzable request with a dataContainer inside. @parameter mutantClass: The class to use to create the mutants @parameter fuzzableParamList: What parameters should be fuzzed @parameter append: True/False, if we should append the value or replace it. @parameter mutant_str_list: a list with mutant strings to use @return: Mutants that have the JSON postdata changed with the strings at mutant_str_list """ # We define a function that creates the mutants... def _makeMutants(freq, mutantClass, mutant_str_list, fuzzableParamList, append, jsonPostData): res = [] for fuzzed_json, original_value in _fuzzJSON(mutant_str_list, jsonPostData, append): # Create the mutants freq_copy = freq.copy() m = mutantClass(freq_copy) m.setOriginalValue(original_value) m.setVar("JSON data") m.setDc(fuzzed_json) res.append(m) return res # Now we define a function that does the work... def _fuzzJSON(mutant_str_list, jsonPostData, append): """ @return: A list with tuples containing (fuzzed list/dict/string/int that represents a JSON object, original value) """ res = [] if isinstance(jsonPostData, int): for mutant_str in mutant_str_list: if mutant_str.isdigit(): # This (a mutant str that really is an integer) will happend once every 100000 years, # but I wanted to be sure to cover all cases. This will look something like: # # 1 # # In the postdata. if append: fuzzed = int(str(jsonPostData) + str(mutant_str)) res.append((fuzzed, str(jsonPostData))) else: fuzzed = int(mutant_str) res.append((fuzzed, jsonPostData)) elif isinstance(jsonPostData, basestring): # This will look something like: # # "abc" # # In the postdata. for mutant_str in mutant_str_list: if append: fuzzed = jsonPostData + mutant_str res.append((fuzzed, jsonPostData)) else: res.append((mutant_str, jsonPostData)) elif isinstance(jsonPostData, list): # This will look something like: # # ["abc", "def"] # # In the postdata. for item, i in zip(jsonPostData, xrange(len(jsonPostData))): fuzzed_item_list = _fuzzJSON(mutant_str_list, jsonPostData[i], append) for fuzzed_item, original_value in fuzzed_item_list: jsonPostDataCopy = copy.deepcopy(jsonPostData) jsonPostDataCopy[i] = fuzzed_item res.append((jsonPostDataCopy, original_value)) elif isinstance(jsonPostData, dict): for key in jsonPostData: fuzzed_item_list = _fuzzJSON(mutant_str_list, jsonPostData[key], append) for fuzzed_item, original_value in fuzzed_item_list: jsonPostDataCopy = copy.deepcopy(jsonPostData) jsonPostDataCopy[key] = fuzzed_item res.append((jsonPostDataCopy, original_value)) return res # Now, fuzz the parsed JSON data... postdata = freq.getData() jsonPostData = json.loads(postdata) return _makeMutants(freq, mutantClass, mutant_str_list, fuzzableParamList, append, jsonPostData)
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