Securing Documentum – Audit trail lockdown

Installing ‘Big Brother’ round the back

(For Securing a Unix/Linux Installation please see here)

Documentum has the ability to audit hundreds of events relating to activity within a Repository. Events are generated because something happens (a user read a document, their login failed, a document reached a certain point in a workflow). These events are captured if the business required them and they were properly registered in the Documentum system.

That’s all well and good but a dubious Documentum administrator is able to act wrecklessly or maliciously: He can create random users, giving them extreme powers. He has the ability to get in the back end database and remove or change information – particularly that of the Documentum audit trail tables which capture the events mentioned.
But – and especially if it is a regulated/production system the customer won’t want that system open to compromise.
There are ways to make sure unauthorised change is identified and culprits caught. We also have the option of preventing security incidents by letting staff having special privileges know any abuse of power is recorded as evidence – which they can’t change. What evidence? Well that’s generally what audit trails are good at capturing – but it’s not reliable if it is easy to delete evidence or maliciously implicate another. Proof may be needed that someone wanted to:

  • delete evidence from the audit trail – that he unregistered certain events or something else.
  • modify an entry in the audittrail to “point the finger” at an unsuspecting and otherwise totally innocent scientist by pushing a sensitive document into an approved and published state.

The thing to do is to look at how we can capture any suspicious activity and good ways to do it.

Oracle Auditing

From a recent read-up on Oracle’s Auditing features I got the impression that it’s not Oracle’s most well-known and most utilised feature.
Since possibly you need to manufacture a solution post-haste and the Oracle Admin was not already familiar with Oracle Auditing it could be lead to voluminous amounts of redundant information being captured only then to have to be filtered as well as decreasing performance if all the options are enabled.
I’m not an expert on Oracle and was given a fair bit of help from my friend Ari with the Oracle parts of this Document. This is a slick and easy alternative method which focuses on the audit trail tables. It works but is subject to further customisation and enhancements. Please feed them back to me.

Alternative and effective method

First the drawback here is that the following SQL is more limited that Oracle Auditing but it could be implemented as either a proper solution to satisfactorally address a security requirement or react quicly to a potential security incident. The steps are first to prepare the system and ensure the right events are being captured. For this post we are only interested in Documentum’s dm_getlogin event and so we’ll commence by making sure getlogin events are being captured.

Register the dm_getlogin event

(Also register dm_connect)

Using the API tool, connect to the repository as a user that has been assigned the extended privileges which permit the manipulation of the audit trail. The simplest way to achieve this is to login to DA as the installation owner, create user with an inline password and provide them with Superuser and all extended privileges.

Login to the API tool with this new account and execute the following:


API> retrieve,c,dm_type where name = 'dm_user'
...
030f436180000103
API> audit,c,,dm_connect
...
OK
API> audit,c,,dm_getlogin
...
OK
API>

Create some events

Have available the login details of a user you which to spoof. The user has to be one that exists in the repository.
Write down the name of a different user that also exists in the repository and connect as that user to the repository using the API tool and get a login:

Connected to Documentum Server running Release 6.6.0.041 Linux.Oracle
Session id is s0
API> getlogin,c,user01
...
DM_TICKET=T0JKIE5VTEwgMAoxMwp2ZXJzaW9uIElOVCBTIDAKMwpmbGFncyBJTlQgUyAwCjAKc2VxdWVuY2VfbnVtIElOVCBTIDAKMTkKY3JlYXRlX3RpbWUgSU5UIFMgMAoxMzAyNTA0MDQ2CmV4cGlyZV90aW1lIElOVCBTIDAKMTMwMjUwNDM0Ngpkb21haW4gSU5UIFMgMAowCnVzZXJfbmFtZSBTVFJJTkcgUyAwCkEgMTIgWUFOREVMIEtldmluCnBhc3N3b3JkIElOVCBTIDAKMApkb2NiYXNlX25hbWUgU1RSSU5HIFMgMApBIDExIFNWSENfUFJPVE8yCmhvc3RfbmFtZSBTVFJJTkcgUyAwCkEgMzEgcy1kZXYtdmRlY20tMDYuZGV2LmV1cm9wYS5sb2NhbApzZXJ2ZXJfbmFtZSBTVFJJTkcgUyAwCkEgMTEgU1ZIQ19QUk9UTzIKc2lnbmF0dXJlX2xlbiBJTlQgUyAwCjU2CnNpZ25hdHVyZSBTVFJJTkcgUyAwCkEgNTYgcWZQMFY3U1hkQitrTDdGUmpKc29hSEl2U2FqcklrbGRqMWpJcWgrZVlRMlJHYnloU1orNXFBPT0K

