選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 
 

262 行
8.7 KiB

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. from binascii import unhexlify
  4. from ldap3.protocol.formatters.formatters import format_sid
  5. import argparse
  6. import datetime
  7. import json
  8. import ldap3
  9. import logging
  10. import os
  11. import ssl
  12. import sys
  13. import hashlib
  14. import binascii
  15. ### Data utils
  16. def cast_to_dict(cid):
  17. out = {}
  18. for key, value in cid.items():
  19. if type(value) == bytes:
  20. out[key] = str(value)
  21. elif type(value) == list:
  22. if len(value) == 1:
  23. value = value[0]
  24. if type(value) == bytes:
  25. out[key] = str(value)
  26. elif type(value) == datetime.datetime:
  27. out[key] = value.strftime('%Y-%m-%d %T')
  28. elif type(value) == datetime.timedelta:
  29. # Output format to change
  30. out[key] = value.seconds
  31. else:
  32. out[key] = value
  33. else:
  34. newlist = []
  35. for element in value:
  36. if type(element) == bytes:
  37. newlist.append(str(element))
  38. elif type(element) == datetime.datetime:
  39. newlist.append(element.strftime('%Y-%m-%d %T'))
  40. elif type(element) == datetime.timedelta:
  41. # Output format to change
  42. newlist.append(element.seconds)
  43. out[key] = newlist
  44. elif type(value) == datetime.datetime:
  45. out[key] = value.strftime('%Y-%m-%d %T')
  46. elif type(value) == datetime.timedelta:
  47. # Output format to change
  48. out[key] = value.seconds
  49. else:
  50. out[key] = value
  51. return out
  52. def dict_get_paths(d):
  53. paths = []
  54. for key in d.keys():
  55. if type(d[key]) == dict:
  56. paths = [[key]+p for p in dict_get_paths(d[key])]
  57. else:
  58. paths.append([key])
  59. return paths
  60. def dict_path_access(d, path):
  61. for key in path:
  62. if key in d.keys():
  63. d = d[key]
  64. else:
  65. return None
  66. return d
  67. class LDAPConsole(object):
  68. """docstring for LDAPConsole."""
  69. def __init__(self, ldap_server, ldap_session, target_dn, debug=True):
  70. super(LDAPConsole, self).__init__()
  71. self.ldap_server = ldap_server
  72. self.ldap_session = ldap_session
  73. self.delegate_from = None
  74. self.target_dn = target_dn
  75. self.debug = debug
  76. def queryallusers(self, subtree, attributes=['*']):
  77. results = {}
  78. try:
  79. # https://ldap3.readthedocs.io/en/latest/searches.html#the-search-operation
  80. print (subtree+','+self.target_dn)
  81. self.ldap_session.search(subtree+','+self.target_dn, '(&(uid=*))' , attributes=attributes )
  82. for entry in self.ldap_session.response:
  83. print(entry)
  84. for entry in self.ldap_session.response:
  85. if entry['type'] != 'searchResEntry':
  86. continue
  87. results[entry['dn']] = entry["attributes"]
  88. except ldap3.core.exceptions.LDAPInvalidFilterError as e:
  89. print("Invalid Filter. (ldap3.core.exceptions.LDAPInvalidFilterError)")
  90. except Exception as e:
  91. raise e
  92. return results
  93. def doLdapLogin(self,subtree, username, password):
  94. results = {}
  95. try:
  96. self.ldap_session.search(subtree+','+self.target_dn, '(&(uid='+username+'))' , attributes=['ntPassword'] )
  97. for entry in self.ldap_session.response:
  98. if entry['type'] != 'searchResEntry':
  99. continue
  100. hash = hashlib.new('md4', password.encode('utf-16le')).digest()
  101. ntPassword = binascii.hexlify(hash).upper().decode("utf-8")
  102. #print (str(ntPassword))
  103. print (entry['attributes']['ntPassword'])
  104. results['data'] = entry["attributes"]
  105. if entry['attributes']['ntPassword'] == ntPassword:
  106. results['authen'] = "yeah"
  107. else:
  108. results['authen'] = "none"
  109. except ldap3.core.exceptions.LDAPInvalidFilterError as e:
  110. print("Invalid Filter. (ldap3.core.exceptions.LDAPInvalidFilterError)")
  111. except Exception as e:
  112. raise e
  113. return results
  114. def init_ldap_connection(target, tls_version, args, username, password):
  115. if tls_version is not None:
  116. use_ssl = True
  117. port = 636
  118. tls = ldap3.Tls(validate=ssl.CERT_NONE, version=tls_version)
  119. else:
  120. use_ssl = False
  121. port = 389
  122. tls = None
  123. ldap_server = ldap3.Server(target, get_info=ldap3.ALL, port=port, use_ssl=use_ssl, tls=tls)
  124. ldap_session = ldap3.Connection(ldap_server, user=username, password=password, authentication='SIMPLE',auto_bind=True)
  125. return ldap_server, ldap_session
  126. def init_ldap_session(args, username, password):
  127. if args.dc_ip is not None:
  128. target = args.dc_ip
  129. if args.use_ldaps is True:
  130. try:
  131. return init_ldap_connection(target, ssl.PROTOCOL_TLSv1_2, args, username, password )
  132. except ldap3.core.exceptions.LDAPSocketOpenError:
  133. return init_ldap_connection(target, ssl.PROTOCOL_TLSv1, args, username, password )
  134. else:
  135. return init_ldap_connection(target, None, args, username, password )
  136. def bytessize(data):
  137. l = len(data)
  138. units = ['B','kB','MB','GB','TB','PB']
  139. for k in range(len(units)):
  140. if l < (1024**(k+1)):
  141. break
  142. return "%4.2f %s" % (round(l/(1024**(k)),2), units[k])
  143. def parse_args():
  144. parser = argparse.ArgumentParser(add_help=True, description='')
  145. parser.add_argument('--use-ldaps', action='store_true', help='Use LDAPS instead of LDAP')
  146. parser.add_argument("-q", "--quiet", dest="quiet", action="store_true", default=False, help="show no information at all")
  147. parser.add_argument("-debug", dest="debug", action="store_true", default=False, help="Debug mode")
  148. parser.add_argument("-o", "--outfile", dest="jsonfile", default="ldap.json", help="Output JSON file. (default: ldap.json)")
  149. parser.add_argument("-b", "--base", dest="searchbase", default=None, help="Search base for LDAP query.")
  150. authconn = parser.add_argument_group('authentication & connection')
  151. authconn.add_argument('--dc-ip', action='store', metavar="ip address", help='IP Address of the domain controller')
  152. authconn.add_argument("-u", "--user", dest="auth_username", metavar="USER", action="store", help="user to authenticate with")
  153. secret = parser.add_argument_group()
  154. cred = secret.add_mutually_exclusive_group()
  155. cred.add_argument("-p", "--password", dest="auth_password", metavar="PASSWORD", action="store", help="password to authenticate with")
  156. if len(sys.argv) == 1:
  157. parser.print_help()
  158. sys.exit(1)
  159. args = parser.parse_args()
  160. return args
  161. if __name__ == '__main__':
  162. args = parse_args()
  163. print("[+]================LDAP2JSON======================================[+]")
  164. print()
  165. ldap_server, ldap_session = init_ldap_session(
  166. args=args,
  167. username=args.auth_username,
  168. password=args.auth_password
  169. )
  170. if args.debug:
  171. print("[>] Authentication successful!")
  172. print("[>] Extracting all objects from LDAP ...")
  173. data = {}
  174. baseDN = "dc=majornet,dc=local"
  175. if args.debug:
  176. print("[>] Querying to LDAP on %s ..." % baseDN)
  177. lc = LDAPConsole(ldap_server, ldap_session, baseDN, debug=args.debug)
  178. response = lc.queryallusers("ou=users", attributes=["displayName"])
  179. if args.debug:
  180. print("[>] LDAP query (objectClass=*) returned %d objects" % len(response))
  181. if args.debug:
  182. print("[>] Parsing data ...")
  183. for cn in response:
  184. path = cn.split(',')[::-1]
  185. tmp = data
  186. for key in path[:-1]:
  187. if key in tmp.keys():
  188. tmp = tmp[key]
  189. else:
  190. tmp[key] = {}
  191. tmp = tmp[key]
  192. tmp[path[-1]] = cast_to_dict(response[cn])
  193. json_data = json.dumps(data, indent=4)
  194. if args.debug:
  195. print("[>] JSON data generated.")
  196. print("[>] Writing json data to %s" % args.jsonfile)
  197. f = open(args.jsonfile, 'w')
  198. f.write(json_data)
  199. f.close()
  200. print("[>] Written %s bytes to %s" % (bytessize(json_data), args.jsonfile))
  201. response = lc.doLdapLogin("ou=users", username='emorrone',password='morrone')
  202. print (response['authen'])
  203. response = lc.doLdapLogin("ou=users", username='emorrone',password='emorrone')
  204. print (response['authen'])
  205. ### ./bin/python ldap2json.py -u "cn=ldapadmin,dc=majornet,dc=local" -p "secret" --dc-ip "127.0.0.1" -b "dc=majornet,dc=local" -debug