Call: +44 (0)1904 557620 Call
Passwords

Some issues with password protected roles

This short article describes an issue with password protected roles and like a previous paper about clear text password leakage on SQL*Net when changing a users password this paper also shows that SQL*Net sends the password in clear text when a SET ROLE command is issued. First let's look at an issue with password protected roles.

First we connect as sys and create a test user. This user has only create session privilege to keep things simple:

	SQL> connect sys/change_on_install@sans as sysdba
	Connected.
	SQL> create user role_test identified by role_test;

	User created.

	SQL> grant create session to role_test;

	Grant succeeded.

	SQL>

Next create a password protected role and grant some arbitrary privilege to it. In this case I will use a select privilege on the dictionary view DBA_USERS. let's do this:

	SQL> create role pwd_role identified by pwd_role;

	Role created.

	SQL> grant select on dba_users to pwd_role;

	Grant succeeded.

	SQL>

Next grant this password protected role to our test user ROLE_TEST and also alter the user so that he has no default roles set when he connects:

	SQL> grant pwd_role to role_test;

	Grant succeeded.

	SQL> alter user role_test default role none;

	User altered.

	SQL>

Connect as ROLE_TEST and make sure that no roles are set.

	SQL> connect role_test/role_test@sans
	Connected.
	SQL> select * from session_roles;

	no rows selected

	SQL> select * from user_role_privs;

	USERNAME                       GRANTED_ROLE                   ADM DEF OS_
	------------------------------ ------------------------------ --- --- ---
	ROLE_TEST                      PWD_ROLE                       NO  NO  NO

	1 row selected.

	SQL>

Next try to select from SYS.DBA_USERS just to prove we do not have access to it:

	SQL> select username from dba_users
	  2  where rownum=1;
	select username from dba_users
	                     *
	ERROR at line 1:
	ORA-00942: table or view does not exist

	SQL>

Now finally we set the password protected role and check that it is enabled:

	SQL> set role pwd_role identified by pwd_role;

	Role set.

	SQL> select * from session_roles;

	ROLE
	------------------------------
	PWD_ROLE

	1 row selected.

	SQL>

OK now test the select again from SYS.DBA_USERS and show that we have this privilege now:

	SQL> -- test our select again
	SQL> select username from sys.dba_users
	  2  where username='ROLE_TEST';

	USERNAME
	------------------------------
	ROLE_TEST

	1 row selected.

	SQL> -- OK that works fine

OK, that works as expected. Now let's show how the password protected role can be bypassed. First we will create a second role that is not password protected.

	SQL> connect sys/change_on_install@sans as sysdba
	Connected.
	SQL> create role non_pwd_role;

	Role created.

	SQL>

Grant the password protected role to this new role and then grant the new role to our test user ROLE_TEST and again make sure he has not got any default roles set:

	SQL> grant pwd_role to non_pwd_role;

	Grant succeeded.

	SQL> grant non_pwd_role to role_test;

	Grant succeeded.

	SQL> alter user role_test default role none;

	User altered.

	SQL>

Connect as ROLE_TEST and check that no roles are set yet:

	SQL> connect role_test/role_test@sans
	Connected.
	SQL> select * from session_roles;

	no rows selected

	SQL> select * from user_role_privs;

	USERNAME                       GRANTED_ROLE                   ADM DEF OS_
	------------------------------ ------------------------------ --- --- ---
	ROLE_TEST                      NON_PWD_ROLE                   NO  NO  NO
	ROLE_TEST                      PWD_ROLE                       NO  NO  NO

	2 rows selected.

	SQL>

Now set the role that is not password protected, obviously no password is used.

	SQL> set role non_pwd_role;

	Role set.

	SQL>

Check now what roles are set. You will see that the password protected role has been set as well and we didn't need to supply the password for it!

	SQL> select * from session_roles;

	ROLE
	------------------------------
	NON_PWD_ROLE
	PWD_ROLE

	2 rows selected.

	SQL>

Finally just check we can use our select privilege.

	SQL> select username from sys.dba_users
	  2  where username='ROLE_TEST';

	USERNAME
	------------------------------
	ROLE_TEST

	1 row selected.

	SQL> -- excuse me!!

Hmmmmmmm. This is probably the behavior Oracle intended but not what I expected. If a role is password protected then surely you should not be able to bypass giving the password. Using roles with passwords and not allowing any user to have any roles set by default has long been a good way to control privileges. There is a downside to this though as the application needs to send the "SET ROLE {BLAH} IDENTIFIED BY {BLAH}" command to the RDBMS. This means that the password is usually embedded in the application code and also that at least one developer knows it. There are ways tohide the password by splitting it up or obfuscating it in the binary but the idea is flawed. The more modern application roles method is a better solution.

