abductor.py 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-"
  3. """
  4. UFONet - DDoS Botnet via Web Abuse - 2017 - by psy (epsylon@riseup.net)
  5. You should have received a copy of the GNU General Public License along
  6. with UFONet; if not, write to the Free Software Foundation, Inc., 51
  7. Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  8. """
  9. import urllib, urllib2, ssl, random, socket, time, re
  10. from urlparse import urlparse
  11. # UFONet recognizance (abduction) class
  12. class Abductor(object):
  13. def __init__(self,ufonet):
  14. self.ufonet=ufonet
  15. self.start = None
  16. self.stop = None
  17. self.port = None
  18. self.ctx = ssl.create_default_context() # creating context to bypass SSL cert validation (black magic)
  19. self.ctx.check_hostname = False
  20. self.ctx.verify_mode = ssl.CERT_NONE
  21. def proxy_transport(self, proxy):
  22. proxy_url = self.ufonet.extract_proxy(proxy)
  23. proxy = urllib2.ProxyHandler({'https': proxy_url})
  24. opener = urllib2.build_opener(proxy)
  25. urllib2.install_opener(opener)
  26. def establish_connection(self, target):
  27. if target.endswith(""):
  28. target.replace("", "/")
  29. self.ufonet.user_agent = random.choice(self.ufonet.agents).strip() # suffle user-agent
  30. headers = {'User-Agent' : self.ufonet.user_agent, 'Referer' : self.ufonet.referer} # set fake user-agent and referer
  31. try:
  32. req = urllib2.Request(target, None, headers)
  33. if self.ufonet.options.proxy: # set proxy
  34. self.proxy_transport(self.ufonet.options.proxy)
  35. self.start = time.time()
  36. target_reply = urllib2.urlopen(req).read()
  37. header = urllib2.urlopen(req).info()
  38. self.stop = time.time()
  39. else:
  40. self.start = time.time()
  41. target_reply = urllib2.urlopen(req, context=self.ctx).read()
  42. header = urllib2.urlopen(req).info()
  43. self.stop = time.time()
  44. except:
  45. print('[Error] - Unable to connect...\n')
  46. return #sys.exit(2)
  47. return target_reply, header
  48. def convert_size(self, size):
  49. import math
  50. if (size == 0):
  51. return '0B'
  52. size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
  53. i = int(math.floor(math.log(size,1024)))
  54. p = math.pow(1024,i)
  55. s = round(size/p,2)
  56. return '%s %s' % (s,size_name[i])
  57. def convert_time(self, time):
  58. return '%.2f' % time
  59. def extract_banner(self, header): # extract webserver banner
  60. try:
  61. banner = header["server"]
  62. except:
  63. banner = "NOT found!"
  64. try:
  65. via = header["via"]
  66. except: # return when fails performing query
  67. via = "NOT found!"
  68. return banner, via
  69. def extract_whois(self, domain): # extract whois data from target domain
  70. try:
  71. import whois
  72. d = whois.query(domain, ignore_returncode=True) # ignore return code
  73. if d.creation_date is None: # return when no creation date
  74. return
  75. else:
  76. print " -Registrant : " + str(d.registrar)
  77. print " -Creation date: " + str(d.creation_date)
  78. print " -Expiration : " + str(d.expiration_date)
  79. print " -Last update : " + str(d.last_updated)
  80. except: # return when fails performing query
  81. return
  82. def extract_cve(self, banner): # extract Denial of Service vulnerabilities related with webserver banner from CVE database
  83. url = 'https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword'
  84. q = str(banner)
  85. query_string = { '':q}
  86. data = urllib.urlencode(query_string)
  87. target = url + data
  88. try:
  89. self.ufonet.user_agent = random.choice(self.ufonet.agents).strip() # suffle user-agent
  90. headers = {'User-Agent' : self.ufonet.user_agent, 'Referer' : self.ufonet.referer} # set fake user-agent and referer
  91. req = urllib2.Request(target, None, headers)
  92. if self.ufonet.options.proxy: # set proxy
  93. self.proxy_transport(self.ufonet.options.proxy)
  94. target_reply = urllib2.urlopen(req).read()
  95. else:
  96. target_reply = urllib2.urlopen(req, context=self.ctx).read()
  97. except:
  98. return #sys.exit(2)
  99. if target_reply == "": # no records found
  100. return
  101. if "<b>0</b> CVE entries" in target_reply: # regex for: no CVE records found
  102. cve = "NOT found!"
  103. else:
  104. regex_s = '<td valign="top" nowrap="nowrap"><a href="(.+?)">' # regex magics
  105. pattern_s = re.compile(regex_s)
  106. cve = re.findall(pattern_s, target_reply)
  107. return cve
  108. def waf_detection(self, banner, target_reply):
  109. self.wafs_file = "core/txt/wafs.txt" # set source path to retrieve 'wafs'
  110. try:
  111. f = open(self.wafs_file)
  112. wafs = f.readlines()
  113. f.close()
  114. except:
  115. wafs = "broken!"
  116. sep = "##"
  117. for w in wafs:
  118. if sep in w:
  119. w = w.split(sep)
  120. signature = w[0] # signature
  121. t = w[1] # vendor
  122. if signature in target_reply or signature in banner:
  123. waf = "VENDOR -> " + str(t)
  124. else:
  125. waf = "FIREWALL NOT PRESENT (or not discovered yet)! ;-)\n"
  126. return waf
  127. def abducting(self, target):
  128. try:
  129. target_reply, header = self.establish_connection(target)
  130. except:
  131. print "[Error] - Something wrong connecting to your target. Aborting...\n"
  132. return #sys.exit(2)
  133. if not target_reply:
  134. print "[Error] - Something wrong connecting to your target. Aborting...\n"
  135. return #sys.exit(2)
  136. print ' -Target URL:', target, "\n"
  137. try:
  138. if target.startswith("http://"):
  139. self.port = "80"
  140. if target.startswith("https://"):
  141. self.port = "443"
  142. except:
  143. self.port = "Error!"
  144. try:
  145. domain = urlparse(target)
  146. domain = domain.netloc
  147. if domain.startswith("www."):
  148. domain = domain.replace("www.", "")
  149. except:
  150. domain = "OFF"
  151. try:
  152. ipv4 = socket.gethostbyname(domain)
  153. except:
  154. ipv4 = "OFF"
  155. try:
  156. ipv6 = socket.getaddrinfo(domain, port, socket.AF_INET6)
  157. ftpca = ipv6[0]
  158. ipv6 = ftpca[4][0]
  159. except:
  160. ipv6 = "OFF"
  161. print ' -IP :', ipv4
  162. print ' -IPv6 :', ipv6
  163. print ' -Port :', self.port
  164. print ' \n -Domain:', domain
  165. try:
  166. whois = self.extract_whois(domain)
  167. except:
  168. pass
  169. try:
  170. size = self.convert_size(len(target_reply))
  171. except:
  172. size = "Error!"
  173. try:
  174. time_required = self.stop - self.start
  175. load = self.convert_time(time_required)
  176. except:
  177. load = "Error!"
  178. try:
  179. banner, via = self.extract_banner(header)
  180. except:
  181. pass
  182. print '\n---------'
  183. print "\nTrying single visit broadband test (using GET)...\n"
  184. print ' -Bytes in :', size
  185. print ' -Load time:', load, "seconds\n"
  186. print '---------'
  187. print "\nDetermining webserver fingerprint (note that this value can be a fake)...\n"
  188. print ' -Banner:', banner
  189. print ' -Vía :', via , "\n"
  190. print '---------'
  191. print "\nSearching for extra Anti-DDoS protections...\n"
  192. waf = self.waf_detection(banner, target_reply)
  193. print ' -WAF/IDS: ' + waf
  194. if 'VENDOR' in waf:
  195. print ' -NOTICE : This FIREWALL probably is using Anti-(D)DoS measures!', "\n"
  196. print '---------'
  197. if banner == "NOT found!":
  198. pass
  199. else:
  200. print "\nSearching at CVE (https://cve.mitre.org) for vulnerabilities...\n"
  201. try:
  202. cve = self.extract_cve(banner)
  203. if cve == None:
  204. print ' -Reports: NOT found!', "\n"
  205. elif cve == "NOT found!":
  206. print ' -Reports:', cve
  207. else:
  208. print ' -Reports:'
  209. for c in cve:
  210. cve_info = c.replace("/cgi-bin/cvename.cgi?name=","")
  211. print "\n +", cve_info, "->", "https://cve.mitre.org" + c # 8 tab for zen
  212. print '\n---------'
  213. except:
  214. pass
  215. print "\n[Info] Abduction finished... ;-)\n"