Oracle DBMS_PRIV_CAPTURE Built-In Package
Versions 12.1 - 19.4

Security Advisory
Capture privileges used in Oracle defined PL/SQL packages.

The purpose of this project, #32973, is to capture privileges used for an operation. Privileges checked in the kernel(e.g, through KZP layer) have been collected. However, many Oracle defined PL/SQL packages query privilege related dictionary tables/views(for example, session_privs, session_roles, sysauth$, objauth$, etc.) to check whether a user has a given privilege. For such cases, APIs in this package have been used to replace original check. For queries that cannot be replaced, privileges are collected directly by calling dbms_priv_capture.capture_privilege_use.
 
Recommended Security Rules

 NEVER
  • Let any user or schema without documented justification or escalated privileges gain access to this package by revoking EXECUTE from PUBLIC
 WITH GREAT CARE
  • Identify legitimate requirements for access to this package and grant EXECUTE explicitly to only justified schemas
  • Query the data dictionary after EXECUTE has been revoked from PUBLIC to verify the equivalence created is the equivalence approved by IT management and your CISO
 CAUTIONS
  • Some usage may be in the form of dynamic SQL so carefully verify usage requirements in source code as well as in DBA_DEPENDENCIES
 
How Oracle Works
Part of Oracle's security design is fine grained granting of object privileges. This package, in theory, assists in identifying granted privileges in use. Sounds like a great piece of code and something you would want to use to identify who has what privileges and to be able to correctly manage privilege allocation.

And you'd be correct.

But the ability to identify who has what privileges is also an asset to someone attempting an attack.

Be sure that this tool is only available to those that actually need it, audit its usage, and review the list no less frequently than once a year.
 
DBMS_PRIV_CAPTURE Package Information
AUTHID CURRENT_USER
Dependencies
DBMS_AQADM_SYS DBMS_PARALLEL_EXECUTE KUPF$FILE
DBMS_CMP_INT DBMS_RULE_EXP_UTLI KUPP$PROC
DBMS_COMPARISON DBMS_SCHED_ARGUMENT_IMPORT KUPV$FT
DBMS_COMPRESSION DBMS_SCHED_JOB_EXPORT KUPW$WORKER
DBMS_CSX_ADMIN DBMS_SCHED_MAIN_EXPORT LBAC_EXP
DBMS_CUBE DBMS_SMB LBAC_SERVICES
DBMS_CUBE_ADVISE DBMS_SNAPSHOT_COMMON LBAC_SYSDBA
DBMS_DATAPUMP DBMS_SQLTUNE LOGMNR_EM_SUPPORT
DBMS_DATA_MINING DBMS_STATS LOGSTDBY_INTERNAL
DBMS_DDL DBMS_STATS_ADVISOR OLS_ENFORCEMENT
DBMS_EDITIONS_UTILITIES DBMS_STREAMS_ADM_UTL_INVOK PRIV_CAPTURE$
DBMS_FILE_GROUP DBMS_STREAMS_PUB_RPC PRIV_PROFILE_LIB
DBMS_FILE_GROUP_IMP DBMS_TRANSFORM RDF_APIS
DBMS_HPROF DBMS_XDB_CONFIG ROLENAME_ARRAY
DBMS_ILM DRIACC ROLE_ARRAY
DBMS_LOGREP_IMP DRIIMP SDO_RDF
DBMS_LOGREP_UTIL_INVOK DRVDDL SEM_RDFSA_DR
DBMS_METADATA ISXMLTYPETABLE XS_DATA_SECURITY_UTIL
Documented No
First Available 12.1.0
Security Model Owned by SYS with EXECUTE granted to EXFSYS, LBACSYS, OLAPSYS, and XDB
Source {ORACLE_HOME}/rdbms/admin/catprofp.sql
Subprograms
 
CAPTURE_PRIVILEGE_USE
Capture a privilege usage, if a privilege capture condition is met. This procedure is called when a privilege is used in PL/SQL or JAVA.