While you are at it, quit the tool and repeat the exercise with a different user.
Make sure to write down who you are going to log in as this time and who you are going to spoof.


API> getlogin,c,user02
...
DM_TICKET=T0JKIE5VTEwgMAoxMwp2ZXJzaW9uIElOVCBTIDAKMwpmbGFncyBJTlQgUyAwCjAKc2VxdWVuY2VfbnVtIElOVCBTIDAKMjAKY3JlYXRlX3RpbWUgSU5UIFMgMAoxMzAyNTA0MDc2CmV4cGlyZV90aW1lIElOVCBTIDAKMTMwMjUwNDM3Ngpkb21haW4gSU5UIFMgMAowCnVzZXJfbmFtZSBTVFJJTkcgUyAwCkEgMTggTUFMQ1pFV1NLSSBNaWNoYWVsCnBhc3N3b3JkIElOVCBTIDAKMApkb2NiYXNlX25hbWUgU1RSSU5HIFMgMApBIDExIFNWSENfUFJPVE8yCmhvc3RfbmFtZSBTVFJJTkcgUyAwCkEgMzEgcy1kZXYtdmRlY20tMDYuZGV2LmV1cm9wYS5sb2NhbApzZXJ2ZXJfbmFtZSBTVFJJTkcgUyAwCkEgMTEgU1ZIQ19QUk9UTzIKc2lnbmF0dXJlX2xlbiBJTlQgUyAwCjU2CnNpZ25hdHVyZSBTVFJJTkcgUyAwCkEgNTYgcWZQMFY3U1hkQitrTDdGUmpKc29hSWhyUGRZZFpqNUtBVUVPeUF6SXB3YldyTzI0dFdjUXZBPT0K

List the events captured to the audit trail

Test the actual events are being recorded in the audit trail. The example below uses SQLPLUS but you can use DQL.


COL event_name FORMAT A12
COL string_1 FORMAT A20
COL host_name format A26
COL user_name format A14

select time_stamp, user_name, host_name, string_1 from dm_audittrail_s
where event_name='dm_getlogin';

TIME_STAM USER_NAME HOST_NAME STRING_1
--------- -------------- -------------------------- --------------------
11-APR-11 user01 psyc-vdev06.dev.local YEANDEL Kevin
11-APR-11 user02 psyc-vdev10.dev.local ANOTHER User

Creating the secured database

We need to covertly and secretly sniff for certain things occurring in the Documentum audit trail.
A secured database is designed to capture deletes, inserts and changes to user permissions and certain Documentum auditable events (such as dm_getlogin).

This database schema is not accessible to the Documentum Administrator and the password is kept by a secure user.
There are no changes made to the Documentum installation or its underlying database. The Documentum Administrators need have no knowledge of it’s existence.

Secured audit user

The account is created and a number of grants given.
This user has to select rows from the dm_audit_trail_s table of the Documentum repository(y|ies) of interest.
A grant is given for each Documentum installation it has to be aware of.

CREATE USER "ECMAUDIT" PROFILE "DEFAULT" IDENTIFIED BY DEFAULT TABLESPACE "USERS" TEMPORARY TABLESPACE "TEMP" QUOTA UNLIMITED ON "USERS" ACCOUNT UNLOCK;
GRANT UNLIMITED TABLESPACE TO "ECMAUDIT";
GRANT SELECT ON "REPOSITORY_OWNER"."DM_AUDITTRAIL_S" TO "ECMAUDIT";
GRANT "CONNECT" TO "ECMAUDIT";
GRANT CREATE ANY TRIGGER TO "ECMAUDIT";
GRANT "RESOURCE" TO "ECMAUDIT";

