PageRenderTime 691ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/modules/gather/CSamrDump.py

https://code.google.com/p/inguma/
Python | 292 lines | 264 code | 8 blank | 20 comment | 0 complexity | 2544c5d8f022af4f8ec46664aac13710 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. #!/usr/bin/python
  2. #
  3. # Modified version of the CORE's script "samrdump.py" adapted for Inguma
  4. #
  5. # Copyright (c) 2007 Joxean Koret <joxeankoret@yahoo.es>
  6. # Copyright (c) 2003 CORE Security Technologies
  7. #
  8. # This software is provided under under a slightly modified version
  9. # of the Apache Software License. See the accompanying LICENSE file
  10. # for more information.
  11. #
  12. # $Id: samrdump.py,v 1.2 2003/11/14 21:26:07 jkohen Exp $
  13. #
  14. # Description: DCE/RPC SAMR dumper.
  15. #
  16. # Author:
  17. # Javier Kohen <jkohen@coresecurity.com>
  18. #
  19. # Reference for:
  20. # DCE/RPC.
  21. import socket
  22. import string
  23. import sys
  24. import types
  25. from impacket import uuid
  26. from impacket.dcerpc import dcerpc_v4, dcerpc, transport, samr
  27. from lib.libexploit import CIngumaModule
  28. name = "samrdump"
  29. brief_description = "Dump the SAM database"
  30. type = "gather"
  31. class ListUsersException(Exception):
  32. pass
  33. class SAMRDump(CIngumaModule):
  34. KNOWN_PROTOCOLS = {
  35. '139/SMB': (r'ncacn_np:%s[\pipe\samr]', 139),
  36. '445/SMB': (r'ncacn_np:%s[\pipe\samr]', 445),
  37. }
  38. entries = []
  39. debug = False
  40. dict = {}
  41. def __init__(self, protocols = None,
  42. username = '', password = '', gom=None):
  43. if not protocols:
  44. protocols = SAMRDump.KNOWN_PROTOCOLS.keys()
  45. self.__username = username
  46. self.__password = password
  47. self.__protocols = protocols
  48. self.gom = gom
  49. def debugPrint(self, *params):
  50. self.gom.echo( str(params) )
  51. def dump(self, addr):
  52. """Dumps the list of users and shares registered present at
  53. addr. Addr is a valid host name or IP address.
  54. """
  55. encoding = sys.getdefaultencoding()
  56. self.gom.echo( '[+] Retrieving endpoint list from %s' % addr )
  57. # Try all requested protocols until one works.
  58. entries = []
  59. for protocol in self.__protocols:
  60. protodef = SAMRDump.KNOWN_PROTOCOLS[protocol]
  61. port = protodef[1]
  62. self.gom.echo( "[+] Trying protocol %s..." % protocol )
  63. rpctransport = transport.SMBTransport(addr, port, r'\samr', self.__username, self.__password)
  64. try:
  65. entries = self.__fetchList(rpctransport)
  66. except Exception, e:
  67. self.gom.echo( '[!] Protocol failed: %s' % e )
  68. raise
  69. else:
  70. # Got a response. No need for further iterations.
  71. break
  72. # Display results.
  73. for entry in entries:
  74. (username, uid, user) = entry
  75. if user.is_enabled():
  76. self.addToDict(addr + "_users", username.replace("\x00", ""))
  77. buf = "User %s" % username
  78. self.gom.echo( buf )
  79. self.gom.echo( "-"*len(buf) )
  80. self.gom.echo( "" )
  81. base = "%s (%d)" % (username, uid)
  82. self.gom.echo( base + 'Enabled:' + str( ('false', 'true')[user.is_enabled()] ) )
  83. try:
  84. self.gom.echo( base + 'Last Logon:' + str(user.get_logon_time()) )
  85. except:
  86. self.gom.echo( sys.exc_info()[1] )
  87. try:
  88. self.gom.echo( base + 'Last Logoff:' + str(user.get_logoff_time()) )
  89. except:
  90. self.gom.echo( sys.exc_info()[1] )
  91. try:
  92. self.gom.echo( base + 'Kickoff:' + str(user.get_kickoff_time()) )
  93. except:
  94. self.gom.echo( sys.exc_info()[1] )
  95. try:
  96. self.gom.echo( base + 'Last PWD Set:' + str(user.get_pwd_last_set()) )
  97. except:
  98. self.gom.echo( sys.exc_info()[1] )
  99. try:
  100. self.gom.echo( base + 'PWD Can Change:' + str(user.get_pwd_can_change()) )
  101. except:
  102. self.gom.echo( sys.exc_info()[1] )
  103. try:
  104. self.gom.echo( base + 'PWD Must Change:' + str(user.get_pwd_must_change()) )
  105. except:
  106. self.gom.echo( sys.exc_info()[1] )
  107. try:
  108. self.gom.echo( base + 'Group id: %d' % user.get_group_id() )
  109. except:
  110. self.gom.echo( sys.exc_info()[1] )
  111. try:
  112. self.gom.echo( base + 'Bad pwd count: %d' % user.get_bad_pwd_count() )
  113. except:
  114. self.gom.echo( sys.exc_info()[1] )
  115. try:
  116. self.gom.echo( base + 'Logon count: %d' % user.get_logon_count() )
  117. except:
  118. self.gom.echo( sys.exc_info()[1] )
  119. try:
  120. items = user.get_items()
  121. except:
  122. self.gom.echo( sys.exc_info()[1] )
  123. for i in samr.MSRPCUserInfo.ITEMS.keys():
  124. name = items[samr.MSRPCUserInfo.ITEMS[i]].get_name()
  125. name = name.encode(encoding, 'replace')
  126. self.gom.echo( base + ' ' + i + ': ' + name )
  127. self.gom.echo( "" )
  128. if entries:
  129. num = len(entries)
  130. if 1 == num:
  131. self.gom.echo( 'Received one entry.' )
  132. else:
  133. self.gom.echo( 'Received %d entries.' % num )
  134. else:
  135. self.gom.echo( 'No entries received.' )
  136. self.entries = entries
  137. def __fetchList(self, rpctransport):
  138. dce = dcerpc.DCERPC_v5(rpctransport)
  139. encoding = sys.getdefaultencoding()
  140. entries = []
  141. dce.connect()
  142. dce.bind(samr.MSRPC_UUID_SAMR)
  143. rpcsamr = samr.DCERPCSamr(dce)
  144. try:
  145. resp = rpcsamr.connect()
  146. if resp.get_return_code() != 0:
  147. raise ListUsersException, 'Connect error'
  148. _context_handle = resp.get_context_handle()
  149. resp = rpcsamr.enumdomains(_context_handle)
  150. if resp.get_return_code() != 0:
  151. raise ListUsersException, 'EnumDomain error'
  152. domains = resp.get_domains().elements()
  153. self.gom.echo( 'Found domain(s):' )
  154. self.gom.echo( '' )
  155. for i in range(0, resp.get_entries_num()):
  156. self.gom.echo( " . %s" % domains[i].get_name() )
  157. self.gom.echo( '' )
  158. self.gom.echo( "Looking up users in domain %s ... " % domains[0].get_name() )
  159. self.gom.echo( '' )
  160. resp = rpcsamr.lookupdomain(_context_handle, domains[0])
  161. if resp.get_return_code() != 0:
  162. raise ListUsersException, 'LookupDomain error'
  163. resp = rpcsamr.opendomain(_context_handle, resp.get_domain_sid())
  164. if resp.get_return_code() != 0:
  165. raise ListUsersException, 'OpenDomain error'
  166. domain_context_handle = resp.get_context_handle()
  167. resp = rpcsamr.enumusers(domain_context_handle)
  168. if resp.get_return_code() != 0:
  169. raise ListUsersException, 'OpenDomainUsers error'
  170. for user in resp.get_users().elements():
  171. uname = user.get_name().encode(encoding, 'replace')
  172. uid = user.get_id()
  173. r = rpcsamr.openuser(domain_context_handle, uid)
  174. self.gom.echo( "Found user: %s, uid = %d" % (uname, uid) )
  175. if r.get_return_code() == 0:
  176. info = rpcsamr.queryuserinfo(r.get_context_handle()).get_user_info()
  177. entry = (uname, uid, info)
  178. entries.append(entry)
  179. c = rpcsamr.closerequest(r.get_context_handle())
  180. self.gom.echo( '' )
  181. except ListUsersException, e:
  182. self.gom.echo( "Error listing users: %s" % e )
  183. dce.disconnect()
  184. return entries
  185. class CSamrDump:
  186. target = ""
  187. port = 0
  188. waitTime = 0
  189. timeout = 1
  190. exploitType = 1
  191. services = {}
  192. results = {}
  193. _dumper = None
  194. interactive = True
  195. user = ""
  196. password = ""
  197. def help(self):
  198. print "target = <target host or network>"
  199. print "port = <target port>"
  200. print
  201. print "Optional:"
  202. print "username = <username>"
  203. print "password = <password>"
  204. def run(self):
  205. self.gom.echo( "[+] Trying an anonymous connection ... " )
  206. if self.port in (139, 445):
  207. proto = "%d/SMB" % self.port
  208. self.gom.echo( "[+] Using protocol %s" % str(proto) )
  209. self._dumper = SAMRDump(proto, self.user, self.password, self.gom)
  210. else:
  211. self._dumper = SAMRDump(username=self.user, password=self.password, gom=self.gom)
  212. self._dumper.dict = self.dict
  213. self._dumper.dump(self.target)
  214. self.dict = self._dumper.dict
  215. return True
  216. def printSummary(self):
  217. pass
  218. # Process command-line arguments.
  219. if __name__ == '__main__':
  220. if len(sys.argv) <= 1:
  221. print "Usage: %s [username[:password]@]<address> [protocol list...]" % sys.argv[0]
  222. print "Available protocols: %s" % SAMRDump.KNOWN_PROTOCOLS.keys()
  223. print "Username and password are only required for certain transports, eg. SMB."
  224. sys.exit(1)
  225. import re
  226. username, password, address = re.compile('(?:([^@:]*)(?::([^@]*))?@)?(.*)').match(sys.argv[1]).groups('')
  227. if len(sys.argv) > 2:
  228. dumper = SAMRDump(sys.argv[2:], username, password)
  229. else:
  230. dumper = SAMRDump(username = username, password = password)
  231. dumper.dump(address)