Overload 1
dbms_priv_capture.capture_privilege_use(
userid     IN NUMBER,
syspriv    IN NUMBER         DEFAULT NULL,
role       IN VARCHAR2       DEFAULT NULL,
objpriv    IN NUMBER         DEFAULT NULL,
obj        IN NUMBER         DEFAULT NULL,
domain     IN role_array     DEFAULT NULL,
domain_str IN rolename_array DEFAULT NULL);
TBD
Overload 2 dbms_priv_capture.capture_privilege_use(
username   IN VARCHAR2,
syspriv    IN VARCHAR2       DEFAULT NULL,
role       IN VARCHAR2       DEFAULT NULL,
objpriv    IN VARCHAR2       DEFAULT NULL,
owner      IN VARCHAR2       DEFAULT NULL,
object     IN VARCHAR2       DEFAULT NULL,
domain     IN role_array     DEFAULT NULL,
domain_str IN rolename_array DEFAULT NULL);
TBD
 
SES_HAS_OBJ_PRIV
Checks whether the current user has a given object privilege

Appears to have a bug as this returns FALSE with every attempt to product a result of True
dbms_priv_capture.ses_has_obj_priv(
objpriv  IN VARCHAR2,
objowner IN VARCHAR2,
objname  IN VARCHAR2,
nmspace  IN PLS_INTEGER DEFAULT 1)
RETURN BOOLEAN;
conn sys@pdbdev as sysdba

BEGIN
  IF dbms_priv_capture.ses_has_obj_priv('SELECT', 'UWCLASS', 'CDB_USERS') THEN
    dbms_output.put_line('T');
  ELSE
    dbms_output.put_line('F');
  END IF;
END;
/
F

PL/SQL procedure successfully completed.

GRANT select ON cdb_users TO uwclass;

Grant succeeded.

-- verify that the object privilege has been granted
SELECT grantee
FROM dba_tab_privs
WHERE table_name = 'CDB_USERS'
ORDER BY 1;

GRANTEE
------------------------------
ORACLE_OCM
SELECT_CATALOG_ROLE
UWCLASS

-- this procedure fails to produce an accurate response
BEGIN
  IF dbms_priv_capture.ses_has_obj_priv('SELECT', 'UWCLASS', 'CDB_USERS') THEN
    dbms_output.put_line('T');
  ELSE
    dbms_output.put_line('F');
  END IF;
END;
/
F

-- in a separate SQL*Plus session log on as a user
-- create and run a procedure that uses the granted privilege

conn uwclass/uwclass@pdbdev

CREATE OR REPLACE PROCEDURE test_proc AUTHID DEFINER IS
 x INTEGER;
BEGIN
  SELECT COUNT(*) INTO x FROM cdb_users;
  dbms_output.put_line(x);
END test_proc;
/

Procedure created.

SQL> exec test_proc
53

PL/SQL procedure successfully completed.

-- and the procedure still returns "F" so it looks very broken
-- so let's read the docs more carefully and try it in a package


CREATE OR REPLACE PACKAGE test_pkg AUTHID DEFINER IS
  PROCEDURE test_proc;
END test_pkg;
/

CREATE OR REPLACE PACKAGE BODY test_pkg IS
 PROCEDURE test_proc IS
  x INTEGER;
 BEGIN
   SELECT COUNT(*) INTO x FROM cdb_users;
   dbms_output.put_line(x);
 END test_proc;
END test_pkg;
/

SQL> exec test_proc
53

PL/SQL procedure successfully completed.

-- and still this procedure returns an "F" for Failure which it appears to be
 
SES_HAS_ROLE_PRIV
Determines whether the current user has a given role dbms_priv_capture.ses_has_role_priv(rolename IN VARCHAR2)
RETURN PLS_INTEGER;
SELECT dbms_priv_capture.ses_has_role_priv('DBHADOOP')
FROM dual;

DBMS_PRIV_CAPTURE.SES_HAS_ROLE_PRIV('DBHADOOP')
-----------------------------------------------
                                              0
 
SES_HAS_SYS_PRIV
Determines whether the current user has a given system privilege dbms_priv_capture.ses_has_sys_priv(systempriv IN VARCHAR2)
RETURN PLS_INTEGER;
SELECT dbms_priv_capture.ses_has_sys_priv('CREATE TABLE')
FROM dual;

DBMS_PRIV_CAPTURE.SES_HAS_SYS_PRIV('CREATETABLE')
-------------------------------------------------
                                                1

Related Topics
DBMS_PRIVILEGE_CAPTURE