Creating the table

We need to securely store data from the audit trail belonging to a repository. We need to limit the data to what is really needed and in this case the table is a cut down version of a standard dm_audittrail_s table that is in Documentum Version 6.6


create table ecmaudit.dm_audittrail_admin_log (
EVENT_NAME varchar2(64),
USER_NAME varchar2(32),
TIME_STAMP DATE,
STRING_1 varchar2(200),
STRING_2 varchar2(200),
HOST_NAME varchar2(128),
ENTRY_DATE DATE,
ENTRY_USER varchar2(15),
ACTION varchar2(10)
);

A couple of additional fields have been created. One of these is to record the action (DELETE, INSERT, CHANGE) and which user (repository) it came from as well as the date the event occurred.
A couple of additional fields have been created. One of these is to record the action (DELETE, INSERT, CHANGE) and which user (repository) it came from as well as the date the event occurred.

Creation of triggers

-- Creates a trigger to monitor INSERT statements with 'dm_getlogin', 'dm_connect' and 'dm_audit' event_names
-- Trigger generates a row for each insert done to dm_audittrail_s
-- NOTE: Remember to change the db user of dm_audittrail_s table

create or replace trigger ecmaudit.dm_audittrail_ins_trg
before insert
on svhc_proto2.dm_audittrail_s
REFERENCING NEW AS NEW OLD AS OLD
for each row

declare
	v_username varchar2(15);
	v_action varchar2(10);
	
begin
	select user into v_username from dual;
	
	v_action := 'INSERT';
	
	if :new.event_name = 'dm_getlogin' then
		insert into dm_audittrail_admin_log values (
			:new.event_name,
			:new.user_name,
			:new.time_stamp,
			:new.string_1,
			:new.string_2,
			:new.host_name,
			sysdate,
			v_username,
			v_action);
	elsif :new.event_name = 'dm_connect' then
		insert into dm_audittrail_admin_log values (
			:new.event_name,
			:new.user_name,
			:new.time_stamp,
			:new.string_1,
			:new.string_2,
			:new.host_name,
			sysdate,
			v_username,
			v_action);
	elsif :new.event_name = 'dm_audit' then
		insert into dm_audittrail_admin_log values (
			:new.event_name,
			:new.user_name,
			:new.time_stamp,
			:new.string_1,
			:new.string_2,
			:new.host_name,
			sysdate,
			v_username,
			v_action);
	end if;

end referencing_clause;
/

-- Creates a trigger to monitor DELETE statements with 'dm_getlogin', 'dm_connect' and 'dm_audit' event_names
-- Trigger generates a row for each delete done to dm_audittrail_s
-- NOTE: Remember to change the db user of dm_audittrail_s table
	
create or replace trigger ecmaudit.dm_audittrail_del_trg
before delete
on proto2.dm_audittrail_s
REFERENCING NEW AS NEW OLD AS OLD
for each row

declare
	v_username varchar2(15);
	v_action varchar2(10);
	
begin
	select user into v_username from dual;
	
	v_action := 'DELETE';
	
	if :old.event_name = 'dm_getlogin' then
		insert into dm_audittrail_admin_log values (
			:old.event_name,
			:old.user_name,
			:old.time_stamp,
			:old.string_1,
			:old.string_2,
			:old.host_name,
			sysdate,
			v_username,
			v_action);
	elsif :old.event_name = 'dm_connect' then
		insert into dm_audittrail_admin_log values (
			:old.event_name,
			:old.user_name,
			:old.time_stamp,
			:old.string_1,
			:old.string_2,
			:old.host_name,
			sysdate,
			v_username,
			v_action);
	elsif :old.event_name = 'dm_audit' then
		insert into dm_audittrail_admin_log values (
			:old.event_name,
			:old.user_name,
			:old.time_stamp,
			:old.string_1,
			:old.string_2,
			:old.host_name,
			sysdate,
			v_username,
			v_action);
	end if;