One more observation with this is that like issuing an ALTER USER command the password when passed via the SET ROLE command is sent in clear text to the server. This can be seen using SQL*Net trace. I set the following values in my server $ORACLE_HOME/network/admin/sqlnet.ora file:

TRACE_FILE_SERVER=role.trc
TRACE_DIRECTORY_SERVER=c:\temp
TRACE_LEVEL_SERVER=SUPPORT

Testing with the following commands in SQL*Plus:

Connected to:
Personal Oracle9i Release 9.2.0.1.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.1.0 - Production

SQL> select * from session_roles;

no rows selected

SQL> set role pwd_role identified by pwd_role;

Role set.

SQL>

results in the following entries in the SQL*Net trace file.

[13-MAR-2004 22:47:41:327] nsprecv: 00 00 00 00 28 73 65 74  |....(set|
[13-MAR-2004 22:47:41:327] nsprecv: 20 72 6F 6C 65 20 70 77  |.role.pw|
[13-MAR-2004 22:47:41:327] nsprecv: 64 5F 72 6F 6C 65 20 69  |d_role.i|
[13-MAR-2004 22:47:41:327] nsprecv: 64 65 6E 74 69 66 69 65  |dentifie|
[13-MAR-2004 22:47:41:327] nsprecv: 64 20 62 79 20 70 77 64  |d.by.pwd|
[13-MAR-2004 22:47:41:327] nsprecv: 5F 72 6F 6C 65 01 00 00  |_role...|
[13-MAR-2004 22:47:41:327] nsprecv: 00 01 00 00 00 00 00 00  |........|

This is the same issue as covered in the ALTER USER paper Passwords in clear text. Basically if you use the SET ROLE commands then you will need to ensure that the network cannot be sniffed to avoid giving out passwords (This is assuming you have protected the password used in the application binary as well). The Oracle Advanced Security Option or something free like ssh could be used.

Going back to the password protected role bypass issue. If you want to use password protected roles you need to ensure two things:

  • That the password protected role cannot be granted on by the recipient of the role, otherwise he could grant it to any other role he had access to and use the same technique as above to gain the privileges without the password. For example:
    	Connected to:
    	Personal Oracle9i Release 9.2.0.1.0 - Production
    	With the Partitioning, OLAP and Oracle Data Mining options
    	JServer Release 9.2.0.1.0 - Production
    
    	SQL> desc dba_role_privs
    	 Name                                      Null?    Type
    	 ----------------------------------------- -------- ----------------------------
    	 GRANTEE                                            VARCHAR2(30)
    	 GRANTED_ROLE                              NOT NULL VARCHAR2(30)
    	 ADMIN_OPTION                                       VARCHAR2(3)
    	 DEFAULT_ROLE                                       VARCHAR2(3)
    
    	SQL> select * from dba_role_privs
    	  2  where granted_role='PWD_ROLE';
    
    	GRANTEE                        GRANTED_ROLE                   ADM DEF
    	------------------------------ ------------------------------ --- ---
    	SYS                            PWD_ROLE                       YES YES
    	ROLE_TEST                      PWD_ROLE                       NO  NO
    	NON_PWD_ROLE                   PWD_ROLE                       NO  YES
    
    	SQL>
    

    In this case as you can see ROLE_TEST cannot grant this role to anyone else. It also may be prudent to check if a recipient of a password protected role has the CREATE ROLE privilege. If they did and the ADMIN_OPTION was yes they have then the option of just creating a wrapper role.

  • The other thing to check is for password protected roles that have been granted to non password protected roles. If you find any revoke the password protected role from the non password role. The following SQL illustrates:
    	SQL> select p.grantee,p.granted_role,p.admin_option
    	  2  from dba_role_privs p,
    	  3     dba_roles r
    	  4  where exists (select 'x'
    	  5   from dba_roles d
    	  6   where d.password_required='YES'
    	  7   and d.role=p.granted_role)
    	  8  and p.grantee=r.role
    	SQL> /
    
    	GRANTEE                        GRANTED_ROLE                   ADM
    	------------------------------ ------------------------------ ---
    	NON_PWD_ROLE                   PWD_ROLE                       NO
    
    	SQL>
    

    As you can see the non password role is shown as a grantee for the password protected one.

OK, that's it, remember that if you use password protected roles to ensure they cannot be sniffed or bypassed.



Back