end referencing_clause;
/

-- Creates a trigger to monitor UPDATE statements with 'dm_getlogin', 'dm_connect' and 'dm_audit' event_names
-- Trigger generates a row for each update done to dm_audittrail_s
-- It records the OLD and NEW values, so you end up with two records for each update done on dm_audittrail_s table
-- NOTE: Remember to change the db user of dm_audittrail_s table

create or replace trigger ecmaudit.dm_audittrail_upd_trg
before update
on proto2.dm_audittrail_s
REFERENCING NEW AS NEW OLD AS OLD
for each row

declare
	v_username varchar2(15);
	v_action varchar2(10);
	
begin
	select user into v_username from dual;
	
	
	
	if :old.event_name = 'dm_getlogin' then
	
		v_action := 'UPDATE_OLD';

		insert into dm_audittrail_admin_log values (
			:old.event_name,
			:old.user_name,
			:old.time_stamp,
			:old.string_1,
			:old.string_2,
			:old.host_name,
			sysdate,
			v_username,
			v_action);
		
		v_action := 'UPDATE_NEW';
		
		insert into dm_audittrail_admin_log values (
			:new.event_name,
			:new.user_name,
			:new.time_stamp,
			:new.string_1,
			:new.string_2,
			:new.host_name,
			sysdate,
			v_username,
			v_action);
			
	elsif :old.event_name = 'dm_connect' then
		
		v_action := 'UPDATE_OLD';
		
		insert into dm_audittrail_admin_log values (
			:old.event_name,
			:old.user_name,
			:old.time_stamp,
			:old.string_1,
			:old.string_2,
			:old.host_name,
			sysdate,
			v_username,
			v_action);
		
		v_action := 'UPDATE_NEW';
		
		insert into dm_audittrail_admin_log values (
			:new.event_name,
			:new.user_name,
			:new.time_stamp,
			:new.string_1,
			:new.string_2,
			:new.host_name,
			sysdate,
			v_username,
			v_action);
	elsif :old.event_name = 'dm_audit' then
		
		v_action := 'UPDATE_OLD';
		
		insert into dm_audittrail_admin_log values (
			:old.event_name,
			:old.user_name,
			:old.time_stamp,
			:old.string_1,
			:old.string_2,
			:old.host_name,
			sysdate,
			v_username,
			v_action);
			
		v_action := 'UPDATE_NEW';	
			
		insert into dm_audittrail_admin_log values (
			:new.event_name,
			:new.user_name,
			:new.time_stamp,
			:new.string_1,
			:new.string_2,
			:new.host_name,
			sysdate,
			v_username,
			v_action);
	end if;

end referencing_clause;
/

Output

The output captures any changes in the audit trail before change was applied. It captures the name of the user that has been getlogin’d and actual deletes – which apply. It probably wont be so useful when the audittrail purge runs but its something to get up and running with.


SQL> select event_name,action,user_name from dm_audittrail_admin_log

EVENT_NAME ACTION USER_NAME
---------------------------------------------------------------- ---------- --------------------------------
dm_connect DELETE dev-op-jb
dm_getlogin DELETE dev-op-jb
dm_connect DELETE dev-op-jb
dm_connect INSERT dmadmin2
dm_getlogin INSERT dmadmin2
dm_connect INSERT dmadmin2
dm_connect INSERT dev-op-ky
dm_getlogin INSERT dev-op-ky
dm_getlogin INSERT dev-op-ky
dm_connect INSERT dmadmin2
dm_connect INSERT dev-op-ky
dm_getlogin INSERT dev-op-ky

Conclusion

Documentum is safe and secure – if all the measures have been put in place. This can only be achieved if the vulnerabilities are exposed. In the mean time, I’ve yet to work at a customer site which has properly locked down Documentum in an environment which hosts it – I’m sure they are out there.
(If you know of any please let me know).

Advertisement

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 )

Connecting to %s

Follow

Get every new post delivered to your Inbox.